feat: add api support and auth
This commit is contained in:
parent
31e4b854db
commit
a244d98806
21 changed files with 585 additions and 63 deletions
18
.env.example
Normal file
18
.env.example
Normal file
|
@ -0,0 +1,18 @@
|
|||
S3_ORGANIZATION_ID=
|
||||
S3_ACCESS_KEY=
|
||||
S3_SECRET_KEY=
|
||||
|
||||
MONGO_URI=mongodb://root:root@127.0.0.1:27017/forumvirt?authSource=admin
|
||||
|
||||
SMTP_HOST=
|
||||
SMTP_PORT=
|
||||
SMTP_USERNAME=
|
||||
SMTP_PASSWORD=
|
||||
SMTP_SECURE=false
|
||||
|
||||
ADMIN_TOKEN=pass
|
||||
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=root
|
||||
|
10
package.json
10
package.json
|
@ -1,6 +1,12 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.29",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.13.1",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.13.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.13.1",
|
||||
"@types/cors": "^2.8.6",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/ioredis": "^4.17.0",
|
||||
"@types/mongoose": "^5.7.28",
|
||||
"@types/multer": "^1.4.3",
|
||||
"@types/multer-s3": "^2.7.7",
|
||||
|
@ -8,13 +14,17 @@
|
|||
"@types/nodemailer": "^6.4.0",
|
||||
"aws-sdk": "^2.706.0",
|
||||
"body-parser": "^1.19.0",
|
||||
"cors": "^2.8.5",
|
||||
"crypto-random-string": "^3.2.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"ioredis": "^4.17.3",
|
||||
"mongoose": "^5.9.20",
|
||||
"multer": "^1.4.2",
|
||||
"multer-s3": "^2.9.0",
|
||||
"multer-s3-v2": "^2.2.1",
|
||||
"mustache": "^4.0.1",
|
||||
"nanoid": "^3.1.10",
|
||||
"nodemailer": "^6.4.10",
|
||||
"typescript": "^3.9.5"
|
||||
},
|
||||
|
|
18
src/EmailService.ts
Normal file
18
src/EmailService.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import nodemailer from 'nodemailer'
|
||||
|
||||
export default class EmailService {
|
||||
static getTransporter() {
|
||||
if (process.env.SMTP_HOST == undefined || process.env.SMTP_PORT == undefined) {
|
||||
throw new Error("Invalid SMTP config")
|
||||
}
|
||||
return nodemailer.createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: parseInt(process.env.SMTP_PORT),
|
||||
secure: process.env.SMTP_SECURE == 'true',
|
||||
auth: {
|
||||
user: process.env.SMTP_USERNAME,
|
||||
pass: process.env.SMTP_PASSWORD,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
51
src/IconService.ts
Normal file
51
src/IconService.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import * as faSolid from '@fortawesome/free-solid-svg-icons'
|
||||
import * as faBrands from '@fortawesome/free-brands-svg-icons'
|
||||
import * as faRegular from '@fortawesome/free-regular-svg-icons'
|
||||
import { IconDefinition } from '@fortawesome/fontawesome-common-types'
|
||||
|
||||
export interface IconInterface {
|
||||
id: string,
|
||||
width: number,
|
||||
height: number,
|
||||
path: string
|
||||
}
|
||||
|
||||
export class IconService {
|
||||
|
||||
static snakeToCamel(str: string): string {
|
||||
return str.replace(
|
||||
/([-_][a-z])/g,
|
||||
group => group.toUpperCase().replace('-', '').replace('_', '')
|
||||
)
|
||||
}
|
||||
|
||||
static getIcon(id: string): IconInterface|null {
|
||||
let components: string[] = id.split(id.indexOf('_') !== -1 ? '_' : ' ')
|
||||
if (components.length < 2) {
|
||||
return null
|
||||
}
|
||||
let iconSet: any = {}
|
||||
switch (components[0]) {
|
||||
case 'fas':
|
||||
iconSet = faSolid
|
||||
break
|
||||
case 'fab':
|
||||
iconSet = faBrands
|
||||
break
|
||||
case 'far':
|
||||
iconSet = faRegular
|
||||
break
|
||||
}
|
||||
let iconName: string = this.snakeToCamel(components[1])
|
||||
let iconVal: IconDefinition|undefined = iconSet[iconName]
|
||||
if (iconVal === undefined) {
|
||||
return null
|
||||
}
|
||||
return {
|
||||
id: components[0] + ' ' + components[1],
|
||||
width: iconVal.icon[0],
|
||||
height: iconVal.icon[1],
|
||||
path: iconVal.icon[4] as string
|
||||
}
|
||||
}
|
||||
}
|
13
src/RedisService.ts
Normal file
13
src/RedisService.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import Redis from 'ioredis'
|
||||
import IORedis from 'ioredis'
|
||||
|
||||
export default class RedisService {
|
||||
|
||||
static getClient(): IORedis.Redis {
|
||||
return new IORedis(
|
||||
parseInt(process.env.REDIS_PORT === undefined ? '6379' : process.env.REDIS_PORT),
|
||||
process.env.REDIS_HOST === undefined ? "127.0.0.1" : process.env.REDIS_HOST,
|
||||
{ password: process.env.REDIS_PASSWORD }
|
||||
)
|
||||
}
|
||||
}
|
60
src/app.ts
60
src/app.ts
|
@ -3,9 +3,15 @@ import bodyParser from 'body-parser'
|
|||
import express from 'express'
|
||||
import mongoose from 'mongoose'
|
||||
import AdminTagController from './controllers/AdminTagController'
|
||||
import AdminOrganizationController from './controllers/AdminOrganizationController'
|
||||
import DefaultController from './controllers/DefaultController'
|
||||
import MediaController from './controllers/MediaController'
|
||||
import dotenv from 'dotenv'
|
||||
import DelegateController from './controllers/DelegateController'
|
||||
import AdminAuthMiddleware from './middlewares/AdminAuthMiddleware'
|
||||
import DelegateAuthMiddleware from './middlewares/DelegateAuthMiddleware'
|
||||
import PublicController from './controllers/PublicController'
|
||||
import cors from 'cors'
|
||||
|
||||
console.log('WOOWOWO')
|
||||
|
||||
|
@ -32,16 +38,58 @@ let main = async () => {
|
|||
console.log('> Connected to mongodb')
|
||||
})
|
||||
|
||||
app.use(cors())
|
||||
app.use(bodyParser.json())
|
||||
|
||||
app.get('/', DefaultController.home)
|
||||
app.get('/association/:slug', DefaultController.publicOrganization)
|
||||
app.use((err: any, req: express.Request, res: express.Response, next: express.RequestHandler) => {
|
||||
console.error(err.stack)
|
||||
res.status(res.statusCode).json({ success: false, error: err.stack })
|
||||
})
|
||||
|
||||
app.get('/', PublicController.home)
|
||||
app.get('/association/:slug', PublicController.organization)
|
||||
|
||||
app.get('/icon/:id', DefaultController.viewIcon)
|
||||
app.get('/email', DefaultController.sendEmail)
|
||||
|
||||
app.get('/api/tags', AdminTagController.getTags)
|
||||
app.put('/api/tags/:id', AdminTagController.updateTag)
|
||||
app.post('/api/tags', AdminTagController.storeTag)
|
||||
app.delete('/api/tags/:id', AdminTagController.destroyTag)
|
||||
app.use('/admin', express.Router()
|
||||
.use(AdminAuthMiddleware.handle)
|
||||
.get('/', DefaultController.success)
|
||||
.use('/tags', express.Router()
|
||||
.get('/', AdminTagController.getMany)
|
||||
.post('/', AdminTagController.store)
|
||||
.put('/:id', AdminTagController.update)
|
||||
.delete('/:id', AdminTagController.destroy)
|
||||
)
|
||||
.use('/organizations', express.Router()
|
||||
.get('/', AdminOrganizationController.getMany)
|
||||
.get('/:id', AdminOrganizationController.getOne)
|
||||
.post('', AdminOrganizationController.store)
|
||||
.put('/:id', AdminOrganizationController.update)
|
||||
.delete('/:id', AdminOrganizationController.destroy)
|
||||
.post('/:id/reset-token', AdminOrganizationController.resetToken)
|
||||
.post('/:id/approve', AdminOrganizationController.approve)
|
||||
.post('/:id/reject', AdminOrganizationController.reject)
|
||||
)
|
||||
)
|
||||
|
||||
app.use('/delegate', express.Router()
|
||||
.use(DelegateAuthMiddleware.handle)
|
||||
.get('/', DelegateController.get)
|
||||
.put('/', DelegateController.update)
|
||||
.put('/submit', DelegateController.submit)
|
||||
.delete('/', DelegateController.destroy)
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
.put('/tags/:id', AdminTagController.update)
|
||||
.put('/tags/:id', AdminTagController.destroy)
|
||||
.use('/organizations', () => express.Router()
|
||||
.get('/', AdminOrganizationController.getMany)
|
||||
)
|
||||
*/
|
||||
|
||||
|
||||
app.post('/api/upload', MediaController.uploadRoute())
|
||||
|
||||
|
|
|
@ -1,10 +1,79 @@
|
|||
import * as express from 'express'
|
||||
import Organization from '../models/Organization'
|
||||
import cryptoRandomString from 'crypto-random-string'
|
||||
|
||||
export default class AdminOrganizationController {
|
||||
static getOrganizations(req: express.Request, res: express.Response) {
|
||||
static getMany(req: express.Request, res: express.Response) {
|
||||
Organization.find().then(data => {
|
||||
res.json(data)
|
||||
})
|
||||
}
|
||||
|
||||
static getOne(req: express.Request, res: express.Response) {
|
||||
Organization.findById(req.params.id).then(data => {
|
||||
res.json(data)
|
||||
})
|
||||
}
|
||||
|
||||
static store(req: express.Request, res: express.Response) {
|
||||
Organization.create({
|
||||
token: cryptoRandomString({ length: 10, type: 'distinguishable' }),
|
||||
...req.body
|
||||
}).then(data => {
|
||||
res.json({
|
||||
success: true,
|
||||
data
|
||||
})
|
||||
}).catch(err => {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
errors: err.errors
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
static update(req: express.Request, res: express.Response) {
|
||||
Organization.updateOne({ _id: req.params.id }, req.body).then(data => {
|
||||
res.json({
|
||||
success: true,
|
||||
data
|
||||
})
|
||||
}).catch(err => {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
errors: err.errors !== undefined ? err.errors : err
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
static destroy(req: express.Request, res: express.Response) {
|
||||
Organization.deleteOne({ _id: req.params.id }).then(data => {
|
||||
let isSuccess = data.deletedCount !== undefined && data.deletedCount > 0
|
||||
res.status(isSuccess ? 200 : 400).json({
|
||||
success: isSuccess,
|
||||
data
|
||||
})
|
||||
}).catch(err => {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
errors: err.errors
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
static sendEmailToken() {
|
||||
|
||||
}
|
||||
|
||||
static resetToken(req: express.Request, res: express.Response) {
|
||||
|
||||
}
|
||||
|
||||
static approve(req: express.Request, res: express.Response) {
|
||||
|
||||
}
|
||||
|
||||
static reject(req: express.Request, res: express.Response) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,14 +1,26 @@
|
|||
import Tag from '../models/Tag'
|
||||
import express from 'express'
|
||||
import { IconService, IconInterface } from '../IconService'
|
||||
|
||||
export default class AdminTagController {
|
||||
static getTags(_: any, res: express.Response) {
|
||||
static getMany(_: any, res: express.Response) {
|
||||
Tag.find().then(data => {
|
||||
res.json(data)
|
||||
res.json({ success: true, data })
|
||||
})
|
||||
}
|
||||
|
||||
static storeTag(req: express.Request, res: express.Response) {
|
||||
static store(req: express.Request, res: express.Response) {
|
||||
// verify the icon
|
||||
let icon: IconInterface|null = IconService.getIcon(req.body.icon)
|
||||
if (icon === null) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
errors: [
|
||||
{code: 'invalid-icon', message: 'Invalid font awesome icon code'}
|
||||
]
|
||||
})
|
||||
}
|
||||
req.body.icon = icon
|
||||
Tag.create(req.body).then(data => {
|
||||
res.json({
|
||||
success: true,
|
||||
|
@ -22,30 +34,35 @@ export default class AdminTagController {
|
|||
})
|
||||
}
|
||||
|
||||
static updateTag(req: express.Request, res: express.Response) {
|
||||
static update(req: express.Request, res: express.Response) {
|
||||
let icon: IconInterface|null = IconService.getIcon(req.body.icon)
|
||||
if (icon === null) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
errors: [
|
||||
{code: 'invalid-icon', message: 'Invalid font awesome icon code'}
|
||||
]
|
||||
})
|
||||
}
|
||||
req.body.icon = icon
|
||||
Tag.updateOne({ _id: req.params.id }, req.body).then(data => {
|
||||
res.json({
|
||||
success: true,
|
||||
data
|
||||
})
|
||||
}).catch(err => {
|
||||
let errors
|
||||
if (err.errors !== undefined) {
|
||||
errors = err.errors
|
||||
} else {
|
||||
errors = err
|
||||
}
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
errors
|
||||
errors: err.errors !== undefined ? err.errors : err
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
static destroyTag(req: express.Request, res: express.Response) {
|
||||
static destroy(req: express.Request, res: express.Response) {
|
||||
Tag.deleteOne({ _id: req.params.id }).then(data => {
|
||||
res.json({
|
||||
success: true,
|
||||
let isSuccess = data.deletedCount !== undefined && data.deletedCount > 0
|
||||
res.status(isSuccess ? 200 : 400).json({
|
||||
success: isSuccess,
|
||||
data
|
||||
})
|
||||
}).catch(err => {
|
||||
|
|
|
@ -3,45 +3,65 @@ import * as express from 'express'
|
|||
import nodemailer from 'nodemailer'
|
||||
import Mustache from 'mustache'
|
||||
import fs from 'fs'
|
||||
import { IconService, IconInterface } from '../IconService'
|
||||
import EmailService from '../EmailService'
|
||||
|
||||
export default class DefaultController {
|
||||
static home(req: express.Request, res: express.Response) {
|
||||
// Organization.create({
|
||||
// admin_name: "hello",
|
||||
// email: 'spamfree@matthieubessat.fr',
|
||||
// token: 'dqsdsqdsq',
|
||||
// validationState: "ndsqqdsd"
|
||||
// }).then(data => {
|
||||
// console.log(data)
|
||||
// res.json({
|
||||
// success: true
|
||||
// })
|
||||
// }).catch(err => {
|
||||
// res.json({
|
||||
// success: false,
|
||||
// errors: err.errors
|
||||
// })
|
||||
// })
|
||||
static success(req: express.Request, res: express.Response) {
|
||||
res.json({
|
||||
success: true
|
||||
})
|
||||
}
|
||||
|
||||
static viewIcon(req: express.Request, res: express.Response) {
|
||||
// let components: string[] = req.params.id.split('_')
|
||||
// if (components.length < 2) {
|
||||
// return res
|
||||
// .status(400)
|
||||
// .json({ success: false, errors: [{ code: 'invalid-input', message: 'Invalid Input icon' }] })
|
||||
// }
|
||||
// components = [components[0].replace(' ', ''), components[1].replace(' ', '')]
|
||||
// let iconSet: any = {}
|
||||
// console.log(components[0], components[1])
|
||||
// if (components[0] === "fas") {
|
||||
// iconSet = faSolid
|
||||
// }
|
||||
// if (components[0] === "fab") {
|
||||
// iconSet = faBrands
|
||||
// }
|
||||
// if (components[0] === "far") {
|
||||
// iconSet = faRegular
|
||||
// }
|
||||
// let iconName: string = snakeToCamel(components[1])
|
||||
// let iconVal: IconDefinition|undefined = iconSet[iconName]
|
||||
let icon: IconInterface|null = IconService.getIcon(req.params.id)
|
||||
if (icon === null) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ success: false, errors: [{ code: 'invalid-icon', message: 'The icon is invalid' }] })
|
||||
}
|
||||
res.json({ success: true, data: icon })
|
||||
// res.setHeader('Content-Type', 'text/html')
|
||||
// return res.send(Mustache.render(`
|
||||
// <svg
|
||||
// style="width: {{width}}px; height: {{height}}px;"
|
||||
// aria-hidden="true"
|
||||
// focusable="false"
|
||||
// data-prefix="fas"
|
||||
// data-icon="camera"
|
||||
// class="svg-inline--fa fa-camera fa-w-16"
|
||||
// role="img"
|
||||
// xmlns="http://www.w3.org/2000/svg"
|
||||
// viewBox="0 0 {{ width }} {{ height }}">
|
||||
// <path fill="currentColor" d="{{ path }}"></path>
|
||||
// </svg>`, {...icon}))
|
||||
}
|
||||
|
||||
static async sendEmail(req: express.Request, res: express.Response) {
|
||||
// create reusable transporter object using the default SMTP transport
|
||||
let transporter = nodemailer.createTransport({
|
||||
host: "node02.cluster.stantabcorp.net",
|
||||
port: 587,
|
||||
secure: false,
|
||||
auth: {
|
||||
user: "mail@matthieubessat.fr",
|
||||
pass: "",
|
||||
},
|
||||
});
|
||||
|
||||
transporter.sendMail({
|
||||
from: '"Matthieu Bessat" <mail@matthieubessat.fr>',
|
||||
to: "matthieu.bessat.27@gmail.com",
|
||||
EmailService.getTransporter().sendMail({
|
||||
from: '"Some Sender" <noreply@somedomain.com>',
|
||||
to: "spamfree@matthieubessat.fr",
|
||||
subject: "Hello ✔",
|
||||
text: "Hello world? Comment va tu Earum facilis libero excepturi sunt fuga eveniet autem. Illo odit quae aperiam et praesentium. Error dignissimos atque omnis. Ea iste in doloribus praesentium corrupti. Ut consequatur eius eveniet quia aut. Nam a rerum quis. Repudiandae sit nobis esse. Eaque ipsum qui enim. Expedita laudantium officia omnis maxime. Odio exercitationem recusandae quis consequatur voluptatum.",
|
||||
html: "<p><b>Hello world?</b> Comment va tu Earum facilis libero excepturi sunt fuga eveniet autem. Illo odit quae aperiam et praesentium. Error dignissimos atque omnis. Ea iste in doloribus praesentium corrupti. Ut consequatur eius eveniet quia aut. Nam a rerum quis. Repudiandae sit nobis esse. Eaque ipsum qui enim. Expedita laudantium officia omnis maxime. Odio exercitationem recusandae quis consequatur voluptatum.</p>",
|
||||
|
@ -55,9 +75,9 @@ export default class DefaultController {
|
|||
return res.json({ success: true })
|
||||
}
|
||||
|
||||
static async publicOrganization(req: express.Request, res: express.Response) {
|
||||
res.setHeader('Content-Type', 'text/html')
|
||||
let path: string = __dirname + '/../../templates/organization.html'
|
||||
return res.send(Mustache.render(fs.readFileSync(path).toString(), {}))
|
||||
}
|
||||
// static async publicOrganization(req: express.Request, res: express.Response) {
|
||||
// res.setHeader('Content-Type', 'text/html')
|
||||
// let path: string = __dirname + '/../../templates/organization.html'
|
||||
// return res.send(Mustache.render(fs.readFileSync(path).toString(), {}))
|
||||
// }
|
||||
}
|
21
src/controllers/DelegateController.ts
Normal file
21
src/controllers/DelegateController.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import Organization from '../models/Organization'
|
||||
import * as express from 'express'
|
||||
|
||||
export default class DelegateController {
|
||||
|
||||
static get(req: express.Request, res: express.Response) {
|
||||
res.json({ success: true, data: res.locals.organization })
|
||||
}
|
||||
|
||||
static update(req: express.Request, res: express.Response) {
|
||||
res.json({ success: true })
|
||||
}
|
||||
|
||||
static submit(req: express.Request, res: express.Response) {
|
||||
res.json({ success: true })
|
||||
}
|
||||
|
||||
static destroy(req: express.Request, res: express.Response) {
|
||||
res.json({ success: true })
|
||||
}
|
||||
}
|
27
src/controllers/PublicController.ts
Normal file
27
src/controllers/PublicController.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
import RedisService from '../RedisService'
|
||||
import Organization from '../models/Organization'
|
||||
import * as express from 'express'
|
||||
import nodemailer from 'nodemailer'
|
||||
import Mustache from 'mustache'
|
||||
import fs from 'fs'
|
||||
import { IconService, IconInterface } from '../IconService'
|
||||
import IORedis from 'ioredis'
|
||||
|
||||
export default class PublicController {
|
||||
|
||||
|
||||
static async home(req: express.Request, res: express.Response) {
|
||||
let client: IORedis.Redis = RedisService.getClient()
|
||||
await client.set('hello', 'world')
|
||||
res.json({
|
||||
data: await client.get('hello')
|
||||
})
|
||||
}
|
||||
|
||||
static async organization(req: express.Request, res: express.Response) {
|
||||
res.setHeader('Content-Type', 'text/html')
|
||||
let path: string = __dirname + '/../../templates/organization.html'
|
||||
return res.send(Mustache.render(fs.readFileSync(path).toString(), {}))
|
||||
}
|
||||
}
|
17
src/middlewares/AdminAuthMiddleware.ts
Normal file
17
src/middlewares/AdminAuthMiddleware.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import express from 'express'
|
||||
|
||||
export default class AdminAuthMiddleware {
|
||||
static handle(req: express.Request, res: express.Response, next: any) {
|
||||
let auth: string | undefined = req.get('Authorization')
|
||||
if (auth === undefined || auth.replace('Bearer ', '') !== process.env.ADMIN_TOKEN) {
|
||||
res
|
||||
.status(400)
|
||||
.json({
|
||||
success: false,
|
||||
errors: { code: 'invalid-auth', message: 'Invalid admin Authorization header' }
|
||||
})
|
||||
return
|
||||
}
|
||||
next()
|
||||
}
|
||||
}
|
23
src/middlewares/DelegateAuthMiddleware.ts
Normal file
23
src/middlewares/DelegateAuthMiddleware.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import express from 'express'
|
||||
import Organization from '../models/Organization'
|
||||
|
||||
export default class DelegateAuthMiddleware {
|
||||
static async handle(req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
let token: string | undefined = req.get('Authorization')
|
||||
// fetch the token
|
||||
if (token !== undefined) {
|
||||
let data = await Organization.findOne({ token: token.replace('Bearer ', '') })
|
||||
if (data !== null) {
|
||||
res.locals.organization = data
|
||||
next()
|
||||
return
|
||||
}
|
||||
}
|
||||
res
|
||||
.status(400)
|
||||
.json({
|
||||
success: false,
|
||||
errors: { code: 'invalid-auth', message: 'Invalid admin Authorization header' }
|
||||
})
|
||||
}
|
||||
}
|
|
@ -17,7 +17,6 @@ class AllowedString extends mongoose.SchemaType {
|
|||
}
|
||||
|
||||
cast(value: any) {
|
||||
console.log(value + ' is being validated')
|
||||
if (this.allowedValues.indexOf(value) === -1) {
|
||||
let validationStr: string = 'AllowedString: ' + value + ' must be one of which: [' + this.allowedValues.join(', ') + ']'
|
||||
console.log(validationStr)
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
import mongoose, { Schema } from 'mongoose'
|
||||
|
||||
const Icon = new Schema({
|
||||
id: { type: String, required: true },
|
||||
width: { type: Number, required: true },
|
||||
height: { type: Number, required: true },
|
||||
path: { type: String, required: true }
|
||||
})
|
||||
|
||||
const _Tag = new Schema({
|
||||
name: { type: String, required: true },
|
||||
icon: { type: String, required: true },
|
||||
icon: { type: Icon, required: true },
|
||||
description: { type: String }
|
||||
})
|
||||
|
||||
|
|
1
static/fa_icons
Symbolic link
1
static/fa_icons
Symbolic link
|
@ -0,0 +1 @@
|
|||
/home/mbess/font_awesome_icons/
|
0
templates/about.html
Normal file
0
templates/about.html
Normal file
0
templates/home.html
Normal file
0
templates/home.html
Normal file
37
templates/legals.html
Normal file
37
templates/legals.html
Normal file
|
@ -0,0 +1,37 @@
|
|||
<h1>Informations légalesw</h1>
|
||||
|
||||
<h3>Siège social</h3>
|
||||
|
||||
<p>
|
||||
Espace Condorcet Centre Social<br>
|
||||
12 rue Jean Moulin,<br>
|
||||
27600 GAILLON
|
||||
</p>
|
||||
|
||||
<h3>Contact</h3>
|
||||
|
||||
<p>
|
||||
Téléphone : 02 32 77 50 80<br>
|
||||
Fax : 02 32 77 50 99
|
||||
</p>
|
||||
|
||||
<h3>Représentant légal</h3>
|
||||
|
||||
<p>Liliane COQUET</p>
|
||||
|
||||
|
||||
<h3>Immatriculation</h3>
|
||||
|
||||
<p>
|
||||
Numéro SIREN : 338 248 206 000 25<br>
|
||||
|
||||
Code APE 88 99 B
|
||||
</p>
|
||||
|
||||
<h3>Hébergement</h3>
|
||||
|
||||
<p>
|
||||
Scaleway<br>
|
||||
|
||||
ONLINE SAS BP 438 75366 PARIS CEDEX 08 FRANCE
|
||||
</p>
|
0
templates/organization.html
Normal file
0
templates/organization.html
Normal file
132
yarn.lock
132
yarn.lock
|
@ -2,6 +2,39 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@fortawesome/fontawesome-common-types@^0.2.29":
|
||||
version "0.2.29"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.29.tgz#e1a456b643237462d390304cab6975ff3fd68397"
|
||||
integrity sha512-cY+QfDTbZ7XVxzx7jxbC98Oxr/zc7R2QpTLqTxqlfyXDrAJjzi/xUIqAUsygELB62JIrbsWxtSRhayKFkGI7MA==
|
||||
|
||||
"@fortawesome/fontawesome-svg-core@^1.2.29":
|
||||
version "1.2.29"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.29.tgz#34ef32824664534f9e4ef37982ebf286b899a189"
|
||||
integrity sha512-xmPmP2t8qrdo8RyKihTkGb09RnZoc+7HFBCnr0/6ZhStdGDSLeEd7ajV181+2W29NWIFfylO13rU+s3fpy3cnA==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.29"
|
||||
|
||||
"@fortawesome/free-brands-svg-icons@^5.13.1":
|
||||
version "5.13.1"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.13.1.tgz#fef07a4b957dc1708f2191a94cdfcd6901c35383"
|
||||
integrity sha512-dKwF+NpIV2LVCNBA7hibH53k+ChF4Wu59P2z35gu3zwRBZpmpLVhS9k1/RiSqUqkyXUQvA2rSv48GY6wp5axZQ==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.29"
|
||||
|
||||
"@fortawesome/free-regular-svg-icons@^5.13.1":
|
||||
version "5.13.1"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.13.1.tgz#02ac0c2fd52948d2139eca3ca42b267f17e3d725"
|
||||
integrity sha512-sSeaqqmv2ovA5LKcrbh3VnEDZHVhaxijWKm4R0AdT0eG21pgxNsJbStD8lW9z6bgSuWXRNHhbhOmARuRCLS8tw==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.29"
|
||||
|
||||
"@fortawesome/free-solid-svg-icons@^5.13.1":
|
||||
version "5.13.1"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.13.1.tgz#010a846b718a0f110b3cd137d072639b4e8bd41a"
|
||||
integrity sha512-LQH/0L1p4+rqtoSHa9qFYR84hpuRZKqaQ41cfBQx8b68p21zoWSekTAeA54I/2x9VlCHDLFlG74Nmdg4iTPQOg==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.29"
|
||||
|
||||
"@sindresorhus/is@^0.14.0":
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
|
||||
|
@ -41,6 +74,13 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/cors@^2.8.6":
|
||||
version "2.8.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.6.tgz#cfaab33c49c15b1ded32f235111ce9123009bd02"
|
||||
integrity sha512-invOmosX0DqbpA+cE2yoHGUlF/blyf7nB0OGYBBiH27crcVm5NmFaZkLP4Ta1hGaesckCi5lVLlydNJCxkTOSg==
|
||||
dependencies:
|
||||
"@types/express" "*"
|
||||
|
||||
"@types/express-serve-static-core@*":
|
||||
version "4.17.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.8.tgz#b8f7b714138536742da222839892e203df569d1c"
|
||||
|
@ -60,6 +100,13 @@
|
|||
"@types/qs" "*"
|
||||
"@types/serve-static" "*"
|
||||
|
||||
"@types/ioredis@^4.17.0":
|
||||
version "4.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.17.0.tgz#25fea62388f546958d53e31bbb6284b60c793e60"
|
||||
integrity sha512-2wmT+lB9JAHSYlBrmJGeYDQ4cGlIgxmaC3Bv85LJws/G/OkoFoxPezhMqtTp0JMCgsMadIoI9c43QvRz8WKLSw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/mime@*":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.2.tgz#857a118d8634c84bba7ae14088e4508490cd5da5"
|
||||
|
@ -370,6 +417,11 @@ clone-response@^1.0.2:
|
|||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
cluster-key-slot@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
|
||||
integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==
|
||||
|
||||
color-convert@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
|
||||
|
@ -453,11 +505,26 @@ core-util-is@~1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
cors@^2.8.5:
|
||||
version "2.8.5"
|
||||
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
|
||||
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
|
||||
dependencies:
|
||||
object-assign "^4"
|
||||
vary "^1"
|
||||
|
||||
crypto-random-string@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
|
||||
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
|
||||
|
||||
crypto-random-string@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-3.2.0.tgz#d513ef0c2ac6ff7cad5769de585d9bf2ad5a2b4d"
|
||||
integrity sha512-8vPu5bsKaq2uKRy3OL7h1Oo7RayAWB8sYexLKAqvCXVib8SxgbmoF1IN4QMKjBv8uI8mp5gPPMbiRah25GMrVQ==
|
||||
dependencies:
|
||||
type-fest "^0.8.1"
|
||||
|
||||
debug@2.6.9, debug@^2.2.0:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
|
@ -479,6 +546,13 @@ debug@^3.1.0, debug@^3.2.6:
|
|||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
|
||||
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
decompress-response@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
|
||||
|
@ -501,7 +575,7 @@ delayed-stream@~1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
||||
|
||||
denque@^1.4.1:
|
||||
denque@^1.1.0, denque@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf"
|
||||
integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==
|
||||
|
@ -822,6 +896,21 @@ ini@^1.3.5, ini@~1.3.0:
|
|||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
||||
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
||||
|
||||
ioredis@^4.17.3:
|
||||
version "4.17.3"
|
||||
resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.17.3.tgz#9938c60e4ca685f75326337177bdc2e73ae9c9dc"
|
||||
integrity sha512-iRvq4BOYzNFkDnSyhx7cmJNOi1x/HWYe+A4VXHBu4qpwJaGT1Mp+D2bVGJntH9K/Z/GeOM/Nprb8gB3bmitz1Q==
|
||||
dependencies:
|
||||
cluster-key-slot "^1.1.0"
|
||||
debug "^4.1.1"
|
||||
denque "^1.1.0"
|
||||
lodash.defaults "^4.2.0"
|
||||
lodash.flatten "^4.4.0"
|
||||
redis-commands "1.5.0"
|
||||
redis-errors "^1.2.0"
|
||||
redis-parser "^3.0.0"
|
||||
standard-as-callback "^2.0.1"
|
||||
|
||||
ipaddr.js@1.9.1:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
|
||||
|
@ -947,6 +1036,16 @@ latest-version@^5.0.0:
|
|||
dependencies:
|
||||
package-json "^6.3.0"
|
||||
|
||||
lodash.defaults@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
|
||||
integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
|
||||
|
||||
lodash.flatten@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
|
||||
integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
|
||||
|
||||
lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
|
||||
|
@ -1128,6 +1227,11 @@ mustache@^4.0.1:
|
|||
resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.0.1.tgz#d99beb031701ad433338e7ea65e0489416c854a2"
|
||||
integrity sha512-yL5VE97+OXn4+Er3THSmTdCFCtx5hHWzrolvH+JObZnUYwuaG7XV+Ch4fR2cIrcYI0tFHxS7iyFYl14bW8y2sA==
|
||||
|
||||
nanoid@^3.1.10:
|
||||
version "3.1.10"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.10.tgz#69a8a52b77892de0d11cede96bc9762852145bc4"
|
||||
integrity sha512-iZFMXKeXWkxzlfmMfM91gw7YhN2sdJtixY+eZh9V6QWJWTOiurhpKhBMgr82pfzgSqglQgqYSCowEYsz8D++6w==
|
||||
|
||||
negotiator@0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
|
||||
|
@ -1171,7 +1275,7 @@ normalize-url@^4.1.0:
|
|||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
|
||||
integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
|
||||
|
||||
object-assign@^4.1.1:
|
||||
object-assign@^4, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
@ -1333,6 +1437,23 @@ readdirp@~3.4.0:
|
|||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
redis-commands@1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.5.0.tgz#80d2e20698fe688f227127ff9e5164a7dd17e785"
|
||||
integrity sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg==
|
||||
|
||||
redis-errors@^1.0.0, redis-errors@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad"
|
||||
integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=
|
||||
|
||||
redis-parser@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4"
|
||||
integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=
|
||||
dependencies:
|
||||
redis-errors "^1.0.0"
|
||||
|
||||
regexp-clone@1.0.0, regexp-clone@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63"
|
||||
|
@ -1482,6 +1603,11 @@ sparse-bitfield@^3.0.3:
|
|||
dependencies:
|
||||
memory-pager "^1.0.2"
|
||||
|
||||
standard-as-callback@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.0.1.tgz#ed8bb25648e15831759b6023bdb87e6b60b38126"
|
||||
integrity sha512-NQOxSeB8gOI5WjSaxjBgog2QFw55FV8TkS6Y07BiB3VJ8xNTvUYm0wl0s8ObgQ5NhdpnNfigMIKjgPESzgr4tg==
|
||||
|
||||
"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
|
||||
|
@ -1706,7 +1832,7 @@ uuid@3.3.2:
|
|||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
||||
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
|
||||
|
||||
vary@~1.1.2:
|
||||
vary@^1, vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||
|
|
Loading…
Reference in a new issue