diff --git a/src/api/routes/guilds/index.ts b/src/api/routes/guilds/index.ts index 78ba93a2c..663677dcb 100644 --- a/src/api/routes/guilds/index.ts +++ b/src/api/routes/guilds/index.ts @@ -55,7 +55,7 @@ router.post( const guild = await Guild.createGuild({ ...body, owner_id: req.user_id, - template_guild_id: null, + source_guild_id: null, }); const { autoJoin } = Config.get().guild; diff --git a/src/api/routes/guilds/templates/index.ts b/src/api/routes/guilds/templates/index.ts index 391f9c8ae..6eb6ffbee 100644 --- a/src/api/routes/guilds/templates/index.ts +++ b/src/api/routes/guilds/templates/index.ts @@ -17,10 +17,10 @@ */ import { route } from "@spacebar/api"; -import { Config, DiscordApiErrors, Guild, Member, Template } from "@spacebar/util"; +import { Config, DiscordApiErrors, Guild, Member, Tag, Template } from "@spacebar/util"; import { Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; -import { GuildTemplateCreateSchema } from "@spacebar/schemas"; +import { ChannelType, GuildTemplateCreateSchema } from "@spacebar/schemas"; const router: Router = Router({ mergeParams: true }); @@ -64,7 +64,7 @@ router.post("/:template_code", route({ requestBody: "GuildTemplateCreateSchema" // body comes after the template ...body, owner_id: req.user_id, - template_guild_id: template.source_guild_id, + source_guild_id: template.source_guild_id, }); await Member.addToGuild(req.user_id, guild.id); @@ -87,7 +87,28 @@ async function getTemplate(code: string) { headers: { "Content-Type": "application/json" }, }); - return (await discordTemplateData.json()) as Template; + const templateData = (await discordTemplateData.json()) as Template; + + // Role ID is position in new Discord template schema. Do a little converting. + templateData.serialized_source_guild.roles.forEach((role) => { + role.position = role.id as unknown as number; + }); + + templateData.serialized_source_guild.channels.forEach((channel) => { + if (channel.type === ChannelType.GUILD_FORUM) { + channel.available_tags = + channel.available_tags?.map((tag) => + Tag.create({ + name: tag.name, + emoji_id: tag.emoji_id, + emoji_name: tag.emoji_name, + moderated: tag.moderated, + }), + ) ?? []; + } + }); + + return templateData; } if (code.startsWith("external:")) { diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index cea2bfad3..e47d078a2 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -218,7 +218,10 @@ export class Channel extends BaseClass { for (const character of InvisibleCharacters) if (channel.name.includes(character)) throw new HTTPError("Channel name cannot include invalid characters", 403); // Categories skip these checks on discord.com - if (channel.type !== ChannelType.GUILD_CATEGORY || guild.features.includes("IRC_LIKE_CATEGORY_NAMES")) { + if ( + (channel.type !== ChannelType.GUILD_CATEGORY && channel.type !== ChannelType.GUILD_STAGE_VOICE && channel.type !== ChannelType.GUILD_VOICE) || + guild.features.includes("IRC_LIKE_CATEGORY_NAMES") + ) { if (channel.name.includes(" ")) throw new HTTPError("Channel name cannot include invalid characters", 403); if (channel.name.match(/--+/g)) throw new HTTPError("Channel name cannot include multiple adjacent dashes.", 403); diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts index aac3daf0e..43d22aaa4 100644 --- a/src/util/entities/Guild.ts +++ b/src/util/entities/Guild.ts @@ -310,7 +310,7 @@ export class Guild extends BaseClass { owner_id?: string; roles?: Partial[]; channels?: Partial[]; - template_guild_id: string | null; + source_guild_id: string | null; }) { const guild_id = Snowflake.generate(); @@ -372,7 +372,7 @@ export class Guild extends BaseClass { guild_id, id: // role.id === body.template_guild_id indicates that this is the @everyone role - role.id === body.template_guild_id ? guild_id : Snowflake.generate(), + role.id === body.source_guild_id || role.id == "0" ? guild_id : Snowflake.generate(), }) .save() .then(resolve); diff --git a/src/util/entities/Role.ts b/src/util/entities/Role.ts index 7908f42d5..0647d6da6 100644 --- a/src/util/entities/Role.ts +++ b/src/util/entities/Role.ts @@ -42,7 +42,7 @@ export class Role extends BaseClass { @Column() hoist: boolean; - @Column() + @Column({ default: false }) managed: boolean; @Column() diff --git a/src/util/migration/postgres/1771271159006-set-role-managed-default.ts b/src/util/migration/postgres/1771271159006-set-role-managed-default.ts new file mode 100644 index 000000000..fad55f237 --- /dev/null +++ b/src/util/migration/postgres/1771271159006-set-role-managed-default.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class SetRoleManagedDefault1771271159006 implements MigrationInterface { + name = "SetRoleManagedDefault1771271159006"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "roles" ALTER COLUMN "managed" SET DEFAULT false`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "roles" ALTER COLUMN "managed" DROP DEFAULT`); + } +}