summary refs log tree commit diff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/entities/Application.ts165
-rw-r--r--src/util/entities/SKU.ts225
-rw-r--r--src/util/entities/index.ts1
-rw-r--r--src/util/util/ApplicationDiscoveryEligibilityFlags.ts40
-rw-r--r--src/util/util/ApplicationFlags.ts54
-rw-r--r--src/util/util/ApplicationMonetizationEligibilityFlags.ts43
-rw-r--r--src/util/util/index.ts4
-rw-r--r--src/util/util/slugify.ts10
8 files changed, 526 insertions, 16 deletions
diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts

index e00b4a988..014361bca 100644 --- a/src/util/entities/Application.ts +++ b/src/util/entities/Application.ts
@@ -21,6 +21,22 @@ import { BaseClass } from "./BaseClass"; import { Team } from "./Team"; import { User } from "./User"; import { Guild } from "./Guild"; +import { + ApplicationApprovableConsoleType, + ApplicationCompanySchema, + ApplicationDiscoverabilityState, + ApplicationEventWebhooksStatus, + ApplicationEventWebhooksType, + ApplicationExecutableSchema, + ApplicationGuildRestriction, + ApplicationIntegrationTypeConfigurationSchema, + ApplicationInteractionsVersion, + ApplicationMonetizationState, + ApplicationSKUSchema, + ApplicationVerificationState, + RPCApplicationState, + StoreApplicationState, +} from "@spacebar/schemas"; @Entity({ name: "applications", @@ -45,9 +61,11 @@ export class Application extends BaseClass { hook: boolean = true; @Column() + // deprecated bot_public?: boolean = true; @Column() + // deprecated bot_require_code_grant?: boolean = false; @Column() @@ -57,21 +75,21 @@ export class Application extends BaseClass { @ManyToOne(() => User, { onDelete: "CASCADE" }) owner: User; - // TODO: enum this? https://discord.com/developers/docs/resources/application#application-object-application-flags @Column() + // ApplicationFlags bitfield flags: number = 0; @Column({ type: "simple-array", nullable: true }) redirect_uris: string[] = []; - @Column({ nullable: true }) - rpc_application_state: number = 0; + @Column() + rpc_application_state: RPCApplicationState = RPCApplicationState.DISABLED; - @Column({ nullable: true }) - store_application_state: number = 1; + @Column() + store_application_state: StoreApplicationState = StoreApplicationState.NONE; - @Column({ nullable: true }) - verification_state: number = 1; + @Column() + verification_state: ApplicationVerificationState = ApplicationVerificationState.INELIGIBLE; @Column({ nullable: true }) interactions_endpoint_url?: string; @@ -83,10 +101,10 @@ export class Application extends BaseClass { integration_require_code_grant: boolean = false; @Column({ nullable: true }) - discoverability_state: number = 1; + discoverability_state: ApplicationDiscoverabilityState = ApplicationDiscoverabilityState.INELIGIBLE; @Column({ nullable: true }) - discovery_eligibility_flags: number = 2240; + discovery_eligibility_flags: number = 0; // ApplicationDiscoveryEligibilityFlags bitfield @JoinColumn({ name: "bot_user_id" }) @OneToOne(() => User, { onDelete: "CASCADE" }) @@ -118,16 +136,131 @@ export class Application extends BaseClass { @Column({ nullable: true }) custom_install_url?: string; - //just for us + @Column({ nullable: true }) + splash?: string; + + @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, + + @Column({ nullable: true }) + eula_id?: string; + + @Column({ nullable: true }) + slug?: string; // if this application is a game sold, this field will be the URL slug that links to the store page + + @Column({ type: "simple-array", nullable: true }) + aliases?: string[]; + + @Column({ type: "simple-json", nullable: true }) + executables?: ApplicationExecutableSchema[]; + + @Column({ type: "simple-json", nullable: true }) + third_party_skus?: ApplicationSKUSchema[]; + + @Column({ nullable: true }) + overlay?: boolean = false; + + @Column({ nullable: true }) + overlay_methods?: number; // only one right now is 1 << 0 OUT_OF_PROCESS + + @Column({ nullable: true }) + overlay_warn?: boolean = false; + + @Column({ nullable: true }) + overlay_compatibility_hook?: boolean = false; + + @Column({ type: "simple-json", nullable: true }) + developers?: ApplicationCompanySchema[]; + + @Column({ type: "simple-json", nullable: true }) + publishers?: ApplicationCompanySchema[]; + + @Column({ type: "simple-array", nullable: true }) + rpc_origins?: string[]; + + @Column({ nullable: true }) + deeplink_uri?: string; + + @Column({ nullable: true }) + bot_disabled?: boolean = false; + + @Column({ nullable: true }) + bot_quarantined?: boolean = false; + + @Column({ nullable: true }) + bot_approximate_guild_count?: number; + + @Column({ nullable: true }) + approximate_guild_count?: number; + + @Column({ nullable: true }) + approximate_user_install_count?: number; + + @Column({ nullable: true }) + approximate_user_authorization_count?: number; + + @Column({ nullable: true }) + internal_guild_restriction?: ApplicationGuildRestriction; + + @Column({ nullable: true, type: "text" }) + role_connections_verification_url: string | null = null; + + @Column() + interactions_version: ApplicationInteractionsVersion = ApplicationInteractionsVersion.VERSION_1; - //@Column({ type: "simple-array", nullable: true }) - //rpc_origins?: string[]; + @Column({ type: "simple-array" }) + interactions_event_types: ApplicationEventWebhooksType[] = []; + + @Column({ nullable: true }) + event_webhooks_status?: ApplicationEventWebhooksStatus; + + @Column({ nullable: true }) + event_webhooks_url?: string; + + @Column({ type: "simple-array", nullable: true }) + event_webhooks_types?: ApplicationEventWebhooksType[]; + + @Column() + explicit_content_filter: number = 0; // Inherits the guild's explicit content filter + + @Column({ type: "simple-json", nullable: true }) + integration_types_config?: Record<number, ApplicationIntegrationTypeConfigurationSchema>; + + @Column({ nullable: true }) + connection_entrypoint_url?: string; + + @Column() + is_verified: boolean = false; + + @Column() + creator_monetization_state: number = 0; // unknown values + + @Column() + is_discoverable: boolean = false; + + @Column() + is_monetized: boolean = false; + + @Column() + storefront_available: boolean = false; + + @Column() + monetization_state: ApplicationMonetizationState = ApplicationMonetizationState.NONE; + + @Column({ nullable: true }) + monetization_eligibility_flags?: number = 0; // ApplicationMonetizationEligibilityFlags + + @Column({ nullable: true }) + max_participants?: number; // max participants for embedded applications, -1 for unlimited + + @Column({ type: "simple-json", nullable: true }) + embedded_activity_config?: object; // dont feel like making types for this rn - //@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, + @Column({ type: "simple-array" }) + approved_consoles: ApplicationApprovableConsoleType[] = []; - //@Column({ nullable: true }) - //slug?: string; // if this application is a game sold, this field will be the URL slug that links to the store page + // @Column() + // pricing_localization_strategy: string; @JoinColumn({ name: "team_id" }) @ManyToOne(() => Team, { diff --git a/src/util/entities/SKU.ts b/src/util/entities/SKU.ts new file mode 100644
index 000000000..e615ed088 --- /dev/null +++ b/src/util/entities/SKU.ts
@@ -0,0 +1,225 @@ +/* + 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 <https://www.gnu.org/licenses/>. +*/ + +import { BaseEntity, Column, Entity, JoinColumn, ManyToOne, OneToMany, Unique } from "typeorm"; +import { BaseClass } from "./BaseClass"; +import { User } from "./User"; +import { Application } from "./Application"; +import { + BillingPaymentGateway, + CreateSKUSchema, + LocalizedStringSchema, + SKUAccessType, + SKUContentRatingAgency, + SKUContentRatingSchema, + SKUExternalSKUStrategySchema, + SKUFeature, + SKUGenre, + SKUOperatingSystem, + SKUPriceSchema, + SKUProductLine, + SKUSystemRequirementsSchema, + SKUTenantMetadataSchema, + SKUType, +} from "@spacebar/schemas"; +import { SKUGuildPowerupMetadataSchema } from "../../schemas/api/store/SKUGuildPowerupMetadataSchema"; +import { slugify } from "../util"; + +@Entity({ + name: "skus", +}) +export class SKU extends BaseClass { + @Column() + type: SKUType; + + @Column() + application_id: string; + + @JoinColumn({ name: "application_id" }) + @ManyToOne(() => Application, { onDelete: "CASCADE" }) + application: Application; + + @Column() + product_line: SKUProductLine; + + @Column() + product_id?: string; + + @Column({ type: "bigint" }) + flags: number = 0; // SKUFlags + + @Column({ type: "simple-json" }) + name: LocalizedStringSchema; + + @Column({ nullable: true, type: "simple-json" }) + summary?: LocalizedStringSchema; + + @Column({ nullable: true, type: "simple-json" }) + description?: LocalizedStringSchema; + + @Column({ nullable: true, type: "simple-json" }) + legal_notice?: LocalizedStringSchema; + + @Column() + slug: string; + + @Column({ nullable: true }) + thumbnail_asset_id?: string; + + @Column({ nullable: true, type: "text" }) + dependent_sku_id?: string | null; + + @JoinColumn({ name: "bundled_sku_ids" }) + @OneToMany(() => SKU, (sku: SKU) => sku.id, { + cascade: true, + orphanedRowAction: "delete", + onDelete: "CASCADE", + }) + bundled_skus?: SKU[]; + + @Column({ nullable: true, type: "simple-array" }) + bundled_sku_ids?: string[]; + + @Column() + access_type: SKUAccessType; + + @Column({ nullable: true, type: "simple-array" }) + manifest_labels?: string[] | null; + + @Column({ type: "simple-array" }) + features: SKUFeature[]; + + @Column({ nullable: true, type: "simple-array" }) + locales?: string[]; + + @Column({ nullable: true, type: "simple-array" }) + genres?: SKUGenre[]; + + @Column({ nullable: true, type: "simple-array" }) + available_regions?: string[]; + + @Column({ nullable: true, type: "simple-json" }) + // only for localized skus + content_rating?: SKUContentRatingSchema; + + @Column({ nullable: true, type: "simple-json" }) + // only for localized skus + content_rating_agency?: SKUContentRatingAgency; + + @Column({ nullable: true, type: "simple-json" }) + // only for unlocalized skus + content_ratings?: Record<SKUContentRatingAgency, SKUContentRatingSchema>; + + @Column({ nullable: true, type: "simple-json" }) + system_requirements?: Record<SKUOperatingSystem, SKUSystemRequirementsSchema>; + + @Column({ nullable: true, type: "simple-json" }) + // used for localized skus + price?: SKUPriceSchema | Record<string, unknown>; // discord.food says map[string, integer] but i dont think thats true, its probably SKUPriceSchema + + @Column({ nullable: true }) + // used for unlocalized skus + price_tier?: number; + + @Column({ nullable: true }) + // used for unlocalized skus + sale_price_tier?: number; + + @Column({ nullable: true, type: "simple-json" }) + // used for localized skus + sale_price?: Record<string, unknown>; // same here, discord.food says map[string, integer] which i dont believe + + @Column() + created_at: Date; + + @Column() + updated_at: Date; + + @Column({ nullable: true, type: Date }) + release_date?: Date | null; + + @Column({ nullable: true }) + preorder_approximate_release_date?: string; + + @Column({ nullable: true }) + preorder_released_at?: string; + + @Column({ nullable: true }) + external_purchase_url?: string; + + @Column({ nullable: true, type: "simple-json" }) + external_sku_strategies?: Record<BillingPaymentGateway, SKUExternalSKUStrategySchema>; + + @Column({ nullable: true, type: "simple-array" }) + eligible_payment_gateways?: BillingPaymentGateway[]; + + @Column() + premium: boolean; + + @Column() + show_age_gate: boolean; + + @Column({ nullable: true }) + // only for localized skus + restricted?: boolean; + + @Column({ nullable: true }) + exclusive?: boolean; + + @Column({ nullable: true, default: false }) + deleted?: boolean = false; + + @Column({ nullable: true, type: "simple-json" }) + tenant_metadata?: SKUTenantMetadataSchema; + + @Column({ nullable: true, type: "simple-json" }) + powerup_metadata?: SKUGuildPowerupMetadataSchema; + + static async createSku(data: CreateSKUSchema): Promise<SKU> { + const n = { + ...data, + bundled_skus: undefined, + name: undefined, + slug: undefined, + }; + + // convert string to localized string or use as is + const name = typeof data.name === "string" ? { default: data.name } : data.name; + + const sku = await SKU.create({ + product_line: SKUProductLine.APPLICATION, + dependent_sku_id: null, + manifest_labels: null, + access_type: SKUAccessType.FULL, + features: [], + release_date: null, + premium: false, + flags: 0, + show_age_gate: false, + tenant_metadata: {}, + created_at: new Date(), + updated_at: new Date(), + ...n, + bundled_sku_ids: data.bundled_skus, + name, + slug: slugify(name.default), + }); + + return sku; + } +} diff --git a/src/util/entities/index.ts b/src/util/entities/index.ts
index 0e67675a8..dcd91ba7f 100644 --- a/src/util/entities/index.ts +++ b/src/util/entities/index.ts
@@ -62,3 +62,4 @@ export * from "./UserSettingsProtos"; export * from "./ValidRegistrationTokens"; export * from "./VoiceState"; export * from "./Webhook"; +export * from "./SKU"; diff --git a/src/util/util/ApplicationDiscoveryEligibilityFlags.ts b/src/util/util/ApplicationDiscoveryEligibilityFlags.ts new file mode 100644
index 000000000..acdf64401 --- /dev/null +++ b/src/util/util/ApplicationDiscoveryEligibilityFlags.ts
@@ -0,0 +1,40 @@ +/* + 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 <https://www.gnu.org/licenses/>. +*/ + +import { BitField } from "./BitField"; + +export class ApplicationDiscoveryEligibilityFlags extends BitField { + static FLAGS = { + VERIFIED: BigInt(1) << BigInt(0), + TAG: BigInt(1) << BigInt(1), + DESCRIPTION: BigInt(1) << BigInt(2), + TERMS_OF_SERVICE: BigInt(1) << BigInt(3), + PRIVACY_POLICY: BigInt(1) << BigInt(4), + INSTALL_PARAMS: BigInt(1) << BigInt(5), + SAFE_NAME: BigInt(1) << BigInt(6), + SAFE_DESCRIPTION: BigInt(1) << BigInt(7), + APPROVED_COMMANDS: BigInt(1) << BigInt(8), + SUPPORT_GUILD: BigInt(1) << BigInt(9), + SAFE_COMMANDS: BigInt(1) << BigInt(10), + MFA: BigInt(1) << BigInt(11), + SAFE_DIRECTORY_OVERVIEW: BigInt(1) << BigInt(12), + SUPPORTED_LOCALES: BigInt(1) << BigInt(13), + SAFE_SHORT_DESCRIPTION: BigInt(1) << BigInt(14), + SAFE_ROLE_CONNECTIONS: BigInt(1) << BigInt(15), + }; +} diff --git a/src/util/util/ApplicationFlags.ts b/src/util/util/ApplicationFlags.ts new file mode 100644
index 000000000..a158cf786 --- /dev/null +++ b/src/util/util/ApplicationFlags.ts
@@ -0,0 +1,54 @@ +/* + 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 <https://www.gnu.org/licenses/>. +*/ + +import { BitField } from "./BitField"; + +export class ApplicationFlags extends BitField { + static FLAGS = { + EMBEDDED_RELEASED: BigInt(1) << BigInt(1), + MANAGED_EMOJI: BigInt(1) << BigInt(2), + EMBEDDED_IAP: BigInt(1) << BigInt(3), + GROUP_DM_CREATE: BigInt(1) << BigInt(4), + RPC_PRIVATE_BETA: BigInt(1) << BigInt(5), + AUTO_MODERATION_RULE_CREATE_BADGE: BigInt(1) << BigInt(6), + GAME_PROFILE_DISABLED: BigInt(1) << BigInt(7), + PUBLIC_OAUTH2_CLIENT: BigInt(1) << BigInt(8), + CONTEXTLESS_ACTIVITY: BigInt(1) << BigInt(9), + SOCIAL_LAYER_INTEGRATION_LIMITED: BigInt(1) << BigInt(10), + CLOUD_GAMING_DEMO: BigInt(1) << BigInt(11), + GATEWAY_PRESENCE: BigInt(1) << BigInt(12), + GATEWAY_PRESENCE_LIMITED: BigInt(1) << BigInt(13), + GATEWAY_GUILD_MEMBERS: BigInt(1) << BigInt(14), + GATEWAY_GUILD_MEMBERS_LIMITED: BigInt(1) << BigInt(15), + VERIFICATION_PENDING_GUILD_LIMIT: BigInt(1) << BigInt(16), + EMBEDDED: BigInt(1) << BigInt(17), + GATEWAY_MESSAGE_CONTENT: BigInt(1) << BigInt(18), + GATEWAY_MESSAGE_CONTENT_LIMITED: BigInt(1) << BigInt(19), + EMBEDDED_FIRST_PARTY: BigInt(1) << BigInt(20), + APPLICATION_COMMAND_MIGRATED: BigInt(1) << BigInt(21), + APPLICATION_COMMAND_BADGE: BigInt(1) << BigInt(23), + ACTIVE: BigInt(1) << BigInt(24), + ACTIVE_GRACE_PERIOD: BigInt(1) << BigInt(25), + IFRAME_MODAL: BigInt(1) << BigInt(26), + SOCIAL_LAYER_INTEGRATION: BigInt(1) << BigInt(27), + PROMOTED: BigInt(1) << BigInt(29), + PARTNER: BigInt(1) << BigInt(30), + PARENT: BigInt(1) << BigInt(33), + DISABLE_RELATIONSHIP_ACCESS: BigInt(1) << BigInt(34), + }; +} diff --git a/src/util/util/ApplicationMonetizationEligibilityFlags.ts b/src/util/util/ApplicationMonetizationEligibilityFlags.ts new file mode 100644
index 000000000..1fb19bd29 --- /dev/null +++ b/src/util/util/ApplicationMonetizationEligibilityFlags.ts
@@ -0,0 +1,43 @@ +/* + 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 <https://www.gnu.org/licenses/>. +*/ + +import { BitField } from "./BitField"; + +export class ApplicationMonetizationEligibilityFlags extends BitField { + static FLAGS = { + VERIFIED: BigInt(1) << BigInt(0), + HAS_TEAM: BigInt(1) << BigInt(1), + APPROVED_COMMANDS: BigInt(1) << BigInt(2), + TERMS_OF_SERVICE: BigInt(1) << BigInt(3), + PRIVACY_POLICY: BigInt(1) << BigInt(4), + SAFE_NAME: BigInt(1) << BigInt(5), + SAFE_DESCRIPTION: BigInt(1) << BigInt(6), + SAFE_ROLE_CONNECTIONS: BigInt(1) << BigInt(7), + USER_IS_TEAM_OWNER: BigInt(1) << BigInt(8), + NOT_QUARANTINED: BigInt(1) << BigInt(9), + USER_LOCALE_SUPPORTED: BigInt(1) << BigInt(10), + USER_AGE_SUPPORTED: BigInt(1) << BigInt(11), + USER_DATE_OF_BIRTH_DEFINED: BigInt(1) << BigInt(12), + USER_MFA_ENABLED: BigInt(1) << BigInt(13), + USER_EMAIL_VERIFIED: BigInt(1) << BigInt(14), + TEAM_MEMBERS_EMAIL_VERIFIED: BigInt(1) << BigInt(15), + TEAM_MEMBERS_MFA_ENABLED: BigInt(1) << BigInt(16), + NO_BLOCKING_ISSUES: BigInt(1) << BigInt(17), + VALID_PAYOUT_STATUS: BigInt(1) << BigInt(18), + }; +} diff --git a/src/util/util/index.ts b/src/util/util/index.ts
index 18f279fed..0563888a8 100644 --- a/src/util/util/index.ts +++ b/src/util/util/index.ts
@@ -56,3 +56,7 @@ export * from "./Random"; export * from "./Url"; export * from "./SKUFlags"; export * from "./EntitlementGiftCodeFlags"; +export * from "./slugify"; +export * from "./ApplicationDiscoveryEligibilityFlags"; +export * from "./ApplicationFlags"; +export * from "./ApplicationMonetizationEligibilityFlags"; diff --git a/src/util/util/slugify.ts b/src/util/util/slugify.ts new file mode 100644
index 000000000..03f772fae --- /dev/null +++ b/src/util/util/slugify.ts
@@ -0,0 +1,10 @@ +export function slugify(text: string): string { + // return as url friendly slug + return text + .toString() + .toLowerCase() + .trim() + .replace(/\s+/g, "-") + .replace(/[^\w\\-]+/g, "") + .replace(/\\-\\-+/g, "-"); +}