44 Commits

Author SHA1 Message Date
Alexis
db2a0cf9de Fixed dead class 2021-10-27 14:21:36 +02:00
Alexis
a1c6b31f9f Removed useless imports 2021-10-27 14:10:24 +02:00
Alexis
5d54730f6d Added parent class to models 2021-10-27 14:10:09 +02:00
Alexis
8631eac69d Updated API request messages 2021-08-18 17:49:07 +02:00
Alexis
e84ff967a7 Updated API launch messages 2021-08-18 17:48:24 +02:00
Alexis
bf0a19fa45 Added env specimen files and start scripts 2021-08-18 17:47:48 +02:00
Alexis
fabe285fb2 Rearranged and refactored main Api Class 2021-08-03 17:33:20 +02:00
Alexis
288432244b Updated models with unique columns constraints 2021-08-03 17:15:31 +02:00
Alexis
2a59436625 Added terminal colours for logging 2021-08-03 17:09:39 +02:00
Alexis
5913d3914d Removed useless imports 2021-08-02 16:45:19 +02:00
Alexis
884edba504 Updated Repository
Repositories and controllers are merged, since the functions would just be really redundant thanks to TypeORM
2021-08-02 16:44:40 +02:00
Alexis
f12190c95a Added relationships to entities 2021-08-01 22:30:53 +02:00
Alexis
3b0c79c57b Added timestamp columns 2021-08-01 21:43:24 +02:00
Alexis
f19b48f801 Fixed a typo 2021-07-31 12:48:32 +02:00
Alexis
2cef0d6f8c Fixed vulnerabilities 2021-07-31 12:48:08 +02:00
Alexis
481b52bb30 Added JWT for the future 2021-07-31 12:46:10 +02:00
Alexis
dce8bf95d6 Converted models to TypeORM models 2021-07-31 12:38:04 +02:00
Alexis
477dc14e63 TypeORM tsconfig 2021-07-31 12:37:47 +02:00
Alexis
f6b95b9be1 Replacer Sequelize for TypeORM
This decision was made because it's become apparent that the Sequelize TS support is more of an afterthought than an actual feature.
TypeORM, on the other hand, seems to achieve what Sequelize does in far less lines of code.
2021-07-31 12:20:41 +02:00
Alexis
4cc7c5533e Massive cleanup
Functionnal basic API calls for spells
Cleaned up some functions
Moved some files around
2021-07-30 12:24:11 +02:00
Alexis
a15a6614e7 Fixed tablenames 2021-07-24 22:51:21 +02:00
Alexis
f1d620dacd Fixed sequelize crash, added variables 2021-07-24 22:47:45 +02:00
Alexis
f3bbe696ed Updated db models 2021-07-24 22:20:48 +02:00
Alexis
ca9dbbd7db Moved old scripts to docs folder 2021-07-23 21:57:01 +02:00
Alexis
681ff2b086 Added nodemon scripts 2021-07-23 21:56:44 +02:00
Alexis
a43b5a95c4 Removed migration files and modules
This is too time consuming for now, need to focus on something more useful
2021-07-21 22:35:14 +02:00
Alexis
4be8a25370 Automated model registration 2021-07-20 22:03:20 +02:00
Alexis
c03a5d62ec Cleaned up old files and moved things around 2021-07-19 22:02:04 +02:00
Alexis
c61293c1a9 Moved data (again) to the root folder 2021-07-19 21:52:47 +02:00
Alexis
693f481cf5 Added csv-parser and sequelize-cli 2021-07-19 21:52:34 +02:00
Alexis
e84143c114 Added cast to apiPort and cleaned more code 2021-07-19 21:34:00 +02:00
Alexis
b80ff9a982 Moved old files down a peg 2021-07-19 21:26:58 +02:00
Alexis
546e8a1eed Implemented models and cleaned some code 2021-07-19 21:26:37 +02:00
Alexis
0048c59d56 Fixed wrong import of sequelize 2021-07-19 21:25:58 +02:00
Alexis
382e8633ad Added mariadb package 2021-07-19 21:25:11 +02:00
Alexis
30a5454934 Created main class instance 2021-07-18 20:05:46 +02:00
Alexis
206a1e0737 Updated dependencies and removed esconfig rules from package json 2021-07-18 20:05:31 +02:00
Alexis
392af38965 Updated tsconfig 2021-07-18 20:04:49 +02:00
Alexis
21329863d3 Added eslint rules 2021-07-18 20:04:37 +02:00
Alexis
061bb52dac Added ts scripts and config 2021-07-18 16:08:15 +02:00
Alexis
d977ce6551 Moved code to /src folder 2021-07-18 16:08:03 +02:00
Alexis
fbc38207f7 Updated dependencies before refacto 2021-07-18 16:00:00 +02:00
Alexis
e865fe6423 Merge branch 'refactor/moved_repo' into develop 2021-07-18 15:53:05 +02:00
Alexis
c7c24a30a0 File dump from old repo 2021-07-18 15:48:01 +02:00
29 changed files with 5233 additions and 0 deletions

