summary refs log tree commit diff
path: root/util/src/entities
diff options
context:
space:
mode:
Diffstat (limited to 'util/src/entities')
-rw-r--r--util/src/entities/AuditLog.ts5
-rw-r--r--util/src/entities/BaseClass.ts57
-rw-r--r--util/src/entities/Channel.ts2
-rw-r--r--util/src/entities/Config.ts23
-rw-r--r--util/src/entities/Emoji.ts14
-rw-r--r--util/src/entities/Guild.ts8
-rw-r--r--util/src/entities/Invite.ts11
-rw-r--r--util/src/entities/Member.ts21
-rw-r--r--util/src/entities/Message.ts7
-rw-r--r--util/src/entities/Migration.ts18
-rw-r--r--util/src/entities/RateLimit.ts3
-rw-r--r--util/src/entities/ReadState.ts5
-rw-r--r--util/src/entities/Relationship.ts2
-rw-r--r--util/src/entities/Session.ts20
-rw-r--r--util/src/entities/Sticker.ts36
-rw-r--r--util/src/entities/StickerPack.ts31
-rw-r--r--util/src/entities/TeamMember.ts2
-rw-r--r--util/src/entities/User.ts25
-rw-r--r--util/src/entities/Webhook.ts5
-rw-r--r--util/src/entities/index.ts2
20 files changed, 173 insertions, 124 deletions
diff --git a/util/src/entities/AuditLog.ts b/util/src/entities/AuditLog.ts

