Fix some model refactor usages

This commit is contained in:
Alice Gaudon 2020-07-26 11:37:01 +02:00
parent a79e2292d7
commit 21b7def9e4
12 changed files with 53 additions and 21 deletions

View File

@ -80,7 +80,8 @@ export default class Logger {
const logID = Buffer.alloc(16); const logID = Buffer.alloc(16);
uuid({}, logID); uuid({}, logID);
if (shouldSaveToDB) output += `${logID} - `; let strLogID = bufferToUUID(logID);
if (shouldSaveToDB) output += `${strLogID} - `;
output += computedMsg.replace(/\n/g, '\n' + ' '.repeat(pad)); output += computedMsg.replace(/\n/g, '\n' + ' '.repeat(pad));
@ -116,7 +117,7 @@ export default class Logger {
} }
}); });
} }
return bufferToUUID(logID); return strLogID;
} }
return null; return null;
} }

View File

@ -47,3 +47,13 @@ export function bufferToUUID(buffer: Buffer): string {
} }
return out; return out;
} }
export function getMethods<T>(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')
}

View File

@ -7,6 +7,7 @@ import {PENDING_ACCOUNT_REVIEW_MAIL_TEMPLATE} from "../Mails";
import Mail from "../Mail"; import Mail from "../Mail";
import Controller from "../Controller"; import Controller from "../Controller";
import config from "config"; import config from "config";
import ModelFactory from "../db/ModelFactory";
export default abstract class AuthGuard<P extends AuthProof<User>> { export default abstract class AuthGuard<P extends AuthProof<User>> {
public abstract async getProofForSession(session: Express.Session): Promise<P | null>; public abstract async getProofForSession(session: Express.Session): Promise<P | null>;
@ -31,12 +32,11 @@ export default abstract class AuthGuard<P extends AuthProof<User>> {
const callbacks: RegisterCallback[] = []; const callbacks: RegisterCallback[] = [];
await MysqlConnectionManager.wrapTransaction(async connection => { await MysqlConnectionManager.wrapTransaction(async connection => {
user = new User({}); user = ModelFactory.get(User).make({});
await user.save(connection, c => callbacks.push(c));
if (onRegister) { if (onRegister) {
(await onRegister(connection, user)).forEach(c => callbacks.push(c)); (await onRegister(connection, user)).forEach(c => callbacks.push(c));
} }
await user.save(connection, c => callbacks.push(c));
}); });
for (const callback of callbacks) { for (const callback of callbacks) {

View File

@ -9,6 +9,7 @@ import {AuthError, PendingApprovalAuthError, RegisterCallback} from "../AuthGuar
import geoip from "geoip-lite"; import geoip from "geoip-lite";
import AuthController from "../AuthController"; import AuthController from "../AuthController";
import NunjucksComponent from "../../components/NunjucksComponent"; import NunjucksComponent from "../../components/NunjucksComponent";
import ModelFactory from "../../db/ModelFactory";
export default abstract class MagicLinkAuthController extends AuthController { 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) => { await req.authGuard.authenticateOrRegister(req.session!, magicLink, undefined, async (connection, user) => {
const callbacks: RegisterCallback[] = []; const callbacks: RegisterCallback[] = [];
const userEmail = new UserEmail({ const userEmail = ModelFactory.get(UserEmail).make({
user_id: user.id, user_id: user.id,
email: magicLink.getEmail(), email: magicLink.getEmail(),
}); });
@ -83,7 +84,7 @@ export default abstract class MagicLinkAuthController extends AuthController {
if (!userEmail) { if (!userEmail) {
isRegistration = true; isRegistration = true;
userEmail = new UserEmail({ userEmail = ModelFactory.get(UserEmail).make({
email: email, email: email,
main: true, main: true,
}); });

View File

@ -6,6 +6,7 @@ import Throttler from "../../Throttler";
import Mail, {MailTemplate} from "../../Mail"; import Mail, {MailTemplate} from "../../Mail";
import MagicLink from "../models/MagicLink"; import MagicLink from "../models/MagicLink";
import config from "config"; import config from "config";
import ModelFactory from "../../db/ModelFactory";
export default abstract class MagicLinkController extends Controller { 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<void> { public static async sendMagicLink(sessionID: string, actionType: string, original_url: string, email: string, mailTemplate: MailTemplate, data: object): Promise<void> {
@ -13,7 +14,7 @@ export default abstract class MagicLinkController extends Controller {
Throttler.throttle('magic_link', 1, MagicLink.validityPeriod(), email, 0, 0); Throttler.throttle('magic_link', 1, MagicLink.validityPeriod(), email, 0, 0);
const link = await MagicLink.bySessionID(sessionID, actionType) || const link = await MagicLink.bySessionID(sessionID, actionType) ||
new MagicLink({ ModelFactory.get(MagicLink).make({
session_id: sessionID, session_id: sessionID,
action_type: actionType, action_type: actionType,
original_url: original_url, original_url: original_url,

View File

@ -6,6 +6,7 @@ import User from "./User";
import argon2 from "argon2"; import argon2 from "argon2";
import {WhereTest} from "../../db/ModelQuery"; import {WhereTest} from "../../db/ModelQuery";
import UserEmail from "./UserEmail"; import UserEmail from "./UserEmail";
import ModelFactory from "../../db/ModelFactory";
export default class MagicLink extends Model implements AuthProof<User> { export default class MagicLink extends Model implements AuthProof<User> {
public static async bySessionID(sessionID: string, actionType?: string | string[]): Promise<MagicLink | null> { public static async bySessionID(sessionID: string, actionType?: string | string[]): Promise<MagicLink | null> {
@ -33,10 +34,8 @@ export default class MagicLink extends Model implements AuthProof<User> {
private generated_at?: Date = undefined; private generated_at?: Date = undefined;
private authorized: boolean = false; private authorized: boolean = false;
constructor(data: any) { constructor(factory: ModelFactory<MagicLink>) {
super(data); super(factory);
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.');
} }
protected init(): void { protected init(): void {

View File

@ -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 readonly mainEmail = this.emails.cloneReduceToOne().constraint(q => q.where('id', this.main_email_id));
public constructor(data: any) { public constructor(factory: ModelFactory<User>) {
super(data); super(factory);
} }
protected init(): void { protected init(): void {

View File

@ -3,4 +3,7 @@ import User from "./User";
export default class UserApprovedComponent extends ModelComponent<User> { export default class UserApprovedComponent extends ModelComponent<User> {
public approved: boolean = false; public approved: boolean = false;
protected init(): void {
}
} }

View File

@ -1,7 +1,5 @@
import User from "./User"; import User from "./User";
import {Connection} from "mysql";
import Model, {EMAIL_REGEX} from "../../db/Model"; import Model, {EMAIL_REGEX} from "../../db/Model";
import {query} from "../../db/MysqlConnectionManager";
import {OneModelRelation} from "../../db/ModelRelation"; import {OneModelRelation} from "../../db/ModelRelation";
import ModelFactory from "../../db/ModelFactory"; import ModelFactory from "../../db/ModelFactory";
@ -16,8 +14,8 @@ export default class UserEmail extends Model {
foreignKey: 'id' foreignKey: 'id'
}); });
constructor(data: any) { constructor(factory: ModelFactory<UserEmail>) {
super(data); super(factory);
} }
protected init(): void { protected init(): void {

View File

@ -50,7 +50,7 @@ export default abstract class Model {
} }
public addComponent(modelComponent: ModelComponent<this>): void { public addComponent(modelComponent: ModelComponent<this>): void {
modelComponent.init(); modelComponent.applyToModel();
this._components.push(modelComponent); this._components.push(modelComponent);
} }
@ -179,7 +179,9 @@ export default abstract class Model {
private get _properties(): string[] { private get _properties(): string[] {
return Object.getOwnPropertyNames(this).filter(p => { return Object.getOwnPropertyNames(this).filter(p => {
return !p.startsWith('_') && !(this[p] instanceof ModelRelation); return !p.startsWith('_') &&
typeof this[p] !== 'function' &&
!(this[p] instanceof ModelRelation);
}); });
} }
} }

View File

@ -1,5 +1,6 @@
import Model from "./Model"; import Model from "./Model";
import Validator from "./Validator"; import Validator from "./Validator";
import {getMethods} from "../Utils";
export default abstract class ModelComponent<T extends Model> { export default abstract class ModelComponent<T extends Model> {
protected readonly _model: T; protected readonly _model: T;
@ -11,14 +12,28 @@ export default abstract class ModelComponent<T extends Model> {
this._model = model; this._model = model;
} }
public init(): void { public applyToModel(): void {
this.init();
for (const property of this._properties) { for (const property of this._properties) {
if (!property.startsWith('_')) { if (!property.startsWith('_')) {
(this._model as Model)[property] = this[property]; (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<V>(propertyName: keyof this): Validator<V> { protected setValidation<V>(propertyName: keyof this): Validator<V> {
const validator = new Validator<V>(); const validator = new Validator<V>();
this._validators[propertyName as string] = validator; this._validators[propertyName as string] = validator;

View File

@ -192,7 +192,9 @@ export default class MysqlConnectionManager {
]); ]);
}); });
} }
}
for (const migration of this.migrations) {
migration.registerModels(); migration.registerModels();
} }
} }