14
.env.dev Normal file
View File

@@ -0,0 +1,14 @@
NODE_ENV = dev
API_PORT =
DB_NAME =
DB_USER =
DB_PASSWORD =
DB_HOST =
API_KEY_PUBLIC =
API_KEY_PRIVATE =
SMTP_USER =
SMTP_PASS =

14
.env.prod Normal file
View File

@@ -0,0 +1,14 @@
NODE_ENV = prod
API_PORT =
DB_NAME =
DB_USER =
DB_PASSWORD =
DB_HOST =
API_KEY_PUBLIC =
API_KEY_PRIVATE =
SMTP_USER =
SMTP_PASS =

28
.eslintrc.js Normal file
View File

@@ -0,0 +1,28 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'prettier/@typescript-eslint',
'plugin:prettier/recommended',
],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
"prettier/prettier": ["error", {
"endOfLine":"auto"
}],
},
}

BIN
_docs/old_scripts.zip Normal file

Binary file not shown.

13
nodemon.json Normal file
View File

@@ -0,0 +1,13 @@
{
"ignore": [
"src/**/*.test.ts",
"src/**/*.spec.ts",
".git",
"node_modules"
],
"watch": [
"src"
],
"exec": "npm start",
"ext": "ts"
}

4273
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

61
package.json Normal file
View File

@@ -0,0 +1,61 @@
{
"name": "auracle-api",
"version": "1.0.0",
"description": "API for Auracle database",
"main": "./src/main.ts",
"private": true,
"scripts": {
"build": "tsc -p ./",
"start:dev": "set NODE_ENV=dev && ts-node ./src/main.ts",
"start:prod": "set NODE_ENV=prod && npm run build && node ./dist/main.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/AlexisNP/auracle_api"
},
"keywords": [
"api",
"rpg",
"spells",
"magic",
"database",
"ttrpg",
"dices",
"worldbuilding",
"express",
"node",
"typescript"
],
"author": "AlexisNP",
"license": "ISC",
"bugs": {
"url": "https://github.com/AlexisNP/spellsaurus/issues"
},
"homepage": "https://github.com/AlexisNP/spellsaurus#readme",
"dependencies": {
"bcrypt": "^5.0.1",
"cors": "^2.8.5",
"express": "^4.17.1",
"helmet": "^4.4.1",
"jsonwebtoken": "^8.5.1",
"mariadb": "^2.5.4",
"morgan": "^1.10.0",
"mysql": "^2.18.1",
"nodemailer": "^6.6.3",
"typeorm": "^0.2.35"
},
"devDependencies": {
"@types/cors": "^2.8.12",
"@types/express": "^4.17.13",
"@types/helmet": "^4.0.0",
"@types/morgan": "^1.9.3",
"@types/validator": "^13.6.3",
"babel-eslint": "^10.1.0",
"dotenv": "^8.6.0",
"eslint": "^7.31.0",
"eslint-plugin-import": "^2.23.4",
"nodemon": "^2.0.12",
"ts-node": "^10.1.0",
"typescript": "^4.3.5"
}
}

View File

