- Introduced `PATCH /admin/:uuid` endpoint for admin-specific user updates. - Updated `update` logic to handle role assignment via `rbacService`. - Refactored `findAll` method in repository for improved readability.
166 lines
3.9 KiB
TypeScript
166 lines
3.9 KiB
TypeScript
import { Injectable } from "@nestjs/common";
|
|
import { and, eq, lte, 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,
|
|
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 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();
|
|
}
|
|
}
|