Skip to content

Commit

Permalink
feat: remove legacy search
Browse files Browse the repository at this point in the history
  • Loading branch information
sdjdd committed Jan 5, 2024
1 parent c434984 commit 8f37705
Show file tree
Hide file tree
Showing 4 changed files with 8 additions and 183 deletions.
153 changes: 0 additions & 153 deletions next/api/src/router/ticket.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Router from '@koa/router';
import AV from 'leancloud-storage';
import _ from 'lodash';
import UAParser from 'ua-parser-js';

Expand Down Expand Up @@ -290,130 +289,6 @@ router.get(
}
);

const searchTicketParamsSchema = ticketFiltersSchema.shape({
keyword: yup.string().required(),
});

router.get(
'/search',
sort('orderBy', ['status', 'createdAt', 'updatedAt']),
parseRange('createdAt'),
async (ctx) => {
const currentUser = ctx.state.currentUser as User;
const params = searchTicketParamsSchema.validateSync(ctx.query);

const sortFields = sort.get(ctx);

const categoryIds = new Set(params.categoryId);
if (params.rootCategoryId) {
categoryIds.add(params.rootCategoryId);
const subCategories = await categoryService.getSubCategories(params.rootCategoryId);
subCategories.forEach((c) => categoryIds.add(c.id));
}

const conditions = [`(title:${params.keyword} OR content:${params.keyword})`];

const addEqCondition = (field: string, value: string | number | (string | number)[]) => {
if (Array.isArray(value)) {
if (value.includes('null')) {
const nonNullValue = value.filter((v) => v !== 'null');
if (nonNullValue.length) {
if (nonNullValue.length === 1) {
conditions.push(`(_missing_:${field} OR ${field}:${nonNullValue[0]})`);
} else {
conditions.push(`(_missing_:${field} OR ${field}:(${nonNullValue.join(' OR ')}))`);
}
} else {
conditions.push(`_missing_:${field}`);
}
} else {
if (value.length === 1) {
conditions.push(`${field}:${value[0]}`);
} else {
conditions.push(`${field}:(${value.join(' OR ')})`);
}
}
} else {
if (value === 'null') {
conditions.push(`_missing_:${field}`);
} else {
conditions.push(`${field}:${value}`);
}
}
};

if (params.authorId) {
addEqCondition('author.objectId', params.authorId);
}
if (params.assigneeId) {
addEqCondition('assignee.objectId', params.assigneeId);
}
if (params.groupId) {
addEqCondition('group.objectId', params.groupId);
}
if (params.reporterId) {
addEqCondition('reporter.objectId', params.reporterId);
}
if (params.participantId) {
addEqCondition('joinedCustomerServices.objectId', params.participantId);
}
if (categoryIds.size) {
addEqCondition('category.objectId', Array.from(categoryIds));
}
if (params.status) {
addEqCondition('status', params.status);
}
if (params['evaluation.star'] !== undefined) {
addEqCondition('evaluation.star', params['evaluation.star']);
}
if (params['evaluation.ts']) {
const from = params['evaluation.ts'][0]?.toISOString() ?? '*';
const to = params['evaluation.ts'][1]?.toISOString() ?? '*';
conditions.push(`evaluation.ts:[${from} TO ${to}]`);
}
if (params.createdAtFrom || params.createdAtTo) {
const from = params.createdAtFrom?.toISOString() ?? '*';
const to = params.createdAtTo?.toISOString() ?? '*';
conditions.push(`createdAt:[${from} TO ${to}]`);
}
if (params.tagKey) {
addEqCondition('tags.key', params.tagKey);
}
if (params.tagValue) {
addEqCondition('tags.value', params.tagValue);
}
if (params.privateTagKey) {
addEqCondition('privateTags.key', params.privateTagKey);
}
if (params.privateTagValue) {
addEqCondition('privateTags.value', params.privateTagValue);
}

if (params.language) {
addEqCondition('language', params.language);
}

const queryString = conditions.join(' AND ');

const searchQuery = new AV.SearchQuery('Ticket');
searchQuery.queryString(queryString);
sortFields?.forEach(({ key, order }) => {
if (order === 'asc') {
searchQuery.addAscending(key);
} else {
searchQuery.addDescending(key);
}
});
searchQuery.skip((params.page - 1) * params.pageSize).limit(params.pageSize);

const ticketObjects = await searchQuery.find(currentUser.getAuthOptions());
const tickets = ticketObjects.map((o) => Ticket.fromAVObject(o as AV.Object));

ctx.set('X-Total-Count', searchQuery.hits().toString());
ctx.body = tickets.map((t) => new TicketListItemResponse(t));
}
);

