web-service/apps/assets/src/services/assets.service.ts

138 lines
3.4 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { S3Service } from './s3.service';
import { AssetUploadRequest } from '../interfaces/upload-request.interface';
import {
NotFoundRpcException,
UnauthorizedRpcException,
UserInfo,
} from '@freeblox/shared';
import { InjectEntityManager } from '@nestjs/typeorm';
import { EntityManager } from 'typeorm';
import { AssetEntity } from '../database/entities/asset.entity';
import { ConfigService } from '@nestjs/config';
import { instanceToPlain } from 'class-transformer';
@Injectable()
export class AssetsService {
constructor(
@InjectEntityManager() private manager: EntityManager,
private readonly s3Service: S3Service,
private readonly config: ConfigService,
) {}
/**
* Upload a new asset.
* @param body Upload info
* @param user User
* @returns Uploaded asset
*/
async uploadFile(body: AssetUploadRequest, user?: UserInfo) {
const file = Buffer.from(body.buffer as any, 'base64');
const uploaded = this.manager.transaction(async (manager) => {
const asset = manager.create(AssetEntity, {
id: body.id,
userId: body.userId || user?.sub,
assetTag: body.assetTag,
sourceUri: 'fblxassetid://stub',
uploadIp: body.uploadIp,
public: body.public,
originalname: body.originalname,
mimetype: body.mimetype,
filesize: body.filesize,
});
// Create ID if not provided
await manager.save(AssetEntity, asset);
// Upload to S3
const key = `fblxassetid-${asset.id}`;
const bucket = this.config.get('s3.bucket');
await this.s3Service.uploadFile(key, file, bucket);
// Save S3 keys
asset.source = bucket;
asset.sourceUri = key;
return manager.save(AssetEntity, asset);
});
return instanceToPlain(uploaded);
}
/**
* Get asset info by ID.
* @param id Asset ID
* @param user (optional) User
* @returns Asset info
*/
async getAssetInfoById(id: string, user?: UserInfo) {
const asset = await this.manager.findOne(AssetEntity, {
where: {
deletedAt: null,
id: id,
},
});
if (!asset) {
throw new NotFoundRpcException('Asset not found');
}
if (!user && !asset.public) {
throw new UnauthorizedRpcException('Unauthorized');
}
return instanceToPlain(asset);
}
/**
* Download asset by ID.
* @param id Asset ID
* @param user (optional) User
* @returns Buffer
*/
async downloadAssetById(id: string, user?: UserInfo) {
const asset = await this.manager.findOne(AssetEntity, {
where: {
deletedAt: null,
id: id,
},
});
if (!asset) {
throw new NotFoundRpcException('Asset not found');
}
if (!user && !asset.public) {
throw new UnauthorizedRpcException('Unauthorized');
}
const url = await this.s3Service.getFileUrl(asset.sourceUri, asset.source);
return {
url,
mimetype: asset.mimetype,
filename: `${asset.id}.${asset.extension}`,
};
}
/**
* Delete asset.
* @param id Asset ID
*/
async deleteAsset(id: string) {
const asset = await this.manager.findOne(AssetEntity, {
where: {
deletedAt: null,
id: id,
},
});
if (!asset) {
throw new NotFoundRpcException('Asset not found');
}
await this.manager.softRemove(AssetEntity, asset);
try {
await this.s3Service.deleteFile(asset.sourceUri, asset.source);
} catch {}
}
}