/* * 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 . */ import type {ChannelID, GuildID, MessageID, PhoneVerificationToken, UserID} from '~/BrandedTypes'; import type { AuthSessionRow, BetaCodeRow, EmailRevertTokenRow, EmailVerificationTokenRow, GiftCodeRow, PasswordResetTokenRow, PaymentBySubscriptionRow, PaymentRow, PhoneTokenRow, PushSubscriptionRow, RecentMentionRow, RelationshipRow, UserGuildSettingsRow, UserRow, UserSettingsRow, } from '~/database/CassandraTypes'; import type { AuthSession, BetaCode, Channel, EmailRevertToken, EmailVerificationToken, GiftCode, MfaBackupCode, PasswordResetToken, Payment, PushSubscription, ReadState, RecentMention, Relationship, SavedMessage, User, UserGuildSettings, UserNote, UserSettings, VisionarySlot, WebAuthnCredential, } from '~/Models'; import {ReadStateRepository} from '~/read_state/ReadStateRepository'; import type {PrivateChannelSummary} from './IUserChannelRepository'; import type {IUserRepositoryAggregate} from './IUserRepositoryAggregate'; import {UserAccountRepository} from './UserAccountRepository'; import {UserAuthRepository} from './UserAuthRepository'; import {UserChannelRepository} from './UserChannelRepository'; import {UserContentRepository} from './UserContentRepository'; import {UserRelationshipRepository} from './UserRelationshipRepository'; import {UserSettingsRepository} from './UserSettingsRepository'; export class UserRepository implements IUserRepositoryAggregate { private accountRepo: UserAccountRepository; private settingsRepo: UserSettingsRepository; private authRepo: UserAuthRepository; private relationshipRepo: UserRelationshipRepository; private channelRepo: UserChannelRepository; private contentRepo: UserContentRepository; private readStateRepo: ReadStateRepository; constructor() { this.accountRepo = new UserAccountRepository(); this.settingsRepo = new UserSettingsRepository(); this.authRepo = new UserAuthRepository(this.accountRepo); this.relationshipRepo = new UserRelationshipRepository(); this.channelRepo = new UserChannelRepository(); this.contentRepo = new UserContentRepository(); this.readStateRepo = new ReadStateRepository(); } async create(data: UserRow): Promise { return this.accountRepo.create(data); } async upsert(data: UserRow, oldData?: UserRow | null): Promise { return this.accountRepo.upsert(data, oldData); } async patchUpsert(userId: UserID, patchData: Partial, oldData?: UserRow | null): Promise { return this.accountRepo.patchUpsert(userId, patchData, oldData); } async findUnique(userId: UserID): Promise { return this.accountRepo.findUnique(userId); } async findUniqueAssert(userId: UserID): Promise { return this.accountRepo.findUniqueAssert(userId); } async findByUsernameDiscriminator(username: string, discriminator: number): Promise { return this.accountRepo.findByUsernameDiscriminator(username, discriminator); } async findDiscriminatorsByUsername(username: string): Promise> { return this.accountRepo.findDiscriminatorsByUsername(username); } async findByEmail(email: string): Promise { return this.accountRepo.findByEmail(email); } async findByPhone(phone: string): Promise { return this.accountRepo.findByPhone(phone); } async findByStripeSubscriptionId(stripeSubscriptionId: string): Promise { return this.accountRepo.findByStripeSubscriptionId(stripeSubscriptionId); } async findByStripeCustomerId(stripeCustomerId: string): Promise { return this.accountRepo.findByStripeCustomerId(stripeCustomerId); } async listUsers(userIds: Array): Promise> { return this.accountRepo.listUsers(userIds); } async listAllUsersPaginated(limit: number, lastUserId?: UserID): Promise> { return this.accountRepo.listAllUsersPaginated(limit, lastUserId); } async getUserGuildIds(userId: UserID): Promise> { return this.accountRepo.getUserGuildIds(userId); } async getActivityTracking(userId: UserID): Promise<{last_active_at: Date | null; last_active_ip: string | null}> { return this.accountRepo.getActivityTracking(userId); } async addPendingDeletion(userId: UserID, pendingDeletionAt: Date, deletionReasonCode: number): Promise { return this.accountRepo.addPendingDeletion(userId, pendingDeletionAt, deletionReasonCode); } async removePendingDeletion(userId: UserID, pendingDeletionAt: Date): Promise { return this.accountRepo.removePendingDeletion(userId, pendingDeletionAt); } async findUsersPendingDeletion(now: Date): Promise> { return this.accountRepo.findUsersPendingDeletion(now); } async findUsersPendingDeletionByDate( deletionDate: string, ): Promise> { return this.accountRepo.findUsersPendingDeletionByDate(deletionDate); } async isUserPendingDeletion(userId: UserID, deletionDate: string): Promise { return this.accountRepo.isUserPendingDeletion(userId, deletionDate); } async scheduleDeletion(userId: UserID, pendingDeletionAt: Date, deletionReasonCode: number): Promise { return this.accountRepo.scheduleDeletion(userId, pendingDeletionAt, deletionReasonCode); } async deleteUserSecondaryIndices(userId: UserID): Promise { return this.accountRepo.deleteUserSecondaryIndices(userId); } async removeFromAllGuilds(userId: UserID): Promise { return this.accountRepo.removeFromAllGuilds(userId); } async updateLastActiveAt(params: {userId: UserID; lastActiveAt: Date; lastActiveIp?: string}): Promise { return this.accountRepo.updateLastActiveAt(params); } async findSettings(userId: UserID): Promise { return this.settingsRepo.findSettings(userId); } async upsertSettings(settings: UserSettingsRow): Promise { return this.settingsRepo.upsertSettings(settings); } async deleteUserSettings(userId: UserID): Promise { return this.settingsRepo.deleteUserSettings(userId); } async findGuildSettings(userId: UserID, guildId: GuildID | null): Promise { return this.settingsRepo.findGuildSettings(userId, guildId); } async findAllGuildSettings(userId: UserID): Promise> { return this.settingsRepo.findAllGuildSettings(userId); } async upsertGuildSettings(settings: UserGuildSettingsRow): Promise { return this.settingsRepo.upsertGuildSettings(settings); } async deleteGuildSettings(userId: UserID, guildId: GuildID): Promise { return this.settingsRepo.deleteGuildSettings(userId, guildId); } async deleteAllUserGuildSettings(userId: UserID): Promise { return this.settingsRepo.deleteAllUserGuildSettings(userId); } async listAuthSessions(userId: UserID): Promise> { return this.authRepo.listAuthSessions(userId); } async getAuthSessionByToken(sessionIdHash: Buffer): Promise { return this.authRepo.getAuthSessionByToken(sessionIdHash); } async createAuthSession(sessionData: AuthSessionRow): Promise { return this.authRepo.createAuthSession(sessionData); } async updateAuthSessionLastUsed(sessionIdHash: Buffer): Promise { return this.authRepo.updateAuthSessionLastUsed(sessionIdHash); } async deleteAuthSessions(userId: UserID, sessionIdHashes: Array): Promise { return this.authRepo.deleteAuthSessions(userId, sessionIdHashes); } async revokeAuthSession(sessionIdHash: Buffer): Promise { return this.authRepo.revokeAuthSession(sessionIdHash); } async deleteAllAuthSessions(userId: UserID): Promise { return this.authRepo.deleteAllAuthSessions(userId); } async listMfaBackupCodes(userId: UserID): Promise> { return this.authRepo.listMfaBackupCodes(userId); } async createMfaBackupCodes(userId: UserID, codes: Array): Promise> { return this.authRepo.createMfaBackupCodes(userId, codes); } async clearMfaBackupCodes(userId: UserID): Promise { return this.authRepo.clearMfaBackupCodes(userId); } async consumeMfaBackupCode(userId: UserID, code: string): Promise { return this.authRepo.consumeMfaBackupCode(userId, code); } async deleteAllMfaBackupCodes(userId: UserID): Promise { return this.authRepo.deleteAllMfaBackupCodes(userId); } async getEmailVerificationToken(token: string): Promise { return this.authRepo.getEmailVerificationToken(token); } async createEmailVerificationToken(tokenData: EmailVerificationTokenRow): Promise { return this.authRepo.createEmailVerificationToken(tokenData); } async deleteEmailVerificationToken(token: string): Promise { return this.authRepo.deleteEmailVerificationToken(token); } async getPasswordResetToken(token: string): Promise { return this.authRepo.getPasswordResetToken(token); } async createPasswordResetToken(tokenData: PasswordResetTokenRow): Promise { return this.authRepo.createPasswordResetToken(tokenData); } async deletePasswordResetToken(token: string): Promise { return this.authRepo.deletePasswordResetToken(token); } async getEmailRevertToken(token: string): Promise { return this.authRepo.getEmailRevertToken(token); } async createEmailRevertToken(tokenData: EmailRevertTokenRow): Promise { return this.authRepo.createEmailRevertToken(tokenData); } async deleteEmailRevertToken(token: string): Promise { return this.authRepo.deleteEmailRevertToken(token); } async createPhoneToken(token: PhoneVerificationToken, phone: string, userId: UserID | null): Promise { return this.authRepo.createPhoneToken(token, phone, userId); } async getPhoneToken(token: PhoneVerificationToken): Promise { return this.authRepo.getPhoneToken(token); } async deletePhoneToken(token: PhoneVerificationToken): Promise { return this.authRepo.deletePhoneToken(token); } async updateUserActivity(userId: UserID, clientIp: string): Promise { return this.authRepo.updateUserActivity(userId, clientIp); } async checkIpAuthorized(userId: UserID, ip: string): Promise { return this.authRepo.checkIpAuthorized(userId, ip); } async createAuthorizedIp(userId: UserID, ip: string): Promise { return this.authRepo.createAuthorizedIp(userId, ip); } async createIpAuthorizationToken(userId: UserID, token: string): Promise { return this.authRepo.createIpAuthorizationToken(userId, token); } async authorizeIpByToken(token: string): Promise<{userId: UserID; email: string} | null> { return this.authRepo.authorizeIpByToken(token); } async getAuthorizedIps(userId: UserID): Promise> { return this.authRepo.getAuthorizedIps(userId); } async deleteAllAuthorizedIps(userId: UserID): Promise { return this.authRepo.deleteAllAuthorizedIps(userId); } async listWebAuthnCredentials(userId: UserID): Promise> { return this.authRepo.listWebAuthnCredentials(userId); } async getWebAuthnCredential(userId: UserID, credentialId: string): Promise { return this.authRepo.getWebAuthnCredential(userId, credentialId); } async createWebAuthnCredential( userId: UserID, credentialId: string, publicKey: Buffer, counter: bigint, transports: Set | null, name: string, ): Promise { return this.authRepo.createWebAuthnCredential(userId, credentialId, publicKey, counter, transports, name); } async updateWebAuthnCredentialCounter(userId: UserID, credentialId: string, counter: bigint): Promise { return this.authRepo.updateWebAuthnCredentialCounter(userId, credentialId, counter); } async updateWebAuthnCredentialLastUsed(userId: UserID, credentialId: string): Promise { return this.authRepo.updateWebAuthnCredentialLastUsed(userId, credentialId); } async updateWebAuthnCredentialName(userId: UserID, credentialId: string, name: string): Promise { return this.authRepo.updateWebAuthnCredentialName(userId, credentialId, name); } async deleteWebAuthnCredential(userId: UserID, credentialId: string): Promise { return this.authRepo.deleteWebAuthnCredential(userId, credentialId); } async getUserIdByCredentialId(credentialId: string): Promise { return this.authRepo.getUserIdByCredentialId(credentialId); } async deleteAllWebAuthnCredentials(userId: UserID): Promise { return this.authRepo.deleteAllWebAuthnCredentials(userId); } async createPendingVerification(userId: UserID, createdAt: Date, metadata: Map): Promise { return this.authRepo.createPendingVerification(userId, createdAt, metadata); } async deletePendingVerification(userId: UserID): Promise { return this.authRepo.deletePendingVerification(userId); } async listRelationships(sourceUserId: UserID): Promise> { return this.relationshipRepo.listRelationships(sourceUserId); } async getRelationship(sourceUserId: UserID, targetUserId: UserID, type: number): Promise { return this.relationshipRepo.getRelationship(sourceUserId, targetUserId, type); } async upsertRelationship(relationship: RelationshipRow): Promise { return this.relationshipRepo.upsertRelationship(relationship); } async deleteRelationship(sourceUserId: UserID, targetUserId: UserID, type: number): Promise { return this.relationshipRepo.deleteRelationship(sourceUserId, targetUserId, type); } async deleteAllRelationships(userId: UserID): Promise { return this.relationshipRepo.deleteAllRelationships(userId); } async getUserNote(sourceUserId: UserID, targetUserId: UserID): Promise { return this.relationshipRepo.getUserNote(sourceUserId, targetUserId); } async getUserNotes(sourceUserId: UserID): Promise> { return this.relationshipRepo.getUserNotes(sourceUserId); } async upsertUserNote(sourceUserId: UserID, targetUserId: UserID, note: string): Promise { return this.relationshipRepo.upsertUserNote(sourceUserId, targetUserId, note); } async clearUserNote(sourceUserId: UserID, targetUserId: UserID): Promise { return this.relationshipRepo.clearUserNote(sourceUserId, targetUserId); } async deleteAllNotes(userId: UserID): Promise { return this.relationshipRepo.deleteAllNotes(userId); } async listPrivateChannels(userId: UserID): Promise> { return this.channelRepo.listPrivateChannels(userId); } async listHistoricalDmChannelIds(userId: UserID): Promise> { return this.channelRepo.listHistoricalDmChannelIds(userId); } async recordHistoricalDmChannel(userId: UserID, channelId: ChannelID, isGroupDm: boolean): Promise { return this.channelRepo.recordHistoricalDmChannel(userId, channelId, isGroupDm); } async listPrivateChannelSummaries(userId: UserID): Promise> { return this.channelRepo.listPrivateChannelSummaries(userId); } async deleteAllPrivateChannels(userId: UserID): Promise { return this.channelRepo.deleteAllPrivateChannels(userId); } async findExistingDmState(user1Id: UserID, user2Id: UserID): Promise { return this.channelRepo.findExistingDmState(user1Id, user2Id); } async createDmChannelAndState(user1Id: UserID, user2Id: UserID, channelId: ChannelID): Promise { return this.channelRepo.createDmChannelAndState(user1Id, user2Id, channelId); } async isDmChannelOpen(userId: UserID, channelId: ChannelID): Promise { return this.channelRepo.isDmChannelOpen(userId, channelId); } async openDmForUser(userId: UserID, channelId: ChannelID, isGroupDm?: boolean): Promise { return this.channelRepo.openDmForUser(userId, channelId, isGroupDm); } async closeDmForUser(userId: UserID, channelId: ChannelID): Promise { return this.channelRepo.closeDmForUser(userId, channelId); } async getPinnedDms(userId: UserID): Promise> { return this.channelRepo.getPinnedDms(userId); } async getPinnedDmsWithDetails(userId: UserID): Promise> { return this.channelRepo.getPinnedDmsWithDetails(userId); } async addPinnedDm(userId: UserID, channelId: ChannelID): Promise> { return this.channelRepo.addPinnedDm(userId, channelId); } async removePinnedDm(userId: UserID, channelId: ChannelID): Promise> { return this.channelRepo.removePinnedDm(userId, channelId); } async deletePinnedDmsByUserId(userId: UserID): Promise { return this.channelRepo.deletePinnedDmsByUserId(userId); } async deleteAllReadStates(userId: UserID): Promise { return this.channelRepo.deleteAllReadStates(userId); } async getReadStates(userId: UserID): Promise> { return this.readStateRepo.listReadStates(userId); } async getRecentMention(userId: UserID, messageId: MessageID): Promise { return this.contentRepo.getRecentMention(userId, messageId); } async listRecentMentions( userId: UserID, includeEveryone: boolean, includeRole: boolean, includeGuilds: boolean, limit: number, before?: MessageID, ): Promise> { return this.contentRepo.listRecentMentions(userId, includeEveryone, includeRole, includeGuilds, limit, before); } async createRecentMention(mention: RecentMentionRow): Promise { return this.contentRepo.createRecentMention(mention); } async createRecentMentions(mentions: Array): Promise { return this.contentRepo.createRecentMentions(mentions); } async deleteRecentMention(mention: RecentMention): Promise { return this.contentRepo.deleteRecentMention(mention); } async deleteAllRecentMentions(userId: UserID): Promise { return this.contentRepo.deleteAllRecentMentions(userId); } async listSavedMessages(userId: UserID, limit?: number, before?: MessageID): Promise> { return this.contentRepo.listSavedMessages(userId, limit, before); } async createSavedMessage(userId: UserID, channelId: ChannelID, messageId: MessageID): Promise { return this.contentRepo.createSavedMessage(userId, channelId, messageId); } async deleteSavedMessage(userId: UserID, messageId: MessageID): Promise { return this.contentRepo.deleteSavedMessage(userId, messageId); } async deleteAllSavedMessages(userId: UserID): Promise { return this.contentRepo.deleteAllSavedMessages(userId); } async listBetaCodes(creatorId: UserID): Promise> { return this.contentRepo.listBetaCodes(creatorId); } async getBetaCode(code: string): Promise { return this.contentRepo.getBetaCode(code); } async upsertBetaCode(betaCode: BetaCodeRow): Promise { return this.contentRepo.upsertBetaCode(betaCode); } async updateBetaCodeRedeemed(code: string, redeemerId: UserID, redeemedAt: Date): Promise { return this.contentRepo.updateBetaCodeRedeemed(code, redeemerId, redeemedAt); } async deleteBetaCode(code: string, creatorId: UserID): Promise { return this.contentRepo.deleteBetaCode(code, creatorId); } async deleteAllBetaCodes(userId: UserID): Promise { return this.contentRepo.deleteAllBetaCodes(userId); } async createGiftCode(data: GiftCodeRow): Promise { return this.contentRepo.createGiftCode(data); } async findGiftCode(code: string): Promise { return this.contentRepo.findGiftCode(code); } async findGiftCodeByPaymentIntent(paymentIntentId: string): Promise { return this.contentRepo.findGiftCodeByPaymentIntent(paymentIntentId); } async findGiftCodesByCreator(userId: UserID): Promise> { return this.contentRepo.findGiftCodesByCreator(userId); } async redeemGiftCode(code: string, userId: UserID): Promise<{applied: boolean}> { return this.contentRepo.redeemGiftCode(code, userId); } async updateGiftCode(code: string, data: Partial): Promise { return this.contentRepo.updateGiftCode(code, data); } async linkGiftCodeToCheckoutSession(code: string, checkoutSessionId: string): Promise { return this.contentRepo.linkGiftCodeToCheckoutSession(code, checkoutSessionId); } async listPushSubscriptions(userId: UserID): Promise> { return this.contentRepo.listPushSubscriptions(userId); } async createPushSubscription(data: PushSubscriptionRow): Promise { return this.contentRepo.createPushSubscription(data); } async deletePushSubscription(userId: UserID, subscriptionId: string): Promise { return this.contentRepo.deletePushSubscription(userId, subscriptionId); } async getBulkPushSubscriptions(userIds: Array): Promise>> { return this.contentRepo.getBulkPushSubscriptions(userIds); } async deleteAllPushSubscriptions(userId: UserID): Promise { return this.contentRepo.deleteAllPushSubscriptions(userId); } async createPayment(data: { checkout_session_id: string; user_id: UserID; price_id: string; product_type: string; status: string; is_gift: boolean; created_at: Date; }): Promise { return this.contentRepo.createPayment(data); } async updatePayment(data: Partial & {checkout_session_id: string}): Promise<{applied: boolean}> { return this.contentRepo.updatePayment(data); } async getPaymentByCheckoutSession(checkoutSessionId: string): Promise { return this.contentRepo.getPaymentByCheckoutSession(checkoutSessionId); } async getPaymentByPaymentIntent(paymentIntentId: string): Promise { return this.contentRepo.getPaymentByPaymentIntent(paymentIntentId); } async getSubscriptionInfo(subscriptionId: string): Promise { return this.contentRepo.getSubscriptionInfo(subscriptionId); } async listVisionarySlots(): Promise> { return this.contentRepo.listVisionarySlots(); } async expandVisionarySlots(byCount: number): Promise { return this.contentRepo.expandVisionarySlots(byCount); } async shrinkVisionarySlots(toCount: number): Promise { return this.contentRepo.shrinkVisionarySlots(toCount); } async reserveVisionarySlot(slotIndex: number, userId: UserID): Promise { return this.contentRepo.reserveVisionarySlot(slotIndex, userId); } async unreserveVisionarySlot(slotIndex: number, userId: UserID): Promise { return this.contentRepo.unreserveVisionarySlot(slotIndex, userId); } }