138 lines
3.4 KiB
TypeScript
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 {}
|
|
}
|
|
}
|