refactor progress
This commit is contained in:
66
packages/api/src/models/AdminApiKey.tsx
Normal file
66
packages/api/src/models/AdminApiKey.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {AdminApiKeyRow} from '@fluxer/api/src/database/types/AdminAuthTypes';
|
||||
|
||||
export class AdminApiKey {
|
||||
readonly keyId: bigint;
|
||||
readonly keyHash: string;
|
||||
readonly name: string;
|
||||
readonly createdById: UserID;
|
||||
readonly createdAt: Date;
|
||||
readonly lastUsedAt: Date | null;
|
||||
readonly expiresAt: Date | null;
|
||||
readonly version: number;
|
||||
readonly acls: Set<string>;
|
||||
|
||||
constructor(row: AdminApiKeyRow) {
|
||||
this.keyId = row.key_id;
|
||||
this.keyHash = row.key_hash;
|
||||
this.name = row.name;
|
||||
this.createdById = row.created_by_user_id;
|
||||
this.createdAt = row.created_at;
|
||||
this.lastUsedAt = row.last_used_at ?? null;
|
||||
this.expiresAt = row.expires_at ?? null;
|
||||
this.version = row.version;
|
||||
this.acls = row.acls ?? new Set();
|
||||
}
|
||||
|
||||
toRow(): AdminApiKeyRow {
|
||||
return {
|
||||
key_id: this.keyId,
|
||||
key_hash: this.keyHash,
|
||||
name: this.name,
|
||||
created_by_user_id: this.createdById,
|
||||
created_at: this.createdAt,
|
||||
last_used_at: this.lastUsedAt,
|
||||
expires_at: this.expiresAt,
|
||||
version: this.version,
|
||||
acls: this.acls.size > 0 ? this.acls : new Set(),
|
||||
};
|
||||
}
|
||||
|
||||
isExpired(): boolean {
|
||||
if (!this.expiresAt) {
|
||||
return false;
|
||||
}
|
||||
return this.expiresAt < new Date();
|
||||
}
|
||||
}
|
||||
79
packages/api/src/models/Application.tsx
Normal file
79
packages/api/src/models/Application.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ApplicationID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {ApplicationRow} from '@fluxer/api/src/database/types/OAuth2Types';
|
||||
|
||||
export class Application {
|
||||
readonly applicationId: ApplicationID;
|
||||
readonly ownerUserId: UserID;
|
||||
readonly name: string;
|
||||
readonly botUserId: UserID | null;
|
||||
readonly botIsPublic: boolean;
|
||||
readonly botRequireCodeGrant: boolean;
|
||||
readonly oauth2RedirectUris: Set<string>;
|
||||
readonly clientSecretHash: string | null;
|
||||
readonly botTokenHash: string | null;
|
||||
readonly botTokenPreview: string | null;
|
||||
readonly botTokenCreatedAt: Date | null;
|
||||
readonly clientSecretCreatedAt: Date | null;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: ApplicationRow) {
|
||||
this.applicationId = row.application_id;
|
||||
this.ownerUserId = row.owner_user_id;
|
||||
this.name = row.name;
|
||||
this.botUserId = row.bot_user_id;
|
||||
this.botIsPublic = row.bot_is_public ?? row.bot_user_id !== null;
|
||||
this.botRequireCodeGrant = row.bot_require_code_grant ?? false;
|
||||
this.oauth2RedirectUris = row.oauth2_redirect_uris ?? new Set<string>();
|
||||
this.clientSecretHash = row.client_secret_hash;
|
||||
this.botTokenHash = row.bot_token_hash;
|
||||
this.botTokenPreview = row.bot_token_preview;
|
||||
this.botTokenCreatedAt = row.bot_token_created_at;
|
||||
this.clientSecretCreatedAt = row.client_secret_created_at;
|
||||
this.version = row.version ?? 1;
|
||||
}
|
||||
|
||||
toRow(): ApplicationRow {
|
||||
return {
|
||||
application_id: this.applicationId,
|
||||
owner_user_id: this.ownerUserId,
|
||||
name: this.name,
|
||||
bot_user_id: this.botUserId,
|
||||
bot_is_public: this.botIsPublic,
|
||||
bot_require_code_grant: this.botRequireCodeGrant,
|
||||
oauth2_redirect_uris: this.oauth2RedirectUris,
|
||||
client_secret_hash: this.clientSecretHash,
|
||||
bot_token_hash: this.botTokenHash,
|
||||
bot_token_preview: this.botTokenPreview,
|
||||
bot_token_created_at: this.botTokenCreatedAt,
|
||||
client_secret_created_at: this.clientSecretCreatedAt,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
|
||||
hasBotUser(): boolean {
|
||||
return this.botUserId !== null;
|
||||
}
|
||||
|
||||
getBotUserId(): UserID | null {
|
||||
return this.botUserId;
|
||||
}
|
||||
}
|
||||
74
packages/api/src/models/Attachment.tsx
Normal file
74
packages/api/src/models/Attachment.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {AttachmentID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {MessageAttachment} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
|
||||
export class Attachment {
|
||||
readonly id: AttachmentID;
|
||||
readonly filename: string;
|
||||
readonly size: bigint;
|
||||
readonly title: string | null;
|
||||
readonly description: string | null;
|
||||
readonly width: number | null;
|
||||
readonly height: number | null;
|
||||
readonly contentType: string;
|
||||
readonly contentHash: string | null;
|
||||
readonly placeholder: string | null;
|
||||
readonly flags: number;
|
||||
readonly duration: number | null;
|
||||
readonly nsfw: boolean | null;
|
||||
readonly waveform: string | null;
|
||||
|
||||
constructor(attachment: MessageAttachment) {
|
||||
this.id = attachment.attachment_id;
|
||||
this.filename = attachment.filename;
|
||||
this.size = attachment.size;
|
||||
this.title = attachment.title ?? null;
|
||||
this.description = attachment.description ?? null;
|
||||
this.width = attachment.width ?? null;
|
||||
this.height = attachment.height ?? null;
|
||||
this.contentType = attachment.content_type;
|
||||
this.contentHash = attachment.content_hash ?? null;
|
||||
this.placeholder = attachment.placeholder ?? null;
|
||||
this.flags = attachment.flags ?? 0;
|
||||
this.duration = attachment.duration ?? null;
|
||||
this.nsfw = attachment.nsfw ?? null;
|
||||
this.waveform = attachment.waveform ?? null;
|
||||
}
|
||||
|
||||
toMessageAttachment(): MessageAttachment {
|
||||
return {
|
||||
attachment_id: this.id,
|
||||
filename: this.filename,
|
||||
size: this.size,
|
||||
title: this.title,
|
||||
description: this.description,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
content_type: this.contentType,
|
||||
content_hash: this.contentHash,
|
||||
placeholder: this.placeholder,
|
||||
flags: this.flags,
|
||||
duration: this.duration,
|
||||
nsfw: this.nsfw,
|
||||
waveform: this.waveform,
|
||||
};
|
||||
}
|
||||
}
|
||||
62
packages/api/src/models/AuthSession.tsx
Normal file
62
packages/api/src/models/AuthSession.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {AuthSessionRow} from '@fluxer/api/src/database/types/AuthTypes';
|
||||
|
||||
export class AuthSession {
|
||||
readonly userId: UserID;
|
||||
readonly sessionIdHash: Buffer;
|
||||
readonly createdAt: Date;
|
||||
readonly approximateLastUsedAt: Date;
|
||||
readonly clientIp: string;
|
||||
readonly clientUserAgent: string | null;
|
||||
readonly clientIsDesktop: boolean | null;
|
||||
readonly clientOs?: string | null;
|
||||
readonly clientPlatform?: string | null;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: AuthSessionRow) {
|
||||
this.userId = row.user_id;
|
||||
this.sessionIdHash = row.session_id_hash;
|
||||
this.createdAt = row.created_at;
|
||||
this.approximateLastUsedAt = row.approx_last_used_at;
|
||||
this.clientIp = row.client_ip;
|
||||
this.clientUserAgent = row.client_user_agent ?? null;
|
||||
this.clientIsDesktop = row.client_is_desktop ?? null;
|
||||
this.clientOs = row.client_os ?? null;
|
||||
this.clientPlatform = row.client_platform ?? null;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): AuthSessionRow {
|
||||
return {
|
||||
user_id: this.userId,
|
||||
session_id_hash: this.sessionIdHash,
|
||||
created_at: this.createdAt,
|
||||
approx_last_used_at: this.approximateLastUsedAt,
|
||||
client_ip: this.clientIp,
|
||||
client_user_agent: this.clientUserAgent,
|
||||
client_is_desktop: this.clientIsDesktop,
|
||||
client_os: this.clientOs,
|
||||
client_platform: this.clientPlatform,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
38
packages/api/src/models/CallInfo.tsx
Normal file
38
packages/api/src/models/CallInfo.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {MessageCall} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
|
||||
export class CallInfo {
|
||||
readonly participantIds: Set<UserID>;
|
||||
readonly endedTimestamp: Date | null;
|
||||
|
||||
constructor(call: MessageCall) {
|
||||
this.participantIds = call.participant_ids ?? new Set();
|
||||
this.endedTimestamp = call.ended_timestamp ? new Date(call.ended_timestamp) : null;
|
||||
}
|
||||
|
||||
toMessageCall(): MessageCall {
|
||||
return {
|
||||
participant_ids: this.participantIds.size > 0 ? this.participantIds : null,
|
||||
ended_timestamp: this.endedTimestamp,
|
||||
};
|
||||
}
|
||||
}
|
||||
117
packages/api/src/models/Channel.tsx
Normal file
117
packages/api/src/models/Channel.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, GuildID, MessageID, RoleID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {ChannelRow, PermissionOverwrite} from '@fluxer/api/src/database/types/ChannelTypes';
|
||||
import {ChannelPermissionOverwrite} from '@fluxer/api/src/models/ChannelPermissionOverwrite';
|
||||
|
||||
export class Channel {
|
||||
readonly id: ChannelID;
|
||||
readonly guildId: GuildID | null;
|
||||
readonly type: number;
|
||||
readonly name: string | null;
|
||||
readonly topic: string | null;
|
||||
readonly iconHash: string | null;
|
||||
readonly url: string | null;
|
||||
readonly parentId: ChannelID | null;
|
||||
readonly position: number;
|
||||
readonly ownerId: UserID | null;
|
||||
readonly recipientIds: Set<UserID>;
|
||||
readonly isNsfw: boolean;
|
||||
readonly rateLimitPerUser: number;
|
||||
readonly bitrate: number | null;
|
||||
readonly userLimit: number | null;
|
||||
readonly rtcRegion: string | null;
|
||||
readonly lastMessageId: MessageID | null;
|
||||
readonly lastPinTimestamp: Date | null;
|
||||
readonly permissionOverwrites: Map<RoleID | UserID, ChannelPermissionOverwrite>;
|
||||
readonly nicknames: Map<string, string>;
|
||||
readonly isSoftDeleted: boolean;
|
||||
readonly indexedAt: Date | null;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: ChannelRow) {
|
||||
this.id = row.channel_id;
|
||||
this.guildId = row.guild_id ?? null;
|
||||
this.type = row.type;
|
||||
this.name = row.name ?? null;
|
||||
this.topic = row.topic ?? null;
|
||||
this.iconHash = row.icon_hash ?? null;
|
||||
this.url = row.url ?? null;
|
||||
this.parentId = row.parent_id ?? null;
|
||||
this.position = row.position ?? 0;
|
||||
this.ownerId = row.owner_id ?? null;
|
||||
this.recipientIds = row.recipient_ids ?? new Set();
|
||||
this.isNsfw = row.nsfw ?? false;
|
||||
this.rateLimitPerUser = row.rate_limit_per_user ?? 0;
|
||||
this.bitrate = row.bitrate ?? 0;
|
||||
this.userLimit = row.user_limit ?? 0;
|
||||
this.rtcRegion = row.rtc_region ?? null;
|
||||
this.lastMessageId = row.last_message_id ?? null;
|
||||
this.lastPinTimestamp = row.last_pin_timestamp ?? null;
|
||||
this.permissionOverwrites = new Map();
|
||||
if (row.permission_overwrites) {
|
||||
for (const [id, overwrite] of row.permission_overwrites) {
|
||||
this.permissionOverwrites.set(id, new ChannelPermissionOverwrite(overwrite));
|
||||
}
|
||||
}
|
||||
this.nicknames = row.nicks ?? new Map();
|
||||
this.isSoftDeleted = row.soft_deleted;
|
||||
this.indexedAt = row.indexed_at ?? null;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): ChannelRow {
|
||||
const permOverwritesMap: Map<UserID | RoleID, PermissionOverwrite> | null =
|
||||
this.permissionOverwrites.size > 0
|
||||
? new Map(
|
||||
Array.from(this.permissionOverwrites.entries()).map(([id, overwrite]) => [
|
||||
id,
|
||||
overwrite.toPermissionOverwrite(),
|
||||
]),
|
||||
)
|
||||
: null;
|
||||
|
||||
return {
|
||||
channel_id: this.id,
|
||||
guild_id: this.guildId,
|
||||
type: this.type,
|
||||
name: this.name,
|
||||
topic: this.topic,
|
||||
icon_hash: this.iconHash,
|
||||
url: this.url,
|
||||
parent_id: this.parentId,
|
||||
position: this.position,
|
||||
owner_id: this.ownerId,
|
||||
recipient_ids: this.recipientIds.size > 0 ? this.recipientIds : null,
|
||||
nsfw: this.isNsfw,
|
||||
rate_limit_per_user: this.rateLimitPerUser,
|
||||
bitrate: this.bitrate,
|
||||
user_limit: this.userLimit,
|
||||
rtc_region: this.rtcRegion,
|
||||
last_message_id: this.lastMessageId,
|
||||
last_pin_timestamp: this.lastPinTimestamp,
|
||||
permission_overwrites: permOverwritesMap,
|
||||
nicks: this.nicknames.size > 0 ? this.nicknames : null,
|
||||
soft_deleted: this.isSoftDeleted,
|
||||
indexed_at: this.indexedAt,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
40
packages/api/src/models/ChannelPermissionOverwrite.tsx
Normal file
40
packages/api/src/models/ChannelPermissionOverwrite.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {PermissionOverwrite} from '@fluxer/api/src/database/types/ChannelTypes';
|
||||
|
||||
export class ChannelPermissionOverwrite {
|
||||
readonly type: number;
|
||||
readonly allow: bigint;
|
||||
readonly deny: bigint;
|
||||
|
||||
constructor(overwrite: PermissionOverwrite) {
|
||||
this.type = overwrite.type;
|
||||
this.allow = overwrite.allow_ ?? 0n;
|
||||
this.deny = overwrite.deny_ ?? 0n;
|
||||
}
|
||||
|
||||
toPermissionOverwrite(): PermissionOverwrite {
|
||||
return {
|
||||
type: this.type,
|
||||
allow_: this.allow,
|
||||
deny_: this.deny,
|
||||
};
|
||||
}
|
||||
}
|
||||
42
packages/api/src/models/EmailRevertToken.tsx
Normal file
42
packages/api/src/models/EmailRevertToken.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import {createEmailRevertToken} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {EmailRevertTokenRow} from '@fluxer/api/src/database/types/AuthTypes';
|
||||
|
||||
export class EmailRevertToken {
|
||||
readonly token: string;
|
||||
readonly userId: UserID;
|
||||
readonly email: string;
|
||||
|
||||
constructor(row: EmailRevertTokenRow) {
|
||||
this.token = row.token_;
|
||||
this.userId = row.user_id;
|
||||
this.email = row.email;
|
||||
}
|
||||
|
||||
toRow(): EmailRevertTokenRow {
|
||||
return {
|
||||
token_: createEmailRevertToken(this.token),
|
||||
user_id: this.userId,
|
||||
email: this.email,
|
||||
};
|
||||
}
|
||||
}
|
||||
42
packages/api/src/models/EmailVerificationToken.tsx
Normal file
42
packages/api/src/models/EmailVerificationToken.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import {createEmailVerificationToken} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {EmailVerificationTokenRow} from '@fluxer/api/src/database/types/AuthTypes';
|
||||
|
||||
export class EmailVerificationToken {
|
||||
readonly token: string;
|
||||
readonly userId: UserID;
|
||||
readonly email: string;
|
||||
|
||||
constructor(row: EmailVerificationTokenRow) {
|
||||
this.token = row.token_;
|
||||
this.userId = row.user_id;
|
||||
this.email = row.email;
|
||||
}
|
||||
|
||||
toRow(): EmailVerificationTokenRow {
|
||||
return {
|
||||
token_: createEmailVerificationToken(this.token),
|
||||
user_id: this.userId,
|
||||
email: this.email,
|
||||
};
|
||||
}
|
||||
}
|
||||
91
packages/api/src/models/Embed.tsx
Normal file
91
packages/api/src/models/Embed.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {MessageEmbed, MessageEmbedChild} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
import {EmbedAuthor} from '@fluxer/api/src/models/EmbedAuthor';
|
||||
import {EmbedField} from '@fluxer/api/src/models/EmbedField';
|
||||
import {EmbedFooter} from '@fluxer/api/src/models/EmbedFooter';
|
||||
import {EmbedMedia} from '@fluxer/api/src/models/EmbedMedia';
|
||||
import {EmbedProvider} from '@fluxer/api/src/models/EmbedProvider';
|
||||
import {sanitizeOptionalAbsoluteUrlOrNull} from '@fluxer/api/src/utils/UrlSanitizer';
|
||||
|
||||
export class Embed {
|
||||
readonly type: string | null;
|
||||
readonly title: string | null;
|
||||
readonly description: string | null;
|
||||
readonly url: string | null;
|
||||
readonly timestamp: Date | null;
|
||||
readonly color: number | null;
|
||||
readonly author: EmbedAuthor | null;
|
||||
readonly provider: EmbedProvider | null;
|
||||
readonly thumbnail: EmbedMedia | null;
|
||||
readonly image: EmbedMedia | null;
|
||||
readonly video: EmbedMedia | null;
|
||||
readonly footer: EmbedFooter | null;
|
||||
readonly fields: Array<EmbedField>;
|
||||
readonly children: Array<Embed>;
|
||||
readonly nsfw: boolean | null;
|
||||
|
||||
constructor(embed: MessageEmbed | MessageEmbedChild, allowChildren: boolean = true) {
|
||||
this.type = embed.type ?? null;
|
||||
this.title = embed.title ?? null;
|
||||
this.description = embed.description ?? null;
|
||||
this.url = sanitizeOptionalAbsoluteUrlOrNull(embed.url);
|
||||
this.timestamp = embed.timestamp ? new Date(embed.timestamp) : null;
|
||||
this.color = embed.color ?? null;
|
||||
this.author = embed.author ? new EmbedAuthor(embed.author) : null;
|
||||
this.provider = embed.provider ? new EmbedProvider(embed.provider) : null;
|
||||
this.thumbnail = embed.thumbnail ? new EmbedMedia(embed.thumbnail) : null;
|
||||
this.image = embed.image ? new EmbedMedia(embed.image) : null;
|
||||
this.video = embed.video ? new EmbedMedia(embed.video) : null;
|
||||
this.footer = embed.footer ? new EmbedFooter(embed.footer) : null;
|
||||
this.fields = (embed.fields ?? []).map((field) => new EmbedField(field));
|
||||
this.children =
|
||||
allowChildren && 'children' in embed && embed.children
|
||||
? embed.children.map((child) => new Embed(child, false))
|
||||
: [];
|
||||
this.nsfw = embed.nsfw ?? null;
|
||||
}
|
||||
|
||||
toMessageEmbed(): MessageEmbed {
|
||||
return {
|
||||
...this.toMessageEmbedChild(),
|
||||
children: this.children.length > 0 ? this.children.map((child) => child.toMessageEmbedChild()) : null,
|
||||
};
|
||||
}
|
||||
|
||||
private toMessageEmbedChild(): MessageEmbedChild {
|
||||
return {
|
||||
type: this.type,
|
||||
title: this.title,
|
||||
description: this.description,
|
||||
url: this.url,
|
||||
timestamp: this.timestamp,
|
||||
color: this.color,
|
||||
author: this.author?.toMessageEmbedAuthor() ?? null,
|
||||
provider: this.provider?.toMessageEmbedProvider() ?? null,
|
||||
thumbnail: this.thumbnail?.toMessageEmbedMedia() ?? null,
|
||||
image: this.image?.toMessageEmbedMedia() ?? null,
|
||||
video: this.video?.toMessageEmbedMedia() ?? null,
|
||||
footer: this.footer?.toMessageEmbedFooter() ?? null,
|
||||
fields: this.fields.length > 0 ? this.fields.map((field) => field.toMessageEmbedField()) : null,
|
||||
nsfw: this.nsfw,
|
||||
};
|
||||
}
|
||||
}
|
||||
41
packages/api/src/models/EmbedAuthor.tsx
Normal file
41
packages/api/src/models/EmbedAuthor.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {MessageEmbedAuthor} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
import {sanitizeOptionalAbsoluteUrlOrNull} from '@fluxer/api/src/utils/UrlSanitizer';
|
||||
|
||||
export class EmbedAuthor {
|
||||
readonly name: string | null;
|
||||
readonly url: string | null;
|
||||
readonly iconUrl: string | null;
|
||||
|
||||
constructor(author: MessageEmbedAuthor) {
|
||||
this.name = author.name ?? null;
|
||||
this.url = sanitizeOptionalAbsoluteUrlOrNull(author.url);
|
||||
this.iconUrl = sanitizeOptionalAbsoluteUrlOrNull(author.icon_url);
|
||||
}
|
||||
|
||||
toMessageEmbedAuthor(): MessageEmbedAuthor {
|
||||
return {
|
||||
name: this.name,
|
||||
url: this.url,
|
||||
icon_url: this.iconUrl,
|
||||
};
|
||||
}
|
||||
}
|
||||
40
packages/api/src/models/EmbedField.tsx
Normal file
40
packages/api/src/models/EmbedField.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {MessageEmbedField} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
|
||||
export class EmbedField {
|
||||
readonly name: string;
|
||||
readonly value: string;
|
||||
readonly inline: boolean;
|
||||
|
||||
constructor(field: MessageEmbedField) {
|
||||
this.name = field.name ?? '';
|
||||
this.value = field.value ?? '';
|
||||
this.inline = field.inline ?? false;
|
||||
}
|
||||
|
||||
toMessageEmbedField(): MessageEmbedField {
|
||||
return {
|
||||
name: this.name || null,
|
||||
value: this.value || null,
|
||||
inline: this.inline,
|
||||
};
|
||||
}
|
||||
}
|
||||
38
packages/api/src/models/EmbedFooter.tsx
Normal file
38
packages/api/src/models/EmbedFooter.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {MessageEmbedFooter} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
import {sanitizeOptionalAbsoluteUrlOrNull} from '@fluxer/api/src/utils/UrlSanitizer';
|
||||
|
||||
export class EmbedFooter {
|
||||
readonly text: string | null;
|
||||
readonly iconUrl: string | null;
|
||||
|
||||
constructor(footer: MessageEmbedFooter) {
|
||||
this.text = footer.text ?? null;
|
||||
this.iconUrl = sanitizeOptionalAbsoluteUrlOrNull(footer.icon_url);
|
||||
}
|
||||
|
||||
toMessageEmbedFooter(): MessageEmbedFooter {
|
||||
return {
|
||||
text: this.text,
|
||||
icon_url: this.iconUrl,
|
||||
};
|
||||
}
|
||||
}
|
||||
58
packages/api/src/models/EmbedMedia.tsx
Normal file
58
packages/api/src/models/EmbedMedia.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {MessageEmbedMedia} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
|
||||
export class EmbedMedia {
|
||||
readonly url: string | null;
|
||||
readonly width: number | null;
|
||||
readonly height: number | null;
|
||||
readonly description: string | null;
|
||||
readonly contentType: string | null;
|
||||
readonly contentHash: string | null;
|
||||
readonly placeholder: string | null;
|
||||
readonly flags: number;
|
||||
readonly duration: number | null;
|
||||
|
||||
constructor(media: MessageEmbedMedia) {
|
||||
this.url = media.url ?? null;
|
||||
this.width = media.width ?? null;
|
||||
this.height = media.height ?? null;
|
||||
this.description = media.description ?? null;
|
||||
this.contentType = media.content_type ?? null;
|
||||
this.contentHash = media.content_hash ?? null;
|
||||
this.placeholder = media.placeholder ?? null;
|
||||
this.flags = media.flags ?? 0;
|
||||
this.duration = media.duration ?? null;
|
||||
}
|
||||
|
||||
toMessageEmbedMedia(): MessageEmbedMedia {
|
||||
return {
|
||||
url: this.url,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
description: this.description,
|
||||
content_type: this.contentType,
|
||||
content_hash: this.contentHash,
|
||||
placeholder: this.placeholder,
|
||||
flags: this.flags,
|
||||
duration: this.duration,
|
||||
};
|
||||
}
|
||||
}
|
||||
38
packages/api/src/models/EmbedProvider.tsx
Normal file
38
packages/api/src/models/EmbedProvider.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {MessageEmbedProvider} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
import {sanitizeOptionalAbsoluteUrlOrNull} from '@fluxer/api/src/utils/UrlSanitizer';
|
||||
|
||||
export class EmbedProvider {
|
||||
readonly name: string | null;
|
||||
readonly url: string | null;
|
||||
|
||||
constructor(provider: MessageEmbedProvider) {
|
||||
this.name = provider.name ?? null;
|
||||
this.url = sanitizeOptionalAbsoluteUrlOrNull(provider.url);
|
||||
}
|
||||
|
||||
toMessageEmbedProvider(): MessageEmbedProvider {
|
||||
return {
|
||||
name: this.name,
|
||||
url: this.url,
|
||||
};
|
||||
}
|
||||
}
|
||||
57
packages/api/src/models/ExpressionPack.tsx
Normal file
57
packages/api/src/models/ExpressionPack.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {GuildID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {ExpressionPackRow} from '@fluxer/api/src/database/types/UserTypes';
|
||||
|
||||
export type ExpressionPackType = 'emoji' | 'sticker';
|
||||
export class ExpressionPack {
|
||||
readonly id: GuildID;
|
||||
readonly type: ExpressionPackType;
|
||||
readonly creatorId: UserID;
|
||||
readonly name: string;
|
||||
readonly description: string | null;
|
||||
readonly createdAt: Date;
|
||||
readonly updatedAt: Date;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: ExpressionPackRow) {
|
||||
this.id = row.pack_id;
|
||||
this.type = row.pack_type as ExpressionPackType;
|
||||
this.creatorId = row.creator_id;
|
||||
this.name = row.name;
|
||||
this.description = row.description ?? null;
|
||||
this.createdAt = row.created_at;
|
||||
this.updatedAt = row.updated_at;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): ExpressionPackRow {
|
||||
return {
|
||||
pack_id: this.id,
|
||||
pack_type: this.type,
|
||||
creator_id: this.creatorId,
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
created_at: this.createdAt,
|
||||
updated_at: this.updatedAt,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
92
packages/api/src/models/FavoriteMeme.tsx
Normal file
92
packages/api/src/models/FavoriteMeme.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {AttachmentID, MemeID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import {userIdToChannelId} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {FavoriteMemeRow} from '@fluxer/api/src/database/types/UserTypes';
|
||||
import {snowflakeToDate} from '@fluxer/snowflake/src/Snowflake';
|
||||
|
||||
export class FavoriteMeme {
|
||||
readonly id: MemeID;
|
||||
readonly userId: UserID;
|
||||
readonly name: string;
|
||||
readonly altText: string | null;
|
||||
readonly tags: Array<string>;
|
||||
readonly attachmentId: AttachmentID;
|
||||
readonly filename: string;
|
||||
readonly contentType: string;
|
||||
readonly contentHash: string | null;
|
||||
readonly size: bigint;
|
||||
readonly width: number | null;
|
||||
readonly height: number | null;
|
||||
readonly duration: number | null;
|
||||
readonly isGifv: boolean;
|
||||
readonly klipySlug: string | null;
|
||||
readonly tenorSlugId: string | null;
|
||||
readonly createdAt: Date;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: FavoriteMemeRow) {
|
||||
this.id = row.meme_id;
|
||||
this.userId = row.user_id;
|
||||
this.name = row.name;
|
||||
this.altText = row.alt_text ?? null;
|
||||
this.tags = row.tags ?? [];
|
||||
this.attachmentId = row.attachment_id;
|
||||
this.filename = row.filename;
|
||||
this.contentType = row.content_type;
|
||||
this.contentHash = row.content_hash ?? null;
|
||||
this.size = row.size;
|
||||
this.width = row.width ?? null;
|
||||
this.height = row.height ?? null;
|
||||
this.duration = row.duration ?? null;
|
||||
this.isGifv = row.is_gifv ?? false;
|
||||
this.klipySlug = row.klipy_slug ?? null;
|
||||
this.tenorSlugId = row.tenor_id_str ?? null;
|
||||
this.createdAt = snowflakeToDate(this.id);
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): FavoriteMemeRow {
|
||||
return {
|
||||
user_id: this.userId,
|
||||
meme_id: this.id,
|
||||
name: this.name,
|
||||
alt_text: this.altText,
|
||||
tags: this.tags.length > 0 ? this.tags : null,
|
||||
attachment_id: this.attachmentId,
|
||||
filename: this.filename,
|
||||
content_type: this.contentType,
|
||||
content_hash: this.contentHash,
|
||||
size: this.size,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
duration: this.duration,
|
||||
is_gifv: this.isGifv,
|
||||
klipy_slug: this.klipySlug,
|
||||
tenor_id_str: this.tenorSlugId,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
|
||||
get storageKey(): string {
|
||||
const channelId = userIdToChannelId(this.userId);
|
||||
return `attachments/${channelId}/${this.attachmentId}/${this.filename}`;
|
||||
}
|
||||
}
|
||||
62
packages/api/src/models/GiftCode.tsx
Normal file
62
packages/api/src/models/GiftCode.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {GiftCodeRow} from '@fluxer/api/src/database/types/PaymentTypes';
|
||||
|
||||
export class GiftCode {
|
||||
readonly code: string;
|
||||
readonly durationMonths: number;
|
||||
readonly createdAt: Date;
|
||||
readonly createdByUserId: UserID;
|
||||
readonly redeemedAt: Date | null;
|
||||
readonly redeemedByUserId: UserID | null;
|
||||
readonly stripePaymentIntentId: string | null;
|
||||
readonly visionarySequenceNumber: number | null;
|
||||
readonly checkoutSessionId: string | null;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: GiftCodeRow) {
|
||||
this.code = row.code;
|
||||
this.durationMonths = row.duration_months;
|
||||
this.createdAt = row.created_at;
|
||||
this.createdByUserId = row.created_by_user_id as UserID;
|
||||
this.redeemedAt = row.redeemed_at ?? null;
|
||||
this.redeemedByUserId = row.redeemed_by_user_id ? (row.redeemed_by_user_id as UserID) : null;
|
||||
this.stripePaymentIntentId = row.stripe_payment_intent_id ?? null;
|
||||
this.visionarySequenceNumber = row.visionary_sequence_number ?? null;
|
||||
this.checkoutSessionId = row.checkout_session_id ?? null;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): GiftCodeRow {
|
||||
return {
|
||||
code: this.code,
|
||||
duration_months: this.durationMonths,
|
||||
created_at: this.createdAt,
|
||||
created_by_user_id: this.createdByUserId,
|
||||
redeemed_at: this.redeemedAt,
|
||||
redeemed_by_user_id: this.redeemedByUserId,
|
||||
stripe_payment_intent_id: this.stripePaymentIntentId,
|
||||
visionary_sequence_number: this.visionarySequenceNumber,
|
||||
checkout_session_id: this.checkoutSessionId,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
129
packages/api/src/models/Guild.tsx
Normal file
129
packages/api/src/models/Guild.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, GuildID, UserID, VanityURLCode} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {GuildRow} from '@fluxer/api/src/database/types/GuildTypes';
|
||||
import {GuildSplashCardAlignment, type GuildSplashCardAlignmentValue} from '@fluxer/constants/src/GuildConstants';
|
||||
|
||||
export class Guild {
|
||||
readonly id: GuildID;
|
||||
readonly ownerId: UserID;
|
||||
readonly name: string;
|
||||
readonly vanityUrlCode: VanityURLCode | null;
|
||||
readonly iconHash: string | null;
|
||||
readonly bannerHash: string | null;
|
||||
readonly bannerWidth: number | null;
|
||||
readonly bannerHeight: number | null;
|
||||
readonly splashHash: string | null;
|
||||
readonly splashWidth: number | null;
|
||||
readonly splashHeight: number | null;
|
||||
readonly splashCardAlignment: GuildSplashCardAlignmentValue;
|
||||
readonly embedSplashHash: string | null;
|
||||
readonly embedSplashWidth: number | null;
|
||||
readonly embedSplashHeight: number | null;
|
||||
readonly features: Set<string>;
|
||||
readonly verificationLevel: number;
|
||||
readonly mfaLevel: number;
|
||||
readonly nsfwLevel: number;
|
||||
readonly explicitContentFilter: number;
|
||||
readonly defaultMessageNotifications: number;
|
||||
readonly systemChannelId: ChannelID | null;
|
||||
readonly systemChannelFlags: number;
|
||||
readonly rulesChannelId: ChannelID | null;
|
||||
readonly afkChannelId: ChannelID | null;
|
||||
readonly afkTimeout: number;
|
||||
readonly disabledOperations: number;
|
||||
readonly memberCount: number;
|
||||
readonly auditLogsIndexedAt: Date | null;
|
||||
readonly membersIndexedAt: Date | null;
|
||||
readonly messageHistoryCutoff: Date | null;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: GuildRow) {
|
||||
this.id = row.guild_id;
|
||||
this.ownerId = row.owner_id;
|
||||
this.name = row.name;
|
||||
this.vanityUrlCode = row.vanity_url_code ?? null;
|
||||
this.iconHash = row.icon_hash ?? null;
|
||||
this.bannerHash = row.banner_hash ?? null;
|
||||
this.bannerWidth = row.banner_width ?? null;
|
||||
this.bannerHeight = row.banner_height ?? null;
|
||||
this.splashHash = row.splash_hash ?? null;
|
||||
this.splashWidth = row.splash_width ?? null;
|
||||
this.splashHeight = row.splash_height ?? null;
|
||||
this.splashCardAlignment = row.splash_card_alignment ?? GuildSplashCardAlignment.CENTER;
|
||||
this.embedSplashHash = row.embed_splash_hash ?? null;
|
||||
this.embedSplashWidth = row.embed_splash_width ?? null;
|
||||
this.embedSplashHeight = row.embed_splash_height ?? null;
|
||||
this.features = row.features ?? new Set();
|
||||
this.verificationLevel = row.verification_level ?? 0;
|
||||
this.mfaLevel = row.mfa_level ?? 0;
|
||||
this.nsfwLevel = row.nsfw_level ?? 0;
|
||||
this.explicitContentFilter = row.explicit_content_filter ?? 0;
|
||||
this.defaultMessageNotifications = row.default_message_notifications ?? 0;
|
||||
this.systemChannelId = row.system_channel_id ?? null;
|
||||
this.systemChannelFlags = row.system_channel_flags ?? 0;
|
||||
this.rulesChannelId = row.rules_channel_id ?? null;
|
||||
this.afkChannelId = row.afk_channel_id ?? null;
|
||||
this.afkTimeout = row.afk_timeout ?? 0;
|
||||
this.disabledOperations = row.disabled_operations ?? 0;
|
||||
this.memberCount = row.member_count ?? 0;
|
||||
this.auditLogsIndexedAt = row.audit_logs_indexed_at ?? null;
|
||||
this.membersIndexedAt = row.members_indexed_at ?? null;
|
||||
this.messageHistoryCutoff = row.message_history_cutoff ?? null;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): GuildRow {
|
||||
return {
|
||||
guild_id: this.id,
|
||||
owner_id: this.ownerId,
|
||||
name: this.name,
|
||||
vanity_url_code: this.vanityUrlCode,
|
||||
icon_hash: this.iconHash,
|
||||
banner_hash: this.bannerHash,
|
||||
banner_width: this.bannerWidth,
|
||||
banner_height: this.bannerHeight,
|
||||
splash_hash: this.splashHash,
|
||||
splash_width: this.splashWidth,
|
||||
splash_height: this.splashHeight,
|
||||
splash_card_alignment: this.splashCardAlignment,
|
||||
embed_splash_hash: this.embedSplashHash,
|
||||
embed_splash_width: this.embedSplashWidth,
|
||||
embed_splash_height: this.embedSplashHeight,
|
||||
features: this.features.size > 0 ? this.features : null,
|
||||
verification_level: this.verificationLevel,
|
||||
mfa_level: this.mfaLevel,
|
||||
nsfw_level: this.nsfwLevel,
|
||||
explicit_content_filter: this.explicitContentFilter,
|
||||
default_message_notifications: this.defaultMessageNotifications,
|
||||
system_channel_id: this.systemChannelId,
|
||||
system_channel_flags: this.systemChannelFlags,
|
||||
rules_channel_id: this.rulesChannelId,
|
||||
afk_channel_id: this.afkChannelId,
|
||||
afk_timeout: this.afkTimeout,
|
||||
disabled_operations: this.disabledOperations,
|
||||
member_count: this.memberCount,
|
||||
audit_logs_indexed_at: this.auditLogsIndexedAt,
|
||||
members_indexed_at: this.membersIndexedAt,
|
||||
message_history_cutoff: this.messageHistoryCutoff,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
68
packages/api/src/models/GuildAuditLog.tsx
Normal file
68
packages/api/src/models/GuildAuditLog.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {GuildID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {GuildAuditLogRow} from '@fluxer/api/src/database/types/GuildTypes';
|
||||
import type {GuildAuditLogChange} from '@fluxer/api/src/guild/GuildAuditLogTypes';
|
||||
import {snowflakeToDate} from '@fluxer/snowflake/src/Snowflake';
|
||||
|
||||
export class GuildAuditLog {
|
||||
readonly guildId: GuildID;
|
||||
readonly logId: bigint;
|
||||
readonly userId: UserID;
|
||||
readonly targetId: string | null;
|
||||
readonly actionType: number;
|
||||
readonly reason: string | null;
|
||||
readonly options: Map<string, string>;
|
||||
readonly changes: GuildAuditLogChange | null;
|
||||
readonly createdAt: Date;
|
||||
|
||||
constructor(row: GuildAuditLogRow) {
|
||||
this.guildId = row.guild_id;
|
||||
this.logId = row.log_id;
|
||||
this.userId = row.user_id;
|
||||
this.targetId = row.target_id ?? null;
|
||||
this.actionType = row.action_type;
|
||||
this.reason = row.reason ?? null;
|
||||
this.options = row.options ?? new Map();
|
||||
this.changes = row.changes ? this.safeParseChanges(row.changes) : null;
|
||||
this.createdAt = snowflakeToDate(this.logId);
|
||||
}
|
||||
|
||||
toRow(): GuildAuditLogRow {
|
||||
return {
|
||||
guild_id: this.guildId,
|
||||
log_id: this.logId,
|
||||
user_id: this.userId,
|
||||
target_id: this.targetId,
|
||||
action_type: this.actionType,
|
||||
reason: this.reason,
|
||||
options: this.options.size > 0 ? this.options : null,
|
||||
changes: this.changes ? JSON.stringify(this.changes) : null,
|
||||
};
|
||||
}
|
||||
|
||||
private safeParseChanges(raw: string): GuildAuditLogChange | null {
|
||||
try {
|
||||
return JSON.parse(raw) as GuildAuditLogChange;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
packages/api/src/models/GuildBan.tsx
Normal file
53
packages/api/src/models/GuildBan.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {GuildID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {GuildBanRow} from '@fluxer/api/src/database/types/GuildTypes';
|
||||
|
||||
export class GuildBan {
|
||||
readonly guildId: GuildID;
|
||||
readonly userId: UserID;
|
||||
readonly moderatorId: UserID;
|
||||
readonly bannedAt: Date;
|
||||
readonly expiresAt: Date | null;
|
||||
readonly reason: string | null;
|
||||
readonly ipAddress: string | null;
|
||||
|
||||
constructor(row: GuildBanRow) {
|
||||
this.guildId = row.guild_id;
|
||||
this.userId = row.user_id;
|
||||
this.moderatorId = row.moderator_id;
|
||||
this.bannedAt = row.banned_at;
|
||||
this.expiresAt = row.expires_at ?? null;
|
||||
this.reason = row.reason ?? null;
|
||||
this.ipAddress = row.ip ?? null;
|
||||
}
|
||||
|
||||
toRow(): GuildBanRow {
|
||||
return {
|
||||
guild_id: this.guildId,
|
||||
user_id: this.userId,
|
||||
moderator_id: this.moderatorId,
|
||||
banned_at: this.bannedAt,
|
||||
expires_at: this.expiresAt,
|
||||
reason: this.reason,
|
||||
ip: this.ipAddress,
|
||||
};
|
||||
}
|
||||
}
|
||||
44
packages/api/src/models/GuildChannelOverride.tsx
Normal file
44
packages/api/src/models/GuildChannelOverride.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelOverride} from '@fluxer/api/src/database/types/UserTypes';
|
||||
import {MuteConfiguration} from '@fluxer/api/src/models/MuteConfiguration';
|
||||
|
||||
export class GuildChannelOverride {
|
||||
readonly collapsed: boolean;
|
||||
readonly messageNotifications: number | null;
|
||||
readonly muted: boolean;
|
||||
readonly muteConfig: MuteConfiguration | null;
|
||||
|
||||
constructor(override: ChannelOverride) {
|
||||
this.collapsed = override.collapsed ?? false;
|
||||
this.messageNotifications = override.message_notifications ?? null;
|
||||
this.muted = override.muted ?? false;
|
||||
this.muteConfig = override.mute_config ? new MuteConfiguration(override.mute_config) : null;
|
||||
}
|
||||
|
||||
toChannelOverride(): ChannelOverride {
|
||||
return {
|
||||
collapsed: this.collapsed,
|
||||
message_notifications: this.messageNotifications,
|
||||
muted: this.muted,
|
||||
mute_config: this.muteConfig?.toMuteConfig() ?? null,
|
||||
};
|
||||
}
|
||||
}
|
||||
50
packages/api/src/models/GuildEmoji.tsx
Normal file
50
packages/api/src/models/GuildEmoji.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {EmojiID, GuildID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {GuildEmojiRow} from '@fluxer/api/src/database/types/GuildTypes';
|
||||
|
||||
export class GuildEmoji {
|
||||
readonly guildId: GuildID;
|
||||
readonly id: EmojiID;
|
||||
readonly name: string;
|
||||
readonly creatorId: UserID;
|
||||
readonly isAnimated: boolean;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: GuildEmojiRow) {
|
||||
this.guildId = row.guild_id;
|
||||
this.id = row.emoji_id;
|
||||
this.name = row.name;
|
||||
this.creatorId = row.creator_id;
|
||||
this.isAnimated = row.animated ?? false;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): GuildEmojiRow {
|
||||
return {
|
||||
guild_id: this.guildId,
|
||||
emoji_id: this.id,
|
||||
name: this.name,
|
||||
creator_id: this.creatorId,
|
||||
animated: this.isAnimated,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
105
packages/api/src/models/GuildMember.tsx
Normal file
105
packages/api/src/models/GuildMember.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {GuildID, InviteCode, RoleID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {GuildMemberRow} from '@fluxer/api/src/database/types/GuildTypes';
|
||||
import {GuildMemberProfileFlags} from '@fluxer/constants/src/GuildConstants';
|
||||
|
||||
export class GuildMember {
|
||||
readonly guildId: GuildID;
|
||||
readonly userId: UserID;
|
||||
readonly joinedAt: Date;
|
||||
readonly nickname: string | null;
|
||||
readonly avatarHash: string | null;
|
||||
readonly bannerHash: string | null;
|
||||
readonly bio: string | null;
|
||||
readonly pronouns: string | null;
|
||||
readonly accentColor: number | null;
|
||||
readonly joinSourceType: number | null;
|
||||
readonly sourceInviteCode: InviteCode | null;
|
||||
readonly inviterId: UserID | null;
|
||||
readonly isDeaf: boolean;
|
||||
readonly isMute: boolean;
|
||||
readonly communicationDisabledUntil: Date | null;
|
||||
readonly roleIds: Set<RoleID>;
|
||||
readonly isPremiumSanitized: boolean;
|
||||
readonly isTemporary: boolean;
|
||||
readonly profileFlags: number;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: GuildMemberRow) {
|
||||
this.guildId = row.guild_id;
|
||||
this.userId = row.user_id;
|
||||
this.joinedAt = row.joined_at;
|
||||
this.nickname = row.nick ?? null;
|
||||
this.avatarHash = row.avatar_hash ?? null;
|
||||
this.bannerHash = row.banner_hash ?? null;
|
||||
this.bio = row.bio ?? null;
|
||||
this.pronouns = row.pronouns ?? null;
|
||||
this.accentColor = row.accent_color ?? null;
|
||||
this.joinSourceType = row.join_source_type ?? null;
|
||||
this.sourceInviteCode = row.source_invite_code ?? null;
|
||||
this.inviterId = row.inviter_id ?? null;
|
||||
this.isDeaf = row.deaf ?? false;
|
||||
this.isMute = row.mute ?? false;
|
||||
this.communicationDisabledUntil = row.communication_disabled_until ?? null;
|
||||
this.roleIds = row.role_ids ?? new Set();
|
||||
this.isPremiumSanitized = row.is_premium_sanitized ?? false;
|
||||
this.isTemporary = row.temporary ?? false;
|
||||
this.profileFlags = row.profile_flags ?? 0;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
hasProfileFlag(flag: number): boolean {
|
||||
return (this.profileFlags & flag) === flag;
|
||||
}
|
||||
|
||||
isAvatarUnset(): boolean {
|
||||
return this.hasProfileFlag(GuildMemberProfileFlags.AVATAR_UNSET);
|
||||
}
|
||||
|
||||
isBannerUnset(): boolean {
|
||||
return this.hasProfileFlag(GuildMemberProfileFlags.BANNER_UNSET);
|
||||
}
|
||||
|
||||
toRow(): GuildMemberRow {
|
||||
return {
|
||||
guild_id: this.guildId,
|
||||
user_id: this.userId,
|
||||
joined_at: this.joinedAt,
|
||||
nick: this.nickname,
|
||||
avatar_hash: this.avatarHash,
|
||||
banner_hash: this.bannerHash,
|
||||
bio: this.bio,
|
||||
pronouns: this.pronouns,
|
||||
accent_color: this.accentColor,
|
||||
join_source_type: this.joinSourceType,
|
||||
source_invite_code: this.sourceInviteCode,
|
||||
inviter_id: this.inviterId,
|
||||
deaf: this.isDeaf,
|
||||
mute: this.isMute,
|
||||
communication_disabled_until: this.communicationDisabledUntil,
|
||||
role_ids: this.roleIds.size > 0 ? this.roleIds : null,
|
||||
is_premium_sanitized: this.isPremiumSanitized,
|
||||
temporary: this.isTemporary,
|
||||
profile_flags: this.profileFlags || null,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
72
packages/api/src/models/GuildRole.tsx
Normal file
72
packages/api/src/models/GuildRole.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {GuildID, RoleID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {GuildRoleRow} from '@fluxer/api/src/database/types/GuildTypes';
|
||||
|
||||
export class GuildRole {
|
||||
readonly guildId: GuildID;
|
||||
readonly id: RoleID;
|
||||
readonly name: string;
|
||||
readonly permissions: bigint;
|
||||
readonly position: number;
|
||||
readonly hoistPosition: number | null;
|
||||
readonly color: number;
|
||||
readonly iconHash: string | null;
|
||||
readonly unicodeEmoji: string | null;
|
||||
readonly isHoisted: boolean;
|
||||
readonly isMentionable: boolean;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: GuildRoleRow) {
|
||||
this.guildId = row.guild_id;
|
||||
this.id = row.role_id;
|
||||
this.name = row.name;
|
||||
this.permissions = row.permissions;
|
||||
this.position = row.position;
|
||||
this.hoistPosition = row.hoist_position ?? null;
|
||||
this.color = row.color ?? 0;
|
||||
this.iconHash = row.icon_hash ?? null;
|
||||
this.unicodeEmoji = row.unicode_emoji ?? null;
|
||||
this.isHoisted = row.hoist ?? false;
|
||||
this.isMentionable = row.mentionable ?? false;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
get effectiveHoistPosition(): number {
|
||||
return this.hoistPosition ?? this.position;
|
||||
}
|
||||
|
||||
toRow(): GuildRoleRow {
|
||||
return {
|
||||
guild_id: this.guildId,
|
||||
role_id: this.id,
|
||||
name: this.name,
|
||||
permissions: this.permissions,
|
||||
position: this.position,
|
||||
hoist_position: this.hoistPosition,
|
||||
color: this.color,
|
||||
icon_hash: this.iconHash,
|
||||
unicode_emoji: this.unicodeEmoji,
|
||||
hoist: this.isHoisted,
|
||||
mentionable: this.isMentionable,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
56
packages/api/src/models/GuildSticker.tsx
Normal file
56
packages/api/src/models/GuildSticker.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {GuildID, StickerID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {GuildStickerRow} from '@fluxer/api/src/database/types/GuildTypes';
|
||||
|
||||
export class GuildSticker {
|
||||
readonly guildId: GuildID;
|
||||
readonly id: StickerID;
|
||||
readonly name: string;
|
||||
readonly description: string | null;
|
||||
readonly animated: boolean;
|
||||
readonly tags: Array<string>;
|
||||
readonly creatorId: UserID;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: GuildStickerRow) {
|
||||
this.guildId = row.guild_id;
|
||||
this.id = row.sticker_id;
|
||||
this.name = row.name;
|
||||
this.description = row.description ?? null;
|
||||
this.animated = row.animated;
|
||||
this.tags = row.tags ?? [];
|
||||
this.creatorId = row.creator_id;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): GuildStickerRow {
|
||||
return {
|
||||
guild_id: this.guildId,
|
||||
sticker_id: this.id,
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
animated: this.animated,
|
||||
tags: this.tags.length > 0 ? this.tags : null,
|
||||
creator_id: this.creatorId,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
65
packages/api/src/models/Invite.tsx
Normal file
65
packages/api/src/models/Invite.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, GuildID, InviteCode, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {InviteRow} from '@fluxer/api/src/database/types/ChannelTypes';
|
||||
|
||||
export class Invite {
|
||||
readonly code: InviteCode;
|
||||
readonly type: number;
|
||||
readonly guildId: GuildID | null;
|
||||
readonly channelId: ChannelID | null;
|
||||
readonly inviterId: UserID | null;
|
||||
readonly createdAt: Date;
|
||||
readonly uses: number;
|
||||
readonly maxUses: number;
|
||||
readonly maxAge: number;
|
||||
readonly temporary: boolean;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: InviteRow) {
|
||||
this.code = row.code;
|
||||
this.type = row.type;
|
||||
this.guildId = row.guild_id ?? null;
|
||||
this.channelId = row.channel_id ?? null;
|
||||
this.inviterId = row.inviter_id ?? null;
|
||||
this.createdAt = row.created_at;
|
||||
this.uses = row.uses ?? 0;
|
||||
this.maxUses = row.max_uses ?? 0;
|
||||
this.maxAge = row.max_age ?? 0;
|
||||
this.temporary = row.temporary ?? false;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): InviteRow {
|
||||
return {
|
||||
code: this.code,
|
||||
type: this.type,
|
||||
guild_id: this.guildId,
|
||||
channel_id: this.channelId,
|
||||
inviter_id: this.inviterId,
|
||||
created_at: this.createdAt,
|
||||
uses: this.uses,
|
||||
max_uses: this.maxUses,
|
||||
max_age: this.maxAge,
|
||||
temporary: this.temporary,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
111
packages/api/src/models/Message.tsx
Normal file
111
packages/api/src/models/Message.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, MessageID, RoleID, UserID, WebhookID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {MessageRow} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
import {Attachment} from '@fluxer/api/src/models/Attachment';
|
||||
import {CallInfo} from '@fluxer/api/src/models/CallInfo';
|
||||
import {Embed} from '@fluxer/api/src/models/Embed';
|
||||
import {MessageRef} from '@fluxer/api/src/models/MessageRef';
|
||||
import {MessageSnapshot} from '@fluxer/api/src/models/MessageSnapshot';
|
||||
import {StickerItem} from '@fluxer/api/src/models/StickerItem';
|
||||
|
||||
export class Message {
|
||||
readonly channelId: ChannelID;
|
||||
readonly bucket: number;
|
||||
readonly id: MessageID;
|
||||
readonly authorId: UserID | null;
|
||||
readonly type: number;
|
||||
readonly webhookId: WebhookID | null;
|
||||
readonly webhookName: string | null;
|
||||
readonly webhookAvatarHash: string | null;
|
||||
readonly content: string | null;
|
||||
readonly editedTimestamp: Date | null;
|
||||
readonly pinnedTimestamp: Date | null;
|
||||
readonly flags: number;
|
||||
readonly mentionEveryone: boolean;
|
||||
readonly mentionedUserIds: Set<UserID>;
|
||||
readonly mentionedRoleIds: Set<RoleID>;
|
||||
readonly mentionedChannelIds: Set<ChannelID>;
|
||||
readonly attachments: Array<Attachment>;
|
||||
readonly embeds: Array<Embed>;
|
||||
readonly stickers: Array<StickerItem>;
|
||||
readonly reference: MessageRef | null;
|
||||
readonly messageSnapshots: Array<MessageSnapshot>;
|
||||
readonly call: CallInfo | null;
|
||||
readonly hasReaction: boolean | null;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: MessageRow) {
|
||||
this.channelId = row.channel_id;
|
||||
this.bucket = row.bucket;
|
||||
this.id = row.message_id;
|
||||
this.authorId = row.author_id ?? null;
|
||||
this.type = row.type;
|
||||
this.webhookId = row.webhook_id ?? null;
|
||||
this.webhookName = row.webhook_name ?? null;
|
||||
this.webhookAvatarHash = row.webhook_avatar_hash ?? null;
|
||||
this.content = row.content ?? null;
|
||||
this.editedTimestamp = row.edited_timestamp ?? null;
|
||||
this.pinnedTimestamp = row.pinned_timestamp ?? null;
|
||||
this.flags = row.flags ?? 0;
|
||||
this.mentionEveryone = row.mention_everyone ?? false;
|
||||
this.mentionedUserIds = row.mention_users ?? new Set();
|
||||
this.mentionedRoleIds = row.mention_roles ?? new Set();
|
||||
this.mentionedChannelIds = row.mention_channels ?? new Set();
|
||||
this.attachments = (row.attachments ?? []).map((att) => new Attachment(att));
|
||||
this.embeds = (row.embeds ?? []).map((embed) => new Embed(embed));
|
||||
this.stickers = (row.sticker_items ?? []).map((sticker) => new StickerItem(sticker));
|
||||
this.reference = row.message_reference ? new MessageRef(row.message_reference) : null;
|
||||
this.messageSnapshots = (row.message_snapshots ?? []).map((snapshot) => new MessageSnapshot(snapshot));
|
||||
this.call = row.call ? new CallInfo(row.call) : null;
|
||||
this.hasReaction = row.has_reaction ?? null;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): MessageRow {
|
||||
return {
|
||||
channel_id: this.channelId,
|
||||
bucket: this.bucket,
|
||||
message_id: this.id,
|
||||
author_id: this.authorId,
|
||||
type: this.type,
|
||||
webhook_id: this.webhookId,
|
||||
webhook_name: this.webhookName,
|
||||
webhook_avatar_hash: this.webhookAvatarHash,
|
||||
content: this.content,
|
||||
edited_timestamp: this.editedTimestamp,
|
||||
pinned_timestamp: this.pinnedTimestamp,
|
||||
flags: this.flags,
|
||||
mention_everyone: this.mentionEveryone,
|
||||
mention_users: this.mentionedUserIds.size > 0 ? this.mentionedUserIds : null,
|
||||
mention_roles: this.mentionedRoleIds.size > 0 ? this.mentionedRoleIds : null,
|
||||
mention_channels: this.mentionedChannelIds.size > 0 ? this.mentionedChannelIds : null,
|
||||
attachments: this.attachments.length > 0 ? this.attachments.map((att) => att.toMessageAttachment()) : null,
|
||||
embeds: this.embeds.length > 0 ? this.embeds.map((embed) => embed.toMessageEmbed()) : null,
|
||||
sticker_items: this.stickers.length > 0 ? this.stickers.map((sticker) => sticker.toMessageStickerItem()) : null,
|
||||
message_reference: this.reference?.toMessageReference() ?? null,
|
||||
message_snapshots:
|
||||
this.messageSnapshots.length > 0 ? this.messageSnapshots.map((snapshot) => snapshot.toMessageSnapshot()) : null,
|
||||
call: this.call?.toMessageCall() ?? null,
|
||||
has_reaction: this.hasReaction ?? null,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
53
packages/api/src/models/MessageReaction.tsx
Normal file
53
packages/api/src/models/MessageReaction.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, EmojiID, MessageID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {MessageReactionRow} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
|
||||
export class MessageReaction {
|
||||
readonly channelId: ChannelID;
|
||||
readonly bucket: number;
|
||||
readonly messageId: MessageID;
|
||||
readonly userId: UserID;
|
||||
readonly emojiId: EmojiID;
|
||||
readonly emojiName: string;
|
||||
readonly isEmojiAnimated: boolean;
|
||||
|
||||
constructor(row: MessageReactionRow) {
|
||||
this.channelId = row.channel_id;
|
||||
this.bucket = row.bucket;
|
||||
this.messageId = row.message_id;
|
||||
this.userId = row.user_id;
|
||||
this.emojiId = row.emoji_id;
|
||||
this.emojiName = row.emoji_name;
|
||||
this.isEmojiAnimated = row.emoji_animated ?? false;
|
||||
}
|
||||
|
||||
toRow(): MessageReactionRow {
|
||||
return {
|
||||
channel_id: this.channelId,
|
||||
bucket: this.bucket,
|
||||
message_id: this.messageId,
|
||||
user_id: this.userId,
|
||||
emoji_id: this.emojiId,
|
||||
emoji_name: this.emojiName,
|
||||
emoji_animated: this.isEmojiAnimated,
|
||||
};
|
||||
}
|
||||
}
|
||||
44
packages/api/src/models/MessageRef.tsx
Normal file
44
packages/api/src/models/MessageRef.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, GuildID, MessageID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {MessageReference} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
|
||||
export class MessageRef {
|
||||
readonly channelId: ChannelID;
|
||||
readonly messageId: MessageID;
|
||||
readonly guildId: GuildID | null;
|
||||
readonly type: number;
|
||||
|
||||
constructor(ref: MessageReference) {
|
||||
this.channelId = ref.channel_id;
|
||||
this.messageId = ref.message_id;
|
||||
this.guildId = ref.guild_id ?? null;
|
||||
this.type = ref.type;
|
||||
}
|
||||
|
||||
toMessageReference(): MessageReference {
|
||||
return {
|
||||
channel_id: this.channelId,
|
||||
message_id: this.messageId,
|
||||
guild_id: this.guildId,
|
||||
type: this.type,
|
||||
};
|
||||
}
|
||||
}
|
||||
68
packages/api/src/models/MessageSnapshot.tsx
Normal file
68
packages/api/src/models/MessageSnapshot.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, RoleID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {MessageSnapshot as CassandraMessageSnapshot} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
import {Attachment} from '@fluxer/api/src/models/Attachment';
|
||||
import {Embed} from '@fluxer/api/src/models/Embed';
|
||||
import {StickerItem} from '@fluxer/api/src/models/StickerItem';
|
||||
|
||||
export class MessageSnapshot {
|
||||
readonly content: string | null;
|
||||
readonly timestamp: Date;
|
||||
readonly editedTimestamp: Date | null;
|
||||
readonly mentionedUserIds: Set<UserID>;
|
||||
readonly mentionedRoleIds: Set<RoleID>;
|
||||
readonly mentionedChannelIds: Set<ChannelID>;
|
||||
readonly attachments: Array<Attachment>;
|
||||
readonly embeds: Array<Embed>;
|
||||
readonly stickers: Array<StickerItem>;
|
||||
readonly type: number;
|
||||
readonly flags: number;
|
||||
|
||||
constructor(snapshot: CassandraMessageSnapshot) {
|
||||
this.content = snapshot.content ?? null;
|
||||
this.timestamp = new Date(snapshot.timestamp);
|
||||
this.editedTimestamp = snapshot.edited_timestamp ? new Date(snapshot.edited_timestamp) : null;
|
||||
this.mentionedUserIds = snapshot.mention_users ?? new Set();
|
||||
this.mentionedRoleIds = snapshot.mention_roles ?? new Set();
|
||||
this.mentionedChannelIds = snapshot.mention_channels ?? new Set();
|
||||
this.attachments = (snapshot.attachments ?? []).map((att) => new Attachment(att));
|
||||
this.embeds = (snapshot.embeds ?? []).map((embed) => new Embed(embed));
|
||||
this.stickers = (snapshot.sticker_items ?? []).map((sticker) => new StickerItem(sticker));
|
||||
this.type = snapshot.type;
|
||||
this.flags = snapshot.flags;
|
||||
}
|
||||
|
||||
toMessageSnapshot(): CassandraMessageSnapshot {
|
||||
return {
|
||||
content: this.content,
|
||||
timestamp: this.timestamp,
|
||||
edited_timestamp: this.editedTimestamp,
|
||||
mention_users: this.mentionedUserIds.size > 0 ? this.mentionedUserIds : null,
|
||||
mention_roles: this.mentionedRoleIds.size > 0 ? this.mentionedRoleIds : null,
|
||||
mention_channels: this.mentionedChannelIds.size > 0 ? this.mentionedChannelIds : null,
|
||||
attachments: this.attachments.length > 0 ? this.attachments.map((att) => att.toMessageAttachment()) : null,
|
||||
embeds: this.embeds.length > 0 ? this.embeds.map((embed) => embed.toMessageEmbed()) : null,
|
||||
sticker_items: this.stickers.length > 0 ? this.stickers.map((sticker) => sticker.toMessageStickerItem()) : null,
|
||||
type: this.type,
|
||||
flags: this.flags,
|
||||
};
|
||||
}
|
||||
}
|
||||
42
packages/api/src/models/MfaBackupCode.tsx
Normal file
42
packages/api/src/models/MfaBackupCode.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import {createMfaBackupCode} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {MfaBackupCodeRow} from '@fluxer/api/src/database/types/AuthTypes';
|
||||
|
||||
export class MfaBackupCode {
|
||||
readonly userId: UserID;
|
||||
readonly code: string;
|
||||
readonly consumed: boolean;
|
||||
|
||||
constructor(row: MfaBackupCodeRow) {
|
||||
this.userId = row.user_id;
|
||||
this.code = row.code;
|
||||
this.consumed = row.consumed ?? false;
|
||||
}
|
||||
|
||||
toRow(): MfaBackupCodeRow {
|
||||
return {
|
||||
user_id: this.userId,
|
||||
code: createMfaBackupCode(this.code),
|
||||
consumed: this.consumed,
|
||||
};
|
||||
}
|
||||
}
|
||||
37
packages/api/src/models/MuteConfiguration.tsx
Normal file
37
packages/api/src/models/MuteConfiguration.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {MuteConfig} from '@fluxer/api/src/database/types/UserTypes';
|
||||
|
||||
export class MuteConfiguration {
|
||||
readonly endTime: Date | null;
|
||||
readonly selectedTimeWindow: number | null;
|
||||
|
||||
constructor(config: MuteConfig) {
|
||||
this.endTime = config.end_time ?? null;
|
||||
this.selectedTimeWindow = config.selected_time_window ?? null;
|
||||
}
|
||||
|
||||
toMuteConfig(): MuteConfig {
|
||||
return {
|
||||
end_time: this.endTime,
|
||||
selected_time_window: this.selectedTimeWindow,
|
||||
};
|
||||
}
|
||||
}
|
||||
51
packages/api/src/models/OAuth2AccessToken.tsx
Normal file
51
packages/api/src/models/OAuth2AccessToken.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ApplicationID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {OAuth2AccessTokenRow} from '@fluxer/api/src/database/types/OAuth2Types';
|
||||
|
||||
export class OAuth2AccessToken {
|
||||
readonly token: string;
|
||||
readonly applicationId: ApplicationID;
|
||||
readonly userId: UserID | null;
|
||||
readonly scope: Set<string>;
|
||||
readonly createdAt: Date;
|
||||
|
||||
constructor(row: OAuth2AccessTokenRow) {
|
||||
this.token = row.token_;
|
||||
this.applicationId = row.application_id;
|
||||
this.userId = row.user_id;
|
||||
this.scope = row.scope;
|
||||
this.createdAt = row.created_at;
|
||||
}
|
||||
|
||||
toRow(): OAuth2AccessTokenRow {
|
||||
return {
|
||||
token_: this.token,
|
||||
application_id: this.applicationId,
|
||||
user_id: this.userId,
|
||||
scope: this.scope,
|
||||
created_at: this.createdAt,
|
||||
};
|
||||
}
|
||||
|
||||
hasScope(scope: string): boolean {
|
||||
return this.scope.has(scope);
|
||||
}
|
||||
}
|
||||
57
packages/api/src/models/OAuth2AuthorizationCode.tsx
Normal file
57
packages/api/src/models/OAuth2AuthorizationCode.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ApplicationID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {OAuth2AuthorizationCodeRow} from '@fluxer/api/src/database/types/OAuth2Types';
|
||||
|
||||
export class OAuth2AuthorizationCode {
|
||||
readonly code: string;
|
||||
readonly applicationId: ApplicationID;
|
||||
readonly userId: UserID;
|
||||
readonly redirectUri: string;
|
||||
readonly scope: Set<string>;
|
||||
readonly nonce: string | null;
|
||||
readonly createdAt: Date;
|
||||
|
||||
constructor(row: OAuth2AuthorizationCodeRow) {
|
||||
this.code = row.code;
|
||||
this.applicationId = row.application_id;
|
||||
this.userId = row.user_id;
|
||||
this.redirectUri = row.redirect_uri;
|
||||
this.scope = row.scope;
|
||||
this.nonce = row.nonce;
|
||||
this.createdAt = row.created_at;
|
||||
}
|
||||
|
||||
toRow(): OAuth2AuthorizationCodeRow {
|
||||
return {
|
||||
code: this.code,
|
||||
application_id: this.applicationId,
|
||||
user_id: this.userId,
|
||||
redirect_uri: this.redirectUri,
|
||||
scope: this.scope,
|
||||
nonce: this.nonce,
|
||||
created_at: this.createdAt,
|
||||
};
|
||||
}
|
||||
|
||||
hasScope(scope: string): boolean {
|
||||
return this.scope.has(scope);
|
||||
}
|
||||
}
|
||||
51
packages/api/src/models/OAuth2RefreshToken.tsx
Normal file
51
packages/api/src/models/OAuth2RefreshToken.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ApplicationID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {OAuth2RefreshTokenRow} from '@fluxer/api/src/database/types/OAuth2Types';
|
||||
|
||||
export class OAuth2RefreshToken {
|
||||
readonly token: string;
|
||||
readonly applicationId: ApplicationID;
|
||||
readonly userId: UserID;
|
||||
readonly scope: Set<string>;
|
||||
readonly createdAt: Date;
|
||||
|
||||
constructor(row: OAuth2RefreshTokenRow) {
|
||||
this.token = row.token_;
|
||||
this.applicationId = row.application_id;
|
||||
this.userId = row.user_id;
|
||||
this.scope = row.scope;
|
||||
this.createdAt = row.created_at;
|
||||
}
|
||||
|
||||
toRow(): OAuth2RefreshTokenRow {
|
||||
return {
|
||||
token_: this.token,
|
||||
application_id: this.applicationId,
|
||||
user_id: this.userId,
|
||||
scope: this.scope,
|
||||
created_at: this.createdAt,
|
||||
};
|
||||
}
|
||||
|
||||
hasScope(scope: string): boolean {
|
||||
return this.scope.has(scope);
|
||||
}
|
||||
}
|
||||
42
packages/api/src/models/PasswordResetToken.tsx
Normal file
42
packages/api/src/models/PasswordResetToken.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import {createPasswordResetToken} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {PasswordResetTokenRow} from '@fluxer/api/src/database/types/AuthTypes';
|
||||
|
||||
export class PasswordResetToken {
|
||||
readonly token: string;
|
||||
readonly userId: UserID;
|
||||
readonly email: string;
|
||||
|
||||
constructor(row: PasswordResetTokenRow) {
|
||||
this.token = row.token_;
|
||||
this.userId = row.user_id;
|
||||
this.email = row.email;
|
||||
}
|
||||
|
||||
toRow(): PasswordResetTokenRow {
|
||||
return {
|
||||
token_: createPasswordResetToken(this.token),
|
||||
user_id: this.userId,
|
||||
email: this.email,
|
||||
};
|
||||
}
|
||||
}
|
||||
80
packages/api/src/models/Payment.tsx
Normal file
80
packages/api/src/models/Payment.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {PaymentRow} from '@fluxer/api/src/database/types/PaymentTypes';
|
||||
|
||||
export class Payment {
|
||||
readonly checkoutSessionId: string;
|
||||
readonly userId: UserID;
|
||||
readonly stripeCustomerId: string | null;
|
||||
readonly paymentIntentId: string | null;
|
||||
readonly subscriptionId: string | null;
|
||||
readonly invoiceId: string | null;
|
||||
readonly priceId: string | null;
|
||||
readonly productType: string | null;
|
||||
readonly amountCents: number;
|
||||
readonly currency: string;
|
||||
readonly status: string;
|
||||
readonly isGift: boolean;
|
||||
readonly giftCode: string | null;
|
||||
readonly createdAt: Date;
|
||||
readonly completedAt: Date | null;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: PaymentRow) {
|
||||
this.checkoutSessionId = row.checkout_session_id;
|
||||
this.userId = row.user_id as UserID;
|
||||
this.stripeCustomerId = row.stripe_customer_id ?? null;
|
||||
this.paymentIntentId = row.payment_intent_id ?? null;
|
||||
this.subscriptionId = row.subscription_id ?? null;
|
||||
this.invoiceId = row.invoice_id ?? null;
|
||||
this.priceId = row.price_id ?? null;
|
||||
this.productType = row.product_type ?? null;
|
||||
this.amountCents = row.amount_cents;
|
||||
this.currency = row.currency;
|
||||
this.status = row.status;
|
||||
this.isGift = row.is_gift;
|
||||
this.giftCode = row.gift_code ?? null;
|
||||
this.createdAt = row.created_at;
|
||||
this.completedAt = row.completed_at ?? null;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): PaymentRow {
|
||||
return {
|
||||
checkout_session_id: this.checkoutSessionId,
|
||||
user_id: this.userId,
|
||||
stripe_customer_id: this.stripeCustomerId,
|
||||
payment_intent_id: this.paymentIntentId,
|
||||
subscription_id: this.subscriptionId,
|
||||
invoice_id: this.invoiceId,
|
||||
price_id: this.priceId,
|
||||
product_type: this.productType,
|
||||
amount_cents: this.amountCents,
|
||||
currency: this.currency,
|
||||
status: this.status,
|
||||
is_gift: this.isGift,
|
||||
gift_code: this.giftCode,
|
||||
created_at: this.createdAt,
|
||||
completed_at: this.completedAt,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
50
packages/api/src/models/PushSubscription.tsx
Normal file
50
packages/api/src/models/PushSubscription.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {PushSubscriptionRow} from '@fluxer/api/src/database/types/UserTypes';
|
||||
|
||||
export class PushSubscription {
|
||||
readonly userId: UserID;
|
||||
readonly subscriptionId: string;
|
||||
readonly endpoint: string;
|
||||
readonly p256dhKey: string;
|
||||
readonly authKey: string;
|
||||
readonly userAgent: string | null;
|
||||
|
||||
constructor(row: PushSubscriptionRow) {
|
||||
this.userId = row.user_id;
|
||||
this.subscriptionId = row.subscription_id;
|
||||
this.endpoint = row.endpoint;
|
||||
this.p256dhKey = row.p256dh_key;
|
||||
this.authKey = row.auth_key;
|
||||
this.userAgent = row.user_agent ?? null;
|
||||
}
|
||||
|
||||
toRow(): PushSubscriptionRow {
|
||||
return {
|
||||
user_id: this.userId,
|
||||
subscription_id: this.subscriptionId,
|
||||
endpoint: this.endpoint,
|
||||
p256dh_key: this.p256dhKey,
|
||||
auth_key: this.authKey,
|
||||
user_agent: this.userAgent,
|
||||
};
|
||||
}
|
||||
}
|
||||
47
packages/api/src/models/ReadState.tsx
Normal file
47
packages/api/src/models/ReadState.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, MessageID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {ReadStateRow} from '@fluxer/api/src/database/types/ChannelTypes';
|
||||
|
||||
export class ReadState {
|
||||
readonly userId: UserID;
|
||||
readonly channelId: ChannelID;
|
||||
readonly lastMessageId: MessageID | null;
|
||||
readonly mentionCount: number;
|
||||
readonly lastPinTimestamp: Date | null;
|
||||
|
||||
constructor(row: ReadStateRow) {
|
||||
this.userId = row.user_id;
|
||||
this.channelId = row.channel_id;
|
||||
this.lastMessageId = row.message_id ?? null;
|
||||
this.mentionCount = row.mention_count ?? 0;
|
||||
this.lastPinTimestamp = row.last_pin_timestamp ?? null;
|
||||
}
|
||||
|
||||
toRow(): ReadStateRow {
|
||||
return {
|
||||
user_id: this.userId,
|
||||
channel_id: this.channelId,
|
||||
message_id: this.lastMessageId,
|
||||
mention_count: this.mentionCount,
|
||||
last_pin_timestamp: this.lastPinTimestamp,
|
||||
};
|
||||
}
|
||||
}
|
||||
50
packages/api/src/models/RecentMention.tsx
Normal file
50
packages/api/src/models/RecentMention.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, GuildID, MessageID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {RecentMentionRow} from '@fluxer/api/src/database/types/UserTypes';
|
||||
|
||||
export class RecentMention {
|
||||
readonly userId: UserID;
|
||||
readonly channelId: ChannelID;
|
||||
readonly messageId: MessageID;
|
||||
readonly guildId: GuildID;
|
||||
readonly isEveryone: boolean;
|
||||
readonly isRole: boolean;
|
||||
|
||||
constructor(row: RecentMentionRow) {
|
||||
this.userId = row.user_id;
|
||||
this.channelId = row.channel_id;
|
||||
this.messageId = row.message_id;
|
||||
this.guildId = row.guild_id;
|
||||
this.isEveryone = row.is_everyone;
|
||||
this.isRole = row.is_role;
|
||||
}
|
||||
|
||||
toRow(): RecentMentionRow {
|
||||
return {
|
||||
user_id: this.userId,
|
||||
channel_id: this.channelId,
|
||||
message_id: this.messageId,
|
||||
guild_id: this.guildId,
|
||||
is_everyone: this.isEveryone,
|
||||
is_role: this.isRole,
|
||||
};
|
||||
}
|
||||
}
|
||||
50
packages/api/src/models/Relationship.tsx
Normal file
50
packages/api/src/models/Relationship.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {RelationshipRow} from '@fluxer/api/src/database/types/UserTypes';
|
||||
|
||||
export class Relationship {
|
||||
readonly sourceUserId: UserID;
|
||||
readonly targetUserId: UserID;
|
||||
readonly type: number;
|
||||
readonly nickname: string | null;
|
||||
readonly since: Date | null;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: RelationshipRow) {
|
||||
this.sourceUserId = row.source_user_id;
|
||||
this.targetUserId = row.target_user_id;
|
||||
this.type = row.type;
|
||||
this.nickname = row.nickname ?? null;
|
||||
this.since = row.since ?? null;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): RelationshipRow {
|
||||
return {
|
||||
source_user_id: this.sourceUserId,
|
||||
target_user_id: this.targetUserId,
|
||||
type: this.type,
|
||||
nickname: this.nickname,
|
||||
since: this.since,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
44
packages/api/src/models/SavedMessage.tsx
Normal file
44
packages/api/src/models/SavedMessage.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, MessageID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {SavedMessageRow} from '@fluxer/api/src/database/types/UserTypes';
|
||||
|
||||
export class SavedMessage {
|
||||
readonly userId: UserID;
|
||||
readonly channelId: ChannelID;
|
||||
readonly messageId: MessageID;
|
||||
readonly savedAt: Date;
|
||||
|
||||
constructor(row: SavedMessageRow) {
|
||||
this.userId = row.user_id;
|
||||
this.channelId = row.channel_id;
|
||||
this.messageId = row.message_id;
|
||||
this.savedAt = row.saved_at;
|
||||
}
|
||||
|
||||
toRow(): SavedMessageRow {
|
||||
return {
|
||||
user_id: this.userId,
|
||||
channel_id: this.channelId,
|
||||
message_id: this.messageId,
|
||||
saved_at: this.savedAt,
|
||||
};
|
||||
}
|
||||
}
|
||||
198
packages/api/src/models/ScheduledMessage.tsx
Normal file
198
packages/api/src/models/ScheduledMessage.tsx
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, MessageID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {AttachmentRequestData} from '@fluxer/api/src/channel/AttachmentDTOs';
|
||||
import type {MessageRequest} from '@fluxer/api/src/channel/MessageTypes';
|
||||
import type {ScheduledMessageRow} from '@fluxer/api/src/database/types/UserTypes';
|
||||
import type {AllowedMentionsRequest} from '@fluxer/schema/src/domains/message/SharedMessageSchemas';
|
||||
|
||||
export type ScheduledMessageStatus = 'pending' | 'invalid';
|
||||
export interface ScheduledMessageReference {
|
||||
message_id: string;
|
||||
channel_id?: string;
|
||||
guild_id?: string;
|
||||
type?: number;
|
||||
}
|
||||
|
||||
export interface ScheduledAllowedMentions {
|
||||
parse?: AllowedMentionsRequest['parse'];
|
||||
users?: Array<string>;
|
||||
roles?: Array<string>;
|
||||
replied_user?: boolean;
|
||||
}
|
||||
|
||||
export interface ScheduledMessagePayload {
|
||||
content?: string | null;
|
||||
embeds?: MessageRequest['embeds'];
|
||||
attachments?: Array<AttachmentRequestData>;
|
||||
message_reference?: ScheduledMessageReference;
|
||||
allowed_mentions?: ScheduledAllowedMentions;
|
||||
flags?: number;
|
||||
nonce?: string;
|
||||
favorite_meme_id?: string;
|
||||
sticker_ids?: Array<string>;
|
||||
tts?: boolean;
|
||||
}
|
||||
|
||||
export interface ScheduledMessageResponse {
|
||||
id: string;
|
||||
channel_id: string;
|
||||
scheduled_at: string;
|
||||
scheduled_local_at: string;
|
||||
timezone: string;
|
||||
status: ScheduledMessageStatus;
|
||||
status_reason: string | null;
|
||||
payload: ScheduledMessagePayload;
|
||||
created_at: string;
|
||||
invalidated_at: string | null;
|
||||
}
|
||||
|
||||
export class ScheduledMessage {
|
||||
readonly userId: UserID;
|
||||
readonly id: MessageID;
|
||||
readonly channelId: ChannelID;
|
||||
readonly scheduledAt: Date;
|
||||
readonly scheduledLocalAt: string;
|
||||
readonly timezone: string;
|
||||
readonly payload: ScheduledMessagePayload;
|
||||
readonly status: ScheduledMessageStatus;
|
||||
readonly statusReason: string | null;
|
||||
readonly createdAt: Date;
|
||||
readonly invalidatedAt: Date | null;
|
||||
|
||||
constructor(params: {
|
||||
userId: UserID;
|
||||
id: MessageID;
|
||||
channelId: ChannelID;
|
||||
scheduledAt: Date;
|
||||
scheduledLocalAt: string;
|
||||
timezone: string;
|
||||
payload: ScheduledMessagePayload;
|
||||
status?: ScheduledMessageStatus;
|
||||
statusReason?: string | null;
|
||||
createdAt?: Date;
|
||||
invalidatedAt?: Date | null;
|
||||
}) {
|
||||
this.userId = params.userId;
|
||||
this.id = params.id;
|
||||
this.channelId = params.channelId;
|
||||
this.scheduledAt = params.scheduledAt;
|
||||
this.scheduledLocalAt = params.scheduledLocalAt;
|
||||
this.timezone = params.timezone;
|
||||
this.payload = params.payload;
|
||||
this.status = params.status ?? 'pending';
|
||||
this.statusReason = params.statusReason ?? null;
|
||||
this.createdAt = params.createdAt ?? new Date();
|
||||
this.invalidatedAt = params.invalidatedAt ?? null;
|
||||
}
|
||||
|
||||
static fromRow(row: ScheduledMessageRow): ScheduledMessage {
|
||||
return new ScheduledMessage({
|
||||
userId: row.user_id,
|
||||
id: row.scheduled_message_id,
|
||||
channelId: row.channel_id,
|
||||
scheduledAt: row.scheduled_at,
|
||||
scheduledLocalAt: row.scheduled_local_at,
|
||||
timezone: row.timezone,
|
||||
payload: parsePayload(row.payload),
|
||||
status: toStatus(row.status),
|
||||
statusReason: row.status_reason,
|
||||
createdAt: row.created_at,
|
||||
invalidatedAt: row.invalidated_at,
|
||||
});
|
||||
}
|
||||
|
||||
toRow(): ScheduledMessageRow {
|
||||
return {
|
||||
user_id: this.userId,
|
||||
scheduled_message_id: this.id,
|
||||
channel_id: this.channelId,
|
||||
payload: JSON.stringify(this.payload),
|
||||
scheduled_at: this.scheduledAt,
|
||||
scheduled_local_at: this.scheduledLocalAt,
|
||||
timezone: this.timezone,
|
||||
status: this.status,
|
||||
status_reason: this.statusReason,
|
||||
created_at: this.createdAt,
|
||||
invalidated_at: this.invalidatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
toResponse(): ScheduledMessageResponse {
|
||||
return {
|
||||
id: this.id.toString(),
|
||||
channel_id: this.channelId.toString(),
|
||||
scheduled_at: this.scheduledAt.toISOString(),
|
||||
scheduled_local_at: this.scheduledLocalAt,
|
||||
timezone: this.timezone,
|
||||
status: this.status,
|
||||
status_reason: this.statusReason,
|
||||
payload: this.payload,
|
||||
created_at: this.createdAt.toISOString(),
|
||||
invalidated_at: this.invalidatedAt?.toISOString() ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
parseToMessageRequest(): MessageRequest {
|
||||
return hydrateMessageRequest(this.payload);
|
||||
}
|
||||
}
|
||||
|
||||
function parsePayload(payload: string): ScheduledMessagePayload {
|
||||
try {
|
||||
return JSON.parse(payload) as ScheduledMessagePayload;
|
||||
} catch (_error) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function toStatus(value: string): ScheduledMessageStatus {
|
||||
return value === 'invalid' ? 'invalid' : 'pending';
|
||||
}
|
||||
|
||||
function hydrateMessageRequest(payload: ScheduledMessagePayload): MessageRequest {
|
||||
const message: MessageRequest = {
|
||||
content: payload.content,
|
||||
embeds: payload.embeds ?? [],
|
||||
attachments: payload.attachments,
|
||||
message_reference: payload.message_reference
|
||||
? {
|
||||
...payload.message_reference,
|
||||
message_id: BigInt(payload.message_reference.message_id),
|
||||
channel_id: payload.message_reference.channel_id ? BigInt(payload.message_reference.channel_id) : undefined,
|
||||
guild_id: payload.message_reference.guild_id ? BigInt(payload.message_reference.guild_id) : undefined,
|
||||
}
|
||||
: undefined,
|
||||
allowed_mentions: payload.allowed_mentions
|
||||
? {
|
||||
parse: payload.allowed_mentions.parse,
|
||||
users: payload.allowed_mentions.users?.map((value) => BigInt(value)),
|
||||
roles: payload.allowed_mentions.roles?.map((value) => BigInt(value)),
|
||||
replied_user: payload.allowed_mentions.replied_user,
|
||||
}
|
||||
: undefined,
|
||||
flags: payload.flags,
|
||||
nonce: payload.nonce,
|
||||
favorite_meme_id: payload.favorite_meme_id ? BigInt(payload.favorite_meme_id) : undefined,
|
||||
sticker_ids: payload.sticker_ids?.map((value) => BigInt(value)),
|
||||
tts: payload.tts,
|
||||
};
|
||||
return message;
|
||||
}
|
||||
41
packages/api/src/models/StickerItem.tsx
Normal file
41
packages/api/src/models/StickerItem.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {StickerID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {MessageStickerItem} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
|
||||
export class StickerItem {
|
||||
readonly id: StickerID;
|
||||
readonly name: string;
|
||||
readonly animated: boolean;
|
||||
|
||||
constructor(sticker: MessageStickerItem) {
|
||||
this.id = sticker.sticker_id;
|
||||
this.name = sticker.name;
|
||||
this.animated = sticker.animated ?? false;
|
||||
}
|
||||
|
||||
toMessageStickerItem(): MessageStickerItem {
|
||||
return {
|
||||
sticker_id: this.id,
|
||||
name: this.name,
|
||||
animated: this.animated,
|
||||
};
|
||||
}
|
||||
}
|
||||
220
packages/api/src/models/User.tsx
Normal file
220
packages/api/src/models/User.tsx
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {UserRow} from '@fluxer/api/src/database/types/UserTypes';
|
||||
import {getGlobalLimitConfigSnapshot} from '@fluxer/api/src/limits/LimitConfigService';
|
||||
import {resolveLimitSafe} from '@fluxer/api/src/limits/LimitConfigUtils';
|
||||
import {createLimitMatchContext} from '@fluxer/api/src/limits/LimitMatchContextBuilder';
|
||||
import {checkIsPremium} from '@fluxer/api/src/user/UserHelpers';
|
||||
import {types} from 'cassandra-driver';
|
||||
|
||||
export class User {
|
||||
readonly id: UserID;
|
||||
readonly username: string;
|
||||
readonly discriminator: number;
|
||||
readonly globalName: string | null;
|
||||
readonly isBot: boolean;
|
||||
readonly isSystem: boolean;
|
||||
readonly email: string | null;
|
||||
readonly emailVerified: boolean;
|
||||
readonly emailBounced: boolean;
|
||||
readonly phone: string | null;
|
||||
readonly passwordHash: string | null;
|
||||
readonly passwordLastChangedAt: Date | null;
|
||||
readonly totpSecret: string | null;
|
||||
readonly authenticatorTypes: Set<number>;
|
||||
readonly avatarHash: string | null;
|
||||
readonly avatarColor: number | null;
|
||||
readonly bannerHash: string | null;
|
||||
readonly bannerColor: number | null;
|
||||
readonly bio: string | null;
|
||||
readonly pronouns: string | null;
|
||||
readonly accentColor: number | null;
|
||||
readonly dateOfBirth: string | null;
|
||||
readonly locale: string | null;
|
||||
readonly flags: bigint;
|
||||
readonly premiumType: number | null;
|
||||
readonly premiumSince: Date | null;
|
||||
readonly premiumUntil: Date | null;
|
||||
readonly premiumWillCancel: boolean;
|
||||
readonly premiumBillingCycle: string | null;
|
||||
readonly premiumLifetimeSequence: number | null;
|
||||
readonly stripeSubscriptionId: string | null;
|
||||
readonly stripeCustomerId: string | null;
|
||||
readonly hasEverPurchased: boolean;
|
||||
readonly suspiciousActivityFlags: number;
|
||||
readonly termsAgreedAt: Date | null;
|
||||
readonly privacyAgreedAt: Date | null;
|
||||
readonly lastActiveAt: Date | null;
|
||||
readonly lastActiveIp: string | null;
|
||||
readonly tempBannedUntil: Date | null;
|
||||
readonly pendingBulkMessageDeletionAt: Date | null;
|
||||
readonly pendingBulkMessageDeletionChannelCount: number | null;
|
||||
readonly pendingBulkMessageDeletionMessageCount: number | null;
|
||||
readonly pendingDeletionAt: Date | null;
|
||||
readonly deletionReasonCode: number | null;
|
||||
readonly deletionPublicReason: string | null;
|
||||
readonly deletionAuditLogReason: string | null;
|
||||
readonly acls: Set<string>;
|
||||
private readonly _traits: Set<string>;
|
||||
readonly firstRefundAt: Date | null;
|
||||
readonly giftInventoryServerSeq: number | null;
|
||||
readonly giftInventoryClientSeq: number | null;
|
||||
readonly premiumOnboardingDismissedAt: Date | null;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: UserRow) {
|
||||
this.id = row.user_id;
|
||||
this.username = row.username;
|
||||
this.discriminator = row.discriminator;
|
||||
this.globalName = row.global_name ?? null;
|
||||
this.isBot = row.bot ?? false;
|
||||
this.isSystem = row.system ?? false;
|
||||
this.email = row.email ?? null;
|
||||
this.emailVerified = row.email_verified ?? false;
|
||||
this.emailBounced = row.email_bounced ?? false;
|
||||
this.phone = row.phone ?? null;
|
||||
this.passwordHash = row.password_hash ?? null;
|
||||
this.passwordLastChangedAt = row.password_last_changed_at ?? null;
|
||||
this.totpSecret = row.totp_secret ?? null;
|
||||
this.authenticatorTypes = row.authenticator_types ?? new Set();
|
||||
this.avatarHash = row.avatar_hash ?? null;
|
||||
this.avatarColor = row.avatar_color ?? null;
|
||||
this.bannerHash = row.banner_hash ?? null;
|
||||
this.bannerColor = row.banner_color ?? null;
|
||||
this.bio = row.bio ?? null;
|
||||
this.pronouns = row.pronouns ?? null;
|
||||
this.accentColor = row.accent_color ?? null;
|
||||
this.dateOfBirth = row.date_of_birth ? row.date_of_birth.toString() : null;
|
||||
this.locale = row.locale ?? null;
|
||||
this.flags = row.flags ?? 0n;
|
||||
this.premiumType = row.premium_type ?? null;
|
||||
this.premiumSince = row.premium_since ?? null;
|
||||
this.premiumUntil = row.premium_until ?? null;
|
||||
this.premiumWillCancel = row.premium_will_cancel ?? false;
|
||||
this.premiumBillingCycle = row.premium_billing_cycle ?? null;
|
||||
this.premiumLifetimeSequence = row.premium_lifetime_sequence ?? null;
|
||||
this.stripeSubscriptionId = row.stripe_subscription_id ?? null;
|
||||
this.stripeCustomerId = row.stripe_customer_id ?? null;
|
||||
this.hasEverPurchased = row.has_ever_purchased ?? false;
|
||||
this.suspiciousActivityFlags = row.suspicious_activity_flags ?? 0;
|
||||
this.termsAgreedAt = row.terms_agreed_at ?? null;
|
||||
this.privacyAgreedAt = row.privacy_agreed_at ?? null;
|
||||
this.lastActiveAt = row.last_active_at ?? null;
|
||||
this.lastActiveIp = row.last_active_ip ?? null;
|
||||
this.tempBannedUntil = row.temp_banned_until ?? null;
|
||||
this.pendingBulkMessageDeletionAt = row.pending_bulk_message_deletion_at ?? null;
|
||||
this.pendingBulkMessageDeletionChannelCount = row.pending_bulk_message_deletion_channel_count ?? null;
|
||||
this.pendingBulkMessageDeletionMessageCount = row.pending_bulk_message_deletion_message_count ?? null;
|
||||
this.pendingDeletionAt = row.pending_deletion_at ?? null;
|
||||
this.deletionReasonCode = row.deletion_reason_code ?? null;
|
||||
this.deletionPublicReason = row.deletion_public_reason ?? null;
|
||||
this.deletionAuditLogReason = row.deletion_audit_log_reason ?? null;
|
||||
this.acls = row.acls ?? new Set();
|
||||
this._traits = row.traits ?? new Set();
|
||||
this.firstRefundAt = row.first_refund_at ?? null;
|
||||
this.giftInventoryServerSeq = row.gift_inventory_server_seq ?? null;
|
||||
this.giftInventoryClientSeq = row.gift_inventory_client_seq ?? null;
|
||||
this.premiumOnboardingDismissedAt = row.premium_onboarding_dismissed_at ?? null;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
get traits(): Set<string> {
|
||||
return new Set(this._traits);
|
||||
}
|
||||
|
||||
isPremium(): boolean {
|
||||
return checkIsPremium(this);
|
||||
}
|
||||
|
||||
isUnclaimedAccount(): boolean {
|
||||
return this.passwordHash === null && !this.isBot;
|
||||
}
|
||||
|
||||
canUseGlobalExpressions(): boolean {
|
||||
if (this.isBot) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const ctx = createLimitMatchContext({user: this});
|
||||
const snapshot = getGlobalLimitConfigSnapshot();
|
||||
const hasGlobalExpressions = resolveLimitSafe(snapshot, ctx, 'feature_global_expressions', 0);
|
||||
|
||||
return hasGlobalExpressions > 0;
|
||||
}
|
||||
|
||||
toRow(): UserRow {
|
||||
return {
|
||||
user_id: this.id,
|
||||
username: this.username,
|
||||
discriminator: this.discriminator,
|
||||
global_name: this.globalName,
|
||||
bot: this.isBot,
|
||||
system: this.isSystem,
|
||||
email: this.email,
|
||||
email_verified: this.emailVerified,
|
||||
email_bounced: this.emailBounced,
|
||||
phone: this.phone,
|
||||
password_hash: this.passwordHash,
|
||||
password_last_changed_at: this.passwordLastChangedAt,
|
||||
totp_secret: this.totpSecret,
|
||||
authenticator_types: this.authenticatorTypes.size > 0 ? this.authenticatorTypes : null,
|
||||
avatar_hash: this.avatarHash,
|
||||
avatar_color: this.avatarColor,
|
||||
banner_hash: this.bannerHash,
|
||||
banner_color: this.bannerColor,
|
||||
bio: this.bio,
|
||||
pronouns: this.pronouns,
|
||||
accent_color: this.accentColor,
|
||||
date_of_birth: this.dateOfBirth ? types.LocalDate.fromString(this.dateOfBirth) : null,
|
||||
locale: this.locale,
|
||||
flags: this.flags,
|
||||
premium_type: this.premiumType,
|
||||
premium_since: this.premiumSince,
|
||||
premium_until: this.premiumUntil,
|
||||
premium_will_cancel: this.premiumWillCancel,
|
||||
premium_billing_cycle: this.premiumBillingCycle,
|
||||
premium_lifetime_sequence: this.premiumLifetimeSequence,
|
||||
stripe_subscription_id: this.stripeSubscriptionId,
|
||||
stripe_customer_id: this.stripeCustomerId,
|
||||
has_ever_purchased: this.hasEverPurchased,
|
||||
suspicious_activity_flags: this.suspiciousActivityFlags,
|
||||
terms_agreed_at: this.termsAgreedAt,
|
||||
privacy_agreed_at: this.privacyAgreedAt,
|
||||
last_active_at: this.lastActiveAt,
|
||||
last_active_ip: this.lastActiveIp,
|
||||
temp_banned_until: this.tempBannedUntil,
|
||||
pending_bulk_message_deletion_at: this.pendingBulkMessageDeletionAt,
|
||||
pending_bulk_message_deletion_channel_count: this.pendingBulkMessageDeletionChannelCount,
|
||||
pending_bulk_message_deletion_message_count: this.pendingBulkMessageDeletionMessageCount,
|
||||
pending_deletion_at: this.pendingDeletionAt,
|
||||
deletion_reason_code: this.deletionReasonCode,
|
||||
deletion_public_reason: this.deletionPublicReason,
|
||||
deletion_audit_log_reason: this.deletionAuditLogReason,
|
||||
acls: this.acls.size > 0 ? this.acls : null,
|
||||
traits: this._traits.size > 0 ? this._traits : null,
|
||||
first_refund_at: this.firstRefundAt,
|
||||
gift_inventory_server_seq: this.giftInventoryServerSeq,
|
||||
gift_inventory_client_seq: this.giftInventoryClientSeq,
|
||||
premium_onboarding_dismissed_at: this.premiumOnboardingDismissedAt,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
51
packages/api/src/models/UserCustomStatus.tsx
Normal file
51
packages/api/src/models/UserCustomStatus.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {EmojiID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {CustomStatus} from '@fluxer/api/src/database/types/UserTypes';
|
||||
|
||||
export class UserCustomStatus {
|
||||
readonly text: string | null;
|
||||
readonly emojiId: EmojiID | null;
|
||||
readonly emojiName: string | null;
|
||||
readonly emojiAnimated: boolean;
|
||||
readonly expiresAt: Date | null;
|
||||
|
||||
constructor(status: CustomStatus) {
|
||||
this.text = status.text ?? null;
|
||||
this.emojiId = status.emoji_id ?? null;
|
||||
this.emojiName = status.emoji_name ?? null;
|
||||
this.emojiAnimated = status.emoji_animated ?? false;
|
||||
this.expiresAt = status.expires_at ?? null;
|
||||
}
|
||||
|
||||
toCustomStatus(): CustomStatus {
|
||||
return {
|
||||
text: this.text,
|
||||
emoji_id: this.emojiId,
|
||||
emoji_name: this.emojiName,
|
||||
emoji_animated: this.emojiAnimated,
|
||||
expires_at: this.expiresAt,
|
||||
};
|
||||
}
|
||||
|
||||
isExpired(referenceTime: Date = new Date()): boolean {
|
||||
return this.expiresAt !== null && this.expiresAt.getTime() <= referenceTime.getTime();
|
||||
}
|
||||
}
|
||||
51
packages/api/src/models/UserGuildFolder.tsx
Normal file
51
packages/api/src/models/UserGuildFolder.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {GuildID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {GuildFolder} from '@fluxer/api/src/database/types/UserTypes';
|
||||
import {DEFAULT_GUILD_FOLDER_ICON, type GuildFolderIcon} from '@fluxer/constants/src/UserConstants';
|
||||
|
||||
export class UserGuildFolder {
|
||||
readonly folderId: number;
|
||||
readonly name: string | null;
|
||||
readonly color: number | null;
|
||||
readonly flags: number;
|
||||
readonly icon: GuildFolderIcon;
|
||||
readonly guildIds: Array<GuildID>;
|
||||
|
||||
constructor(folder: GuildFolder) {
|
||||
this.folderId = folder.folder_id;
|
||||
this.name = folder.name ?? null;
|
||||
this.color = folder.color ?? null;
|
||||
this.flags = folder.flags ?? 0;
|
||||
this.icon = folder.icon ?? DEFAULT_GUILD_FOLDER_ICON;
|
||||
this.guildIds = folder.guild_ids ?? [];
|
||||
}
|
||||
|
||||
toGuildFolder(): GuildFolder {
|
||||
return {
|
||||
folder_id: this.folderId,
|
||||
name: this.name,
|
||||
color: this.color,
|
||||
flags: this.flags,
|
||||
icon: this.icon,
|
||||
guild_ids: this.guildIds.length > 0 ? this.guildIds : null,
|
||||
};
|
||||
}
|
||||
}
|
||||
79
packages/api/src/models/UserGuildSettings.tsx
Normal file
79
packages/api/src/models/UserGuildSettings.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, GuildID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {ChannelOverride, UserGuildSettingsRow} from '@fluxer/api/src/database/types/UserTypes';
|
||||
import {GuildChannelOverride} from '@fluxer/api/src/models/GuildChannelOverride';
|
||||
import {MuteConfiguration} from '@fluxer/api/src/models/MuteConfiguration';
|
||||
|
||||
export class UserGuildSettings {
|
||||
readonly userId: UserID;
|
||||
readonly guildId: GuildID;
|
||||
readonly messageNotifications: number | null;
|
||||
readonly muted: boolean;
|
||||
readonly muteConfig: MuteConfiguration | null;
|
||||
readonly mobilePush: boolean;
|
||||
readonly suppressEveryone: boolean;
|
||||
readonly suppressRoles: boolean;
|
||||
readonly hideMutedChannels: boolean;
|
||||
readonly channelOverrides: Map<ChannelID, GuildChannelOverride>;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: UserGuildSettingsRow) {
|
||||
this.userId = row.user_id;
|
||||
this.guildId = row.guild_id;
|
||||
this.messageNotifications = row.message_notifications ?? null;
|
||||
this.muted = row.muted ?? false;
|
||||
this.muteConfig = row.mute_config ? new MuteConfiguration(row.mute_config) : null;
|
||||
this.mobilePush = row.mobile_push ?? false;
|
||||
this.suppressEveryone = row.suppress_everyone ?? false;
|
||||
this.suppressRoles = row.suppress_roles ?? false;
|
||||
this.hideMutedChannels = row.hide_muted_channels ?? false;
|
||||
this.channelOverrides = new Map();
|
||||
if (row.channel_overrides) {
|
||||
for (const [channelId, override] of row.channel_overrides) {
|
||||
this.channelOverrides.set(channelId, new GuildChannelOverride(override));
|
||||
}
|
||||
}
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): UserGuildSettingsRow {
|
||||
const channelOverridesMap: Map<ChannelID, ChannelOverride> | null =
|
||||
this.channelOverrides.size > 0
|
||||
? new Map(
|
||||
Array.from(this.channelOverrides.entries()).map(([id, override]) => [id, override.toChannelOverride()]),
|
||||
)
|
||||
: null;
|
||||
|
||||
return {
|
||||
user_id: this.userId,
|
||||
guild_id: this.guildId,
|
||||
message_notifications: this.messageNotifications,
|
||||
muted: this.muted,
|
||||
mute_config: this.muteConfig?.toMuteConfig() ?? null,
|
||||
mobile_push: this.mobilePush,
|
||||
suppress_everyone: this.suppressEveryone,
|
||||
suppress_roles: this.suppressRoles,
|
||||
hide_muted_channels: this.hideMutedChannels,
|
||||
channel_overrides: channelOverridesMap,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
44
packages/api/src/models/UserNote.tsx
Normal file
44
packages/api/src/models/UserNote.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {NoteRow} from '@fluxer/api/src/database/types/UserTypes';
|
||||
|
||||
export class UserNote {
|
||||
readonly sourceUserId: UserID;
|
||||
readonly targetUserId: UserID;
|
||||
readonly note: string;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: NoteRow) {
|
||||
this.sourceUserId = row.source_user_id;
|
||||
this.targetUserId = row.target_user_id;
|
||||
this.note = row.note;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): NoteRow {
|
||||
return {
|
||||
source_user_id: this.sourceUserId,
|
||||
target_user_id: this.targetUserId,
|
||||
note: this.note,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
214
packages/api/src/models/UserSettings.tsx
Normal file
214
packages/api/src/models/UserSettings.tsx
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {GuildID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import {Config} from '@fluxer/api/src/Config';
|
||||
import type {UserSettingsRow} from '@fluxer/api/src/database/types/UserTypes';
|
||||
import {UserCustomStatus} from '@fluxer/api/src/models/UserCustomStatus';
|
||||
import {UserGuildFolder} from '@fluxer/api/src/models/UserGuildFolder';
|
||||
import type {LocaleCode} from '@fluxer/constants/src/Locales';
|
||||
import {
|
||||
DEFAULT_GUILD_FOLDER_ICON,
|
||||
FriendSourceFlags,
|
||||
GroupDmAddPermissionFlags,
|
||||
IncomingCallFlags,
|
||||
RenderSpoilers,
|
||||
StickerAnimationOptions,
|
||||
ThemeTypes,
|
||||
UNCATEGORIZED_FOLDER_ID,
|
||||
UserExplicitContentFilterTypes,
|
||||
} from '@fluxer/constants/src/UserConstants';
|
||||
|
||||
export class UserSettings {
|
||||
readonly userId: UserID;
|
||||
readonly locale: LocaleCode;
|
||||
readonly theme: string;
|
||||
readonly status: string;
|
||||
readonly statusResetsAt: Date | null;
|
||||
readonly statusResetsTo: string | null;
|
||||
readonly customStatus: UserCustomStatus | null;
|
||||
readonly developerMode: boolean;
|
||||
readonly compactMessageDisplay: boolean;
|
||||
readonly animateEmoji: boolean;
|
||||
readonly animateStickers: number;
|
||||
readonly gifAutoPlay: boolean;
|
||||
readonly renderEmbeds: boolean;
|
||||
readonly renderReactions: boolean;
|
||||
readonly renderSpoilers: number;
|
||||
readonly inlineAttachmentMedia: boolean;
|
||||
readonly inlineEmbedMedia: boolean;
|
||||
readonly explicitContentFilter: number;
|
||||
readonly friendSourceFlags: number;
|
||||
readonly incomingCallFlags: number;
|
||||
readonly groupDmAddPermissionFlags: number;
|
||||
readonly defaultGuildsRestricted: boolean;
|
||||
readonly botDefaultGuildsRestricted: boolean;
|
||||
readonly restrictedGuilds: Set<GuildID>;
|
||||
readonly botRestrictedGuilds: Set<GuildID>;
|
||||
readonly guildPositions: Array<GuildID>;
|
||||
readonly guildFolders: Array<UserGuildFolder>;
|
||||
readonly afkTimeout: number;
|
||||
readonly timeFormat: number;
|
||||
readonly trustedDomains: Set<string>;
|
||||
readonly defaultHideMutedChannels: boolean;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: UserSettingsRow) {
|
||||
this.userId = row.user_id;
|
||||
this.locale = row.locale;
|
||||
this.theme = row.theme;
|
||||
this.status = row.status;
|
||||
this.statusResetsAt = row.status_resets_at ?? null;
|
||||
this.statusResetsTo = row.status_resets_to ?? null;
|
||||
this.customStatus = row.custom_status ? new UserCustomStatus(row.custom_status) : null;
|
||||
this.developerMode = row.developer_mode ?? false;
|
||||
this.compactMessageDisplay = row.message_display_compact ?? false;
|
||||
this.animateEmoji = row.animate_emoji ?? false;
|
||||
this.animateStickers = row.animate_stickers ?? 0;
|
||||
this.gifAutoPlay = row.gif_auto_play ?? false;
|
||||
this.renderEmbeds = row.render_embeds ?? false;
|
||||
this.renderReactions = row.render_reactions ?? false;
|
||||
this.renderSpoilers = row.render_spoilers ?? 0;
|
||||
this.inlineAttachmentMedia = row.inline_attachment_media ?? false;
|
||||
this.inlineEmbedMedia = row.inline_embed_media ?? false;
|
||||
this.explicitContentFilter = row.explicit_content_filter ?? 0;
|
||||
this.friendSourceFlags = row.friend_source_flags ?? 0;
|
||||
this.incomingCallFlags = row.incoming_call_flags ?? 0;
|
||||
this.groupDmAddPermissionFlags = row.group_dm_add_permission_flags ?? 0;
|
||||
this.defaultGuildsRestricted = row.default_guilds_restricted ?? false;
|
||||
this.botDefaultGuildsRestricted = row.bot_default_guilds_restricted ?? false;
|
||||
this.restrictedGuilds = row.restricted_guilds ?? new Set();
|
||||
this.botRestrictedGuilds = row.bot_restricted_guilds ?? new Set();
|
||||
this.guildPositions = row.guild_positions ?? [];
|
||||
this.guildFolders = (row.guild_folders ?? []).map((folder) => new UserGuildFolder(folder));
|
||||
this.afkTimeout = row.afk_timeout ?? 600;
|
||||
this.timeFormat = row.time_format ?? 0;
|
||||
this.trustedDomains = row.trusted_domains ?? new Set();
|
||||
this.defaultHideMutedChannels = row.default_hide_muted_channels ?? false;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
getUncategorizedFolder(): UserGuildFolder | null {
|
||||
return this.guildFolders.find((folder) => folder.folderId === UNCATEGORIZED_FOLDER_ID) ?? null;
|
||||
}
|
||||
|
||||
getOrderedGuildIds(): Array<GuildID> {
|
||||
return this.guildFolders.flatMap((folder) => folder.guildIds);
|
||||
}
|
||||
|
||||
toRow(): UserSettingsRow {
|
||||
return {
|
||||
user_id: this.userId,
|
||||
locale: this.locale,
|
||||
theme: this.theme,
|
||||
status: this.status,
|
||||
status_resets_at: this.statusResetsAt,
|
||||
status_resets_to: this.statusResetsTo,
|
||||
custom_status: this.customStatus?.toCustomStatus() ?? null,
|
||||
developer_mode: this.developerMode,
|
||||
message_display_compact: this.compactMessageDisplay,
|
||||
animate_emoji: this.animateEmoji,
|
||||
animate_stickers: this.animateStickers,
|
||||
gif_auto_play: this.gifAutoPlay,
|
||||
render_embeds: this.renderEmbeds,
|
||||
render_reactions: this.renderReactions,
|
||||
render_spoilers: this.renderSpoilers,
|
||||
inline_attachment_media: this.inlineAttachmentMedia,
|
||||
inline_embed_media: this.inlineEmbedMedia,
|
||||
explicit_content_filter: this.explicitContentFilter,
|
||||
friend_source_flags: this.friendSourceFlags,
|
||||
incoming_call_flags: this.incomingCallFlags,
|
||||
group_dm_add_permission_flags: this.groupDmAddPermissionFlags,
|
||||
default_guilds_restricted: this.defaultGuildsRestricted,
|
||||
bot_default_guilds_restricted: this.botDefaultGuildsRestricted,
|
||||
restricted_guilds: this.restrictedGuilds.size > 0 ? this.restrictedGuilds : null,
|
||||
bot_restricted_guilds: this.botRestrictedGuilds.size > 0 ? this.botRestrictedGuilds : null,
|
||||
guild_positions: this.guildPositions.length > 0 ? this.guildPositions : null,
|
||||
guild_folders: this.guildFolders.length > 0 ? this.guildFolders.map((folder) => folder.toGuildFolder()) : null,
|
||||
afk_timeout: this.afkTimeout,
|
||||
time_format: this.timeFormat,
|
||||
trusted_domains: this.trustedDomains.size > 0 ? this.trustedDomains : null,
|
||||
default_hide_muted_channels: this.defaultHideMutedChannels,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
|
||||
static getDefaultUserSettings({
|
||||
userId,
|
||||
locale,
|
||||
isAdult,
|
||||
}: {
|
||||
userId: UserID;
|
||||
locale: LocaleCode;
|
||||
isAdult: boolean;
|
||||
}): UserSettingsRow {
|
||||
let explicitContentFilter: number = UserExplicitContentFilterTypes.NON_FRIENDS;
|
||||
if (isAdult) {
|
||||
explicitContentFilter = UserExplicitContentFilterTypes.FRIENDS_AND_NON_FRIENDS;
|
||||
}
|
||||
let friendSourceFlags: number = FriendSourceFlags.MUTUAL_FRIENDS | FriendSourceFlags.MUTUAL_GUILDS;
|
||||
if (isAdult) {
|
||||
friendSourceFlags |= FriendSourceFlags.NO_RELATION;
|
||||
}
|
||||
|
||||
return {
|
||||
user_id: userId,
|
||||
locale,
|
||||
theme: ThemeTypes.SYSTEM,
|
||||
status: 'online',
|
||||
status_resets_at: null,
|
||||
status_resets_to: null,
|
||||
custom_status: null,
|
||||
developer_mode: Config.nodeEnv === 'development',
|
||||
message_display_compact: false,
|
||||
animate_emoji: true,
|
||||
animate_stickers: StickerAnimationOptions.ALWAYS_ANIMATE,
|
||||
gif_auto_play: true,
|
||||
render_embeds: true,
|
||||
render_reactions: true,
|
||||
render_spoilers: RenderSpoilers.ON_CLICK,
|
||||
inline_attachment_media: true,
|
||||
inline_embed_media: true,
|
||||
explicit_content_filter: explicitContentFilter,
|
||||
friend_source_flags: friendSourceFlags,
|
||||
incoming_call_flags: IncomingCallFlags.FRIENDS_ONLY,
|
||||
group_dm_add_permission_flags: GroupDmAddPermissionFlags.FRIENDS_ONLY,
|
||||
default_guilds_restricted: false,
|
||||
bot_default_guilds_restricted: false,
|
||||
restricted_guilds: new Set(),
|
||||
bot_restricted_guilds: new Set(),
|
||||
guild_positions: [],
|
||||
guild_folders: [
|
||||
{
|
||||
folder_id: UNCATEGORIZED_FOLDER_ID,
|
||||
name: null,
|
||||
color: null,
|
||||
flags: 0,
|
||||
icon: DEFAULT_GUILD_FOLDER_ICON,
|
||||
guild_ids: [],
|
||||
},
|
||||
],
|
||||
afk_timeout: 600,
|
||||
time_format: 0,
|
||||
trusted_domains: new Set(),
|
||||
default_hide_muted_channels: false,
|
||||
version: 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
42
packages/api/src/models/VisionarySlot.tsx
Normal file
42
packages/api/src/models/VisionarySlot.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {VisionarySlotRow} from '@fluxer/api/src/database/types/PaymentTypes';
|
||||
|
||||
export class VisionarySlot {
|
||||
readonly slotIndex: number;
|
||||
readonly userId: UserID | null;
|
||||
|
||||
constructor(row: VisionarySlotRow) {
|
||||
this.slotIndex = row.slot_index;
|
||||
this.userId = row.user_id;
|
||||
}
|
||||
|
||||
toRow(): VisionarySlotRow {
|
||||
return {
|
||||
slot_index: this.slotIndex,
|
||||
user_id: this.userId,
|
||||
};
|
||||
}
|
||||
|
||||
isReserved(): boolean {
|
||||
return this.userId !== null;
|
||||
}
|
||||
}
|
||||
57
packages/api/src/models/WebAuthnCredential.tsx
Normal file
57
packages/api/src/models/WebAuthnCredential.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {WebAuthnCredentialRow} from '@fluxer/api/src/database/types/AuthTypes';
|
||||
|
||||
export class WebAuthnCredential {
|
||||
readonly credentialId: string;
|
||||
readonly publicKey: Buffer;
|
||||
readonly counter: bigint;
|
||||
readonly transports: Set<string> | null;
|
||||
readonly name: string;
|
||||
readonly createdAt: Date;
|
||||
readonly lastUsedAt: Date | null;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: WebAuthnCredentialRow) {
|
||||
this.credentialId = row.credential_id;
|
||||
this.publicKey = row.public_key;
|
||||
this.counter = row.counter;
|
||||
this.transports = row.transports ?? null;
|
||||
this.name = row.name;
|
||||
this.createdAt = row.created_at;
|
||||
this.lastUsedAt = row.last_used_at ?? null;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(userId: UserID): WebAuthnCredentialRow {
|
||||
return {
|
||||
user_id: userId,
|
||||
credential_id: this.credentialId,
|
||||
public_key: this.publicKey,
|
||||
counter: this.counter,
|
||||
transports: this.transports,
|
||||
name: this.name,
|
||||
created_at: this.createdAt,
|
||||
last_used_at: this.lastUsedAt,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
59
packages/api/src/models/Webhook.tsx
Normal file
59
packages/api/src/models/Webhook.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ChannelID, GuildID, UserID, WebhookID, WebhookToken} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {WebhookRow} from '@fluxer/api/src/database/types/ChannelTypes';
|
||||
|
||||
export class Webhook {
|
||||
readonly id: WebhookID;
|
||||
readonly token: WebhookToken;
|
||||
readonly type: number;
|
||||
readonly guildId: GuildID | null;
|
||||
readonly channelId: ChannelID | null;
|
||||
readonly creatorId: UserID | null;
|
||||
readonly name: string;
|
||||
readonly avatarHash: string | null;
|
||||
readonly version: number;
|
||||
|
||||
constructor(row: WebhookRow) {
|
||||
this.id = row.webhook_id;
|
||||
this.token = row.webhook_token;
|
||||
this.type = row.type;
|
||||
this.guildId = row.guild_id ?? null;
|
||||
this.channelId = row.channel_id ?? null;
|
||||
this.creatorId = row.creator_id ?? null;
|
||||
this.name = row.name;
|
||||
this.avatarHash = row.avatar_hash ?? null;
|
||||
this.version = row.version;
|
||||
}
|
||||
|
||||
toRow(): WebhookRow {
|
||||
return {
|
||||
webhook_id: this.id,
|
||||
webhook_token: this.token,
|
||||
type: this.type,
|
||||
guild_id: this.guildId,
|
||||
channel_id: this.channelId,
|
||||
creator_id: this.creatorId,
|
||||
name: this.name,
|
||||
avatar_hash: this.avatarHash,
|
||||
version: this.version,
|
||||
};
|
||||
}
|
||||
}
|
||||
174
packages/api/src/models/tests/EmbedIconUrlSanitization.test.tsx
Normal file
174
packages/api/src/models/tests/EmbedIconUrlSanitization.test.tsx
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer 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.
|
||||
*
|
||||
* Fluxer 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 Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Embed} from '@fluxer/api/src/models/Embed';
|
||||
import {EmbedAuthor} from '@fluxer/api/src/models/EmbedAuthor';
|
||||
import {EmbedFooter} from '@fluxer/api/src/models/EmbedFooter';
|
||||
import {EmbedProvider} from '@fluxer/api/src/models/EmbedProvider';
|
||||
import {describe, expect, it} from 'vitest';
|
||||
|
||||
describe('EmbedAuthor icon URL sanitisation', () => {
|
||||
it('normalises empty icon_url values to null', () => {
|
||||
const author = new EmbedAuthor({
|
||||
name: 'Alice',
|
||||
url: 'https://remote.example/@alice',
|
||||
icon_url: '',
|
||||
});
|
||||
|
||||
expect(author.iconUrl).toBeNull();
|
||||
expect(author.toMessageEmbedAuthor().icon_url).toBeNull();
|
||||
});
|
||||
|
||||
it('normalises invalid icon_url values to null', () => {
|
||||
const author = new EmbedAuthor({
|
||||
name: 'Alice',
|
||||
url: 'https://remote.example/@alice',
|
||||
icon_url: 'not-a-valid-url',
|
||||
});
|
||||
|
||||
expect(author.iconUrl).toBeNull();
|
||||
expect(author.toMessageEmbedAuthor().icon_url).toBeNull();
|
||||
});
|
||||
|
||||
it('keeps valid icon_url values', () => {
|
||||
const author = new EmbedAuthor({
|
||||
name: 'Alice',
|
||||
url: ' https://remote.example/@alice ',
|
||||
icon_url: ' https://remote.example/avatar.png ',
|
||||
});
|
||||
|
||||
expect(author.url).toBe('https://remote.example/@alice');
|
||||
expect(author.iconUrl).toBe('https://remote.example/avatar.png');
|
||||
expect(author.toMessageEmbedAuthor().url).toBe('https://remote.example/@alice');
|
||||
expect(author.toMessageEmbedAuthor().icon_url).toBe('https://remote.example/avatar.png');
|
||||
});
|
||||
|
||||
it('normalises invalid author url values to null', () => {
|
||||
const author = new EmbedAuthor({
|
||||
name: 'Alice',
|
||||
url: 'not-a-valid-url',
|
||||
icon_url: 'https://remote.example/avatar.png',
|
||||
});
|
||||
|
||||
expect(author.url).toBeNull();
|
||||
expect(author.toMessageEmbedAuthor().url).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('EmbedFooter icon URL sanitisation', () => {
|
||||
it('normalises empty icon_url values to null', () => {
|
||||
const footer = new EmbedFooter({
|
||||
text: 'Example Server',
|
||||
icon_url: '',
|
||||
});
|
||||
|
||||
expect(footer.iconUrl).toBeNull();
|
||||
expect(footer.toMessageEmbedFooter().icon_url).toBeNull();
|
||||
});
|
||||
|
||||
it('normalises invalid icon_url values to null', () => {
|
||||
const footer = new EmbedFooter({
|
||||
text: 'Example Server',
|
||||
icon_url: 'not-a-valid-url',
|
||||
});
|
||||
|
||||
expect(footer.iconUrl).toBeNull();
|
||||
expect(footer.toMessageEmbedFooter().icon_url).toBeNull();
|
||||
});
|
||||
|
||||
it('keeps valid icon_url values', () => {
|
||||
const footer = new EmbedFooter({
|
||||
text: 'Example Server',
|
||||
icon_url: ' https://remote.example/server-icon.png ',
|
||||
});
|
||||
|
||||
expect(footer.iconUrl).toBe('https://remote.example/server-icon.png');
|
||||
expect(footer.toMessageEmbedFooter().icon_url).toBe('https://remote.example/server-icon.png');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Embed URL sanitisation', () => {
|
||||
it('normalises invalid embed url values to null', () => {
|
||||
const embed = new Embed({
|
||||
type: 'rich',
|
||||
title: null,
|
||||
description: null,
|
||||
url: 'not-a-valid-url',
|
||||
timestamp: null,
|
||||
color: null,
|
||||
author: null,
|
||||
provider: null,
|
||||
thumbnail: null,
|
||||
image: null,
|
||||
video: null,
|
||||
footer: null,
|
||||
fields: null,
|
||||
nsfw: null,
|
||||
children: null,
|
||||
});
|
||||
|
||||
expect(embed.url).toBeNull();
|
||||
expect(embed.toMessageEmbed().url).toBeNull();
|
||||
});
|
||||
|
||||
it('keeps valid embed urls', () => {
|
||||
const embed = new Embed({
|
||||
type: 'rich',
|
||||
title: null,
|
||||
description: null,
|
||||
url: ' https://remote.example/post/1 ',
|
||||
timestamp: null,
|
||||
color: null,
|
||||
author: null,
|
||||
provider: null,
|
||||
thumbnail: null,
|
||||
image: null,
|
||||
video: null,
|
||||
footer: null,
|
||||
fields: null,
|
||||
nsfw: null,
|
||||
children: null,
|
||||
});
|
||||
|
||||
expect(embed.url).toBe('https://remote.example/post/1');
|
||||
expect(embed.toMessageEmbed().url).toBe('https://remote.example/post/1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('EmbedProvider URL sanitisation', () => {
|
||||
it('normalises invalid provider url values to null', () => {
|
||||
const provider = new EmbedProvider({
|
||||
name: 'Example',
|
||||
url: 'not-a-valid-url',
|
||||
});
|
||||
|
||||
expect(provider.url).toBeNull();
|
||||
expect(provider.toMessageEmbedProvider().url).toBeNull();
|
||||
});
|
||||
|
||||
it('keeps valid provider urls', () => {
|
||||
const provider = new EmbedProvider({
|
||||
name: 'Example',
|
||||
url: ' https://remote.example ',
|
||||
});
|
||||
|
||||
expect(provider.url).toBe('https://remote.example/');
|
||||
expect(provider.toMessageEmbedProvider().url).toBe('https://remote.example/');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user