19 Commits

Author SHA1 Message Date
5591449094 chore(release): 1.2.9 [skip ci] 2023-09-18 20:41:25 +00:00
5532a6a398 fix: update dependencies to latest 2023-09-18 22:36:35 +02:00
2bdcae81b5 build(deps): update latest 2023-08-24 22:17:26 +02:00
cc9fa70498 chore: rename docker-compose.yml to compose.yaml
Ref: https://docs.docker.com/compose/compose-file/03-compose-file/
2023-07-28 12:23:57 +02:00
59cd6083a6 chore(release): 1.2.8 [skip ci] 2023-07-22 14:31:14 +00:00
9a1684e22b fix: update dependencies to latest 2023-07-22 16:26:27 +02:00
23d2a9da71 chore(release): 1.2.7 [skip ci] 2023-07-02 16:58:58 +00:00
8e238f80c5 docs: use ssh to clone the repository 2023-07-02 18:54:02 +02:00
ca7de85e4b chore: enable source maps for easier debugging 2023-07-02 18:52:01 +02:00
ab19598edd fix: update author - Théo LUDWIG 2023-07-02 18:46:58 +02:00
1c1644f243 fix: update dependencies to latest 2023-07-02 18:45:54 +02:00
10110d1a36 chore(release): 1.2.6 [skip ci] 2023-05-13 18:12:41 +00:00
73d2da66b2 fix: update dependencies to latest 2023-05-13 20:09:02 +02:00
b07a62de8b chore(release): 1.2.5 [skip ci] 2023-04-02 21:49:01 +00:00
8a327eb7c7 fix: update dependencies to latest 2023-04-02 23:45:47 +02:00
78d7dbdb3f chore(release): 1.2.4 [skip ci] 2023-01-11 17:04:21 +00:00
e30a66eeb6 fix: update dependencies to latest 2023-01-11 18:02:38 +01:00
12dcabccb3 chore(release): 1.2.3 [skip ci] 2022-12-13 10:40:30 +00:00
224d3b3764 fix: dependencies security vulnerabilities (fastify) 2022-12-13 10:38:59 +00:00
133 changed files with 8845 additions and 19747 deletions

View File

@ -1,7 +1,3 @@
{ {
"extends": ["@commitlint/config-conventional"], "extends": ["@commitlint/config-conventional"]
"rules": {
"body-max-length": [0, "always"],
"body-max-line-length": [0, "always"]
}
} }

View File

@ -1 +1 @@
FROM mcr.microsoft.com/devcontainers/javascript-node:18 FROM mcr.microsoft.com/devcontainers/javascript-node:20

View File

@ -1,5 +1,3 @@
version: '3.0'
services: services:
workspace: workspace:
build: build:
@ -8,23 +6,18 @@ services:
volumes: volumes:
- '..:/workspace:cached' - '..:/workspace:cached'
command: 'sleep infinity' command: 'sleep infinity'
extra_hosts: network_mode: 'host'
- 'host.docker.internal:host-gateway'
thream-database: thream-database:
image: 'postgres:15.0' image: 'postgres:15.4'
environment: environment:
POSTGRES_USER: 'user' POSTGRES_USER: 'thream_user'
POSTGRES_PASSWORD: 'password' POSTGRES_PASSWORD: 'password'
POSTGRES_DB: 'thream' POSTGRES_DB: 'thream'
volumes: volumes:
- 'postgres-data:/var/lib/postgresql/data' - 'thream-postgres-data:/var/lib/postgresql/data'
restart: 'unless-stopped' restart: 'unless-stopped'
network_mode: 'host'
thream-maildev:
image: 'maildev/maildev:1.1.0'
ports:
- '1080:80'
volumes: volumes:
postgres-data: thream-postgres-data:

View File

@ -1,10 +1,14 @@
{ {
"name": "@thream/api", "name": "@thream/api",
"dockerComposeFile": "./docker-compose.yml", "dockerComposeFile": "./compose.yaml",
"service": "workspace", "service": "workspace",
"workspaceFolder": "/workspace", "workspaceFolder": "/workspace",
"customizations": {
"vscode": {
"settings": { "settings": {
"remote.autoForwardPorts": false "remote.autoForwardPorts": false,
"remote.localPortHost": "allInterfaces"
}
}, },
"extensions": [ "extensions": [
"editorconfig.editorconfig", "editorconfig.editorconfig",
@ -14,8 +18,7 @@
"prisma.prisma", "prisma.prisma",
"mikestead.dotenv", "mikestead.dotenv",
"ms-azuretools.vscode-docker" "ms-azuretools.vscode-docker"
], ]
"forwardPorts": [8080, 5555, 5432, 1080], },
"postAttachCommand": ["npm", "install"],
"remoteUser": "node" "remoteUser": "node"
} }

View File

@ -1,9 +1,6 @@
.vscode .*
.git !.npmrc
.env !.swcrc
build build
coverage coverage
.nyc_output
node_modules node_modules
tmp
temp

View File

@ -1,14 +1,22 @@
API_URL=http://localhost:8080 API_URL=http://127.0.0.1:8080
COMPOSE_PROJECT_NAME=thream-api COMPOSE_PROJECT_NAME=thream-api
DATABASE_URL=postgresql://user:password@thream-database:5432/thream
DATABASE_USER=thream_user
DATABASE_PASSWORD=password
DATABASE_NAME=thream
DATABASE_URL=postgresql://thream_user:password@127.0.0.1:5432/thream
EMAIL_HOST=0.0.0.0
EMAIL_PASSWORD=password
EMAIL_PORT=1025
EMAIL_USER=no-reply@thream.fr
DISCORD_CLIENT_ID= DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET= DISCORD_CLIENT_SECRET=
EMAIL_HOST=thream-maildev
EMAIL_PASSWORD=password
EMAIL_PORT=25
EMAIL_USER=no-reply@thream.fr
FILE_UPLOADS_API_KEY=apiKeySecret FILE_UPLOADS_API_KEY=apiKeySecret
FILE_UPLOADS_API_URL=http://host.docker.internal:8000 FILE_UPLOADS_API_URL=http://127.0.0.1:8000
GITHUB_CLIENT_ID= GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET= GITHUB_CLIENT_SECRET=
GOOGLE_CLIENT_ID= GOOGLE_CLIENT_ID=

View File

@ -1,16 +1,13 @@
{ {
"extends": ["conventions", "prettier"], "extends": ["conventions", "prettier"],
"plugins": ["prettier", "import", "unicorn"], "plugins": ["prettier", "import", "unicorn"],
"parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"project": "./tsconfig.json" "project": "./tsconfig.json"
}, },
"env": {
"node": true
},
"rules": { "rules": {
"prettier/prettier": "error", "prettier/prettier": "error",
"import/extensions": ["error", "always"], "import/extensions": ["error", "always"],
"unicorn/prevent-abbreviations": "error", "unicorn/prevent-abbreviations": "error"
"unicorn/prefer-node-protocol": "error"
} }
} }

View File

@ -1,6 +1,6 @@
<!-- Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time. --> <!-- Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time. -->
## What changes this PR introduce? # What changes this PR introduce?
## List any relevant issue numbers ## List any relevant issue numbers

View File

@ -16,7 +16,7 @@ jobs:
language: ['javascript'] language: ['javascript']
steps: steps:
- uses: 'actions/checkout@v3.0.0' - uses: 'actions/checkout@v4.0.0'
- name: 'Initialize CodeQL' - name: 'Initialize CodeQL'
uses: 'github/codeql-action/init@v2' uses: 'github/codeql-action/init@v2'

View File

@ -10,16 +10,18 @@ jobs:
build: build:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.1.0' - uses: 'actions/checkout@v4.0.0'
- name: 'Use Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.5.1' uses: 'actions/setup-node@v3.8.1'
with: with:
node-version: '18.x' node-version: '20.x'
cache: 'npm' cache: 'npm'
- name: 'Install' - name: 'Install dependencies'
run: 'npm install' run: 'npm clean-install'
- name: 'Build' - name: 'Build'
run: 'npm run build' run: 'npm run build'
- run: 'npm run build:typescript'

View File

@ -10,16 +10,16 @@ jobs:
lint: lint:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.1.0' - uses: 'actions/checkout@v4.0.0'
- name: 'Use Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.5.1' uses: 'actions/setup-node@v3.8.1'
with: with:
node-version: '18.x' node-version: '20.x'
cache: 'npm' cache: 'npm'
- name: 'Install' - name: 'Install dependencies'
run: 'npm install' run: 'npm clean-install'
- name: 'lint:commit' - name: 'lint:commit'
run: 'npm run lint:commit -- --to "${{ github.sha }}"' run: 'npm run lint:commit -- --to "${{ github.sha }}"'
@ -30,21 +30,11 @@ jobs:
- name: 'lint:markdown' - name: 'lint:markdown'
run: 'npm run lint:markdown' run: 'npm run lint:markdown'
- name: 'lint:typescript' - name: 'lint:eslint'
run: 'npm run lint:typescript' run: 'npm run lint:eslint'
- name: 'lint:prettier' - name: 'lint:prettier'
run: 'npm run lint:prettier' run: 'npm run lint:prettier'
- name: 'lint:dotenv'
uses: 'dotenv-linter/action-dotenv-linter@v2'
with:
github_token: ${{ secrets.github_token }}
- name: 'lint:docker'
uses: 'hadolint/hadolint-action@v1.6.0'
with:
dockerfile: './Dockerfile'
- name: 'prisma:validate' - name: 'prisma:validate'
run: 'cp .env.example .env && npm run prisma:validate' run: 'cp .env.example .env && npm run prisma:validate'

View File

@ -8,30 +8,32 @@ jobs:
release: release:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.1.0' - uses: 'actions/checkout@v4.0.0'
with: with:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
- name: 'Import GPG key' - name: 'Import GPG key'
uses: 'crazy-max/ghaction-import-gpg@v3.2.0' uses: 'crazy-max/ghaction-import-gpg@v6.0.0'
with: with:
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
git-user-signingkey: true git_user_signingkey: true
git-commit-gpgsign: true git_commit_gpgsign: true
- name: 'Use Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.5.1' uses: 'actions/setup-node@v3.8.1'
with: with:
node-version: '18.x' node-version: '20.x'
cache: 'npm' cache: 'npm'
- name: 'Install' - name: 'Install dependencies'
run: 'npm install' run: 'npm clean-install'
- name: 'Build' - name: 'Build'
run: 'npm run build' run: 'npm run build'
- run: 'npm run build:typescript'
- name: 'Release' - name: 'Release'
run: 'npm run release' run: 'npm run release'
env: env:

View File

@ -10,16 +10,16 @@ jobs:
test: test:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.1.0' - uses: 'actions/checkout@v4.0.0'
- name: 'Use Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.5.1' uses: 'actions/setup-node@v3.8.1'
with: with:
node-version: '18.x' node-version: '20.x'
cache: 'npm' cache: 'npm'
- name: 'Install' - name: 'Install dependencies'
run: 'npm install' run: 'npm clean-install'
- name: 'Build' - name: 'Build'
run: 'npm run build' run: 'npm run build'

View File

@ -3,3 +3,4 @@
npm run lint:staged npm run lint:staged
npm run build npm run build
npm run build:typescript

View File

@ -1,10 +1,11 @@
{ {
"config": { "config": {
"extends": "markdownlint/style/prettier",
"relative-links": true,
"default": true, "default": true,
"MD013": false, "MD033": false
"MD033": false,
"MD041": false
}, },
"globs": ["**/*.{md,mdx}"], "globs": ["**/*.{md,mdx}"],
"ignores": ["**/node_modules"] "ignores": ["**/node_modules"],
"customRules": ["markdownlint-rule-relative-links"]
} }

View File

@ -1,5 +0,0 @@
{
"reporter": ["text", "cobertura"],
"src": "./build",
"all": true
}

3
.swcrc
View File

