diff --git a/assets/openapi.json b/assets/openapi.json
index b1818f4b..35b75a77 100644
Binary files a/assets/openapi.json and b/assets/openapi.json differ
diff --git a/assets/schemas.json b/assets/schemas.json
index c92ac3e9..6681e695 100644
Binary files a/assets/schemas.json and b/assets/schemas.json differ
diff --git a/src/api/routes/applications/#id/index.ts b/src/api/routes/applications/#id/index.ts
index 949d66f8..2b4bcd88 100644
--- a/src/api/routes/applications/#id/index.ts
+++ b/src/api/routes/applications/#id/index.ts
@@ -1,17 +1,17 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors
-
+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
-
+
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
@@ -21,6 +21,7 @@ import {
Application,
ApplicationModifySchema,
DiscordApiErrors,
+ Guild,
handleFile,
} from "@spacebar/util";
import { Request, Response, Router } from "express";
@@ -90,6 +91,24 @@ router.patch(
body.icon as string,
);
}
+ if (body.cover_image) {
+ body.cover_image = await handleFile(
+ `/app-icons/${app.id}`,
+ body.cover_image as string,
+ );
+ }
+
+ if (body.guild_id) {
+ const guild = await Guild.findOneOrFail({
+ where: { id: body.guild_id },
+ select: ["owner_id"],
+ });
+ if (guild.owner_id != req.user_id)
+ throw new HTTPError(
+ "You must be the owner of the guild to link it to an application",
+ 400,
+ );
+ }
if (app.bot) {
app.bot.assign({ bio: body.description });
diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts
index 4ed75f27..747ef860 100644
--- a/src/util/entities/Application.ts
+++ b/src/util/entities/Application.ts
@@ -16,11 +16,19 @@
along with this program. If not, see .
*/
-import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from "typeorm";
+import {
+ Column,
+ Entity,
+ JoinColumn,
+ ManyToOne,
+ OneToOne,
+ RelationId,
+} from "typeorm";
import { BaseClass } from "./BaseClass";
import { Team } from "./Team";
import { User } from "./User";
import { dbEngine } from "../util/Database";
+import { Guild } from "./Guild";
@Entity({
name: "applications",
@@ -108,15 +116,22 @@ export class Application extends BaseClass {
@Column({ nullable: true })
privacy_policy_url?: string;
+ @Column({ nullable: true })
+ @RelationId((application: Application) => application.guild)
+ guild_id?: string;
+
+ @JoinColumn({ name: "guild_id" })
+ @ManyToOne(() => Guild)
+ guild?: Guild; // guild to which the app is linked, e.g. a developer support server
+
+ @Column({ nullable: true })
+ custom_install_url?: string;
+
//just for us
//@Column({ type: "simple-array", nullable: true })
//rpc_origins?: string[];
- //@JoinColumn({ name: "guild_id" })
- //@ManyToOne(() => Guild)
- //guild?: Guild; // if this application is a game sold, this field will be the guild to which it has been linked
-
//@Column({ nullable: true })
//primary_sku_id?: string; // if this application is a game sold, this field will be the id of the "Game SKU" that is created,
diff --git a/src/util/migration/mariadb/1725090962922-applicationProperties.ts b/src/util/migration/mariadb/1725090962922-applicationProperties.ts
new file mode 100644
index 00000000..ee8c0bea
--- /dev/null
+++ b/src/util/migration/mariadb/1725090962922-applicationProperties.ts
@@ -0,0 +1,23 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class ApplicationProperties1725090962922 implements MigrationInterface {
+ name = "ApplicationProperties1725090962922";
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(
+ "ALTER TABLE `applications` ADD COLUMN `guild_id` VARCHAR(255) NOT NULL",
+ );
+ await queryRunner.query(
+ "ALTER TABLE `applications` ADD COLUMN `custom_install_url` TEXT NOT NULL",
+ );
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(
+ "ALTER TABLE `applications` DROP COLUMN `guild_id`",
+ );
+ await queryRunner.query(
+ "ALTER TABLE `applications` DROP COLUMN `custom_install_url`",
+ );
+ }
+}
diff --git a/src/util/migration/mysql/1725090962922-applicationProperties.ts b/src/util/migration/mysql/1725090962922-applicationProperties.ts
new file mode 100644
index 00000000..ee8c0bea
--- /dev/null
+++ b/src/util/migration/mysql/1725090962922-applicationProperties.ts
@@ -0,0 +1,23 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class ApplicationProperties1725090962922 implements MigrationInterface {
+ name = "ApplicationProperties1725090962922";
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(
+ "ALTER TABLE `applications` ADD COLUMN `guild_id` VARCHAR(255) NOT NULL",
+ );
+ await queryRunner.query(
+ "ALTER TABLE `applications` ADD COLUMN `custom_install_url` TEXT NOT NULL",
+ );
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(
+ "ALTER TABLE `applications` DROP COLUMN `guild_id`",
+ );
+ await queryRunner.query(
+ "ALTER TABLE `applications` DROP COLUMN `custom_install_url`",
+ );
+ }
+}
diff --git a/src/util/migration/postgres/1725090962922-applicationProperties.ts b/src/util/migration/postgres/1725090962922-applicationProperties.ts
new file mode 100644
index 00000000..d43a0277
--- /dev/null
+++ b/src/util/migration/postgres/1725090962922-applicationProperties.ts
@@ -0,0 +1,23 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class ApplicationProperties1725090962922 implements MigrationInterface {
+ name = "ApplicationProperties1725090962922";
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(
+ "ALTER TABLE applications ADD COLUMN guild_id TEXT NOT NULL",
+ );
+ await queryRunner.query(
+ "ALTER TABLE applications ADD COLUMN custom_install_url TEXT NOT NULL",
+ );
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(
+ "ALTER TABLE applications DROP COLUMN guild_id",
+ );
+ await queryRunner.query(
+ "ALTER TABLE applications DROP COLUMN custom_install_url",
+ );
+ }
+}
diff --git a/src/util/schemas/ApplicationModifySchema.ts b/src/util/schemas/ApplicationModifySchema.ts
index f75dd5b1..a8717976 100644
--- a/src/util/schemas/ApplicationModifySchema.ts
+++ b/src/util/schemas/ApplicationModifySchema.ts
@@ -1,17 +1,17 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors
-
+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
-
+
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
@@ -19,6 +19,7 @@
export interface ApplicationModifySchema {
description?: string;
icon?: string;
+ cover_image?: string;
interactions_endpoint_url?: string;
max_participants?: number | null;
name?: string;
@@ -29,4 +30,10 @@ export interface ApplicationModifySchema {
bot_public?: boolean;
bot_require_code_grant?: boolean;
flags?: number;
+ custom_install_url?: string;
+ guild_id?: string;
+ /*install_params?: { TODO: Validation
+ scopes: string[];
+ permissions: string;
+ };*/
}