From 528662446c3377032190c117f5a3fe2fa8f3b88e Mon Sep 17 00:00:00 2001 From: Rory& Date: Sat, 12 Jul 2025 20:12:37 +0200 Subject: [PATCH] Colorful roles --- assets/schemas.json | Bin 34416894 -> 34538103 bytes .../routes/guilds/#guild_id/roles/index.ts | 7 ++++++- src/util/entities/Role.ts | 17 +++++++++++++++++ .../postgres/1752321571508-RoleColors.ts | 14 ++++++++++++++ .../1752342900886-RoleColorsSolidColor.ts | 15 +++++++++++++++ src/util/schemas/RoleModifySchema.ts | 5 +++++ 6 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/util/migration/postgres/1752321571508-RoleColors.ts create mode 100644 src/util/migration/postgres/1752342900886-RoleColorsSolidColor.ts diff --git a/assets/schemas.json b/assets/schemas.json index 84fc55adc34d842a94d3b5782cb3f8fb3ebdb2e5..65a85c207abfea21eab599ffefc33f33e0663877 100755 GIT binary patch delta 27865 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 diff --git a/src/api/routes/guilds/#guild_id/roles/index.ts b/src/api/routes/guilds/#guild_id/roles/index.ts index e2c34e7f..bd944324 100644 --- a/src/api/routes/guilds/#guild_id/roles/index.ts +++ b/src/api/routes/guilds/#guild_id/roles/index.ts @@ -72,7 +72,7 @@ router.post( throw DiscordApiErrors.MAXIMUM_ROLES.withParams(maxRoles); const role = Role.create({ - // values before ...body are default and can be overriden + // values before ...body are default and can be overridden position: 1, hoist: false, color: 0, @@ -88,6 +88,11 @@ router.post( icon: undefined, unicode_emoji: undefined, id: Snowflake.generate(), + colors: { + primary_color: body.colors?.primary_color || body.color || 0, + secondary_color: body.colors?.secondary_color || undefined, // gradient + tertiary_color: body.colors?.tertiary_color || undefined, // "holographic" + }, }); await Promise.all([ diff --git a/src/util/entities/Role.ts b/src/util/entities/Role.ts index c5df6068..a58742ad 100644 --- a/src/util/entities/Role.ts +++ b/src/util/entities/Role.ts @@ -22,6 +22,20 @@ import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { dbEngine } from "../util/Database"; +export class RoleColors { + primary_color: number; + secondary_color: number | undefined; // only used for "holographic" and "gradient" styles + tertiary_color?: number | undefined; // only used for "holographic" style + + toJSON(): RoleColors { + return { + ...this, + secondary_color: this.secondary_color ?? undefined, + tertiary_color: this.tertiary_color ?? undefined, + }; + } +} + @Entity({ name: "roles", engine: dbEngine, @@ -74,6 +88,9 @@ export class Role extends BaseClass { @Column({ default: 0 }) flags: number; + @Column({ nullable: false, type: "simple-json" }) + colors: RoleColors; + toJSON(): Role { return { ...this, diff --git a/src/util/migration/postgres/1752321571508-RoleColors.ts b/src/util/migration/postgres/1752321571508-RoleColors.ts new file mode 100644 index 00000000..687142e3 --- /dev/null +++ b/src/util/migration/postgres/1752321571508-RoleColors.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class RoleColors1752321571508 implements MigrationInterface { + name = 'RoleColors1752321571508' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "roles" ADD "colors" text`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "roles" DROP COLUMN "colors"`); + } + +} diff --git a/src/util/migration/postgres/1752342900886-RoleColorsSolidColor.ts b/src/util/migration/postgres/1752342900886-RoleColorsSolidColor.ts new file mode 100644 index 00000000..36c24a37 --- /dev/null +++ b/src/util/migration/postgres/1752342900886-RoleColorsSolidColor.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class RoleColorsSolidColor1752342900886 implements MigrationInterface { + name = 'RoleColorsSolidColor1752342900886' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`UPDATE "roles" SET "colors" = jsonb_build_object('primary_color', "color") WHERE "colors" IS NULL`); + await queryRunner.query(`ALTER TABLE "roles" ALTER COLUMN "colors" SET NOT NULL`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "roles" ALTER COLUMN "colors" DROP NOT NULL`); + } + +} diff --git a/src/util/schemas/RoleModifySchema.ts b/src/util/schemas/RoleModifySchema.ts index 1466953c..a6d18931 100644 --- a/src/util/schemas/RoleModifySchema.ts +++ b/src/util/schemas/RoleModifySchema.ts @@ -25,4 +25,9 @@ export interface RoleModifySchema { position?: number; icon?: string; unicode_emoji?: string; + colors?: { + primary_color: number; + secondary_color: number | null | undefined; // only used for "holographic" and "gradient" styles + tertiary_color?: number | null | undefined; // only used for "holographic" style + } | undefined; }