@ -1,10 +1,11 @@
{ {
"sourceMaps": true,
"jsc": { "jsc": {
"parser": { "parser": {
"syntax": "typescript", "syntax": "typescript",
"dynamicImport": true "dynamicImport": true
}, },
"target": "es2022" "target": "esnext"
}, },
"module": { "module": {
"type": "es6" "type": "es6"

8
.taprc
View File

@ -1,8 +0,0 @@
ts: false
jsx: false
flow: false
check-coverage: false
coverage: false
files:
- 'build/**/*.test.js'

View File

@ -60,7 +60,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at reported to the community leaders responsible for enforcement at
contact@divlo.fr. <contact@theoludwig.fr>.
All complaints will be reviewed and investigated promptly and fairly. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the All community leaders are obligated to respect the privacy and security of the

View File

@ -29,31 +29,7 @@ If you're adding new features to **Thream/api**, please include tests.
## Commits ## Commits
The commit message guidelines respect The commit message guidelines adheres to [Conventional Commits](https://www.conventionalcommits.org/) and [Semantic Versioning](https://semver.org/) for releases.
[@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional)
and [Semantic Versioning](https://semver.org/) for releases.
### Types
Types define which kind of changes you made to the project.
| Types | Description |
| -------- | ------------------------------------------------------------------------------------------------------------ |
| feat | A new feature. |
| fix | A bug fix. |
| docs | Documentation only changes. |
| style | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc). |
| refactor | A code change that neither fixes a bug nor adds a feature. |
| perf | A code change that improves performance. |
| test | Adding missing tests or correcting existing tests. |
| build | Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm). |
| ci | Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs). |
| chore | Other changes that don't modify src or test files. |
| revert | Reverts a previous commit. |
### Scopes
Scopes define what part of the code changed.
### Examples ### Examples
@ -91,7 +67,7 @@ git commit -m "fix: should emit events to connected users"
We have API REST services for the `channels`. We have API REST services for the `channels`.
Here is what potentially look like a folder structure for this service : Here is what potentially look like a folder structure for this service:
```text ```text
└── src └── src
@ -110,7 +86,7 @@ Here is what potentially look like a folder structure for this service :
└── index.ts └── index.ts
``` ```
This folder structure will map to these REST API routes : This folder structure will map to these REST API routes:
- GET `/channels` - GET `/channels`
- DELETE `/channels/:channelId` - DELETE `/channels/:channelId`

View File

@ -1,21 +1,22 @@
FROM node:18.12.1 AS dependencies FROM node:20.6.1 AS dependencies
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY ./package*.json ./ COPY ./package*.json ./
RUN npm install RUN npm clean-install
FROM node:18.12.1 AS builder FROM node:20.6.1 AS builder
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY --from=dependencies /usr/src/app/node_modules ./node_modules COPY --from=dependencies /usr/src/app/node_modules ./node_modules
COPY ./ ./ COPY ./ ./
RUN npm run prisma:generate && npm run build RUN npm run prisma:generate && npm run build
FROM node:18.12.1 AS runner FROM node:20.6.1 AS runner
WORKDIR /usr/src/app WORKDIR /usr/src/app
ENV NODE_ENV=production ENV NODE_ENV=production
ENV NODE_OPTIONS=--enable-source-maps
COPY --from=builder /usr/src/app/node_modules ./node_modules COPY --from=builder /usr/src/app/node_modules ./node_modules
COPY --from=builder /usr/src/app/package.json ./package.json COPY --from=builder /usr/src/app/package.json ./package.json
COPY --from=builder /usr/src/app/email ./email COPY --from=builder /usr/src/app/email ./email
COPY --from=builder /usr/src/app/build ./build COPY --from=builder /usr/src/app/build ./build
COPY --from=builder /usr/src/app/prisma ./prisma COPY --from=builder /usr/src/app/prisma ./prisma
USER node USER node
CMD ["node", "build/index.js"] CMD npm run prisma:migrate:deploy && node build/index.js

View File

@ -1,4 +1,4 @@
<h1 align="center"><a href="https://api.thream.divlo.fr/documentation">Thream/api</a></h1> <h1 align="center"><a href="https://api.thream.theoludwig.fr/documentation">Thream/api</a></h1>
<p align="center"> <p align="center">
<a href="./CONTRIBUTING.md"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" /></a> <a href="./CONTRIBUTING.md"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" /></a>
@ -18,7 +18,7 @@
Thream's Application Programming Interface (API) to stay close with your friends and communities. Thream's Application Programming Interface (API) to stay close with your friends and communities.
It uses [Thream/file-uploads-api](https://github.com/Thream/file-uploads-api) [v1.1.0](https://github.com/Thream/file-uploads-api/releases/tag/v1.1.0). It uses [Thream/file-uploads-api](https://github.com/Thream/file-uploads-api) [v1.1.7](https://github.com/Thream/file-uploads-api/releases/tag/v1.1.7).
## ⚙️ Getting Started ## ⚙️ Getting Started
@ -32,50 +32,80 @@ It uses [Thream/file-uploads-api](https://github.com/Thream/file-uploads-api) [v
```sh ```sh
# Clone the repository # Clone the repository
git clone https://github.com/Thream/api.git git clone git@github.com:Thream/api.git
# Go to the project root # Go to the project root
cd api cd api
# Install dependencies
npm clean-install
# Configure environment variables # Configure environment variables
cp .env.example .env cp .env.example .env
# Install # Generate Prisma client types
npm install npm run prisma:generate
``` ```
You will need to configure the environment variables by creating an `.env` file at ### Database Setup
the root of the project (see `.env.example`).
```sh
# Create a new user and database
psql
CREATE DATABASE thream;
CREATE USER thream_user with encrypted password 'password';
ALTER USER thream_user WITH SUPERUSER;
```
### Database Production migration
```sh
npm run prisma:migrate:deploy
```
### Local Development environment ### Local Development environment
Recommended to use [VSCode: Remote development in Containers](https://code.visualstudio.com/docs/remote/containers-tutorial). Recommended to use [VSCode: Remote development in Containers](https://code.visualstudio.com/docs/remote/containers-tutorial).
#### Setup the database #### Database Development migration
```sh
# Create a new user and database
psql
create database thream_database;
create user thream_user with encrypted password 'password';
ALTER USER thream_user WITH SUPERUSER;
```
Replace `DATABASE_URL` inside `.env` with `postgresql://thream_user:password@localhost:5432/thream_database`
```sh ```sh
# Run Prisma migrations # Run Prisma migrations
npm run prisma:migrate:dev npm run prisma:migrate:dev
# Reset the database (WARNING: This will delete all data)
npm run prisma:migrate:reset
``` ```
#### Usage #### Usage
```sh ```sh
# Run API
npm run dev npm run dev
```
# Run Prisma Studio ##### Services started
npm run prisma:studio
- `api`: <http://127.0.0.1:8080>
- [Maildev](https://maildev.github.io/maildev/): <http://127.0.0.1:1080>
- [Prisma Studio](https://www.prisma.io/studio): <http://127.0.0.1:5555>
##### Commands
```sh
# Build, Lint and Test
npm run build
npm run build:typescript
npm run lint:editorconfig
npm run lint:markdown
npm run lint:eslint
npm run lint:prettier
npm run test
```
### Production environment (with [Docker](https://www.docker.com/))
```sh
docker compose up --build
``` ```
## 💡 Contributing ## 💡 Contributing

27
compose.yaml Normal file
View File

@ -0,0 +1,27 @@
services:
thream-api:
container_name: 'thream-api'
image: 'thream-api'
restart: 'unless-stopped'
network_mode: 'host'
build:
context: './'
env_file: '.env'
depends_on:
- 'thream-database'
thream-database:
container_name: 'thream-database'
image: 'postgres:15.4'
restart: 'unless-stopped'
network_mode: 'host'
env_file: '.env'
environment:
POSTGRES_USER: ${DATABASE_USER}
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
POSTGRES_DB: ${DATABASE_NAME}
volumes:
- 'thream-postgres-data:/var/lib/postgresql/data'
volumes:
thream-postgres-data:

View File

@ -1,18 +1,20 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from 'application.js' import { application } from '#src/application.js'
{{#if shouldBeAuthenticated}} {{#if shouldBeAuthenticated}}
import { authenticateUserTest } from '__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
{{/if}} {{/if}}
import prisma from 'tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
await tap.test('{{httpMethod}} {{url}}', async (t) => { await test('{{httpMethod}} {{url}}', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
{{#if shouldBeAuthenticated}} {{#if shouldBeAuthenticated}}
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
{{/if}} {{/if}}
@ -32,6 +34,6 @@ await tap.test('{{httpMethod}} {{url}}', async (t) => {
payload: {} payload: {}
}) })
// const responseJson = response.json() // const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
}) })
}) })

View File

@ -1,10 +1,10 @@
import { Static, Type } from '@sinclair/typebox' import { Static, Type } from '@sinclair/typebox'
import { FastifyPluginAsync, FastifySchema } from 'fastify' import { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from 'tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from 'models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
{{#if shouldBeAuthenticated}} {{#if shouldBeAuthenticated}}
import authenticateUser from 'tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
{{/if}} {{/if}}
const body{{sentenceCase httpMethod}}ServiceSchema = Type.Object({ const body{{sentenceCase httpMethod}}ServiceSchema = Type.Object({

25971
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,105 +1,110 @@
{ {
"name": "@thream/api", "name": "@thream/api",
"version": "1.2.2", "version": "1.2.9",
"description": "Thream's application programming interface to stay close with your friends and communities.", "description": "Thream's application programming interface to stay close with your friends and communities.",
"private": true, "private": true,
"type": "module", "type": "module",
"repository": { "imports": {
"type": "git", "#src/*": "./build/*"
"url": "https://github.com/Thream/api"
}, },
"engines": { "engines": {
"node": ">=16.0.0", "node": ">=16.0.0",
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"repository": {
"type": "git",
"url": "https://github.com/Thream/api"
},
"scripts": { "scripts": {
"build": "rimraf ./build && swc ./src --out-dir ./build && tsc", "build": "rimraf ./build && swc ./src --out-dir ./build",
"build:dev": "swc ./src --out-dir ./build --watch", "build:typescript": "tsc",
"start": "node build/index.js", "start": "node --enable-source-maps build/index.js",
"dev": "concurrently -k -n \"TypeScript,Node\" -p \"[{name}]\" -c \"blue,green\" \"npm run build:dev\" \"cross-env NODE_ENV=development nodemon build/index.js\"", "dev:build": "swc ./src --out-dir ./build --watch",
"dev": "concurrently --kill-others --names \"TypeScript,Node,Maildev,Prisma Studio\" \"npm run dev:build\" \"cross-env NODE_ENV=development node --watch --enable-source-maps build/index.js\" \"npm run maildev\" \"npm run prisma:studio\"",
"maildev": "maildev",
"generate": "plop", "generate": "plop",
"generate:jwt-secret": "node ./build/scripts/generate-jwt-secret.js", "generate:jwt-secret": "node --enable-source-maps ./build/scripts/generate-jwt-secret.js",
"lint:commit": "commitlint", "lint:commit": "commitlint",
"lint:editorconfig": "editorconfig-checker", "lint:editorconfig": "editorconfig-checker",
"lint:markdown": "markdownlint-cli2", "lint:markdown": "markdownlint-cli2",
"lint:typescript": "eslint \"**/*.{js,jsx,ts,tsx}\" --ignore-path \".gitignore\"", "lint:eslint": "eslint . --max-warnings 0 --report-unused-disable-directives --ignore-path .gitignore",
"lint:prettier": "prettier \".\" --check --ignore-path \".gitignore\"", "lint:prettier": "prettier . --check",
"lint:staged": "lint-staged", "lint:staged": "lint-staged",
"test": "cross-env NODE_ENV=test c8 tap", "test": "cross-env NODE_ENV=test node --enable-source-maps --test build/",
"prisma:validate": "prisma validate", "prisma:validate": "prisma validate",
"prisma:generate": "prisma generate", "prisma:generate": "prisma generate",
"prisma:studio": "prisma studio", "prisma:studio": "prisma studio --browser=none",
"prisma:migrate:dev": "prisma migrate dev", "prisma:migrate:dev": "prisma migrate dev",
"prisma:migrate:deploy": "prisma migrate deploy", "prisma:migrate:deploy": "prisma migrate deploy",
"release": "semantic-release", "release": "semantic-release",
"postinstall": "husky install" "postinstall": "husky install"
}, },
"dependencies": { "dependencies": {
"@fastify/cors": "8.2.0", "@fastify/cors": "8.3.0",
"@fastify/helmet": "10.0.2", "@fastify/helmet": "11.1.1",
"@fastify/multipart": "7.3.0", "@fastify/multipart": "7.7.3",
"@fastify/rate-limit": "7.5.0", "@fastify/rate-limit": "8.0.3",
"@fastify/sensible": "5.1.1", "@fastify/sensible": "5.3.0",
"@fastify/swagger": "8.1.0", "@fastify/swagger": "8.10.0",
"@fastify/swagger-ui": "1.2.0", "@fastify/swagger-ui": "1.9.3",
"@prisma/client": "4.5.0", "@prisma/client": "5.3.1",
"@sinclair/typebox": "0.25.3", "@sinclair/typebox": "0.31.15",
"@thream/socketio-jwt": "3.0.1", "@thream/socketio-jwt": "3.1.3",
"axios": "1.1.3", "axios": "1.5.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"dotenv": "16.0.3", "dotenv": "16.3.1",
"ejs": "3.1.8", "ejs": "3.1.9",
"fastify": "4.9.2", "fastify": "4.23.2",
"fastify-plugin": "4.3.0", "fastify-plugin": "4.5.1",
"form-data": "4.0.0", "form-data": "4.0.0",
"http-errors": "2.0.0", "http-errors": "2.0.0",
"jsonwebtoken": "8.5.1", "jsonwebtoken": "9.0.2",
"ms": "2.1.3", "ms": "2.1.3",
"nodemailer": "6.8.0", "nodemailer": "6.9.5",
"read-pkg": "7.1.0", "read-pkg": "8.1.0",
"socket.io": "4.5.3" "socket.io": "4.7.2"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "17.2.0", "@commitlint/cli": "17.7.1",
"@commitlint/config-conventional": "17.2.0", "@commitlint/config-conventional": "17.7.0",
"@saithodev/semantic-release-backmerge": "2.1.2", "@saithodev/semantic-release-backmerge": "3.2.0",
"@semantic-release/git": "10.0.1", "@semantic-release/git": "10.0.1",
"@swc/cli": "0.1.57", "@swc/cli": "0.1.62",
"@swc/core": "1.3.14", "@swc/core": "1.3.85",
"@types/bcryptjs": "2.4.2", "@tsconfig/strictest": "2.0.2",
"@types/busboy": "1.5.0", "@types/bcryptjs": "2.4.4",
"@types/ejs": "3.1.1", "@types/busboy": "1.5.1",
"@types/http-errors": "1.8.2", "@types/ejs": "3.1.2",
"@types/jsonwebtoken": "8.5.9", "@types/http-errors": "2.0.2",
"@types/jsonwebtoken": "9.0.3",
"@types/ms": "0.7.31", "@types/ms": "0.7.31",
"@types/node": "18.11.9", "@types/node": "20.6.2",
"@types/nodemailer": "6.4.6", "@types/nodemailer": "6.4.10",
"@types/sinon": "10.0.13", "@types/sinon": "10.0.16",
"@types/tap": "15.0.7", "@typescript-eslint/eslint-plugin": "6.7.2",
"@typescript-eslint/eslint-plugin": "5.42.1", "@typescript-eslint/parser": "6.7.2",
"@typescript-eslint/parser": "5.42.1", "chokidar": "3.5.3",
"c8": "7.12.0", "concurrently": "8.2.1",
"concurrently": "7.5.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"editorconfig-checker": "4.0.2", "editorconfig-checker": "5.1.1",
"eslint": "8.27.0", "eslint": "8.49.0",
"eslint-config-conventions": "5.0.0", "eslint-config-conventions": "11.0.1",
"eslint-config-prettier": "8.5.0", "eslint-config-prettier": "9.0.0",
"eslint-plugin-import": "2.26.0", "eslint-plugin-import": "2.28.1",
"eslint-plugin-prettier": "4.2.1", "eslint-plugin-prettier": "5.0.0",
"eslint-plugin-promise": "6.1.1", "eslint-plugin-promise": "6.1.1",
"eslint-plugin-unicorn": "44.0.2", "eslint-plugin-unicorn": "48.0.1",
"husky": "8.0.2", "husky": "8.0.3",
"lint-staged": "13.0.3", "lint-staged": "14.0.1",
"markdownlint-cli2": "0.5.1", "maildev": "2.1.0",
"nodemon": "2.0.20", "markdownlint-cli2": "0.10.0",
"plop": "3.1.1", "markdownlint-rule-relative-links": "2.1.0",
"prettier": "2.7.1", "plop": "4.0.0",
"prisma": "4.5.0", "prettier": "3.0.3",
"rimraf": "3.0.2", "prisma": "5.3.1",
"semantic-release": "19.0.5", "rimraf": "5.0.1",
"sinon": "14.0.2", "semantic-release": "21.1.1",
"tap": "16.3.0", "sinon": "16.0.0",
"typescript": "4.8.4" "typescript": "5.2.2"
} }
} }

View File

@ -1,45 +1,46 @@
import type { User } from '@prisma/client' import type { User } from '@prisma/client'
import sinon from 'sinon' import sinon from 'sinon'
import { refreshTokenExample } from '../../models/RefreshToken.js' import { refreshTokenExample } from '#src/models/RefreshToken.js'
import type { UserJWT } from '../../models/User.js' import type { UserJWT } from '#src/models/User.js'
import { userExample } from '../../models/User.js' import { userExample } from '#src/models/User.js'
import { userSettingsExample } from '../../models/UserSettings.js' import { userSettingsExample } from '#src/models/UserSettings.js'
import { import {
generateAccessToken, generateAccessToken,
generateRefreshToken generateRefreshToken
} from '../../tools/utils/jwtToken.js' } from '#src/tools/utils/jwtToken.js'
import prisma from '../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
const userStubValue = {
findUnique: async () => {
return userExample
}
}
const userSettingStubValue = {
findFirst: async () => {
return userSettingsExample
}
}
const oAuthStubValue = {
findMany: async () => {
return []
}
}
const refreshTokenStubValue = {
create: async () => {
return refreshTokenExample
}
}
export const authenticateUserTest = async (): Promise<{ export const authenticateUserTest = async (): Promise<{
accessToken: string accessToken: string
refreshToken: string refreshToken: string
user: User user: User
userStubValue: any userStubValue: typeof userStubValue
userSettingStubValue: any userSettingStubValue: typeof userSettingStubValue
oAuthStubValue: any oAuthStubValue: typeof oAuthStubValue
refreshTokenStubValue: any refreshTokenStubValue: typeof refreshTokenStubValue
}> => { }> => {
const userStubValue = {
findUnique: async () => {
return userExample
}
}
const userSettingStubValue = {
findFirst: async () => {
return userSettingsExample
}
}
const oAuthStubValue = {
findMany: async () => {
return []
}
}
const refreshTokenStubValue = {
create: async () => {
return refreshTokenExample
}
}
sinon.stub(prisma, 'user').value(userStubValue) sinon.stub(prisma, 'user').value(userStubValue)
sinon.stub(prisma, 'userSetting').value(userSettingStubValue) sinon.stub(prisma, 'userSetting').value(userSettingStubValue)
sinon.stub(prisma, 'oAuth').value(oAuthStubValue) sinon.stub(prisma, 'oAuth').value(oAuthStubValue)

View File

@ -8,13 +8,13 @@ import fastifyRateLimit from '@fastify/rate-limit'
import fastifySensible from '@fastify/sensible' import fastifySensible from '@fastify/sensible'
import { readPackage } from 'read-pkg' import { readPackage } from 'read-pkg'
import { services } from './services/index.js' import { services } from '#src/services/index.js'
import fastifySocketIo from './tools/plugins/socket-io.js' import fastifySocketIo from '#src/tools/plugins/socket-io.js'
dotenv.config() dotenv.config()
const packageJSON = await readPackage() const packageJSON = await readPackage()
export const application = fastify({ export const application = fastify({
logger: process.env.NODE_ENV === 'development', logger: process.env['NODE_ENV'] === 'development',
ajv: { ajv: {
customOptions: { customOptions: {
strict: 'log', strict: 'log',

View File

@ -1,8 +1,8 @@
import { application } from './application.js' import { application } from '#src/application.js'
import { HOST, PORT } from './tools/configurations.js' import { HOST, PORT } from '#src/tools/configurations.js'
const address = await application.listen({ const address = await application.listen({
port: PORT, port: PORT,
host: HOST host: HOST
}) })
console.log('\u001B[36m%s\u001B[0m', `🚀 Server listening at ${address}`) console.log(`Server listening at ${address}`)

View File

@ -1,8 +1,8 @@
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { Channel } from '@prisma/client' import type { Channel } from '@prisma/client'
import { date, id } from './utils.js' import { date, id } from '#src/models/utils.js'
import { guildExample } from './Guild.js' import { guildExample } from '#src/models/Guild.js'
export const types = [Type.Literal('text')] export const types = [Type.Literal('text')]

View File

@ -1,7 +1,7 @@
import type { Guild } from '@prisma/client' import type { Guild } from '@prisma/client'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import { date, id } from './utils.js' import { date, id } from '#src/models/utils.js'
export const guildSchema = { export const guildSchema = {
id, id,

View File

@ -1,9 +1,9 @@
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { Member } from '@prisma/client' import type { Member } from '@prisma/client'
import { date, id } from './utils.js' import { date, id } from '#src/models/utils.js'
import { guildExample } from './Guild.js' import { guildExample } from '#src/models/Guild.js'
import { userExample } from './User.js' import { userExample } from '#src/models/User.js'
export const memberSchema = { export const memberSchema = {
id, id,

View File

@ -1,7 +1,7 @@
import type { Message } from '@prisma/client' import type { Message } from '@prisma/client'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import { date, id } from './utils.js' import { date, id } from '#src/models/utils.js'
export const types = [Type.Literal('text'), Type.Literal('file')] export const types = [Type.Literal('text'), Type.Literal('file')]

View File

@ -1,6 +1,6 @@
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import { date, id } from './utils.js' import { date, id } from '#src/models/utils.js'
export const providers = ['Google', 'GitHub', 'Discord'] as const export const providers = ['Google', 'GitHub', 'Discord'] as const
export const strategies = [...providers, 'Local'] as const export const strategies = [...providers, 'Local'] as const
@ -12,8 +12,8 @@ export const providersTypebox = providers.map((provider) => {
return Type.Literal(provider) return Type.Literal(provider)
}) })
export type ProviderOAuth = typeof providers[number] export type ProviderOAuth = (typeof providers)[number]
export type AuthenticationStrategy = typeof strategies[number] export type AuthenticationStrategy = (typeof strategies)[number]
export const oauthSchema = { export const oauthSchema = {
id, id,

View File

@ -1,8 +1,8 @@
import type { RefreshToken } from '@prisma/client' import type { RefreshToken } from '@prisma/client'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import { userExample } from './User.js' import { userExample } from '#src/models/User.js'
import { date, id } from './utils.js' import { date, id } from '#src/models/utils.js'
export const refreshTokensSchema = { export const refreshTokensSchema = {
id, id,

View File

@ -2,10 +2,10 @@ import type { User } from '@prisma/client'
import type { Static } from '@sinclair/typebox' import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { AuthenticationStrategy } from './OAuth.js' import type { AuthenticationStrategy } from '#src/models/OAuth.js'
import { strategiesTypebox } from './OAuth.js' import { strategiesTypebox } from '#src/models/OAuth.js'
import { userSettingsSchema } from './UserSettings.js' import { userSettingsSchema } from '#src/models/UserSettings.js'
import { date, id } from './utils.js' import { date, id } from '#src/models/utils.js'
export interface UserJWT { export interface UserJWT {
id: number id: number

View File

@ -2,7 +2,7 @@ import type { UserSetting } from '@prisma/client'
import type { Static } from '@sinclair/typebox' import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import { date, id } from './utils.js' import { date, id } from '#src/models/utils.js'
export const languages = [Type.Literal('fr'), Type.Literal('en')] export const languages = [Type.Literal('fr'), Type.Literal('en')]
export const themes = [Type.Literal('light'), Type.Literal('dark')] export const themes = [Type.Literal('light'), Type.Literal('dark')]

View File

@ -1,18 +1,20 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { channelExample } from '../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
import { memberExample } from '../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
await tap.test('DELETE /channels/[channelId]', async (t) => { await test('DELETE /channels/[channelId]', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const defaultChannelId = 5 const defaultChannelId = 5
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
@ -45,14 +47,14 @@ await tap.test('DELETE /channels/[channelId]', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.id, channelExample.id) assert.strictEqual(responseJson.id, channelExample.id)
t.equal(responseJson.name, channelExample.name) assert.strictEqual(responseJson.name, channelExample.name)
t.equal(responseJson.guildId, channelExample.guildId) assert.strictEqual(responseJson.guildId, channelExample.guildId)
t.equal(responseJson.defaultChannelId, defaultChannelId) assert.strictEqual(responseJson.defaultChannelId, defaultChannelId)
}) })
await t.test('fails if there is only one channel', async (t) => { await t.test('fails if there is only one channel', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -74,10 +76,10 @@ await tap.test('DELETE /channels/[channelId]', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
}) })
await t.test('fails if the channel is not found', async (t) => { await t.test('fails if the channel is not found', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -91,10 +93,10 @@ await tap.test('DELETE /channels/[channelId]', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the member is not found', async (t) => { await t.test('fails if the member is not found', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -113,10 +115,10 @@ await tap.test('DELETE /channels/[channelId]', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the member is not owner', async (t) => { await t.test('fails if the member is not owner', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -138,6 +140,6 @@ await tap.test('DELETE /channels/[channelId]', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
}) })
}) })

View File

@ -1,18 +1,20 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { channelExample } from '../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
import { memberExample } from '../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
await tap.test('GET /channels/[channelId]', async (t) => { await test('GET /channels/[channelId]', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -32,13 +34,13 @@ await tap.test('GET /channels/[channelId]', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.channel.id, channelExample.id) assert.strictEqual(responseJson.channel.id, channelExample.id)
t.equal(responseJson.channel.name, channelExample.name) assert.strictEqual(responseJson.channel.name, channelExample.name)
t.equal(responseJson.channel.guildId, channelExample.guildId) assert.strictEqual(responseJson.channel.guildId, channelExample.guildId)
}) })
await t.test('fails with not found member', async (t) => { await t.test('fails with not found member', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -58,11 +60,11 @@ await tap.test('GET /channels/[channelId]', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
t.equal(responseJson.message, 'Channel not found') assert.strictEqual(responseJson.message, 'Channel not found')
}) })
await t.test('fails with not found channel', async (t) => { await t.test('fails with not found channel', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -82,15 +84,15 @@ await tap.test('GET /channels/[channelId]', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
t.equal(responseJson.message, 'Channel not found') assert.strictEqual(responseJson.message, 'Channel not found')
}) })
await t.test('fails with unauthenticated user', async (t) => { await t.test('fails with unauthenticated user', async () => {
const response = await application.inject({ const response = await application.inject({
method: 'GET', method: 'GET',
url: '/channels/1' url: '/channels/1'
}) })
t.equal(response.statusCode, 401) assert.strictEqual(response.statusCode, 401)
}) })
}) })

View File

@ -1,20 +1,22 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { channelExample } from '../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
import { memberExample } from '../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
const newName = 'new channel name' const newName = 'new channel name'
await tap.test('PUT /channels/[channelId]', async (t) => { await test('PUT /channels/[channelId]', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const defaultChannelId = 5 const defaultChannelId = 5
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
@ -48,14 +50,14 @@ await tap.test('PUT /channels/[channelId]', async (t) => {
payload: { name: newName } payload: { name: newName }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.id, channelExample.id) assert.strictEqual(responseJson.id, channelExample.id)
t.equal(responseJson.name, newName) assert.strictEqual(responseJson.name, newName)
t.equal(responseJson.guildId, channelExample.guildId) assert.strictEqual(responseJson.guildId, channelExample.guildId)
t.equal(responseJson.defaultChannelId, defaultChannelId) assert.strictEqual(responseJson.defaultChannelId, defaultChannelId)
}) })
await t.test('fails if the channel is not found', async (t) => { await t.test('fails if the channel is not found', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -75,10 +77,10 @@ await tap.test('PUT /channels/[channelId]', async (t) => {
}, },
payload: { name: newName } payload: { name: newName }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the member is not found', async (t) => { await t.test('fails if the member is not found', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -98,10 +100,10 @@ await tap.test('PUT /channels/[channelId]', async (t) => {
}, },
payload: { name: newName } payload: { name: newName }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the member is not owner', async (t) => { await t.test('fails if the member is not owner', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -124,6 +126,6 @@ await tap.test('PUT /channels/[channelId]', async (t) => {
}, },
payload: { name: newName } payload: { name: newName }
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
}) })
}) })

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { channelSchema } from '../../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
channelId: channelSchema.id channelId: channelSchema.id
@ -48,8 +48,8 @@ export const deleteChannelService: FastifyPluginAsync = async (fastify) => {
if (request.user == null) { if (request.user == null) {
throw fastify.httpErrors.forbidden() throw fastify.httpErrors.forbidden()
} }
const { user } = request const { user, params } = request
const { channelId } = request.params const { channelId } = params
const channelCheck = await prisma.channel.findUnique({ const channelCheck = await prisma.channel.findUnique({
where: { id: channelId } where: { id: channelId }
}) })

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { channelSchema } from '../../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
channelId: channelSchema.id channelId: channelSchema.id

View File

@ -1,20 +1,22 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { channelExample } from '../../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
import { memberExample } from '../../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { userExample } from '../../../../../models/User.js' import { userExample } from '#src/models/User.js'
import { messageExample } from '../../../../../models/Message.js' import { messageExample } from '#src/models/Message.js'
await tap.test('GET /channels/[channelId]/messages', async (t) => { await test('GET /channels/[channelId]/messages', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -42,19 +44,19 @@ await tap.test('GET /channels/[channelId]/messages', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.length, 1) assert.strictEqual(responseJson.length, 1)
t.equal(responseJson[0].id, messageExample.id) assert.strictEqual(responseJson[0].id, messageExample.id)
t.equal(responseJson[0].value, messageExample.value) assert.strictEqual(responseJson[0].value, messageExample.value)
t.equal(responseJson[0].type, messageExample.type) assert.strictEqual(responseJson[0].type, messageExample.type)
t.equal(responseJson[0].mimetype, messageExample.mimetype) assert.strictEqual(responseJson[0].mimetype, messageExample.mimetype)
t.equal(responseJson[0].member.id, memberExample.id) assert.strictEqual(responseJson[0].member.id, memberExample.id)
t.equal(responseJson[0].member.isOwner, memberExample.isOwner) assert.strictEqual(responseJson[0].member.isOwner, memberExample.isOwner)
t.equal(responseJson[0].member.user.id, userExample.id) assert.strictEqual(responseJson[0].member.user.id, userExample.id)
t.equal(responseJson[0].member.user.name, userExample.name) assert.strictEqual(responseJson[0].member.user.name, userExample.name)
}) })
await t.test('fails with not found channel', async (t) => { await t.test('fails with not found channel', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -77,11 +79,11 @@ await tap.test('GET /channels/[channelId]/messages', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
t.equal(responseJson.message, 'Channel not found') assert.strictEqual(responseJson.message, 'Channel not found')
}) })
await t.test('fails with not found member', async (t) => { await t.test('fails with not found member', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -101,15 +103,15 @@ await tap.test('GET /channels/[channelId]/messages', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
t.equal(responseJson.message, 'Channel not found') assert.strictEqual(responseJson.message, 'Channel not found')
}) })
await t.test('fails with unauthenticated user', async (t) => { await t.test('fails with unauthenticated user', async () => {
const response = await application.inject({ const response = await application.inject({
method: 'GET', method: 'GET',
url: `/channels/1/messages` url: `/channels/1/messages`
}) })
t.equal(response.statusCode, 401) assert.strictEqual(response.statusCode, 401)
}) })
}) })

View File

@ -1,20 +1,22 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { channelExample } from '../../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
import { memberExample } from '../../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { userExample } from '../../../../../models/User.js' import { userExample } from '#src/models/User.js'
import { messageExample } from '../../../../../models/Message.js' import { messageExample } from '#src/models/Message.js'
await tap.test('POST /channels/[channelId]/messages', async (t) => { await test('POST /channels/[channelId]/messages', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -43,18 +45,18 @@ await tap.test('POST /channels/[channelId]/messages', async (t) => {
payload: { value: messageExample.value } payload: { value: messageExample.value }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 201) assert.strictEqual(response.statusCode, 201)
t.equal(responseJson.id, messageExample.id) assert.strictEqual(responseJson.id, messageExample.id)
t.equal(responseJson.value, messageExample.value) assert.strictEqual(responseJson.value, messageExample.value)
t.equal(responseJson.type, messageExample.type) assert.strictEqual(responseJson.type, messageExample.type)
t.equal(responseJson.mimetype, messageExample.mimetype) assert.strictEqual(responseJson.mimetype, messageExample.mimetype)
t.equal(responseJson.member.id, memberExample.id) assert.strictEqual(responseJson.member.id, memberExample.id)
t.equal(responseJson.member.isOwner, memberExample.isOwner) assert.strictEqual(responseJson.member.isOwner, memberExample.isOwner)
t.equal(responseJson.member.user.id, userExample.id) assert.strictEqual(responseJson.member.user.id, userExample.id)
t.equal(responseJson.member.user.name, userExample.name) assert.strictEqual(responseJson.member.user.name, userExample.name)
}) })
await t.test('fails with no message value', async (t) => { await t.test('fails with no message value', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -77,10 +79,10 @@ await tap.test('POST /channels/[channelId]/messages', async (t) => {
}, },
payload: {} payload: {}
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
}) })
await t.test('fails with not found channel', async (t) => { await t.test('fails with not found channel', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -104,11 +106,11 @@ await tap.test('POST /channels/[channelId]/messages', async (t) => {
payload: { value: messageExample.value } payload: { value: messageExample.value }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
t.equal(responseJson.message, 'Channel not found') assert.strictEqual(responseJson.message, 'Channel not found')
}) })
await t.test('fails with not found member', async (t) => { await t.test('fails with not found member', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'channel').value({ sinon.stub(prisma, 'channel').value({
findUnique: async () => { findUnique: async () => {
@ -129,7 +131,7 @@ await tap.test('POST /channels/[channelId]/messages', async (t) => {
payload: { value: messageExample.value } payload: { value: messageExample.value }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
t.equal(responseJson.message, 'Channel not found') assert.strictEqual(responseJson.message, 'Channel not found')
}) })
}) })

View File

@ -2,17 +2,17 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { messageSchema } from '../../../../models/Message.js' import { messageSchema } from '#src/models/Message.js'
import { memberSchema } from '../../../../models/Member.js' import { memberSchema } from '#src/models/Member.js'
import { userPublicWithoutSettingsSchema } from '../../../../models/User.js' import { userPublicWithoutSettingsSchema } from '#src/models/User.js'
import { import {
getPaginationOptions, getPaginationOptions,
queryPaginationObjectSchema queryPaginationObjectSchema
} from '../../../../tools/database/pagination.js' } from '#src/tools/database/pagination.js'
import { channelSchema } from '../../../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
type QuerySchemaType = Static<typeof queryPaginationObjectSchema> type QuerySchemaType = Static<typeof queryPaginationObjectSchema>

View File

@ -2,13 +2,13 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { messageSchema } from '../../../../models/Message.js' import { messageSchema } from '#src/models/Message.js'
import { channelSchema } from '../../../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
import { memberSchema } from '../../../../models/Member.js' import { memberSchema } from '#src/models/Member.js'
import { userPublicWithoutSettingsSchema } from '../../../../models/User.js' import { userPublicWithoutSettingsSchema } from '#src/models/User.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
channelId: channelSchema.id channelId: channelSchema.id

View File

@ -3,14 +3,14 @@ import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import fastifyMultipart from '@fastify/multipart' import fastifyMultipart from '@fastify/multipart'
import prisma from '../../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { messageSchema } from '../../../../../models/Message.js' import { messageSchema } from '#src/models/Message.js'
import { memberSchema } from '../../../../../models/Member.js' import { memberSchema } from '#src/models/Member.js'
import { userPublicWithoutSettingsSchema } from '../../../../../models/User.js' import { userPublicWithoutSettingsSchema } from '#src/models/User.js'
import { channelSchema } from '../../../../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
import { uploadFile } from '../../../../../tools/utils/uploadFile.js' import { uploadFile } from '#src/tools/utils/uploadFile.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
channelId: channelSchema.id channelId: channelSchema.id

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { channelSchema } from '../../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
const bodyPutServiceSchema = Type.Object({ const bodyPutServiceSchema = Type.Object({
name: channelSchema.name name: channelSchema.name
@ -56,9 +56,9 @@ export const putChannelService: FastifyPluginAsync = async (fastify) => {
if (request.user == null) { if (request.user == null) {
throw fastify.httpErrors.forbidden() throw fastify.httpErrors.forbidden()
} }
const { user } = request const { user, params, body } = request
const { channelId } = request.params const { channelId } = params
const { name } = request.body const { name } = body
const channelCheck = await prisma.channel.findUnique({ const channelCheck = await prisma.channel.findUnique({
where: { id: channelId } where: { id: channelId }
}) })

View File

@ -1,18 +1,20 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { memberExample } from '../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { guildExample } from '../../../../models/Guild.js' import { guildExample } from '#src/models/Guild.js'
await tap.test('DELETE /guilds/[guildId]', async (t) => { await test('DELETE /guilds/[guildId]', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds and delete the guild', async (t) => { await t.test('succeeds and delete the guild', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -36,13 +38,13 @@ await tap.test('DELETE /guilds/[guildId]', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.id, guildExample.id) assert.strictEqual(responseJson.id, guildExample.id)
t.equal(responseJson.name, guildExample.name) assert.strictEqual(responseJson.name, guildExample.name)
t.equal(responseJson.description, guildExample.description) assert.strictEqual(responseJson.description, guildExample.description)
}) })
await t.test("fails if the guild doesn't exist", async (t) => { await t.test("fails if the guild doesn't exist", async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -56,10 +58,10 @@ await tap.test('DELETE /guilds/[guildId]', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the user is not the owner', async (t) => { await t.test('fails if the user is not the owner', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -78,7 +80,10 @@ await tap.test('DELETE /guilds/[guildId]', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
t.equal(responseJson.message, 'You should be an owner of the guild') assert.strictEqual(
responseJson.message,
'You should be an owner of the guild'
)
}) })
}) })

View File

@ -1,22 +1,24 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { memberExample } from '../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { guildExample } from '../../../../models/Guild.js' import { guildExample } from '#src/models/Guild.js'
import { userExample } from '../../../../models/User.js' import { userExample } from '#src/models/User.js'
import { channelExample } from '../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
const defaultChannelId = 5 const defaultChannelId = 5
await tap.test('GET /guilds/[guildId]', async (t) => { await test('GET /guilds/[guildId]', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken, user } = await authenticateUserTest() const { accessToken, user } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -43,17 +45,17 @@ await tap.test('GET /guilds/[guildId]', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.member.id, memberExample.id) assert.strictEqual(responseJson.member.id, memberExample.id)
t.equal(responseJson.member.isOwner, memberExample.isOwner) assert.strictEqual(responseJson.member.isOwner, memberExample.isOwner)
t.equal(responseJson.member.user.name, user.name) assert.strictEqual(responseJson.member.user.name, user.name)
t.equal(responseJson.member.user.email, null) assert.strictEqual(responseJson.member.user.email, null)
t.equal(responseJson.guild.id, guildExample.id) assert.strictEqual(responseJson.guild.id, guildExample.id)
t.equal(responseJson.guild.name, guildExample.name) assert.strictEqual(responseJson.guild.name, guildExample.name)
t.equal(responseJson.guild.defaultChannelId, defaultChannelId) assert.strictEqual(responseJson.guild.defaultChannelId, defaultChannelId)
}) })
await t.test('fails with not found member/guild', async (t) => { await t.test('fails with not found member/guild', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -68,15 +70,15 @@ await tap.test('GET /guilds/[guildId]', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
t.equal(responseJson.message, 'Member not found') assert.strictEqual(responseJson.message, 'Member not found')
}) })
await t.test('fails with unauthenticated user', async (t) => { await t.test('fails with unauthenticated user', async () => {
const response = await application.inject({ const response = await application.inject({
method: 'GET', method: 'GET',
url: '/guilds/1' url: '/guilds/1'
}) })
t.equal(response.statusCode, 401) assert.strictEqual(response.statusCode, 401)
}) })
}) })

View File

@ -1,23 +1,25 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { memberExample } from '../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { guildExample } from '../../../../models/Guild.js' import { guildExample } from '#src/models/Guild.js'
import { channelExample } from '../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
const defaultChannelId = 5 const defaultChannelId = 5
const newName = 'New guild name' const newName = 'New guild name'
const newDescription = 'New guild description' const newDescription = 'New guild description'
await tap.test('PUT /guilds/[guildId]', async (t) => { await test('PUT /guilds/[guildId]', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds and edit the guild', async (t) => { await t.test('succeeds and edit the guild', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -57,13 +59,13 @@ await tap.test('PUT /guilds/[guildId]', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.name, newName) assert.strictEqual(responseJson.name, newName)
t.equal(responseJson.description, newDescription) assert.strictEqual(responseJson.description, newDescription)
t.equal(responseJson.defaultChannelId, defaultChannelId) assert.strictEqual(responseJson.defaultChannelId, defaultChannelId)
}) })
await t.test("fails if the guild doesn't exist", async (t) => { await t.test("fails if the guild doesn't exist", async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -81,10 +83,10 @@ await tap.test('PUT /guilds/[guildId]', async (t) => {
description: newDescription description: newDescription
} }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the user is not the owner', async (t) => { await t.test('fails if the user is not the owner', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -107,7 +109,10 @@ await tap.test('PUT /guilds/[guildId]', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
t.equal(responseJson.message, 'You should be an owner of the guild') assert.strictEqual(
responseJson.message,
'You should be an owner of the guild'
)
}) })
}) })

