feat(billing): cap each owner's stored file volume

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-11-02 15:44:36 +03:30
co-authored by Cursor
parent e6e90aabf3
commit 28938e8f77
20 changed files with 647 additions and 22 deletions
@@ -4,6 +4,7 @@ import { CurrentUser } from '../auth/current-user.decorator';
import { RequireOrgModule } from '../billing/org-module.decorator';
import { OrgModuleGuard } from '../billing/org-module.guard';
import {
ConversationFileBytesDto,
CreateConversationDmDto,
CreateConversationGroupDto,
CreateConversationChannelDto,
@@ -19,12 +20,34 @@ import {
ToggleMessageReactionDto,
} from './dto';
import { ConversationsService } from './conversations.service';
import { StorageQuotaService } from '../billing/storage-quota.service';
@Controller('conversations')
@UseGuards(JwtAuthGuard, OrgModuleGuard)
@RequireOrgModule('conversations')
export class ConversationsController {
constructor(private readonly conversations: ConversationsService) {}
constructor(
private readonly conversations: ConversationsService,
private readonly storage: StorageQuotaService,
) {}
@Post('files/reserve')
reserveFile(
@CurrentUser() user: { organizationId: string },
@Body() dto: ConversationFileBytesDto,
) {
return this.storage.assertCanAdd(user.organizationId, dto.bytes).then(() =>
this.storage.usageForOrganization(user.organizationId),
);
}
@Post('files/commit')
commitFile(
@CurrentUser() user: { organizationId: string },
@Body() dto: ConversationFileBytesDto,
) {
return this.storage.addChat(user.organizationId, dto.bytes);
}
@Get('access')
access(@CurrentUser() user: { userId: string; organizationId: string; role: string }) {
+12
View File
@@ -1,9 +1,13 @@
import { Type } from 'class-transformer';
import {
IsArray,
IsBoolean,
IsInt,
IsOptional,
IsString,
Max,
MaxLength,
Min,
MinLength,
ArrayMinSize,
ArrayMaxSize,
@@ -32,6 +36,14 @@ export class UpdateConversationSettingsDto {
downloadUrl?: string;
}
export class ConversationFileBytesDto {
@Type(() => Number)
@IsInt()
@Min(1)
@Max(100 * 1024 * 1024)
bytes!: number;
}
export class CreateConversationDmDto {
@IsString()
@MinLength(1)