import { ConflictException, Injectable } from '@nestjs/common'; import * as Upload from 'graphql-upload/Upload.js'; import * as sharp from 'sharp'; import { SocialLink, User } from '@/prisma/generated'; import { PrismaService } from '@/src/core/prisma/prisma.service'; import { ChangeProfileInfoInput } from '@/src/module/auth/profile/inputs/change-profile-info.input'; import { SocialLinkInput, SocialLinkOrderInput, } from '@/src/module/auth/profile/inputs/social-link.input'; import { StorageService } from '../../libs/storage/storage.service'; @Injectable() export class ProfileService { constructor( private readonly prismaService: PrismaService, private readonly storageService: StorageService, ) { } public async changeAvatar(user: User, file: Upload) { if (user.avatar) { await this.storageService.remove(user.avatar); } const chunks: Buffer[] = []; for await (const chunk of file.createReadStream()) { chunks.push(chunk); } const buffer = Buffer.concat(chunks); const fileName = `/channels/${user.name}.webp`; const processedBuffer = await sharp(buffer, { animated: file.filename.endsWith('.gif') }) .resize(512, 512) .webp() .toBuffer(); await this.storageService.upload(processedBuffer, fileName, 'image/webp'); await this.prismaService.user.update({ where: { id: user.id }, data: { avatar: fileName }, }); return true; } public async removeAvatar(user: User) { if (!user.avatar) { return true; } await this.storageService.remove(user.avatar); await this.prismaService.user.update({ where: { id: user.id }, data: { avatar: null }, }); return true; } public async changeInfo(user: User, input: ChangeProfileInfoInput) { const { bio = user.bio, displayName = user.displayName, name = user.name } = input; const existingUser = await this.prismaService.user.findUnique({ where: { name }, }); if (existingUser && user.name !== name) { throw new ConflictException('Пользователь с таким именем уже существует'); } return this.prismaService.user.update({ where: { id: user.id }, data: { bio, displayName, name }, }); } public async createSocialLink(user: User, input: SocialLinkInput) { const { title, url } = input; const lastSocialLink = await this.prismaService.socialLink.findFirst({ where: { userId: user.id }, orderBy: { position: 'desc' }, }); return this.prismaService.socialLink.create({ data: { url, title, position: lastSocialLink ? lastSocialLink.position + 1 : 1, user: { connect: { id: user.id, }, }, }, }); } public async findSocialLink(user: User) { return this.prismaService.socialLink.findMany({ where: { userId: user.id }, }); } public async reorderSocialLinks(list: SocialLinkOrderInput[]) { if (list.length === 0) { return; } const updatePromises = list.map(async (socialLink) => this.prismaService.socialLink.update({ where: { id: socialLink.id }, data: { position: Number(socialLink.position) }, })); await Promise.all(updatePromises); return true; } public async updateSocialLink(id: SocialLink['id'], input: SocialLinkInput) { const { title, url } = input; return this.prismaService.socialLink.update({ where: { id }, data: { title, url }, }); } public async removeSocialLink(id: SocialLink['id']) { await this.prismaService.socialLink.delete({ where: { id }, }); return true; } }