@@ -0,0 +1,161 @@
import express, { Application } from 'express'
import { Connection } from 'typeorm'
import { VSColors } from '../enums/VSColors'
import { AuracleApiRouter } from './AuracleApiRouter'
/**
* AuracleApi is the main class handling all the routing, modules and middlewares.
* The
* Once the constructor is called, it automatically listens on the given port.
*/
export class AuracleApi {
/**
* Express core App.
*/
public app: Application
/**
* The port where the Express app is running on.
* @default 3000
*/
public port = 3000
/**
* Current version of the API.
*
* The usual format follows after `v1`
*/
public version = 'v1'
/**
* Base URI to access the various endpoints of the Express App.
*
* The usual format follows
* ```javascript
* /api/${this.version}/
* ```
*/
public baseUri = `/api/${this.version}/`
constructor(
init: {
database: Promise<Connection>
port?: any
routers?: Array<AuracleApiRouter>
modules?: Array<any>
middlewares?: Array<any>
}
) {
this.app = express()
if (init.port) {
this.port = Number(init.port)
}
console.log(VSColors.cyan, `[INFO] Running in a ${process.env.NODE_ENV} environment.`)
// Making sure the DB is up before init routers, modules, etc...
if (init.database) {
this.connectDatabase(init.database)
.then(async () => {
// Loads other services
await this.registerServices(init.routers, init.modules, init.middlewares)
this.listen()
})
.catch((err) => {
console.error(VSColors.red, "[ERROR] App couldn't boot up with the following errors : ")
console.error(VSColors.red, err)
})
}
}
/**
* Links the API with a TypeORM connection
*/
private async connectDatabase(db_driver: Promise<Connection>) {
try {
// Tries to connect...
console.info(VSColors.yellow, '[TASK] Trying to connect to the database...')
const connection = await db_driver
console.info(VSColors.green, '[SUCCESS] Connection has been established successfully.')
// Should the DB be rebuilt ? Are we in production ?
const dropDatabase = (process.env.NODE_ENV === 'prod') ? false : true
// Then builds the data schema from registered entities...
console.info(VSColors.yellow, '[TASK] Syncing database and its schemas...')
await connection.synchronize(dropDatabase)
console.info(VSColors.green, '[SUCCESS] Syncing done.')
return connection
} catch (err) {
console.error(VSColors.red, '[ERROR] Unable to connect to the database !')
throw err
}
}
/**
* Registers other express services to add onto the core app
*
* @param routers A list of Express Routers extended from AuracleApiRouter
* @param modules A list of Express extensions
* @param middlewares A list of Express middlewares that handle other functions
*/
private async registerServices(routers: Array<AuracleApiRouter>, modules: Array<any>, middlewares: Array<any>) {
return Promise.all([
this.modules(modules),
this.routers(routers),
this.middlewares(middlewares)
])
.catch((err) => {
throw err
})
}
/**
* Initializes the App with a bunch of modules like helmet, cors, morgan...
* @param modules An array of modules and extensions
*/
private async modules(modules: Array<any>) {
try {
modules.forEach(module => this.app.use(module))
} catch (err) {
console.error(VSColors.red, '[ERROR] Unable to initialize modules and extensions.')
throw err
}
}
/**
* Initializes routers
* @param routers An array of AuracleApiRouter children objects
*/
private async routers(routers: Array<AuracleApiRouter>) {
try {
routers.forEach(router => this.app.use(`${this.baseUri}`, router.instance))
} catch (err) {
console.error(VSColors.red, '[ERROR] Unable to initialize routers.')
throw err
}
}
private async middlewares(middleWares: {
forEach: (arg0: (middleWare: any) => void) => void;
}) {
try {
middleWares.forEach(middleWare => this.app.use(middleWare))
} catch (err) {
console.error(VSColors.red, '[ERROR] Unable to initialize middlewares.')
throw err
}
}
/**
* Allows the App to run on its given port
*/
public listen() {
this.app.listen(this.port, () => console.info(VSColors.green, `\n[APP] App listening on http://localhost${this.baseUri}.`))
}
}

View File

@@ -0,0 +1,9 @@
import { Repository } from "typeorm";
export class AuracleApiController {
public repository: Repository<any>
constructor() {
// Todo
}
}

View File

@@ -0,0 +1 @@
export class AuracleApiModel {}

View File

