143 lines
3.6 KiB
TypeScript
143 lines
3.6 KiB
TypeScript
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;
|
||
}
|
||
}
|