feat(scripts): add delete dead uploaded files
This commit is contained in:
parent
1bcee76324
commit
9e6bf25c83
@ -21,7 +21,7 @@ All work on **Thream/api** happens directly on [GitHub](https://github.com/Threa
|
|||||||
|
|
||||||
- **Please first discuss** the change you wish to make via issues.
|
- **Please first discuss** the change you wish to make via issues.
|
||||||
|
|
||||||
- Ensure your code respect `eslint` and `prettier`.
|
- Ensure your code respect linting.
|
||||||
|
|
||||||
- Make sure your **code passes the tests**.
|
- Make sure your **code passes the tests**.
|
||||||
|
|
||||||
@ -70,6 +70,7 @@ git commit -m "fix(services): should emit events to connected users"
|
|||||||
├── prisma
|
├── prisma
|
||||||
└── src
|
└── src
|
||||||
├── models
|
├── models
|
||||||
|
├── scripts
|
||||||
├── services
|
├── services
|
||||||
├── tools
|
├── tools
|
||||||
└── typings
|
└── typings
|
||||||
@ -81,6 +82,7 @@ git commit -m "fix(services): should emit events to connected users"
|
|||||||
- `prisma` : contains the prisma schema and migrations
|
- `prisma` : contains the prisma schema and migrations
|
||||||
- `src` : all source files
|
- `src` : all source files
|
||||||
- `models` : models that represent tables in database as JSON schema
|
- `models` : models that represent tables in database as JSON schema
|
||||||
|
- `scripts` : scripts
|
||||||
- `services` : all REST API endpoints
|
- `services` : all REST API endpoints
|
||||||
- `tools` : configs and utilities
|
- `tools` : configs and utilities
|
||||||
- `typings` : types gloablly used in the project
|
- `typings` : types gloablly used in the project
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
FROM node:16.13.2 AS dependencies
|
FROM node:16.14.0 AS dependencies
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
COPY ./package*.json ./
|
COPY ./package*.json ./
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
FROM node:16.13.2 AS builder
|
FROM node:16.14.0 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:16.13.2 AS runner
|
FROM node:16.14.0 AS runner
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
COPY --from=builder /usr/src/app/node_modules ./node_modules
|
COPY --from=builder /usr/src/app/node_modules ./node_modules
|
||||||
|
@ -16,9 +16,7 @@
|
|||||||
|
|
||||||
## 📜 About
|
## 📜 About
|
||||||
|
|
||||||
Thream's application programming interface to stay close with your friends and communities.
|
Thream's Application Programming Interface (API) to stay close with your friends and communities.
|
||||||
|
|
||||||
This project was bootstrapped with [create-fullstack-app](https://github.com/Divlo/create-fullstack-app).
|
|
||||||
|
|
||||||
## ⚙️ Getting Started
|
## ⚙️ Getting Started
|
||||||
|
|
||||||
|
695
package-lock.json
generated
695
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@
|
|||||||
"start": "cross-env NODE_ENV=production node build/index.js",
|
"start": "cross-env NODE_ENV=production node build/index.js",
|
||||||
"dev": "concurrently -k -n \"TypeScript,Node\" -p \"[{name}]\" -c \"blue,green\" \"swc ./src --out-dir ./build --watch\" \"cross-env NODE_ENV=development nodemon build/index.js\"",
|
"dev": "concurrently -k -n \"TypeScript,Node\" -p \"[{name}]\" -c \"blue,green\" \"swc ./src --out-dir ./build --watch\" \"cross-env NODE_ENV=development nodemon build/index.js\"",
|
||||||
"generate": "plop",
|
"generate": "plop",
|
||||||
|
"scripts:delete-dead-uploaded-files": "node build/scripts/delete-dead-uploaded-files.js",
|
||||||
"lint:commit": "commitlint",
|
"lint:commit": "commitlint",
|
||||||
"lint:editorconfig": "editorconfig-checker",
|
"lint:editorconfig": "editorconfig-checker",
|
||||||
"lint:markdown": "markdownlint \"**/*.md\" --dot --ignore-path \".gitignore\"",
|
"lint:markdown": "markdownlint \"**/*.md\" --dot --ignore-path \".gitignore\"",
|
||||||
@ -46,7 +47,7 @@
|
|||||||
"fastify-rate-limit": "5.7.2",
|
"fastify-rate-limit": "5.7.2",
|
||||||
"fastify-sensible": "3.1.2",
|
"fastify-sensible": "3.1.2",
|
||||||
"fastify-static": "4.5.0",
|
"fastify-static": "4.5.0",
|
||||||
"fastify-swagger": "4.15.0",
|
"fastify-swagger": "4.17.0",
|
||||||
"fastify-url-data": "3.0.3",
|
"fastify-url-data": "3.0.3",
|
||||||
"http-errors": "2.0.0",
|
"http-errors": "2.0.0",
|
||||||
"jsonwebtoken": "8.5.1",
|
"jsonwebtoken": "8.5.1",
|
||||||
@ -60,7 +61,7 @@
|
|||||||
"@commitlint/config-conventional": "16.2.1",
|
"@commitlint/config-conventional": "16.2.1",
|
||||||
"@saithodev/semantic-release-backmerge": "2.1.2",
|
"@saithodev/semantic-release-backmerge": "2.1.2",
|
||||||
"@swc/cli": "0.1.55",
|
"@swc/cli": "0.1.55",
|
||||||
"@swc/core": "1.2.146",
|
"@swc/core": "1.2.148",
|
||||||
"@swc/jest": "0.2.20",
|
"@swc/jest": "0.2.20",
|
||||||
"@types/bcryptjs": "2.4.2",
|
"@types/bcryptjs": "2.4.2",
|
||||||
"@types/busboy": "1.3.0",
|
"@types/busboy": "1.3.0",
|
||||||
@ -76,7 +77,7 @@
|
|||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"editorconfig-checker": "4.0.2",
|
"editorconfig-checker": "4.0.2",
|
||||||
"eslint": "8.10.0",
|
"eslint": "8.10.0",
|
||||||
"eslint-config-prettier": "8.4.0",
|
"eslint-config-prettier": "8.5.0",
|
||||||
"eslint-config-conventions": "1.1.0",
|
"eslint-config-conventions": "1.1.0",
|
||||||
"eslint-plugin-import": "2.25.4",
|
"eslint-plugin-import": "2.25.4",
|
||||||
"eslint-plugin-prettier": "4.0.0",
|
"eslint-plugin-prettier": "4.0.0",
|
||||||
@ -86,7 +87,7 @@
|
|||||||
"jest": "27.5.1",
|
"jest": "27.5.1",
|
||||||
"jest-mock-extended": "2.0.4",
|
"jest-mock-extended": "2.0.4",
|
||||||
"jest-ts-webcompat-resolver": "1.0.0",
|
"jest-ts-webcompat-resolver": "1.0.0",
|
||||||
"lint-staged": "12.3.4",
|
"lint-staged": "12.3.5",
|
||||||
"markdownlint-cli": "0.31.1",
|
"markdownlint-cli": "0.31.1",
|
||||||
"nodemon": "2.0.15",
|
"nodemon": "2.0.15",
|
||||||
"plop": "3.0.5",
|
"plop": "3.0.5",
|
||||||
|
@ -3,13 +3,15 @@ import { mockDeep, mockReset, DeepMockProxy } from 'jest-mock-extended'
|
|||||||
|
|
||||||
import prisma from '../tools/database/prisma.js'
|
import prisma from '../tools/database/prisma.js'
|
||||||
|
|
||||||
jest.mock('nodemailer', () => ({
|
jest.mock('nodemailer', () => {
|
||||||
createTransport: () => {
|
return {
|
||||||
return {
|
createTransport: () => {
|
||||||
sendMail: jest.fn(async () => {})
|
return {
|
||||||
|
sendMail: jest.fn(async () => {})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
|
|
||||||
jest.mock('../tools/database/prisma.js', () => ({
|
jest.mock('../tools/database/prisma.js', () => ({
|
||||||
__esModule: true,
|
__esModule: true,
|
||||||
|
58
src/scripts/delete-dead-uploaded-files.ts
Normal file
58
src/scripts/delete-dead-uploaded-files.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import fs from 'node:fs'
|
||||||
|
|
||||||
|
import prisma from '../tools/database/prisma.js'
|
||||||
|
import { UPLOADS_URL } from '../tools/configurations/index.js'
|
||||||
|
|
||||||
|
const getPathStoredInDatabaseFromFile = (
|
||||||
|
file: string,
|
||||||
|
folderInUploadsFolder: string
|
||||||
|
): string => {
|
||||||
|
return `/uploads/${folderInUploadsFolder}/${file}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteDeadUploadedFiles = async (
|
||||||
|
folderInUploadsFolder: string,
|
||||||
|
getElementInDatabase: (file: string) => Promise<unknown | null>
|
||||||
|
): Promise<void> => {
|
||||||
|
const UPLOADS_FILES_URL = new URL(`./${folderInUploadsFolder}`, UPLOADS_URL)
|
||||||
|
const files = await fs.promises.readdir(UPLOADS_FILES_URL)
|
||||||
|
for (const file of files) {
|
||||||
|
if (file !== '.gitkeep') {
|
||||||
|
const pathStoredInDatabase = getPathStoredInDatabaseFromFile(
|
||||||
|
file,
|
||||||
|
folderInUploadsFolder
|
||||||
|
)
|
||||||
|
const element = await getElementInDatabase(pathStoredInDatabase)
|
||||||
|
if (element == null) {
|
||||||
|
const fileURL = new URL(
|
||||||
|
`./${folderInUploadsFolder}/${file}`,
|
||||||
|
UPLOADS_URL
|
||||||
|
)
|
||||||
|
await fs.promises.rm(fileURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const main = async (): Promise<void> => {
|
||||||
|
await deleteDeadUploadedFiles('guilds', async (icon: string) => {
|
||||||
|
return await prisma.guild.findFirst({
|
||||||
|
where: { icon }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await deleteDeadUploadedFiles('messages', async (value: string) => {
|
||||||
|
return await prisma.message.findFirst({
|
||||||
|
where: { type: 'file', value }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await deleteDeadUploadedFiles('users', async (logo: string) => {
|
||||||
|
return await prisma.user.findFirst({
|
||||||
|
where: { logo }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(error)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
77
src/tools/plugins/__test__/authenticateUser.test.ts
Normal file
77
src/tools/plugins/__test__/authenticateUser.test.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import httpErrors from 'http-errors'
|
||||||
|
import jwt from 'jsonwebtoken'
|
||||||
|
|
||||||
|
import { userExample } from '../../../models/User.js'
|
||||||
|
import { prismaMock } from '../../../__test__/setup.js'
|
||||||
|
import { getUserWithBearerToken } from '../authenticateUser.js'
|
||||||
|
|
||||||
|
const { Unauthorized, Forbidden, BadRequest } = httpErrors
|
||||||
|
|
||||||
|
describe('tools/plugins/authenticateUser - getUserWithBearerToken', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shoulds succeeds with the right information', async () => {
|
||||||
|
prismaMock.user.findUnique.mockResolvedValue(userExample)
|
||||||
|
const currentStrategy = 'local'
|
||||||
|
jwt.verify = jest.fn<any, any[]>((() => {
|
||||||
|
return { id: userExample.id, currentStrategy }
|
||||||
|
}) as any)
|
||||||
|
const userWithBearerToken = await getUserWithBearerToken('Bearer token')
|
||||||
|
expect(userWithBearerToken.current.id).toEqual(userExample.id)
|
||||||
|
expect(userWithBearerToken.current.name).toEqual(userExample.name)
|
||||||
|
expect(userWithBearerToken.accessToken).toEqual('token')
|
||||||
|
expect(userWithBearerToken.currentStrategy).toEqual(currentStrategy)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shoulds throws `Unauthorized` if `bearerToken` is not a string', async () => {
|
||||||
|
await expect(
|
||||||
|
async () => await getUserWithBearerToken(undefined)
|
||||||
|
).rejects.toThrow(Unauthorized)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shoulds throws `Unauthorized` if `bearerToken` is not to the right format: `"Bearer token"`', async () => {
|
||||||
|
await expect(
|
||||||
|
async () => await getUserWithBearerToken('Bearer')
|
||||||
|
).rejects.toThrow(Unauthorized)
|
||||||
|
await expect(async () => await getUserWithBearerToken('')).rejects.toThrow(
|
||||||
|
Unauthorized
|
||||||
|
)
|
||||||
|
await expect(
|
||||||
|
async () => await getUserWithBearerToken('Bearer token token2')
|
||||||
|
).rejects.toThrow(Unauthorized)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shoulds throws `Forbidden` if invalid `bearerToken` by `jwt.verify`', async () => {
|
||||||
|
jwt.verify = jest.fn<any, any[]>((() => {
|
||||||
|
throw new Error('Invalid token')
|
||||||
|
}) as any)
|
||||||
|
await expect(
|
||||||
|
async () => await getUserWithBearerToken('Bearer token')
|
||||||
|
).rejects.toThrow(Forbidden)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("shoulds throws `Forbidden` if the user doesn't exist", async () => {
|
||||||
|
prismaMock.user.findUnique.mockResolvedValue(null)
|
||||||
|
jwt.verify = jest.fn<any, any[]>((() => {
|
||||||
|
return { id: userExample.id }
|
||||||
|
}) as any)
|
||||||
|
await expect(
|
||||||
|
async () => await getUserWithBearerToken('Bearer token')
|
||||||
|
).rejects.toThrow(Forbidden)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shoulds throws `BadRequest` if the user account is not confirmed', async () => {
|
||||||
|
prismaMock.user.findUnique.mockResolvedValue({
|
||||||
|
...userExample,
|
||||||
|
isConfirmed: false
|
||||||
|
})
|
||||||
|
jwt.verify = jest.fn<any, any[]>((() => {
|
||||||
|
return { id: userExample.id, currentStrategy: 'local' }
|
||||||
|
}) as any)
|
||||||
|
await expect(
|
||||||
|
async () => await getUserWithBearerToken('Bearer token')
|
||||||
|
).rejects.toThrow(BadRequest)
|
||||||
|
})
|
||||||
|
})
|
Reference in New Issue
Block a user