diff --git a/config/default.ts b/config/default.ts index bd9ad07..95072f6 100644 --- a/config/default.ts +++ b/config/default.ts @@ -1,4 +1,8 @@ export default { + app: { + name: 'Example App', + contact_email: 'noreply@example.net' + }, log_level: "DEV", db_log_level: "ERROR", public_url: "http://localhost:4899", diff --git a/package.json b/package.json index 72ccdc6..13357ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wms-core", - "version": "0.10.2", + "version": "0.10.16", "description": "Node web framework", "repository": "git@gitlab.com:ArisuOngaku/wms-core.git", "author": "Alice Gaudon ", diff --git a/src/Application.ts b/src/Application.ts index cf1f2bc..2db1f0a 100644 --- a/src/Application.ts +++ b/src/Application.ts @@ -11,6 +11,7 @@ import {Type} from "./Utils"; import LogRequestsComponent from "./components/LogRequestsComponent"; import {ValidationBag} from "./db/Validator"; import TemplateError = lib.TemplateError; +import config from "config"; export default abstract class Application { private readonly version: string; @@ -42,7 +43,7 @@ export default abstract class Application { } public async start(): Promise { - Logger.info(`${this.constructor.name} v${this.version} - hi`); + Logger.info(`${config.get('app.name')} v${this.version} - hi`); process.once('SIGINT', () => { this.stop().catch(console.error); }); diff --git a/src/auth/magic_link/MagicLinkAuthController.ts b/src/auth/magic_link/MagicLinkAuthController.ts index 8dfcda4..a75c38d 100644 --- a/src/auth/magic_link/MagicLinkAuthController.ts +++ b/src/auth/magic_link/MagicLinkAuthController.ts @@ -11,13 +11,33 @@ import geoip from "geoip-lite"; export default abstract class MagicLinkAuthController extends Controller { - public static async checkAndAuth(req: Request, magicLink: MagicLink): Promise { + public static async checkAndAuth(req: Request, res: Response, magicLink: MagicLink): Promise { if (magicLink.getSessionID() !== req.sessionID!) throw new BadOwnerMagicLink(); if (!await magicLink.isAuthorized()) throw new UnauthorizedMagicLink(); if (!await magicLink.isValid()) throw new InvalidMagicLink(); // Auth - await req.authGuard.authenticateOrRegister(req.session!, magicLink); + try { + await req.authGuard.authenticateOrRegister(req.session!, magicLink); + } catch (e) { + if (e instanceof PendingApprovalAuthError) { + res.format({ + json: () => { + res.json({ + 'status': 'warning', + 'message': `Your account is pending review. You'll receive an email once you're approved.` + }); + }, + html: () => { + req.flash('warning', `Your account is pending review. You'll receive an email once you're approved.`); + res.redirectBack('/'); + } + }); + return; + } else { + throw e; + } + } } protected readonly loginMagicLinkActionType: string = 'Login'; @@ -114,27 +134,7 @@ export default abstract class MagicLinkAuthController extends Controller { return; } - try { - await MagicLinkAuthController.checkAndAuth(req, magicLink); - } catch (e) { - if (e instanceof PendingApprovalAuthError) { - res.format({ - json: () => { - res.json({ - 'status': 'warning', - 'message': `Your account is pending review. You'll receive an email once you're approved.` - }); - }, - default: () => { - req.flash('warning', `Your account is pending review. You'll receive an email once you're approved.`); - res.redirectBack('/'); - } - }); - return; - } else { - throw e; - } - } + await MagicLinkAuthController.checkAndAuth(req, res, magicLink); // Auth success const username = req.models.user?.name; diff --git a/src/auth/models/User.ts b/src/auth/models/User.ts index 19a7b87..62768b2 100644 --- a/src/auth/models/User.ts +++ b/src/auth/models/User.ts @@ -12,8 +12,8 @@ export default class User extends Model { } public name?: string; - public approved: boolean = false; - public is_admin: boolean = false; + public approved!: boolean; + public is_admin!: boolean; public created_at?: Date; public updated_at?: Date; @@ -24,6 +24,12 @@ export default class User extends Model { public readonly mainEmail = this.emails.cloneReduceToOne().constraint(q => q.where('main', true)); + constructor(data: any) { + super(data); + if (this.approved === undefined) this.approved = false; + if (this.is_admin === undefined) this.is_admin = false; + } + protected init(): void { this.addProperty('name', new Validator().acceptUndefined().between(3, 64)); if (User.isApprovalMode()) this.addProperty('approved', new Validator().defined()); diff --git a/src/components/NunjucksComponent.ts b/src/components/NunjucksComponent.ts index 0af66ce..7dda1ce 100644 --- a/src/components/NunjucksComponent.ts +++ b/src/components/NunjucksComponent.ts @@ -29,6 +29,9 @@ export default class NunjucksComponent extends ApplicationComponent { req.env = env; res.locals.url = req.url; res.locals.params = () => req.params; + + res.locals.app = config.get('app'); + next(); }); } diff --git a/src/db/Model.ts b/src/db/Model.ts index 48eb31d..ec7f3c6 100644 --- a/src/db/Model.ts +++ b/src/db/Model.ts @@ -224,7 +224,7 @@ export default abstract class Model { for (const indexField of this.getPrimaryKeyFields()) { query = query.where(indexField, this[indexField]); } - return typeof (await query.first()) !== 'undefined'; + return (await query.limit(1).execute()).results.length > 0; } public async delete(): Promise { diff --git a/src/db/ModelQuery.ts b/src/db/ModelQuery.ts index 5b5b4d5..1f3f8e5 100644 --- a/src/db/ModelQuery.ts +++ b/src/db/ModelQuery.ts @@ -190,8 +190,10 @@ export default class ModelQuery { // Eager loading execute for (const relationName of this.relations) { const relations = relationMap[relationName]; - const allModels = await relations[0].eagerLoad(relations); - await Promise.all(relations.map(r => r.populate(allModels))); + if (relations.length > 0) { + const allModels = await relations[0].eagerLoad(relations); + await Promise.all(relations.map(r => r.populate(allModels))); + } } return models; diff --git a/src/db/ModelRelation.ts b/src/db/ModelRelation.ts index dff0c31..eecb5f7 100644 --- a/src/db/ModelRelation.ts +++ b/src/db/ModelRelation.ts @@ -31,6 +31,11 @@ export default abstract class ModelRelation[]): Promise>; public abstract async populate(models: ModelQueryResult): Promise;