friends-backend
This commit is contained in:
parent
df79bc5a80
commit
590604b385
22 changed files with 1826 additions and 29 deletions
|
|
@ -4,17 +4,19 @@ import { FastifyInstance, FastifyPluginAsync } from 'fastify';
|
|||
import { Database as DbImpl } from './mixin/_base';
|
||||
import { IUserDb, UserImpl } from './mixin/user';
|
||||
import { IBlockedDb, BlockedImpl } from './mixin/blocked';
|
||||
import { IFriendsDb, FriendsImpl } from './mixin/friends';
|
||||
import { ITicTacToeDb, TicTacToeImpl } from './mixin/tictactoe';
|
||||
import { IPongDb, PongImpl } from './mixin/pong';
|
||||
import { ITournamentDb, TournamentImpl } from './mixin/tournament';
|
||||
|
||||
Object.assign(DbImpl.prototype, UserImpl);
|
||||
Object.assign(DbImpl.prototype, BlockedImpl);
|
||||
Object.assign(DbImpl.prototype, FriendsImpl);
|
||||
Object.assign(DbImpl.prototype, TicTacToeImpl);
|
||||
Object.assign(DbImpl.prototype, PongImpl);
|
||||
Object.assign(DbImpl.prototype, TournamentImpl);
|
||||
|
||||
export interface Database extends DbImpl, IUserDb, IBlockedDb, ITicTacToeDb, IPongDb, ITournamentDb { }
|
||||
export interface Database extends DbImpl, IUserDb, IBlockedDb, ITicTacToeDb, IPongDb, ITournamentDb, IFriendsDb { }
|
||||
|
||||
// When using .decorate you have to specify added properties for Typescript
|
||||
declare module 'fastify' {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,15 @@ CREATE TABLE IF NOT EXISTS blocked (
|
|||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_blocked_user_pair ON blocked (user, blocked);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS friends (
|
||||
id INTEGER PRIMARY KEY NOT NULL,
|
||||
user TEXT NOT NULL,
|
||||
friend TEXT NOT NULL,
|
||||
FOREIGN KEY (user) REFERENCES user (id) FOREIGN KEY (friend) REFERENCES user (id)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_friends_user_pair ON friends (user, friend);
|
||||
|
||||
----------------
|
||||
-- TICTACTOE --
|
||||
----------------
|
||||
|
|
|
|||
72
src/@shared/src/database/mixin/friends.ts
Normal file
72
src/@shared/src/database/mixin/friends.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import { isNullish } from '@shared/utils';
|
||||
import type { Database } from './_base';
|
||||
import { UserId } from './user';
|
||||
|
||||
|
||||
// describe every function in the object
|
||||
export interface IFriendsDb extends Database {
|
||||
getFriendsUserFor(id: UserId): FriendsData[],
|
||||
addFriendsUserFor(id: UserId, friend: UserId): void,
|
||||
removeFriendsUserFor(id: UserId, friend: UserId): void,
|
||||
removeAllFriendUserFor(id: UserId): void,
|
||||
getAllFriendsUsers(this: IFriendsDb): FriendsData[] | undefined,
|
||||
|
||||
};
|
||||
|
||||
export const FriendsImpl: Omit<IFriendsDb, keyof Database> = {
|
||||
getFriendsUserFor(this: IFriendsDb, id: UserId): FriendsData[] {
|
||||
const query = this.prepare('SELECT * FROM friends WHERE user = @id');
|
||||
const data = query.all({ id }) as Partial<FriendsData>[];
|
||||
return data.map(friendsFromRow).filter(b => !isNullish(b));
|
||||
},
|
||||
|
||||
removeAllFriendUserFor(this: IFriendsDb, id: UserId): void {
|
||||
this.prepare('DELETE FROM friends WHERE user = @id').run({ id });
|
||||
},
|
||||
addFriendsUserFor(this: IFriendsDb, id: UserId, friend: UserId): void {
|
||||
this.prepare('INSERT OR IGNORE INTO friends (user, friend) VALUES (@id, @friend)').run({ id, friend });
|
||||
},
|
||||
removeFriendsUserFor(this: IFriendsDb, id: UserId, friend: UserId): void {
|
||||
this.prepare('DELETE FROM friends WHERE user = @id AND friend = @friend').run({ id, friend });
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all friends user
|
||||
*
|
||||
* @param
|
||||
*
|
||||
* @returns The list of users if it exists, undefined otherwise
|
||||
*/
|
||||
getAllFriendsUsers(this: IFriendsDb): FriendsData[] {
|
||||
const rows = this.prepare('SELECT * FROM friends').all() as Partial<FriendsData>[];
|
||||
|
||||
return rows
|
||||
.map(row => friendsFromRow(row))
|
||||
.filter((u): u is FriendsData => u !== undefined);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export type FriendsId = number & { readonly __brand: unique symbol };
|
||||
|
||||
export type FriendsData = {
|
||||
readonly id: FriendsId;
|
||||
readonly user: UserId;
|
||||
readonly friend: UserId;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a friends from a row
|
||||
*
|
||||
* @param row The data from sqlite
|
||||
*
|
||||
* @returns The friends if it exists, undefined otherwise
|
||||
*/
|
||||
export function friendsFromRow(row?: Partial<FriendsData>): FriendsData | undefined {
|
||||
if (isNullish(row)) return undefined;
|
||||
if (isNullish(row.id)) return undefined;
|
||||
if (isNullish(row.user)) return undefined;
|
||||
if (isNullish(row.friend)) return undefined;
|
||||
|
||||
return row as FriendsData;
|
||||
}
|
||||
21
src/icons/openapi.json
Normal file
21
src/icons/openapi.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"version": "9.6.1",
|
||||
"title": "@fastify/swagger"
|
||||
},
|
||||
"components": {
|
||||
"schemas": {}
|
||||
},
|
||||
"paths": {},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://local.maix.me:8888",
|
||||
"description": "direct from docker"
|
||||
},
|
||||
{
|
||||
"url": "https://local.maix.me:8000",
|
||||
"description": "using fnginx"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -6,18 +6,17 @@ import sharp from 'sharp';
|
|||
import path from 'path';
|
||||
import fs from 'node:fs/promises';
|
||||
|
||||
|
||||
export const IconSetRes = {
|
||||
'200': typeResponse('success', 'iconset.success'),
|
||||
'400': typeResponse('success', ['iconset.failure.invalidFile', 'iconset.failure.noFile']),
|
||||
'400': typeResponse('success', [
|
||||
'iconset.failure.invalidFile',
|
||||
'iconset.failure.noFile',
|
||||
]),
|
||||
};
|
||||
|
||||
export type IconSetRes = MakeStaticResponse<typeof IconSetRes>;
|
||||
|
||||
const validMimeTypes = new Set([
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
]);
|
||||
const validMimeTypes = new Set(['image/jpeg', 'image/png']);
|
||||
|
||||
async function resizeAndSaveImage(
|
||||
imageBuffer: Buffer,
|
||||
|
|
@ -42,20 +41,42 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
|||
await fastify.register(multipart);
|
||||
fastify.post(
|
||||
'/api/icons/set',
|
||||
{ schema: { response: IconSetRes, operationId: 'setIcons' }, config: { requireAuth: true } },
|
||||
{
|
||||
schema: {
|
||||
response: IconSetRes,
|
||||
hide: true,
|
||||
},
|
||||
config: { requireAuth: true },
|
||||
},
|
||||
async function(req, res) {
|
||||
// req.authUser is always set, since this is gated
|
||||
const userid = req.authUser!.id;
|
||||
const file = await req.file();
|
||||
if (!file) {
|
||||
return res.makeResponse(400, 'failure', 'iconset.failure.noFile');
|
||||
return res.makeResponse(
|
||||
400,
|
||||
'failure',
|
||||
'iconset.failure.noFile',
|
||||
);
|
||||
}
|
||||
if (!validMimeTypes.has(file.mimetype)) {
|
||||
return res.makeResponse(400, 'failure', 'iconset.failure.invalidFile');
|
||||
return res.makeResponse(
|
||||
400,
|
||||
'failure',
|
||||
'iconset.failure.invalidFile',
|
||||
);
|
||||
}
|
||||
const buf = await file.toBuffer();
|
||||
if (!validMimeTypes.has((await fileTypeFromBuffer(buf))?.mime ?? 'unknown')) {
|
||||
return res.makeResponse(400, 'failure', 'iconset.failure.invalidFile');
|
||||
if (
|
||||
!validMimeTypes.has(
|
||||
(await fileTypeFromBuffer(buf))?.mime ?? 'unknown',
|
||||
)
|
||||
) {
|
||||
return res.makeResponse(
|
||||
400,
|
||||
'failure',
|
||||
'iconset.failure.invalidFile',
|
||||
);
|
||||
}
|
||||
try {
|
||||
resizeAndSaveImage(buf, userid);
|
||||
|
|
@ -63,7 +84,11 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
|||
}
|
||||
catch (e: unknown) {
|
||||
this.log.warn(e);
|
||||
return res.makeResponse(400, 'failure', 'iconset.failure.invalidFile');
|
||||
return res.makeResponse(
|
||||
400,
|
||||
'failure',
|
||||
'iconset.failure.invalidFile',
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
|||
320
src/openapi.json
320
src/openapi.json
|
|
@ -1714,6 +1714,326 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/api/user/friend/add/{user}": {
|
||||
"put": {
|
||||
"operationId": "addFriend",
|
||||
"parameters": [
|
||||
{
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"in": "path",
|
||||
"name": "user",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"success"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"addFriend.success"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"notLoggedIn"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"auth.noCookie",
|
||||
"auth.invalidKind",
|
||||
"auth.noUser",
|
||||
"auth.invalid"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"addFriend.failure.unknownUser"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"openapi_other"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/user/friend/list": {
|
||||
"get": {
|
||||
"operationId": "listFriend",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg",
|
||||
"payload"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"success"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"listFriend.success"
|
||||
]
|
||||
},
|
||||
"payload": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"friends"
|
||||
],
|
||||
"properties": {
|
||||
"friends": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"notLoggedIn"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"auth.noCookie",
|
||||
"auth.invalidKind",
|
||||
"auth.noUser",
|
||||
"auth.invalid"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"notLoggedIn"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"auth.noCookie",
|
||||
"auth.invalidKind",
|
||||
"auth.noUser",
|
||||
"auth.invalid"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"openapi_other"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/user/friend/remove/{user}": {
|
||||
"put": {
|
||||
"operationId": "removeFriend",
|
||||
"parameters": [
|
||||
{
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"in": "path",
|
||||
"name": "user",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"success"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"removeFriend.success"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"notLoggedIn"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"auth.noCookie",
|
||||
"auth.invalidKind",
|
||||
"auth.noUser",
|
||||
"auth.invalid"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"removeFriend.failure.unknownUser"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"openapi_other"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/user/info/{user}": {
|
||||
"get": {
|
||||
"operationId": "getUser",
|
||||
|
|
|
|||
|
|
@ -476,6 +476,317 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/user/friend/add/{user}": {
|
||||
"put": {
|
||||
"operationId": "addFriend",
|
||||
"parameters": [
|
||||
{
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"in": "path",
|
||||
"name": "user",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"success"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"addFriend.success"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"notLoggedIn"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"auth.noCookie",
|
||||
"auth.invalidKind",
|
||||
"auth.noUser",
|
||||
"auth.invalid"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"addFriend.failure.unknownUser"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/user/friend/list": {
|
||||
"get": {
|
||||
"operationId": "listFriend",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg",
|
||||
"payload"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"success"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"listFriend.success"
|
||||
]
|
||||
},
|
||||
"payload": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"friends"
|
||||
],
|
||||
"properties": {
|
||||
"friends": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"notLoggedIn"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"auth.noCookie",
|
||||
"auth.invalidKind",
|
||||
"auth.noUser",
|
||||
"auth.invalid"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"notLoggedIn"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"auth.noCookie",
|
||||
"auth.invalidKind",
|
||||
"auth.noUser",
|
||||
"auth.invalid"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/user/friend/remove/{user}": {
|
||||
"put": {
|
||||
"operationId": "removeFriend",
|
||||
"parameters": [
|
||||
{
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"in": "path",
|
||||
"name": "user",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"success"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"removeFriend.success"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"notLoggedIn"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"auth.noCookie",
|
||||
"auth.invalidKind",
|
||||
"auth.noUser",
|
||||
"auth.invalid"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"removeFriend.failure.unknownUser"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/user/info/{user}": {
|
||||
"get": {
|
||||
"operationId": "getUser",
|
||||
|
|
|
|||
44
src/user/src/routes/friendAdd.ts
Normal file
44
src/user/src/routes/friendAdd.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { FastifyPluginAsync } from 'fastify';
|
||||
import { MakeStaticResponse, typeResponse } from '@shared/utils';
|
||||
import Type, { Static } from 'typebox';
|
||||
|
||||
export const AddFriendRes = {
|
||||
'200': typeResponse('success', 'addFriend.success'),
|
||||
'404': typeResponse('failure', 'addFriend.failure.unknownUser'),
|
||||
};
|
||||
|
||||
export type AddFriendRes = MakeStaticResponse<typeof AddFriendRes>;
|
||||
|
||||
const AddFriendParams = Type.Object({
|
||||
user: Type.String(),
|
||||
});
|
||||
export type AddFriendParams = Static<typeof AddFriendParams>;
|
||||
|
||||
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||
void _opts;
|
||||
fastify.put<{ Params: AddFriendParams }>(
|
||||
'/api/user/friend/add/:user',
|
||||
{
|
||||
schema: {
|
||||
params: AddFriendParams,
|
||||
response: AddFriendRes,
|
||||
operationId: 'addFriend',
|
||||
},
|
||||
config: { requireAuth: true },
|
||||
},
|
||||
async function(req, res) {
|
||||
const friend = this.db.getUser(req.params.user);
|
||||
if (!friend) {
|
||||
return res.makeResponse(
|
||||
404,
|
||||
'failure',
|
||||
'addFriend.failure.unknownUser',
|
||||
);
|
||||
}
|
||||
this.db.addFriendsUserFor(req.authUser!.id, friend.id);
|
||||
return res.makeResponse(200, 'success', 'addFriend.success');
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export default route;
|
||||
40
src/user/src/routes/friendList.ts
Normal file
40
src/user/src/routes/friendList.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { FastifyPluginAsync } from 'fastify';
|
||||
import { isNullish, MakeStaticResponse, typeResponse } from '@shared/utils';
|
||||
import Type, { Static } from 'typebox';
|
||||
|
||||
export const ListFriendRes = {
|
||||
'200': typeResponse('success', 'listFriend.success', {
|
||||
friends: Type.Array(Type.Object({
|
||||
id: Type.String(),
|
||||
name: Type.String(),
|
||||
})),
|
||||
}),
|
||||
};
|
||||
|
||||
export type ListFriendRes = MakeStaticResponse<typeof ListFriendRes>;
|
||||
|
||||
const RemoveFriendParams = Type.Object({
|
||||
user: Type.String(),
|
||||
});
|
||||
export type RemoveFriendParams = Static<typeof RemoveFriendParams>;
|
||||
|
||||
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||
void _opts;
|
||||
fastify.get(
|
||||
'/api/user/friend/list',
|
||||
{
|
||||
schema: {
|
||||
response: ListFriendRes,
|
||||
operationId: 'listFriend',
|
||||
},
|
||||
config: { requireAuth: true },
|
||||
},
|
||||
async function(req, res) {
|
||||
void req;
|
||||
const friends: ListFriendRes['200']['payload']['friends'] = this.db.getFriendsUserFor(req.authUser!.id).map(v => this.db.getUser(v.friend)).filter(v => !isNullish(v)).map(v => ({ id: v.id, name: v.name }));
|
||||
return res.makeResponse(200, 'success', 'listFriend.success', { friends });
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export default route;
|
||||
44
src/user/src/routes/friendRemove.ts
Normal file
44
src/user/src/routes/friendRemove.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { FastifyPluginAsync } from 'fastify';
|
||||
import { MakeStaticResponse, typeResponse } from '@shared/utils';
|
||||
import Type, { Static } from 'typebox';
|
||||
|
||||
export const RemoveFriendRes = {
|
||||
'200': typeResponse('success', 'removeFriend.success'),
|
||||
'404': typeResponse('failure', 'removeFriend.failure.unknownUser'),
|
||||
};
|
||||
|
||||
export type RemoveFriendRes = MakeStaticResponse<typeof RemoveFriendRes>;
|
||||
|
||||
const RemoveFriendParams = Type.Object({
|
||||
user: Type.String(),
|
||||
});
|
||||
export type RemoveFriendParams = Static<typeof RemoveFriendParams>;
|
||||
|
||||
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||
void _opts;
|
||||
fastify.put<{ Params: RemoveFriendParams }>(
|
||||
'/api/user/friend/remove/:user',
|
||||
{
|
||||
schema: {
|
||||
params: RemoveFriendParams,
|
||||
response: RemoveFriendRes,
|
||||
operationId: 'removeFriend',
|
||||
},
|
||||
config: { requireAuth: true },
|
||||
},
|
||||
async function(req, res) {
|
||||
const friend = this.db.getUser(req.params.user);
|
||||
if (!friend) {
|
||||
return res.makeResponse(
|
||||
404,
|
||||
'failure',
|
||||
'removeFriend.failure.unknownUser',
|
||||
);
|
||||
}
|
||||
this.db.removeFriendsUserFor(req.authUser!.id, friend.id);
|
||||
return res.makeResponse(200, 'success', 'removeFriend.success');
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export default route;
|
||||
Loading…
Add table
Add a link
Reference in a new issue