Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/email-marketing/controllers/analytics.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
Controller,
Get,
Param,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../../auth/guards/roles.guard';
import { Roles } from '../../auth/decorators/roles.decorator';
import { AnalyticsService } from '../services/analytics.service';

@ApiTags('Email Analytics')
@Controller('email-marketing/analytics')
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiBearerAuth()
export class AnalyticsController {
constructor(private readonly analyticsService: AnalyticsService) {}

@Get('dashboard')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Get email marketing dashboard metrics' })
@ApiResponse({ status: 200, description: 'Dashboard metrics retrieved successfully' })
async getDashboardMetrics(
@Query('startDate') startDate?: string,
@Query('endDate') endDate?: string,
) {
const dateRange = {
startDate: startDate ? new Date(startDate) : new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
endDate: endDate ? new Date(endDate) : new Date(),
};
return this.analyticsService.getDashboardMetrics(dateRange);
}

@Get('campaigns/:id')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Get detailed campaign analytics' })
@ApiResponse({ status: 200, description: 'Campaign analytics retrieved successfully' })
async getCampaignAnalytics(@Param('id') campaignId: string) {
return this.analyticsService.getCampaignAnalytics(campaignId);
}

@Get('automation/:id')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Get automation workflow analytics' })
@ApiResponse({ status: 200, description: 'Automation analytics retrieved successfully' })
async getAutomationAnalytics(@Param('id') workflowId: string) {
return this.analyticsService.getAutomationAnalytics(workflowId);
}

@Get('segments/:id')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Get segment analytics' })
@ApiResponse({ status: 200, description: 'Segment analytics retrieved successfully' })
async getSegmentAnalytics(@Param('id') segmentId: string) {
return this.analyticsService.getSegmentAnalytics(segmentId);
}
}
141 changes: 141 additions & 0 deletions src/email-marketing/controllers/automation.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
UseGuards,
HttpCode,
HttpStatus,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../../auth/guards/roles.guard';
import { Roles } from '../../auth/decorators/roles.decorator';
import { AutomationService } from '../services/automation.service';
import { WorkflowType, WorkflowStatus } from '../entities/automation-workflow.entity';
import { TriggerType } from '../entities/automation-trigger.entity';
import { ActionType } from '../entities/automation-action.entity';

@ApiTags('Email Automation')
@Controller('email-marketing/automation')
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiBearerAuth()
export class AutomationController {
constructor(private readonly automationService: AutomationService) {}

@Post('workflows')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Create a new automation workflow' })
@ApiResponse({ status: 201, description: 'Workflow created successfully' })
async createWorkflow(@Body() workflowData: {
name: string;
description?: string;
workflowType: WorkflowType;
goalType?: string;
goalValue?: number;
settings?: Record<string, any>;
createdBy?: string;
}) {
return this.automationService.createWorkflow(workflowData);
}

@Post('workflows/:id/triggers')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Add trigger to workflow' })
@ApiResponse({ status: 201, description: 'Trigger added successfully' })
async addTrigger(
@Param('id') workflowId: string,
@Body() triggerData: {
triggerType: TriggerType;
eventName: string;
conditions?: Record<string, any>;
filters?: Record<string, any>;
delay?: number;
delayUnit?: string;
},
) {
return this.automationService.addTrigger(workflowId, triggerData);
}

@Post('workflows/:id/actions')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Add action to workflow' })
@ApiResponse({ status: 201, description: 'Action added successfully' })
async addAction(
@Param('id') workflowId: string,
@Body() actionData: {
actionType: ActionType;
sortOrder: number;
configuration: Record<string, any>;
conditions?: Record<string, any>;
delay?: number;
delayUnit?: string;
},
) {
return this.automationService.addAction(workflowId, actionData);
}

@Post('workflows/:id/activate')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Activate workflow' })
@ApiResponse({ status: 200, description: 'Workflow activated successfully' })
async activateWorkflow(@Param('id') workflowId: string) {
return this.automationService.activateWorkflow(workflowId);
}

@Post('workflows/:id/pause')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Pause workflow' })
@ApiResponse({ status: 200, description: 'Workflow paused successfully' })
async pauseWorkflow(@Param('id') workflowId: string) {
return this.automationService.pauseWorkflow(workflowId);
}

@Post('workflows/:id/resume')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Resume workflow' })
@ApiResponse({ status: 200, description: 'Workflow resumed successfully' })
async resumeWorkflow(@Param('id') workflowId: string) {
return this.automationService.resumeWorkflow(workflowId);
}

@Get('workflows/:id')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Get workflow by ID' })
@ApiResponse({ status: 200, description: 'Workflow retrieved successfully' })
async getWorkflow(@Param('id') workflowId: string) {
return this.automationService.findWorkflow(workflowId);
}

@Get('workflows/:id/stats')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Get workflow statistics' })
@ApiResponse({ status: 200, description: 'Workflow statistics retrieved successfully' })
async getWorkflowStats(@Param('id') workflowId: string) {
return this.automationService.getWorkflowStats(workflowId);
}

@Post('events')
@Roles('admin', 'organizer', 'system')
@HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({ summary: 'Process automation event' })
@ApiResponse({ status: 204, description: 'Event processed successfully' })
async processEvent(@Body() eventData: {
eventName: string;
data: Record<string, any>;
}) {
await this.automationService.processEvent(eventData.eventName, eventData.data);
}

@Delete('workflows/:id')
@Roles('admin')
@HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({ summary: 'Delete workflow' })
@ApiResponse({ status: 204, description: 'Workflow deleted successfully' })
async deleteWorkflow(@Param('id') workflowId: string) {
await this.automationService.deleteWorkflow(workflowId);
}
}
137 changes: 137 additions & 0 deletions src/email-marketing/controllers/campaign.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
Query,
UseGuards,
HttpCode,
HttpStatus,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../../auth/guards/roles.guard';
import { Roles } from '../../auth/decorators/roles.decorator';
import { CampaignService } from '../services/campaign.service';
import { CreateCampaignDto } from '../dto/create-campaign.dto';
import { CampaignStatus, CampaignType } from '../entities/email-campaign.entity';

