diff --git a/api/migrations/54-add-discord-integration-enabled.sql b/api/migrations/54-add-discord-integration-enabled.sql
new file mode 100644
index 000000000..e94c5db8d
--- /dev/null
+++ b/api/migrations/54-add-discord-integration-enabled.sql
@@ -0,0 +1,8 @@
+ALTER TABLE ctfnote.settings
+ ADD COLUMN "discord_integration_enabled" boolean NOT NULL DEFAULT FALSE;
+
+GRANT SELECT ("discord_integration_enabled") ON ctfnote.settings TO user_anonymous;
+REVOKE UPDATE ON ctfnote.settings FROM user_admin;
+GRANT UPDATE (unique_id, registration_allowed, registration_password_allowed, registration_password, registration_default_role, style, ical_password) ON ctfnote.settings TO user_admin;
+GRANT UPDATE ("discord_integration_enabled") ON ctfnote.settings TO user_postgraphile;
+
diff --git a/api/src/index.ts b/api/src/index.ts
index 8d92cc41e..b28461238 100644
--- a/api/src/index.ts
+++ b/api/src/index.ts
@@ -22,6 +22,7 @@ import discordHooks from "./plugins/discordHooks";
import { getDiscordClient } from "./discord";
import PgManyToManyPlugin from "@graphile-contrib/pg-many-to-many";
import ProfileSubscriptionPlugin from "./plugins/ProfileSubscriptionPlugin";
+import { connectToDatabase } from "./discord/database/database";
function getDbUrl(role: "user" | "admin") {
const login = config.db[role].login;
@@ -154,6 +155,22 @@ async function main() {
getDiscordClient();
+ const pgClient = await connectToDatabase(); //? maybe we should not keep this dependency in the discord folder?
+
+ try {
+ const query =
+ "UPDATE ctfnote.settings SET discord_integration_enabled = $1";
+ const values = [config.discord.use.toLowerCase() !== "false"];
+ await pgClient.query(query, values);
+ } catch (error) {
+ console.error(
+ "Failed to set discord_integration_enabled flag in the database:",
+ error
+ );
+ } finally {
+ pgClient.release();
+ }
+
app.listen(config.web.port, () => {
//sendMessageToDiscord("CTFNote API started");
console.log(`Listening on :${config.web.port}`);
diff --git a/front/graphql.schema.json b/front/graphql.schema.json
index 9f91ea6af..dd9db3579 100644
--- a/front/graphql.schema.json
+++ b/front/graphql.schema.json
@@ -12122,6 +12122,22 @@
"name": "Setting",
"description": null,
"fields": [
+ {
+ "name": "discordIntegrationEnabled",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "icalPassword",
"description": null,
@@ -12248,6 +12264,18 @@
"description": "Represents an update to a `Setting`. Fields that are set will be updated.",
"fields": null,
"inputFields": [
+ {
+ "name": "discordIntegrationEnabled",
+ "description": null,
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "icalPassword",
"description": null,
diff --git a/front/src/components/CTF/Guests.vue b/front/src/components/CTF/Guests.vue
index 86f38a2d4..8ec832d75 100644
--- a/front/src/components/CTF/Guests.vue
+++ b/front/src/components/CTF/Guests.vue
@@ -33,7 +33,12 @@
No guests found.
Sync with Discord event
-
+
+
+ The Discord integration is currently disabled.
+
+
+
@@ -55,10 +60,12 @@ export default defineComponent({
setup() {
const team = ctfnote.profiles.injectTeam();
const now = ref(new Date());
+ const settings = ctfnote.settings.injectSettings();
return {
now,
team,
+ settings,
inviteUserToCtf: ctfnote.ctfs.useInviteUserToCtf(),
uninviteUserToCtf: ctfnote.ctfs.useUninviteUserToCtf(),
};
diff --git a/front/src/ctfnote/models.ts b/front/src/ctfnote/models.ts
index f505310c8..00debfa7a 100644
--- a/front/src/ctfnote/models.ts
+++ b/front/src/ctfnote/models.ts
@@ -102,6 +102,7 @@ export type Settings = {
registrationAllowed: boolean;
registrationPasswordAllowed: boolean;
style: SettingsColorMap;
+ discordIntegrationEnabled: boolean;
};
export type AdminSettings = Settings & {
diff --git a/front/src/ctfnote/settings.ts b/front/src/ctfnote/settings.ts
index 04c6fd746..5096a1d1c 100644
--- a/front/src/ctfnote/settings.ts
+++ b/front/src/ctfnote/settings.ts
@@ -40,6 +40,7 @@ export function buildSettings(
registrationAllowed: fragment.registrationAllowed ?? false,
registrationPasswordAllowed: fragment.registrationPasswordAllowed ?? false,
style: parseStyle(fragment.style ?? '{}'),
+ discordIntegrationEnabled: fragment.discordIntegrationEnabled ?? false,
};
}
diff --git a/front/src/generated/graphql.ts b/front/src/generated/graphql.ts
index a2d6744e1..8f374beab 100644
--- a/front/src/generated/graphql.ts
+++ b/front/src/generated/graphql.ts
@@ -2350,6 +2350,7 @@ export type SetDiscordEventLinkPayload = {
export type Setting = Node & {
__typename?: 'Setting';
+ discordIntegrationEnabled: Scalars['Boolean'];
icalPassword?: Maybe
;
/** A globally unique identifier. Can be used in various places throughout the system to identify this single value. */
nodeId: Scalars['ID'];
@@ -2362,6 +2363,7 @@ export type Setting = Node & {
/** Represents an update to a `Setting`. Fields that are set will be updated. */
export type SettingPatch = {
+ discordIntegrationEnabled?: InputMaybe;
icalPassword?: InputMaybe;
registrationAllowed?: InputMaybe;
registrationDefaultRole?: InputMaybe;
@@ -3661,14 +3663,14 @@ export type UpdateCredentialsForCtfIdMutationVariables = Exact<{
export type UpdateCredentialsForCtfIdMutation = { __typename?: 'Mutation', updateCtfSecret?: { __typename?: 'UpdateCtfSecretPayload', ctfSecret?: { __typename?: 'CtfSecret', nodeId: string, credentials?: string | null } | null } | null };
-export type SettingsInfoFragment = { __typename?: 'Setting', nodeId: string, registrationAllowed: boolean, registrationPasswordAllowed: boolean, style: string };
+export type SettingsInfoFragment = { __typename?: 'Setting', nodeId: string, registrationAllowed: boolean, registrationPasswordAllowed: boolean, style: string, discordIntegrationEnabled: boolean };
-export type AdminSettingsInfoFragment = { __typename?: 'Setting', nodeId: string, registrationPassword: string, registrationDefaultRole: Role, icalPassword?: string | null, registrationAllowed: boolean, registrationPasswordAllowed: boolean, style: string };
+export type AdminSettingsInfoFragment = { __typename?: 'Setting', nodeId: string, registrationPassword: string, registrationDefaultRole: Role, icalPassword?: string | null, registrationAllowed: boolean, registrationPasswordAllowed: boolean, style: string, discordIntegrationEnabled: boolean };
export type GetSettingsQueryVariables = Exact<{ [key: string]: never; }>;
-export type GetSettingsQuery = { __typename?: 'Query', settings?: { __typename?: 'SettingsConnection', nodes: Array<{ __typename?: 'Setting', nodeId: string, registrationAllowed: boolean, registrationPasswordAllowed: boolean, style: string }> } | null };
+export type GetSettingsQuery = { __typename?: 'Query', settings?: { __typename?: 'SettingsConnection', nodes: Array<{ __typename?: 'Setting', nodeId: string, registrationAllowed: boolean, registrationPasswordAllowed: boolean, style: string, discordIntegrationEnabled: boolean }> } | null };
export type GetIcalPasswordQueryVariables = Exact<{ [key: string]: never; }>;
@@ -3678,7 +3680,7 @@ export type GetIcalPasswordQuery = { __typename?: 'Query', settings?: { __typena
export type GetAdminSettingsQueryVariables = Exact<{ [key: string]: never; }>;
-export type GetAdminSettingsQuery = { __typename?: 'Query', settings?: { __typename?: 'SettingsConnection', nodes: Array<{ __typename?: 'Setting', nodeId: string, registrationPassword: string, registrationDefaultRole: Role, icalPassword?: string | null, registrationAllowed: boolean, registrationPasswordAllowed: boolean, style: string }> } | null };
+export type GetAdminSettingsQuery = { __typename?: 'Query', settings?: { __typename?: 'SettingsConnection', nodes: Array<{ __typename?: 'Setting', nodeId: string, registrationPassword: string, registrationDefaultRole: Role, icalPassword?: string | null, registrationAllowed: boolean, registrationPasswordAllowed: boolean, style: string, discordIntegrationEnabled: boolean }> } | null };
export type UpdateSettingsMutationVariables = Exact<{
nodeId: Scalars['ID'];
@@ -3686,7 +3688,7 @@ export type UpdateSettingsMutationVariables = Exact<{
}>;
-export type UpdateSettingsMutation = { __typename?: 'Mutation', updateSettingByNodeId?: { __typename?: 'UpdateSettingPayload', setting?: { __typename?: 'Setting', nodeId: string, registrationPassword: string, registrationDefaultRole: Role, icalPassword?: string | null, registrationAllowed: boolean, registrationPasswordAllowed: boolean, style: string } | null } | null };
+export type UpdateSettingsMutation = { __typename?: 'Mutation', updateSettingByNodeId?: { __typename?: 'UpdateSettingPayload', setting?: { __typename?: 'Setting', nodeId: string, registrationPassword: string, registrationDefaultRole: Role, icalPassword?: string | null, registrationAllowed: boolean, registrationPasswordAllowed: boolean, style: string, discordIntegrationEnabled: boolean } | null } | null };
export type TagFragment = { __typename?: 'Tag', nodeId: string, id: number, tag: string };
@@ -3955,6 +3957,7 @@ export const SettingsInfoFragmentDoc = gql`
registrationAllowed
registrationPasswordAllowed
style
+ discordIntegrationEnabled
}
`;
export const AdminSettingsInfoFragmentDoc = gql`
@@ -6127,6 +6130,7 @@ export const SettingsInfo = gql`
registrationAllowed
registrationPasswordAllowed
style
+ discordIntegrationEnabled
}
`;
export const AdminSettingsInfo = gql`
diff --git a/front/src/graphql/Settings.graphql b/front/src/graphql/Settings.graphql
index 75fbb4932..c3cc15a32 100644
--- a/front/src/graphql/Settings.graphql
+++ b/front/src/graphql/Settings.graphql
@@ -3,6 +3,7 @@ fragment SettingsInfo on Setting {
registrationAllowed
registrationPasswordAllowed
style
+ discordIntegrationEnabled
}
fragment AdminSettingsInfo on Setting {
diff --git a/front/src/pages/Settings.vue b/front/src/pages/Settings.vue
index df98a3392..d289a2504 100644
--- a/front/src/pages/Settings.vue
+++ b/front/src/pages/Settings.vue
@@ -138,7 +138,17 @@
Link your Discord account
-
+
+ The Discord integration is currently disabled.
+
+
+
Your CTFNote account is not linked to your Discord account.
@@ -162,7 +172,11 @@
-
+
= ref('');
const { result: profileTokenResult } = ctfnote.me.getProfileToken();
+ const settings = ctfnote.settings.injectSettings();
+
watch(
profileTokenResult,
(s) => {
@@ -242,6 +258,7 @@ export default defineComponent({
username,
description,
me,
+ settings,
systemNotificationEnabled,
askForNotificationPrivilege,
disableSystemNotification,