@@ -0,0 +1,63 @@
import { Response } from "express"
/**
* An enum that contains all the default value for the ApiResponse class
*/
enum AuracleApiResponseMessages {
defaultValid = "La requête a été effectuée avec succès.",
default201 = "La ressource a été créée avec succès.",
defaultAdditionnalAction = "La requête redirige vers une autre URL.",
default301 = "La ressource n'est plus accessible à cet URI et a été déplacée de manière permanente.",
default302 = "La ressource n'est plus accessible à cet URI et a été déplacée de manière temporaire.",
defaultClientError = "Une erreur inconnue dûe à une erreur client s'est produite",
default401 = "Vous n'êtes pas autorisé à consulter cette ressource car vous n'êtes pas identifié.",
default403 = "Vous n'êtes pas autorisé à consulter cette ressource car vous n'avez pas le niveau d'authentification requis.",
default404 = "La ressource demandée n'est pas ou plus disponible.",
default405 = "Cette méthode n'est pas disponible pour cette ressource.",
default409 = "La requête génère un conflit de ressource et ne peut aboutir.",
defaultServerError = "Une erreur serveur inconnue s'est produite, veuillez contactez l'administrateur de l'application.",
}
export class AuracleApiResponse {
public status: number
public message?: string
public data?: Object | Array<any>
constructor(status: number, data?: Array<any> | Object, message?: string) {
this.status = status
this.data = data
if (message) {
this.message = message
}
// If a message was not provided, gets one by default
else {
// HTTP Valid ranges
if ((this.status >= 200) && (this.status <= 299)) {
this.message = AuracleApiResponseMessages.defaultValid
}
// HTTP Additionnal Action ranges
else if ((this.status >= 300) && (this.status <= 399)) {
this.message = AuracleApiResponseMessages.defaultAdditionnalAction
}
// HTTP Client Error ranges
else if ((this.status >= 400) && (this.status <= 499)) {
this.message = AuracleApiResponseMessages.defaultClientError
}
// HTTP Server Error ranges
else if ((this.status >= 500) && (this.status <= 599)) {
this.message = AuracleApiResponseMessages.defaultServerError
}
}
}
public send(res: Response): Response {
return res.status(this.status).json(this)
}
}

View File

@@ -0,0 +1,17 @@
import { Router, RouterOptions } from "express";
import { AuracleApiController } from "./AuracleApiController";
export abstract class AuracleApiRouter {
public instance: Router
public routerOptions: RouterOptions
public resource: string
public controller: AuracleApiController
constructor(resource: string, controller: AuracleApiController, options?: RouterOptions) {
this.resource = resource
this.routerOptions = options
this.controller = controller
this.instance = Router(this.routerOptions) as Router
}
}

View File

@@ -0,0 +1,7 @@
export enum VSColors {
red = '\x1b[31m%s\x1b[0m',
yellow = '\x1b[33m%s\x1b[0m',
green = '\x1b[32m%s\x1b[0m',
cyan = '\x1b[36m%s\x1b[0m',
blue = '\x1b[34m%s\x1b[0m'
}

View File

@@ -0,0 +1,37 @@
import { NextFunction, Response } from "express";
const regexInt = RegExp(/^[1-9]\d*$/);
const regexXSS = RegExp(/<[^>]*script/);
// Check if int for param validation
const paramIntCheck = (req: Request, res: Response, next: NextFunction, input: any) => {
try {
if (regexInt.test(input)) {
next();
} else {
throw new Error;
}
} catch (err) {
res.status(err.code).send(JSON.stringify({
"message": "Le paramètre doit être un entier non-nul.",
"code": 403,
})
);
}
};
// Check if script injection attempt
const isXSSAttempt = (string: string) => {
return regexXSS.test(string);
};
// Check if object is null
const isEmptyObject = (obj: Object) => {
return (Object.keys(obj).length === 0 && obj.constructor === Object);
};
module.exports = {
paramIntCheck,
isXSSAttempt,
isEmptyObject
};

View File

