Assist_Design/apps/bff/src/subscriptions/subscriptions.controller.ts

172 lines
5.3 KiB
TypeScript
Raw Normal View History

import {
Controller,
Get,
Param,
Query,
UseGuards,
Request,
ParseIntPipe,
BadRequestException,
} from '@nestjs/common';
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiQuery,
ApiBearerAuth,
ApiParam,
} from '@nestjs/swagger';
import { SubscriptionsService } from './subscriptions.service';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { Subscription, SubscriptionList, InvoiceList } from '@customer-portal/shared';
@ApiTags('subscriptions')
@Controller('subscriptions')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class SubscriptionsController {
constructor(private readonly subscriptionsService: SubscriptionsService) {}
@Get()
@ApiOperation({
summary: 'Get all user subscriptions',
description: 'Retrieves all subscriptions/services for the authenticated user'
})
@ApiQuery({ name: 'status', required: false, type: String, description: 'Filter by subscription status' })
@ApiResponse({
status: 200,
description: 'List of user subscriptions',
type: Object, // Would be SubscriptionList if we had proper DTO decorators
})
async getSubscriptions(
@Request() req: any,
@Query('status') status?: string,
): Promise<SubscriptionList | Subscription[]> {
// Validate status if provided
if (status && !['Active', 'Suspended', 'Terminated', 'Cancelled', 'Pending'].includes(status)) {
throw new BadRequestException('Invalid status filter');
}
if (status) {
const subscriptions = await this.subscriptionsService.getSubscriptionsByStatus(req.user.id, status);
return subscriptions;
}
return this.subscriptionsService.getSubscriptions(req.user.id);
}
@Get('active')
@ApiOperation({
summary: 'Get active subscriptions only',
description: 'Retrieves only active subscriptions for the authenticated user'
})
@ApiResponse({
status: 200,
description: 'List of active subscriptions',
type: [Object], // Would be Subscription[] if we had proper DTO decorators
})
async getActiveSubscriptions(
@Request() req: any,
): Promise<Subscription[]> {
return this.subscriptionsService.getActiveSubscriptions(req.user.id);
}
@Get('stats')
@ApiOperation({
summary: 'Get subscription statistics',
description: 'Retrieves subscription count statistics by status'
})
@ApiResponse({
status: 200,
description: 'Subscription statistics',
type: Object,
})
async getSubscriptionStats(
@Request() req: any,
): Promise<{
total: number;
active: number;
suspended: number;
cancelled: number;
pending: number;
}> {
return this.subscriptionsService.getSubscriptionStats(req.user.id);
}
@Get(':id')
@ApiOperation({
summary: 'Get subscription details by ID',
description: 'Retrieves detailed information for a specific subscription'
})
@ApiParam({ name: 'id', type: Number, description: 'Subscription ID' })
@ApiResponse({
status: 200,
description: 'Subscription details',
type: Object, // Would be Subscription if we had proper DTO decorators
})
@ApiResponse({ status: 404, description: 'Subscription not found' })
async getSubscriptionById(
@Request() req: any,
@Param('id', ParseIntPipe) subscriptionId: number,
): Promise<Subscription> {
if (subscriptionId <= 0) {
throw new BadRequestException('Subscription ID must be a positive number');
}
return this.subscriptionsService.getSubscriptionById(req.user.id, subscriptionId);
}
@Get(':id/invoices')
@ApiOperation({
summary: 'Get invoices for a specific subscription',
description: 'Retrieves all invoices related to a specific subscription'
})
@ApiParam({ name: 'id', type: Number, description: 'Subscription ID' })
@ApiQuery({ name: 'page', required: false, type: Number, description: 'Page number (default: 1)' })
@ApiQuery({ name: 'limit', required: false, type: Number, description: 'Items per page (default: 10)' })
@ApiResponse({
status: 200,
description: 'List of invoices for the subscription',
type: Object, // Would be InvoiceList if we had proper DTO decorators
})
@ApiResponse({ status: 404, description: 'Subscription not found' })
async getSubscriptionInvoices(
@Request() req: any,
@Param('id', ParseIntPipe) subscriptionId: number,
@Query('page') page?: string,
@Query('limit') limit?: string,
): Promise<InvoiceList> {
if (subscriptionId <= 0) {
throw new BadRequestException('Subscription ID must be a positive number');
}
// Validate and sanitize input
const pageNum = this.validatePositiveInteger(page, 1, 'page');
const limitNum = this.validatePositiveInteger(limit, 10, 'limit');
// Limit max page size for performance
if (limitNum > 100) {
throw new BadRequestException('Limit cannot exceed 100 items per page');
}
return this.subscriptionsService.getSubscriptionInvoices(
req.user.id,
subscriptionId,
{ page: pageNum, limit: limitNum }
);
}
private validatePositiveInteger(value: string | undefined, defaultValue: number, fieldName: string): number {
if (!value) {
return defaultValue;
}
const parsed = parseInt(value, 10);
if (isNaN(parsed) || parsed <= 0) {
throw new BadRequestException(`${fieldName} must be a positive integer`);
}
return parsed;
}
}