From 21b7def9e4cebd2ae4b48e9d0bd0a8f651f84a40 Mon Sep 17 00:00:00 2001 From: Alice Gaudon Date: Sun, 26 Jul 2020 11:37:01 +0200 Subject: [PATCH] Fix some model refactor usages --- src/Logger.ts | 5 +++-- src/Utils.ts | 10 ++++++++++ src/auth/AuthGuard.ts | 6 +++--- src/auth/magic_link/MagicLinkAuthController.ts | 5 +++-- src/auth/magic_link/MagicLinkController.ts | 3 ++- src/auth/models/MagicLink.ts | 7 +++---- src/auth/models/User.ts | 4 ++-- src/auth/models/UserApprovedComponent.ts | 3 +++ src/auth/models/UserEmail.ts | 6 ++---- src/db/Model.ts | 6 ++++-- src/db/ModelComponent.ts | 17 ++++++++++++++++- src/db/MysqlConnectionManager.ts | 2 ++ 12 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/Logger.ts b/src/Logger.ts index 325be1b..fae6c03 100644 --- a/src/Logger.ts +++ b/src/Logger.ts @@ -80,7 +80,8 @@ export default class Logger { const logID = Buffer.alloc(16); uuid({}, logID); - if (shouldSaveToDB) output += `${logID} - `; + let strLogID = bufferToUUID(logID); + if (shouldSaveToDB) output += `${strLogID} - `; output += computedMsg.replace(/\n/g, '\n' + ' '.repeat(pad)); @@ -116,7 +117,7 @@ export default class Logger { } }); } - return bufferToUUID(logID); + return strLogID; } return null; } diff --git a/src/Utils.ts b/src/Utils.ts index e91a5b8..9316a5d 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -47,3 +47,13 @@ export function bufferToUUID(buffer: Buffer): string { } return out; } + +export function getMethods(obj: T): (string)[] { + let properties = new Set() + let currentObj = obj + do { + Object.getOwnPropertyNames(currentObj).map(item => properties.add(item)) + } while ((currentObj = Object.getPrototypeOf(currentObj))) + // @ts-ignore + return [...properties.keys()].filter(item => typeof obj[item] === 'function') +} diff --git a/src/auth/AuthGuard.ts b/src/auth/AuthGuard.ts index 5cd82b9..d213089 100644 --- a/src/auth/AuthGuard.ts +++ b/src/auth/AuthGuard.ts @@ -7,6 +7,7 @@ import {PENDING_ACCOUNT_REVIEW_MAIL_TEMPLATE} from "../Mails"; import Mail from "../Mail"; import Controller from "../Controller"; import config from "config"; +import ModelFactory from "../db/ModelFactory"; export default abstract class AuthGuard

> { public abstract async getProofForSession(session: Express.Session): Promise

; @@ -31,12 +32,11 @@ export default abstract class AuthGuard

> { const callbacks: RegisterCallback[] = []; await MysqlConnectionManager.wrapTransaction(async connection => { - user = new User({}); - await user.save(connection, c => callbacks.push(c)); - + user = ModelFactory.get(User).make({}); if (onRegister) { (await onRegister(connection, user)).forEach(c => callbacks.push(c)); } + await user.save(connection, c => callbacks.push(c)); }); for (const callback of callbacks) { diff --git a/src/auth/magic_link/MagicLinkAuthController.ts b/src/auth/magic_link/MagicLinkAuthController.ts index f6a6714..b749afd 100644 --- a/src/auth/magic_link/MagicLinkAuthController.ts +++ b/src/auth/magic_link/MagicLinkAuthController.ts @@ -9,6 +9,7 @@ import {AuthError, PendingApprovalAuthError, RegisterCallback} from "../AuthGuar import geoip from "geoip-lite"; import AuthController from "../AuthController"; import NunjucksComponent from "../../components/NunjucksComponent"; +import ModelFactory from "../../db/ModelFactory"; export default abstract class MagicLinkAuthController extends AuthController { @@ -22,7 +23,7 @@ export default abstract class MagicLinkAuthController extends AuthController { await req.authGuard.authenticateOrRegister(req.session!, magicLink, undefined, async (connection, user) => { const callbacks: RegisterCallback[] = []; - const userEmail = new UserEmail({ + const userEmail = ModelFactory.get(UserEmail).make({ user_id: user.id, email: magicLink.getEmail(), }); @@ -83,7 +84,7 @@ export default abstract class MagicLinkAuthController extends AuthController { if (!userEmail) { isRegistration = true; - userEmail = new UserEmail({ + userEmail = ModelFactory.get(UserEmail).make({ email: email, main: true, }); diff --git a/src/auth/magic_link/MagicLinkController.ts b/src/auth/magic_link/MagicLinkController.ts index a516db8..879be42 100644 --- a/src/auth/magic_link/MagicLinkController.ts +++ b/src/auth/magic_link/MagicLinkController.ts @@ -6,6 +6,7 @@ import Throttler from "../../Throttler"; import Mail, {MailTemplate} from "../../Mail"; import MagicLink from "../models/MagicLink"; import config from "config"; +import ModelFactory from "../../db/ModelFactory"; export default abstract class MagicLinkController extends Controller { public static async sendMagicLink(sessionID: string, actionType: string, original_url: string, email: string, mailTemplate: MailTemplate, data: object): Promise { @@ -13,7 +14,7 @@ export default abstract class MagicLinkController extends Controller { Throttler.throttle('magic_link', 1, MagicLink.validityPeriod(), email, 0, 0); const link = await MagicLink.bySessionID(sessionID, actionType) || - new MagicLink({ + ModelFactory.get(MagicLink).make({ session_id: sessionID, action_type: actionType, original_url: original_url, diff --git a/src/auth/models/MagicLink.ts b/src/auth/models/MagicLink.ts index 0d3d422..eceb51e 100644 --- a/src/auth/models/MagicLink.ts +++ b/src/auth/models/MagicLink.ts @@ -6,6 +6,7 @@ import User from "./User"; import argon2 from "argon2"; import {WhereTest} from "../../db/ModelQuery"; import UserEmail from "./UserEmail"; +import ModelFactory from "../../db/ModelFactory"; export default class MagicLink extends Model implements AuthProof { public static async bySessionID(sessionID: string, actionType?: string | string[]): Promise { @@ -33,10 +34,8 @@ export default class MagicLink extends Model implements AuthProof { private generated_at?: Date = undefined; private authorized: boolean = false; - constructor(data: any) { - super(data); - if (this.action_type === undefined) throw new Error('Action type must always be defined.'); - if (this.original_url === undefined) throw new Error('Origin url must always be defined.'); + constructor(factory: ModelFactory) { + super(factory); } protected init(): void { diff --git a/src/auth/models/User.ts b/src/auth/models/User.ts index ec0c17a..33415fc 100644 --- a/src/auth/models/User.ts +++ b/src/auth/models/User.ts @@ -25,8 +25,8 @@ export default class User extends Model { public readonly mainEmail = this.emails.cloneReduceToOne().constraint(q => q.where('id', this.main_email_id)); - public constructor(data: any) { - super(data); + public constructor(factory: ModelFactory) { + super(factory); } protected init(): void { diff --git a/src/auth/models/UserApprovedComponent.ts b/src/auth/models/UserApprovedComponent.ts index ab65006..5060fcd 100644 --- a/src/auth/models/UserApprovedComponent.ts +++ b/src/auth/models/UserApprovedComponent.ts @@ -3,4 +3,7 @@ import User from "./User"; export default class UserApprovedComponent extends ModelComponent { public approved: boolean = false; + + protected init(): void { + } } \ No newline at end of file diff --git a/src/auth/models/UserEmail.ts b/src/auth/models/UserEmail.ts index ced7eb2..c42d671 100644 --- a/src/auth/models/UserEmail.ts +++ b/src/auth/models/UserEmail.ts @@ -1,7 +1,5 @@ import User from "./User"; -import {Connection} from "mysql"; import Model, {EMAIL_REGEX} from "../../db/Model"; -import {query} from "../../db/MysqlConnectionManager"; import {OneModelRelation} from "../../db/ModelRelation"; import ModelFactory from "../../db/ModelFactory"; @@ -16,8 +14,8 @@ export default class UserEmail extends Model { foreignKey: 'id' }); - constructor(data: any) { - super(data); + constructor(factory: ModelFactory) { + super(factory); } protected init(): void { diff --git a/src/db/Model.ts b/src/db/Model.ts index 23bc7b6..578705e 100644 --- a/src/db/Model.ts +++ b/src/db/Model.ts @@ -50,7 +50,7 @@ export default abstract class Model { } public addComponent(modelComponent: ModelComponent): void { - modelComponent.init(); + modelComponent.applyToModel(); this._components.push(modelComponent); } @@ -179,7 +179,9 @@ export default abstract class Model { private get _properties(): string[] { return Object.getOwnPropertyNames(this).filter(p => { - return !p.startsWith('_') && !(this[p] instanceof ModelRelation); + return !p.startsWith('_') && + typeof this[p] !== 'function' && + !(this[p] instanceof ModelRelation); }); } } diff --git a/src/db/ModelComponent.ts b/src/db/ModelComponent.ts index 5c4b6c9..967e465 100644 --- a/src/db/ModelComponent.ts +++ b/src/db/ModelComponent.ts @@ -1,5 +1,6 @@ import Model from "./Model"; import Validator from "./Validator"; +import {getMethods} from "../Utils"; export default abstract class ModelComponent { protected readonly _model: T; @@ -11,14 +12,28 @@ export default abstract class ModelComponent { this._model = model; } - public init(): void { + public applyToModel(): void { + this.init(); + for (const property of this._properties) { if (!property.startsWith('_')) { (this._model as Model)[property] = this[property]; } } + + for (const method of getMethods(this)) { + // @ts-ignore + if (!method.startsWith('_') && + ['init', 'setValidation'].indexOf(method) < 0 && + this._model[method] === undefined) { + // @ts-ignore + this._model[method] = this[method]; + } + } } + protected abstract init(): void; + protected setValidation(propertyName: keyof this): Validator { const validator = new Validator(); this._validators[propertyName as string] = validator; diff --git a/src/db/MysqlConnectionManager.ts b/src/db/MysqlConnectionManager.ts index 6594e53..0a59818 100644 --- a/src/db/MysqlConnectionManager.ts +++ b/src/db/MysqlConnectionManager.ts @@ -192,7 +192,9 @@ export default class MysqlConnectionManager { ]); }); } + } + for (const migration of this.migrations) { migration.registerModels(); } }