Tech4biz-channel/Channel-Backend/src/controllers/asset.controller.ts
2026-07-30 11:34:37 +05:30

310 lines
12 KiB
TypeScript

import { Response, NextFunction } from 'express';
import path from 'path';
import { PutObjectCommand } from '@aws-sdk/client-s3';
import { s3Client, BUCKET_NAME } from '../utils/s3';
import { AssetService } from '../services/asset.service';
import { ScraperService } from '../services/scraper.service';
import { AuthRequest } from '../middleware/auth.middleware';
export class AssetController {
private assetService = new AssetService();
private scraperService = new ScraperService();
public scrapeCaseStudy = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const url = req.query.url as string;
if (!url) {
return res.status(400).json({ error: 'URL parameter is required' });
}
const data = await this.scraperService.scrapeCaseStudy(url);
res.status(200).json(data);
} catch (err) { next(err); }
}
public uploadAsset = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const files = req.files as { [fieldname: string]: Express.Multer.File[] } | undefined;
const assetFile = files?.file?.[0] || req.file;
const thumbnailFile = files?.thumbnail?.[0];
const isUrlAsset = req.body.isUrlAsset === 'true' || req.body.isUrlAsset === true || req.body.type === 'url' || req.body.type === 'case_study';
if (!isUrlAsset && !assetFile) {
throw new Error('No file uploaded');
}
const uploaderId = req.user?.userId || 'system';
const description = req.body.description;
if (!description || !description.trim()) {
return res.status(400).json({ error: 'Description is required' });
}
// Parse shares if present
let shares = req.body.shares;
if (typeof shares === 'string' && shares.trim()) {
try { shares = JSON.parse(shares); } catch { shares = undefined; }
}
let fileUrl = '';
if (!isUrlAsset && assetFile) {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
const filename = uniqueSuffix + path.extname(assetFile.originalname);
await s3Client.send(new PutObjectCommand({
Bucket: BUCKET_NAME,
Key: filename,
Body: assetFile.buffer,
ContentType: assetFile.mimetype,
}));
fileUrl = `/uploads/${filename}`;
} else {
fileUrl = req.body.url;
}
// Handle thumbnail file upload if present
let thumbnailUrl: string | null = req.body.thumbnailUrl || null;
if (thumbnailFile) {
if (!thumbnailFile.mimetype.startsWith('image/')) {
return res.status(400).json({ error: 'Thumbnail must be an image file' });
}
const thumbSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
const thumbFilename = 'thumb-' + thumbSuffix + path.extname(thumbnailFile.originalname);
await s3Client.send(new PutObjectCommand({
Bucket: BUCKET_NAME,
Key: thumbFilename,
Body: thumbnailFile.buffer,
ContentType: thumbnailFile.mimetype,
}));
thumbnailUrl = `/uploads/${thumbFilename}`;
}
const parseJsonOrArray = (val: any) => {
if (!val) return undefined;
if (typeof val === 'string' && val.trim()) {
try { return JSON.parse(val); } catch { return val.split(',').map((id: string) => id.trim()).filter(Boolean); }
}
return val;
};
let verticalIds = parseJsonOrArray(req.body.verticalIds);
let techStackIds = parseJsonOrArray(req.body.techStackIds);
let engagementTypeIds = parseJsonOrArray(req.body.engagementTypeIds);
let complianceIds = parseJsonOrArray(req.body.complianceIds);
const assetData = {
title: req.body.title || (assetFile ? assetFile.originalname : 'URL Asset'),
type: req.body.type || (isUrlAsset ? 'url' : assetFile!.mimetype),
size: isUrlAsset ? 0 : assetFile!.size,
url: fileUrl,
uploadedBy: uploaderId,
description: req.body.description || null,
categoryId: req.body.categoryId || null,
subcategory: req.body.subcategory || null,
tags: req.body.tags || [],
githubUrl: req.body.githubUrl || null,
status: req.body.status || 'published',
isDownloadable: req.body.isDownloadable === 'true' || req.body.isDownloadable === true,
thumbnailUrl: thumbnailUrl,
problemStatement: req.body.problemStatement || null,
solution: req.body.solution || null,
verticalIds,
techStackIds,
engagementTypeIds,
complianceIds,
shares,
sharedOrgIds: req.body.sharedOrgIds || null,
};
const asset = await this.assetService.createAsset(assetData);
res.status(201).json(asset);
} catch (err) { next(err); }
}
public uploadThumbnail = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const files = req.files as { [fieldname: string]: Express.Multer.File[] } | undefined;
const file = req.file || files?.thumbnail?.[0];
if (!file) {
return res.status(400).json({ error: 'No thumbnail file uploaded' });
}
if (!file.mimetype.startsWith('image/')) {
return res.status(400).json({ error: 'Thumbnail must be an image file' });
}
const thumbSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
const thumbFilename = 'thumb-' + thumbSuffix + path.extname(file.originalname);
await s3Client.send(new PutObjectCommand({
Bucket: BUCKET_NAME,
Key: thumbFilename,
Body: file.buffer,
ContentType: file.mimetype,
}));
const thumbnailUrl = `/uploads/${thumbFilename}`;
res.status(200).json({ thumbnailUrl });
} catch (err) { next(err); }
}
public listAssets = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const userContext = req.user ? { role: req.user.role, userId: req.user.userId } : undefined;
const filters = {
search: req.query.search as string,
verticalIds: req.query.verticalIds ? (req.query.verticalIds as string).split(',') : undefined,
techStackIds: req.query.techStackIds ? (req.query.techStackIds as string).split(',') : undefined,
engagementTypeIds: req.query.engagementTypeIds ? (req.query.engagementTypeIds as string).split(',') : undefined,
complianceIds: req.query.complianceIds ? (req.query.complianceIds as string).split(',') : undefined,
contentTypes: req.query.contentTypes ? (req.query.contentTypes as string).split(',') : undefined,
subcategories: req.query.subcategories ? (req.query.subcategories as string).split(',') : undefined,
tags: req.query.tags ? (req.query.tags as string).split(',') : undefined,
sortBy: req.query.sortBy as any,
};
const assets = await this.assetService.getAssets(userContext, filters);
res.status(200).json(assets);
} catch(err) { next(err); }
}
public getAsset = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const asset = await this.assetService.getAssetById(req.params.id);
if (!asset) {
return res.status(404).json({ error: 'Asset not found' });
}
res.status(200).json(asset);
} catch (err) { next(err); }
}
public updateAsset = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const asset = await this.assetService.updateAsset(req.params.id, req.body);
res.status(200).json(asset);
} catch (err) { next(err); }
}
public bulkShareAssets = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const { assetIds, shares } = req.body;
if (!Array.isArray(assetIds)) {
return res.status(400).json({ error: 'assetIds must be an array' });
}
if (!Array.isArray(shares)) {
return res.status(400).json({ error: 'shares must be an array' });
}
await this.assetService.bulkShareAssets(assetIds, shares);
res.status(200).json({ message: 'Assets shared successfully' });
} catch (err) { next(err); }
}
public shareAsset = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const { organizationIds } = req.body;
if (!Array.isArray(organizationIds)) {
return res.status(400).json({ error: 'organizationIds must be an array' });
}
const asset = await this.assetService.shareAsset(req.params.id, organizationIds);
res.status(200).json(asset);
} catch (err) { next(err); }
}
public unshareAsset = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const { organizationIds } = req.body;
if (!Array.isArray(organizationIds)) {
return res.status(400).json({ error: 'organizationIds must be an array' });
}
const asset = await this.assetService.unshareAsset(req.params.id, organizationIds);
res.status(200).json(asset);
} catch (err) { next(err); }
}
public incrementDownload = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const asset = await this.assetService.incrementDownloadCount(req.params.id);
res.status(200).json(asset);
} catch (err) { next(err); }
}
public deleteAsset = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
await this.assetService.deleteAsset(req.params.id);
res.status(204).send();
} catch(err) { next(err); }
}
public requestDownload = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const userId = req.user?.userId;
if (!userId) return res.status(401).json({ error: 'Unauthorized' });
const request = await this.assetService.requestDownload(req.params.id, userId);
res.status(200).json(request);
} catch (err) { next(err); }
}
public approveDownload = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const request = await this.assetService.approveDownloadRequest(req.params.requestId);
res.status(200).json(request);
} catch (err) { next(err); }
}
public rejectDownload = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const request = await this.assetService.rejectDownloadRequest(req.params.requestId);
res.status(200).json(request);
} catch (err) { next(err); }
}
public createAssetGroup = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const { name, description, assetIds } = req.body;
if (!name) {
return res.status(400).json({ error: 'Group name is required' });
}
const group = await this.assetService.createAssetGroup(name, description, assetIds || []);
res.status(201).json(group);
} catch (err) { next(err); }
}
public listAssetGroups = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const groups = await this.assetService.getAssetGroups();
res.status(200).json(groups);
} catch (err) { next(err); }
}
public deleteAssetGroup = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
await this.assetService.deleteAssetGroup(req.params.id);
res.status(204).send();
} catch (err) { next(err); }
}
public addAssetsToGroup = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const { assetIds } = req.body;
if (!Array.isArray(assetIds)) {
return res.status(400).json({ error: 'assetIds must be an array' });
}
const group = await this.assetService.addAssetsToGroup(req.params.id, assetIds);
res.status(200).json(group);
} catch (err) { next(err); }
}
public removeAssetsFromGroup = async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const { assetIds } = req.body;
if (!Array.isArray(assetIds)) {
return res.status(400).json({ error: 'assetIds must be an array' });
}
const group = await this.assetService.removeAssetsFromGroup(req.params.id, assetIds);
res.status(200).json(group);
} catch (err) { next(err); }
}
}