- Introduced a detailed PlantUML diagram illustrating backend modules, services, controllers, and key relationships. - Enhanced documentation with visual representation of system architecture for improved understanding.
757 lines
36 KiB
Plaintext
757 lines
36 KiB
Plaintext
@startuml
|
|
|
|
!theme plain
|
|
top to bottom direction
|
|
skinparam linetype ortho
|
|
|
|
class AdminController {
|
|
constructor(adminService: AdminService):
|
|
getStats(): Promise<{users: number, contents: numbe…
|
|
}
|
|
class AdminModule
|
|
class AdminService {
|
|
constructor(usersRepository: UsersRepository, contentsRepository: ContentsRepository, categoriesRepository: CategoriesRepository):
|
|
getStats(): Promise<{users: number, contents: numbe…
|
|
}
|
|
class AllExceptionsFilter {
|
|
logger: Logger
|
|
catch(exception: unknown, host: ArgumentsHost): void
|
|
}
|
|
class ApiKeysController {
|
|
constructor(apiKeysService: ApiKeysService):
|
|
create(req: AuthenticatedRequest, createApiKeyDto: CreateApiKeyDto): Promise<{name: string, key: string, exp…
|
|
findAll(req: AuthenticatedRequest): Promise<any>
|
|
revoke(req: AuthenticatedRequest, id: string): Promise<any>
|
|
}
|
|
class ApiKeysModule
|
|
class ApiKeysRepository {
|
|
constructor(databaseService: DatabaseService):
|
|
create(data: {userId: string; name: string; prefix: string; keyHash: string; expiresAt?: Date}): Promise<any>
|
|
findAll(userId: string): Promise<any>
|
|
revoke(userId: string, keyId: string): Promise<any>
|
|
findActiveByKeyHash(keyHash: string): Promise<any>
|
|
updateLastUsed(id: string): Promise<any>
|
|
}
|
|
class ApiKeysService {
|
|
constructor(apiKeysRepository: ApiKeysRepository, hashingService: HashingService):
|
|
logger: Logger
|
|
create(userId: string, name: string, expiresAt?: Date): Promise<{name: string, key: string, exp…
|
|
findAll(userId: string): Promise<any>
|
|
revoke(userId: string, keyId: string): Promise<any>
|
|
validateKey(key: string): Promise<any>
|
|
}
|
|
class AppController {
|
|
constructor(appService: AppService):
|
|
getHello(): string
|
|
}
|
|
class AppModule {
|
|
configure(consumer: MiddlewareConsumer): void
|
|
}
|
|
class AppService {
|
|
getHello(): string
|
|
}
|
|
class AuditLogInDb
|
|
class AuthController {
|
|
constructor(authService: AuthService, bootstrapService: BootstrapService, configService: ConfigService):
|
|
register(registerDto: RegisterDto): Promise<{message: string, userId: any}>
|
|
login(loginDto: LoginDto, userAgent: string, req: Request, res: Response): Promise<Response<any, Record<string, an…
|
|
verifyTwoFactor(verify2faDto: Verify2faDto, userAgent: string, req: Request, res: Response): Promise<Response<any, Record<string, an…
|
|
refresh(req: Request, res: Response): Promise<Response<any, Record<string, an…
|
|
logout(req: Request, res: Response): Promise<Response<any, Record<string, an…
|
|
bootstrapAdmin(token: string, username: string): Promise<{message: string}>
|
|
}
|
|
class AuthGuard {
|
|
constructor(jwtService: JwtService, configService: ConfigService):
|
|
canActivate(context: ExecutionContext): Promise<boolean>
|
|
}
|
|
class AuthModule
|
|
class AuthService {
|
|
constructor(usersService: UsersService, hashingService: HashingService, jwtService: JwtService, sessionsService: SessionsService, configService: ConfigService):
|
|
logger: Logger
|
|
generateTwoFactorSecret(userId: string): Promise<{secret: string, qrCodeDataUrl:…
|
|
enableTwoFactor(userId: string, token: string): Promise<{message: string}>
|
|
disableTwoFactor(userId: string, token: string): Promise<{message: string}>
|
|
register(dto: RegisterDto): Promise<{message: string, userId: any}>
|
|
login(dto: LoginDto, userAgent?: string, ip?: string): Promise<{message: string, requires2FA: …
|
|
verifyTwoFactorLogin(userId: string, token: string, userAgent?: string, ip?: string): Promise<{message: string, access_token:…
|
|
refresh(refreshToken: string): Promise<{access_token: string, refresh_…
|
|
logout(): Promise<{message: string}>
|
|
}
|
|
class AuthenticatedRequest {
|
|
user: {sub: string, username: string}
|
|
}
|
|
class BootstrapService {
|
|
constructor(rbacService: RbacService, usersService: UsersService, configService: ConfigService):
|
|
logger: Logger
|
|
bootstrapToken: string | null
|
|
onApplicationBootstrap(): Promise<void>
|
|
generateBootstrapToken(): void
|
|
consumeToken(token: string, username: string): Promise<{message: string}>
|
|
}
|
|
class CategoriesController {
|
|
constructor(categoriesService: CategoriesService):
|
|
findAll(): Promise<any>
|
|
findOne(id: string): Promise<any>
|
|
create(createCategoryDto: CreateCategoryDto): Promise<any>
|
|
update(id: string, updateCategoryDto: UpdateCategoryDto): Promise<any>
|
|
remove(id: string): Promise<any>
|
|
}
|
|
class CategoriesModule
|
|
class CategoriesRepository {
|
|
constructor(databaseService: DatabaseService):
|
|
findAll(): Promise<any>
|
|
countAll(): Promise<number>
|
|
findOne(id: string): Promise<any>
|
|
create(data: CreateCategoryDto & {slug: string}): Promise<any>
|
|
update(id: string, data: UpdateCategoryDto & {slug?: string; updatedAt: Date}): Promise<any>
|
|
remove(id: string): Promise<any>
|
|
}
|
|
class CategoriesService {
|
|
constructor(categoriesRepository: CategoriesRepository, cacheManager: Cache):
|
|
logger: Logger
|
|
clearCategoriesCache(): Promise<void>
|
|
findAll(): Promise<any>
|
|
findOne(id: string): Promise<any>
|
|
create(data: CreateCategoryDto): Promise<any>
|
|
update(id: string, data: UpdateCategoryDto): Promise<any>
|
|
remove(id: string): Promise<any>
|
|
}
|
|
class CategoryInDb
|
|
class ClamScanner {
|
|
scanStream(stream: Readable): Promise<{isInfected: boolean, viruses: …
|
|
}
|
|
class CommonModule
|
|
class ContentInDb
|
|
class ContentType {
|
|
MEME:
|
|
GIF:
|
|
}
|
|
class ContentsController {
|
|
constructor(contentsService: ContentsService):
|
|
create(req: AuthenticatedRequest, createContentDto: CreateContentDto): Promise<any>
|
|
getUploadUrl(req: AuthenticatedRequest, fileName: string): Promise<{url: string, key: string}>
|
|
upload(req: AuthenticatedRequest, file: Express.Multer.File, uploadContentDto: UploadContentDto): Promise<any>
|
|
explore(req: AuthenticatedRequest, limit: number, offset: number, sort?: "trend" | "recent", tag?: string, category?: string, author?: string): Promise<{data: any, totalCount: any}>
|
|
trends(req: AuthenticatedRequest, limit: number, offset: number): Promise<{data: any, totalCount: any}>
|
|
recent(req: AuthenticatedRequest, limit: number, offset: number): Promise<{data: any, totalCount: any}>
|
|
findOne(idOrSlug: string, req: AuthenticatedRequest, res: Response): Promise<Response<any, Record<string, an…
|
|
incrementViews(id: string): Promise<void>
|
|
incrementUsage(id: string): Promise<void>
|
|
update(id: string, req: AuthenticatedRequest, updateContentDto: any): Promise<any>
|
|
remove(id: string, req: AuthenticatedRequest): Promise<any>
|
|
removeAdmin(id: string): Promise<any>
|
|
updateAdmin(id: string, updateContentDto: any): Promise<any>
|
|
}
|
|
class ContentsModule
|
|
class ContentsRepository {
|
|
constructor(databaseService: DatabaseService):
|
|
findAll(options: FindAllOptions): Promise<any>
|
|
create(data: NewContentInDb & {userId: string}, tagNames?: string[]): Promise<any>
|
|
findOne(idOrSlug: string, userId?: string): Promise<any>
|
|
count(options: {tag?: string; category?: string; author?: string; query?: string; favoritesOnly?: boolean; userId?: string}): Promise<number>
|
|
incrementViews(id: string): Promise<void>
|
|
incrementUsage(id: string): Promise<void>
|
|
softDelete(id: string, userId: string): Promise<any>
|
|
softDeleteAdmin(id: string): Promise<any>
|
|
update(id: string, data: Partial<typeof contents.$inferInsert>): Promise<any>
|
|
findBySlug(slug: string): Promise<any>
|
|
purgeSoftDeleted(before: Date): Promise<any>
|
|
}
|
|
class ContentsService {
|
|
constructor(contentsRepository: ContentsRepository, s3Service: IStorageService, mediaService: IMediaService, configService: ConfigService, cacheManager: Cache):
|
|
logger: Logger
|
|
clearContentsCache(): Promise<void>
|
|
getUploadUrl(userId: string, fileName: string): Promise<{url: string, key: string}>
|
|
uploadAndProcess(userId: string, file: Express.Multer.File, data: UploadContentDto): Promise<any>
|
|
findAll(options: {limit: number; offset: number; sortBy?: "trend" | "recent"; tag?: string; category?: string; author?: string; query?: string; favoritesOnly?: boolean; userId?: string}): Promise<{data: any, totalCount: any}>
|
|
create(userId: string, data: CreateContentDto): Promise<any>
|
|
incrementViews(id: string): Promise<void>
|
|
incrementUsage(id: string): Promise<void>
|
|
remove(id: string, userId: string): Promise<any>
|
|
removeAdmin(id: string): Promise<any>
|
|
updateAdmin(id: string, data: any): Promise<any>
|
|
update(id: string, userId: string, data: any): Promise<any>
|
|
findOne(idOrSlug: string, userId?: string): Promise<any>
|
|
generateBotHtml(content: {title: string; storageKey: string}): string
|
|
generateSlug(text: string): string
|
|
ensureUniqueSlug(title: string): Promise<string>
|
|
}
|
|
class CrawlerDetectionMiddleware {
|
|
logger: Logger
|
|
SUSPICIOUS_PATTERNS: RegExp[]
|
|
BOT_USER_AGENTS: RegExp[]
|
|
use(req: Request, res: Response, next: NextFunction): void
|
|
}
|
|
class CreateApiKeyDto {
|
|
name: string
|
|
expiresAt: string
|
|
}
|
|
class CreateCategoryDto {
|
|
name: string
|
|
description: string
|
|
iconUrl: string
|
|
}
|
|
class CreateContentDto {
|
|
type: "meme" | "gif"
|
|
title: string
|
|
storageKey: string
|
|
mimeType: string
|
|
fileSize: number
|
|
categoryId: string
|
|
tags: string[]
|
|
}
|
|
class CreateReportDto {
|
|
contentId: string
|
|
tagId: string
|
|
reason: "inappropriate" | "spam" | "copyright" …
|
|
description: string
|
|
}
|
|
class CryptoModule
|
|
class CryptoService {
|
|
constructor(hashingService: HashingService, jwtService: JwtService, encryptionService: EncryptionService, postQuantumService: PostQuantumService):
|
|
hashEmail(email: string): Promise<string>
|
|
hashIp(ip: string): Promise<string>
|
|
getPgpEncryptionKey(): string
|
|
hashPassword(password: string): Promise<string>
|
|
verifyPassword(password: string, hash: string): Promise<boolean>
|
|
generateJwt(payload: jose.JWTPayload, expiresIn?: string): Promise<string>
|
|
verifyJwt(token: string): Promise<T>
|
|
encryptContent(content: string): Promise<string>
|
|
decryptContent(jwe: string): Promise<string>
|
|
signContent(content: string): Promise<string>
|
|
verifyContentSignature(jws: string): Promise<string>
|
|
generatePostQuantumKeyPair(): {publicKey: Uint8Array<ArrayBufferLike>…
|
|
encapsulate(publicKey: Uint8Array): {cipherText: Uint8Array, sharedSecret: …
|
|
decapsulate(cipherText: Uint8Array, secretKey: Uint8Array): Uint8Array<ArrayBufferLike>
|
|
}
|
|
class DatabaseModule
|
|
class DatabaseService {
|
|
constructor(configService: ConfigService):
|
|
logger: Logger
|
|
pool: Pool
|
|
db: ReturnType<typeof drizzle>
|
|
onModuleInit(): Promise<void>
|
|
onModuleDestroy(): Promise<void>
|
|
getDatabaseConnectionString(): string
|
|
}
|
|
class EncryptionService {
|
|
constructor(configService: ConfigService):
|
|
logger: Logger
|
|
jwtSecret: Uint8Array
|
|
encryptionKey: Uint8Array
|
|
encryptContent(content: string): Promise<string>
|
|
decryptContent(jwe: string): Promise<string>
|
|
signContent(content: string): Promise<string>
|
|
verifyContentSignature(jws: string): Promise<string>
|
|
getPgpEncryptionKey(): string
|
|
}
|
|
class Env
|
|
class FavoriteInDb
|
|
class FavoritesController {
|
|
constructor(favoritesService: FavoritesService):
|
|
add(req: AuthenticatedRequest, contentId: string): Promise<any>
|
|
remove(req: AuthenticatedRequest, contentId: string): Promise<any>
|
|
list(req: AuthenticatedRequest, limit: number, offset: number): Promise<any>
|
|
}
|
|
class FavoritesModule
|
|
class FavoritesRepository {
|
|
constructor(databaseService: DatabaseService):
|
|
findContentById(contentId: string): Promise<any>
|
|
add(userId: string, contentId: string): Promise<any>
|
|
remove(userId: string, contentId: string): Promise<any>
|
|
findByUserId(userId: string, limit: number, offset: number): Promise<any>
|
|
}
|
|
class FavoritesService {
|
|
constructor(favoritesRepository: FavoritesRepository):
|
|
logger: Logger
|
|
addFavorite(userId: string, contentId: string): Promise<any>
|
|
removeFavorite(userId: string, contentId: string): Promise<any>
|
|
getUserFavorites(userId: string, limit: number, offset: number): Promise<any>
|
|
}
|
|
class FindAllOptions {
|
|
limit: number
|
|
offset: number
|
|
sortBy: "trend" | "recent"
|
|
tag: string
|
|
category: string
|
|
author: string
|
|
query: string
|
|
favoritesOnly: boolean
|
|
userId: string
|
|
}
|
|
class HTTPLoggerMiddleware {
|
|
logger: Logger
|
|
use(request: Request, response: Response, next: NextFunction): void
|
|
}
|
|
class HashingService {
|
|
hashEmail(email: string): Promise<string>
|
|
hashIp(ip: string): Promise<string>
|
|
hashSha256(text: string): Promise<string>
|
|
hashPassword(password: string): Promise<string>
|
|
verifyPassword(password: string, hash: string): Promise<boolean>
|
|
}
|
|
class HealthController {
|
|
constructor(databaseService: DatabaseService, cacheManager: Cache):
|
|
check(): Promise<any>
|
|
}
|
|
class IMailService {
|
|
sendEmailValidation(email: string, token: string): Promise<void>
|
|
sendPasswordReset(email: string, token: string): Promise<void>
|
|
}
|
|
class IMediaProcessorStrategy {
|
|
canHandle(mimeType: string): boolean
|
|
process(buffer: Buffer, options?: Record<string, unknown>): Promise<MediaProcessingResult>
|
|
}
|
|
class IMediaService {
|
|
scanFile(buffer: Buffer, filename: string): Promise<ScanResult>
|
|
processImage(buffer: Buffer, format?: "webp" | "avif", resize?: {width?: number; height?: number}): Promise<MediaProcessingResult>
|
|
processVideo(buffer: Buffer, format?: "webm" | "av1"): Promise<MediaProcessingResult>
|
|
}
|
|
class IStorageService {
|
|
uploadFile(fileName: string, file: Buffer, mimeType: string, metaData?: Record<string, string>, bucketName?: string): Promise<string>
|
|
getFile(fileName: string, bucketName?: string): Promise<Readable>
|
|
getFileUrl(fileName: string, expiry?: number, bucketName?: string): Promise<string>
|
|
getUploadUrl(fileName: string, expiry?: number, bucketName?: string): Promise<string>
|
|
deleteFile(fileName: string, bucketName?: string): Promise<void>
|
|
getFileInfo(fileName: string, bucketName?: string): Promise<unknown>
|
|
moveFile(sourceFileName: string, destinationFileName: string, sourceBucketName?: string, destinationBucketName?: string): Promise<string>
|
|
getPublicUrl(storageKey: string): string
|
|
}
|
|
class ImageProcessorStrategy {
|
|
logger: Logger
|
|
canHandle(mimeType: string): boolean
|
|
process(buffer: Buffer, options?: {format: "webp" | "avif"; resize?: {width?: number; height?: number}}): Promise<MediaProcessingResult>
|
|
}
|
|
class JwtService {
|
|
constructor(configService: ConfigService):
|
|
logger: Logger
|
|
jwtSecret: Uint8Array
|
|
generateJwt(payload: jose.JWTPayload, expiresIn?: string): Promise<string>
|
|
verifyJwt(token: string): Promise<T>
|
|
}
|
|
class LoginDto {
|
|
email: string
|
|
password: string
|
|
}
|
|
class MailModule
|
|
class MailService {
|
|
constructor(mailerService: MailerService, configService: ConfigService):
|
|
logger: Logger
|
|
domain: string
|
|
sendEmailValidation(email: string, token: string): Promise<void>
|
|
sendPasswordReset(email: string, token: string): Promise<void>
|
|
}
|
|
class MediaController {
|
|
constructor(s3Service: S3Service):
|
|
logger: Logger
|
|
getFile(path: string, res: Response): Promise<void>
|
|
}
|
|
class MediaModule
|
|
class MediaProcessingResult {
|
|
buffer: Buffer
|
|
mimeType: string
|
|
extension: string
|
|
width: number
|
|
height: number
|
|
size: number
|
|
}
|
|
class MediaProcessingResult {
|
|
buffer: Buffer
|
|
mimeType: string
|
|
extension: string
|
|
width: number
|
|
height: number
|
|
size: number
|
|
}
|
|
class MediaService {
|
|
constructor(configService: ConfigService, imageProcessor: ImageProcessorStrategy, videoProcessor: VideoProcessorStrategy):
|
|
logger: Logger
|
|
clamscan: ClamScanner | null
|
|
isClamAvInitialized: boolean
|
|
initClamScan(): Promise<void>
|
|
scanFile(buffer: Buffer, filename: string): Promise<ScanResult>
|
|
processImage(buffer: Buffer, format?: "webp" | "avif", resize?: {width?: number; height?: number}): Promise<MediaProcessingResult>
|
|
processVideo(buffer: Buffer, format?: "webm" | "av1"): Promise<MediaProcessingResult>
|
|
}
|
|
class NewAuditLogInDb
|
|
class NewCategoryInDb
|
|
class NewContentInDb
|
|
class NewFavoriteInDb
|
|
class NewReportInDb
|
|
class NewTagInDb
|
|
class NewUserInDb
|
|
class OptionalAuthGuard {
|
|
constructor(jwtService: JwtService, configService: ConfigService):
|
|
canActivate(context: ExecutionContext): Promise<boolean>
|
|
}
|
|
class PostQuantumService {
|
|
generatePostQuantumKeyPair(): {publicKey: Uint8Array<ArrayBufferLike>…
|
|
encapsulate(publicKey: Uint8Array): {cipherText: Uint8Array, sharedSecret: …
|
|
decapsulate(cipherText: Uint8Array, secretKey: Uint8Array): Uint8Array<ArrayBufferLike>
|
|
}
|
|
class PurgeService {
|
|
constructor(sessionsRepository: SessionsRepository, reportsRepository: ReportsRepository, usersRepository: UsersRepository, contentsRepository: ContentsRepository):
|
|
logger: Logger
|
|
purgeExpiredData(): Promise<void>
|
|
}
|
|
class RbacRepository {
|
|
constructor(databaseService: DatabaseService):
|
|
findRolesByUserId(userId: string): Promise<any>
|
|
findPermissionsByUserId(userId: string): Promise<any[]>
|
|
countRoles(): Promise<number>
|
|
countAdmins(): Promise<number>
|
|
createRole(name: string, slug: string, description?: string): Promise<any>
|
|
assignRole(userId: string, roleSlug: string): Promise<any>
|
|
}
|
|
class RbacService {
|
|
constructor(rbacRepository: RbacRepository):
|
|
logger: Logger
|
|
onApplicationBootstrap(): Promise<void>
|
|
seedRoles(): Promise<void>
|
|
getUserRoles(userId: string): Promise<any>
|
|
getUserPermissions(userId: string): Promise<any[]>
|
|
countAdmins(): Promise<number>
|
|
assignRoleToUser(userId: string, roleSlug: string): Promise<any>
|
|
}
|
|
class RefreshDto {
|
|
refresh_token: string
|
|
}
|
|
class RegisterDto {
|
|
username: string
|
|
displayName: string
|
|
email: string
|
|
password: string
|
|
}
|
|
class ReportInDb
|
|
class ReportReason {
|
|
INAPPROPRIATE:
|
|
SPAM:
|
|
COPYRIGHT:
|
|
OTHER:
|
|
}
|
|
class ReportStatus {
|
|
PENDING:
|
|
REVIEWED:
|
|
RESOLVED:
|
|
DISMISSED:
|
|
}
|
|
class ReportsController {
|
|
constructor(reportsService: ReportsService):
|
|
create(req: AuthenticatedRequest, createReportDto: CreateReportDto): Promise<any>
|
|
findAll(limit: number, offset: number): Promise<any>
|
|
updateStatus(id: string, updateReportStatusDto: UpdateReportStatusDto): Promise<any>
|
|
}
|
|
class ReportsModule
|
|
class ReportsRepository {
|
|
constructor(databaseService: DatabaseService):
|
|
create(data: {reporterId: string; contentId?: string; tagId?: string; reason: "inappropriate" | "spam" | "copyright" | "other"; description?: string}): Promise<any>
|
|
findAll(limit: number, offset: number): Promise<any>
|
|
updateStatus(id: string, status: "pending" | "reviewed" | "resolved" | "dismissed"): Promise<any>
|
|
purgeObsolete(now: Date): Promise<any>
|
|
}
|
|
class ReportsService {
|
|
constructor(reportsRepository: ReportsRepository):
|
|
logger: Logger
|
|
create(reporterId: string, data: CreateReportDto): Promise<any>
|
|
findAll(limit: number, offset: number): Promise<any>
|
|
updateStatus(id: string, status: "pending" | "reviewed" | "resolved" | "dismissed"): Promise<any>
|
|
}
|
|
class RequestWithUser {
|
|
user: {sub?: string, username?: string, id?: …
|
|
}
|
|
class RolesGuard {
|
|
constructor(reflector: Reflector, rbacService: RbacService):
|
|
canActivate(context: ExecutionContext): Promise<boolean>
|
|
}
|
|
class S3Module
|
|
class S3Service {
|
|
constructor(configService: ConfigService):
|
|
logger: Logger
|
|
minioClient: Minio.Client
|
|
bucketName: string
|
|
onModuleInit(): Promise<void>
|
|
ensureBucketExists(bucketName: string): Promise<void>
|
|
uploadFile(fileName: string, file: Buffer, mimeType: string, metaData?: Minio.ItemBucketMetadata, bucketName?: string): Promise<string>
|
|
getFile(fileName: string, bucketName?: string): Promise<stream.Readable>
|
|
getFileUrl(fileName: string, expiry?: number, bucketName?: string): Promise<string>
|
|
getUploadUrl(fileName: string, expiry?: number, bucketName?: string): Promise<string>
|
|
deleteFile(fileName: string, bucketName?: string): Promise<void>
|
|
getFileInfo(fileName: string, bucketName?: string): Promise<BucketItemStat>
|
|
moveFile(sourceFileName: string, destinationFileName: string, sourceBucketName?: string, destinationBucketName?: string): Promise<string>
|
|
getPublicUrl(storageKey: string): string
|
|
}
|
|
class ScanResult {
|
|
isInfected: boolean
|
|
virusName: string
|
|
}
|
|
class ScanResult {
|
|
isInfected: boolean
|
|
virusName: string
|
|
}
|
|
class SessionData {
|
|
accessToken: string
|
|
refreshToken: string
|
|
userId: string
|
|
}
|
|
class SessionsModule
|
|
class SessionsRepository {
|
|
constructor(databaseService: DatabaseService):
|
|
create(data: {userId: string; refreshToken: string; userAgent?: string; ipHash?: string | null; expiresAt: Date}): Promise<any>
|
|
findValidByRefreshToken(refreshToken: string): Promise<any>
|
|
update(sessionId: string, data: Record<string, unknown>): Promise<any>
|
|
revoke(sessionId: string): Promise<void>
|
|
revokeAllByUserId(userId: string): Promise<void>
|
|
purgeExpired(now: Date): Promise<any>
|
|
}
|
|
class SessionsService {
|
|
constructor(sessionsRepository: SessionsRepository, hashingService: HashingService, jwtService: JwtService):
|
|
createSession(userId: string, userAgent?: string, ip?: string): Promise<any>
|
|
refreshSession(oldRefreshToken: string): Promise<any>
|
|
revokeSession(sessionId: string): Promise<void>
|
|
revokeAllUserSessions(userId: string): Promise<void>
|
|
}
|
|
class TagInDb
|
|
class TagsController {
|
|
constructor(tagsService: TagsService):
|
|
findAll(limit: number, offset: number, query?: string, sort?: "popular" | "recent"): Promise<any>
|
|
}
|
|
class TagsModule
|
|
class TagsRepository {
|
|
constructor(databaseService: DatabaseService):
|
|
findAll(options: {limit: number; offset: number; query?: string; sortBy?: "popular" | "recent"}): Promise<any>
|
|
}
|
|
class TagsService {
|
|
constructor(tagsRepository: TagsRepository):
|
|
logger: Logger
|
|
findAll(options: {limit: number; offset: number; query?: string; sortBy?: "popular" | "recent"}): Promise<any>
|
|
}
|
|
class UpdateCategoryDto
|
|
class UpdateConsentDto {
|
|
termsVersion: string
|
|
privacyVersion: string
|
|
}
|
|
class UpdateReportStatusDto {
|
|
status: "pending" | "reviewed" | "resolved" | "…
|
|
}
|
|
class UpdateUserDto {
|
|
displayName: string
|
|
bio: string
|
|
avatarUrl: string
|
|
status: "active" | "verification" | "suspended"…
|
|
role: string
|
|
}
|
|
class UploadContentDto {
|
|
type: "meme" | "gif"
|
|
title: string
|
|
categoryId: string
|
|
tags: string[]
|
|
}
|
|
class UserInDb
|
|
class UsersController {
|
|
constructor(usersService: UsersService, authService: AuthService):
|
|
findAll(limit: number, offset: number): Promise<{data: any, totalCount: any}>
|
|
findPublicProfile(username: string): Promise<any>
|
|
findMe(req: AuthenticatedRequest): Promise<any>
|
|
exportMe(req: AuthenticatedRequest): Promise<null | {profile: any, contents:…
|
|
updateMe(req: AuthenticatedRequest, updateUserDto: UpdateUserDto): Promise<any>
|
|
updateAvatar(req: AuthenticatedRequest, file: Express.Multer.File): Promise<any>
|
|
updateConsent(req: AuthenticatedRequest, consentDto: UpdateConsentDto): Promise<any>
|
|
removeMe(req: AuthenticatedRequest): Promise<any>
|
|
removeAdmin(uuid: string): Promise<any>
|
|
updateAdmin(uuid: string, updateUserDto: UpdateUserDto): Promise<any>
|
|
setup2fa(req: AuthenticatedRequest): Promise<{secret: string, qrCodeDataUrl:…
|
|
enable2fa(req: AuthenticatedRequest, token: string): Promise<{message: string}>
|
|
disable2fa(req: AuthenticatedRequest, token: string): Promise<{message: string}>
|
|
}
|
|
class UsersModule
|
|
class UsersRepository {
|
|
constructor(databaseService: DatabaseService):
|
|
create(data: {username: string; email: string; passwordHash: string; emailHash: string}): Promise<any>
|
|
findByEmailHash(emailHash: string): Promise<any>
|
|
findOneWithPrivateData(uuid: string): Promise<any>
|
|
countAll(): Promise<number>
|
|
findAll(limit: number, offset: number): Promise<any>
|
|
findByUsername(username: string): Promise<any>
|
|
findOne(uuid: string): Promise<any>
|
|
update(uuid: string, data: Partial<typeof users.$inferInsert>): Promise<any>
|
|
getTwoFactorSecret(uuid: string): Promise<any>
|
|
getUserContents(uuid: string): Promise<any>
|
|
getUserFavorites(uuid: string): Promise<any>
|
|
softDeleteUserAndContents(uuid: string): Promise<any>
|
|
purgeDeleted(before: Date): Promise<any>
|
|
}
|
|
class UsersService {
|
|
constructor(usersRepository: UsersRepository, cacheManager: Cache, rbacService: RbacService, mediaService: IMediaService, s3Service: IStorageService):
|
|
logger: Logger
|
|
clearUserCache(username?: string): Promise<void>
|
|
create(data: {username: string; email: string; passwordHash: string; emailHash: string}): Promise<any>
|
|
findByEmailHash(emailHash: string): Promise<any>
|
|
findOneWithPrivateData(uuid: string): Promise<any>
|
|
findAll(limit: number, offset: number): Promise<{data: any, totalCount: any}>
|
|
findPublicProfile(username: string): Promise<any>
|
|
findOne(uuid: string): Promise<any>
|
|
update(uuid: string, data: UpdateUserDto): Promise<any>
|
|
updateAvatar(uuid: string, file: Express.Multer.File): Promise<any>
|
|
updateConsent(uuid: string, termsVersion: string, privacyVersion: string): Promise<any>
|
|
setTwoFactorSecret(uuid: string, secret: string): Promise<any>
|
|
toggleTwoFactor(uuid: string, enabled: boolean): Promise<any>
|
|
getTwoFactorSecret(uuid: string): Promise<string | null>
|
|
exportUserData(uuid: string): Promise<null | {profile: any, contents:…
|
|
remove(uuid: string): Promise<any>
|
|
}
|
|
class Verify2faDto {
|
|
userId: string
|
|
token: string
|
|
}
|
|
class VideoProcessorStrategy {
|
|
logger: Logger
|
|
canHandle(mimeType: string): boolean
|
|
process(buffer: Buffer, options?: {format: "webm" | "av1"}): Promise<MediaProcessingResult>
|
|
}
|
|
|
|
AdminController -[#595959,dashed]-> AdminService
|
|
AdminService -[#595959,dashed]-> CategoriesRepository
|
|
AdminService -[#595959,dashed]-> ContentsRepository
|
|
AdminService -[#595959,dashed]-> UsersRepository
|
|
AllExceptionsFilter -[#595959,dashed]-> RequestWithUser
|
|
ApiKeysController -[#595959,dashed]-> ApiKeysService
|
|
ApiKeysController -[#595959,dashed]-> AuthenticatedRequest
|
|
ApiKeysController -[#595959,dashed]-> CreateApiKeyDto
|
|
ApiKeysRepository -[#595959,dashed]-> DatabaseService
|
|
ApiKeysService -[#595959,dashed]-> ApiKeysRepository
|
|
ApiKeysService -[#595959,dashed]-> ApiKeysService
|
|
ApiKeysService -[#595959,dashed]-> HashingService
|
|
AppController -[#595959,dashed]-> AppService
|
|
AppModule -[#595959,dashed]-> CrawlerDetectionMiddleware
|
|
AppModule -[#595959,dashed]-> HTTPLoggerMiddleware
|
|
AuthController -[#595959,dashed]-> AuthService
|
|
AuthController -[#595959,dashed]-> BootstrapService
|
|
AuthController -[#595959,dashed]-> LoginDto
|
|
AuthController -[#595959,dashed]-> RegisterDto
|
|
AuthController -[#595959,dashed]-> SessionData
|
|
AuthController -[#595959,dashed]-> Verify2faDto
|
|
AuthGuard -[#595959,dashed]-> JwtService
|
|
AuthGuard -[#595959,dashed]-> SessionData
|
|
AuthService -[#595959,dashed]-> AuthService
|
|
AuthService -[#595959,dashed]-> HashingService
|
|
AuthService -[#595959,dashed]-> JwtService
|
|
AuthService -[#595959,dashed]-> LoginDto
|
|
AuthService -[#595959,dashed]-> RegisterDto
|
|
AuthService -[#595959,dashed]-> SessionsService
|
|
AuthService -[#595959,dashed]-> UsersService
|
|
BootstrapService -[#595959,dashed]-> BootstrapService
|
|
BootstrapService -[#595959,dashed]-> RbacService
|
|
BootstrapService -[#595959,dashed]-> UsersService
|
|
CategoriesController -[#595959,dashed]-> AuthGuard
|
|
CategoriesController -[#595959,dashed]-> CategoriesService
|
|
CategoriesController -[#595959,dashed]-> CreateCategoryDto
|
|
CategoriesController -[#595959,dashed]-> RolesGuard
|
|
CategoriesController -[#595959,dashed]-> UpdateCategoryDto
|
|
CategoriesRepository -[#595959,dashed]-> CreateCategoryDto
|
|
CategoriesRepository -[#595959,dashed]-> DatabaseService
|
|
CategoriesRepository -[#595959,dashed]-> UpdateCategoryDto
|
|
CategoriesService -[#595959,dashed]-> CategoriesRepository
|
|
CategoriesService -[#595959,dashed]-> CategoriesService
|
|
CategoriesService -[#595959,dashed]-> CreateCategoryDto
|
|
CategoriesService -[#595959,dashed]-> UpdateCategoryDto
|
|
ContentsController -[#595959,dashed]-> AuthGuard
|
|
ContentsController -[#595959,dashed]-> AuthenticatedRequest
|
|
ContentsController -[#595959,dashed]-> ContentsService
|
|
ContentsController -[#595959,dashed]-> CreateContentDto
|
|
ContentsController -[#595959,dashed]-> OptionalAuthGuard
|
|
ContentsController -[#595959,dashed]-> RolesGuard
|
|
ContentsController -[#595959,dashed]-> UploadContentDto
|
|
ContentsRepository -[#595959,dashed]-> DatabaseService
|
|
ContentsRepository -[#595959,dashed]-> FindAllOptions
|
|
ContentsRepository -[#595959,dashed]-> NewContentInDb
|
|
ContentsService -[#595959,dashed]-> ContentsRepository
|
|
ContentsService -[#595959,dashed]-> ContentsService
|
|
ContentsService -[#595959,dashed]-> CreateContentDto
|
|
ContentsService -[#595959,dashed]-> IMediaService
|
|
ContentsService -[#595959,dashed]-> IStorageService
|
|
ContentsService -[#595959,dashed]-> MediaProcessingResult
|
|
ContentsService -[#595959,dashed]-> MediaService
|
|
ContentsService -[#595959,dashed]-> S3Service
|
|
ContentsService -[#595959,dashed]-> UploadContentDto
|
|
CryptoService -[#595959,dashed]-> EncryptionService
|
|
CryptoService -[#595959,dashed]-> HashingService
|
|
CryptoService -[#595959,dashed]-> JwtService
|
|
CryptoService -[#595959,dashed]-> PostQuantumService
|
|
DatabaseService -[#595959,dashed]-> DatabaseService
|
|
EncryptionService -[#595959,dashed]-> EncryptionService
|
|
FavoritesController -[#595959,dashed]-> AuthenticatedRequest
|
|
FavoritesController -[#595959,dashed]-> FavoritesService
|
|
FavoritesRepository -[#595959,dashed]-> DatabaseService
|
|
FavoritesService -[#595959,dashed]-> FavoritesRepository
|
|
FavoritesService -[#595959,dashed]-> FavoritesService
|
|
HealthController -[#595959,dashed]-> DatabaseService
|
|
IMediaProcessorStrategy -[#595959,dashed]-> MediaProcessingResult
|
|
IMediaService -[#595959,dashed]-> MediaProcessingResult
|
|
IMediaService -[#595959,dashed]-> ScanResult
|
|
ImageProcessorStrategy -[#008200,dashed]-^ IMediaProcessorStrategy
|
|
ImageProcessorStrategy -[#595959,dashed]-> ImageProcessorStrategy
|
|
ImageProcessorStrategy -[#595959,dashed]-> MediaProcessingResult
|
|
JwtService -[#595959,dashed]-> JwtService
|
|
MailService -[#008200,dashed]-^ IMailService
|
|
MailService -[#595959,dashed]-> MailService
|
|
MediaController -[#595959,dashed]-> MediaController
|
|
MediaController -[#595959,dashed]-> S3Service
|
|
MediaService -[#595959,dashed]-> ClamScanner
|
|
MediaService -[#008200,dashed]-^ IMediaService
|
|
MediaService -[#595959,dashed]-> ImageProcessorStrategy
|
|
MediaService -[#595959,dashed]-> MediaProcessingResult
|
|
MediaService -[#595959,dashed]-> MediaService
|
|
MediaService -[#595959,dashed]-> ScanResult
|
|
MediaService -[#595959,dashed]-> VideoProcessorStrategy
|
|
OptionalAuthGuard -[#595959,dashed]-> JwtService
|
|
OptionalAuthGuard -[#595959,dashed]-> SessionData
|
|
PurgeService -[#595959,dashed]-> ContentsRepository
|
|
PurgeService -[#595959,dashed]-> PurgeService
|
|
PurgeService -[#595959,dashed]-> ReportsRepository
|
|
PurgeService -[#595959,dashed]-> SessionsRepository
|
|
PurgeService -[#595959,dashed]-> UsersRepository
|
|
RbacRepository -[#595959,dashed]-> DatabaseService
|
|
RbacService -[#595959,dashed]-> RbacRepository
|
|
RbacService -[#595959,dashed]-> RbacService
|
|
ReportsController -[#595959,dashed]-> AuthGuard
|
|
ReportsController -[#595959,dashed]-> AuthenticatedRequest
|
|
ReportsController -[#595959,dashed]-> CreateReportDto
|
|
ReportsController -[#595959,dashed]-> ReportsService
|
|
ReportsController -[#595959,dashed]-> RolesGuard
|
|
ReportsController -[#595959,dashed]-> UpdateReportStatusDto
|
|
ReportsRepository -[#595959,dashed]-> DatabaseService
|
|
ReportsService -[#595959,dashed]-> CreateReportDto
|
|
ReportsService -[#595959,dashed]-> ReportsRepository
|
|
ReportsService -[#595959,dashed]-> ReportsService
|
|
RolesGuard -[#595959,dashed]-> RbacService
|
|
S3Service -[#008200,dashed]-^ IStorageService
|
|
S3Service -[#595959,dashed]-> S3Service
|
|
SessionsRepository -[#595959,dashed]-> DatabaseService
|
|
SessionsService -[#595959,dashed]-> HashingService
|
|
SessionsService -[#595959,dashed]-> JwtService
|
|
SessionsService -[#595959,dashed]-> SessionsRepository
|
|
TagsController -[#595959,dashed]-> TagsService
|
|
TagsRepository -[#595959,dashed]-> DatabaseService
|
|
TagsService -[#595959,dashed]-> TagsRepository
|
|
TagsService -[#595959,dashed]-> TagsService
|
|
UsersController -[#595959,dashed]-> AuthGuard
|
|
UsersController -[#595959,dashed]-> AuthService
|
|
UsersController -[#595959,dashed]-> AuthenticatedRequest
|
|
UsersController -[#595959,dashed]-> RolesGuard
|
|
UsersController -[#595959,dashed]-> UpdateConsentDto
|
|
UsersController -[#595959,dashed]-> UpdateUserDto
|
|
UsersController -[#595959,dashed]-> UsersService
|
|
UsersRepository -[#595959,dashed]-> DatabaseService
|
|
UsersService -[#595959,dashed]-> IMediaService
|
|
UsersService -[#595959,dashed]-> IStorageService
|
|
UsersService -[#595959,dashed]-> MediaService
|
|
UsersService -[#595959,dashed]-> RbacService
|
|
UsersService -[#595959,dashed]-> S3Service
|
|
UsersService -[#595959,dashed]-> UpdateUserDto
|
|
UsersService -[#595959,dashed]-> UsersRepository
|
|
UsersService -[#595959,dashed]-> UsersService
|
|
VideoProcessorStrategy -[#008200,dashed]-^ IMediaProcessorStrategy
|
|
VideoProcessorStrategy -[#595959,dashed]-> MediaProcessingResult
|
|
VideoProcessorStrategy -[#595959,dashed]-> VideoProcessorStrategy
|
|
@enduml
|