Skip to content

Commit

Permalink
fix: use post query instead get with query parameters not to exceed m…
Browse files Browse the repository at this point in the history
…ax url length
  • Loading branch information
drodil committed Nov 4, 2024
1 parent b48f1d2 commit 5010ced
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 72 deletions.
8 changes: 4 additions & 4 deletions plugins/qeta-backend/src/database/DatabaseQetaStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
import { Knex } from 'knex';
import {
Answers,
AnswersOptions,
AttachmentParameters,
CollectionPostRank,
Collections,
Expand All @@ -17,7 +16,6 @@ import {
MaybeComment,
MaybePost,
MaybeTemplate,
PostOptions,
Posts,
QetaStore,
TagResponse,
Expand All @@ -29,6 +27,7 @@ import {
import {
AIResponse,
Answer,
AnswersQuery,
Attachment,
Collection,
CollectionsQuery,
Expand All @@ -37,6 +36,7 @@ import {
filterTags,
GlobalStat,
Post,
PostsQuery,
PostType,
Statistic,
StatisticsRequestParameters,
Expand Down Expand Up @@ -240,7 +240,7 @@ export class DatabaseQetaStore implements QetaStore {

async getPosts(
user_ref: string,
options: PostOptions,
options: PostsQuery,
filters?: PermissionCriteria<QetaFilters>,
): Promise<Posts> {
const query = this.getPostsBaseQuery(user_ref);
Expand Down Expand Up @@ -683,7 +683,7 @@ export class DatabaseQetaStore implements QetaStore {

async getAnswers(
user_ref: string,
options: AnswersOptions,
options: AnswersQuery,
filters?: PermissionCriteria<QetaFilters>,
): Promise<Answers> {
const query = this.getAnswerBaseQuery();
Expand Down
63 changes: 4 additions & 59 deletions plugins/qeta-backend/src/database/QetaStore.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import {
AIResponse,
Answer,
AnswersQuery,
Attachment,
Collection,
CollectionsQuery,
Comment,
EntitiesQuery,
GlobalStat,
Post,
PostsQuery,
PostType,
Statistic,
StatisticsRequestParameters,
Expand Down Expand Up @@ -57,63 +59,6 @@ export interface Templates {
total: number;
}

export interface PostOptions {
type?: PostType;
limit?: number;
offset?: number;
author?: string | string[];
orderBy?:
| 'views'
| 'rank'
| 'title'
| 'score'
| 'answersCount'
| 'created'
| 'updated'
| 'trend';
order?: 'desc' | 'asc';
noCorrectAnswer?: boolean;
noAnswers?: boolean;
noVotes?: boolean;
favorite?: boolean;
tags?: string[];
tagsRelation?: 'and' | 'or';
entities?: string[];
entitiesRelation?: 'and' | 'or';
includeAnswers?: boolean;
includeVotes?: boolean;
includeEntities?: boolean;
includeTrend?: boolean;
random?: boolean;
searchQuery?: string;
fromDate?: string;
toDate?: string;
collectionId?: number;
}

export interface AnswersOptions {
limit?: number;
offset?: number;
author?: string;
noCorrectAnswer?: boolean;
noVotes?: boolean;
orderBy?:
| 'views'
| 'score'
| 'answersCount'
| 'created'
| 'updated'
| 'trend';
order?: 'desc' | 'asc';
tags?: string[];
tagsRelation?: 'and' | 'or';
entities?: string[];
entitiesRelation?: 'and' | 'or';
searchQuery?: string;
fromDate?: string;
toDate?: string;
}

export interface TagResponse {
id: number;
tag: string;
Expand Down Expand Up @@ -186,7 +131,7 @@ export interface QetaStore {
*/
getPosts(
user_ref: string,
options: PostOptions,
options: PostsQuery,
filters?: PermissionCriteria<QetaFilters>,
): Promise<Posts>;

Expand Down Expand Up @@ -345,7 +290,7 @@ export interface QetaStore {
*/
getAnswers(
user_ref: string,
options: AnswersOptions,
options: AnswersQuery,
filters?: PermissionCriteria<QetaFilters>,
): Promise<Answers>;

Expand Down
37 changes: 37 additions & 0 deletions plugins/qeta-backend/src/service/routes/answers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,43 @@ export const answersRoutes = (router: Router, options: RouteOptions) => {
}
});

router.post(`/answers/query`, async (request, response) => {
// Validation
const username = await getUsername(request, options, true);
const validateQuery = ajv.compile(AnswersQuerySchema);
if (!validateQuery(request.body)) {
response
.status(400)
.send({ errors: validateQuery.errors, type: 'query' });
return;
}

const validDate = validateDateRange(
request.body.fromDate as string,
request.body.toDate as string,
);
if (!validDate?.isValid) {
response.status(400).send(validDate);
return;
}

const decision = await authorizeConditional(
request,
qetaReadAnswerPermission,
options,
);

if (decision.result === AuthorizeResult.CONDITIONAL) {
const filter: PermissionCriteria<QetaFilters> = transformConditions(
decision.conditions,
);
const answers = await database.getAnswers(username, request.body, filter);
response.json(answers);
} else {
response.json(await database.getAnswers(username, request.body));
}
});

// POST /posts/:id/answers
router.post(`/posts/:id/answers`, async (request, response) => {
// Validation
Expand Down
49 changes: 49 additions & 0 deletions plugins/qeta-backend/src/service/routes/collections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,55 @@ export const collectionsRoutes = (router: Router, options: RouteOptions) => {
}
});

router.post(`/collections/query`, async (request, response) => {
// Validation
const username = await getUsername(request, options, true);
const validateQuery = ajv.compile(CollectionsQuerySchema);
if (!validateQuery(request.body)) {
response
.status(400)
.send({ errors: validateQuery.errors, type: 'query' });
return;
}

const validDate = validateDateRange(
request.body.fromDate as string,
request.body.toDate as string,
);
if (!validDate?.isValid) {
response.status(400).send(validDate);
return;
}

const decision = await authorizeConditional(
request,
qetaReadPostPermission,
options,
);

// Act
if (decision.result === AuthorizeResult.CONDITIONAL) {
const filter: PermissionCriteria<QetaFilters> = transformConditions(
decision.conditions,
);
const collections = await database.getCollections(
username,
request.body,
filter,
);
response.json({
collections: collections.collections,
total: collections.total,
});
} else {
const collections = await database.getCollections(username, request.body);
response.json({
collections: collections.collections,
total: collections.total,
});
}
});

// POST /collections
router.post(`/collections`, async (request, response) => {
// Validation
Expand Down
41 changes: 39 additions & 2 deletions plugins/qeta-backend/src/service/routes/posts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { PostOptions } from '../../database/QetaStore';
import {
authorize,
authorizeConditional,
Expand All @@ -12,6 +11,7 @@ import Ajv from 'ajv';
import { Request, Router } from 'express';
import {
findUserMentions,
PostsQuery,
qetaCreateCommentPermission,
qetaCreatePostPermission,
qetaDeleteCommentPermission,
Expand Down Expand Up @@ -79,6 +79,43 @@ export const postsRoutes = (router: Router, options: RouteOptions) => {
}
});

router.post(`/posts/query`, async (request, response) => {
// Validation
const username = await getUsername(request, options, true);
const validateQuery = ajv.compile(PostsQuerySchema);
if (!validateQuery(request.body)) {
response.status(400).send({ errors: validateQuery.errors, type: 'body' });
return;
}

const validDate = validateDateRange(
request.body.fromDate as string,
request.body.toDate as string,
);
if (!validDate?.isValid) {
response.status(400).send(validDate);
return;
}

const decision = await authorizeConditional(
request,
qetaReadPostPermission,
options,
);

// Act
if (decision.result === AuthorizeResult.CONDITIONAL) {
const filter: PermissionCriteria<QetaFilters> = transformConditions(
decision.conditions,
);
const posts = await database.getPosts(username, request.body, filter);
response.json({ posts: posts.posts, total: posts.total });
} else {
const posts = await database.getPosts(username, request.body);
response.json({ posts: posts.posts, total: posts.total });
}
});

// GET /posts/list/:type
router.get(`/posts/list/:type`, async (request, response) => {
// Validation
Expand All @@ -91,7 +128,7 @@ export const postsRoutes = (router: Router, options: RouteOptions) => {
return;
}

const optionOverride: PostOptions = {};
const optionOverride: PostsQuery = {};
const type = request.params.type;
if (type === 'unanswered') {
optionOverride.random = true;
Expand Down
24 changes: 18 additions & 6 deletions plugins/qeta-common/src/api/QetaClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,13 @@ export class QetaClient implements QetaApi {
options: PostsQuery,
requestOptions?: RequestOptions,
): Promise<PostsResponse> {
const response = await this.fetch('/posts', {
const response = await this.fetch('/posts/query', {
reqInit: {
method: 'POST',
body: JSON.stringify(options),
headers: { 'Content-Type': 'application/json' },
},
requestOptions,
queryParams: options,
});

if (response.status === 403) {
Expand Down Expand Up @@ -682,8 +686,12 @@ export class QetaClient implements QetaApi {
options: AnswersQuery,
requestOptions?: RequestOptions,
): Promise<AnswersResponse> {
const response = await this.fetch('/answers', {
queryParams: options,
const response = await this.fetch('/answers/query', {
reqInit: {
method: 'POST',
body: JSON.stringify(options),
headers: { 'Content-Type': 'application/json' },
},
requestOptions,
});
if (response.status === 403) {
Expand Down Expand Up @@ -968,8 +976,12 @@ export class QetaClient implements QetaApi {
options?: CollectionsQuery,
requestOptions?: RequestOptions,
): Promise<CollectionsResponse> {
const response = await this.fetch('/collections', {
queryParams: options,
const response = await this.fetch('/collections/query', {
reqInit: {
method: 'POST',
body: JSON.stringify(options),
headers: { 'Content-Type': 'application/json' },
},
requestOptions,
});
if (response.status === 403) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const AnswersContainer = (props: AnswersContainerProps) => {
orderBy: 'created',
searchQuery: '',
dateRange: '',
entity: entity ?? '',
entities: entity ? [entity] : undefined,
tags: tags ?? [],
noVotes: 'false',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ export const FilterPanel = <T extends Filters>(props: FilterPanelProps<T>) => {
}
>
<IconButton
disabled={starredEntities || ownedEntities}
onClick={() => {
if (filters.entitiesRelation === 'or') {
onChange({ key: 'entitiesRelation', value: 'and' });
Expand Down
5 changes: 5 additions & 0 deletions plugins/qeta-react/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ export const getFiltersWithDateRange = (filters: Filters) => {
return filtersWithDateRange;
}
}

if ('dateRange' in filters) {
delete filters.dateRange;
}

return filters;
};

Expand Down

0 comments on commit 5010ced

Please sign in to comment.