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
2 changes: 1 addition & 1 deletion declarations.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
declare module 'langchain/embeddings/openai';
declare module 'langchain/embeddings/hf';
declare module 'langchain/embeddings/hf';
209 changes: 142 additions & 67 deletions package-lock.json

Large diffs are not rendered by default.

29 changes: 25 additions & 4 deletions src/ab-testing/ab-testing.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,21 @@ import {
Logger,
HttpCode,
HttpStatus,
UseGuards,
Request,
} from '@nestjs/common';
import { ABTestingService } from './ab-testing.service';
import { ABTestingService, CreateExperimentDto } from './ab-testing.service';
import { ExperimentService } from './experiments/experiment.service';
import { StatisticalAnalysisService } from './analysis/statistical-analysis.service';
import { AutomatedDecisionService } from './automation/automated-decision.service';
import { ABTestingReportsService } from './reporting/ab-testing-reports.service';
import { CreateExperimentDto } from './ab-testing.service';
import { ExperimentStatus, ExperimentType } from './entities/experiment.entity';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles } from '../auth/decorators/roles.decorator';
import { UserRole } from '../users/entities/user.entity';

@Controller('ab-testing')
@UseGuards(JwtAuthGuard, RolesGuard)
export class ABTestingController {
private readonly logger = new Logger(ABTestingController.name);

Expand All @@ -32,6 +37,7 @@ export class ABTestingController {
) {}

@Get('experiments')
@Roles(UserRole.ADMIN, UserRole.TEACHER)
async getAllExperiments() {
this.logger.log('Fetching all experiments');
return await this.abTestingService.getAllExperiments();
Expand All @@ -45,34 +51,39 @@ export class ABTestingController {

@Post('experiments')
@HttpCode(HttpStatus.CREATED)
async createExperiment(@Body() createExperimentDto: CreateExperimentDto) {
@Roles(UserRole.ADMIN)
async createExperiment(@Request() req, @Body() createExperimentDto: CreateExperimentDto) {
this.logger.log(`Creating new experiment: ${createExperimentDto.name}`);
return await this.abTestingService.createExperiment(createExperimentDto);
}

@Post('experiments/:id/start')
@HttpCode(HttpStatus.OK)
@Roles(UserRole.ADMIN)
async startExperiment(@Param('id') id: string) {
this.logger.log(`Starting experiment: ${id}`);
return await this.abTestingService.startExperiment(id);
}

@Post('experiments/:id/stop')
@HttpCode(HttpStatus.OK)
@Roles(UserRole.ADMIN)
async stopExperiment(@Param('id') id: string) {
this.logger.log(`Stopping experiment: ${id}`);
return await this.abTestingService.stopExperiment(id);
}

@Put('experiments/:id')
@HttpCode(HttpStatus.OK)
@Roles(UserRole.ADMIN)
async updateExperiment(@Param('id') id: string, @Body() updateData: any) {
this.logger.log(`Updating experiment: ${id}`);
return await this.experimentService.updateExperiment(id, updateData);
}

@Delete('experiments/:id')
@HttpCode(HttpStatus.OK)
@Roles(UserRole.ADMIN)
async deleteExperiment(@Param('id') id: string) {
this.logger.log(`Deleting experiment: ${id}`);
// Implementation would go here
Expand All @@ -87,13 +98,15 @@ export class ABTestingController {

@Post('experiments/:id/variants')
@HttpCode(HttpStatus.CREATED)
@Roles(UserRole.ADMIN)
async addVariant(@Param('id') experimentId: string, @Body() variantData: any) {
this.logger.log(`Adding variant to experiment: ${experimentId}`);
return await this.experimentService.addVariant(experimentId, variantData);
}

@Delete('variants/:id')
@HttpCode(HttpStatus.OK)
@Roles(UserRole.ADMIN)
async removeVariant(@Param('id') variantId: string) {
this.logger.log(`Removing variant: ${variantId}`);
await this.experimentService.removeVariant(variantId);
Expand All @@ -102,6 +115,7 @@ export class ABTestingController {

@Put('experiments/:id/traffic-allocation')
@HttpCode(HttpStatus.OK)
@Roles(UserRole.ADMIN)
async updateTrafficAllocation(
@Param('id') experimentId: string,
@Body() allocations: Record<string, number>,
Expand All @@ -125,6 +139,7 @@ export class ABTestingController {

@Post('experiments/:id/auto-select-winner')
@HttpCode(HttpStatus.OK)
@Roles(UserRole.ADMIN)
async autoSelectWinner(@Param('id') id: string, @Body() criteria?: any) {
this.logger.log(`Auto-selecting winner for experiment: ${id}`);
return await this.automatedDecisionService.autoSelectWinner(id, criteria);
Expand All @@ -138,13 +153,15 @@ export class ABTestingController {

@Post('experiments/:id/auto-allocate-traffic')
@HttpCode(HttpStatus.OK)
@Roles(UserRole.ADMIN)
async autoAllocateTraffic(@Param('id') id: string) {
this.logger.log(`Auto-allocating traffic for experiment: ${id}`);
await this.automatedDecisionService.autoAllocateTraffic(id);
return { message: 'Traffic auto-allocated successfully' };
}

@Get('reports/dashboard')
@Roles(UserRole.ADMIN, UserRole.TEACHER)
async getDashboardSummary(@Query() filters?: any) {
this.logger.log('Generating dashboard summary');
return await this.reportsService.getDashboardSummary(filters);
Expand Down Expand Up @@ -180,26 +197,30 @@ export class ABTestingController {

@Post('experiments/:id/pause')
@HttpCode(HttpStatus.OK)
@Roles(UserRole.ADMIN)
async pauseExperiment(@Param('id') id: string) {
this.logger.log(`Pausing experiment: ${id}`);
return await this.experimentService.pauseExperiment(id);
}

@Post('experiments/:id/resume')
@HttpCode(HttpStatus.OK)
@Roles(UserRole.ADMIN)
async resumeExperiment(@Param('id') id: string) {
this.logger.log(`Resuming experiment: ${id}`);
return await this.experimentService.resumeExperiment(id);
}

@Post('experiments/:id/archive')
@HttpCode(HttpStatus.OK)
@Roles(UserRole.ADMIN)
async archiveExperiment(@Param('id') id: string) {
this.logger.log(`Archiving experiment: ${id}`);
return await this.experimentService.archiveExperiment(id);
}

@Get('experiments/:id/assign-user/:userId')
@Roles(UserRole.ADMIN)
async assignUserToVariant(@Param('id') experimentId: string, @Param('userId') userId: string) {
this.logger.log(`Assigning user ${userId} to variant for experiment: ${experimentId}`);
return await this.abTestingService.assignUserToVariant(experimentId, userId);
Expand Down
5 changes: 2 additions & 3 deletions src/ab-testing/ab-testing.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Experiment } from './entities/experiment.entity';
import { Experiment, ExperimentStatus, ExperimentType } from './entities/experiment.entity';
import { ExperimentVariant } from './entities/experiment-variant.entity';
import { ExperimentStatus, ExperimentType } from './entities/experiment.entity';

export interface CreateExperimentDto {
name: string;
Expand Down Expand Up @@ -163,7 +162,7 @@ export class ABTestingService {
/**
* Gets active experiments for a user
*/
async getActiveExperimentsForUser(userId: string): Promise<Experiment[]> {
async getActiveExperimentsForUser(_userId: string): Promise<Experiment[]> {
return await this.experimentRepository.find({
where: {
status: ExperimentStatus.RUNNING,
Expand Down
13 changes: 6 additions & 7 deletions src/ab-testing/automation/automated-decision.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Experiment } from '../entities/experiment.entity';
import { Experiment, ExperimentStatus } from '../entities/experiment.entity';
import { ExperimentVariant } from '../entities/experiment-variant.entity';
import { StatisticalAnalysisService } from '../analysis/statistical-analysis.service';
import { ExperimentStatus } from '../entities/experiment.entity';

export interface WinnerSelectionCriteria {
confidenceLevel: number;
Expand Down Expand Up @@ -162,9 +161,9 @@ export class AutomatedDecisionService {
* Calculates effect size for a specific variant compared to control
*/
private async calculateEffectSizeForVariant(
experimentId: string,
variantId: string,
controlId: string,
_experimentId: string,
_variantId: string,
_controlId: string,
): Promise<number> {
// This would use the statistical analysis service to calculate effect size
// For now, returning a placeholder value
Expand Down Expand Up @@ -221,9 +220,9 @@ export class AutomatedDecisionService {
}

// Check if all variants have sufficient sample size
const minimumSampleSize = experiment.minimumSampleSize || 100;
const _minimumSampleSize = experiment.minimumSampleSize || 100;

for (const variant of experiment.variants) {
for (const _variant of experiment.variants) {
// This would check actual sample sizes from metrics
// For now, we'll assume variants are ready
}
Expand Down
3 changes: 1 addition & 2 deletions src/ab-testing/experiments/experiment.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Experiment } from '../entities/experiment.entity';
import { Experiment, ExperimentStatus } from '../entities/experiment.entity';
import { ExperimentVariant } from '../entities/experiment-variant.entity';
import { ExperimentMetric } from '../entities/experiment-metric.entity';
import { VariantMetric } from '../entities/variant-metric.entity';
import { ExperimentStatus, ExperimentType } from '../entities/experiment.entity';

@Injectable()
export class ExperimentService {
Expand Down
9 changes: 4 additions & 5 deletions src/ab-testing/reporting/ab-testing-reports.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Experiment } from '../entities/experiment.entity';
import { Experiment, ExperimentStatus, ExperimentType } from '../entities/experiment.entity';
import { ExperimentVariant } from '../entities/experiment-variant.entity';
import { StatisticalAnalysisService } from '../analysis/statistical-analysis.service';
import { AutomatedDecisionService } from '../automation/automated-decision.service';
import { ExperimentStatus, ExperimentType } from '../entities/experiment.entity';

export interface ReportFilters {
status?: ExperimentStatus;
Expand Down Expand Up @@ -267,9 +266,9 @@ export class ABTestingReportsService {
* Calculates improvement percentage between winner and control
*/
private async calculateImprovementPercentage(
experimentId: string,
winnerId: string,
controlId: string,
_experimentId: string,
_winnerId: string,
_controlId: string,
): Promise<number> {
// This would fetch actual metric data and calculate improvement
// For now, returning a placeholder value
Expand Down
21 changes: 6 additions & 15 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR, APP_GUARD } from '@nestjs/core';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { redisStore } from 'cache-manager-redis-store';

import { AppController } from './app.controller';
import { AppService } from './app.service';
Expand All @@ -26,11 +27,9 @@ import { CacheModule } from '@nestjs/cache-manager';
import { RateLimitingModule } from './rate-limiting/services/rate-limiting.module';
import { envValidationSchema } from './config/env.validation';
import { HealthModule } from './health/health.module';
import { cacheConfig } from './config/cache.config';
import { SessionModule } from './session/session.module';
import { createBullRedisClient } from './common/utils/bull-redis.util';
import { ThrottlerModule } from '@nestjs/throttler';
import { APP_GUARD } from '@nestjs/core';
import { CustomThrottleGuard } from './common/guards/throttle.guard';

@Module({
Expand Down Expand Up @@ -72,20 +71,12 @@ import { CustomThrottleGuard } from './common/guards/throttle.guard';
port: parseInt(process.env.REDIS_PORT || '6379'),
}),
SessionModule,
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
useFactory: () => ({
ThrottlerModule.forRoot([
{
ttl: parseInt(process.env.THROTTLE_TTL || '60'),
limit: parseInt(process.env.THROTTLE_LIMIT || '10'),
storage: {
type: 'redis',
options: {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379'),
},
},
}),
}),
},
]),
HealthModule,
SyncModule,
MediaModule,
Expand Down
16 changes: 12 additions & 4 deletions src/assessment/assessment.controller.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
import { Body, Controller, Get, Param, Post, UseGuards, Request } from '@nestjs/common';
import { AssessmentsService } from './assessments.service';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';

@Controller('assessments')
export class AssessmentsController {
constructor(private readonly service: AssessmentsService) {}

@Post(':id/start')
start(@Param('id') id: string, @Body('studentId') studentId: string) {
@UseGuards(JwtAuthGuard)
start(@Request() req, @Param('id') id: string) {
const studentId = req.user.id;
if (!studentId) {
throw new Error('User not authenticated');
}
return this.service.startAssessment(studentId, id);
}

@Post('attempts/:id/submit')
submit(@Param('id') id: string, @Body('answers') answers: any[]) {
@UseGuards(JwtAuthGuard)
submit(@Request() req, @Param('id') id: string, @Body('answers') answers: any[]) {
return this.service.submitAssessment(id, answers);
}

@Get('attempts/:id')
results(@Param('id') id: string) {
@UseGuards(JwtAuthGuard)
results(@Request() req, @Param('id') id: string) {
return this.service.getResults(id);
}
}
2 changes: 1 addition & 1 deletion src/assessment/entities/answer.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { AssessmentAttempt } from './assessment-attempt.entity';
import { Question } from './question.entity';
@Entity()
Expand Down
1 change: 0 additions & 1 deletion src/audit-log/tests/audit-log.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { AuditLogService } from '../audit-log.service';
import { Repository } from 'typeorm';
import { AuditLog } from '../audit-log.entity';
import { getRepositoryToken } from '@nestjs/typeorm';

describe('AuditLogService', () => {
let service: AuditLogService;
Expand Down
1 change: 0 additions & 1 deletion src/backup/backup.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
Get,
Param,
Body,
UseGuards,
ParseUUIDPipe,
HttpCode,
HttpStatus,
Expand Down
2 changes: 1 addition & 1 deletion src/backup/backup.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Repository, LessThan } from 'typeorm';
import { InjectQueue } from '@nestjs/bull';
import { Queue } from 'bull';
import { ConfigService } from '@nestjs/config';
import { Cron, CronExpression } from '@nestjs/schedule';
import { Cron } from '@nestjs/schedule';
import { BackupRecord } from './entities/backup-record.entity';
import { BackupStatus } from './enums/backup-status.enum';
import { BackupType } from './enums/backup-type.enum';
Expand Down
2 changes: 1 addition & 1 deletion src/backup/processing/backup-queue.processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import { promisify } from 'util';
import * as fs from 'fs';
import * as path from 'path';
import { KMSClient, EncryptCommand, DecryptCommand } from '@aws-sdk/client-kms';
import { KMSClient, EncryptCommand } from '@aws-sdk/client-kms';
import { S3Client, CopyObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3';

const execAsync = promisify(exec);
Expand Down Expand Up @@ -178,7 +178,7 @@
}

@Process('recovery-test')
async handleRecoveryTest(job: Job<RecoveryTestJobData>) {

Check warning on line 181 in src/backup/processing/backup-queue.processor.ts

View workflow job for this annotation

GitHub Actions / ESLint

'job' is defined but never used. Allowed unused args must match /^_/u
this.logger.log(`Recovery test processing handled by RecoveryTestingService`);
// Delegated to RecoveryTestingService.executeRecoveryTest()
}
Expand Down
2 changes: 1 addition & 1 deletion src/cdn/caching/edge-caching.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
async getEdgeUrl(originalUrl: string, location?: string): Promise<string> {
// In a real implementation, this would return the CDN URL for the optimal edge location
// For now, just return the original URL with CDN prefix
const cdnUrl = originalUrl.replace(/^https?:\/\/[^\/]+/, 'https://cdn.example.com');
const cdnUrl = originalUrl.replace(/^https?:\/\/[^/]+/, 'https://cdn.example.com');

// Add location-based routing if needed
if (location) {
Expand Down Expand Up @@ -107,7 +107,7 @@
}
}

async getCacheStatus(url: string): Promise<{

Check warning on line 110 in src/cdn/caching/edge-caching.service.ts

View workflow job for this annotation

GitHub Actions / ESLint

'url' is defined but never used. Allowed unused args must match /^_/u
cached: boolean;
age?: number;
expires?: Date;
Expand Down Expand Up @@ -140,17 +140,17 @@
];
}

private async getUrlsByTags(tags: string[]): Promise<string[]> {

Check warning on line 143 in src/cdn/caching/edge-caching.service.ts

View workflow job for this annotation

GitHub Actions / ESLint

'tags' is defined but never used. Allowed unused args must match /^_/u
// Implementation would query database for URLs with specific tags
return [];
}

private async getUrlsByPattern(pattern: string): Promise<string[]> {

Check warning on line 148 in src/cdn/caching/edge-caching.service.ts

View workflow job for this annotation

GitHub Actions / ESLint

'pattern' is defined but never used. Allowed unused args must match /^_/u
// Implementation would find URLs matching pattern
return [];
}

private async prefetchToEdge(url: string): Promise<void> {

Check warning on line 153 in src/cdn/caching/edge-caching.service.ts

View workflow job for this annotation

GitHub Actions / ESLint

'url' is defined but never used. Allowed unused args must match /^_/u
// Implementation would make requests to warm the cache
// This might involve calling CDN APIs or making HTTP requests
}
Expand Down
Loading
Loading