@@ -0,0 +1,52 @@
import express from 'express';
import { getRepository } from 'typeorm';
import { AuracleApiController } from "../common/classes/AuracleApiController";
import { AuracleApiResponse } from '../common/classes/AuracleApiResponse';
import { Spell } from '../database/models/spells/Spell';
export class SpellController extends AuracleApiController {
constructor() {
super()
}
public async getAll(req: express.Request, res: express.Response) {
let spells: Spell[]
try {
spells = await getRepository(Spell).find()
res = new AuracleApiResponse(200, spells).send(res)
} catch (err) {
res = new AuracleApiResponse(400).send(res)
}
}
public async getOne(req: express.Request, res: express.Response) {
const uuid = req.params.uuid
let spell: Spell
try {
spell = await getRepository(Spell).findOne(uuid)
res = new AuracleApiResponse(200, spell).send(res)
} catch (err) {
res = new AuracleApiResponse(400).send(res)
}
}
public async createOne(req: express.Request, res: express.Response) {
const spell = {
name: req.body.name,
description: req.body.description,
level: req.body.level,
charge: req.body.charge,
cost: req.body.cost,
isRitual: req.body.isRitual
}
try {
const newSpell = getRepository(Spell).insert(spell)
res = new AuracleApiResponse(201, newSpell).send(res)
} catch (err) {
console.log(err)
}
}
}

View File

@@ -0,0 +1,4 @@
import { createConnection } from 'typeorm';
import { dbConfig } from './config'
export const AuracleDatabaseDriver = createConnection(dbConfig);

View File

@@ -0,0 +1,52 @@
import { MysqlConnectionOptions } from "typeorm/driver/mysql/MysqlConnectionOptions"
import * as fs from 'fs'
const tablePrefix = 'au_'
/**
* Fetches all Typescript files from a given directory
*
* @param dir The folder to scan where the models are located
* @param acc (Optional) The array to start
* @returns All .ts files within the dir
*/
export const fetchAllTypescriptFiles = (dir: string, acc: string[] = []): string[] => {
fs.readdirSync(dir)
.forEach(file => {
const fileIsTypescript = (file.split('.').pop() === 'ts')
const fileIsFolder = (file.indexOf('.') === -1)
if (fileIsFolder) {
fetchAllTypescriptFiles(`${dir}/${file}`, acc)
}
if (fileIsTypescript) {
acc.push(`${dir}/${file}`)
}
})
return acc
}
const modelDir = './src/database/models/'
const models = fetchAllTypescriptFiles(modelDir)
/**
* Registers the options to create the sequelize instance
*/
export const dbConfig: MysqlConnectionOptions = {
/**
* Access to database
*/
type: 'mariadb',
database: process.env.DB_NAME,
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
host: process.env.DB_HOST,
logging: false,
entityPrefix: tablePrefix,
entities: models
}

View File

