diff --git a/package.json b/package.json index ea4a8e0..3077c09 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stiletto-node-api", - "version": "3.6.0", + "version": "3.7.0", "description": "API for [Stiletto Web](https://github.com/dm94/stiletto-web)", "type": "module", "scripts": { @@ -17,7 +17,11 @@ "engines": { "node": ">=20.0.0" }, - "keywords": ["nodejs", "fastify", "typescript"], + "keywords": [ + "nodejs", + "fastify", + "typescript" + ], "author": "Daniel Martín", "bugs": { "url": "https://github.com/dm94/stiletto-node-api/issues" @@ -50,4 +54,4 @@ "typescript": "^5.4.5", "vitest": "^2.1.8" } -} +} \ No newline at end of file diff --git a/src/routes/walkers/index.ts b/src/routes/walkers/index.ts index 675d617..ce18495 100644 --- a/src/routes/walkers/index.ts +++ b/src/routes/walkers/index.ts @@ -1,60 +1,74 @@ -import type { FastifyPluginAsync } from 'fastify'; -import { Type } from '@sinclair/typebox'; -import { type WalkerInfo, WalkerSchema, WalkerType, WalkerUse } from '@customtypes/walkers'; -import type { GetWalkersRequest } from '@customtypes/requests/walkers'; -import { Error401Default, Error405Default, Error503Default } from '@customtypes/errors'; +import type { FastifyPluginAsync } from "fastify"; +import { Type } from "@sinclair/typebox"; +import { + type WalkerInfo, + WalkerSchema, + WalkerType, + WalkerUse, +} from "@customtypes/walkers"; +import type { + AddWalkersRequest, + GetWalkersRequest, +} from "@customtypes/requests/walkers"; +import { + Error400Default, + Error401Default, + Error405Default, + Error503Default, +} from "@customtypes/errors"; +import { randomUUID } from "node:crypto"; const routes: FastifyPluginAsync = async (server) => { server.get( - '/', + "/", { onRequest: [server.authenticate], schema: { - description: 'Return walkers from a discord server', - summary: 'getWalkers', - operationId: 'getWalkers', - tags: ['walkers'], + description: "Return walkers from a discord server", + summary: "getWalkers", + operationId: "getWalkers", + tags: ["walkers"], querystring: { - type: 'object', + type: "object", required: [], properties: { pageSize: { - type: 'integer', + type: "integer", default: 10, minimum: 1, maximum: 100, }, page: { - type: 'integer', + type: "integer", default: 1, minimum: 1, }, name: { - type: 'string', + type: "string", }, owner: { - type: 'string', + type: "string", }, lastuser: { - type: 'string', + type: "string", }, walkerid: { - type: 'string', + type: "string", }, ready: { - type: 'boolean', + type: "boolean", }, use: { - type: 'string', + type: "string", enum: Object.values(WalkerUse), }, type: { - type: 'string', - description: 'Walker Type: Dinghy, Falco...', + type: "string", + description: "Walker Type: Dinghy, Falco...", enum: Object.values(WalkerType), }, description: { - type: 'string', + type: "string", }, }, }, @@ -74,19 +88,26 @@ const routes: FastifyPluginAsync = async (server) => { (request, reply) => { if (!request?.dbuser) { reply.code(401); - return new Error('Invalid token JWT'); + return new Error("Invalid token JWT"); } if (!request?.dbuser.clanid) { reply.code(405); - return new Error('No clan'); + return new Error("No clan"); } let pageSize: number = - request.query?.pageSize && request.query?.pageSize > 0 ? request.query.pageSize : 10; - let page: number = request.query?.page && request.query.page > 0 ? request.query.page : 1; + request.query?.pageSize && request.query?.pageSize > 0 + ? request.query.pageSize + : 10; + let page: number = + request.query?.page && request.query.page > 0 ? request.query.page : 1; - const name: string | undefined = request.query?.name ? `%${request.query.name}%` : undefined; - const owner: string | undefined = request.query?.owner ? request.query.owner : undefined; + const name: string | undefined = request.query?.name + ? `%${request.query.name}%` + : undefined; + const owner: string | undefined = request.query?.owner + ? request.query.owner + : undefined; const lastuser: string | undefined = request.query?.lastuser ? request.query.lastuser : undefined; @@ -94,7 +115,9 @@ const routes: FastifyPluginAsync = async (server) => { ? request.query.walkerid : undefined; const ready: boolean | undefined = request.query?.ready ?? undefined; - const type: WalkerType | undefined = request.query?.type ? request.query.type : undefined; + const type: WalkerType | undefined = request.query?.type + ? request.query.type + : undefined; const use: WalkerUse | undefined = request.query?.use ?? undefined; const description: string | undefined = request.query?.description ? `%${request.query.description}%` @@ -111,39 +134,39 @@ const routes: FastifyPluginAsync = async (server) => { const queryValues: unknown[] = []; let sql = - 'SELECT walkers.walkerID as walkerid, walkers.name, walkers.ownerUser, walkers.lastUser as lastuser, walkers.datelastuse, walkers.type, walkers.walker_use, walkers.isReady, walkers.description from walkers, clans where clans.discordid=walkers.discorid and clans.clanid=?'; + "SELECT walkers.walkerID as walkerid, walkers.name, walkers.ownerUser, walkers.lastUser as lastuser, walkers.datelastuse, walkers.type, walkers.walker_use, walkers.isReady, walkers.description from walkers, clans where clans.discordid=walkers.discorid and clans.clanid=?"; queryValues.push(request.dbuser.clanid); if (name) { - sql += ' and walkers.name like ?'; + sql += " and walkers.name like ?"; queryValues.push(name); } if (owner) { - sql += ' and walkers.ownerUser like ?'; + sql += " and walkers.ownerUser like ?"; queryValues.push(owner); } if (lastuser) { - sql += ' and walkers.lastUser like ?'; + sql += " and walkers.lastUser like ?"; queryValues.push(lastuser); } if (walkerid) { - sql += ' and walkers.walkerID=?'; + sql += " and walkers.walkerID=?"; queryValues.push(walkerid); } if (ready !== undefined) { - sql += ' and walkers.isReady=?'; + sql += " and walkers.isReady=?"; queryValues.push(ready); } if (use) { - sql += ' and walkers.walker_use=?'; + sql += " and walkers.walker_use=?"; queryValues.push(use); } if (description) { - sql += ' and walkers.description like ?'; + sql += " and walkers.description like ?"; queryValues.push(description); } if (type) { - sql += ' and walkers.type=?'; + sql += " and walkers.type=?"; queryValues.push(type); } @@ -159,6 +182,112 @@ const routes: FastifyPluginAsync = async (server) => { }); }, ); + server.post( + "/", + { + onRequest: [server.authenticate], + schema: { + description: "Add a new walker", + summary: "addWalkerFromUser", + operationId: "addWalkerFromUser", + tags: ["walkers"], + body: { + type: "object", + required: ["name"], + properties: { + name: { + type: "string", + }, + owner: { + type: "string", + }, + use: { + type: "string", + enum: Object.values(WalkerUse), + }, + ready: { + type: "boolean", + }, + type: { + type: "string", + enum: Object.values(WalkerType), + }, + description: { + type: "string", + }, + }, + }, + security: [ + { + token: [], + }, + ], + response: { + 201: Type.Object({ + message: Type.String(), + }), + 400: Error400Default, + 401: Error401Default, + 405: Error405Default, + 503: Error503Default, + }, + }, + }, + (request, reply) => { + if (!request?.dbuser) { + reply.code(401); + return new Error("Invalid token JWT"); + } + if (!request?.dbuser.clanid || !request?.dbuser.serverdiscord) { + reply.code(405); + return new Error("No clan"); + } + if (!request?.body?.name) { + return reply.code(400).send("Bad Request"); + } + + const walkerid: string = randomUUID(); + const discordid: string = request.dbuser.serverdiscord; + const name: string = request.body.name; + const lastuser: string = request.dbuser.nickname ?? ""; + const owner: string = + request.body.owner ?? + request.dbuser.nickname ?? + request.dbuser.discordid; + const date = new Date().toISOString().split("T")[0]; + const walkerUse: WalkerUse = request.body.use ?? WalkerUse.PERSONAL; + const ready: boolean = request.body.ready ?? false; + const walkerType: WalkerType = request.body.type ?? WalkerType.DINGHY; + const description: string = request.body.description ?? ""; + + server.mysql.query( + "insert into walkers(walkerID,discorid,name,ownerUser,lastUser,datelastuse, walker_use, type, isReady, description) values(?,?,?,?,?,?,?,?,?,?)", + [ + walkerid, + discordid, + name, + owner, + lastuser, + date, + walkerUse, + walkerType, + ready, + description, + ], + (insertErr, insertResult) => { + if (insertErr) { + return reply.code(503).send(); + } + + if (insertResult) { + return reply.code(201).send({ + message: "Walker created", + }); + } + }, + ); + }, + ); }; export default routes; diff --git a/src/types/requests/walkers.ts b/src/types/requests/walkers.ts index 5d23d10..ddd2a79 100644 --- a/src/types/requests/walkers.ts +++ b/src/types/requests/walkers.ts @@ -16,6 +16,17 @@ export interface GetWalkersRequest extends RequestGenericInterface { }; } +export interface AddWalkersRequest extends RequestGenericInterface { + Body: { + name: string; + owner?: string; + use?: WalkerUse; + ready?: boolean; + type?: WalkerType; + description?: string; + }; +} + export interface EditWalkersRequest extends RequestGenericInterface { Params: { walkerid: string; diff --git a/src/types/walkers.ts b/src/types/walkers.ts index d56cabc..8d05a7d 100644 --- a/src/types/walkers.ts +++ b/src/types/walkers.ts @@ -1,10 +1,16 @@ import { type Static, Type } from '@sinclair/typebox'; export enum WalkerUse { - PVP = 'pvp', - FARMING = 'farming', - PERSONAL = 'personal', - RAM = 'ram', + PVP = "pvp", + FARMING = "farming", + PERSONAL = "personal", + RAM = "ram", + SCOUT = "scout", + RAIDER = "raider", + SUPPORT = "support", + HAULER = "hauler", + CRAFT = "craft", + STORAGE = "storage", } export enum WalkerType {