View File

@ -1,19 +1,21 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { memberExample } from '../../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { guildExample } from '../../../../../models/Guild.js' import { guildExample } from '#src/models/Guild.js'
import { channelExample } from '../../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
await tap.test('GET /guilds/[guildId]/channels', async (t) => { await test('GET /guilds/[guildId]/channels', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -33,14 +35,14 @@ await tap.test('GET /guilds/[guildId]/channels', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.length, 1) assert.strictEqual(responseJson.length, 1)
t.equal(responseJson[0].id, channelExample.id) assert.strictEqual(responseJson[0].id, channelExample.id)
t.equal(responseJson[0].name, channelExample.name) assert.strictEqual(responseJson[0].name, channelExample.name)
t.equal(responseJson[0].guildId, channelExample.guildId) assert.strictEqual(responseJson[0].guildId, channelExample.guildId)
}) })
await t.test('fails with not found member/guild', async (t) => { await t.test('fails with not found member/guild', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -55,15 +57,15 @@ await tap.test('GET /guilds/[guildId]/channels', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
t.equal(responseJson.message, 'Member not found') assert.strictEqual(responseJson.message, 'Member not found')
}) })
await t.test('fails with unauthenticated user', async (t) => { await t.test('fails with unauthenticated user', async () => {
const response = await application.inject({ const response = await application.inject({
method: 'GET', method: 'GET',
url: '/guilds/1/channels' url: '/guilds/1/channels'
}) })
t.equal(response.statusCode, 401) assert.strictEqual(response.statusCode, 401)
}) })
}) })

