fix: file upload and OAuth2 (#10)
This commit is contained in:
		@@ -8,6 +8,8 @@ services:
 | 
				
			|||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
      - '..:/workspace:cached'
 | 
					      - '..:/workspace:cached'
 | 
				
			||||||
    command: 'sleep infinity'
 | 
					    command: 'sleep infinity'
 | 
				
			||||||
 | 
					    extra_hosts:
 | 
				
			||||||
 | 
					      - 'host.docker.internal:host-gateway'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  thream-database:
 | 
					  thream-database:
 | 
				
			||||||
    image: 'postgres:14.2'
 | 
					    image: 'postgres:14.2'
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										40
									
								
								.env.example
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								.env.example
									
									
									
									
									
								
							@@ -1,19 +1,21 @@
 | 
				
			|||||||
COMPOSE_PROJECT_NAME='thream-api'
 | 
					API_URL=http://localhost:8080
 | 
				
			||||||
HOST='0.0.0.0'
 | 
					COMPOSE_PROJECT_NAME=thream-api
 | 
				
			||||||
PORT='8080'
 | 
					DATABASE_URL=postgresql://user:password@thream-database:5432/thream
 | 
				
			||||||
NODE_ENV='development'
 | 
					DISCORD_CLIENT_ID=
 | 
				
			||||||
API_URL='http://localhost:8080'
 | 
					DISCORD_CLIENT_SECRET=
 | 
				
			||||||
DATABASE_URL='postgresql://user:password@thream-database:5432/thream'
 | 
					EMAIL_HOST=thream-maildev
 | 
				
			||||||
JWT_ACCESS_EXPIRES_IN='15 minutes'
 | 
					EMAIL_PASSWORD=password
 | 
				
			||||||
JWT_ACCESS_SECRET='accessTokenSecret'
 | 
					EMAIL_PORT=25
 | 
				
			||||||
JWT_REFRESH_SECRET='refreshTokenSecret'
 | 
					EMAIL_USER=no-reply@thream.fr
 | 
				
			||||||
DISCORD_CLIENT_ID=''
 | 
					FILE_UPLOADS_API_KEY=apiKeySecret
 | 
				
			||||||
DISCORD_CLIENT_SECRET=''
 | 
					FILE_UPLOADS_API_URL=http://host.docker.internal:8000
 | 
				
			||||||
GITHUB_CLIENT_ID=''
 | 
					GITHUB_CLIENT_ID=
 | 
				
			||||||
GITHUB_CLIENT_SECRET=''
 | 
					GITHUB_CLIENT_SECRET=
 | 
				
			||||||
GOOGLE_CLIENT_ID=''
 | 
					GOOGLE_CLIENT_ID=
 | 
				
			||||||
GOOGLE_CLIENT_SECRET=''
 | 
					GOOGLE_CLIENT_SECRET=
 | 
				
			||||||
EMAIL_HOST='thream-maildev'
 | 
					HOST=0.0.0.0
 | 
				
			||||||
EMAIL_USER='no-reply@thream.fr'
 | 
					JWT_ACCESS_EXPIRES_IN=15 minutes
 | 
				
			||||||
EMAIL_PASSWORD='password'
 | 
					JWT_ACCESS_SECRET=accessTokenSecret
 | 
				
			||||||
EMAIL_PORT='25'
 | 
					JWT_REFRESH_SECRET=refreshTokenSecret
 | 
				
			||||||
 | 
					NODE_ENV=development
 | 
				
			||||||
 | 
					PORT=8080
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -35,4 +35,3 @@ npm-debug.log*
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# misc
 | 
					# misc
 | 
				
			||||||
.DS_Store
 | 
					.DS_Store
 | 
				
			||||||
/uploads
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ FROM node:16.14.2 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
 | 
				
			||||||
COPY --from=builder /usr/src/app/start.sh ./start.sh
 | 
					COPY --from=builder /usr/src/app/start.sh ./docker-start.sh
 | 
				
			||||||
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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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.0.0](https://github.com/Thream/file-uploads-api/releases/tag/v1.0.0).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## ⚙️ Getting Started
 | 
					## ⚙️ Getting Started
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Prerequisites
 | 
					### Prerequisites
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										167
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										167
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -23,9 +23,8 @@
 | 
				
			|||||||
        "fastify-plugin": "3.0.1",
 | 
					        "fastify-plugin": "3.0.1",
 | 
				
			||||||
        "fastify-rate-limit": "5.8.0",
 | 
					        "fastify-rate-limit": "5.8.0",
 | 
				
			||||||
        "fastify-sensible": "3.1.2",
 | 
					        "fastify-sensible": "3.1.2",
 | 
				
			||||||
        "fastify-static": "4.6.1",
 | 
					 | 
				
			||||||
        "fastify-swagger": "5.1.0",
 | 
					        "fastify-swagger": "5.1.0",
 | 
				
			||||||
        "fastify-url-data": "3.0.3",
 | 
					        "form-data": "4.0.0",
 | 
				
			||||||
        "http-errors": "2.0.0",
 | 
					        "http-errors": "2.0.0",
 | 
				
			||||||
        "jsonwebtoken": "8.5.1",
 | 
					        "jsonwebtoken": "8.5.1",
 | 
				
			||||||
        "ms": "2.1.3",
 | 
					        "ms": "2.1.3",
 | 
				
			||||||
@@ -37,6 +36,7 @@
 | 
				
			|||||||
        "@commitlint/cli": "16.2.3",
 | 
					        "@commitlint/cli": "16.2.3",
 | 
				
			||||||
        "@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",
 | 
				
			||||||
 | 
					        "@semantic-release/git": "10.0.1",
 | 
				
			||||||
        "@swc/cli": "0.1.57",
 | 
					        "@swc/cli": "0.1.57",
 | 
				
			||||||
        "@swc/core": "1.2.164",
 | 
					        "@swc/core": "1.2.164",
 | 
				
			||||||
        "@types/bcryptjs": "2.4.2",
 | 
					        "@types/bcryptjs": "2.4.2",
 | 
				
			||||||
@@ -1159,6 +1159,28 @@
 | 
				
			|||||||
        "node": ">=14.17"
 | 
					        "node": ">=14.17"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@semantic-release/git": {
 | 
				
			||||||
 | 
					      "version": "10.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-10.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@semantic-release/error": "^3.0.0",
 | 
				
			||||||
 | 
					        "aggregate-error": "^3.0.0",
 | 
				
			||||||
 | 
					        "debug": "^4.0.0",
 | 
				
			||||||
 | 
					        "dir-glob": "^3.0.0",
 | 
				
			||||||
 | 
					        "execa": "^5.0.0",
 | 
				
			||||||
 | 
					        "lodash": "^4.17.4",
 | 
				
			||||||
 | 
					        "micromatch": "^4.0.0",
 | 
				
			||||||
 | 
					        "p-reduce": "^2.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=14.17"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "semantic-release": ">=18.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@semantic-release/github": {
 | 
					    "node_modules/@semantic-release/github": {
 | 
				
			||||||
      "version": "8.0.4",
 | 
					      "version": "8.0.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-8.0.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-8.0.4.tgz",
 | 
				
			||||||
@@ -2380,6 +2402,11 @@
 | 
				
			|||||||
        "node": ">=10"
 | 
					        "node": ">=10"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/asynckit": {
 | 
				
			||||||
 | 
					      "version": "0.4.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/atomic-sleep": {
 | 
					    "node_modules/atomic-sleep": {
 | 
				
			||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
 | 
				
			||||||
@@ -2844,9 +2871,9 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/caniuse-lite": {
 | 
					    "node_modules/caniuse-lite": {
 | 
				
			||||||
      "version": "1.0.30001325",
 | 
					      "version": "1.0.30001327",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001325.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001327.tgz",
 | 
				
			||||||
      "integrity": "sha512-sB1bZHjseSjDtijV1Hb7PB2Zd58Kyx+n/9EotvZ4Qcz2K3d0lWB8dB4nb8wN/TsOGFq3UuAm0zQZNQ4SoR7TrQ==",
 | 
					      "integrity": "sha512-1/Cg4jlD9qjZzhbzkzEaAC2JHsP0WrOc8Rd/3a3LuajGzGWR/hD7TVyvq99VqmTy99eVh8Zkmdq213OgvgXx7w==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "funding": [
 | 
					      "funding": [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -3212,6 +3239,17 @@
 | 
				
			|||||||
        "node": ">=0.1.90"
 | 
					        "node": ">=0.1.90"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/combined-stream": {
 | 
				
			||||||
 | 
					      "version": "1.0.8",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "delayed-stream": "~1.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">= 0.8"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/commander": {
 | 
					    "node_modules/commander": {
 | 
				
			||||||
      "version": "7.2.0",
 | 
					      "version": "7.2.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
 | 
				
			||||||
@@ -3773,6 +3811,14 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
					        "url": "https://github.com/sponsors/sindresorhus"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/delayed-stream": {
 | 
				
			||||||
 | 
					      "version": "1.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=0.4.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/depd": {
 | 
					    "node_modules/depd": {
 | 
				
			||||||
      "version": "2.0.0",
 | 
					      "version": "2.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
 | 
				
			||||||
@@ -4916,23 +4962,6 @@
 | 
				
			|||||||
        "openapi-types": "^10.0.0"
 | 
					        "openapi-types": "^10.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/fastify-url-data": {
 | 
					 | 
				
			||||||
      "version": "3.0.3",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/fastify-url-data/-/fastify-url-data-3.0.3.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-fw9F6JhAPjg8oHm1xyZCcdj/agY8+z3xGZBUoHrUvBXOW0PDH+yDBihOsCeXYk4fbpI0KfJ9E44a5KOgpQkoBw==",
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "fastify-plugin": "^2.0.0",
 | 
					 | 
				
			||||||
        "uri-js": "^4.2.1"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/fastify-url-data/node_modules/fastify-plugin": {
 | 
					 | 
				
			||||||
      "version": "2.3.4",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-2.3.4.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-I+Oaj6p9oiRozbam30sh39BiuiqBda7yK2nmSPVwDCfIBlKnT8YB3MY+pRQc2Fcd07bf6KPGklHJaQ2Qu81TYQ==",
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "semver": "^7.3.2"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/fastq": {
 | 
					    "node_modules/fastq": {
 | 
				
			||||||
      "version": "1.13.0",
 | 
					      "version": "1.13.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
 | 
				
			||||||
@@ -5182,6 +5211,19 @@
 | 
				
			|||||||
        "node": ">=8.0.0"
 | 
					        "node": ">=8.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/form-data": {
 | 
				
			||||||
 | 
					      "version": "4.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "asynckit": "^0.4.0",
 | 
				
			||||||
 | 
					        "combined-stream": "^1.0.8",
 | 
				
			||||||
 | 
					        "mime-types": "^2.1.12"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">= 6"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/forwarded": {
 | 
					    "node_modules/forwarded": {
 | 
				
			||||||
      "version": "0.2.0",
 | 
					      "version": "0.2.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
 | 
				
			||||||
@@ -7815,9 +7857,9 @@
 | 
				
			|||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/marked": {
 | 
					    "node_modules/marked": {
 | 
				
			||||||
      "version": "4.0.12",
 | 
					      "version": "4.0.13",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.12.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.13.tgz",
 | 
				
			||||||
      "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==",
 | 
					      "integrity": "sha512-lS/ZCa4X0gsRcfWs1eoh6dLnHr9kVH3K1t2X4M/tTtNouhZ7anS1Csb6464VGLQHv8b2Tw1cLeZQs58Jav8Rzw==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "bin": {
 | 
					      "bin": {
 | 
				
			||||||
        "marked": "bin/marked.js"
 | 
					        "marked": "bin/marked.js"
 | 
				
			||||||
@@ -17303,6 +17345,22 @@
 | 
				
			|||||||
      "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==",
 | 
					      "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@semantic-release/git": {
 | 
				
			||||||
 | 
					      "version": "10.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-10.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@semantic-release/error": "^3.0.0",
 | 
				
			||||||
 | 
					        "aggregate-error": "^3.0.0",
 | 
				
			||||||
 | 
					        "debug": "^4.0.0",
 | 
				
			||||||
 | 
					        "dir-glob": "^3.0.0",
 | 
				
			||||||
 | 
					        "execa": "^5.0.0",
 | 
				
			||||||
 | 
					        "lodash": "^4.17.4",
 | 
				
			||||||
 | 
					        "micromatch": "^4.0.0",
 | 
				
			||||||
 | 
					        "p-reduce": "^2.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@semantic-release/github": {
 | 
					    "@semantic-release/github": {
 | 
				
			||||||
      "version": "8.0.4",
 | 
					      "version": "8.0.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-8.0.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-8.0.4.tgz",
 | 
				
			||||||
@@ -18172,6 +18230,11 @@
 | 
				
			|||||||
      "integrity": "sha512-14LjCmlK1PK8eDtTezR6WX8TMaYNIzBIsd2D1sGoGjgx0BuNMMoSdk7i/drlbtamy0AWv9yv2tkB+ASdmeqFIw==",
 | 
					      "integrity": "sha512-14LjCmlK1PK8eDtTezR6WX8TMaYNIzBIsd2D1sGoGjgx0BuNMMoSdk7i/drlbtamy0AWv9yv2tkB+ASdmeqFIw==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "asynckit": {
 | 
				
			||||||
 | 
					      "version": "0.4.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "atomic-sleep": {
 | 
					    "atomic-sleep": {
 | 
				
			||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
 | 
				
			||||||
@@ -18511,9 +18574,9 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "caniuse-lite": {
 | 
					    "caniuse-lite": {
 | 
				
			||||||
      "version": "1.0.30001325",
 | 
					      "version": "1.0.30001327",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001325.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001327.tgz",
 | 
				
			||||||
      "integrity": "sha512-sB1bZHjseSjDtijV1Hb7PB2Zd58Kyx+n/9EotvZ4Qcz2K3d0lWB8dB4nb8wN/TsOGFq3UuAm0zQZNQ4SoR7TrQ==",
 | 
					      "integrity": "sha512-1/Cg4jlD9qjZzhbzkzEaAC2JHsP0WrOc8Rd/3a3LuajGzGWR/hD7TVyvq99VqmTy99eVh8Zkmdq213OgvgXx7w==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "capital-case": {
 | 
					    "capital-case": {
 | 
				
			||||||
@@ -18789,6 +18852,14 @@
 | 
				
			|||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "optional": true
 | 
					      "optional": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "combined-stream": {
 | 
				
			||||||
 | 
					      "version": "1.0.8",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "delayed-stream": "~1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "commander": {
 | 
					    "commander": {
 | 
				
			||||||
      "version": "7.2.0",
 | 
					      "version": "7.2.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
 | 
				
			||||||
@@ -19221,6 +19292,11 @@
 | 
				
			|||||||
        "slash": "^3.0.0"
 | 
					        "slash": "^3.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "delayed-stream": {
 | 
				
			||||||
 | 
					      "version": "1.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "depd": {
 | 
					    "depd": {
 | 
				
			||||||
      "version": "2.0.0",
 | 
					      "version": "2.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
 | 
				
			||||||
@@ -20141,25 +20217,6 @@
 | 
				
			|||||||
        "openapi-types": "^10.0.0"
 | 
					        "openapi-types": "^10.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "fastify-url-data": {
 | 
					 | 
				
			||||||
      "version": "3.0.3",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/fastify-url-data/-/fastify-url-data-3.0.3.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-fw9F6JhAPjg8oHm1xyZCcdj/agY8+z3xGZBUoHrUvBXOW0PDH+yDBihOsCeXYk4fbpI0KfJ9E44a5KOgpQkoBw==",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "fastify-plugin": "^2.0.0",
 | 
					 | 
				
			||||||
        "uri-js": "^4.2.1"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "fastify-plugin": {
 | 
					 | 
				
			||||||
          "version": "2.3.4",
 | 
					 | 
				
			||||||
          "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-2.3.4.tgz",
 | 
					 | 
				
			||||||
          "integrity": "sha512-I+Oaj6p9oiRozbam30sh39BiuiqBda7yK2nmSPVwDCfIBlKnT8YB3MY+pRQc2Fcd07bf6KPGklHJaQ2Qu81TYQ==",
 | 
					 | 
				
			||||||
          "requires": {
 | 
					 | 
				
			||||||
            "semver": "^7.3.2"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "fastq": {
 | 
					    "fastq": {
 | 
				
			||||||
      "version": "1.13.0",
 | 
					      "version": "1.13.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
 | 
				
			||||||
@@ -20340,6 +20397,16 @@
 | 
				
			|||||||
        "signal-exit": "^3.0.2"
 | 
					        "signal-exit": "^3.0.2"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "form-data": {
 | 
				
			||||||
 | 
					      "version": "4.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "asynckit": "^0.4.0",
 | 
				
			||||||
 | 
					        "combined-stream": "^1.0.8",
 | 
				
			||||||
 | 
					        "mime-types": "^2.1.12"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "forwarded": {
 | 
					    "forwarded": {
 | 
				
			||||||
      "version": "0.2.0",
 | 
					      "version": "0.2.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
 | 
				
			||||||
@@ -22320,9 +22387,9 @@
 | 
				
			|||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "marked": {
 | 
					    "marked": {
 | 
				
			||||||
      "version": "4.0.12",
 | 
					      "version": "4.0.13",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.12.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.13.tgz",
 | 
				
			||||||
      "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==",
 | 
					      "integrity": "sha512-lS/ZCa4X0gsRcfWs1eoh6dLnHr9kVH3K1t2X4M/tTtNouhZ7anS1Csb6464VGLQHv8b2Tw1cLeZQs58Jav8Rzw==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "marked-terminal": {
 | 
					    "marked-terminal": {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@
 | 
				
			|||||||
    "start": "node build/index.js",
 | 
					    "start": "node 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": "concurrently -k -n \"TypeScript,Node\" -p \"[{name}]\" -c \"blue,green\" \"npm run build:dev\" \"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\"",
 | 
				
			||||||
@@ -48,9 +47,8 @@
 | 
				
			|||||||
    "fastify-plugin": "3.0.1",
 | 
					    "fastify-plugin": "3.0.1",
 | 
				
			||||||
    "fastify-rate-limit": "5.8.0",
 | 
					    "fastify-rate-limit": "5.8.0",
 | 
				
			||||||
    "fastify-sensible": "3.1.2",
 | 
					    "fastify-sensible": "3.1.2",
 | 
				
			||||||
    "fastify-static": "4.6.1",
 | 
					 | 
				
			||||||
    "fastify-swagger": "5.1.0",
 | 
					    "fastify-swagger": "5.1.0",
 | 
				
			||||||
    "fastify-url-data": "3.0.3",
 | 
					    "form-data": "4.0.0",
 | 
				
			||||||
    "http-errors": "2.0.0",
 | 
					    "http-errors": "2.0.0",
 | 
				
			||||||
    "jsonwebtoken": "8.5.1",
 | 
					    "jsonwebtoken": "8.5.1",
 | 
				
			||||||
    "ms": "2.1.3",
 | 
					    "ms": "2.1.3",
 | 
				
			||||||
@@ -62,6 +60,7 @@
 | 
				
			|||||||
    "@commitlint/cli": "16.2.3",
 | 
					    "@commitlint/cli": "16.2.3",
 | 
				
			||||||
    "@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",
 | 
				
			||||||
 | 
					    "@semantic-release/git": "10.0.1",
 | 
				
			||||||
    "@swc/cli": "0.1.57",
 | 
					    "@swc/cli": "0.1.57",
 | 
				
			||||||
    "@swc/core": "1.2.164",
 | 
					    "@swc/core": "1.2.164",
 | 
				
			||||||
    "@types/bcryptjs": "2.4.2",
 | 
					    "@types/bcryptjs": "2.4.2",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,19 +1,14 @@
 | 
				
			|||||||
import { fileURLToPath } from 'node:url'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dotenv from 'dotenv'
 | 
					import dotenv from 'dotenv'
 | 
				
			||||||
import fastify from 'fastify'
 | 
					import fastify from 'fastify'
 | 
				
			||||||
import fastifyCors from 'fastify-cors'
 | 
					import fastifyCors from 'fastify-cors'
 | 
				
			||||||
import fastifySwagger from 'fastify-swagger'
 | 
					import fastifySwagger from 'fastify-swagger'
 | 
				
			||||||
import fastifyUrlData from 'fastify-url-data'
 | 
					 | 
				
			||||||
import fastifyHelmet from 'fastify-helmet'
 | 
					import fastifyHelmet from 'fastify-helmet'
 | 
				
			||||||
import fastifyRateLimit from 'fastify-rate-limit'
 | 
					import fastifyRateLimit from 'fastify-rate-limit'
 | 
				
			||||||
import fastifySensible from 'fastify-sensible'
 | 
					import fastifySensible from 'fastify-sensible'
 | 
				
			||||||
import fastifyStatic from 'fastify-static'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { services } from './services/index.js'
 | 
					import { services } from './services/index.js'
 | 
				
			||||||
import { swaggerOptions } from './tools/configurations/swaggerOptions.js'
 | 
					import { swaggerOptions } from './tools/configurations/swaggerOptions.js'
 | 
				
			||||||
import fastifySocketIo from './tools/plugins/socket-io.js'
 | 
					import fastifySocketIo from './tools/plugins/socket-io.js'
 | 
				
			||||||
import { UPLOADS_URL } from './tools/configurations/index.js'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
dotenv.config()
 | 
					dotenv.config()
 | 
				
			||||||
export const application = fastify({
 | 
					export const application = fastify({
 | 
				
			||||||
@@ -27,7 +22,6 @@ export const application = fastify({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
await application.register(fastifyCors)
 | 
					await application.register(fastifyCors)
 | 
				
			||||||
await application.register(fastifySensible)
 | 
					await application.register(fastifySensible)
 | 
				
			||||||
await application.register(fastifyUrlData)
 | 
					 | 
				
			||||||
await application.register(fastifySocketIo, {
 | 
					await application.register(fastifySocketIo, {
 | 
				
			||||||
  cors: {
 | 
					  cors: {
 | 
				
			||||||
    origin: '*',
 | 
					    origin: '*',
 | 
				
			||||||
@@ -41,9 +35,5 @@ await application.register(fastifyRateLimit, {
 | 
				
			|||||||
  max: 200,
 | 
					  max: 200,
 | 
				
			||||||
  timeWindow: '1 minute'
 | 
					  timeWindow: '1 minute'
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
await application.register(fastifyStatic, {
 | 
					 | 
				
			||||||
  root: fileURLToPath(UPLOADS_URL),
 | 
					 | 
				
			||||||
  prefix: '/uploads/'
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
await application.register(fastifySwagger, swaggerOptions)
 | 
					await application.register(fastifySwagger, swaggerOptions)
 | 
				
			||||||
await application.register(services)
 | 
					await application.register(services)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,51 +0,0 @@
 | 
				
			|||||||
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)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 }
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
@@ -10,7 +10,6 @@ import { memberSchema } from '../../../../../models/Member.js'
 | 
				
			|||||||
import { userPublicWithoutSettingsSchema } from '../../../../../models/User.js'
 | 
					import { userPublicWithoutSettingsSchema } from '../../../../../models/User.js'
 | 
				
			||||||
import { channelSchema } from '../../../../../models/Channel.js'
 | 
					import { channelSchema } from '../../../../../models/Channel.js'
 | 
				
			||||||
import { uploadFile } from '../../../../../tools/utils/uploadFile.js'
 | 
					import { uploadFile } from '../../../../../tools/utils/uploadFile.js'
 | 
				
			||||||
import { MAXIMUM_FILE_SIZE } from '../../../../../tools/configurations/index.js'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const parametersSchema = Type.Object({
 | 
					const parametersSchema = Type.Object({
 | 
				
			||||||
  channelId: channelSchema.id
 | 
					  channelId: channelSchema.id
 | 
				
			||||||
@@ -94,8 +93,7 @@ export const postMessageUploadsByChannelIdService: FastifyPluginAsync = async (
 | 
				
			|||||||
      const file = await uploadFile({
 | 
					      const file = await uploadFile({
 | 
				
			||||||
        fastify,
 | 
					        fastify,
 | 
				
			||||||
        request,
 | 
					        request,
 | 
				
			||||||
        folderInUploadsFolder: 'messages',
 | 
					        folderInUploadsFolder: 'messages'
 | 
				
			||||||
        maximumFileSize: MAXIMUM_FILE_SIZE
 | 
					 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      const message = await prisma.message.create({
 | 
					      const message = await prisma.message.create({
 | 
				
			||||||
        data: {
 | 
					        data: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,10 +7,6 @@ import { fastifyErrors } from '../../../../models/utils.js'
 | 
				
			|||||||
import prisma from '../../../../tools/database/prisma.js'
 | 
					import prisma from '../../../../tools/database/prisma.js'
 | 
				
			||||||
import { uploadFile } from '../../../../tools/utils/uploadFile.js'
 | 
					import { uploadFile } from '../../../../tools/utils/uploadFile.js'
 | 
				
			||||||
import { guildSchema } from '../../../../models/Guild.js'
 | 
					import { guildSchema } from '../../../../models/Guild.js'
 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  MAXIMUM_IMAGE_SIZE,
 | 
					 | 
				
			||||||
  SUPPORTED_IMAGE_MIMETYPE
 | 
					 | 
				
			||||||
} from '../../../../tools/configurations/index.js'
 | 
					 | 
				
			||||||
import { channelSchema } from '../../../../models/Channel.js'
 | 
					import { channelSchema } from '../../../../models/Channel.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const parametersSchema = Type.Object({
 | 
					const parametersSchema = Type.Object({
 | 
				
			||||||
@@ -67,9 +63,7 @@ export const putGuildIconById: FastifyPluginAsync = async (fastify) => {
 | 
				
			|||||||
      const file = await uploadFile({
 | 
					      const file = await uploadFile({
 | 
				
			||||||
        fastify,
 | 
					        fastify,
 | 
				
			||||||
        request,
 | 
					        request,
 | 
				
			||||||
        folderInUploadsFolder: 'guilds',
 | 
					        folderInUploadsFolder: 'guilds'
 | 
				
			||||||
        maximumFileSize: MAXIMUM_IMAGE_SIZE,
 | 
					 | 
				
			||||||
        supportedFileMimetype: SUPPORTED_IMAGE_MIMETYPE
 | 
					 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      await prisma.guild.update({
 | 
					      await prisma.guild.update({
 | 
				
			||||||
        where: { id: guildId },
 | 
					        where: { id: guildId },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,6 @@ import { FastifyPluginAsync } from 'fastify'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { usersService } from './users/index.js'
 | 
					import { usersService } from './users/index.js'
 | 
				
			||||||
import { guildsService } from './guilds/index.js'
 | 
					import { guildsService } from './guilds/index.js'
 | 
				
			||||||
import { uploadsService } from './uploads/index.js'
 | 
					 | 
				
			||||||
import { channelsService } from './channels/index.js'
 | 
					import { channelsService } from './channels/index.js'
 | 
				
			||||||
import { messagesService } from './messages/index.js'
 | 
					import { messagesService } from './messages/index.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -10,6 +9,5 @@ export const services: FastifyPluginAsync = async (fastify) => {
 | 
				
			|||||||
  await fastify.register(channelsService)
 | 
					  await fastify.register(channelsService)
 | 
				
			||||||
  await fastify.register(guildsService)
 | 
					  await fastify.register(guildsService)
 | 
				
			||||||
  await fastify.register(messagesService)
 | 
					  await fastify.register(messagesService)
 | 
				
			||||||
  await fastify.register(uploadsService)
 | 
					 | 
				
			||||||
  await fastify.register(usersService)
 | 
					  await fastify.register(usersService)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,40 +0,0 @@
 | 
				
			|||||||
import path from 'node:path'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { FastifyPluginAsync, FastifySchema } from 'fastify'
 | 
					 | 
				
			||||||
import { Static, Type } from '@sinclair/typebox'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { fastifyErrors } from '../../../models/utils.js'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const parameters = Type.Object({
 | 
					 | 
				
			||||||
  file: Type.String()
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Parameters = Static<typeof parameters>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getServiceSchema: FastifySchema = {
 | 
					 | 
				
			||||||
  tags: ['uploads'] as string[],
 | 
					 | 
				
			||||||
  params: parameters,
 | 
					 | 
				
			||||||
  response: {
 | 
					 | 
				
			||||||
    200: {
 | 
					 | 
				
			||||||
      type: 'string',
 | 
					 | 
				
			||||||
      format: 'binary'
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    400: fastifyErrors[400],
 | 
					 | 
				
			||||||
    404: fastifyErrors[404],
 | 
					 | 
				
			||||||
    500: fastifyErrors[500]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
} as const
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getGuildsUploadsService: FastifyPluginAsync = async (fastify) => {
 | 
					 | 
				
			||||||
  await fastify.route<{
 | 
					 | 
				
			||||||
    Params: Parameters
 | 
					 | 
				
			||||||
  }>({
 | 
					 | 
				
			||||||
    method: 'GET',
 | 
					 | 
				
			||||||
    url: '/uploads/guilds/:file',
 | 
					 | 
				
			||||||
    schema: getServiceSchema,
 | 
					 | 
				
			||||||
    handler: async (request, reply) => {
 | 
					 | 
				
			||||||
      const { file } = request.params
 | 
					 | 
				
			||||||
      return await reply.sendFile(path.join('guilds', file))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,11 +0,0 @@
 | 
				
			|||||||
import { FastifyPluginAsync } from 'fastify'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { getGuildsUploadsService } from './guilds/get.js'
 | 
					 | 
				
			||||||
import { getMessagesUploadsService } from './messages/get.js'
 | 
					 | 
				
			||||||
import { getUsersUploadsService } from './users/get.js'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const uploadsService: FastifyPluginAsync = async (fastify) => {
 | 
					 | 
				
			||||||
  await fastify.register(getGuildsUploadsService)
 | 
					 | 
				
			||||||
  await fastify.register(getMessagesUploadsService)
 | 
					 | 
				
			||||||
  await fastify.register(getUsersUploadsService)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,76 +0,0 @@
 | 
				
			|||||||
import path from 'node:path'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { FastifyPluginAsync, FastifySchema } from 'fastify'
 | 
					 | 
				
			||||||
import { Static, Type } from '@sinclair/typebox'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { fastifyErrors } from '../../../models/utils.js'
 | 
					 | 
				
			||||||
import authenticateUser from '../../../tools/plugins/authenticateUser.js'
 | 
					 | 
				
			||||||
import prisma from '../../../tools/database/prisma.js'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const parameters = Type.Object({
 | 
					 | 
				
			||||||
  file: Type.String()
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Parameters = Static<typeof parameters>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getServiceSchema: FastifySchema = {
 | 
					 | 
				
			||||||
  tags: ['uploads'] as string[],
 | 
					 | 
				
			||||||
  security: [
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      bearerAuth: []
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  ] as Array<{ [key: string]: [] }>,
 | 
					 | 
				
			||||||
  params: parameters,
 | 
					 | 
				
			||||||
  response: {
 | 
					 | 
				
			||||||
    200: {
 | 
					 | 
				
			||||||
      type: 'string',
 | 
					 | 
				
			||||||
      format: 'binary'
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    400: fastifyErrors[400],
 | 
					 | 
				
			||||||
    401: fastifyErrors[401],
 | 
					 | 
				
			||||||
    403: fastifyErrors[403],
 | 
					 | 
				
			||||||
    404: fastifyErrors[404],
 | 
					 | 
				
			||||||
    500: fastifyErrors[500]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
} as const
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getMessagesUploadsService: FastifyPluginAsync = async (
 | 
					 | 
				
			||||||
  fastify
 | 
					 | 
				
			||||||
) => {
 | 
					 | 
				
			||||||
  await fastify.register(authenticateUser)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fastify.route<{
 | 
					 | 
				
			||||||
    Params: Parameters
 | 
					 | 
				
			||||||
  }>({
 | 
					 | 
				
			||||||
    method: 'GET',
 | 
					 | 
				
			||||||
    url: '/uploads/messages/:file',
 | 
					 | 
				
			||||||
    schema: getServiceSchema,
 | 
					 | 
				
			||||||
    handler: async (request, reply) => {
 | 
					 | 
				
			||||||
      if (request.user == null) {
 | 
					 | 
				
			||||||
        throw fastify.httpErrors.forbidden()
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      const { file } = request.params
 | 
					 | 
				
			||||||
      const message = await prisma.message.findFirst({
 | 
					 | 
				
			||||||
        where: { value: `/uploads/messages/${file}` },
 | 
					 | 
				
			||||||
        include: {
 | 
					 | 
				
			||||||
          member: {
 | 
					 | 
				
			||||||
            select: { guildId: true }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
      if (message == null) {
 | 
					 | 
				
			||||||
        throw fastify.httpErrors.notFound('Message not found')
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      const member = await prisma.member.findFirst({
 | 
					 | 
				
			||||||
        where: {
 | 
					 | 
				
			||||||
          guildId: message.member?.guildId,
 | 
					 | 
				
			||||||
          userId: request.user.current.id
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
      if (member == null) {
 | 
					 | 
				
			||||||
        throw fastify.httpErrors.notFound('Member not found')
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return await reply.sendFile(path.join('messages', file))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,40 +0,0 @@
 | 
				
			|||||||
import path from 'node:path'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { FastifyPluginAsync, FastifySchema } from 'fastify'
 | 
					 | 
				
			||||||
import { Static, Type } from '@sinclair/typebox'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { fastifyErrors } from '../../../models/utils.js'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const parameters = Type.Object({
 | 
					 | 
				
			||||||
  file: Type.String()
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Parameters = Static<typeof parameters>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getServiceSchema: FastifySchema = {
 | 
					 | 
				
			||||||
  tags: ['uploads'] as string[],
 | 
					 | 
				
			||||||
  params: parameters,
 | 
					 | 
				
			||||||
  response: {
 | 
					 | 
				
			||||||
    200: {
 | 
					 | 
				
			||||||
      type: 'string',
 | 
					 | 
				
			||||||
      format: 'binary'
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    400: fastifyErrors[400],
 | 
					 | 
				
			||||||
    404: fastifyErrors[404],
 | 
					 | 
				
			||||||
    500: fastifyErrors[500]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
} as const
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getUsersUploadsService: FastifyPluginAsync = async (fastify) => {
 | 
					 | 
				
			||||||
  await fastify.route<{
 | 
					 | 
				
			||||||
    Params: Parameters
 | 
					 | 
				
			||||||
  }>({
 | 
					 | 
				
			||||||
    method: 'GET',
 | 
					 | 
				
			||||||
    url: '/uploads/users/:file',
 | 
					 | 
				
			||||||
    schema: getServiceSchema,
 | 
					 | 
				
			||||||
    handler: async (request, reply) => {
 | 
					 | 
				
			||||||
      const { file } = request.params
 | 
					 | 
				
			||||||
      return await reply.sendFile(path.join('users', file))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -6,10 +6,6 @@ import authenticateUser from '../../../../tools/plugins/authenticateUser.js'
 | 
				
			|||||||
import { fastifyErrors } from '../../../../models/utils.js'
 | 
					import { fastifyErrors } from '../../../../models/utils.js'
 | 
				
			||||||
import prisma from '../../../../tools/database/prisma.js'
 | 
					import prisma from '../../../../tools/database/prisma.js'
 | 
				
			||||||
import { uploadFile } from '../../../../tools/utils/uploadFile.js'
 | 
					import { uploadFile } from '../../../../tools/utils/uploadFile.js'
 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  MAXIMUM_IMAGE_SIZE,
 | 
					 | 
				
			||||||
  SUPPORTED_IMAGE_MIMETYPE
 | 
					 | 
				
			||||||
} from '../../../../tools/configurations/index.js'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const putServiceSchema: FastifySchema = {
 | 
					const putServiceSchema: FastifySchema = {
 | 
				
			||||||
  description: 'Edit the current connected user logo',
 | 
					  description: 'Edit the current connected user logo',
 | 
				
			||||||
@@ -51,9 +47,7 @@ export const putCurrentUserLogo: FastifyPluginAsync = async (fastify) => {
 | 
				
			|||||||
      const file = await uploadFile({
 | 
					      const file = await uploadFile({
 | 
				
			||||||
        fastify,
 | 
					        fastify,
 | 
				
			||||||
        request,
 | 
					        request,
 | 
				
			||||||
        folderInUploadsFolder: 'users',
 | 
					        folderInUploadsFolder: 'users'
 | 
				
			||||||
        maximumFileSize: MAXIMUM_IMAGE_SIZE,
 | 
					 | 
				
			||||||
        supportedFileMimetype: SUPPORTED_IMAGE_MIMETYPE
 | 
					 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      await prisma.user.update({
 | 
					      await prisma.user.update({
 | 
				
			||||||
        where: { id: request.user.current.id },
 | 
					        where: { id: request.user.current.id },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,12 @@ import { getCallbackGoogleOAuth2Service } from './oauth2/google/callback/get.js'
 | 
				
			|||||||
import { getSigninGitHubOAuth2Service } from './oauth2/github/signin/get.js'
 | 
					import { getSigninGitHubOAuth2Service } from './oauth2/github/signin/get.js'
 | 
				
			||||||
import { getCallbackGitHubOAuth2Service } from './oauth2/github/callback/get.js'
 | 
					import { getCallbackGitHubOAuth2Service } from './oauth2/github/callback/get.js'
 | 
				
			||||||
import { deleteProviderService } from './oauth2/[provider]/delete.js'
 | 
					import { deleteProviderService } from './oauth2/[provider]/delete.js'
 | 
				
			||||||
 | 
					import { getCallbackAddStrategyDiscordOAuth2Service } from './oauth2/discord/callback-add-strategy/get.js'
 | 
				
			||||||
 | 
					import { getAddStrategyDiscordOAuth2Service } from './oauth2/discord/add-strategy/get.js'
 | 
				
			||||||
 | 
					import { getAddStrategyGitHubOAuth2Service } from './oauth2/github/add-strategy/get.js'
 | 
				
			||||||
 | 
					import { getCallbackAddStrategyGitHubOAuth2Service } from './oauth2/github/callback-add-strategy/get.js'
 | 
				
			||||||
 | 
					import { getCallbackAddStrategyGoogleOAuth2Service } from './oauth2/google/callback-add-strategy/get.js'
 | 
				
			||||||
 | 
					import { getAddStrategyGoogleOAuth2Service } from './oauth2/google/add-strategy/get.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const usersService: FastifyPluginAsync = async (fastify) => {
 | 
					export const usersService: FastifyPluginAsync = async (fastify) => {
 | 
				
			||||||
  await fastify.register(postSignupUser)
 | 
					  await fastify.register(postSignupUser)
 | 
				
			||||||
@@ -38,12 +44,18 @@ export const usersService: FastifyPluginAsync = async (fastify) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  await fastify.register(getSigninDiscordOAuth2Service)
 | 
					  await fastify.register(getSigninDiscordOAuth2Service)
 | 
				
			||||||
  await fastify.register(getCallbackDiscordOAuth2Service)
 | 
					  await fastify.register(getCallbackDiscordOAuth2Service)
 | 
				
			||||||
 | 
					  await fastify.register(getCallbackAddStrategyDiscordOAuth2Service)
 | 
				
			||||||
 | 
					  await fastify.register(getAddStrategyDiscordOAuth2Service)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await fastify.register(getSigninGoogleOAuth2Service)
 | 
					  await fastify.register(getSigninGoogleOAuth2Service)
 | 
				
			||||||
  await fastify.register(getCallbackGoogleOAuth2Service)
 | 
					  await fastify.register(getCallbackGoogleOAuth2Service)
 | 
				
			||||||
 | 
					  await fastify.register(getCallbackAddStrategyGoogleOAuth2Service)
 | 
				
			||||||
 | 
					  await fastify.register(getAddStrategyGoogleOAuth2Service)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await fastify.register(getSigninGitHubOAuth2Service)
 | 
					  await fastify.register(getSigninGitHubOAuth2Service)
 | 
				
			||||||
  await fastify.register(getCallbackGitHubOAuth2Service)
 | 
					  await fastify.register(getCallbackGitHubOAuth2Service)
 | 
				
			||||||
 | 
					  await fastify.register(getCallbackAddStrategyGitHubOAuth2Service)
 | 
				
			||||||
 | 
					  await fastify.register(getAddStrategyGitHubOAuth2Service)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await fastify.register(deleteProviderService)
 | 
					  await fastify.register(deleteProviderService)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										53
									
								
								src/services/users/oauth2/discord/add-strategy/get.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/services/users/oauth2/discord/add-strategy/get.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					import { Static, Type } from '@sinclair/typebox'
 | 
				
			||||||
 | 
					import { FastifyPluginAsync, FastifySchema } from 'fastify'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { API_URL } from '../../../../../tools/configurations/index.js'
 | 
				
			||||||
 | 
					import { fastifyErrors } from '../../../../../models/utils.js'
 | 
				
			||||||
 | 
					import { DISCORD_BASE_URL, DISCORD_CLIENT_ID } from '../__utils__/utils.js'
 | 
				
			||||||
 | 
					import authenticateUser from '../../../../../tools/plugins/authenticateUser.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const querySchema = Type.Object({
 | 
				
			||||||
 | 
					  redirectURI: Type.String({ format: 'uri-reference' })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type QuerySchemaType = Static<typeof querySchema>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getServiceSchema: FastifySchema = {
 | 
				
			||||||
 | 
					  description: 'Discord OAuth2 - add-strategy',
 | 
				
			||||||
 | 
					  tags: ['users'] as string[],
 | 
				
			||||||
 | 
					  security: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      bearerAuth: []
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ] as Array<{ [key: string]: [] }>,
 | 
				
			||||||
 | 
					  querystring: querySchema,
 | 
				
			||||||
 | 
					  response: {
 | 
				
			||||||
 | 
					    200: Type.String(),
 | 
				
			||||||
 | 
					    400: fastifyErrors[400],
 | 
				
			||||||
 | 
					    500: fastifyErrors[500]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					} as const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getAddStrategyDiscordOAuth2Service: FastifyPluginAsync = async (
 | 
				
			||||||
 | 
					  fastify
 | 
				
			||||||
 | 
					) => {
 | 
				
			||||||
 | 
					  await fastify.register(authenticateUser)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  await fastify.route<{
 | 
				
			||||||
 | 
					    Querystring: QuerySchemaType
 | 
				
			||||||
 | 
					  }>({
 | 
				
			||||||
 | 
					    method: 'GET',
 | 
				
			||||||
 | 
					    url: '/users/oauth2/discord/add-strategy',
 | 
				
			||||||
 | 
					    schema: getServiceSchema,
 | 
				
			||||||
 | 
					    handler: async (request, reply) => {
 | 
				
			||||||
 | 
					      if (request.user == null) {
 | 
				
			||||||
 | 
					        throw fastify.httpErrors.forbidden()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const { redirectURI } = request.query
 | 
				
			||||||
 | 
					      const redirectCallback = `${API_URL}/users/oauth2/discord/callback-add-strategy?redirectURI=${redirectURI}`
 | 
				
			||||||
 | 
					      const url = `${DISCORD_BASE_URL}/oauth2/authorize?client_id=${DISCORD_CLIENT_ID}&scope=identify&response_type=code&state=${request.user.accessToken}&redirect_uri=${redirectCallback}`
 | 
				
			||||||
 | 
					      reply.statusCode = 200
 | 
				
			||||||
 | 
					      return url
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					import { Static, Type } from '@sinclair/typebox'
 | 
				
			||||||
 | 
					import { FastifyPluginAsync, FastifySchema } from 'fastify'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { API_URL } from '../../../../../tools/configurations/index.js'
 | 
				
			||||||
 | 
					import { fastifyErrors } from '../../../../../models/utils.js'
 | 
				
			||||||
 | 
					import { discordStrategy, getDiscordUserData } from '../__utils__/utils.js'
 | 
				
			||||||
 | 
					import { buildQueryURL } from '../../../../../tools/utils/buildQueryURL.js'
 | 
				
			||||||
 | 
					import { getUserWithBearerToken } from '../../../../../tools/plugins/authenticateUser.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const querySchema = Type.Object({
 | 
				
			||||||
 | 
					  code: Type.String(),
 | 
				
			||||||
 | 
					  state: Type.String(),
 | 
				
			||||||
 | 
					  redirectURI: Type.String({ format: 'uri-reference' })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type QuerySchemaType = Static<typeof querySchema>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getServiceSchema: FastifySchema = {
 | 
				
			||||||
 | 
					  description: 'Discord OAuth2 - callback-add-strategy',
 | 
				
			||||||
 | 
					  tags: ['users'] as string[],
 | 
				
			||||||
 | 
					  querystring: querySchema,
 | 
				
			||||||
 | 
					  response: {
 | 
				
			||||||
 | 
					    200: Type.String(),
 | 
				
			||||||
 | 
					    400: fastifyErrors[400],
 | 
				
			||||||
 | 
					    500: fastifyErrors[500]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					} as const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getCallbackAddStrategyDiscordOAuth2Service: FastifyPluginAsync =
 | 
				
			||||||
 | 
					  async (fastify) => {
 | 
				
			||||||
 | 
					    await fastify.route<{
 | 
				
			||||||
 | 
					      Querystring: QuerySchemaType
 | 
				
			||||||
 | 
					    }>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: '/users/oauth2/discord/callback-add-strategy',
 | 
				
			||||||
 | 
					      schema: getServiceSchema,
 | 
				
			||||||
 | 
					      handler: async (request, reply) => {
 | 
				
			||||||
 | 
					        const { redirectURI, code, state: accessToken } = request.query
 | 
				
			||||||
 | 
					        const userRequest = await getUserWithBearerToken(
 | 
				
			||||||
 | 
					          `Bearer ${accessToken}`
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        const discordUser = await getDiscordUserData(
 | 
				
			||||||
 | 
					          code,
 | 
				
			||||||
 | 
					          `${API_URL}/users/oauth2/discord/callback-add-strategy?redirectURI=${redirectURI}`
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        const message = await discordStrategy.callbackAddStrategy(
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            name: discordUser.username,
 | 
				
			||||||
 | 
					            id: discordUser.id
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          userRequest
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return await reply.redirect(buildQueryURL(redirectURI, { message }))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
							
								
								
									
										53
									
								
								src/services/users/oauth2/github/add-strategy/get.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/services/users/oauth2/github/add-strategy/get.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					import { Static, Type } from '@sinclair/typebox'
 | 
				
			||||||
 | 
					import { FastifyPluginAsync, FastifySchema } from 'fastify'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { API_URL } from '../../../../../tools/configurations/index.js'
 | 
				
			||||||
 | 
					import { fastifyErrors } from '../../../../../models/utils.js'
 | 
				
			||||||
 | 
					import { GITHUB_BASE_URL, GITHUB_CLIENT_ID } from '../__utils__/utils.js'
 | 
				
			||||||
 | 
					import authenticateUser from '../../../../../tools/plugins/authenticateUser.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const querySchema = Type.Object({
 | 
				
			||||||
 | 
					  redirectURI: Type.String({ format: 'uri-reference' })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type QuerySchemaType = Static<typeof querySchema>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getServiceSchema: FastifySchema = {
 | 
				
			||||||
 | 
					  description: 'GitHub OAuth2 - add-strategy',
 | 
				
			||||||
 | 
					  tags: ['users'] as string[],
 | 
				
			||||||
 | 
					  security: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      bearerAuth: []
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ] as Array<{ [key: string]: [] }>,
 | 
				
			||||||
 | 
					  querystring: querySchema,
 | 
				
			||||||
 | 
					  response: {
 | 
				
			||||||
 | 
					    200: Type.String(),
 | 
				
			||||||
 | 
					    400: fastifyErrors[400],
 | 
				
			||||||
 | 
					    500: fastifyErrors[500]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					} as const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getAddStrategyGitHubOAuth2Service: FastifyPluginAsync = async (
 | 
				
			||||||
 | 
					  fastify
 | 
				
			||||||
 | 
					) => {
 | 
				
			||||||
 | 
					  await fastify.register(authenticateUser)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  await fastify.route<{
 | 
				
			||||||
 | 
					    Querystring: QuerySchemaType
 | 
				
			||||||
 | 
					  }>({
 | 
				
			||||||
 | 
					    method: 'GET',
 | 
				
			||||||
 | 
					    url: '/users/oauth2/github/add-strategy',
 | 
				
			||||||
 | 
					    schema: getServiceSchema,
 | 
				
			||||||
 | 
					    handler: async (request, reply) => {
 | 
				
			||||||
 | 
					      if (request.user == null) {
 | 
				
			||||||
 | 
					        throw fastify.httpErrors.forbidden()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const { redirectURI } = request.query
 | 
				
			||||||
 | 
					      const redirectCallback = `${API_URL}/users/oauth2/github/callback-add-strategy?redirectURI=${redirectURI}`
 | 
				
			||||||
 | 
					      const url = `${GITHUB_BASE_URL}/login/oauth/authorize?client_id=${GITHUB_CLIENT_ID}&state=${request.user.accessToken}&redirect_uri=${redirectCallback}`
 | 
				
			||||||
 | 
					      reply.statusCode = 200
 | 
				
			||||||
 | 
					      return url
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					import { Static, Type } from '@sinclair/typebox'
 | 
				
			||||||
 | 
					import { FastifyPluginAsync, FastifySchema } from 'fastify'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { API_URL } from '../../../../../tools/configurations/index.js'
 | 
				
			||||||
 | 
					import { fastifyErrors } from '../../../../../models/utils.js'
 | 
				
			||||||
 | 
					import { githubStrategy, getGitHubUserData } from '../__utils__/utils.js'
 | 
				
			||||||
 | 
					import { buildQueryURL } from '../../../../../tools/utils/buildQueryURL.js'
 | 
				
			||||||
 | 
					import { getUserWithBearerToken } from '../../../../../tools/plugins/authenticateUser.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const querySchema = Type.Object({
 | 
				
			||||||
 | 
					  code: Type.String(),
 | 
				
			||||||
 | 
					  state: Type.String(),
 | 
				
			||||||
 | 
					  redirectURI: Type.String({ format: 'uri-reference' })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type QuerySchemaType = Static<typeof querySchema>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getServiceSchema: FastifySchema = {
 | 
				
			||||||
 | 
					  description: 'GitHub OAuth2 - callback-add-strategy',
 | 
				
			||||||
 | 
					  tags: ['users'] as string[],
 | 
				
			||||||
 | 
					  querystring: querySchema,
 | 
				
			||||||
 | 
					  response: {
 | 
				
			||||||
 | 
					    200: Type.String(),
 | 
				
			||||||
 | 
					    400: fastifyErrors[400],
 | 
				
			||||||
 | 
					    500: fastifyErrors[500]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					} as const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getCallbackAddStrategyGitHubOAuth2Service: FastifyPluginAsync =
 | 
				
			||||||
 | 
					  async (fastify) => {
 | 
				
			||||||
 | 
					    await fastify.route<{
 | 
				
			||||||
 | 
					      Querystring: QuerySchemaType
 | 
				
			||||||
 | 
					    }>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: '/users/oauth2/github/callback-add-strategy',
 | 
				
			||||||
 | 
					      schema: getServiceSchema,
 | 
				
			||||||
 | 
					      handler: async (request, reply) => {
 | 
				
			||||||
 | 
					        const { redirectURI, code, state: accessToken } = request.query
 | 
				
			||||||
 | 
					        const userRequest = await getUserWithBearerToken(
 | 
				
			||||||
 | 
					          `Bearer ${accessToken}`
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        const githubUser = await getGitHubUserData(
 | 
				
			||||||
 | 
					          code,
 | 
				
			||||||
 | 
					          `${API_URL}/users/oauth2/github/callback-add-strategy?redirectURI=${redirectURI}`
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        const message = await githubStrategy.callbackAddStrategy(
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            name: githubUser.name,
 | 
				
			||||||
 | 
					            id: githubUser.id
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          userRequest
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return await reply.redirect(buildQueryURL(redirectURI, { message }))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
							
								
								
									
										53
									
								
								src/services/users/oauth2/google/add-strategy/get.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/services/users/oauth2/google/add-strategy/get.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					import { Static, Type } from '@sinclair/typebox'
 | 
				
			||||||
 | 
					import { FastifyPluginAsync, FastifySchema } from 'fastify'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { API_URL } from '../../../../../tools/configurations/index.js'
 | 
				
			||||||
 | 
					import { fastifyErrors } from '../../../../../models/utils.js'
 | 
				
			||||||
 | 
					import { GOOGLE_BASE_URL, GOOGLE_CLIENT_ID } from '../__utils__/utils.js'
 | 
				
			||||||
 | 
					import authenticateUser from '../../../../../tools/plugins/authenticateUser.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const querySchema = Type.Object({
 | 
				
			||||||
 | 
					  redirectURI: Type.String({ format: 'uri-reference' })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type QuerySchemaType = Static<typeof querySchema>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getServiceSchema: FastifySchema = {
 | 
				
			||||||
 | 
					  description: 'Google OAuth2 - add-strategy',
 | 
				
			||||||
 | 
					  tags: ['users'] as string[],
 | 
				
			||||||
 | 
					  security: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      bearerAuth: []
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ] as Array<{ [key: string]: [] }>,
 | 
				
			||||||
 | 
					  querystring: querySchema,
 | 
				
			||||||
 | 
					  response: {
 | 
				
			||||||
 | 
					    200: Type.String(),
 | 
				
			||||||
 | 
					    400: fastifyErrors[400],
 | 
				
			||||||
 | 
					    500: fastifyErrors[500]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					} as const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getAddStrategyGoogleOAuth2Service: FastifyPluginAsync = async (
 | 
				
			||||||
 | 
					  fastify
 | 
				
			||||||
 | 
					) => {
 | 
				
			||||||
 | 
					  await fastify.register(authenticateUser)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  await fastify.route<{
 | 
				
			||||||
 | 
					    Querystring: QuerySchemaType
 | 
				
			||||||
 | 
					  }>({
 | 
				
			||||||
 | 
					    method: 'GET',
 | 
				
			||||||
 | 
					    url: '/users/oauth2/google/add-strategy',
 | 
				
			||||||
 | 
					    schema: getServiceSchema,
 | 
				
			||||||
 | 
					    handler: async (request, reply) => {
 | 
				
			||||||
 | 
					      if (request.user == null) {
 | 
				
			||||||
 | 
					        throw fastify.httpErrors.forbidden()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const { redirectURI } = request.query
 | 
				
			||||||
 | 
					      const redirectCallback = `${API_URL}/users/oauth2/google/callback-add-strategy?redirectURI=${redirectURI}`
 | 
				
			||||||
 | 
					      const url = `${GOOGLE_BASE_URL}?client_id=${GOOGLE_CLIENT_ID}&state=${request.user.accessToken}&redirect_uri=${redirectCallback}&response_type=code&scope=profile&access_type=online`
 | 
				
			||||||
 | 
					      reply.statusCode = 200
 | 
				
			||||||
 | 
					      return url
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					import { Static, Type } from '@sinclair/typebox'
 | 
				
			||||||
 | 
					import { FastifyPluginAsync, FastifySchema } from 'fastify'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { API_URL } from '../../../../../tools/configurations/index.js'
 | 
				
			||||||
 | 
					import { fastifyErrors } from '../../../../../models/utils.js'
 | 
				
			||||||
 | 
					import { googleStrategy, getGoogleUserData } from '../__utils__/utils.js'
 | 
				
			||||||
 | 
					import { buildQueryURL } from '../../../../../tools/utils/buildQueryURL.js'
 | 
				
			||||||
 | 
					import { getUserWithBearerToken } from '../../../../../tools/plugins/authenticateUser.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const querySchema = Type.Object({
 | 
				
			||||||
 | 
					  code: Type.String(),
 | 
				
			||||||
 | 
					  state: Type.String(),
 | 
				
			||||||
 | 
					  redirectURI: Type.String({ format: 'uri-reference' })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type QuerySchemaType = Static<typeof querySchema>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getServiceSchema: FastifySchema = {
 | 
				
			||||||
 | 
					  description: 'Google OAuth2 - callback-add-strategy',
 | 
				
			||||||
 | 
					  tags: ['users'] as string[],
 | 
				
			||||||
 | 
					  querystring: querySchema,
 | 
				
			||||||
 | 
					  response: {
 | 
				
			||||||
 | 
					    200: Type.String(),
 | 
				
			||||||
 | 
					    400: fastifyErrors[400],
 | 
				
			||||||
 | 
					    500: fastifyErrors[500]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					} as const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getCallbackAddStrategyGoogleOAuth2Service: FastifyPluginAsync =
 | 
				
			||||||
 | 
					  async (fastify) => {
 | 
				
			||||||
 | 
					    await fastify.route<{
 | 
				
			||||||
 | 
					      Querystring: QuerySchemaType
 | 
				
			||||||
 | 
					    }>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: '/users/oauth2/google/callback-add-strategy',
 | 
				
			||||||
 | 
					      schema: getServiceSchema,
 | 
				
			||||||
 | 
					      handler: async (request, reply) => {
 | 
				
			||||||
 | 
					        const { redirectURI, code, state: accessToken } = request.query
 | 
				
			||||||
 | 
					        const userRequest = await getUserWithBearerToken(
 | 
				
			||||||
 | 
					          `Bearer ${accessToken}`
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        const googleUser = await getGoogleUserData(
 | 
				
			||||||
 | 
					          code,
 | 
				
			||||||
 | 
					          `${API_URL}/users/oauth2/google/callback-add-strategy?redirectURI=${redirectURI}`
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        const message = await googleStrategy.callbackAddStrategy(
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            name: googleUser.name,
 | 
				
			||||||
 | 
					            id: googleUser.id
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          userRequest
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return await reply.redirect(buildQueryURL(redirectURI, { message }))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
@@ -7,6 +7,10 @@ dotenv.config()
 | 
				
			|||||||
export const PORT = parseInt(process.env.PORT ?? '8080', 10)
 | 
					export const PORT = parseInt(process.env.PORT ?? '8080', 10)
 | 
				
			||||||
export const HOST = process.env.HOST ?? '0.0.0.0'
 | 
					export const HOST = process.env.HOST ?? '0.0.0.0'
 | 
				
			||||||
export const API_URL = process.env.API_URL ?? `http://${HOST}:${PORT}`
 | 
					export const API_URL = process.env.API_URL ?? `http://${HOST}:${PORT}`
 | 
				
			||||||
 | 
					export const FILE_UPLOADS_API_URL =
 | 
				
			||||||
 | 
					  process.env.FILE_UPLOADS_API_URL ?? 'http://localhost:8000'
 | 
				
			||||||
 | 
					export const FILE_UPLOADS_API_KEY =
 | 
				
			||||||
 | 
					  process.env.FILE_UPLOADS_API_KEY ?? 'apiKeySecret'
 | 
				
			||||||
export const JWT_ACCESS_SECRET =
 | 
					export const JWT_ACCESS_SECRET =
 | 
				
			||||||
  process.env.JWT_ACCESS_SECRET ?? 'accessTokenSecret'
 | 
					  process.env.JWT_ACCESS_SECRET ?? 'accessTokenSecret'
 | 
				
			||||||
export const JWT_REFRESH_SECRET =
 | 
					export const JWT_REFRESH_SECRET =
 | 
				
			||||||
@@ -19,17 +23,3 @@ export const ROOT_URL = new URL('../', SRC_URL)
 | 
				
			|||||||
export const EMAIL_URL = new URL('./email/', ROOT_URL)
 | 
					export const EMAIL_URL = new URL('./email/', ROOT_URL)
 | 
				
			||||||
export const EMAIL_TEMPLATE_URL = new URL('./email-template.ejs', EMAIL_URL)
 | 
					export const EMAIL_TEMPLATE_URL = new URL('./email-template.ejs', EMAIL_URL)
 | 
				
			||||||
export const EMAIL_LOCALES_URL = new URL('./locales/', EMAIL_URL)
 | 
					export const EMAIL_LOCALES_URL = new URL('./locales/', EMAIL_URL)
 | 
				
			||||||
export const UPLOADS_URL = new URL('./uploads/', ROOT_URL)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const SUPPORTED_IMAGE_MIMETYPE = [
 | 
					 | 
				
			||||||
  'image/png',
 | 
					 | 
				
			||||||
  'image/jpg',
 | 
					 | 
				
			||||||
  'image/jpeg',
 | 
					 | 
				
			||||||
  'image/gif'
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** in megabytes */
 | 
					 | 
				
			||||||
export const MAXIMUM_IMAGE_SIZE = 10
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** in megabytes */
 | 
					 | 
				
			||||||
export const MAXIMUM_FILE_SIZE = 100
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ export const swaggerOptions: FastifyDynamicSwaggerOptions = {
 | 
				
			|||||||
  routePrefix: '/documentation',
 | 
					  routePrefix: '/documentation',
 | 
				
			||||||
  openapi: {
 | 
					  openapi: {
 | 
				
			||||||
    info: {
 | 
					    info: {
 | 
				
			||||||
      title: 'Thream',
 | 
					      title: packageJSON.name,
 | 
				
			||||||
      description: packageJSON.description,
 | 
					      description: packageJSON.description,
 | 
				
			||||||
      version: packageJSON.version
 | 
					      version: packageJSON.version
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,29 @@
 | 
				
			|||||||
import fs from 'node:fs'
 | 
					import fs from 'node:fs'
 | 
				
			||||||
import { URL } from 'node:url'
 | 
					 | 
				
			||||||
import { randomUUID } from 'node:crypto'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import axios from 'axios'
 | 
				
			||||||
 | 
					import FormData from 'form-data'
 | 
				
			||||||
import { FastifyInstance, FastifyRequest } from 'fastify'
 | 
					import { FastifyInstance, FastifyRequest } from 'fastify'
 | 
				
			||||||
import { Multipart } from 'fastify-multipart'
 | 
					import { Multipart } from 'fastify-multipart'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { ROOT_URL } from '../configurations/index.js'
 | 
					import {
 | 
				
			||||||
 | 
					  FILE_UPLOADS_API_KEY,
 | 
				
			||||||
 | 
					  FILE_UPLOADS_API_URL
 | 
				
			||||||
 | 
					} from '../configurations/index.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const fileUploadAPI = axios.create({
 | 
				
			||||||
 | 
					  baseURL: FILE_UPLOADS_API_URL,
 | 
				
			||||||
 | 
					  headers: {
 | 
				
			||||||
 | 
					    'Content-Type': 'application/json'
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** in megabytes */
 | 
				
			||||||
 | 
					export const MAXIMUM_FILE_SIZE = 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface UploadFileOptions {
 | 
					export interface UploadFileOptions {
 | 
				
			||||||
  folderInUploadsFolder: 'guilds' | 'messages' | 'users'
 | 
					  folderInUploadsFolder: 'guilds' | 'messages' | 'users'
 | 
				
			||||||
  request: FastifyRequest
 | 
					  request: FastifyRequest
 | 
				
			||||||
  fastify: FastifyInstance
 | 
					  fastify: FastifyInstance
 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** in megabytes */
 | 
					 | 
				
			||||||
  maximumFileSize: number
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  supportedFileMimetype?: string[]
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface UploadFileResult {
 | 
					export interface UploadFileResult {
 | 
				
			||||||
@@ -26,43 +34,42 @@ export interface UploadFileResult {
 | 
				
			|||||||
export const uploadFile = async (
 | 
					export const uploadFile = async (
 | 
				
			||||||
  options: UploadFileOptions
 | 
					  options: UploadFileOptions
 | 
				
			||||||
): Promise<UploadFileResult> => {
 | 
					): Promise<UploadFileResult> => {
 | 
				
			||||||
  const {
 | 
					  const { fastify, request, folderInUploadsFolder } = options
 | 
				
			||||||
    fastify,
 | 
					 | 
				
			||||||
    request,
 | 
					 | 
				
			||||||
    folderInUploadsFolder,
 | 
					 | 
				
			||||||
    maximumFileSize,
 | 
					 | 
				
			||||||
    supportedFileMimetype
 | 
					 | 
				
			||||||
  } = options
 | 
					 | 
				
			||||||
  let files: Multipart[] = []
 | 
					  let files: Multipart[] = []
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    files = await request.saveRequestFiles({
 | 
					    files = await request.saveRequestFiles({
 | 
				
			||||||
      limits: {
 | 
					      limits: {
 | 
				
			||||||
        files: 1,
 | 
					        files: 1,
 | 
				
			||||||
        fileSize: maximumFileSize * 1024 * 1024
 | 
					        fileSize: MAXIMUM_FILE_SIZE * 1024 * 1024
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  } catch (error) {
 | 
					  } catch (error) {
 | 
				
			||||||
    throw fastify.httpErrors.requestHeaderFieldsTooLarge(
 | 
					    throw fastify.httpErrors.requestHeaderFieldsTooLarge(
 | 
				
			||||||
      `File should be less than ${maximumFileSize}mb.`
 | 
					      `File should be less than ${MAXIMUM_FILE_SIZE}mb.`
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (files.length !== 1) {
 | 
					  if (files.length !== 1) {
 | 
				
			||||||
    throw fastify.httpErrors.badRequest('You must upload at most one file.')
 | 
					    throw fastify.httpErrors.badRequest('You must upload at most one file.')
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  const file = files[0]
 | 
					  const file = files[0]
 | 
				
			||||||
  if (
 | 
					  const formData = new FormData()
 | 
				
			||||||
    supportedFileMimetype != null &&
 | 
					  formData.append('file', fs.createReadStream(file.filepath))
 | 
				
			||||||
    !supportedFileMimetype.includes(file.mimetype)
 | 
					  try {
 | 
				
			||||||
  ) {
 | 
					    const response = await fileUploadAPI.post(
 | 
				
			||||||
    throw fastify.httpErrors.badRequest(
 | 
					      `/uploads/${folderInUploadsFolder}`,
 | 
				
			||||||
      `The file must have a valid type (${supportedFileMimetype.join(', ')}).`
 | 
					      formData,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        headers: {
 | 
				
			||||||
 | 
					          'X-API-Key': FILE_UPLOADS_API_KEY,
 | 
				
			||||||
 | 
					          ...formData.getHeaders()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    return { pathToStoreInDatabase: response.data, mimetype: file.mimetype }
 | 
				
			||||||
 | 
					  } catch (error: any) {
 | 
				
			||||||
 | 
					    throw fastify.httpErrors.createError(
 | 
				
			||||||
 | 
					      error.response.data.statusCode,
 | 
				
			||||||
 | 
					      error.response.data.message
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  const splitedMimetype = file.mimetype.split('/')
 | 
					 | 
				
			||||||
  const fileExtension = splitedMimetype[1]
 | 
					 | 
				
			||||||
  const filePath = `uploads/${folderInUploadsFolder}/${randomUUID()}.${fileExtension}`
 | 
					 | 
				
			||||||
  const fileURL = new URL(filePath, ROOT_URL)
 | 
					 | 
				
			||||||
  const pathToStoreInDatabase = `/${filePath}`
 | 
					 | 
				
			||||||
  await fs.promises.copyFile(file.filepath, fileURL)
 | 
					 | 
				
			||||||
  return { pathToStoreInDatabase, mimetype: file.mimetype }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user