index ae9feb76..4b81ed6a 100644 --- a/util/src/entities/AuditLog.ts +++ b/util/src/entities/AuditLog.ts
@@ -55,10 +55,7 @@ export class AuditLog extends BaseClass { @ManyToOne(() => User, (user: User) => user.id) user: User; - @Column({ - type: "simple-enum", - enum: AuditLogEvents, - }) + @Column({ type: "int" }) action_type: AuditLogEvents; @Column({ type: "simple-json", nullable: true }) diff --git a/util/src/entities/BaseClass.ts b/util/src/entities/BaseClass.ts
index beccf04b..d20078e5 100644 --- a/util/src/entities/BaseClass.ts +++ b/util/src/entities/BaseClass.ts
@@ -1,19 +1,8 @@ import "reflect-metadata"; -import { - BaseEntity, - BeforeInsert, - BeforeUpdate, - EntityMetadata, - FindConditions, - ObjectIdColumn, - PrimaryColumn, -} from "typeorm"; +import { BaseEntity, EntityMetadata, FindConditions, ObjectIdColumn, PrimaryColumn } from "typeorm"; import { Snowflake } from "../util/Snowflake"; import "missing-native-js-functions"; -// TODO use class-validator https://typeorm.io/#/validation with class annotators (isPhone/isEmail) combined with types from typescript-json-schema -// btw. we don't use class-validator for everything, because we need to explicitly set the type instead of deriving it from typescript also it doesn't easily support nested objects - export class BaseClassWithoutId extends BaseEntity { constructor(props?: any) { super(); @@ -42,7 +31,7 @@ export class BaseClassWithoutId extends BaseEntity { for (const key in props) { if (!properties.has(key)) continue; // @ts-ignore - const setter = this[`set${key.capitalize()}`]; + const setter = this[`set${key.capitalize()}`]; // use setter function if it exists if (setter) { setter.call(this, props[key]); @@ -53,12 +42,6 @@ export class BaseClassWithoutId extends BaseEntity { } } - @BeforeUpdate() - @BeforeInsert() - validate() { - return this; - } - toJSON(): any { return Object.fromEntries( this.metadata.columns // @ts-ignore @@ -76,42 +59,6 @@ export class BaseClassWithoutId extends BaseEntity { const repository = this.getRepository(); return repository.decrement(conditions, propertyPath, value); } - - // static async delete<T>(criteria: FindConditions<T>, options?: RemoveOptions) { - // if (!criteria) throw new Error("You need to specify delete criteria"); - - // const repository = this.getRepository(); - // const promises = repository.metadata.relations.map(async (x) => { - // if (x.orphanedRowAction !== "delete") return; - - // const foreignKey = - // x.foreignKeys.find((key) => key.entityMetadata === repository.metadata) || - // x.inverseRelation?.foreignKeys[0]; // find foreign key for this entity - // if (!foreignKey) { - // throw new Error( - // `Foreign key not found for entity ${repository.metadata.name} in relation ${x.propertyName}` - // ); - // } - // const id = (criteria as any)[foreignKey.referencedColumnNames[0]]; - // if (!id) throw new Error("id missing in criteria options " + foreignKey.referencedColumnNames); - - // if (x.relationType === "many-to-many") { - // return getConnection() - // .createQueryBuilder() - // .relation(this, x.propertyName) - // .of(id) - // .remove({ [foreignKey.columnNames[0]]: id }); - // } else if ( - // x.relationType === "one-to-one" || - // x.relationType === "many-to-one" || - // x.relationType === "one-to-many" - // ) { - // return (x.inverseEntityMetadata.target as any).delete({ [foreignKey.columnNames[0]]: id }); - // } - // }); - // await Promise.all(promises); - // return super.delete(criteria, options); - // } } export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb") ? ObjectIdColumn : PrimaryColumn; diff --git a/util/src/entities/Channel.ts b/util/src/entities/Channel.ts
index 51d8b026..bd2e5a58 100644 --- a/util/src/entities/Channel.ts +++ b/util/src/entities/Channel.ts
@@ -39,7 +39,7 @@ export class Channel extends BaseClass { @Column({ type: "text", nullable: true }) icon?: string | null; - @Column({ type: "simple-enum", enum: ChannelType }) + @Column({ type: "int" }) type: ChannelType; @OneToMany(() => Recipient, (recipient: Recipient) => recipient.channel, { diff --git a/util/src/entities/Config.ts b/util/src/entities/Config.ts
index 813649ac..b3167ac7 100644 --- a/util/src/entities/Config.ts +++ b/util/src/entities/Config.ts
@@ -51,11 +51,6 @@ export interface ConfigValue { general: { instanceId: string; }; - permissions: { - user: { - createGuilds: boolean; - }; - }; limits: { user: { maxGuilds: number; @@ -64,6 +59,7 @@ export interface ConfigValue { }; guild: { maxRoles: number; + maxEmojis: number; maxMembers: number; maxChannels: number; maxChannelsInCategory: number; @@ -153,6 +149,11 @@ export interface ConfigValue { canLeave: boolean; }; }; + gif: { + enabled: boolean; + provider: "tenor"; // more coming soon + apiKey?: string; + }; rabbitmq: { host: string | null; }; @@ -175,11 +176,6 @@ export const DefaultConfigOptions: ConfigValue = { general: { instanceId: Snowflake.generate(), }, - permissions: { - user: { - createGuilds: true, - }, - }, limits: { user: { maxGuilds: 100, @@ -188,6 +184,7 @@ export const DefaultConfigOptions: ConfigValue = { }, guild: { maxRoles: 250, + maxEmojis: 50, // TODO: max emojis per guild per nitro level maxMembers: 250000, maxChannels: 500, maxChannelsInCategory: 50, @@ -305,7 +302,6 @@ export const DefaultConfigOptions: ConfigValue = { }, ], }, - guild: { showAllGuildsInDiscovery: false, autoJoin: { @@ -314,6 +310,11 @@ export const DefaultConfigOptions: ConfigValue = { guilds: [], }, }, + gif: { + enabled: true, + provider: "tenor", + apiKey: "LIVDSRZULELA", + }, rabbitmq: { host: null, }, diff --git a/util/src/entities/Emoji.ts b/util/src/entities/Emoji.ts
index a252d9f4..03218375 100644 --- a/util/src/entities/Emoji.ts +++ b/util/src/entities/Emoji.ts
@@ -1,4 +1,5 @@ -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import { User } from "."; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { Role } from "./Role"; @@ -20,6 +21,14 @@ export class Emoji extends BaseClass { }) guild: Guild; + @Column({ nullable: true }) + @RelationId((emoji: Emoji) => emoji.user) + user_id: string; + + @JoinColumn({ name: "user_id" }) + @ManyToOne(() => User) + user: User; + @Column() managed: boolean; @@ -28,4 +37,7 @@ export class Emoji extends BaseClass { @Column() require_colons: boolean; + + @Column({ type: "simple-array" }) + roles: string[]; // roles this emoji is whitelisted to (new discord feature?) } diff --git a/util/src/entities/Guild.ts b/util/src/entities/Guild.ts
index 35595191..157f0921 100644 --- a/util/src/entities/Guild.ts +++ b/util/src/entities/Guild.ts
@@ -258,14 +258,6 @@ export class Guild extends BaseClass { unavailable?: boolean; @Column({ nullable: true }) - @RelationId((guild: Guild) => guild.vanity_url) - vanity_url_code?: string; - - @JoinColumn({ name: "vanity_url_code" }) - @ManyToOne(() => Invite) - vanity_url?: Invite; - - @Column({ nullable: true }) verification_level?: number; @Column({ type: "simple-json" }) diff --git a/util/src/entities/Invite.ts b/util/src/entities/Invite.ts
index 82556fab..b3e00957 100644 --- a/util/src/entities/Invite.ts +++ b/util/src/entities/Invite.ts
@@ -1,6 +1,6 @@ -import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId, PrimaryColumn } from "typeorm"; import { Member } from "./Member"; -import { BaseClass, PrimaryIdColumn } from "./BaseClass"; +import { BaseClassWithoutId } from "./BaseClass"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; import { User } from "./User"; @@ -8,8 +8,8 @@ import { User } from "./User"; export const PublicInviteRelation = ["inviter", "guild", "channel"]; @Entity("invites") -export class Invite extends BaseClass { - @PrimaryIdColumn() +export class Invite extends BaseClassWithoutId { + @PrimaryColumn() code: string; @Column() @@ -71,6 +71,9 @@ export class Invite extends BaseClass { @Column({ nullable: true }) target_user_type?: number; + @Column({ nullable: true}) + vanity_url?: boolean; + static async joinGuild(user_id: string, code: string) { const invite = await Invite.findOneOrFail({ code }); if (invite.uses++ >= invite.max_uses && invite.max_uses !== 0) await Invite.delete({ code }); diff --git a/util/src/entities/Member.ts b/util/src/entities/Member.ts
index 7d7ac40a..0f7be2a7 100644 --- a/util/src/entities/Member.ts +++ b/util/src/entities/Member.ts
@@ -26,6 +26,22 @@ import { BaseClassWithoutId } from "./BaseClass"; import { Ban, PublicGuildRelations } from "."; import { DiscordApiErrors } from "../util/Constants"; +export const MemberPrivateProjection: (keyof Member)[] = [ + "id", + "guild", + "guild_id", + "deaf", + "joined_at", + "last_message_id", + "mute", + "nick", + "pending", + "premium_since", + "roles", + "settings", + "user", +]; + @Entity("members") @Index(["id", "guild_id"], { unique: true }) export class Member extends BaseClassWithoutId { @@ -81,9 +97,12 @@ export class Member extends BaseClassWithoutId { @Column() pending: boolean; - @Column({ type: "simple-json" }) + @Column({ type: "simple-json", select: false }) settings: UserGuildSettings; + @Column({ nullable: true }) + last_message_id?: string; + // TODO: update // @Column({ type: "simple-json" }) // read_state: ReadState; diff --git a/util/src/entities/Message.ts b/util/src/entities/Message.ts
index 04c3c7aa..a4d38315 100644 --- a/util/src/entities/Message.ts +++ b/util/src/entities/Message.ts
@@ -46,9 +46,6 @@ export enum MessageType { @Entity("messages") export class Message extends BaseClass { - @Column() - id: string; - @Column({ nullable: true }) @RelationId((message: Message) => message.channel) channel_id: string; @@ -130,7 +127,7 @@ export class Message extends BaseClass { mention_channels: Channel[]; @JoinTable({ name: "message_stickers" }) - @ManyToMany(() => Sticker) + @ManyToMany(() => Sticker, { cascade: true, onDelete: "CASCADE" }) sticker_items?: Sticker[]; @OneToMany(() => Attachment, (attachment: Attachment) => attachment.message, { @@ -151,7 +148,7 @@ export class Message extends BaseClass { @Column({ nullable: true }) pinned?: boolean; - @Column({ type: "simple-enum", enum: MessageType }) + @Column({ type: "int" }) type: MessageType; @Column({ type: "simple-json", nullable: true }) diff --git a/util/src/entities/Migration.ts b/util/src/entities/Migration.ts new file mode 100644
index 00000000..7393496f --- /dev/null +++ b/util/src/entities/Migration.ts
@@ -0,0 +1,18 @@ +import { Column, Entity, ObjectIdColumn, PrimaryGeneratedColumn } from "typeorm"; +import { BaseClassWithoutId } from "."; + +export const PrimaryIdAutoGenerated = process.env.DATABASE?.startsWith("mongodb") + ? ObjectIdColumn + : PrimaryGeneratedColumn; + +@Entity("migrations") +export class Migration extends BaseClassWithoutId { + @PrimaryIdAutoGenerated() + id: number; + + @Column({ type: 'bigint' }) + timestamp: number; + + @Column() + name: string; +} diff --git a/util/src/entities/RateLimit.ts b/util/src/entities/RateLimit.ts
index fa9c32c1..f5916f6b 100644 --- a/util/src/entities/RateLimit.ts +++ b/util/src/entities/RateLimit.ts
@@ -3,9 +3,6 @@ import { BaseClass } from "./BaseClass"; @Entity("rate_limits") export class RateLimit extends BaseClass { - @Column() - id: "global" | "error" | string; // channel_239842397 | guild_238927349823 | webhook_238923423498 - @Column() // no relation as it also executor_id: string; diff --git a/util/src/entities/ReadState.ts b/util/src/entities/ReadState.ts
index 89480e83..ebef89be 100644 --- a/util/src/entities/ReadState.ts +++ b/util/src/entities/ReadState.ts
@@ -32,13 +32,8 @@ export class ReadState extends BaseClass { user: User; @Column({ nullable: true }) - @RelationId((read_state: ReadState) => read_state.last_message) last_message_id: string; - @JoinColumn({ name: "last_message_id" }) - @ManyToOne(() => Message, { nullable: true }) - last_message?: Message; - @Column({ nullable: true }) last_pin_timestamp?: Date; diff --git a/util/src/entities/Relationship.ts b/util/src/entities/Relationship.ts
index e016b36b..c3592c76 100644 --- a/util/src/entities/Relationship.ts +++ b/util/src/entities/Relationship.ts
@@ -35,7 +35,7 @@ export class Relationship extends BaseClass { @Column({ nullable: true }) nickname?: string; - @Column({ type: "simple-enum", enum: RelationshipType }) + @Column({ type: "int" }) type: RelationshipType; toPublicRelationship() { diff --git a/util/src/entities/Session.ts b/util/src/entities/Session.ts
index 7cc325f5..969efa89 100644 --- a/util/src/entities/Session.ts +++ b/util/src/entities/Session.ts
@@ -1,6 +1,8 @@ import { User } from "./User"; import { BaseClass } from "./BaseClass"; import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import { Status } from "../interfaces/Status"; +import { Activity } from "../interfaces/Activity"; //TODO we need to remove all sessions on server start because if the server crashes without closing websockets it won't delete them @@ -17,11 +19,13 @@ export class Session extends BaseClass { user: User; //TODO check, should be 32 char long hex string - @Column({ nullable: false }) + @Column({ nullable: false, select: false }) session_id: string; - activities: []; //TODO + @Column({ type: "simple-json", nullable: true }) + activities: Activity[]; + // TODO client_status @Column({ type: "simple-json", select: false }) client_info: { client: string; @@ -29,6 +33,14 @@ export class Session extends BaseClass { version: number; }; - @Column({ nullable: false }) - status: string; //TODO enum + @Column({ nullable: false, type: "varchar" }) + status: Status; //TODO enum } + +export const PrivateSessionProjection: (keyof Session)[] = [ + "user_id", + "session_id", + "activities", + "client_info", + "status", +]; diff --git a/util/src/entities/Sticker.ts b/util/src/entities/Sticker.ts
index ab224d1d..37bc6fbe 100644 --- a/util/src/entities/Sticker.ts +++ b/util/src/entities/Sticker.ts
@@ -1,4 +1,5 @@ -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import { User } from "./User"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; @@ -8,6 +9,7 @@ export enum StickerType { } export enum StickerFormatType { + GIF = 0, // gif is a custom format type and not in discord spec PNG = 1, APNG = 2, LOTTIE = 3, @@ -21,11 +23,22 @@ export class Sticker extends BaseClass { @Column({ nullable: true }) description?: string; - @Column() - tags: string; + @Column({ nullable: true }) + available?: boolean; - @Column() - pack_id: string; + @Column({ nullable: true }) + tags?: string; + + @Column({ nullable: true }) + @RelationId((sticker: Sticker) => sticker.pack) + pack_id?: string; + + @JoinColumn({ name: "pack_id" }) + @ManyToOne(() => require("./StickerPack").StickerPack, { + onDelete: "CASCADE", + nullable: true, + }) + pack: import("./StickerPack").StickerPack; @Column({ nullable: true }) guild_id?: string; @@ -36,9 +49,18 @@ export class Sticker extends BaseClass { }) guild?: Guild; - @Column({ type: "simple-enum", enum: StickerType }) + @Column({ nullable: true }) + user_id?: string; + + @JoinColumn({ name: "user_id" }) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) + user?: User; + + @Column({ type: "int" }) type: StickerType; - @Column({ type: "simple-enum", enum: StickerFormatType }) + @Column({ type: "int" }) format_type: StickerFormatType; } diff --git a/util/src/entities/StickerPack.ts b/util/src/entities/StickerPack.ts new file mode 100644
index 00000000..ec8c69a2 --- /dev/null +++ b/util/src/entities/StickerPack.ts
@@ -0,0 +1,31 @@ +import { Column, Entity, JoinColumn, ManyToOne, OneToMany, OneToOne, RelationId } from "typeorm"; +import { Sticker } from "."; +import { BaseClass } from "./BaseClass"; + +@Entity("sticker_packs") +export class StickerPack extends BaseClass { + @Column() + name: string; + + @Column({ nullable: true }) + description?: string; + + @Column({ nullable: true }) + banner_asset_id?: string; + + @OneToMany(() => Sticker, (sticker: Sticker) => sticker.pack, { + cascade: true, + orphanedRowAction: "delete", + }) + stickers: Sticker[]; + + // sku_id: string + + @Column({ nullable: true }) + @RelationId((pack: StickerPack) => pack.cover_sticker) + cover_sticker_id?: string; + + @ManyToOne(() => Sticker, { nullable: true }) + @JoinColumn() + cover_sticker?: Sticker; +} diff --git a/util/src/entities/TeamMember.ts b/util/src/entities/TeamMember.ts
index bdfdccf0..b726e1e8 100644 --- a/util/src/entities/TeamMember.ts +++ b/util/src/entities/TeamMember.ts
@@ -9,7 +9,7 @@ export enum TeamMemberState { @Entity("team_members") export class TeamMember extends BaseClass { - @Column({ type: "simple-enum", enum: TeamMemberState }) + @Column({ type: "int" }) membership_state: TeamMemberState; @Column({ type: "simple-array" }) diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts
index 97564af3..bc852616 100644 --- a/util/src/entities/User.ts +++ b/util/src/entities/User.ts
@@ -4,7 +4,7 @@ import { BitField } from "../util/BitField"; import { Relationship } from "./Relationship"; import { ConnectedAccount } from "./ConnectedAccount"; import { Config, FieldErrors, Snowflake, trimSpecial } from ".."; -import { Member } from "."; +import { Member, Session } from "."; export enum PublicUserEnum { username, @@ -131,6 +131,9 @@ export class User extends BaseClass { @Column() rights: string; // Rights + @OneToMany(() => Session, (session: Session) => session.user) + sessions: Session[]; + @JoinColumn({ name: "relationship_ids" }) @OneToMany(() => Relationship, (relationship: Relationship) => relationship.from, { cascade: true, @@ -198,7 +201,7 @@ export class User extends BaseClass { // randomly generates a discriminator between 1 and 9999 and checks max five times if it already exists // if it all five times already exists, abort with USERNAME_TOO_MANY_USERS error // else just continue - // TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the mongodb database? + // TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the database? for (let tries = 0; tries < 5; tries++) { discriminator = Math.randomIntBetween(1, 9999).toString().padStart(4, "0"); exists = await User.findOne({ where: { discriminator, username: username }, select: ["id"] }); @@ -219,7 +222,7 @@ export class User extends BaseClass { // if nsfw_allowed is null/undefined it'll require date_of_birth to set it to true/false const language = req.language === "en" ? "en-US" : req.language || "en-US"; - const user = await new User({ + const user = new User({ created_at: new Date(), username: username, discriminator, @@ -246,13 +249,17 @@ export class User extends BaseClass { }, settings: { ...defaultSettings, locale: language }, fingerprints: [], - }).save(); + }); + + await user.save(); - if (Config.get().guild.autoJoin.enabled) { - for (const guild of Config.get().guild.autoJoin.guilds || []) { - await Member.addToGuild(user.id, guild); + setImmediate(async () => { + if (Config.get().guild.autoJoin.enabled) { + for (const guild of Config.get().guild.autoJoin.guilds || []) { + await Member.addToGuild(user.id, guild).catch((e) => {}); + } } - } + }); return user; } @@ -291,7 +298,7 @@ export const defaultSettings: UserSettings = { render_reactions: true, restricted_guilds: [], show_current_game: true, - status: "offline", + status: "online", stream_notifications_enabled: true, theme: "dark", timezone_offset: 0, diff --git a/util/src/entities/Webhook.ts b/util/src/entities/Webhook.ts
index 8382435f..89538417 100644 --- a/util/src/entities/Webhook.ts +++ b/util/src/entities/Webhook.ts
@@ -12,10 +12,7 @@ export enum WebhookType { @Entity("webhooks") export class Webhook extends BaseClass { - @Column() - id: string; - - @Column({ type: "simple-enum", enum: WebhookType }) + @Column({ type: "int" }) type: WebhookType; @Column({ nullable: true }) diff --git a/util/src/entities/index.ts b/util/src/entities/index.ts
index 7b1c9750..b52841c9 100644 --- a/util/src/entities/index.ts +++ b/util/src/entities/index.ts
@@ -11,6 +11,7 @@ export * from "./Guild"; export * from "./Invite"; export * from "./Member"; export * from "./Message"; +export * from "./Migration"; export * from "./RateLimit"; export * from "./ReadState"; export * from "./Recipient"; @@ -18,6 +19,7 @@ export * from "./Relationship"; export * from "./Role"; export * from "./Session"; export * from "./Sticker"; +export * from "./StickerPack"; export * from "./Team"; export * from "./TeamMember"; export * from "./Template";