refactor(server): use new storage providers (#5433)

This commit is contained in:
liuyi
2024-01-03 10:56:54 +00:00
parent a709624ebf
commit 0d34805375
42 changed files with 614 additions and 679 deletions

View File

@@ -0,0 +1,40 @@
import {
Controller,
ForbiddenException,
Get,
NotFoundException,
Param,
Res,
} from '@nestjs/common';
import type { Response } from 'express';
import { AvatarStorage } from '../storage';
@Controller('/api/avatars')
export class UserAvatarController {
constructor(private readonly storage: AvatarStorage) {}
@Get('/:id')
async getAvatar(@Res() res: Response, @Param('id') id: string) {
if (this.storage.provider.type !== 'fs') {
throw new ForbiddenException(
'Only available when avatar storage provider set to fs.'
);
}
const { body, metadata } = await this.storage.get(id);
if (!body) {
throw new NotFoundException(`Avatar ${id} not found.`);
}
// metadata should always exists if body is not null
if (metadata) {
res.setHeader('content-type', metadata.contentType);
res.setHeader('last-modified', metadata.lastModified.toISOString());
res.setHeader('content-length', metadata.contentLength);
}
body.pipe(res);
}
}

View File

@@ -3,12 +3,14 @@ import { Module } from '@nestjs/common';
import { FeatureModule } from '../features';
import { QuotaModule } from '../quota';
import { StorageModule } from '../storage';
import { UserAvatarController } from './controller';
import { UserResolver } from './resolver';
import { UsersService } from './users';
@Module({
imports: [StorageModule, FeatureModule, QuotaModule],
providers: [UserResolver, UsersService],
controllers: [UserAvatarController],
exports: [UsersService],
})
export class UsersModule {}

View File

@@ -17,6 +17,7 @@ import type { User } from '@prisma/client';
import { GraphQLError } from 'graphql';
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
import { EventEmitter } from '../../event';
import { PrismaService } from '../../prisma/service';
import { CloudThrottlerGuard, Throttle } from '../../throttler';
import type { FileUpload } from '../../types';
@@ -24,7 +25,7 @@ import { Auth, CurrentUser, Public, Publicable } from '../auth/guard';
import { AuthService } from '../auth/service';
import { FeatureManagementService } from '../features';
import { QuotaService } from '../quota';
import { StorageService } from '../storage/storage.service';
import { AvatarStorage } from '../storage';
import { DeleteAccount, RemoveAvatar, UserQuotaType, UserType } from './types';
import { UsersService } from './users';
@@ -39,10 +40,11 @@ export class UserResolver {
constructor(
private readonly auth: AuthService,
private readonly prisma: PrismaService,
private readonly storage: StorageService,
private readonly storage: AvatarStorage,
private readonly users: UsersService,
private readonly feature: FeatureManagementService,
private readonly quota: QuotaService
private readonly quota: QuotaService,
private readonly event: EventEmitter
) {}
@Throttle({
@@ -147,10 +149,20 @@ export class UserResolver {
if (!user) {
throw new BadRequestException(`User not found`);
}
const url = await this.storage.uploadFile(`${user.id}-avatar`, avatar);
const link = await this.storage.put(
`${user.id}-avatar`,
avatar.createReadStream(),
{
contentType: avatar.mimetype,
}
);
return this.prisma.user.update({
where: { id: user.id },
data: { avatarUrl: url },
data: {
avatarUrl: link,
},
});
}
@@ -183,7 +195,8 @@ export class UserResolver {
})
@Mutation(() => DeleteAccount)
async deleteAccount(@CurrentUser() user: UserType): Promise<DeleteAccount> {
await this.users.deleteUser(user.id);
const deletedUser = await this.users.deleteUser(user.id);
this.event.emit('user.deleted', deletedUser);
return { success: true };
}