@@ -0,0 +1,40 @@
import { Column, CreateDateColumn, Entity, JoinTable, ManyToMany, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
import { AuracleApiModel } from "../../../common/classes/AuracleApiModel";
import { User } from "../users/User";
import { Spell } from "./Spell";
@Entity()
export class Ingredient extends AuracleApiModel {
@PrimaryGeneratedColumn('uuid')
public readonly uuid!: string
@Column({
unique: true
})
public name: string
@Column({
unique: true
})
public description: string
@Column()
public published: boolean
@ManyToMany(() => Spell, spell => spell.ingredients)
@JoinTable({
name: 'ingredients_spells'
})
public spells?: Spell[]
@ManyToOne(() => User, user => user.ingredients)
public creator: User
// TIMESTAMPS
@Column()
@CreateDateColumn()
public createdAt?: Date
@Column()
@UpdateDateColumn()
public updatedAt?: Date
}

View File

@@ -0,0 +1,37 @@
import { Column, CreateDateColumn, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm"
import { AuracleApiModel } from "../../../common/classes/AuracleApiModel"
import { User } from "../users/User"
import { School } from "./School"
@Entity()
export class MetaSchool extends AuracleApiModel {
@PrimaryGeneratedColumn('uuid')
public readonly uuid!: string
@Column({
unique: true
})
public name: string
@Column({
unique: true
})
public description: string
@Column()
public published: boolean
@OneToMany(() => School, school => school.metaSchool)
public schools?: School[]
@ManyToOne(() => User, user => user.metaSchools)
public creator: User
// TIMESTAMPS
@Column()
@CreateDateColumn()
public createdAt?: Date
@Column()
@UpdateDateColumn()
public updatedAt?: Date
}

View File

@@ -0,0 +1,44 @@
import { BaseEntity, Column, CreateDateColumn, Entity, JoinTable, ManyToMany, ManyToOne, PrimaryGeneratedColumn, Unique, UpdateDateColumn } from "typeorm";
import { AuracleApiModel } from "../../../common/classes/AuracleApiModel";
import { User } from "../users/User";
import { MetaSchool } from "./MetaSchool";
import { Spell } from "./Spell";
@Entity()
export class School extends AuracleApiModel {
@PrimaryGeneratedColumn('uuid')
public readonly uuid!: string
@Column({
unique: true
})
public name: string
@Column({
unique: true
})
public description: string
@Column()
public published: boolean
@ManyToMany(() => Spell, spell => spell.schools)
@JoinTable({
name: 'schools_spells'
})
public spells?: Spell[]
@ManyToOne(() => MetaSchool, metaSchool => metaSchool.schools)
public metaSchool: MetaSchool
@ManyToOne(() => User, user => user.schools)
public creator: User
// TIMESTAMPS
@Column()
@CreateDateColumn()
public createdAt?: Date
@Column()
@UpdateDateColumn()
public updatedAt?: Date
}

View File

@@ -0,0 +1,58 @@
import { Column, CreateDateColumn, Entity, JoinTable, ManyToMany, ManyToOne, OneToMany, OneToOne, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm"
import { AuracleApiModel } from "../../../common/classes/AuracleApiModel"
import { User } from "../users/User"
import { Ingredient } from "./Ingredient"
import { School } from "./School"
import { Variable } from "./Variable"
@Entity()
export class Spell extends AuracleApiModel {
@PrimaryGeneratedColumn('uuid')
public readonly uuid!: string
@Column({
unique: true
})
public name: string
@Column({
unique: true
})
public description: string
@Column()
public level?: number
@Column()
public charge?: number
@Column()
public cost?: string
@Column()
public isRitual?: boolean
@Column()
public published?: boolean
@Column()
public public?: boolean
// LINKED ENTITIES
@ManyToMany(() => School, school => school.spells)
public schools?: School[]
@ManyToMany(() => Variable, variable => variable.spells)
public variables?: Variable[]
@ManyToMany(() => Ingredient, ingredient => ingredient.spells)
public ingredients?: Ingredient[]
@ManyToOne(() => User, user => user.spells)
public creator: User
// TIMESTAMPS
@Column()
@CreateDateColumn()
public createdAt?: Date
@Column()
@UpdateDateColumn()
public updatedAt?: Date
}

View File

@@ -0,0 +1,36 @@
import { Column, CreateDateColumn, Entity, JoinTable, ManyToMany, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
import { AuracleApiModel } from "../../../common/classes/AuracleApiModel";
import { User } from "../users/User";
import { Spell } from "./Spell";
@Entity()
export class Variable extends AuracleApiModel {
@PrimaryGeneratedColumn('uuid')
public readonly uuid!: string
@Column({
unique: true
})
public description: string
@Column()
public published: boolean
@ManyToMany(() => Spell, spell => spell.variables)
@JoinTable({
name: 'variables_spells'
})
public spells?: Spell[]
@ManyToOne(() => User, user => user.variables)
public creator: User
// TIMESTAMPS
@Column()
@CreateDateColumn()
public createdAt?: Date
@Column()
@UpdateDateColumn()
public updatedAt?: Date
}

View File

@@ -0,0 +1,26 @@
import { Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
import { AuracleApiModel } from "../../../common/classes/AuracleApiModel";
import { Role } from "./Role";
@Entity()
export class Permission extends AuracleApiModel {
@PrimaryGeneratedColumn('uuid')
public readonly uuid!: string
@Column({
unique: true
})
public slug: string
@ManyToOne(() => Role, role => role.permissions)
public roles: Role[]
// TIMESTAMPS
@Column()
@CreateDateColumn()
public createdAt?: Date
@Column()
@UpdateDateColumn()
public updatedAt?: Date
}

View File

@@ -0,0 +1,34 @@
import { Column, CreateDateColumn, Entity, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
import { AuracleApiModel } from "../../../common/classes/AuracleApiModel";
import { Permission } from "./Permission";
import { User } from "./User";
@Entity()
export class Role extends AuracleApiModel {
@PrimaryGeneratedColumn('uuid')
public readonly uuid!: string
@Column({
unique: true
})
public name: string
@Column({
unique: true
})
public description: string
@OneToMany(() => Permission, permission => permission.roles)
public permissions: Permission[]
@OneToMany(() => User, user => user.role)
public users: User[]
// TIMESTAMPS
@Column()
@CreateDateColumn()
public createdAt?: Date
@Column()
@UpdateDateColumn()
public updatedAt?: Date
}

View File

@@ -0,0 +1,60 @@
import { Column, CreateDateColumn, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm"
import { AuracleApiModel } from "../../../common/classes/AuracleApiModel"
import { Ingredient } from "../spells/Ingredient"
import { MetaSchool } from "../spells/MetaSchool"
import { School } from "../spells/School"
import { Spell } from "../spells/Spell"
import { Variable } from "../spells/Variable"
import { Role } from "./Role"
@Entity()
export class User extends AuracleApiModel {
@PrimaryGeneratedColumn('uuid')
public readonly uuid!: string
@Column({
unique: true
})
public readonly mail: string
@Column()
public readonly password: string
@Column()
public name: string
@Column()
public avatar: string
@Column()
public gender: string
@Column()
public verified: boolean
// CREATIONS
@OneToMany(() => Spell, spell => spell.creator)
public spells?: Spell[]
@OneToMany(() => School, school => school.creator)
public schools?: School[]
@OneToMany(() => Variable, variable => variable.creator)
public variables?: Variable[]
@OneToMany(() => Ingredient, ingredients => ingredients.creator)
public ingredients?: Ingredient[]
@OneToMany(() => MetaSchool, metaSchools => metaSchools.creator)
public metaSchools?: Ingredient[]
// ROLE
@ManyToOne(() => Role, role => role.users)
public role: Role
// TIMESTAMPS
@Column()
@CreateDateColumn()
public createdAt?: Date
@Column()
@UpdateDateColumn()
public updatedAt?: Date
}

36
src/main.ts Normal file
View File

@@ -0,0 +1,36 @@
/**
* Dependencies
*/
// .env Data
import * as dotenv from 'dotenv'
dotenv.config();
// TypeORM
import "reflect-metadata";
import morgan from 'morgan'
import helmet from 'helmet'
import express from 'express'
import { AuracleApi } from './common/classes/AuracleApi'
import { AuracleDatabaseDriver } from './database/AuracleDatabaseDriver'
import { SpellRouter } from './routes/SpellRouter';
const apiPort = process.env.API_PORT
const api = new AuracleApi({
database: AuracleDatabaseDriver,
port: apiPort,
middlewares: [],
routers: [
new SpellRouter
],
modules: [
express.json({ limit: '10kb' }),
morgan('dev'),
helmet()
],
})

23
src/routes/SpellRouter.ts Normal file
View File

@@ -0,0 +1,23 @@
import { AuracleApiRouter } from "../common/classes/AuracleApiRouter";
import { SpellController } from "../controllers/SpellController";
export class SpellRouter extends AuracleApiRouter {
public controller: SpellController
constructor() {
super('/spells', new SpellController)
this.initRoutes()
}
public initRoutes() {
// GET: /spells
this.instance.get(this.resource, this.controller.getAll.bind(this.controller))
// GET: /spells/uuid
this.instance.get(`${this.resource}/:uuid`, this.controller.getOne.bind(this.controller))
// POST: /spells
this.instance.post(this.resource, this.controller.createOne.bind(this.controller))
}
}

9
tsconfig.build.json Normal file
View File

@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"exclude": [
"node_modules",
"test",
"dist",
"**/*spec.ts"
]
}

24
tsconfig.json Normal file
View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"noImplicitAny": true,
"alwaysStrict": true,
"charset": "utf-8",
"allowSyntheticDefaultImports": true,
"target": "es2017",
"sourceMap": true,
"outDir": "./dist",
"esModuleInterop": true,
"baseUrl": "/src",
"incremental": true,
"types": [
"node",
"express"
],
// Required for TypeORM
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
}