Skip to content

Commit

Permalink
feat(api): lookup IP info (#940)
Browse files Browse the repository at this point in the history
  • Loading branch information
leeyeh authored Oct 16, 2023
1 parent dbc3568 commit 67fb2bc
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 2 deletions.
25 changes: 23 additions & 2 deletions next/api/src/router/ticket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { addInOrNotExistCondition } from '@/utils/conditions';
import { dynamicContentService } from '@/dynamic-content';
import { FileResponse } from '@/response/file';
import { File } from '@/model/File';
import { lookupIp } from '@/utils/ip';

const router = new Router().use(auth);

Expand Down Expand Up @@ -489,7 +490,7 @@ const extractSystemFields = (
};
};

const { PERSIST_USERAGENT_INFO } = process.env;
const { PERSIST_USERAGENT_INFO, IP_LOOKUP_ENABLED } = process.env;

router.post('/', async (ctx) => {
const currentUser = ctx.state.currentUser as User;
Expand Down Expand Up @@ -585,6 +586,26 @@ router.post('/', async (ctx) => {
[...(customFields ?? []), ...builtInFields],
'field'
);
if (IP_LOOKUP_ENABLED) {
const ipField = fields.find(({ field }) => field === 'ip');
const locationField = fields.find(({ field }) => field === 'location');
const ispField = fields.find(({ field }) => field === 'isp');
if (ipField && (!locationField || !ispField)) {
const { region, city, isp } = await lookupIp(ipField.value);
if (!locationField && region) {
fields.push({
field: 'location',
value: `${region}${city ?? ''}`,
});
}
if (!ispField && isp) {
fields.push({
field: 'isp',
value: isp,
});
}
}
}
if (fields.length) {
const ticketFieldIds = fields.map((field) => field.field);
// TODO(sdjdd): Cache result
Expand Down Expand Up @@ -1187,4 +1208,4 @@ router.post('/search-custom-field', customerServiceOnly, async (ctx) => {
ctx.body = tickets.map((t) => new TicketListItemResponse(t));
});

export default router;
export default router;
18 changes: 18 additions & 0 deletions next/api/src/utils/ip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import axios from 'axios';

const { IP_LOOKUP_ENABLED, IP_LOOKUP_SERVER } = process.env;

export async function lookupIp(
ip: string
): Promise<{ region?: string; city?: string; isp?: string }> {
if (!IP_LOOKUP_ENABLED) throw new Error('IP lookup is disabled.');
if (!IP_LOOKUP_SERVER) throw new Error('IP lookup server is not configured.');

try {
const server = IP_LOOKUP_SERVER.replace(':ip', ip);
return (await axios.get(server)).data;
} catch (error) {
console.warn('Failed to lookup IP:', ip, error instanceof Error ? error.message : error, error);
return { region: undefined, city: undefined, isp: undefined };
}
}
2 changes: 2 additions & 0 deletions resources/data/TicketField.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
{"ACL":{},"objectId":"os","defaultLocale":"zh-cn","type":"text","title":"操作系统","active":true,"visible":false,"required":false,"meta":{"disableFilter": true}}
{"ACL":{},"objectId":"os_name","defaultLocale":"zh-cn","type":"text","title":"操作系统名称","active":true,"visible":false,"required":false,"meta":{"disableFilter": true}}
{"ACL":{},"objectId":"ip","defaultLocale":"zh-cn","type":"text","title":"IP","active":true,"visible":false,"required":false,"meta":{"disableFilter": true},"previewTemplate":"<a href=\"https://www.geolocation.com/zh_cn?ip={{ value }}#ipresult\">{{ value }}</a>"}
{"ACL":{},"objectId":"location","defaultLocale":"zh-cn","type":"text","title":"地区","active":true,"visible":false,"required":false,"meta":{"disableFilter": true}}
{"ACL":{},"objectId":"isp","defaultLocale":"zh-cn","type":"text","title":"运营商","active":true,"visible":false,"required":false,"meta":{"disableFilter": true}}
2 changes: 2 additions & 0 deletions resources/data/TicketFieldVariant.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
{"description":"","titleForCustomerService":"操作系统","ACL":{},"locale":"zh-cn","field":{"__type":"Pointer","className":"TicketField","objectId":"os"},"title":"操作系统"}
{"description":"","titleForCustomerService":"操作系统名称","ACL":{},"locale":"zh-cn","field":{"__type":"Pointer","className":"TicketField","objectId":"os_name"},"title":"操作系统名称"}
{"description":"","titleForCustomerService":"IP","ACL":{},"locale":"zh-cn","field":{"__type":"Pointer","className":"TicketField","objectId":"ip"},"title":"IP"}
{"description":"","titleForCustomerService":"地区","ACL":{},"locale":"zh-cn","field":{"__type":"Pointer","className":"TicketField","objectId":"location"},"title":"地区"}
{"description":"","titleForCustomerService":"运营商","ACL":{},"locale":"zh-cn","field":{"__type":"Pointer","className":"TicketField","objectId":"isp"},"title":"运营商"}

0 comments on commit 67fb2bc

Please sign in to comment.