View File

@ -1,21 +1,23 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { memberExample } from '../../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { guildExample } from '../../../../../models/Guild.js' import { guildExample } from '#src/models/Guild.js'
import { channelExample } from '../../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
const defaultChannelId = 5 const defaultChannelId = 5
await tap.test('POST /guilds/[guildId]/channels', async (t) => { await test('POST /guilds/[guildId]/channels', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -42,14 +44,14 @@ await tap.test('POST /guilds/[guildId]/channels', async (t) => {
payload: { name: channelExample.name } payload: { name: channelExample.name }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 201) assert.strictEqual(response.statusCode, 201)
t.equal(responseJson.id, channelExample.id) assert.strictEqual(responseJson.id, channelExample.id)
t.equal(responseJson.name, channelExample.name) assert.strictEqual(responseJson.name, channelExample.name)
t.equal(responseJson.guildId, channelExample.guildId) assert.strictEqual(responseJson.guildId, channelExample.guildId)
t.equal(responseJson.defaultChannelId, defaultChannelId) assert.strictEqual(responseJson.defaultChannelId, defaultChannelId)
}) })
await t.test('fails if the member is not found', async (t) => { await t.test('fails if the member is not found', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -64,10 +66,10 @@ await tap.test('POST /guilds/[guildId]/channels', async (t) => {
}, },
payload: { name: channelExample.name } payload: { name: channelExample.name }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the member is not owner', async (t) => { await t.test('fails if the member is not owner', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -85,6 +87,6 @@ await tap.test('POST /guilds/[guildId]/channels', async (t) => {
}, },
payload: { name: channelExample.name } payload: { name: channelExample.name }
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
}) })
}) })

