Initial commit

This commit is contained in:
Florian Sylvain
2024-02-08 13:59:12 +01:00
commit d3109983fe
20 changed files with 7811 additions and 0 deletions
Vendored
BIN
View File
Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
node_modules
.env
+16
View File
@@ -0,0 +1,16 @@
FROM node:lts-hydrogen
WORKDIR /app
COPY ./package.json ./
COPY ./package-lock.json ./
COPY ./tsconfig.json ./
COPY ./.env ./
ADD ./src ./src/
ADD ./prisma ./prisma/
RUN npm install
RUN npx prisma generate
RUN npm run build
CMD npx prisma migrate deploy && npm run start
+55
View File
@@ -0,0 +1,55 @@
# what-to-do-in-paris-backend
## Project setup
### Environment variables
The following environment variables are required to run the project:
| Variable name | Description |
|---------------------|----------------------------------------------------------------------------|
| `PORT` | Port on which the server will run |
| `POSTGRES_PASSWORD` | Password for the root user of the PostgreSQL database |
| `DATABASE_URL` | URL of the PostgreSQL database, for Prisma. Required when not using Docker |
| `JWT_SECRET` | Secret used to sign the JWT tokens |
You can either export them in your shell, or create a `.env` file at the root of the project.
### Install dependencies
```bash
pnpm install
```
### Run the server
#### With Docker
```bash
docker compose up --build -d
```
#### Without Docker
```bash
pnpm run build
```
```bash
pnpm run start
```
### Routes
| Method | Route | Description | Body |
|--------|--------------------------------------------------------------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `POST` | `/v1/auth/register` | Register a new user | `email`, `password`, `name` |
| `POST` | `/v1/auth/login` | Login a user | `email`, `password` |
| `POST` | `/v1/events` | Create new events | `Array<Event>` (see `data.json` in `/script`) |
| `GET` | `/v1/events?limit=&page=&from=&to=&deaf=&pmr=&blind=&sortBy=&sortOrder=` | Get all events | limit: `number`, page: `number`, from: `timestamp`, to `timestamp`, tags: `strings separated by ,`, pmr: `0 or 1`, deaf: `0 or 1`, blind: `0 or 1`, sortOrder: `asc or desc`, sortBy: `field of Event` |
| `GET` | `/v1/events/:id` | Get an event by its id | |
### Other information
A default admin user is created when the server starts for the first time. Its password is displayed in the logs of the
backend.
+15
View File
@@ -0,0 +1,15 @@
services:
backend:
build:
dockerfile: ./Dockerfile
image: space-game-backend
env_file:
- .env
ports:
- "${API_PORT}:${API_PORT}"
deploy:
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 30s
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
}
+7158
View File
File diff suppressed because it is too large Load Diff
+41
View File
@@ -0,0 +1,41 @@
{
"name": "space-game-backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "nodemon --exec ts-node src/app.ts",
"build": "tsc",
"start": "node -r dotenv/config ./build/app.js",
"test": "jest"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/bcrypt": "^5.0.2",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.11",
"@types/jsonwebtoken": "^9.0.5",
"@types/node": "^20.10.4",
"@types/passport": "^1.0.16",
"@types/passport-jwt": "^3.0.13",
"jest": "^29.7.0",
"nodemon": "^3.0.2",
"prettier": "^3.1.1",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.2",
"typescript": "^5.3.3",
"prisma": "^5.9.1"
},
"dependencies": {
"@prisma/client": "^5.9.1",
"@types/cors": "^2.8.17",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"prisma-dbml-generator": "^0.10.0",
"zod": "^3.22.4"
}
}
BIN
View File
Binary file not shown.
+170
View File
@@ -0,0 +1,170 @@
//// ------------------------------------------------------
//// THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
//// ------------------------------------------------------
Table City {
id Int [pk, increment]
name String [not null]
zipcode Int [not null]
}
Table ImageCover {
id String [pk]
filename String [not null]
width Int [not null]
height Int [not null]
format Format [not null]
etag String [not null]
mimetype MimeType [not null]
last_synchronized DateTime [not null]
color_summary String[] [not null]
thumbnail Boolean [not null]
}
Table LatLon {
id Int [pk, increment]
lon Float [not null]
lat Float [not null]
}
Table Contact {
id Int [pk, increment]
url String
phone String
mail String
facebook String
twitter String
}
Table Price {
id Int [pk, increment]
type PriceType [not null]
detail String
}
Table Access {
id Int [pk, increment]
type String [not null]
link String
link_text String
}
Table Event {
id Int [pk, increment]
latLonId Int [not null]
cityId Int [not null]
contactId Int
priceId Int
accessId Int
imageCoverId String [not null]
url String [unique, not null]
title String [not null]
lead_text String [not null]
description String [not null]
date_start DateTime [not null]
date_end DateTime [not null]
date_description String [not null]
occurrences String [not null]
cover_url String [not null]
cover_alt String
cover_credit String
tags Tag[] [not null]
address_name String [not null]
address_street String [not null]
pmr Boolean [not null]
blind Boolean [not null]
deaf Boolean [not null]
transport String
updated_at DateTime [not null]
programs String
address_url String
address_url_text String
address_text String
title_event String
audience String
childrens String
group Group [not null]
}
Enum Tag {
Concert
Enfants
Musique
Expo
Theatre
Conference
Loisirs
Peinture
Atelier
Litterature
Danse
Sport
ArtContemporain
SpectacleMusical
Cinema
Innovation
Balade
Nature
Histoire
Photo
Clubbing
BD
Cirque
Solidarite
Brocante
Humour
Salon
Sciences
LGBT
Sante
StreetArt
Gourmand
Jeux2024
}
Enum PriceType {
gratuit
payant
gratuitConditionnel
}
Enum Group {
Aucun
Agenda
CentresAnimations
NuitBlanche
Bibliotheques
ActivitesDJS
ParcsEtJardins
Associations
Musees
}
Enum Format {
PNG
JPEG
}
Enum MimeType {
image_jpeg
image_png
}
Table User {
id Int [pk, increment]
email String [unique, not null]
password String [not null]
name String
}
Ref: Event.cityId > City.id
Ref: Event.latLonId > LatLon.id
Ref: Event.contactId > Contact.id
Ref: Event.priceId > Price.id
Ref: Event.accessId > Access.id
Ref: Event.imageCoverId > ImageCover.id
+123
View File
@@ -0,0 +1,123 @@
//// ------------------------------------------------------
//// THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
//// ------------------------------------------------------
Table City {
id Int [pk, increment]
name String [not null]
zipcode Int [unique, not null]
}
Table Contact {
id Int [pk, increment]
url String
phone String
email String
facebook String
twitter String
}
Table Event {
id Int [pk, increment]
cityId Int
contactId Int
url String
title String
lead_text String
description String
date_start DateTime
date_end DateTime
date_description String
occurrences String
cover_url String
cover_alt String
cover_credit String
tags Tag[] [not null]
address_name String
address_street String
latitude Float
longitude Float
pmr Boolean
blind Boolean
deaf Boolean
transport String
access_type AccessType
access_link String
access_link_text String
price_type PriceType
price_detail String
programs String
audience String
group Group
}
Table User {
id Int [pk, increment]
email String [unique, not null]
password String [not null]
name String
}
Enum Tag {
Concert
Enfants
Musique
Expo
Theatre
Conference
Loisirs
Peinture
Atelier
Litterature
Danse
Sport
ArtContemporain
SpectacleMusical
Cinema
Innovation
Balade
Nature
Histoire
Photo
Clubbing
BD
Cirque
Solidarite
Brocante
Humour
Salon
Sciences
LGBT
Sante
StreetArt
Gourmand
Jeux2024
}
Enum PriceType {
gratuit
payant
gratuitConditionnel
}
Enum Group {
Aucun
Agenda
CentresAnimations
NuitBlanche
Bibliotheques
ActivitesDJS
ParcsEtJardins
Associations
Musees
}
Enum AccessType {
obligatoire
conseillee
non
}
Ref: Event.cityId > City.id
Ref: Event.contactId > Contact.id
+10
View File
@@ -0,0 +1,10 @@
//// ------------------------------------------------------
//// THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
//// ------------------------------------------------------
Table Score {
id Int [pk, increment]
nickname String [not null]
score Int [not null]
position Int [not null]
}
@@ -0,0 +1,7 @@
-- CreateTable
CREATE TABLE "Score" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"nickname" TEXT NOT NULL,
"score" INTEGER NOT NULL,
"position" INTEGER NOT NULL
);
+3
View File
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "sqlite"
+19
View File
@@ -0,0 +1,19 @@
generator client {
provider = "prisma-client-js"
}
generator dblm {
provider = "prisma-dbml-generator"
}
datasource db {
provider = "sqlite"
url = "file:./sqlite.db"
}
model Score {
id Int @id @default(autoincrement())
nickname String
score Int
position Int
}
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+48
View File
@@ -0,0 +1,48 @@
import express from "express";
import { z } from "zod";
import { prisma } from "../app";
export const scoreRouter = express.Router();
const scorePostValidator = z.object({
nickname: z.string(),
score: z.number(),
});
const scoreGetNicknameValidator = z.object({
nickname: z.string(),
});
scoreRouter.post("/", async (req, res) => {
try {
const data = scorePostValidator.parse(req.body);
const scores = await prisma.score.findMany({});
scores.sort((a, b) => a.score + b.score);
let i = 0;
for (const score of scores) {
if (score.score < data.score) break;
i++;
}
const newScore = await prisma.score.create({
data: { ...data, position: i },
});
res.json(newScore);
} catch (e) {
res.send(e);
}
});
scoreRouter.get("/", async (req, res) => {
try {
const scores = await prisma.score.findMany({
take: 5,
orderBy: [{ score: "desc" }],
});
res.json(scores);
} catch (e) {
console.log(e);
res.send(e);
}
});
+30
View File
@@ -0,0 +1,30 @@
import express from "express";
import cors from "cors";
import { PrismaClient } from "@prisma/client";
import { scoreRouter } from "./api/score";
import "dotenv/config";
export const prisma = new PrismaClient();
const app = express();
app.use(cors({ origin: "*" }));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
function initRoutes() {
app.get("/v1", (_, res) =>
res.json({ message: "space-game-api", version: "1.0.0" })
);
app.use("/v1/score", scoreRouter);
}
async function initServer() {
initRoutes();
app.listen(process.env.API_PORT, () => {
console.log(`Server listening on :${process.env.API_PORT}`);
});
}
initServer();
+110
View File
@@ -0,0 +1,110 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
"rootDir": "./src", /* Specify the root folder within your source files. */
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
"outDir": "./build/", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"exclude": ["node_modules", "./src/__test__"]
}