feat(scripts): add delete dead uploaded files

This commit is contained in:
Divlo 2022-03-05 18:49:38 +00:00
parent 1bcee76324
commit 9e6bf25c83
No known key found for this signature in database
GPG Key ID: 8F9478F220CE65E9
8 changed files with 438 additions and 427 deletions

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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",

View File

@ -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,

View 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)
})

View 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)
})
})