feat(services): ability to search GET /guilds/public

This commit is contained in:
Divlo 2021-11-13 14:48:56 +01:00
parent f0f4f9f69f
commit 385c95be90
No known key found for this signature in database
GPG Key ID: 6F24DA54DA3967CF
6 changed files with 2153 additions and 3015 deletions

5064
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -31,33 +31,33 @@
"postinstall": "husky install" "postinstall": "husky install"
}, },
"dependencies": { "dependencies": {
"@prisma/client": "3.2.1", "@prisma/client": "3.4.2",
"@sinclair/typebox": "0.20.5", "@sinclair/typebox": "0.20.5",
"axios": "0.22.0", "axios": "0.24.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"dotenv": "10.0.0", "dotenv": "10.0.0",
"ejs": "3.1.6", "ejs": "3.1.6",
"fastify": "3.22.0", "fastify": "3.23.1",
"fastify-cors": "6.0.2", "fastify-cors": "6.0.2",
"fastify-helmet": "5.3.2", "fastify-helmet": "5.3.2",
"fastify-multipart": "5.0.2", "fastify-multipart": "5.1.0",
"fastify-plugin": "3.0.0", "fastify-plugin": "3.0.0",
"fastify-rate-limit": "5.6.2", "fastify-rate-limit": "5.6.2",
"fastify-sensible": "3.1.1", "fastify-sensible": "3.1.2",
"fastify-static": "4.4.1", "fastify-static": "4.5.0",
"fastify-swagger": "4.12.4", "fastify-swagger": "4.12.6",
"fastify-url-data": "3.0.3", "fastify-url-data": "3.0.3",
"http-errors": "1.8.0", "http-errors": "1.8.0",
"jsonwebtoken": "8.5.1", "jsonwebtoken": "8.5.1",
"ms": "2.1.3", "ms": "2.1.3",
"nodemailer": "6.6.5", "nodemailer": "6.7.0",
"read-pkg": "5.2.0", "read-pkg": "5.2.0",
"socket.io": "4.2.0" "socket.io": "4.3.2"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "13.2.1", "@commitlint/cli": "14.1.0",
"@commitlint/config-conventional": "13.2.0", "@commitlint/config-conventional": "14.1.0",
"@saithodev/semantic-release-backmerge": "1.5.3", "@saithodev/semantic-release-backmerge": "2.1.0",
"@types/bcryptjs": "2.4.2", "@types/bcryptjs": "2.4.2",
"@types/busboy": "0.3.0", "@types/busboy": "0.3.0",
"@types/ejs": "3.1.0", "@types/ejs": "3.1.0",
@ -65,7 +65,7 @@
"@types/jest": "27.0.2", "@types/jest": "27.0.2",
"@types/jsonwebtoken": "8.5.5", "@types/jsonwebtoken": "8.5.5",
"@types/ms": "0.7.31", "@types/ms": "0.7.31",
"@types/node": "16.10.3", "@types/node": "16.11.7",
"@types/nodemailer": "6.4.4", "@types/nodemailer": "6.4.4",
"@typescript-eslint/eslint-plugin": "4.33.0", "@typescript-eslint/eslint-plugin": "4.33.0",
"concurrently": "6.3.0", "concurrently": "6.3.0",
@ -75,24 +75,24 @@
"eslint": "7.32.0", "eslint": "7.32.0",
"eslint-config-prettier": "8.3.0", "eslint-config-prettier": "8.3.0",
"eslint-config-standard-with-typescript": "21.0.1", "eslint-config-standard-with-typescript": "21.0.1",
"eslint-plugin-import": "2.24.2", "eslint-plugin-import": "2.25.3",
"eslint-plugin-node": "11.1.0", "eslint-plugin-node": "11.1.0",
"eslint-plugin-prettier": "4.0.0", "eslint-plugin-prettier": "4.0.0",
"eslint-plugin-promise": "5.1.0", "eslint-plugin-promise": "5.1.1",
"eslint-plugin-unicorn": "36.0.0", "eslint-plugin-unicorn": "38.0.1",
"husky": "7.0.2", "husky": "7.0.4",
"jest": "27.2.5", "jest": "27.3.1",
"jest-mock-extended": "2.0.4", "jest-mock-extended": "2.0.4",
"jest-ts-webcompat-resolver": "1.0.0", "jest-ts-webcompat-resolver": "1.0.0",
"lint-staged": "11.2.1", "lint-staged": "11.2.6",
"markdownlint-cli": "0.29.0", "markdownlint-cli": "0.29.0",
"nodemon": "2.0.13", "nodemon": "2.0.15",
"plop": "2.7.4", "plop": "2.7.6",
"prettier": "2.4.1", "prettier": "2.4.1",
"prisma": "3.2.1", "prisma": "3.4.2",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"semantic-release": "18.0.0", "semantic-release": "18.0.0",
"ts-jest": "27.0.5", "ts-jest": "27.0.7",
"typescript": "4.4.3" "typescript": "4.4.4"
} }
} }

View File

@ -6,8 +6,14 @@ import { date, id } from './utils.js'
export const guildSchema = { export const guildSchema = {
id, id,
name: Type.String({ minLength: 1, maxLength: 30 }), name: Type.String({ minLength: 1, maxLength: 30 }),
icon: Type.Union([Type.String({ format: 'uri-reference' }), Type.Null()]), icon: Type.Union([
description: Type.Union([Type.String({ maxLength: 160 }), Type.Null()]), Type.String({ format: 'uri-reference', minLength: 1 }),
Type.Null()
]),
description: Type.Union([
Type.String({ minLength: 1, maxLength: 160 }),
Type.Null()
]),
createdAt: date.createdAt, createdAt: date.createdAt,
updatedAt: date.updatedAt updatedAt: date.updatedAt
} }

