feat(billing): cap each owner's stored file volume
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import type {
|
||||
} from '@mento/shared';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { LocalFileStorage } from '../storage/local-file.storage';
|
||||
import { StorageQuotaService } from '../billing/storage-quota.service';
|
||||
import type { Actor } from '../common/record-scope';
|
||||
import { TreasuryReceivablesService } from './treasury-receivables.service';
|
||||
|
||||
@@ -61,6 +62,7 @@ export class TreasuryService {
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly receivables: TreasuryReceivablesService,
|
||||
private readonly files: LocalFileStorage,
|
||||
private readonly storage: StorageQuotaService,
|
||||
) {}
|
||||
|
||||
async ensureCategories(organizationId: string) {
|
||||
@@ -613,18 +615,27 @@ export class TreasuryService {
|
||||
if (!doc) throw new NotFoundException('سند پیدا نشد.');
|
||||
const safeName = file.originalname.replace(/[^\w.\-\u0600-\u06FF]+/g, '_').slice(0, 80);
|
||||
const storageKey = `treasury/${actor.organizationId}/${doc.id}/${randomUUID()}-${safeName || 'file'}`;
|
||||
const bytes = file.buffer.length;
|
||||
await this.storage.assertCanAdd(actor.organizationId, bytes);
|
||||
await this.files.save(storageKey, file.buffer);
|
||||
return this.prisma.financialAttachment.create({
|
||||
data: {
|
||||
organizationId: actor.organizationId,
|
||||
documentId: doc.id,
|
||||
fileName: file.originalname,
|
||||
mimeType: file.mimetype || 'application/octet-stream',
|
||||
storageKey,
|
||||
createdById: actor.userId,
|
||||
},
|
||||
select: { id: true, fileName: true, createdAt: true },
|
||||
});
|
||||
try {
|
||||
const row = await this.prisma.financialAttachment.create({
|
||||
data: {
|
||||
organizationId: actor.organizationId,
|
||||
documentId: doc.id,
|
||||
fileName: file.originalname,
|
||||
mimeType: file.mimetype || 'application/octet-stream',
|
||||
storageKey,
|
||||
createdById: actor.userId,
|
||||
},
|
||||
select: { id: true, fileName: true, createdAt: true },
|
||||
});
|
||||
await this.storage.addLocal(actor.organizationId, bytes);
|
||||
return row;
|
||||
} catch (err) {
|
||||
await this.files.remove(storageKey);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async dashboard(
|
||||
|
||||
Reference in New Issue
Block a user