View File

@ -2,15 +2,15 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { guildSchema } from '../../../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
import { channelSchema } from '../../../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
import { import {
getPaginationOptions, getPaginationOptions,
queryPaginationObjectSchema queryPaginationObjectSchema
} from '../../../../tools/database/pagination.js' } from '#src/tools/database/pagination.js'
type QuerySchemaType = Static<typeof queryPaginationObjectSchema> type QuerySchemaType = Static<typeof queryPaginationObjectSchema>

View File

@ -2,11 +2,11 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { channelSchema } from '../../../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
import { guildSchema } from '../../../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
const bodyPostServiceSchema = Type.Object({ const bodyPostServiceSchema = Type.Object({
name: channelSchema.name name: channelSchema.name
@ -57,9 +57,9 @@ export const postChannelService: FastifyPluginAsync = async (fastify) => {
if (request.user == null) { if (request.user == null) {
throw fastify.httpErrors.forbidden() throw fastify.httpErrors.forbidden()
} }
const { user } = request const { user, params, body } = request
const { guildId } = request.params const { guildId } = params
const { name } = request.body const { name } = body
const member = await prisma.member.findFirst({ const member = await prisma.member.findFirst({
where: { guildId, userId: user.current.id } where: { guildId, userId: user.current.id }
}) })

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { guildSchema } from '../../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
guildId: guildSchema.id guildId: guildSchema.id

View File

@ -2,13 +2,13 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { guildSchema } from '../../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
import { memberSchema } from '../../../models/Member.js' import { memberSchema } from '#src/models/Member.js'
import { userPublicWithoutSettingsSchema } from '../../../models/User.js' import { userPublicWithoutSettingsSchema } from '#src/models/User.js'
import { channelSchema } from '../../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
guildId: guildSchema.id guildId: guildSchema.id

View File

@ -3,12 +3,12 @@ import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import fastifyMultipart from '@fastify/multipart' import fastifyMultipart from '@fastify/multipart'
import authenticateUser from '../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { fastifyErrors } from '../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { uploadFile } from '../../../../tools/utils/uploadFile.js' import { uploadFile } from '#src/tools/utils/uploadFile.js'
import { guildSchema } from '../../../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
import { channelSchema } from '../../../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
guildId: guildSchema.id guildId: guildSchema.id

View File

@ -1,19 +1,21 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { memberExample } from '../../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { guildExample } from '../../../../../models/Guild.js' import { guildExample } from '#src/models/Guild.js'
import { userExample } from '../../../../../models/User.js' import { userExample } from '#src/models/User.js'
await tap.test('GET /guilds/[guildId]/members', async (t) => { await test('GET /guilds/[guildId]/members', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -31,16 +33,16 @@ await tap.test('GET /guilds/[guildId]/members', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.length, 1) assert.strictEqual(responseJson.length, 1)
t.equal(responseJson[0].id, memberExample.id) assert.strictEqual(responseJson[0].id, memberExample.id)
t.equal(responseJson[0].isOwner, memberExample.isOwner) assert.strictEqual(responseJson[0].isOwner, memberExample.isOwner)
t.equal(responseJson[0].user.id, userExample.id) assert.strictEqual(responseJson[0].user.id, userExample.id)
t.equal(responseJson[0].user.name, userExample.name) assert.strictEqual(responseJson[0].user.name, userExample.name)
t.equal(responseJson[0].user.email, null) assert.strictEqual(responseJson[0].user.email, null)
}) })
await t.test('fails with not found member/guild', async (t) => { await t.test('fails with not found member/guild', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -55,15 +57,15 @@ await tap.test('GET /guilds/[guildId]/members', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
t.equal(responseJson.message, 'Member not found') assert.strictEqual(responseJson.message, 'Member not found')
}) })
await t.test('fails with unauthenticated user', async (t) => { await t.test('fails with unauthenticated user', async () => {
const response = await application.inject({ const response = await application.inject({
method: 'GET', method: 'GET',
url: '/guilds/1/members' url: '/guilds/1/members'
}) })
t.equal(response.statusCode, 401) assert.strictEqual(response.statusCode, 401)
}) })
}) })

View File

@ -2,16 +2,16 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { guildSchema } from '../../../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
import { import {
getPaginationOptions, getPaginationOptions,
queryPaginationObjectSchema queryPaginationObjectSchema
} from '../../../../tools/database/pagination.js' } from '#src/tools/database/pagination.js'
import { memberSchema } from '../../../../models/Member.js' import { memberSchema } from '#src/models/Member.js'
import { userPublicWithoutSettingsSchema } from '../../../../models/User.js' import { userPublicWithoutSettingsSchema } from '#src/models/User.js'
type QuerySchemaType = Static<typeof queryPaginationObjectSchema> type QuerySchemaType = Static<typeof queryPaginationObjectSchema>

View File

@ -1,22 +1,24 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { memberExample } from '../../../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { guildExample } from '../../../../../../models/Guild.js' import { guildExample } from '#src/models/Guild.js'
import { userExample } from '../../../../../../models/User.js' import { userExample } from '#src/models/User.js'
import { channelExample } from '../../../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
const defaultChannelId = 5 const defaultChannelId = 5
await tap.test('POST /guilds/[guildId]/members/join', async (t) => { await test('POST /guilds/[guildId]/members/join', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -44,17 +46,17 @@ await tap.test('POST /guilds/[guildId]/members/join', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 201) assert.strictEqual(response.statusCode, 201)
t.equal(responseJson.id, memberExample.id) assert.strictEqual(responseJson.id, memberExample.id)
t.equal(responseJson.userId, memberExample.userId) assert.strictEqual(responseJson.userId, memberExample.userId)
t.equal(responseJson.user.name, userExample.name) assert.strictEqual(responseJson.user.name, userExample.name)
t.equal(responseJson.user.email, null) assert.strictEqual(responseJson.user.email, null)
t.equal(responseJson.guild.id, guildExample.id) assert.strictEqual(responseJson.guild.id, guildExample.id)
t.equal(responseJson.guild.name, guildExample.name) assert.strictEqual(responseJson.guild.name, guildExample.name)
t.equal(responseJson.guild.defaultChannelId, channelExample.id) assert.strictEqual(responseJson.guild.defaultChannelId, channelExample.id)
}) })
await t.test('fails if the guild is not found', async (t) => { await t.test('fails if the guild is not found', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -78,10 +80,10 @@ await tap.test('POST /guilds/[guildId]/members/join', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the user is already in the guild', async (t) => { await t.test('fails if the user is already in the guild', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -109,7 +111,7 @@ await tap.test('POST /guilds/[guildId]/members/join', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
t.equal(responseJson.defaultChannelId, defaultChannelId) assert.strictEqual(responseJson.defaultChannelId, defaultChannelId)
}) })
}) })

View File