View File

@ -21,10 +21,14 @@ export const userSchema = {
name: Type.String({ minLength: 1, maxLength: 30 }), name: Type.String({ minLength: 1, maxLength: 30 }),
email: Type.String({ minLength: 1, maxLength: 254, format: 'email' }), email: Type.String({ minLength: 1, maxLength: 254, format: 'email' }),
password: Type.String(), password: Type.String(),
logo: Type.String({ format: 'uri-reference' }), logo: Type.String({ minLength: 1, format: 'uri-reference' }),
status: Type.String({ maxLength: 50 }), status: Type.String({ minLength: 1, maxLength: 50 }),
biography: Type.String({ maxLength: 160 }), biography: Type.String({ minLength: 1, maxLength: 160 }),
website: Type.String({ maxLength: 255, format: 'uri-reference' }), website: Type.String({
minLength: 1,
maxLength: 255,
format: 'uri-reference'
}),
isConfirmed: Type.Boolean({ default: false }), isConfirmed: Type.Boolean({ default: false }),
temporaryToken: Type.String(), temporaryToken: Type.String(),
temporaryExpirationToken: Type.String({ format: 'date-time' }), temporaryExpirationToken: Type.String({ format: 'date-time' }),

View File

@ -1,4 +1,4 @@
import { Type } from '@sinclair/typebox' import { Static, Type } from '@sinclair/typebox'
import { FastifyPluginAsync, FastifySchema } from 'fastify' import { FastifyPluginAsync, FastifySchema } from 'fastify'
@ -8,10 +8,16 @@ import authenticateUser from '../../../tools/plugins/authenticateUser.js'
import { guildSchema } from '../../../models/Guild' import { guildSchema } from '../../../models/Guild'
import { import {
getPaginationOptions, getPaginationOptions,
queryPaginationSchema, queryPaginationSchema
QueryPaginationSchemaType
} from '../../../tools/database/pagination' } from '../../../tools/database/pagination'
const querySchema = Type.Object({
search: Type.Optional(Type.String()),
...queryPaginationSchema
})
export type QuerySchemaType = Static<typeof querySchema>
const getServiceSchema: FastifySchema = { const getServiceSchema: FastifySchema = {
description: 'GET all the public guilds.', description: 'GET all the public guilds.',
tags: ['guilds'] as string[], tags: ['guilds'] as string[],
@ -20,7 +26,7 @@ const getServiceSchema: FastifySchema = {
bearerAuth: [] bearerAuth: []
} }
] as Array<{ [key: string]: [] }>, ] as Array<{ [key: string]: [] }>,
querystring: queryPaginationSchema, querystring: querySchema,
response: { response: {
200: Type.Array( 200: Type.Array(
Type.Object({ Type.Object({
@ -39,7 +45,7 @@ export const getGuildsPublic: FastifyPluginAsync = async (fastify) => {
await fastify.register(authenticateUser) await fastify.register(authenticateUser)
fastify.route<{ fastify.route<{
Querystring: QueryPaginationSchemaType Querystring: QuerySchemaType
}>({ }>({
method: 'GET', method: 'GET',
url: '/guilds/public', url: '/guilds/public',
@ -49,7 +55,13 @@ export const getGuildsPublic: FastifyPluginAsync = async (fastify) => {
throw fastify.httpErrors.forbidden() throw fastify.httpErrors.forbidden()
} }
const guildsRequest = await prisma.guild.findMany({ const guildsRequest = await prisma.guild.findMany({
...getPaginationOptions(request.query) ...getPaginationOptions(request.query),
orderBy: { createdAt: 'desc' },
...(request.query.search != null && {
where: {
name: { contains: request.query.search }
}
})
}) })
const guilds = await Promise.all( const guilds = await Promise.all(
guildsRequest.map(async (guild) => { guildsRequest.map(async (guild) => {

View File

@ -1,7 +1,7 @@
import { Prisma } from '@prisma/client' import { Prisma } from '@prisma/client'
import { Static, Type } from '@sinclair/typebox' import { Static, Type } from '@sinclair/typebox'
export const queryPaginationSchema = Type.Object({ export const queryPaginationSchema = {
/** Maximum number of items to return */ /** Maximum number of items to return */
limit: Type.Integer({ default: 20, minimum: 1, maximum: 100 }), limit: Type.Integer({ default: 20, minimum: 1, maximum: 100 }),
@ -12,9 +12,13 @@ export const queryPaginationSchema = Type.Object({
after: Type.Optional( after: Type.Optional(
Type.Integer({ minimum: 1, description: 'Get items after this id' }) Type.Integer({ minimum: 1, description: 'Get items after this id' })
) )
}) }
export type QueryPaginationSchemaType = Static<typeof queryPaginationSchema> export const queryPaginationObjectSchema = Type.Object(queryPaginationSchema)
export type QueryPaginationSchemaType = Static<
typeof queryPaginationObjectSchema
>
export const getPaginationOptions = ( export const getPaginationOptions = (
query: QueryPaginationSchemaType query: QueryPaginationSchemaType