feat: 支持图片上传接口
This commit is contained in:
11
package-lock.json
generated
11
package-lock.json
generated
@@ -49,6 +49,7 @@
|
|||||||
"@swc/core": "^1.10.7",
|
"@swc/core": "^1.10.7",
|
||||||
"@types/express": "^5.0.0",
|
"@types/express": "^5.0.0",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
|
"@types/multer": "^2.0.0",
|
||||||
"@types/node": "^22.10.7",
|
"@types/node": "^22.10.7",
|
||||||
"@types/sequelize": "^4.28.20",
|
"@types/sequelize": "^4.28.20",
|
||||||
"@types/supertest": "^6.0.2",
|
"@types/supertest": "^6.0.2",
|
||||||
@@ -3385,6 +3386,16 @@
|
|||||||
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
|
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/multer": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://mirrors.tencent.com/npm/@types/multer/-/multer-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/express": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.13.13",
|
"version": "22.13.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.13.tgz",
|
||||||
|
|||||||
@@ -67,6 +67,7 @@
|
|||||||
"@swc/core": "^1.10.7",
|
"@swc/core": "^1.10.7",
|
||||||
"@types/express": "^5.0.0",
|
"@types/express": "^5.0.0",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
|
"@types/multer": "^2.0.0",
|
||||||
"@types/node": "^22.10.7",
|
"@types/node": "^22.10.7",
|
||||||
"@types/sequelize": "^4.28.20",
|
"@types/sequelize": "^4.28.20",
|
||||||
"@types/supertest": "^6.0.2",
|
"@types/supertest": "^6.0.2",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Injectable, Logger, BadRequestException } from '@nestjs/common';
|
import { Injectable, Logger, BadRequestException } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import * as STS from 'qcloud-cos-sts';
|
import * as STS from 'qcloud-cos-sts';
|
||||||
|
import * as COS from 'cos-nodejs-sdk-v5';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -10,20 +11,25 @@ export class CosService {
|
|||||||
private readonly secretKey: string;
|
private readonly secretKey: string;
|
||||||
private readonly bucket: string;
|
private readonly bucket: string;
|
||||||
private readonly region: string;
|
private readonly region: string;
|
||||||
private readonly cdnDomain: string;
|
|
||||||
private readonly allowPrefix: string;
|
private readonly allowPrefix: string;
|
||||||
|
private readonly cosClient: COS;
|
||||||
|
|
||||||
constructor(private configService: ConfigService) {
|
constructor(private configService: ConfigService) {
|
||||||
this.secretId = this.configService.get<string>('TENCENT_SECRET_ID') || '';
|
this.secretId = this.configService.get<string>('TENCENT_SECRET_ID') || '';
|
||||||
this.secretKey = this.configService.get<string>('TENCENT_SECRET_KEY') || '';
|
this.secretKey = this.configService.get<string>('TENCENT_SECRET_KEY') || '';
|
||||||
this.bucket = this.configService.get<string>('COS_BUCKET') || '';
|
this.bucket = this.configService.get<string>('COS_BUCKET') || '';
|
||||||
this.region = this.configService.get<string>('COS_REGION') || 'ap-guangzhou';
|
this.region = this.configService.get<string>('COS_REGION') || 'ap-guangzhou';
|
||||||
this.cdnDomain = this.configService.get<string>('COS_CDN_DOMAIN') || 'https://cdn.richarjiang.com';
|
|
||||||
this.allowPrefix = this.configService.get<string>('COS_ALLOW_PREFIX') || 'uploads/*';
|
this.allowPrefix = this.configService.get<string>('COS_ALLOW_PREFIX') || 'uploads/*';
|
||||||
|
|
||||||
if (!this.secretId || !this.secretKey || !this.bucket) {
|
if (!this.secretId || !this.secretKey || !this.bucket) {
|
||||||
throw new Error('腾讯云COS配置缺失:TENCENT_SECRET_ID, TENCENT_SECRET_KEY, COS_BUCKET 是必需的');
|
throw new Error('腾讯云COS配置缺失:TENCENT_SECRET_ID, TENCENT_SECRET_KEY, COS_BUCKET 是必需的');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化COS客户端
|
||||||
|
this.cosClient = new COS({
|
||||||
|
SecretId: this.secretId,
|
||||||
|
SecretKey: this.secretKey,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,7 +59,6 @@ export class CosService {
|
|||||||
bucket: this.bucket,
|
bucket: this.bucket,
|
||||||
region: this.region,
|
region: this.region,
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
cdnDomain: this.cdnDomain,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.logger.log(`临时密钥获取成功,用户ID: ${userId}, 有效期至: ${new Date(stsResult.expiredTime * 1000)}`);
|
this.logger.log(`临时密钥获取成功,用户ID: ${userId}, 有效期至: ${new Date(stsResult.expiredTime * 1000)}`);
|
||||||
@@ -172,12 +177,8 @@ export class CosService {
|
|||||||
/**
|
/**
|
||||||
* 生成文件访问URL
|
* 生成文件访问URL
|
||||||
*/
|
*/
|
||||||
private generateFileUrl(fileKey: string): string {
|
private generateFileUrl(uploadResult: COS.UploadFileResult): string {
|
||||||
if (this.cdnDomain) {
|
return `https://${uploadResult.Location}`
|
||||||
return `${this.cdnDomain}/${fileKey}`;
|
|
||||||
} else {
|
|
||||||
return `https://${this.bucket}.cos.${this.region}.myqcloud.com/${fileKey}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -225,4 +226,75 @@ export class CosService {
|
|||||||
|
|
||||||
return limits[fileType as keyof typeof limits] || 10 * 1024 * 1024;
|
return limits[fileType as keyof typeof limits] || 10 * 1024 * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直接上传图片到COS
|
||||||
|
*/
|
||||||
|
async uploadImage(userId: string, file: Express.Multer.File): Promise<any> {
|
||||||
|
try {
|
||||||
|
this.logger.log(`开始上传图片,用户ID: ${userId}, 原始文件名: ${file.originalname}`);
|
||||||
|
|
||||||
|
// 验证文件类型
|
||||||
|
const fileExtension = this.getFileExtension(file.originalname);
|
||||||
|
if (!this.validateFileType('image', fileExtension)) {
|
||||||
|
throw new BadRequestException('不支持的图片格式');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证文件大小
|
||||||
|
const sizeLimit = this.getFileSizeLimit('image');
|
||||||
|
if (file.size > sizeLimit) {
|
||||||
|
throw new BadRequestException(`图片文件大小超过限制 (${sizeLimit / 1024 / 1024}MB)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成唯一文件名
|
||||||
|
const uniqueFileName = this.generateUniqueFileName(file.originalname, fileExtension);
|
||||||
|
const fileKey = `uploads/images/${uniqueFileName}`;
|
||||||
|
|
||||||
|
// 上传到COS
|
||||||
|
const uploadResult = await this.uploadToCos(fileKey, file.buffer, file.mimetype);
|
||||||
|
|
||||||
|
// 生成文件访问URL
|
||||||
|
const fileUrl = this.generateFileUrl(uploadResult);
|
||||||
|
|
||||||
|
const response = {
|
||||||
|
fileUrl,
|
||||||
|
fileKey,
|
||||||
|
originalName: file.originalname,
|
||||||
|
fileSize: file.size,
|
||||||
|
fileType: 'image',
|
||||||
|
mimeType: file.mimetype,
|
||||||
|
uploadTime: new Date(),
|
||||||
|
etag: uploadResult.ETag,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.logger.log(`图片上传成功,用户ID: ${userId}, 文件URL: ${fileUrl}`);
|
||||||
|
return response;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(`上传图片失败: ${error.message}`, error.stack);
|
||||||
|
throw new BadRequestException(`上传图片失败: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件到COS
|
||||||
|
*/
|
||||||
|
private async uploadToCos(key: string, body: Buffer, contentType?: string): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.cosClient.putObject({
|
||||||
|
Bucket: this.bucket,
|
||||||
|
Region: this.region,
|
||||||
|
Key: key,
|
||||||
|
Body: body,
|
||||||
|
ContentType: contentType,
|
||||||
|
ContentLength: body.length,
|
||||||
|
}, (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
27
src/users/dto/upload-image.dto.ts
Normal file
27
src/users/dto/upload-image.dto.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class UploadImageResponseDto {
|
||||||
|
@ApiProperty({ description: '文件访问URL', example: 'https://cdn.richarjiang.com/uploads/images/1673123456789-abc123.jpg' })
|
||||||
|
fileUrl: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '文件存储键', example: 'uploads/images/1673123456789-abc123.jpg' })
|
||||||
|
fileKey: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '原始文件名', example: 'photo.jpg' })
|
||||||
|
originalName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '文件大小(字节)', example: 1024000 })
|
||||||
|
fileSize: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '文件类型', example: 'image' })
|
||||||
|
fileType: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'MIME类型', example: 'image/jpeg' })
|
||||||
|
mimeType: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '上传时间', example: '2024-01-08T10:30:45.123Z' })
|
||||||
|
uploadTime: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'COS ETag', example: '"abc123def456"' })
|
||||||
|
etag: string;
|
||||||
|
}
|
||||||
@@ -14,11 +14,15 @@ import {
|
|||||||
Inject,
|
Inject,
|
||||||
Req,
|
Req,
|
||||||
NotFoundException,
|
NotFoundException,
|
||||||
|
UseInterceptors,
|
||||||
|
UploadedFile,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
import { FileInterceptor } from '@nestjs/platform-express';
|
||||||
import { Request } from 'express';
|
import { Request } from 'express';
|
||||||
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
||||||
import { Logger as WinstonLogger } from 'winston';
|
import { Logger as WinstonLogger } from 'winston';
|
||||||
import { UsersService } from './users.service';
|
import { UsersService } from './users.service';
|
||||||
|
import { UploadImageResponseDto } from './dto/upload-image.dto';
|
||||||
import { CreateUserDto } from './dto/create-user.dto';
|
import { CreateUserDto } from './dto/create-user.dto';
|
||||||
import { UserResponseDto } from './dto/user-response.dto';
|
import { UserResponseDto } from './dto/user-response.dto';
|
||||||
import { ApiOperation, ApiBody, ApiResponse, ApiTags, ApiQuery } from '@nestjs/swagger';
|
import { ApiOperation, ApiBody, ApiResponse, ApiTags, ApiQuery } from '@nestjs/swagger';
|
||||||
@@ -193,6 +197,49 @@ export class UsersController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 上传图片到COS
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Post('cos/upload-image')
|
||||||
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@UseInterceptors(FileInterceptor('file'))
|
||||||
|
@ApiOperation({ summary: '上传图片到COS' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: '图片上传成功',
|
||||||
|
type: UploadImageResponseDto,
|
||||||
|
})
|
||||||
|
@ApiResponse({
|
||||||
|
status: 400,
|
||||||
|
description: '上传失败:文件格式不支持或文件过大',
|
||||||
|
})
|
||||||
|
async uploadImageToCos(
|
||||||
|
@CurrentUser() user: AccessTokenPayload,
|
||||||
|
@UploadedFile() file: Express.Multer.File,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
if (!file) {
|
||||||
|
return { code: ResponseCode.ERROR, message: '请选择要上传的图片文件' };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.winstonLogger.log(`file: ${file}`, {
|
||||||
|
context: 'UsersController',
|
||||||
|
userId: user?.sub,
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = await this.cosService.uploadImage(user.sub, file);
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
this.winstonLogger.error('上传图片失败', {
|
||||||
|
context: 'UsersController',
|
||||||
|
userId: user?.sub,
|
||||||
|
error: (error as Error).message,
|
||||||
|
stack: (error as Error).stack,
|
||||||
|
});
|
||||||
|
return { code: ResponseCode.ERROR, message: (error as Error).message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// App Store 服务器通知接收接口
|
// App Store 服务器通知接收接口
|
||||||
@Public()
|
@Public()
|
||||||
@Post('app-store-notifications')
|
@Post('app-store-notifications')
|
||||||
|
|||||||
73
yarn.lock
73
yarn.lock
@@ -879,12 +879,12 @@
|
|||||||
|
|
||||||
"@napi-rs/nice-android-arm-eabi@1.0.1":
|
"@napi-rs/nice-android-arm-eabi@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.0.1.tgz#9a0cba12706ff56500df127d6f4caf28ddb94936"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.0.1.tgz#9a0cba12706ff56500df127d6f4caf28ddb94936"
|
||||||
integrity sha512-5qpvOu5IGwDo7MEKVqqyAxF90I6aLj4n07OzpARdgDRfz8UbBztTByBp0RC59r3J1Ij8uzYi6jI7r5Lws7nn6w==
|
integrity sha512-5qpvOu5IGwDo7MEKVqqyAxF90I6aLj4n07OzpARdgDRfz8UbBztTByBp0RC59r3J1Ij8uzYi6jI7r5Lws7nn6w==
|
||||||
|
|
||||||
"@napi-rs/nice-android-arm64@1.0.1":
|
"@napi-rs/nice-android-arm64@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.0.1.tgz#32fc32e9649bd759d2a39ad745e95766f6759d2f"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.0.1.tgz#32fc32e9649bd759d2a39ad745e95766f6759d2f"
|
||||||
integrity sha512-GqvXL0P8fZ+mQqG1g0o4AO9hJjQaeYG84FRfZaYjyJtZZZcMjXW5TwkL8Y8UApheJgyE13TQ4YNUssQaTgTyvA==
|
integrity sha512-GqvXL0P8fZ+mQqG1g0o4AO9hJjQaeYG84FRfZaYjyJtZZZcMjXW5TwkL8Y8UApheJgyE13TQ4YNUssQaTgTyvA==
|
||||||
|
|
||||||
"@napi-rs/nice-darwin-arm64@1.0.1":
|
"@napi-rs/nice-darwin-arm64@1.0.1":
|
||||||
@@ -894,67 +894,67 @@
|
|||||||
|
|
||||||
"@napi-rs/nice-darwin-x64@1.0.1":
|
"@napi-rs/nice-darwin-x64@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.0.1.tgz#f1b1365a8370c6a6957e90085a9b4873d0e6a957"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.0.1.tgz#f1b1365a8370c6a6957e90085a9b4873d0e6a957"
|
||||||
integrity sha512-jXnMleYSIR/+TAN/p5u+NkCA7yidgswx5ftqzXdD5wgy/hNR92oerTXHc0jrlBisbd7DpzoaGY4cFD7Sm5GlgQ==
|
integrity sha512-jXnMleYSIR/+TAN/p5u+NkCA7yidgswx5ftqzXdD5wgy/hNR92oerTXHc0jrlBisbd7DpzoaGY4cFD7Sm5GlgQ==
|
||||||
|
|
||||||
"@napi-rs/nice-freebsd-x64@1.0.1":
|
"@napi-rs/nice-freebsd-x64@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.0.1.tgz#4280f081efbe0b46c5165fdaea8b286e55a8f89e"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.0.1.tgz#4280f081efbe0b46c5165fdaea8b286e55a8f89e"
|
||||||
integrity sha512-j+iJ/ezONXRQsVIB/FJfwjeQXX7A2tf3gEXs4WUGFrJjpe/z2KB7sOv6zpkm08PofF36C9S7wTNuzHZ/Iiccfw==
|
integrity sha512-j+iJ/ezONXRQsVIB/FJfwjeQXX7A2tf3gEXs4WUGFrJjpe/z2KB7sOv6zpkm08PofF36C9S7wTNuzHZ/Iiccfw==
|
||||||
|
|
||||||
"@napi-rs/nice-linux-arm-gnueabihf@1.0.1":
|
"@napi-rs/nice-linux-arm-gnueabihf@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.0.1.tgz#07aec23a9467ed35eb7602af5e63d42c5d7bd473"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.0.1.tgz#07aec23a9467ed35eb7602af5e63d42c5d7bd473"
|
||||||
integrity sha512-G8RgJ8FYXYkkSGQwywAUh84m946UTn6l03/vmEXBYNJxQJcD+I3B3k5jmjFG/OPiU8DfvxutOP8bi+F89MCV7Q==
|
integrity sha512-G8RgJ8FYXYkkSGQwywAUh84m946UTn6l03/vmEXBYNJxQJcD+I3B3k5jmjFG/OPiU8DfvxutOP8bi+F89MCV7Q==
|
||||||
|
|
||||||
"@napi-rs/nice-linux-arm64-gnu@1.0.1":
|
"@napi-rs/nice-linux-arm64-gnu@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.0.1.tgz#038a77134cc6df3c48059d5a5e199d6f50fb9a90"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.0.1.tgz#038a77134cc6df3c48059d5a5e199d6f50fb9a90"
|
||||||
integrity sha512-IMDak59/W5JSab1oZvmNbrms3mHqcreaCeClUjwlwDr0m3BoR09ZiN8cKFBzuSlXgRdZ4PNqCYNeGQv7YMTjuA==
|
integrity sha512-IMDak59/W5JSab1oZvmNbrms3mHqcreaCeClUjwlwDr0m3BoR09ZiN8cKFBzuSlXgRdZ4PNqCYNeGQv7YMTjuA==
|
||||||
|
|
||||||
"@napi-rs/nice-linux-arm64-musl@1.0.1":
|
"@napi-rs/nice-linux-arm64-musl@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.0.1.tgz#715d0906582ba0cff025109f42e5b84ea68c2bcc"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.0.1.tgz#715d0906582ba0cff025109f42e5b84ea68c2bcc"
|
||||||
integrity sha512-wG8fa2VKuWM4CfjOjjRX9YLIbysSVV1S3Kgm2Fnc67ap/soHBeYZa6AGMeR5BJAylYRjnoVOzV19Cmkco3QEPw==
|
integrity sha512-wG8fa2VKuWM4CfjOjjRX9YLIbysSVV1S3Kgm2Fnc67ap/soHBeYZa6AGMeR5BJAylYRjnoVOzV19Cmkco3QEPw==
|
||||||
|
|
||||||
"@napi-rs/nice-linux-ppc64-gnu@1.0.1":
|
"@napi-rs/nice-linux-ppc64-gnu@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.0.1.tgz#ac1c8f781c67b0559fa7a1cd4ae3ca2299dc3d06"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.0.1.tgz#ac1c8f781c67b0559fa7a1cd4ae3ca2299dc3d06"
|
||||||
integrity sha512-lxQ9WrBf0IlNTCA9oS2jg/iAjQyTI6JHzABV664LLrLA/SIdD+I1i3Mjf7TsnoUbgopBcCuDztVLfJ0q9ubf6Q==
|
integrity sha512-lxQ9WrBf0IlNTCA9oS2jg/iAjQyTI6JHzABV664LLrLA/SIdD+I1i3Mjf7TsnoUbgopBcCuDztVLfJ0q9ubf6Q==
|
||||||
|
|
||||||
"@napi-rs/nice-linux-riscv64-gnu@1.0.1":
|
"@napi-rs/nice-linux-riscv64-gnu@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.0.1.tgz#b0a430549acfd3920ffd28ce544e2fe17833d263"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.0.1.tgz#b0a430549acfd3920ffd28ce544e2fe17833d263"
|
||||||
integrity sha512-3xs69dO8WSWBb13KBVex+yvxmUeEsdWexxibqskzoKaWx9AIqkMbWmE2npkazJoopPKX2ULKd8Fm9veEn0g4Ig==
|
integrity sha512-3xs69dO8WSWBb13KBVex+yvxmUeEsdWexxibqskzoKaWx9AIqkMbWmE2npkazJoopPKX2ULKd8Fm9veEn0g4Ig==
|
||||||
|
|
||||||
"@napi-rs/nice-linux-s390x-gnu@1.0.1":
|
"@napi-rs/nice-linux-s390x-gnu@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.0.1.tgz#5b95caf411ad72a965885217db378c4d09733e97"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.0.1.tgz#5b95caf411ad72a965885217db378c4d09733e97"
|
||||||
integrity sha512-lMFI3i9rlW7hgToyAzTaEybQYGbQHDrpRkg+1gJWEpH0PLAQoZ8jiY0IzakLfNWnVda1eTYYlxxFYzW8Rqczkg==
|
integrity sha512-lMFI3i9rlW7hgToyAzTaEybQYGbQHDrpRkg+1gJWEpH0PLAQoZ8jiY0IzakLfNWnVda1eTYYlxxFYzW8Rqczkg==
|
||||||
|
|
||||||
"@napi-rs/nice-linux-x64-gnu@1.0.1":
|
"@napi-rs/nice-linux-x64-gnu@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.0.1.tgz#a98cdef517549f8c17a83f0236a69418a90e77b7"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.0.1.tgz#a98cdef517549f8c17a83f0236a69418a90e77b7"
|
||||||
integrity sha512-XQAJs7DRN2GpLN6Fb+ZdGFeYZDdGl2Fn3TmFlqEL5JorgWKrQGRUrpGKbgZ25UeZPILuTKJ+OowG2avN8mThBA==
|
integrity sha512-XQAJs7DRN2GpLN6Fb+ZdGFeYZDdGl2Fn3TmFlqEL5JorgWKrQGRUrpGKbgZ25UeZPILuTKJ+OowG2avN8mThBA==
|
||||||
|
|
||||||
"@napi-rs/nice-linux-x64-musl@1.0.1":
|
"@napi-rs/nice-linux-x64-musl@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.0.1.tgz#5e26843eafa940138aed437c870cca751c8a8957"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.0.1.tgz#5e26843eafa940138aed437c870cca751c8a8957"
|
||||||
integrity sha512-/rodHpRSgiI9o1faq9SZOp/o2QkKQg7T+DK0R5AkbnI/YxvAIEHf2cngjYzLMQSQgUhxym+LFr+UGZx4vK4QdQ==
|
integrity sha512-/rodHpRSgiI9o1faq9SZOp/o2QkKQg7T+DK0R5AkbnI/YxvAIEHf2cngjYzLMQSQgUhxym+LFr+UGZx4vK4QdQ==
|
||||||
|
|
||||||
"@napi-rs/nice-win32-arm64-msvc@1.0.1":
|
"@napi-rs/nice-win32-arm64-msvc@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.0.1.tgz#bd62617d02f04aa30ab1e9081363856715f84cd8"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.0.1.tgz#bd62617d02f04aa30ab1e9081363856715f84cd8"
|
||||||
integrity sha512-rEcz9vZymaCB3OqEXoHnp9YViLct8ugF+6uO5McifTedjq4QMQs3DHz35xBEGhH3gJWEsXMUbzazkz5KNM5YUg==
|
integrity sha512-rEcz9vZymaCB3OqEXoHnp9YViLct8ugF+6uO5McifTedjq4QMQs3DHz35xBEGhH3gJWEsXMUbzazkz5KNM5YUg==
|
||||||
|
|
||||||
"@napi-rs/nice-win32-ia32-msvc@1.0.1":
|
"@napi-rs/nice-win32-ia32-msvc@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.0.1.tgz#b8b7aad552a24836027473d9b9f16edaeabecf18"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.0.1.tgz#b8b7aad552a24836027473d9b9f16edaeabecf18"
|
||||||
integrity sha512-t7eBAyPUrWL8su3gDxw9xxxqNwZzAqKo0Szv3IjVQd1GpXXVkb6vBBQUuxfIYaXMzZLwlxRQ7uzM2vdUE9ULGw==
|
integrity sha512-t7eBAyPUrWL8su3gDxw9xxxqNwZzAqKo0Szv3IjVQd1GpXXVkb6vBBQUuxfIYaXMzZLwlxRQ7uzM2vdUE9ULGw==
|
||||||
|
|
||||||
"@napi-rs/nice-win32-x64-msvc@1.0.1":
|
"@napi-rs/nice-win32-x64-msvc@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.0.1.tgz#37d8718b8f722f49067713e9f1e85540c9a3dd09"
|
resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.0.1.tgz#37d8718b8f722f49067713e9f1e85540c9a3dd09"
|
||||||
integrity sha512-JlF+uDcatt3St2ntBG8H02F1mM45i5SF9W+bIKiReVE6wiy3o16oBP/yxt+RZ+N6LbCImJXJ6bXNO2kn9AXicg==
|
integrity sha512-JlF+uDcatt3St2ntBG8H02F1mM45i5SF9W+bIKiReVE6wiy3o16oBP/yxt+RZ+N6LbCImJXJ6bXNO2kn9AXicg==
|
||||||
|
|
||||||
"@napi-rs/nice@^1.0.1":
|
"@napi-rs/nice@^1.0.1":
|
||||||
@@ -1232,47 +1232,47 @@
|
|||||||
|
|
||||||
"@swc/core-darwin-x64@1.11.13":
|
"@swc/core-darwin-x64@1.11.13":
|
||||||
version "1.11.13"
|
version "1.11.13"
|
||||||
resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.11.13.tgz#9cad870d48ebff805e8946ddcbe3d8312182f70b"
|
resolved "https://mirrors.tencent.com/npm/@swc/core-darwin-x64/-/core-darwin-x64-1.11.13.tgz#9cad870d48ebff805e8946ddcbe3d8312182f70b"
|
||||||
integrity sha512-uSA4UwgsDCIysUPfPS8OrQTH2h9spO7IYFd+1NB6dJlVGUuR6jLKuMBOP1IeLeax4cGHayvkcwSJ3OvxHwgcZQ==
|
integrity sha512-uSA4UwgsDCIysUPfPS8OrQTH2h9spO7IYFd+1NB6dJlVGUuR6jLKuMBOP1IeLeax4cGHayvkcwSJ3OvxHwgcZQ==
|
||||||
|
|
||||||
"@swc/core-linux-arm-gnueabihf@1.11.13":
|
"@swc/core-linux-arm-gnueabihf@1.11.13":
|
||||||
version "1.11.13"
|
version "1.11.13"
|
||||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.13.tgz#51839e5a850bfa300e2c838fee8379e4dba1de78"
|
resolved "https://mirrors.tencent.com/npm/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.13.tgz#51839e5a850bfa300e2c838fee8379e4dba1de78"
|
||||||
integrity sha512-boVtyJzS8g30iQfe8Q46W5QE/cmhKRln/7NMz/5sBP/am2Lce9NL0d05NnFwEWJp1e2AMGHFOdRr3Xg1cDiPKw==
|
integrity sha512-boVtyJzS8g30iQfe8Q46W5QE/cmhKRln/7NMz/5sBP/am2Lce9NL0d05NnFwEWJp1e2AMGHFOdRr3Xg1cDiPKw==
|
||||||
|
|
||||||
"@swc/core-linux-arm64-gnu@1.11.13":
|
"@swc/core-linux-arm64-gnu@1.11.13":
|
||||||
version "1.11.13"
|
version "1.11.13"
|
||||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.13.tgz#4145f1e504bdfa92604aee883d777bc8c4fba5d7"
|
resolved "https://mirrors.tencent.com/npm/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.13.tgz#4145f1e504bdfa92604aee883d777bc8c4fba5d7"
|
||||||
integrity sha512-+IK0jZ84zHUaKtwpV+T+wT0qIUBnK9v2xXD03vARubKF+eUqCsIvcVHXmLpFuap62dClMrhCiwW10X3RbXNlHw==
|
integrity sha512-+IK0jZ84zHUaKtwpV+T+wT0qIUBnK9v2xXD03vARubKF+eUqCsIvcVHXmLpFuap62dClMrhCiwW10X3RbXNlHw==
|
||||||
|
|
||||||
"@swc/core-linux-arm64-musl@1.11.13":
|
"@swc/core-linux-arm64-musl@1.11.13":
|
||||||
version "1.11.13"
|
version "1.11.13"
|
||||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.13.tgz#b1813ae2e99e386ca16fff5af6601ac45ef57c5b"
|
resolved "https://mirrors.tencent.com/npm/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.13.tgz#b1813ae2e99e386ca16fff5af6601ac45ef57c5b"
|
||||||
integrity sha512-+ukuB8RHD5BHPCUjQwuLP98z+VRfu+NkKQVBcLJGgp0/+w7y0IkaxLY/aKmrAS5ofCNEGqKL+AOVyRpX1aw+XA==
|
integrity sha512-+ukuB8RHD5BHPCUjQwuLP98z+VRfu+NkKQVBcLJGgp0/+w7y0IkaxLY/aKmrAS5ofCNEGqKL+AOVyRpX1aw+XA==
|
||||||
|
|
||||||
"@swc/core-linux-x64-gnu@1.11.13":
|
"@swc/core-linux-x64-gnu@1.11.13":
|
||||||
version "1.11.13"
|
version "1.11.13"
|
||||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.13.tgz#13b89a0194c4033c01400e9c65d9c21c56a4a6cd"
|
resolved "https://mirrors.tencent.com/npm/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.13.tgz#13b89a0194c4033c01400e9c65d9c21c56a4a6cd"
|
||||||
integrity sha512-q9H3WI3U3dfJ34tdv60zc8oTuWvSd5fOxytyAO9Pc5M82Hic3jjWaf2xBekUg07ubnMZpyfnv+MlD+EbUI3Llw==
|
integrity sha512-q9H3WI3U3dfJ34tdv60zc8oTuWvSd5fOxytyAO9Pc5M82Hic3jjWaf2xBekUg07ubnMZpyfnv+MlD+EbUI3Llw==
|
||||||
|
|
||||||
"@swc/core-linux-x64-musl@1.11.13":
|
"@swc/core-linux-x64-musl@1.11.13":
|
||||||
version "1.11.13"
|
version "1.11.13"
|
||||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.13.tgz#0d0e5aa889dd4da69723e2287c3c1714d9bfd8aa"
|
resolved "https://mirrors.tencent.com/npm/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.13.tgz#0d0e5aa889dd4da69723e2287c3c1714d9bfd8aa"
|
||||||
integrity sha512-9aaZnnq2pLdTbAzTSzy/q8dr7Woy3aYIcQISmw1+Q2/xHJg5y80ZzbWSWKYca/hKonDMjIbGR6dp299I5J0aeA==
|
integrity sha512-9aaZnnq2pLdTbAzTSzy/q8dr7Woy3aYIcQISmw1+Q2/xHJg5y80ZzbWSWKYca/hKonDMjIbGR6dp299I5J0aeA==
|
||||||
|
|
||||||
"@swc/core-win32-arm64-msvc@1.11.13":
|
"@swc/core-win32-arm64-msvc@1.11.13":
|
||||||
version "1.11.13"
|
version "1.11.13"
|
||||||
resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.13.tgz#ad7281f9467e3de09f52615afe2276a8ef738a9d"
|
resolved "https://mirrors.tencent.com/npm/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.13.tgz#ad7281f9467e3de09f52615afe2276a8ef738a9d"
|
||||||
integrity sha512-n3QZmDewkHANcoHvtwvA6yJbmS4XJf0MBMmwLZoKDZ2dOnC9D/jHiXw7JOohEuzYcpLoL5tgbqmjxa3XNo9Oow==
|
integrity sha512-n3QZmDewkHANcoHvtwvA6yJbmS4XJf0MBMmwLZoKDZ2dOnC9D/jHiXw7JOohEuzYcpLoL5tgbqmjxa3XNo9Oow==
|
||||||
|
|
||||||
"@swc/core-win32-ia32-msvc@1.11.13":
|
"@swc/core-win32-ia32-msvc@1.11.13":
|
||||||
version "1.11.13"
|
version "1.11.13"
|
||||||
resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.13.tgz#046f6dbddb5b69a29bbaa98de104090a46088b74"
|
resolved "https://mirrors.tencent.com/npm/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.13.tgz#046f6dbddb5b69a29bbaa98de104090a46088b74"
|
||||||
integrity sha512-wM+Nt4lc6YSJFthCx3W2dz0EwFNf++j0/2TQ0Js9QLJuIxUQAgukhNDVCDdq8TNcT0zuA399ALYbvj5lfIqG6g==
|
integrity sha512-wM+Nt4lc6YSJFthCx3W2dz0EwFNf++j0/2TQ0Js9QLJuIxUQAgukhNDVCDdq8TNcT0zuA399ALYbvj5lfIqG6g==
|
||||||
|
|
||||||
"@swc/core-win32-x64-msvc@1.11.13":
|
"@swc/core-win32-x64-msvc@1.11.13":
|
||||||
version "1.11.13"
|
version "1.11.13"
|
||||||
resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.13.tgz#0412620d8594a7d3e482d3e79d9e89d80f9a14c0"
|
resolved "https://mirrors.tencent.com/npm/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.13.tgz#0412620d8594a7d3e482d3e79d9e89d80f9a14c0"
|
||||||
integrity sha512-+X5/uW3s1L5gK7wAo0E27YaAoidJDo51dnfKSfU7gF3mlEUuWH8H1bAy5OTt2mU4eXtfsdUMEVXSwhDlLtQkuA==
|
integrity sha512-+X5/uW3s1L5gK7wAo0E27YaAoidJDo51dnfKSfU7gF3mlEUuWH8H1bAy5OTt2mU4eXtfsdUMEVXSwhDlLtQkuA==
|
||||||
|
|
||||||
"@swc/core@^1.10.7":
|
"@swc/core@^1.10.7":
|
||||||
@@ -1456,6 +1456,15 @@
|
|||||||
"@types/range-parser" "*"
|
"@types/range-parser" "*"
|
||||||
"@types/send" "*"
|
"@types/send" "*"
|
||||||
|
|
||||||
|
"@types/express@*", "@types/express@^5.0.0":
|
||||||
|
version "5.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/@types/express/-/express-5.0.1.tgz"
|
||||||
|
integrity sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/body-parser" "*"
|
||||||
|
"@types/express-serve-static-core" "^5.0.0"
|
||||||
|
"@types/serve-static" "*"
|
||||||
|
|
||||||
"@types/express@^4.17.20":
|
"@types/express@^4.17.20":
|
||||||
version "4.17.23"
|
version "4.17.23"
|
||||||
resolved "https://mirrors.tencent.com/npm/@types/express/-/express-4.17.23.tgz"
|
resolved "https://mirrors.tencent.com/npm/@types/express/-/express-4.17.23.tgz"
|
||||||
@@ -1466,15 +1475,6 @@
|
|||||||
"@types/qs" "*"
|
"@types/qs" "*"
|
||||||
"@types/serve-static" "*"
|
"@types/serve-static" "*"
|
||||||
|
|
||||||
"@types/express@^5.0.0":
|
|
||||||
version "5.0.1"
|
|
||||||
resolved "https://registry.npmjs.org/@types/express/-/express-5.0.1.tgz"
|
|
||||||
integrity sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ==
|
|
||||||
dependencies:
|
|
||||||
"@types/body-parser" "*"
|
|
||||||
"@types/express-serve-static-core" "^5.0.0"
|
|
||||||
"@types/serve-static" "*"
|
|
||||||
|
|
||||||
"@types/graceful-fs@^4.1.3":
|
"@types/graceful-fs@^4.1.3":
|
||||||
version "4.1.9"
|
version "4.1.9"
|
||||||
resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz"
|
resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz"
|
||||||
@@ -1559,6 +1559,13 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz"
|
resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz"
|
||||||
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
|
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
|
||||||
|
|
||||||
|
"@types/multer@^2.0.0":
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://mirrors.tencent.com/npm/@types/multer/-/multer-2.0.0.tgz"
|
||||||
|
integrity sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==
|
||||||
|
dependencies:
|
||||||
|
"@types/express" "*"
|
||||||
|
|
||||||
"@types/node-fetch@^2.6.4":
|
"@types/node-fetch@^2.6.4":
|
||||||
version "2.6.12"
|
version "2.6.12"
|
||||||
resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz"
|
resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz"
|
||||||
|
|||||||
Reference in New Issue
Block a user