@ -2,17 +2,13 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { import { fastifyErrors, fastifyErrorsSchema, id } from '#src/models/utils.js'
fastifyErrors, import authenticateUser from '#src/tools/plugins/authenticateUser.js'
fastifyErrorsSchema, import { guildSchema } from '#src/models/Guild.js'
id import { memberSchema } from '#src/models/Member.js'
} from '../../../../../models/utils.js' import { userPublicWithoutSettingsSchema } from '#src/models/User.js'
import authenticateUser from '../../../../../tools/plugins/authenticateUser.js' import { channelSchema } from '#src/models/Channel.js'
import { guildSchema } from '../../../../../models/Guild.js'
import { memberSchema } from '../../../../../models/Member.js'
import { userPublicWithoutSettingsSchema } from '../../../../../models/User.js'
import { channelSchema } from '../../../../../models/Channel.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
guildId: guildSchema.id guildId: guildSchema.id
@ -62,8 +58,8 @@ export const postMemberService: FastifyPluginAsync = async (fastify) => {
if (request.user == null) { if (request.user == null) {
throw fastify.httpErrors.forbidden() throw fastify.httpErrors.forbidden()
} }
const { user } = request const { user, params } = request
const { guildId } = request.params const { guildId } = params
const guild = await prisma.guild.findUnique({ const guild = await prisma.guild.findUnique({
where: { where: {
id: guildId id: guildId

View File

@ -1,18 +1,20 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { memberExample } from '../../../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { guildExample } from '../../../../../../models/Guild.js' import { guildExample } from '#src/models/Guild.js'
await tap.test('DELETE /guilds/[guildId]/members/leave', async (t) => { await test('DELETE /guilds/[guildId]/members/leave', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
const member = { const member = {
...memberExample, ...memberExample,
@ -34,13 +36,13 @@ await tap.test('DELETE /guilds/[guildId]/members/leave', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.id, member.id) assert.strictEqual(responseJson.id, member.id)
t.equal(responseJson.isOwner, member.isOwner) assert.strictEqual(responseJson.isOwner, member.isOwner)
t.equal(responseJson.userId, member.userId) assert.strictEqual(responseJson.userId, member.userId)
}) })
await t.test('fails if the member is not found', async (t) => { await t.test('fails if the member is not found', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'member').value({ sinon.stub(prisma, 'member').value({
findFirst: async () => { findFirst: async () => {
@ -54,10 +56,10 @@ await tap.test('DELETE /guilds/[guildId]/members/leave', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the member is owner', async (t) => { await t.test('fails if the member is owner', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
const member = { const member = {
...memberExample, ...memberExample,
@ -75,6 +77,6 @@ await tap.test('DELETE /guilds/[guildId]/members/leave', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
}) })
}) })

View File

@ -2,11 +2,11 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { guildSchema } from '../../../../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
import { memberSchema } from '../../../../../models/Member.js' import { memberSchema } from '#src/models/Member.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
guildId: guildSchema.id guildId: guildSchema.id
@ -46,8 +46,8 @@ export const deleteMemberService: FastifyPluginAsync = async (fastify) => {
if (request.user == null) { if (request.user == null) {
throw fastify.httpErrors.forbidden() throw fastify.httpErrors.forbidden()
} }
const { user } = request const { user, params } = request
const { guildId } = request.params const { guildId } = params
const member = await prisma.member.findFirst({ const member = await prisma.member.findFirst({
where: { guildId, userId: user.current.id } where: { guildId, userId: user.current.id }
}) })

View File

@ -2,12 +2,12 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { guildSchema } from '../../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
import { parseStringNullish } from '../../../tools/utils/parseStringNullish.js' import { parseStringNullish } from '#src/tools/utils/parseStringNullish.js'
import { channelSchema } from '../../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
guildId: guildSchema.id guildId: guildSchema.id

View File

@ -1,19 +1,21 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { memberExample } from '../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { guildExample } from '../../../models/Guild.js' import { guildExample } from '#src/models/Guild.js'
import { channelExample } from '../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
await tap.test('GET /guilds', async (t) => { await test('GET /guilds', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'guild').value({ sinon.stub(prisma, 'guild').value({
findUnique: async () => { findUnique: async () => {
@ -38,10 +40,10 @@ await tap.test('GET /guilds', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.length, 1) assert.strictEqual(responseJson.length, 1)
t.equal(responseJson[0].name, guildExample.name) assert.strictEqual(responseJson[0].name, guildExample.name)
t.equal(responseJson[0].description, guildExample.description) assert.strictEqual(responseJson[0].description, guildExample.description)
t.equal(responseJson[0].defaultChannelId, channelExample.id) assert.strictEqual(responseJson[0].defaultChannelId, channelExample.id)
}) })
}) })

View File

@ -1,20 +1,22 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { memberExample } from '../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { guildExample } from '../../../models/Guild.js' import { guildExample } from '#src/models/Guild.js'
import { channelExample } from '../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
import { userExample } from '../../../models/User.js' import { userExample } from '#src/models/User.js'
await tap.test('POST /guilds', async (t) => { await test('POST /guilds', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken, user } = await authenticateUserTest() const { accessToken, user } = await authenticateUserTest()
sinon.stub(prisma, 'guild').value({ sinon.stub(prisma, 'guild').value({
create: async () => { create: async () => {
@ -49,21 +51,24 @@ await tap.test('POST /guilds', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 201) assert.strictEqual(response.statusCode, 201)
t.equal(responseJson.guild.id, guildExample.id) assert.strictEqual(responseJson.guild.id, guildExample.id)
t.equal(responseJson.guild.name, guildExample.name) assert.strictEqual(responseJson.guild.name, guildExample.name)
t.equal(responseJson.guild.description, guildExample.description) assert.strictEqual(responseJson.guild.description, guildExample.description)
t.equal(responseJson.guild.members.length, 1) assert.strictEqual(responseJson.guild.members.length, 1)
t.equal(responseJson.guild.members[0].userId, user.id) assert.strictEqual(responseJson.guild.members[0].userId, user.id)
t.equal(responseJson.guild.members[0].user.name, user.name) assert.strictEqual(responseJson.guild.members[0].user.name, user.name)
t.equal(responseJson.guild.members[0].guildId, guildExample.id) assert.strictEqual(responseJson.guild.members[0].guildId, guildExample.id)
t.equal(responseJson.guild.members[0].isOwner, memberExample.isOwner) assert.strictEqual(
t.equal(responseJson.guild.channels.length, 1) responseJson.guild.members[0].isOwner,
t.equal(responseJson.guild.channels[0].id, channelExample.id) memberExample.isOwner
t.equal(responseJson.guild.channels[0].guildId, guildExample.id) )
assert.strictEqual(responseJson.guild.channels.length, 1)
assert.strictEqual(responseJson.guild.channels[0].id, channelExample.id)
assert.strictEqual(responseJson.guild.channels[0].guildId, guildExample.id)
}) })
await t.test('fails with empty name and description', async (t) => { await t.test('fails with empty name and description', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
const response = await application.inject({ const response = await application.inject({
method: 'POST', method: 'POST',
@ -72,6 +77,6 @@ await tap.test('POST /guilds', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
}) })
}) })

View File

@ -2,14 +2,14 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors, id } from '../../models/utils.js' import { fastifyErrors, id } from '#src/models/utils.js'
import authenticateUser from '../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { guildSchema } from '../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
import { import {
getPaginationOptions, getPaginationOptions,
queryPaginationObjectSchema queryPaginationObjectSchema
} from '../../tools/database/pagination.js' } from '#src/tools/database/pagination.js'
type QuerySchemaType = Static<typeof queryPaginationObjectSchema> type QuerySchemaType = Static<typeof queryPaginationObjectSchema>

View File

@ -2,14 +2,14 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { guildSchema } from '../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
import { channelSchema } from '../../models/Channel.js' import { channelSchema } from '#src/models/Channel.js'
import { memberSchema } from '../../models/Member.js' import { memberSchema } from '#src/models/Member.js'
import { userPublicWithoutSettingsSchema } from '../../models/User.js' import { userPublicWithoutSettingsSchema } from '#src/models/User.js'
import { parseStringNullish } from '../../tools/utils/parseStringNullish.js' import { parseStringNullish } from '#src/tools/utils/parseStringNullish.js'
const bodyPostServiceSchema = Type.Object({ const bodyPostServiceSchema = Type.Object({
name: guildSchema.name, name: guildSchema.name,

View File

@ -1,17 +1,19 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { guildExample } from '../../../../models/Guild.js' import { guildExample } from '#src/models/Guild.js'
await tap.test('GET /guilds/public', async (t) => { await test('GET /guilds/public', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'guild').value({ sinon.stub(prisma, 'guild').value({
findMany: async () => { findMany: async () => {
@ -31,9 +33,9 @@ await tap.test('GET /guilds/public', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.length, 1) assert.strictEqual(responseJson.length, 1)
t.equal(responseJson[0].name, guildExample.name) assert.strictEqual(responseJson[0].name, guildExample.name)
t.equal(responseJson[0].membersCount, 2) assert.strictEqual(responseJson[0].membersCount, 2)
}) })
}) })

View File

@ -2,14 +2,14 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { guildSchema } from '../../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
import { import {
getPaginationOptions, getPaginationOptions,
queryPaginationSchema queryPaginationSchema
} from '../../../tools/database/pagination.js' } from '#src/tools/database/pagination.js'
const querySchema = Type.Object({ const querySchema = Type.Object({
search: Type.Optional(Type.String()), search: Type.Optional(Type.String()),

View File

@ -1,20 +1,22 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { messageExample } from '../../../../models/Message.js' import { messageExample } from '#src/models/Message.js'
import { memberExample } from '../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { userExample } from '../../../../models/User.js' import { userExample } from '#src/models/User.js'
import { channelExample } from '../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
await tap.test('DELETE /messsages/[messageId]', async (t) => { await test('DELETE /messsages/[messageId]', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'message').value({ sinon.stub(prisma, 'message').value({
findFirst: async () => { findFirst: async () => {
@ -43,18 +45,18 @@ await tap.test('DELETE /messsages/[messageId]', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.id, messageExample.id) assert.strictEqual(responseJson.id, messageExample.id)
t.equal(responseJson.value, messageExample.value) assert.strictEqual(responseJson.value, messageExample.value)
t.equal(responseJson.type, messageExample.type) assert.strictEqual(responseJson.type, messageExample.type)
t.equal(responseJson.mimetype, messageExample.mimetype) assert.strictEqual(responseJson.mimetype, messageExample.mimetype)
t.equal(responseJson.member.id, memberExample.id) assert.strictEqual(responseJson.member.id, memberExample.id)
t.equal(responseJson.member.isOwner, memberExample.isOwner) assert.strictEqual(responseJson.member.isOwner, memberExample.isOwner)
t.equal(responseJson.member.user.id, userExample.id) assert.strictEqual(responseJson.member.user.id, userExample.id)
t.equal(responseJson.member.user.name, userExample.name) assert.strictEqual(responseJson.member.user.name, userExample.name)
}) })
await t.test('fails if the message is not found', async (t) => { await t.test('fails if the message is not found', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'message').value({ sinon.stub(prisma, 'message').value({
findFirst: async () => { findFirst: async () => {
@ -68,10 +70,10 @@ await tap.test('DELETE /messsages/[messageId]', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the member is not found', async (t) => { await t.test('fails if the member is not found', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
sinon.stub(prisma, 'message').value({ sinon.stub(prisma, 'message').value({
findFirst: async () => { findFirst: async () => {
@ -93,10 +95,10 @@ await tap.test('DELETE /messsages/[messageId]', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the member is not owner of the message', async (t) => { await t.test('fails if the member is not owner of the message', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
const randomUserIdOwnerOfMessage = 14 const randomUserIdOwnerOfMessage = 14
sinon.stub(prisma, 'message').value({ sinon.stub(prisma, 'message').value({
@ -122,6 +124,6 @@ await tap.test('DELETE /messsages/[messageId]', async (t) => {
authorization: `Bearer ${accessToken}` authorization: `Bearer ${accessToken}`
} }
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
}) })
}) })

View File

@ -1,20 +1,22 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { messageExample } from '../../../../models/Message.js' import { messageExample } from '#src/models/Message.js'
import { memberExample } from '../../../../models/Member.js' import { memberExample } from '#src/models/Member.js'
import { userExample } from '../../../../models/User.js' import { userExample } from '#src/models/User.js'
import { channelExample } from '../../../../models/Channel.js' import { channelExample } from '#src/models/Channel.js'
await tap.test('PUT /messsages/[messageId]', async (t) => { await test('PUT /messsages/[messageId]', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
const newValue = 'some message' const newValue = 'some message'
sinon.stub(prisma, 'message').value({ sinon.stub(prisma, 'message').value({
@ -48,18 +50,18 @@ await tap.test('PUT /messsages/[messageId]', async (t) => {
payload: { value: newValue } payload: { value: newValue }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.id, messageExample.id) assert.strictEqual(responseJson.id, messageExample.id)
t.equal(responseJson.value, newValue) assert.strictEqual(responseJson.value, newValue)
t.equal(responseJson.type, messageExample.type) assert.strictEqual(responseJson.type, messageExample.type)
t.equal(responseJson.mimetype, messageExample.mimetype) assert.strictEqual(responseJson.mimetype, messageExample.mimetype)
t.equal(responseJson.member.id, memberExample.id) assert.strictEqual(responseJson.member.id, memberExample.id)
t.equal(responseJson.member.isOwner, memberExample.isOwner) assert.strictEqual(responseJson.member.isOwner, memberExample.isOwner)
t.equal(responseJson.member.user.id, userExample.id) assert.strictEqual(responseJson.member.user.id, userExample.id)
t.equal(responseJson.member.user.name, userExample.name) assert.strictEqual(responseJson.member.user.name, userExample.name)
}) })
await t.test('fails if the message is not found', async (t) => { await t.test('fails if the message is not found', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
const newValue = 'some message' const newValue = 'some message'
sinon.stub(prisma, 'message').value({ sinon.stub(prisma, 'message').value({
@ -75,10 +77,10 @@ await tap.test('PUT /messsages/[messageId]', async (t) => {
}, },
payload: { value: newValue } payload: { value: newValue }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test('fails if the member is not found', async (t) => { await t.test('fails if the member is not found', async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
const newValue = 'some message' const newValue = 'some message'
sinon.stub(prisma, 'message').value({ sinon.stub(prisma, 'message').value({
@ -102,12 +104,12 @@ await tap.test('PUT /messsages/[messageId]', async (t) => {
}, },
payload: { value: newValue } payload: { value: newValue }
}) })
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
}) })
await t.test( await t.test(
'fails if the member is not the owner of the message', 'fails if the member is not the owner of the message',
async (t) => { async () => {
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
const newValue = 'some message' const newValue = 'some message'
const randomUserIdOwnerOfMessage = 14 const randomUserIdOwnerOfMessage = 14
@ -135,7 +137,7 @@ await tap.test('PUT /messsages/[messageId]', async (t) => {
}, },
payload: { value: newValue } payload: { value: newValue }
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
} }
) )
}) })

View File

@ -2,12 +2,12 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { messageSchema } from '../../../models/Message.js' import { messageSchema } from '#src/models/Message.js'
import { memberSchema } from '../../../models/Member.js' import { memberSchema } from '#src/models/Member.js'
import { userPublicWithoutSettingsSchema } from '../../../models/User.js' import { userPublicWithoutSettingsSchema } from '#src/models/User.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
messageId: messageSchema.id messageId: messageSchema.id
@ -53,8 +53,8 @@ export const deleteMessageService: FastifyPluginAsync = async (fastify) => {
if (request.user == null) { if (request.user == null) {
throw fastify.httpErrors.forbidden() throw fastify.httpErrors.forbidden()
} }
const { user } = request const { user, params } = request
const { messageId } = request.params const { messageId } = params
const messageCheck = await prisma.message.findFirst({ const messageCheck = await prisma.message.findFirst({
where: { id: messageId }, where: { id: messageId },
include: { include: {

View File

@ -2,12 +2,12 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { messageSchema } from '../../../models/Message.js' import { messageSchema } from '#src/models/Message.js'
import { memberSchema } from '../../../models/Member.js' import { memberSchema } from '#src/models/Member.js'
import { userPublicWithoutSettingsSchema } from '../../../models/User.js' import { userPublicWithoutSettingsSchema } from '#src/models/User.js'
const bodyPutServiceSchema = Type.Object({ const bodyPutServiceSchema = Type.Object({
value: messageSchema.value value: messageSchema.value
@ -61,9 +61,9 @@ export const putMessageService: FastifyPluginAsync = async (fastify) => {
if (request.user == null) { if (request.user == null) {
throw fastify.httpErrors.forbidden() throw fastify.httpErrors.forbidden()
} }
const { user } = request const { user, params, body } = request
const { messageId } = request.params const { messageId } = params
const { value } = request.body const { value } = body
const messageCheck = await prisma.message.findFirst({ const messageCheck = await prisma.message.findFirst({
where: { id: messageId, type: 'text' }, where: { id: messageId, type: 'text' },
include: { include: {

View File

@ -1,17 +1,19 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { userExample } from '../../../../models/User.js' import { userExample } from '#src/models/User.js'
import { userSettingsExample } from '../../../../models/UserSettings.js' import { userSettingsExample } from '#src/models/UserSettings.js'
await tap.test('GET /users/[userId]', async (t) => { await test('GET /users/[userId]', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
sinon.stub(prisma, 'guild').value({ sinon.stub(prisma, 'guild').value({
findMany: async () => { findMany: async () => {
return [] return []
@ -32,12 +34,12 @@ await tap.test('GET /users/[userId]', async (t) => {
url: `/users/${userExample.id}` url: `/users/${userExample.id}`
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.user.id, userExample.id) assert.strictEqual(responseJson.user.id, userExample.id)
t.equal(responseJson.user.name, userExample.name) assert.strictEqual(responseJson.user.name, userExample.name)
}) })
await t.test('fails with not found user', async (t) => { await t.test('fails with not found user', async () => {
sinon.stub(prisma, 'userSetting').value({ sinon.stub(prisma, 'userSetting').value({
findFirst: async () => { findFirst: async () => {
return null return null
@ -48,7 +50,7 @@ await tap.test('GET /users/[userId]', async (t) => {
url: `/users/1` url: `/users/1`
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 404) assert.strictEqual(response.statusCode, 404)
t.equal(responseJson.message, 'User not found') assert.strictEqual(responseJson.message, 'User not found')
}) })
}) })

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import { userPublicSchema } from '../../../models/User.js' import { userPublicSchema } from '#src/models/User.js'
import { guildSchema } from '../../../models/Guild.js' import { guildSchema } from '#src/models/Guild.js'
const parametersGetUserSchema = Type.Object({ const parametersGetUserSchema = Type.Object({
userId: userPublicSchema.id userId: userPublicSchema.id

View File

@ -1,16 +1,18 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { userExample } from '../../../../models/User.js' import { userExample } from '#src/models/User.js'
await tap.test('GET /users/confirm-email', async (t) => { await test('GET /users/confirm-email', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
sinon.stub(prisma, 'user').value({ sinon.stub(prisma, 'user').value({
findFirst: async () => { findFirst: async () => {
return userExample return userExample
@ -26,10 +28,10 @@ await tap.test('GET /users/confirm-email', async (t) => {
temporaryToken: userExample.temporaryToken ?? '' temporaryToken: userExample.temporaryToken ?? ''
} }
}) })
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
}) })
await t.test('should fails with invalid `temporaryToken`', async (t) => { await t.test('should fails with invalid `temporaryToken`', async () => {
sinon.stub(prisma, 'user').value({ sinon.stub(prisma, 'user').value({
findFirst: async () => { findFirst: async () => {
return null return null
@ -45,6 +47,6 @@ await tap.test('GET /users/confirm-email', async (t) => {
temporaryToken: userExample.temporaryToken ?? '' temporaryToken: userExample.temporaryToken ?? ''
} }
}) })
t.equal(response.statusCode, 403) assert.strictEqual(response.statusCode, 403)
}) })
}) })

View File

@ -2,9 +2,9 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import { userSchema } from '../../../models/User.js' import { userSchema } from '#src/models/User.js'
const queryGetConfirmEmailSchema = Type.Object({ const queryGetConfirmEmailSchema = Type.Object({
redirectURI: Type.Optional(Type.String({ format: 'uri-reference' })), redirectURI: Type.Optional(Type.String({ format: 'uri-reference' })),
@ -54,7 +54,7 @@ export const getConfirmEmail: FastifyPluginAsync = async (fastify) => {
reply.statusCode = 200 reply.statusCode = 200
return 'Success, your email has been confirmed, you can now signin!' return 'Success, your email has been confirmed, you can now signin!'
} }
await reply.redirect(redirectURI) return await reply.redirect(redirectURI)
} }
}) })
} }

View File

@ -1,15 +1,17 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
await tap.test('GET /users/current', async (t) => { await test('GET /users/current', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds', async (t) => { await t.test('succeeds', async () => {
const { accessToken, user } = await authenticateUserTest() const { accessToken, user } = await authenticateUserTest()
const response = await application.inject({ const response = await application.inject({
method: 'GET', method: 'GET',
@ -19,16 +21,16 @@ await tap.test('GET /users/current', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.user.name, user.name) assert.strictEqual(responseJson.user.name, user.name)
t.strictSame(responseJson.user.strategies, ['Local']) assert.deepStrictEqual(responseJson.user.strategies, ['Local'])
}) })
await t.test('fails with unauthenticated user', async (t) => { await t.test('fails with unauthenticated user', async () => {
const response = await application.inject({ const response = await application.inject({
method: 'GET', method: 'GET',
url: '/users/current' url: '/users/current'
}) })
t.equal(response.statusCode, 401) assert.strictEqual(response.statusCode, 401)
}) })
}) })

View File

@ -1,16 +1,18 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../application.js' import { application } from '#src/application.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { authenticateUserTest } from '../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
await tap.test('PUT /users/current', async (t) => { await test('PUT /users/current', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test('succeeds with valid accessToken and valid name', async (t) => { await t.test('succeeds with valid accessToken and valid name', async () => {
const newName = 'John Doe' const newName = 'John Doe'
const { accessToken, user, userStubValue } = await authenticateUserTest() const { accessToken, user, userStubValue } = await authenticateUserTest()
sinon.stub(prisma, 'user').value({ sinon.stub(prisma, 'user').value({
@ -36,11 +38,11 @@ await tap.test('PUT /users/current', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.user.name, newName) assert.strictEqual(responseJson.user.name, newName)
}) })
await t.test('succeeds and only update the status', async (t) => { await t.test('succeeds and only update the status', async () => {
const newStatus = '👀 Working on secret projects...' const newStatus = '👀 Working on secret projects...'
const { accessToken, user, userStubValue } = await authenticateUserTest() const { accessToken, user, userStubValue } = await authenticateUserTest()
sinon.stub(prisma, 'user').value({ sinon.stub(prisma, 'user').value({
@ -66,12 +68,12 @@ await tap.test('PUT /users/current', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.user.name, user.name) assert.strictEqual(responseJson.user.name, user.name)
t.equal(responseJson.user.status, newStatus) assert.strictEqual(responseJson.user.status, newStatus)
}) })
await t.test('fails with name already used', async (t) => { await t.test('fails with name already used', async () => {
const newName = 'John Doe' const newName = 'John Doe'
const { accessToken, user, userStubValue } = await authenticateUserTest() const { accessToken, user, userStubValue } = await authenticateUserTest()
sinon.stub(prisma, 'user').value({ sinon.stub(prisma, 'user').value({
@ -90,10 +92,10 @@ await tap.test('PUT /users/current', async (t) => {
name: newName name: newName
} }
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
}) })
await t.test('fails with invalid website url', async (t) => { await t.test('fails with invalid website url', async () => {
const newWebsite = 'invalid website url' const newWebsite = 'invalid website url'
const { accessToken } = await authenticateUserTest() const { accessToken } = await authenticateUserTest()
const response = await application.inject({ const response = await application.inject({
@ -106,10 +108,10 @@ await tap.test('PUT /users/current', async (t) => {
website: newWebsite website: newWebsite
} }
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
}) })
await t.test('succeeds with valid website url', async (t) => { await t.test('succeeds with valid website url', async () => {
const newWebsite = 'https://somerandomwebsite.com' const newWebsite = 'https://somerandomwebsite.com'
const { accessToken, user, userStubValue } = await authenticateUserTest() const { accessToken, user, userStubValue } = await authenticateUserTest()
sinon.stub(prisma, 'user').value({ sinon.stub(prisma, 'user').value({
@ -135,8 +137,8 @@ await tap.test('PUT /users/current', async (t) => {
} }
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.user.name, user.name) assert.strictEqual(responseJson.user.name, user.name)
t.equal(responseJson.user.website, newWebsite) assert.strictEqual(responseJson.user.website, newWebsite)
}) })
}) })

View File

@ -1,9 +1,9 @@
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { userCurrentSchema } from '../../../models/User.js' import { userCurrentSchema } from '#src/models/User.js'
const getCurrentUserSchema: FastifySchema = { const getCurrentUserSchema: FastifySchema = {
description: 'GET the current connected user', description: 'GET the current connected user',

View File

@ -2,10 +2,10 @@ import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import fastifyMultipart from '@fastify/multipart' import fastifyMultipart from '@fastify/multipart'
import authenticateUser from '../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { fastifyErrors } from '../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { uploadFile } from '../../../../tools/utils/uploadFile.js' import { uploadFile } from '#src/tools/utils/uploadFile.js'
const putServiceSchema: FastifySchema = { const putServiceSchema: FastifySchema = {
description: 'Edit the current connected user logo', description: 'Edit the current connected user logo',

View File

@ -4,14 +4,14 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { userCurrentSchema, userSchema } from '../../../models/User.js' import { userCurrentSchema, userSchema } from '#src/models/User.js'
import { sendEmail } from '../../../tools/email/sendEmail.js' import { sendEmail } from '#src/tools/email/sendEmail.js'
import { API_URL } from '../../../tools/configurations.js' import { API_URL } from '#src/tools/configurations.js'
import type { Language, Theme } from '../../../models/UserSettings.js' import type { Language, Theme } from '#src/models/UserSettings.js'
import { parseStringNullish } from '../../../tools/utils/parseStringNullish.js' import { parseStringNullish } from '#src/tools/utils/parseStringNullish.js'
const bodyPutServiceSchema = Type.Object({ const bodyPutServiceSchema = Type.Object({
name: Type.Optional(userSchema.name), name: Type.Optional(userSchema.name),

View File

@ -1,19 +1,21 @@
import tap from 'tap' import test from 'node:test'
import assert from 'node:assert/strict'
import sinon from 'sinon' import sinon from 'sinon'
import { application } from '../../../../../application.js' import { application } from '#src/application.js'
import { authenticateUserTest } from '../../../../../__test__/utils/authenticateUserTest.js' import { authenticateUserTest } from '#src/__test__/utils/authenticateUserTest.js'
import prisma from '../../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { userSettingsExample } from '../../../../../models/UserSettings.js' import { userSettingsExample } from '#src/models/UserSettings.js'
await tap.test('PUT /users/current/settings', async (t) => { await test('PUT /users/current/settings', async (t) => {
t.afterEach(() => { t.afterEach(() => {
sinon.restore() sinon.restore()
}) })
await t.test( await t.test(
'succeeds and edit the theme, language, isPublicEmail and isPublicGuilds', 'succeeds and edit the theme, language, isPublicEmail and isPublicGuilds',
async (t) => { async () => {
const newSettings = { const newSettings = {
theme: 'light', theme: 'light',
language: 'fr', language: 'fr',
@ -42,15 +44,21 @@ await tap.test('PUT /users/current/settings', async (t) => {
payload: newSettings payload: newSettings
}) })
const responseJson = response.json() const responseJson = response.json()
t.equal(response.statusCode, 200) assert.strictEqual(response.statusCode, 200)
t.equal(responseJson.settings.theme, newSettings.theme) assert.strictEqual(responseJson.settings.theme, newSettings.theme)
t.equal(responseJson.settings.language, newSettings.language) assert.strictEqual(responseJson.settings.language, newSettings.language)
t.equal(responseJson.settings.isPublicEmail, newSettings.isPublicEmail) assert.strictEqual(
t.equal(responseJson.settings.isPublicGuilds, newSettings.isPublicGuilds) responseJson.settings.isPublicEmail,
newSettings.isPublicEmail
)
assert.strictEqual(
responseJson.settings.isPublicGuilds,
newSettings.isPublicGuilds
)
} }
) )
await t.test('fails with invalid language', async (t) => { await t.test('fails with invalid language', async () => {
const newSettings = { const newSettings = {
language: 'somerandomlanguage' language: 'somerandomlanguage'
} }
@ -75,6 +83,6 @@ await tap.test('PUT /users/current/settings', async (t) => {
}, },
payload: newSettings payload: newSettings
}) })
t.equal(response.statusCode, 400) assert.strictEqual(response.statusCode, 400)
}) })
}) })

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { userSettingsSchema } from '../../../../models/UserSettings.js' import { userSettingsSchema } from '#src/models/UserSettings.js'
const bodyPutServiceSchema = Type.Object({ const bodyPutServiceSchema = Type.Object({
theme: Type.Optional(userSettingsSchema.theme), theme: Type.Optional(userSettingsSchema.theme),

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import prisma from '../../../../tools/database/prisma.js' import prisma from '#src/tools/database/prisma.js'
import { fastifyErrors } from '../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import authenticateUser from '../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
import { oauthSchema } from '../../../../models/OAuth.js' import { oauthSchema } from '#src/models/OAuth.js'
const parametersSchema = Type.Object({ const parametersSchema = Type.Object({
provider: oauthSchema.provider provider: oauthSchema.provider
@ -45,8 +45,8 @@ export const deleteProviderService: FastifyPluginAsync = async (fastify) => {
if (request.user == null) { if (request.user == null) {
throw fastify.httpErrors.forbidden() throw fastify.httpErrors.forbidden()
} }
const { user } = request const { user, params } = request
const { provider } = request.params const { provider } = params
const OAuths = await prisma.oAuth.findMany({ const OAuths = await prisma.oAuth.findMany({
where: { userId: user.current.id } where: { userId: user.current.id }
}) })

View File

@ -2,14 +2,14 @@ import querystring from 'node:querystring'
import axios from 'axios' import axios from 'axios'
import { OAuthStrategy } from '../../../../../tools/utils/OAuthStrategy.js' import { OAuthStrategy } from '#src/tools/utils/OAuthStrategy.js'
export const DISCORD_PROVIDER = 'Discord' export const DISCORD_PROVIDER = 'Discord'
export const DISCORD_BASE_URL = 'https://discord.com/api/v10' export const DISCORD_BASE_URL = 'https://discord.com/api/v10'
export const DISCORD_CLIENT_ID = export const DISCORD_CLIENT_ID =
process.env.DISCORD_CLIENT_ID ?? 'DISCORD_CLIENT_ID' process.env['DISCORD_CLIENT_ID'] ?? 'DISCORD_CLIENT_ID'
export const DISCORD_CLIENT_SECRET = export const DISCORD_CLIENT_SECRET =
process.env.DISCORD_CLIENT_SECRET ?? 'DISCORD_CLIENT_SECRET' process.env['DISCORD_CLIENT_SECRET'] ?? 'DISCORD_CLIENT_SECRET'
export const discordStrategy = new OAuthStrategy(DISCORD_PROVIDER) export const discordStrategy = new OAuthStrategy(DISCORD_PROVIDER)
export interface DiscordUser { export interface DiscordUser {

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import { API_URL } from '../../../../../tools/configurations.js' import { API_URL } from '#src/tools/configurations.js'
import { fastifyErrors } from '../../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import { DISCORD_BASE_URL, DISCORD_CLIENT_ID } from '../__utils__/utils.js' import { DISCORD_BASE_URL, DISCORD_CLIENT_ID } from '../__utils__/utils.js'
import authenticateUser from '../../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
const querySchema = Type.Object({ const querySchema = Type.Object({
redirectURI: Type.String({ format: 'uri-reference' }) redirectURI: Type.String({ format: 'uri-reference' })

View File

@ -2,11 +2,11 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import { API_URL } from '../../../../../tools/configurations.js' import { API_URL } from '#src/tools/configurations.js'
import { fastifyErrors } from '../../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import { discordStrategy, getDiscordUserData } from '../__utils__/utils.js' import { discordStrategy, getDiscordUserData } from '../__utils__/utils.js'
import { buildQueryURL } from '../../../../../tools/utils/buildQueryURL.js' import { buildQueryURL } from '#src/tools/utils/buildQueryURL.js'
import { getUserWithBearerToken } from '../../../../../tools/plugins/authenticateUser.js' import { getUserWithBearerToken } from '#src/tools/plugins/authenticateUser.js'
const querySchema = Type.Object({ const querySchema = Type.Object({
code: Type.String(), code: Type.String(),

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import { API_URL } from '../../../../../tools/configurations.js' import { API_URL } from '#src/tools/configurations.js'
import { fastifyErrors } from '../../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import { discordStrategy, getDiscordUserData } from '../__utils__/utils.js' import { discordStrategy, getDiscordUserData } from '../__utils__/utils.js'
import { buildQueryURL } from '../../../../../tools/utils/buildQueryURL.js' import { buildQueryURL } from '#src/tools/utils/buildQueryURL.js'
const querySchema = Type.Object({ const querySchema = Type.Object({
code: Type.String(), code: Type.String(),

View File

@ -2,8 +2,8 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import { API_URL } from '../../../../../tools/configurations.js' import { API_URL } from '#src/tools/configurations.js'
import { fastifyErrors } from '../../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import { DISCORD_BASE_URL, DISCORD_CLIENT_ID } from '../__utils__/utils.js' import { DISCORD_BASE_URL, DISCORD_CLIENT_ID } from '../__utils__/utils.js'
const querySchema = Type.Object({ const querySchema = Type.Object({

View File

@ -2,15 +2,15 @@ import querystring from 'node:querystring'
import axios from 'axios' import axios from 'axios'
import { OAuthStrategy } from '../../../../../tools/utils/OAuthStrategy.js' import { OAuthStrategy } from '#src/tools/utils/OAuthStrategy.js'
export const GITHUB_PROVIDER = 'GitHub' export const GITHUB_PROVIDER = 'GitHub'
export const GITHUB_BASE_URL = 'https://github.com' export const GITHUB_BASE_URL = 'https://github.com'
export const GITHUB_API_BASE_URL = 'https://api.github.com' export const GITHUB_API_BASE_URL = 'https://api.github.com'
export const GITHUB_CLIENT_ID = export const GITHUB_CLIENT_ID =
process.env.GITHUB_CLIENT_ID ?? 'GITHUB_CLIENT_ID' process.env['GITHUB_CLIENT_ID'] ?? 'GITHUB_CLIENT_ID'
export const GITHUB_CLIENT_SECRET = export const GITHUB_CLIENT_SECRET =
process.env.GITHUB_CLIENT_SECRET ?? 'GITHUB_CLIENT_SECRET' process.env['GITHUB_CLIENT_SECRET'] ?? 'GITHUB_CLIENT_SECRET'
export const githubStrategy = new OAuthStrategy(GITHUB_PROVIDER) export const githubStrategy = new OAuthStrategy(GITHUB_PROVIDER)
export interface GitHubUser { export interface GitHubUser {

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import { API_URL } from '../../../../../tools/configurations.js' import { API_URL } from '#src/tools/configurations.js'
import { fastifyErrors } from '../../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import { GITHUB_BASE_URL, GITHUB_CLIENT_ID } from '../__utils__/utils.js' import { GITHUB_BASE_URL, GITHUB_CLIENT_ID } from '../__utils__/utils.js'
import authenticateUser from '../../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
const querySchema = Type.Object({ const querySchema = Type.Object({
redirectURI: Type.String({ format: 'uri-reference' }) redirectURI: Type.String({ format: 'uri-reference' })

View File

@ -2,11 +2,11 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import { API_URL } from '../../../../../tools/configurations.js' import { API_URL } from '#src/tools/configurations.js'
import { fastifyErrors } from '../../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import { githubStrategy, getGitHubUserData } from '../__utils__/utils.js' import { githubStrategy, getGitHubUserData } from '../__utils__/utils.js'
import { buildQueryURL } from '../../../../../tools/utils/buildQueryURL.js' import { buildQueryURL } from '#src/tools/utils/buildQueryURL.js'
import { getUserWithBearerToken } from '../../../../../tools/plugins/authenticateUser.js' import { getUserWithBearerToken } from '#src/tools/plugins/authenticateUser.js'
const querySchema = Type.Object({ const querySchema = Type.Object({
code: Type.String(), code: Type.String(),

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import { API_URL } from '../../../../../tools/configurations.js' import { API_URL } from '#src/tools/configurations.js'
import { fastifyErrors } from '../../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import { githubStrategy, getGitHubUserData } from '../__utils__/utils.js' import { githubStrategy, getGitHubUserData } from '../__utils__/utils.js'
import { buildQueryURL } from '../../../../../tools/utils/buildQueryURL.js' import { buildQueryURL } from '#src/tools/utils/buildQueryURL.js'
const querySchema = Type.Object({ const querySchema = Type.Object({
code: Type.String(), code: Type.String(),

View File

@ -2,8 +2,8 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import { API_URL } from '../../../../../tools/configurations.js' import { API_URL } from '#src/tools/configurations.js'
import { fastifyErrors } from '../../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import { GITHUB_BASE_URL, GITHUB_CLIENT_ID } from '../__utils__/utils.js' import { GITHUB_BASE_URL, GITHUB_CLIENT_ID } from '../__utils__/utils.js'
const querySchema = Type.Object({ const querySchema = Type.Object({

View File

@ -2,7 +2,7 @@ import querystring from 'node:querystring'
import axios from 'axios' import axios from 'axios'
import { OAuthStrategy } from '../../../../../tools/utils/OAuthStrategy.js' import { OAuthStrategy } from '#src/tools/utils/OAuthStrategy.js'
export const GOOGLE_PROVIDER = 'Google' export const GOOGLE_PROVIDER = 'Google'
export const GOOGLE_BASE_URL = 'https://accounts.google.com/o/oauth2/v2/auth' export const GOOGLE_BASE_URL = 'https://accounts.google.com/o/oauth2/v2/auth'
@ -10,9 +10,9 @@ export const GOOGLE_OAUTH2_TOKEN = 'https://oauth2.googleapis.com/token'
export const GOOGLE_USERINFO = export const GOOGLE_USERINFO =
'https://www.googleapis.com/oauth2/v1/userinfo?alt=json' 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json'
export const GOOGLE_CLIENT_ID = export const GOOGLE_CLIENT_ID =
process.env.GOOGLE_CLIENT_ID ?? 'GOOGLE_CLIENT_ID' process.env['GOOGLE_CLIENT_ID'] ?? 'GOOGLE_CLIENT_ID'
export const GOOGLE_CLIENT_SECRET = export const GOOGLE_CLIENT_SECRET =
process.env.GOOGLE_CLIENT_SECRET ?? 'GOOGLE_CLIENT_SECRET' process.env['GOOGLE_CLIENT_SECRET'] ?? 'GOOGLE_CLIENT_SECRET'
export const googleStrategy = new OAuthStrategy(GOOGLE_PROVIDER) export const googleStrategy = new OAuthStrategy(GOOGLE_PROVIDER)
export interface GoogleUser { export interface GoogleUser {

View File

@ -2,10 +2,10 @@ import type { Static } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox' import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync, FastifySchema } from 'fastify' import type { FastifyPluginAsync, FastifySchema } from 'fastify'
import { API_URL } from '../../../../../tools/configurations.js' import { API_URL } from '#src/tools/configurations.js'
import { fastifyErrors } from '../../../../../models/utils.js' import { fastifyErrors } from '#src/models/utils.js'
import { GOOGLE_BASE_URL, GOOGLE_CLIENT_ID } from '../__utils__/utils.js' import { GOOGLE_BASE_URL, GOOGLE_CLIENT_ID } from '../__utils__/utils.js'
import authenticateUser from '../../../../../tools/plugins/authenticateUser.js' import authenticateUser from '#src/tools/plugins/authenticateUser.js'
const querySchema = Type.Object({ const querySchema = Type.Object({
redirectURI: Type.String({ format: 'uri-reference' }) redirectURI: Type.String({ format: 'uri-reference' })

Some files were not shown because too many files have changed in this diff Show More