Plugins: Fixes #4407: Apply "fields" query parameter when requesting data from data API

pull/4406/head^2
Laurent Cozic 2021-02-01 12:41:25 +00:00
parent dac6c5fde2
commit 1f536ba3d9
6 changed files with 31 additions and 10 deletions

View File

@ -410,8 +410,18 @@ describe('services_rest_Api', function() {
const response2 = await api.route(RequestMethod.GET, `notes/${note1.id}/tags`);
expect(response2.items.length).toBe(1);
await Tag.addNote(tag2.id, note1.id);
const response3 = await api.route(RequestMethod.GET, `notes/${note1.id}/tags`);
const response3 = await api.route(RequestMethod.GET, `notes/${note1.id}/tags`, { fields: 'id' });
expect(response3.items.length).toBe(2);
// Also check that it only returns the required fields
response3.items.sort((a: any, b: any) => {
return a.id < b.id ? -1 : +1;
});
const sortedTagIds = [tag.id, tag2.id];
sortedTagIds.sort();
expect(JSON.stringify(response3.items)).toBe(`[{"id":"${sortedTagIds[0]}"},{"id":"${sortedTagIds[1]}"}]`);
}));
it('should update tags when updating notes', (async () => {

View File

@ -4,7 +4,7 @@ import uuid from '../../../uuid';
import readonlyProperties from '../utils/readonlyProperties';
import defaultSaveOptions from '../utils/defaultSaveOptions';
import defaultAction from '../utils/defaultAction';
import BaseModel from '../../../BaseModel';
import BaseModel, { ModelType } from '../../../BaseModel';
import defaultLoadOptions from '../utils/defaultLoadOptions';
import { RequestMethod, Request } from '../Api';
import markdownUtils from '../../../markdownUtils';
@ -300,7 +300,7 @@ async function attachImageFromDataUrl(note: any, imageDataUrl: string, cropRect:
export default async function(request: Request, id: string = null, link: string = null) {
if (request.method === 'GET') {
if (link && link === 'tags') {
return collectionToPaginatedResults(await Tag.tagsByNoteId(id), request);
return collectionToPaginatedResults(ModelType.Tag, await Tag.tagsByNoteId(id), request);
} else if (link && link === 'resources') {
const note = await Note.load(id);
if (!note) throw new ErrorNotFound();
@ -310,7 +310,7 @@ export default async function(request: Request, id: string = null, link: string
for (const resourceId of resourceIds) {
output.push(await Resource.load(resourceId, loadOptions));
}
return collectionToPaginatedResults(output, request);
return collectionToPaginatedResults(ModelType.Resource, output, request);
} else if (link) {
throw new ErrorNotFound();
}

View File

@ -1,4 +1,4 @@
import BaseModel from '../../../BaseModel';
import BaseModel, { ModelType } from '../../../BaseModel';
import shim from '../../../shim';
import { Request, RequestMethod } from '../Api';
import defaultAction from '../utils/defaultAction';
@ -41,7 +41,7 @@ export default async function(request: Request, id: string = null, link: string
for (const noteId of noteIds) {
notes.push(await Note.load(noteId, loadOptions));
}
return collectionToPaginatedResults(notes, request);
return collectionToPaginatedResults(ModelType.Note, notes, request);
}
if (link) throw new ErrorNotFound();

View File

@ -31,5 +31,5 @@ export default async function(request: Request) {
results = await SearchEngineUtils.notesForQuery(query, defaultLoadOptions(request, ModelType.Note));
}
return collectionToPaginatedResults(results, request);
return collectionToPaginatedResults(modelType, results, request);
}

View File

@ -34,7 +34,7 @@ export default async function(request: Request, id: string = null, link: string
if (!n) continue;
output.push(n);
}
return collectionToPaginatedResults(output, request);
return collectionToPaginatedResults(ModelType.Note, output, request);
}
}

View File

@ -1,14 +1,17 @@
import { ModelType } from '../../../BaseModel';
import { ModelFeedPage } from '../../../models/utils/paginatedFeed';
import { PaginationOrderDir } from '../../../models/utils/types';
import { Request } from '../Api';
import requestPaginationOptions from '../utils/requestPaginationOptions';
import requestFields from './requestFields';
// Note that this is inefficient pagination as it requires all the items to
// have been loaded first, even if not all of them are returned.
//
// It's however convenient for smaller lists as it reduces the need for
// building complex SQL queries.
export default function(items: any[], request: Request): ModelFeedPage {
export default function(itemType: ModelType, items: any[], request: Request): ModelFeedPage {
const fields = requestFields(request, itemType);
const pagination = requestPaginationOptions(request);
const startIndex = (pagination.page - 1) * pagination.limit;
const itemCount = Math.min(items.length - startIndex, pagination.limit);
@ -17,7 +20,15 @@ export default function(items: any[], request: Request): ModelFeedPage {
const sortBy = pagination.order[0].by;
const sortDir = pagination.order[0].dir;
const caseInsensitive = pagination.order[0].caseInsensitive;
const sortedItems = items.slice();
const sortedItems = items.slice().map((item: any) => {
if (!fields.length) return item;
const newItem: any = {};
for (const k of Object.keys(item)) {
if (!fields.includes(k)) continue;
newItem[k] = item[k];
}
return newItem;
});
sortedItems.sort((a: any, b: any) => {
let v1 = a && (sortBy in a) ? a[sortBy] : '';