@ApiTags('Email Campaigns')
@Controller('email-marketing/campaigns')
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiBearerAuth()
export class CampaignController {
constructor(private readonly campaignService: CampaignService) {}

@Post()
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Create a new email campaign' })
@ApiResponse({ status: 201, description: 'Campaign created successfully' })
async create(@Body() createCampaignDto: CreateCampaignDto) {
return this.campaignService.create(createCampaignDto);
}

@Get()
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Get all campaigns with filtering and pagination' })
@ApiResponse({ status: 200, description: 'Campaigns retrieved successfully' })
async findAll(
@Query('page') page?: number,
@Query('limit') limit?: number,
@Query('status') status?: CampaignStatus,
@Query('type') campaignType?: CampaignType,
@Query('createdBy') createdBy?: string,
@Query('search') search?: string,
@Query('tags') tags?: string,
) {
const options = {
page,
limit,
status,
campaignType,
createdBy,
search,
tags: tags ? tags.split(',') : undefined,
};
return this.campaignService.findAll(options);
}

@Get(':id')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Get campaign by ID' })
@ApiResponse({ status: 200, description: 'Campaign retrieved successfully' })
async findOne(@Param('id') id: string) {
return this.campaignService.findOne(id);
}

@Patch(':id/status')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Update campaign status' })
@ApiResponse({ status: 200, description: 'Campaign status updated successfully' })
async updateStatus(@Param('id') id: string, @Body('status') status: CampaignStatus) {
return this.campaignService.updateStatus(id, status);
}

@Post(':id/schedule')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Schedule campaign for future sending' })
@ApiResponse({ status: 200, description: 'Campaign scheduled successfully' })
async scheduleCampaign(
@Param('id') id: string,
@Body('scheduledAt') scheduledAt: string,
) {
return this.campaignService.scheduleCampaign(id, new Date(scheduledAt));
}

@Post(':id/send')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Send campaign immediately' })
@ApiResponse({ status: 200, description: 'Campaign sent successfully' })
async sendCampaign(@Param('id') id: string) {
return this.campaignService.sendCampaign(id);
}

@Post(':id/pause')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Pause sending campaign' })
@ApiResponse({ status: 200, description: 'Campaign paused successfully' })
async pauseCampaign(@Param('id') id: string) {
return this.campaignService.pauseCampaign(id);
}

@Post(':id/resume')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Resume paused campaign' })
@ApiResponse({ status: 200, description: 'Campaign resumed successfully' })
async resumeCampaign(@Param('id') id: string) {
return this.campaignService.resumeCampaign(id);
}

@Get(':id/stats')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Get campaign statistics' })
@ApiResponse({ status: 200, description: 'Campaign statistics retrieved successfully' })
async getCampaignStats(@Param('id') id: string) {
return this.campaignService.getCampaignStats(id);
}

@Post(':id/duplicate')
@Roles('admin', 'organizer')
@ApiOperation({ summary: 'Duplicate campaign' })
@ApiResponse({ status: 201, description: 'Campaign duplicated successfully' })
async duplicateCampaign(@Param('id') id: string, @Body('name') name: string) {
return this.campaignService.duplicateCampaign(id, name);
}

@Delete(':id')
@Roles('admin')
@HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({ summary: 'Archive campaign' })
@ApiResponse({ status: 204, description: 'Campaign archived successfully' })
async remove(@Param('id') id: string) {
await this.campaignService.remove(id);
}
}
Loading