Files
memegoat/backend/src/users/repositories/users.repository.ts
Mathis HERRIOT 5753477717 feat: add user preferences for online status and read receipts with real-time updates
- Introduced `showOnlineStatus` and `showReadReceipts` fields in the user schema and API.
- Integrated real-time status broadcasting in `UsersService` via `EventsGateway`.
- Updated repository and frontend user types to align with new fields.
- Enhanced user update handling to support dynamic preference changes for online status.
2026-01-29 18:18:52 +01:00

186 lines
4.4 KiB
TypeScript

import { Injectable } from "@nestjs/common";
import { and, eq, ilike, lte, or, sql } from "drizzle-orm";
import { DatabaseService } from "../../database/database.service";
import { contents, favorites, users } from "../../database/schemas";
@Injectable()
export class UsersRepository {
constructor(private readonly databaseService: DatabaseService) {}
async create(data: {
username: string;
email: string;
passwordHash: string;
emailHash: string;
}) {
const [newUser] = await this.databaseService.db
.insert(users)
.values(data)
.returning();
return newUser;
}
async findByEmailHash(emailHash: string) {
const result = await this.databaseService.db
.select({
uuid: users.uuid,
username: users.username,
email: users.email,
passwordHash: users.passwordHash,
status: users.status,
isTwoFactorEnabled: users.isTwoFactorEnabled,
})
.from(users)
.where(eq(users.emailHash, emailHash))
.limit(1);
return result[0] || null;
}
async findOneWithPrivateData(uuid: string) {
const result = await this.databaseService.db
.select({
uuid: users.uuid,
username: users.username,
email: users.email,
displayName: users.displayName,
avatarUrl: users.avatarUrl,
bio: users.bio,
status: users.status,
isTwoFactorEnabled: users.isTwoFactorEnabled,
showOnlineStatus: users.showOnlineStatus,
showReadReceipts: users.showReadReceipts,
createdAt: users.createdAt,
updatedAt: users.updatedAt,
})
.from(users)
.where(eq(users.uuid, uuid))
.limit(1);
return result[0] || null;
}
async countAll() {
const result = await this.databaseService.db
.select({ count: sql<number>`count(*)` })
.from(users);
return Number(result[0].count);
}
async findAll(limit: number, offset: number) {
const result = await this.databaseService.db
.select({
uuid: users.uuid,
username: users.username,
email: users.email,
displayName: users.displayName,
avatarUrl: users.avatarUrl,
status: users.status,
createdAt: users.createdAt,
})
.from(users)
.limit(limit)
.offset(offset);
return result;
}
async findByUsername(username: string) {
const result = await this.databaseService.db
.select({
uuid: users.uuid,
username: users.username,
displayName: users.displayName,
avatarUrl: users.avatarUrl,
bio: users.bio,
createdAt: users.createdAt,
})
.from(users)
.where(eq(users.username, username))
.limit(1);
return result[0] || null;
}
async search(query: string) {
return this.databaseService.db
.select({
uuid: users.uuid,
username: users.username,
displayName: users.displayName,
avatarUrl: users.avatarUrl,
})
.from(users)
.where(
or(
ilike(users.username, `%${query}%`),
ilike(users.displayName, `%${query}%`),
),
)
.limit(10);
}
async findOne(uuid: string) {
const result = await this.databaseService.db
.select()
.from(users)
.where(eq(users.uuid, uuid))
.limit(1);
return result[0] || null;
}
async update(uuid: string, data: Partial<typeof users.$inferInsert>) {
return await this.databaseService.db
.update(users)
.set({ ...data, updatedAt: new Date() })
.where(eq(users.uuid, uuid))
.returning();
}
async getTwoFactorSecret(uuid: string) {
const result = await this.databaseService.db
.select({
secret: users.twoFactorSecret,
})
.from(users)
.where(eq(users.uuid, uuid))
.limit(1);
return result[0]?.secret || null;
}
async getUserContents(uuid: string) {
return await this.databaseService.db
.select()
.from(contents)
.where(eq(contents.userId, uuid));
}
async getUserFavorites(uuid: string) {
return await this.databaseService.db
.select()
.from(favorites)
.where(eq(favorites.userId, uuid));
}
async softDeleteUserAndContents(uuid: string) {
return await this.databaseService.db.transaction(async (tx) => {
const userResult = await tx
.update(users)
.set({ status: "deleted", deletedAt: new Date() })
.where(eq(users.uuid, uuid))
.returning();
await tx
.update(contents)
.set({ deletedAt: new Date() })
.where(eq(contents.userId, uuid));
return userResult;
});
}
async purgeDeleted(before: Date) {
return await this.databaseService.db
.delete(users)
.where(and(eq(users.status, "deleted"), lte(users.deletedAt, before)))
.returning();
}
}