const exportTicketParamsSchema = ticketFiltersSchema.shape({
type: yup.string().oneOf(['json', 'csv']).required(),
utcOffset: yup.number(),
Expand Down Expand Up @@ -1211,32 +1086,4 @@ router.get('/:id/custom-fields', async (ctx) => {
ctx.body = values;
});

const searchCustomFieldSchema = yup.object({
q: yup.string().trim().required(),
});

router.post('/search-custom-field', customerServiceOnly, async (ctx) => {
const { q } = searchCustomFieldSchema.validateSync(ctx.request.body);
const searchQuery = new AV.SearchQuery('TicketFieldValue');
searchQuery.queryString(q);
const results = await searchQuery.limit(1000).find({ useMasterKey: true });
if (results.length === 0) {
ctx.body = [];
return;
}

const ticketIds: string[] = results.map((t) => t.get('ticket').id);
const tickets = await Ticket.queryBuilder()
.where('objectId', 'in', ticketIds)
.preload('assignee')
.preload('author')
.preload('group')
.orderBy('createdAt', 'desc')
.limit(results.length)
.find({ useMasterKey: true });

ctx.set('X-Total-Count', searchQuery.hits().toString());
ctx.body = tickets.map((t) => new TicketListItemResponse(t));
});

export default router;
1 change: 0 additions & 1 deletion next/web/script/generateEnv.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const OPTIONAL_ENV_KEYS = [
'ENABLE_LEANCLOUD_INTEGRATION',
'ALGOLIA_API_KEY',
'ENABLE_USER_CONFIRMATION',
'ENABLE_SEARCH_V2',
];

const CUSTOM_ENVS = {
Expand Down
36 changes: 8 additions & 28 deletions next/web/src/api/ticket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,7 @@ async function searchTickets(
orderBy: `${orderKey}-${orderType}`,
};

const url = import.meta.env.VITE_ENABLE_SEARCH_V2
? '/api/2/tickets/search/v2'
: '/api/2/tickets/search';

const { headers, data } = await http.get(url, { params });
const { headers, data } = await http.get('/api/2/tickets/search/v2', { params });
return { tickets: data, totalCount: parseInt(headers['x-total-count']) };
}

Expand Down Expand Up @@ -326,30 +322,14 @@ async function searchTicketCustomField({
fieldValue,
createdAt,
}: SearchTicketCustomFieldOptions) {
if (import.meta.env.VITE_ENABLE_SEARCH_V2) {
const res = await http.get<TicketSchema[]>('/api/2/tickets/search/v2', {
params: {
fieldId,
fieldValue,
createdAt: createdAt?.map((d) => (d ? d.toISOString() : '*')).join('..'),
},
});
return { tickets: res.data, totalCount: Number(res.headers['x-total-count']) };
}

const q = `values.field:${fieldId ? encodeURIComponent(fieldId) : '*'} AND values.value:${
fieldValue ? encodeURIComponent(fieldValue) : '*'
}${
createdAt
? ` AND createdAt:[${createdAt[0] ? `"${createdAt[0].toISOString()}"` : '*'} TO ${
createdAt[1] ? `"${createdAt[1].toISOString()}"` : '*'
}]`
: ''
}`;
const { data, headers } = await http.post<TicketSchema[]>('/api/2/tickets/search-custom-field', {
q,
const res = await http.get<TicketSchema[]>('/api/2/tickets/search/v2', {
params: {
fieldId,
fieldValue,
createdAt: createdAt?.map((d) => (d ? d.toISOString() : '*')).join('..'),
},
});
return { tickets: data, totalCount: Number(headers['x-total-count']) };
return { tickets: res.data, totalCount: Number(res.headers['x-total-count']) };
}

export function useSearchTicketCustomField(
Expand Down
1 change: 0 additions & 1 deletion next/web/src/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ interface ImportMetaEnv {
VITE_ALGOLIA_API_KEY?: string;
VITE_ENABLE_TAP_SUPPORT?: string;
VITE_ENABLE_USER_CONFIRMATION?: string;
VITE_ENABLE_SEARCH_V2?: string;
}

declare function docsearch(...args: any[]);

0 comments on commit 8f37705

Please sign in to comment.