From ae2896fa6148cc1366573166368e157d6fa50b82 Mon Sep 17 00:00:00 2001 From: Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> Date: Sun, 22 Aug 2021 12:41:21 +0200 Subject: :construction: typeorm --- util/src/models/BaseClass.ts | 24 +++--- util/src/models/User.ts | 171 +++++++++++++++++++++++-------------------- 2 files changed, 103 insertions(+), 92 deletions(-) (limited to 'util/src/models') diff --git a/util/src/models/BaseClass.ts b/util/src/models/BaseClass.ts index 78cd329c..d4f635f6 100644 --- a/util/src/models/BaseClass.ts +++ b/util/src/models/BaseClass.ts @@ -1,22 +1,24 @@ import "reflect-metadata"; -import { BaseEntity, Column } from "typeorm"; +import { BaseEntity, BeforeInsert, BeforeUpdate, Column, PrimaryGeneratedColumn } from "typeorm"; +import { Snowflake } from "../util/Snowflake"; +import { IsString, validateOrReject } from "class-validator"; export class BaseClass extends BaseEntity { + @PrimaryGeneratedColumn() @Column() - id?: string; + @IsString() + id: string; - constructor(props?: any) { + constructor(props?: any, opts: { id?: string } = {}) { super(); - BaseClass.assign(props, this, "body."); + this.id = opts.id || Snowflake.generate(); + Object.defineProperties(this, props); } - private static assign(props: any, object: any, path?: string): any { - const expectedType = Reflect.getMetadata("design:type", object, props); - console.log(expectedType, object, props, path, typeof object); - - if (typeof object !== typeof props) throw new Error(`Property at ${path} must be`); - if (typeof object === "object") - return Object.keys(object).map((key) => BaseClass.assign(props[key], object[key], `${path}.${key}`)); + @BeforeUpdate() + @BeforeInsert() + async validate() { + await validateOrReject(this, {}); } } diff --git a/util/src/models/User.ts b/util/src/models/User.ts index 38045738..27aa63d1 100644 --- a/util/src/models/User.ts +++ b/util/src/models/User.ts @@ -2,6 +2,7 @@ import { Column, PrimaryColumn, PrimaryGeneratedColumn } from "typeorm"; import { Activity } from "./Activity"; import { BaseClass } from "./BaseClass"; import { ClientStatus, Status } from "./Status"; +import { validateOrReject, IsInt, IsEmail, IsPhoneNumber, IsBoolean, IsString, ValidateNested } from "class-validator"; export const PublicUserProjection = { username: true, @@ -16,67 +17,80 @@ export const PublicUserProjection = { }; export class User extends BaseClass { - @PrimaryGeneratedColumn() - id: string; - @Column() + @IsString() username: string; // username max length 32, min 2 (should be configurable) @Column() + @IsInt() discriminator: string; // #0001 4 digit long string from #0001 - #9999 @Column() + @IsString() avatar: string | null; // hash of the user avatar @Column() + @IsInt() accent_color: number | null; // banner color of user @Column() banner: string | null; // hash of the user banner @Column() + @IsPhoneNumber() phone: string | null; // phone number of the user @Column() + @IsBoolean() desktop: boolean; // if the user has desktop app installed @Column() + @IsBoolean() mobile: boolean; // if the user has mobile app installed @Column() + @IsBoolean() premium: boolean; // if user bought nitro @Column() premium_type: number; // nitro level @Column() + @IsBoolean() bot: boolean; // if user is bot @Column() bio: string; // short description of the user (max 190 chars -> should be configurable) @Column() + @IsBoolean() system: boolean; // shouldn't be used, the api sents this field type true, if the generated message comes from a system generated author @Column() + @IsBoolean() nsfw_allowed: boolean; // if the user is older than 18 (resp. Config) @Column() + @IsBoolean() mfa_enabled: boolean; // if multi factor authentication is enabled @Column() created_at: Date; // registration date @Column() + @IsBoolean() verified: boolean; // if the user is offically verified @Column() + @IsBoolean() disabled: boolean; // if the account is disabled @Column() + @IsBoolean() deleted: boolean; // if the user was deleted @Column() + @IsEmail() email: string | null; // email of the user @Column() @@ -86,15 +100,19 @@ export class User extends BaseClass { public_flags: bigint; @Column("simple-array") // string in simple-array must not contain commas + @IsString({ each: true }) guilds: string[]; // array of guild ids the user is part of @Column("simple-json") - user_settings: UserSettings; - - @Column("simple-json") - user_data: UserData; + @ValidateNested() // TODO: https://github.com/typestack/class-validator#validating-nested-objects + user_data: { + valid_tokens_since: Date; // all tokens with a previous issue date are invalid + hash: string; // hash of the password, salt is saved in password (bcrypt) + fingerprints: string[]; // array of fingerprints -> used to prevent multiple accounts + }; @Column("simple-json") + @ValidateNested() // TODO: https://github.com/typestack/class-validator#validating-nested-objects presence: { status: Status; activities: Activity[]; @@ -102,22 +120,76 @@ export class User extends BaseClass { }; @Column("simple-json") - relationships: Relationship[]; + @ValidateNested() // TODO: https://github.com/typestack/class-validator#validating-nested-objects + relationships: { + id: string; + nickname?: string; + type: RelationshipType; + }[]; @Column("simple-json") - connected_accounts: ConnectedAccount[]; -} - -// @ts-ignore -global.User = User; + @ValidateNested() // TODO: https://github.com/typestack/class-validator#validating-nested-objects + connected_accounts: { + access_token: string; + friend_sync: boolean; + id: string; + name: string; + revoked: boolean; + show_activity: boolean; + type: string; + verifie: boolean; + visibility: number; + }[]; -// Private user data that should never get sent to the client -export interface UserData { - valid_tokens_since: Date; // all tokens with a previous issue date are invalid - hash: string; // hash of the password, salt is saved in password (bcrypt) - fingerprints: string[]; // array of fingerprints -> used to prevent multiple accounts + @Column("simple-json") + @ValidateNested() // TODO: https://github.com/typestack/class-validator#validating-nested-objects + user_settings: { + afk_timeout: number; + allow_accessibility_detection: boolean; + animate_emoji: boolean; + animate_stickers: number; + contact_sync_enabled: boolean; + convert_emoticons: boolean; + custom_status: { + emoji_id: string | null; + emoji_name: string | null; + expires_at: number | null; + text: string | null; + }; + default_guilds_restricted: boolean; + detect_platform_accounts: boolean; + developer_mode: boolean; + disable_games_tab: boolean; + enable_tts_command: boolean; + explicit_content_filter: number; + friend_source_flags: { all: boolean }; + gateway_connected: boolean; + gif_auto_play: boolean; + guild_folders: // every top guild is displayed as a "folder" + { + color: number; + guild_ids: string[]; + id: number; + name: string; + }[]; + guild_positions: string[]; // guild ids ordered by position + inline_attachment_media: boolean; + inline_embed_media: boolean; + locale: string; // en_US + message_display_compact: boolean; + native_phone_integration_enabled: boolean; + render_embeds: boolean; + render_reactions: boolean; + restricted_guilds: string[]; + show_current_game: boolean; + status: "online" | "offline" | "dnd" | "idle"; + stream_notifications_enabled: boolean; + theme: "dark" | "white"; // dark + timezone_offset: number; // e.g -60 + }; } +// Private user data that should never get sent to the client export interface PublicUser { id: string; discriminator: string; @@ -129,72 +201,9 @@ export interface PublicUser { bot: boolean; } -export interface ConnectedAccount { - access_token: string; - friend_sync: boolean; - id: string; - name: string; - revoked: boolean; - show_activity: boolean; - type: string; - verifie: boolean; - visibility: number; -} - -export interface Relationship { - id: string; - nickname?: string; - type: RelationshipType; -} - export enum RelationshipType { outgoing = 4, incoming = 3, blocked = 2, friends = 1, } - -export interface UserSettings { - afk_timeout: number; - allow_accessibility_detection: boolean; - animate_emoji: boolean; - animate_stickers: number; - contact_sync_enabled: boolean; - convert_emoticons: boolean; - custom_status: { - emoji_id: string | null; - emoji_name: string | null; - expires_at: number | null; - text: string | null; - }; - default_guilds_restricted: boolean; - detect_platform_accounts: boolean; - developer_mode: boolean; - disable_games_tab: boolean; - enable_tts_command: boolean; - explicit_content_filter: number; - friend_source_flags: { all: boolean }; - gateway_connected: boolean; - gif_auto_play: boolean; - guild_folders: // every top guild is displayed as a "folder" - { - color: number; - guild_ids: string[]; - id: number; - name: string; - }[]; - guild_positions: string[]; // guild ids ordered by position - inline_attachment_media: boolean; - inline_embed_media: boolean; - locale: string; // en_US - message_display_compact: boolean; - native_phone_integration_enabled: boolean; - render_embeds: boolean; - render_reactions: boolean; - restricted_guilds: string[]; - show_current_game: boolean; - status: "online" | "offline" | "dnd" | "idle"; - stream_notifications_enabled: boolean; - theme: "dark" | "white"; // dark - timezone_offset: number; // e.g -60 -} -- cgit 1.4.1