First version for working parallel
Some checks are pending
CI Pipeline / changes (push) Waiting to run
CI Pipeline / core (push) Blocked by required conditions
CI Pipeline / trading-backend (push) Blocked by required conditions
CI Pipeline / trading-data-service (push) Blocked by required conditions
CI Pipeline / trading-frontend (push) Blocked by required conditions
CI Pipeline / erp-core (push) Blocked by required conditions
CI Pipeline / erp-mecanicas (push) Blocked by required conditions
CI Pipeline / gamilit-backend (push) Blocked by required conditions
CI Pipeline / gamilit-frontend (push) Blocked by required conditions

This commit is contained in:
rckrdmrd 2025-12-12 06:36:15 -06:00
parent 789d1ab46b
commit 48e7235e79
221 changed files with 533 additions and 523 deletions

View File

@ -152,7 +152,7 @@ export class AdminAlertsController {
@ApiResponse({ status: 403, description: 'Forbidden - Admin role required' })
async createAlert(
@Body() createDto: CreateAlertDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<AlertResponseDto> {
const userId = req.user?.id || req.user?.sub;
return this.alertsService.createAlert(createDto, userId);
@ -184,7 +184,7 @@ export class AdminAlertsController {
async acknowledgeAlert(
@Param('id') id: string,
@Body() dto: AcknowledgeAlertDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<AlertResponseDto> {
const userId = req.user?.id || req.user?.sub;
return this.alertsService.acknowledgeAlert(id, dto.acknowledgment_note, userId);
@ -216,7 +216,7 @@ export class AdminAlertsController {
async resolveAlert(
@Param('id') id: string,
@Body() dto: ResolveAlertDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<AlertResponseDto> {
const userId = req.user?.id || req.user?.sub;
return this.alertsService.resolveAlert(id, dto.resolution_note, userId);

View File

@ -60,7 +60,7 @@ export class AdminBulkOperationsController {
@ApiResponse({ status: 403, description: 'Forbidden - Admin access required' })
async bulkSuspendUsers(
@Body() dto: BulkSuspendUsersDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> {
const adminId = req.user.sub; // JWT payload contiene sub = user.id
return this.bulkOpsService.bulkSuspendUsers(dto, adminId);
@ -82,7 +82,7 @@ export class AdminBulkOperationsController {
})
async bulkActivateUsers(
@Body() dto: BulkActivateUsersDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> {
const adminId = req.user.sub;
return this.bulkOpsService.bulkActivateUsers(dto, adminId);
@ -104,7 +104,7 @@ export class AdminBulkOperationsController {
})
async bulkUpdateRole(
@Body() dto: BulkUpdateRoleDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> {
const adminId = req.user.sub;
return this.bulkOpsService.bulkUpdateRole(dto, adminId);
@ -126,7 +126,7 @@ export class AdminBulkOperationsController {
})
async bulkDeleteUsers(
@Body() dto: BulkDeleteUsersDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> {
const adminId = req.user.sub;
return this.bulkOpsService.bulkDeleteUsers(dto, adminId);

View File

@ -69,7 +69,7 @@ export class AdminContentController {
async approveContent(
@Param('id') id: string,
@Body() approvalDto: ApproveContentDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<ContentDto> {
const adminId = req.user?.id || req.user?.sub;
return this.adminContentService.approveContent(
@ -87,7 +87,7 @@ export class AdminContentController {
async approveExercise(
@Param('id') id: string,
@Body() approvalDto: ApproveContentDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<ContentDto> {
const adminId = req.user?.id || req.user?.sub;
return this.adminContentService.approveContent(
@ -106,7 +106,7 @@ export class AdminContentController {
async rejectContent(
@Param('id') id: string,
@Body() rejectionDto: RejectContentDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<ContentDto> {
const adminId = req.user?.id || req.user?.sub;
return this.adminContentService.rejectContent(
@ -124,7 +124,7 @@ export class AdminContentController {
async rejectExercise(
@Param('id') id: string,
@Body() rejectionDto: RejectContentDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<ContentDto> {
const adminId = req.user?.id || req.user?.sub;
return this.adminContentService.rejectContent(
@ -157,7 +157,7 @@ export class AdminContentController {
})
async createVersion(
@Body() dto: CreateVersionDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<VersionResponseDto> {
const adminId = req.user?.id || req.user?.sub;
return this.adminContentService.createVersion(dto, adminId);

View File

@ -175,7 +175,7 @@ export class AdminGamificationConfigController {
})
async updateGamificationSettings(
@Body() dto: UpdateGamificationSettingsDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<GamificationSettingsResponseDto> {
const adminId = req.user.sub;
return this.gamificationConfigService.updateGamificationSettings(
@ -282,7 +282,7 @@ export class AdminGamificationConfigController {
description: 'Forbidden - User is not an admin',
})
async restoreDefaults(
@Request() req: any,
@Request() req: AuthRequest,
): Promise<RestoreDefaultsResultDto> {
const adminId = req.user.sub;
return this.gamificationConfigService.restoreDefaults(adminId);
@ -323,7 +323,7 @@ export class AdminGamificationConfigController {
description: 'Forbidden - User is not an admin',
})
async restoreDefaultsAlternative(
@Request() req: any,
@Request() req: AuthRequest,
): Promise<RestoreDefaultsResultDto> {
const adminId = req.user.sub;
return this.gamificationConfigService.restoreDefaults(adminId);
@ -503,7 +503,7 @@ export class AdminGamificationConfigController {
async updateParameterById(
@Param('id') id: string,
@Body() dto: UpdateParameterDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<UpdateParameterResponseDto> {
const adminId = req.user.sub;
return this.gamificationConfigService.updateParameterById(
@ -635,7 +635,7 @@ export class AdminGamificationConfigController {
async updateMayaRank(
@Param('rankName') rankName: string,
@Body() dto: UpdateMayaRankDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<UpdateMayaRankResponseDto> {
const adminId = req.user.sub;
return this.gamificationConfigService.updateMayaRank(

View File

@ -163,7 +163,7 @@ export class AdminInterventionsController {
async acknowledgeIntervention(
@Param('id') id: string,
@Body() dto: AcknowledgeInterventionDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<InterventionAlertDto> {
const userId = req.user?.id || req.user?.sub;
return this.interventionsService.acknowledgeIntervention(id, dto.acknowledgment_note, userId);
@ -211,7 +211,7 @@ export class AdminInterventionsController {
async resolveIntervention(
@Param('id') id: string,
@Body() dto: ResolveInterventionDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<InterventionAlertDto> {
const userId = req.user?.id || req.user?.sub;
return this.interventionsService.resolveIntervention(id, dto.resolution_notes, userId);

View File

@ -37,7 +37,7 @@ export class AdminReportsController {
})
async generateReport(
@Body() generateDto: GenerateReportDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<ReportDto> {
const userId = req.user?.id || req.user?.sub;
return this.adminReportsService.generateReport(generateDto, userId);

View File

@ -71,7 +71,7 @@ export class AdminSystemController {
})
async updateSystemConfig(
@Body() configDto: UpdateSystemConfigDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<SystemConfigDto> {
const adminId = req.user?.id || req.user?.sub;
return this.adminSystemService.updateSystemConfig(configDto, adminId);
@ -94,7 +94,7 @@ export class AdminSystemController {
})
async getConfigByCategory(
@Param('category') category: string,
): Promise<Record<string, any>> {
): Promise<Record<string, unknown>> {
return this.adminSystemService.getConfigByCategory(category);
}
@ -106,9 +106,9 @@ export class AdminSystemController {
})
async updateConfigByCategory(
@Param('category') category: string,
@Body() configDto: Record<string, any>,
@Request() req: any,
): Promise<Record<string, any>> {
@Body() configDto: Record<string, unknown>,
@Request() req: AuthRequest,
): Promise<Record<string, unknown>> {
const adminId = req.user?.id || req.user?.sub;
return this.adminSystemService.updateConfigByCategory(
category,
@ -125,7 +125,7 @@ export class AdminSystemController {
})
async toggleMaintenance(
@Body() toggleDto: ToggleMaintenanceDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<MaintenanceStatusDto> {
const adminId = req.user?.id || req.user?.sub;
return this.adminSystemService.toggleMaintenance(

View File

@ -137,7 +137,7 @@ export class AdminUsersController {
})
async bulkSuspend(
@Body() dto: BulkSuspendUsersDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> {
const adminId = req.user?.id || req.user?.sub;
return this.bulkOpsService.bulkSuspendUsers(dto, adminId);
@ -151,7 +151,7 @@ export class AdminUsersController {
})
async bulkDelete(
@Body() dto: BulkDeleteUsersDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> {
const adminId = req.user?.id || req.user?.sub;
return this.bulkOpsService.bulkDeleteUsers(dto, adminId);
@ -165,7 +165,7 @@ export class AdminUsersController {
})
async bulkUpdateRole(
@Body() dto: BulkUpdateRoleDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> {
const adminId = req.user?.id || req.user?.sub;
return this.bulkOpsService.bulkUpdateRole(dto, adminId);

View File

@ -114,7 +114,7 @@ export class FeatureFlagsController {
})
async create(
@Body() dto: CreateFeatureFlagDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<FeatureFlag> {
const adminId = req.user?.id || req.user?.sub;
return this.featureFlagsService.create(dto, adminId);
@ -140,7 +140,7 @@ export class FeatureFlagsController {
async update(
@Param('key') key: string,
@Body() dto: UpdateFeatureFlagDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<FeatureFlag> {
const adminId = req.user?.id || req.user?.sub;
return this.featureFlagsService.update(key, dto, adminId);
@ -161,7 +161,7 @@ export class FeatureFlagsController {
})
async enable(
@Param('key') key: string,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<FeatureFlag> {
const adminId = req.user?.id || req.user?.sub;
return this.featureFlagsService.enable(key, adminId);
@ -182,7 +182,7 @@ export class FeatureFlagsController {
})
async disable(
@Param('key') key: string,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<FeatureFlag> {
const adminId = req.user?.id || req.user?.sub;
return this.featureFlagsService.disable(key, adminId);
@ -204,7 +204,7 @@ export class FeatureFlagsController {
async updateRollout(
@Param('key') key: string,
@Body('percentage') percentage: number,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<FeatureFlag> {
const adminId = req.user?.id || req.user?.sub;
return this.featureFlagsService.updateRollout(key, percentage, adminId);

View File

@ -75,10 +75,10 @@ export class AlertResponseDto {
suppress_similar!: boolean;
@ApiPropertyOptional({ description: 'Additional context data' })
context_data?: Record<string, any>;
context_data?: Record<string, unknown>;
@ApiPropertyOptional({ description: 'Metrics data' })
metrics?: Record<string, any>;
metrics?: Record<string, unknown>;
@ApiPropertyOptional({ description: 'Related alert IDs', type: [String] })
related_alerts?: string[];

View File

@ -45,10 +45,10 @@ export class CreateAlertDto {
@ApiPropertyOptional({ description: 'Additional context data (JSON)' })
@IsOptional()
@IsObject()
context_data?: Record<string, any>;
context_data?: Record<string, unknown>;
@ApiPropertyOptional({ description: 'Metrics data (JSON)' })
@IsOptional()
@IsObject()
metrics?: Record<string, any>;
metrics?: Record<string, unknown>;
}

View File

@ -61,5 +61,5 @@ export class ContentDto {
@ApiPropertyOptional({ description: 'Additional metadata' })
@Expose()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
}

View File

@ -65,5 +65,5 @@ export class VersionResponseDto {
is_published: true,
},
})
snapshot!: Record<string, any>;
snapshot!: Record<string, unknown>;
}

View File

@ -48,7 +48,7 @@ export class AdminActionDto {
@ApiPropertyOptional({
description: 'Additional metadata in JSON format',
})
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
@ApiProperty({
description: 'Timestamp when the action occurred',

View File

@ -88,7 +88,7 @@ export class CreateFeatureFlagDto {
})
@IsObject()
@IsOptional()
targetConditions?: Record<string, any>;
targetConditions?: Record<string, unknown>;
@ApiProperty({
description: 'Categoría de la feature flag',
@ -106,5 +106,5 @@ export class CreateFeatureFlagDto {
})
@IsObject()
@IsOptional()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
}

View File

@ -15,7 +15,7 @@ export class GamificationSettingsResponseDto {
perfect_score_bonus: 2.0,
},
})
xp!: Record<string, any>;
xp!: Record<string, unknown>;
@ApiProperty({
description: 'Rank thresholds',
@ -27,7 +27,7 @@ export class GamificationSettingsResponseDto {
expert: 5000,
},
})
ranks!: Record<string, any>;
ranks!: Record<string, unknown>;
@ApiProperty({
description: 'ML Coins rewards',
@ -37,13 +37,13 @@ export class GamificationSettingsResponseDto {
exercise_completion_reward: 100,
},
})
coins!: Record<string, any>;
coins!: Record<string, unknown>;
@ApiPropertyOptional({
description: 'Achievement criteria',
example: { criteria: [] },
})
achievements?: Record<string, any>;
achievements?: Record<string, unknown>;
@ApiProperty({
description: 'Default values from system',
@ -52,7 +52,7 @@ export class GamificationSettingsResponseDto {
'gamification.xp.completion_multiplier': 1.5,
},
})
defaults!: Record<string, any>;
defaults!: Record<string, unknown>;
@ApiProperty({
description: 'Timestamp of last update',

View File

@ -109,13 +109,13 @@ export class ParameterResponseDto {
description: 'Validation rules in JSON format',
example: { regex: '^[0-9]+$' },
})
validation_rules?: Record<string, any>;
validation_rules?: Record<string, unknown>;
@ApiPropertyOptional({
description: 'Additional metadata',
example: { unit: 'points', category_order: 1 },
})
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
@ApiProperty({
description: 'Timestamp when parameter was created',

View File

@ -182,5 +182,5 @@ export class UpdateGamificationSettingsDto {
})
@IsOptional()
@IsObject()
achievements?: Record<string, any>;
achievements?: Record<string, unknown>;
}

View File

@ -80,7 +80,7 @@ export class InterventionAlertDto {
description: 'Additional metrics and context data',
example: { average_score: 45, exercises_failed: 3 },
})
metrics?: Record<string, any>;
metrics?: Record<string, unknown>;
@ApiProperty({
enum: InterventionStatus,

View File

@ -58,7 +58,7 @@ export class RecentErrorDto {
nullable: true,
example: { stack: '...', code: 'ECONNREFUSED' },
})
context!: Record<string, any> | null;
context!: Record<string, unknown> | null;
@ApiProperty({
description: 'Source of the error',

View File

@ -91,7 +91,7 @@ export class CreateOrganizationDto {
})
@IsOptional()
@IsObject()
settings?: Record<string, any>;
settings?: Record<string, unknown>;
@ApiPropertyOptional({
description: 'Organization metadata (JSONB)',
@ -99,5 +99,5 @@ export class CreateOrganizationDto {
})
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
}

View File

@ -49,11 +49,11 @@ export class OrganizationDto {
@ApiProperty({ description: 'Organization settings', example: { theme: 'detective' } })
@Expose()
settings!: Record<string, any>;
settings!: Record<string, unknown>;
@ApiProperty({ description: 'Organization metadata', example: { notes: '...' } })
@Expose()
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
@ApiProperty({ description: 'Creation date', example: '2025-01-15T10:00:00Z' })
@Expose()

View File

@ -83,7 +83,7 @@ export class UpdateOrganizationDto {
})
@IsOptional()
@IsObject()
settings?: Record<string, any>;
settings?: Record<string, unknown>;
@ApiPropertyOptional({
description: 'Organization metadata (JSONB)',
@ -91,5 +91,5 @@ export class UpdateOrganizationDto {
})
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
}

View File

@ -48,7 +48,7 @@ export class ReportDto {
@ApiPropertyOptional({
description: 'Report metadata',
})
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
@ApiProperty({
description: 'Report creation timestamp',

View File

@ -60,7 +60,7 @@ export class MaintenanceOperationResultDto {
description: 'Additional metadata about the operation',
example: { execution_time_ms: 1523 },
})
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
}
/**

View File

@ -20,7 +20,7 @@ export class SystemConfigDto {
session_timeout_minutes!: number;
@ApiPropertyOptional({ description: 'Custom settings' })
custom_settings?: Record<string, any>;
custom_settings?: Record<string, unknown>;
@ApiProperty({ description: 'Last updated timestamp', example: '2025-11-02T18:00:00Z' })
updated_at!: string;

View File

@ -61,5 +61,5 @@ export class UpdateSystemConfigDto {
})
@IsOptional()
@IsObject()
custom_settings?: Record<string, any>;
custom_settings?: Record<string, unknown>;
}

View File

@ -24,5 +24,5 @@ export class UpdateUserDto {
@IsOptional()
@IsObject()
raw_user_meta_data?: Record<string, any>;
raw_user_meta_data?: Record<string, unknown>;
}

View File

@ -39,7 +39,7 @@ export class UserDetailsDto {
last_sign_in_at?: Date;
@Expose()
raw_user_meta_data!: Record<string, any>;
raw_user_meta_data!: Record<string, unknown>;
@Expose()
created_at!: Date;

View File

@ -88,7 +88,7 @@ export class AdminReport {
* Formato: { startDate: '2025-01-01', endDate: '2025-12-31', classroomId: 'abc', ... }
*/
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* Mensaje de error si la generación falla

View File

@ -101,7 +101,7 @@ export class FeatureFlag {
* @example { "min_level": 5, "schools": ["uuid1", "uuid2"] }
*/
@Column({ type: 'jsonb', default: {} })
target_conditions!: Record<string, any>;
target_conditions!: Record<string, unknown>;
/**
* Fecha y hora de inicio de la feature
@ -122,7 +122,7 @@ export class FeatureFlag {
* @example { "ab_test_group": "A", "tracking_id": "GA-123" }
*/
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* ID del usuario que creó la feature flag

View File

@ -121,20 +121,20 @@ export class NotificationSettings {
* @example { "max_retries": 3, "backoff": "exponential" }
*/
@Column({ type: 'jsonb', default: {} })
retry_policy!: Record<string, any>;
retry_policy!: Record<string, unknown>;
/**
* Configuraciones específicas del canal de entrega
* @example { "email_format": "html", "reply_to": "support@example.com" }
*/
@Column({ type: 'jsonb', default: {} })
delivery_settings!: Record<string, any>;
delivery_settings!: Record<string, unknown>;
/**
* Metadatos adicionales
*/
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* ID del usuario que creó el setting

View File

@ -176,14 +176,14 @@ export class SystemAlert {
* @example { "endpoint": "/api/users", "statusCode": 500, "requestId": "abc123" }
*/
@Column({ type: 'jsonb', default: {} })
context_data!: Record<string, any>;
context_data!: Record<string, unknown>;
/**
* Métricas asociadas en formato JSONB
* @example { "responseTime": 5000, "errorRate": 0.15, "cpuUsage": 0.95 }
*/
@Column({ type: 'jsonb', default: {} })
metrics!: Record<string, any>;
metrics!: Record<string, unknown>;
/**
* Array de IDs de alertas relacionadas

View File

@ -133,7 +133,7 @@ export class SystemSetting {
* @example { "regex": "^[a-z]+$", "minLength": 3 }
*/
@Column({ type: 'jsonb', default: {} })
validation_rules!: Record<string, any>;
validation_rules!: Record<string, unknown>;
/**
* Valores permitidos para el setting (array de strings)
@ -158,7 +158,7 @@ export class SystemSetting {
* Metadatos adicionales en formato JSONB
*/
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* ID del usuario que creó el setting

View File

@ -194,7 +194,7 @@ export class AdminAlertsService {
* @param userId - ID del usuario que crea la alerta (para auditoría)
* @returns Alerta creada
*/
async createAlert(createDto: CreateAlertDto: string): Promise<AlertResponseDto> {
async createAlert(createDto: CreateAlertDto, _userId: string): Promise<AlertResponseDto> {
const alert = this.alertRepo.create({
alert_type: createDto.alert_type,
severity: createDto.severity,

View File

@ -577,7 +577,7 @@ export class AdminContentService {
private createSnapshot(
content: any,
content_type: string,
): Record<string, any> {
): Record<string, unknown> {
switch (content_type) {
case 'module':
return {
@ -804,7 +804,7 @@ export class AdminContentService {
});
content_title = template?.name;
}
} catch (_error) {
} catch {
// Content might have been deleted, just leave title as undefined
content_title = undefined;
}

View File

@ -279,7 +279,7 @@ export class AdminSystemService {
adminId: string,
): Promise<SystemConfigDto> {
// Update settings in database
const settingsToUpdate: Record<string, any> = {
const settingsToUpdate: Record<string, unknown> = {
maintenance_mode: updateDto.maintenance_mode,
maintenance_message: updateDto.maintenance_message,
allow_registrations: updateDto.allow_registrations,
@ -360,7 +360,7 @@ export class AdminSystemService {
/**
* Get system configuration by category
*/
async getConfigByCategory(category: string): Promise<Record<string, any>> {
async getConfigByCategory(category: string): Promise<Record<string, unknown>> {
// Validate category
const validCategories = ['general', 'email', 'notifications', 'security', 'maintenance'];
if (!validCategories.includes(category)) {
@ -387,7 +387,7 @@ export class AdminSystemService {
});
// Build config object for this category
const config: Record<string, any> = {};
const config: Record<string, unknown> = {};
settings.forEach((setting) => {
config[setting.setting_key] = this.parseValue(setting);
});
@ -400,9 +400,9 @@ export class AdminSystemService {
*/
async updateConfigByCategory(
category: string,
configDto: Record<string, any>,
configDto: Record<string, unknown>,
adminId: string,
): Promise<Record<string, any>> {
): Promise<Record<string, unknown>> {
// Validate category
const validCategories = ['general', 'email', 'notifications', 'security', 'maintenance'];
if (!validCategories.includes(category)) {
@ -744,7 +744,8 @@ export class AdminSystemService {
pool_size: poolSize,
active_connections: activeConnections,
};
} catch () {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (_error) {
return {
status: 'down',
response_time_ms: -1,

View File

@ -425,8 +425,8 @@ export class GamificationConfigService {
* Parse settings array into structured config
* @private
*/
private parseSettings(settings: SystemSetting[]): Record<string, any> {
const config: Record<string, any> = {
private parseSettings(settings: SystemSetting[]): Record<string, unknown> {
const config: Record<string, unknown> = {
xp: {},
ranks: {},
coins: {},
@ -446,7 +446,7 @@ export class GamificationConfigService {
} else if (setting.value_type === 'json') {
try {
value = JSON.parse(value);
} catch (_error) {
} catch {
this.logger.warn(`Failed to parse JSON for ${setting.setting_key}`);
value = {};
}
@ -471,8 +471,8 @@ export class GamificationConfigService {
* Parse default values from settings
* @private
*/
private parseDefaults(settings: SystemSetting[]): Record<string, any> {
const defaults: Record<string, any> = {};
private parseDefaults(settings: SystemSetting[]): Record<string, unknown> {
const defaults: Record<string, unknown> = {};
for (const setting of settings) {
if (setting.default_value) {
@ -484,7 +484,7 @@ export class GamificationConfigService {
} else if (setting.value_type === 'json') {
try {
value = JSON.parse(value);
} catch (_error) {
} catch {
this.logger.warn(
`Failed to parse default JSON for ${setting.setting_key}`,
);
@ -542,7 +542,7 @@ export class GamificationConfigService {
* @private
*/
private async updateXpSettings(
xp: Record<string, any>,
xp: Record<string, unknown>,
adminId: string,
): Promise<void> {
for (const [key, value] of Object.entries(xp)) {
@ -556,7 +556,7 @@ export class GamificationConfigService {
* @private
*/
private async updateRankSettings(
ranks: Record<string, any>,
ranks: Record<string, unknown>,
adminId: string,
): Promise<void> {
const settingKey = 'gamification.ranks.thresholds';
@ -568,7 +568,7 @@ export class GamificationConfigService {
* @private
*/
private async updateCoinsSettings(
coins: Record<string, any>,
coins: Record<string, unknown>,
adminId: string,
): Promise<void> {
for (const [key, value] of Object.entries(coins)) {
@ -582,7 +582,7 @@ export class GamificationConfigService {
* @private
*/
private async updateAchievementSettings(
achievements: Record<string, any>,
achievements: Record<string, unknown>,
adminId: string,
): Promise<void> {
const settingKey = 'gamification.achievements.criteria';
@ -992,7 +992,7 @@ export class GamificationConfigService {
if (parameter.value_type === 'json') {
try {
JSON.parse(value);
} catch (_error) {
} catch {
throw new BadRequestException(
`Invalid JSON value for ${parameter.setting_key}`,
);

View File

@ -69,7 +69,7 @@ export class AssignmentsController {
},
})
@ApiResponse({ status: 400, description: 'Datos inválidos' })
async create(@Body() createDto: CreateAssignmentDto, @Request() req: any) {
async create(@Body() createDto: CreateAssignmentDto, @Request() req: AuthRequest) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.create(createDto, teacherId);
}
@ -116,7 +116,7 @@ export class AssignmentsController {
}],
},
})
async findAll(@Query() query: any, @Request() req: any) {
async findAll(@Query() query: any, @Request() req: AuthRequest) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.findAll(teacherId, {
isPublished: query.isPublished !== undefined ? query.isPublished === 'true' : undefined,
@ -164,7 +164,7 @@ export class AssignmentsController {
status: 404,
description: 'Asignación no encontrada o acceso denegado',
})
async findOne(@Param('id') id: string, @Request() req: any) {
async findOne(@Param('id') id: string, @Request() req: AuthRequest) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.findOne(id, teacherId);
}
@ -199,7 +199,7 @@ export class AssignmentsController {
async update(
@Param('id') id: string,
@Body() updateDto: UpdateAssignmentDto,
@Request() req: any,
@Request() req: AuthRequest,
) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.update(id, updateDto, teacherId);
@ -228,7 +228,7 @@ export class AssignmentsController {
status: 404,
description: 'Asignación no encontrada o acceso denegado',
})
async remove(@Param('id') id: string, @Request() req: any) {
async remove(@Param('id') id: string, @Request() req: AuthRequest) {
const teacherId = req.user?.userId || req.user?.sub;
await this.assignmentsService.remove(id, teacherId);
}
@ -266,7 +266,7 @@ export class AssignmentsController {
async assignToClassrooms(
@Param('id') id: string,
@Body() dto: AssignToClassroomsDto,
@Request() req: any,
@Request() req: AuthRequest,
) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.assignToClassrooms(id, dto, teacherId);
@ -320,7 +320,7 @@ export class AssignmentsController {
async getSubmissions(
@Param('id') id: string,
@Query() query: any,
@Request() req: any,
@Request() req: AuthRequest,
) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.getSubmissions(id, teacherId, {
@ -373,7 +373,7 @@ export class AssignmentsController {
async gradeSubmission(
@Param('submissionId') submissionId: string,
@Body() dto: AssignmentGradeDto,
@Request() req: any,
@Request() req: AuthRequest,
) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.gradeSubmission(submissionId, dto, teacherId);
@ -407,7 +407,7 @@ export class AssignmentsController {
async patch(
@Param('id') id: string,
@Body() patchDto: PatchAssignmentDto,
@Request() req: any,
@Request() req: AuthRequest,
) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.patchAssignment(id, patchDto, teacherId);
@ -441,7 +441,7 @@ export class AssignmentsController {
async distribute(
@Param('id') id: string,
@Body() distributeDto: DistributeAssignmentDto,
@Request() req: any,
@Request() req: AuthRequest,
) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.distributeAssignment(id, distributeDto, teacherId);
@ -472,7 +472,7 @@ export class AssignmentsController {
async duplicate(
@Param('id') id: string,
@Body() duplicateDto: DuplicateAssignmentDto,
@Request() req: any,
@Request() req: AuthRequest,
) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.duplicateAssignment(id, duplicateDto, teacherId);
@ -528,7 +528,7 @@ export class AssignmentsController {
async publish(
@Param('id') id: string,
@Body('notifyStudents') notifyStudents: boolean = false,
@Request() req: any,
@Request() req: AuthRequest,
) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.publishAssignment(id, teacherId, notifyStudents);
@ -569,7 +569,7 @@ export class AssignmentsController {
status: 404,
description: 'Assignment not found or access denied',
})
async close(@Param('id') id: string, @Request() req: any) {
async close(@Param('id') id: string, @Request() req: AuthRequest) {
const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.closeAssignment(id, teacherId);
}

View File

@ -73,7 +73,7 @@ export class StudentAssignmentsController {
}],
},
})
async getMyAssignments(@Query() query: any, @Request() req: any) {
async getMyAssignments(@Query() query: any, @Request() req: AuthRequest) {
const studentId = req.user?.userId || req.user?.sub;
return this.assignmentsService.findStudentAssignments(studentId, {
status: query.status,
@ -104,7 +104,7 @@ export class StudentAssignmentsController {
status: 404,
description: 'Tarea no encontrada o no asignada a este estudiante',
})
async getAssignmentDetails(@Param('id') id: string, @Request() req: any) {
async getAssignmentDetails(@Param('id') id: string, @Request() req: AuthRequest) {
const studentId = req.user?.userId || req.user?.sub;
return this.assignmentsService.findStudentAssignmentById(id, studentId);
}
@ -137,7 +137,7 @@ export class StudentAssignmentsController {
},
},
})
async getGradesSummary(@Request() req: any) {
async getGradesSummary(@Request() req: AuthRequest) {
const studentId = req.user?.userId || req.user?.sub;
return this.assignmentsService.getStudentGradesSummary(studentId);
}

View File

@ -859,7 +859,7 @@ export class AssignmentsService {
*/
async findStudentAssignments(
studentId: string,
filters?: { status?: string; classroomId?: string },
_filters?: { status?: string; classroomId?: string },
): Promise<any[]> {
// Get direct student assignments (without relation join - relations commented out)
const studentAssignments = await this.assignmentStudentRepository.find({

View File

@ -25,7 +25,7 @@ export class AuditInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest<Request>();
const { method, url, _body, _user} = request;
const { method, url, body: _body, user: _user} = request;
// Skip audit logging for certain endpoints
if (this.shouldSkipAudit(url)) {

View File

@ -45,7 +45,7 @@ export class AuthService {
* 4. Generate JWT tokens
* 5. Return sanitized user + tokens
*/
async register(dto: any): Promise<AuthResponse> {
async register(_dto: any): Promise<AuthResponse> {
throw new Error('Register method not implemented - UsersService required');
}
@ -59,7 +59,7 @@ export class AuthService {
* 4. Generate JWT tokens
* 5. Return sanitized user + tokens
*/
async login(dto: LoginDto): Promise<AuthResponse> {
async login(_dto: LoginDto): Promise<AuthResponse> {
throw new Error('Login method not implemented - UsersService required');
}
@ -76,14 +76,14 @@ export class AuthService {
* 3. Validate user is active
* 4. Generate new access + refresh tokens
*/
async refreshToken(dto: RefreshTokenDto): Promise<TokenResponse> {
async refreshToken(_dto: RefreshTokenDto): Promise<TokenResponse> {
throw new Error('RefreshToken method not implemented - UsersService required');
}
/**
* Logout - Invalida tokens (client-side)
*/
async logout(userId: string): Promise<{ message: string }> {
async logout(_userId: string): Promise<{ message: string }> {
// TODO: Implementar blacklist de tokens en Redis (opcional)
// Por ahora, el logout es client-side (eliminar tokens de localStorage)
@ -99,7 +99,7 @@ export class AuthService {
* 2. Check if user exists and is active
* 3. Return sanitized user (without password)
*/
async validateUser(userId: string) {
async validateUser(_userId: string) {
throw new Error('ValidateUser method not implemented - UsersService required');
}

View File

@ -72,7 +72,7 @@ export class AuthController {
@ApiBody({ type: RegisterUserDto })
async register(
@Body() dto: RegisterUserDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<{ user: UserResponseDto; accessToken: string; refreshToken: string }> {
const ip = req.ip;
const userAgent = req.headers['user-agent'];
@ -104,7 +104,7 @@ export class AuthController {
@ApiBody({ type: LoginDto })
async login(
@Body() dto: LoginDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<{ user: UserResponseDto; accessToken: string; refreshToken: string }> {
const ip = req.ip;
const userAgent = req.headers['user-agent'];
@ -129,7 +129,7 @@ export class AuthController {
@ApiOperation({ summary: 'Cerrar sesión de usuario' })
@ApiResponse({ status: 200, description: 'Sesión cerrada exitosamente' })
@ApiResponse({ status: 401, description: 'No autenticado' })
async logout(@Request() req: any): Promise<{ message: string }> {
async logout(@Request() req: AuthRequest): Promise<{ message: string }> {
// Extraer userId y sessionId del token JWT
const userId = req.user?.id;
const sessionId = req.user?.sessionId || 'current-session';
@ -175,7 +175,7 @@ export class AuthController {
type: UserResponseDto,
})
@ApiResponse({ status: 401, description: 'No autenticado' })
async getProfile(@Request() req: any): Promise<UserResponseDto> {
async getProfile(@Request() req: AuthRequest): Promise<UserResponseDto> {
// Extraer userId del token JWT
const userId = req.user?.id;
const user = await this.authService.validateUser(userId);
@ -185,7 +185,7 @@ export class AuthController {
}
// Convertir a UserResponseDto (sin password)
const { _encrypted_password, ...userResponse } = user;
const { encrypted_password: _encrypted_password, ...userResponse } = user;
return userResponse as UserResponseDto;
}
@ -206,7 +206,7 @@ export class AuthController {
@ApiResponse({ status: 400, description: 'Datos inválidos' })
@ApiBody({ type: UpdateProfileDto })
async updateProfile(
@Request() req: any,
@Request() req: AuthRequest,
@Body() dto: UpdateProfileDto,
): Promise<UserResponseDto> {
// Extraer userId del token JWT
@ -220,7 +220,7 @@ export class AuthController {
}
// Convertir a UserResponseDto (sin password)
const { _encrypted_password, ...userResponse } = updatedUser;
const { encrypted_password: _encrypted_password, ...userResponse } = updatedUser;
return userResponse as UserResponseDto;
}
@ -247,7 +247,7 @@ export class AuthController {
},
},
})
async verifyEmail(@Body('token') token: string): Promise<{ message: string }> {
async verifyEmail(@Body('token') _token: string): Promise<{ message: string }> {
// TODO: Implementar lógica de verificación de email
// Por ahora retornamos éxito
return { message: 'Email verificado exitosamente' };
@ -275,7 +275,7 @@ export class AuthController {
},
},
})
async forgotPassword(@Body('email') email: string): Promise<{ message: string }> {
async forgotPassword(@Body('email') _email: string): Promise<{ message: string }> {
// TODO: Implementar lógica de forgot password
return { message: 'Si el email existe, recibirás instrucciones para resetear tu contraseña' };
}
@ -305,8 +305,8 @@ export class AuthController {
},
})
async resetPassword(
@Body('token') token: string,
@Body('newPassword') newPassword: string,
@Body('token') _token: string,
@Body('newPassword') _newPassword: string,
): Promise<{ message: string }> {
// TODO: Implementar lógica de reset password
return { message: 'Contraseña reseteada exitosamente' };
@ -340,9 +340,9 @@ export class AuthController {
},
})
async changePassword(
@Request() req: any,
@Body('currentPassword') currentPassword: string,
@Body('newPassword') newPassword: string,
@Request() req: AuthRequest,
@Body('currentPassword') _currentPassword: string,
@Body('newPassword') _newPassword: string,
): Promise<{ message: string }> {
const _userId = req.user?.id;
// TODO: Implementar lógica de cambio de contraseña
@ -363,7 +363,7 @@ export class AuthController {
isArray: true,
})
@ApiResponse({ status: 401, description: 'No autenticado' })
async getSessions(@Request() req: any): Promise<UserSessionResponseDto[]> {
async getSessions(@Request() req: AuthRequest): Promise<UserSessionResponseDto[]> {
const userId = req.user?.id;
return this.sessionService.getSessions(userId);
}
@ -391,7 +391,7 @@ export class AuthController {
@ApiResponse({ status: 401, description: 'No autenticado' })
@ApiResponse({ status: 404, description: 'Sesión no encontrada o no pertenece al usuario' })
async revokeSession(
@Request() req: any,
@Request() req: AuthRequest,
@Param('sessionId') sessionId: string,
): Promise<{ message: string }> {
const userId = req.user?.id;
@ -420,7 +420,7 @@ export class AuthController {
},
})
@ApiResponse({ status: 401, description: 'No autenticado' })
async revokeAllSessions(@Request() req: any): Promise<{ message: string; count: number }> {
async revokeAllSessions(@Request() req: AuthRequest): Promise<{ message: string; count: number }> {
const userId = req.user?.id;
const currentSessionId = req.user?.sessionId || 'unknown';
return this.sessionService.revokeAllSessions(userId, currentSessionId);

View File

@ -140,7 +140,7 @@ export class PasswordController {
@ApiResponse({ status: 404, description: 'Usuario no encontrado' })
@ApiBody({ type: ChangePasswordDto })
async changePassword(
@Request() req: any,
@Request() req: AuthRequest,
@Body() dto: ChangePasswordDto,
): Promise<{ message: string }> {
// Extraer userId del token JWT
@ -201,7 +201,7 @@ export class PasswordController {
})
@ApiResponse({ status: 401, description: 'No autenticado' })
@ApiResponse({ status: 409, description: 'Email ya verificado' })
async resendVerification(@Request() req: any): Promise<{ message: string }> {
async resendVerification(@Request() req: AuthRequest): Promise<{ message: string }> {
// Extraer userId del token JWT
const userId = req.user?.id;
return this.emailVerificationService.resendVerification(userId);
@ -226,7 +226,7 @@ export class PasswordController {
},
})
@ApiResponse({ status: 401, description: 'No autenticado' })
async checkVerificationStatus(@Request() req: any): Promise<{ verified: boolean }> {
async checkVerificationStatus(@Request() req: AuthRequest): Promise<{ verified: boolean }> {
// Extraer userId del token JWT
const userId = req.user?.id;
return this.emailVerificationService.checkVerificationStatus(userId);

View File

@ -59,7 +59,7 @@ export class UsersController {
type: UserResponseDto,
})
@ApiResponse({ status: 401, description: 'No autenticado' })
async getProfile(@Request() req: any): Promise<UserResponseDto> {
async getProfile(@Request() req: AuthRequest): Promise<UserResponseDto> {
const userId = req.user?.id;
const user = await this.authService.validateUser(userId);
@ -67,7 +67,7 @@ export class UsersController {
throw new UnauthorizedException('Usuario no encontrado');
}
const { _encrypted_password, ...userResponse } = user;
const { encrypted_password: _encrypted_password, ...userResponse } = user;
return userResponse as UserResponseDto;
}
@ -88,7 +88,7 @@ export class UsersController {
@ApiResponse({ status: 400, description: 'Datos inválidos' })
@ApiBody({ type: UpdateProfileDto })
async updateProfile(
@Request() req: any,
@Request() req: AuthRequest,
@Body() dto: UpdateProfileDto,
): Promise<UserResponseDto> {
const userId = req.user?.id;
@ -98,7 +98,7 @@ export class UsersController {
throw new UnauthorizedException('Usuario no encontrado');
}
const { _encrypted_password, ...userResponse } = updatedUser;
const { encrypted_password: _encrypted_password, ...userResponse } = updatedUser;
return userResponse as UserResponseDto;
}
@ -119,7 +119,7 @@ export class UsersController {
},
})
@ApiResponse({ status: 401, description: 'No autenticado' })
async getPreferences(@Request() req: any): Promise<{ preferences: any }> {
async getPreferences(@Request() req: AuthRequest): Promise<{ preferences: any }> {
const userId = req.user?.id;
const preferences = await this.authService.getUserPreferences(userId);
return { preferences };
@ -151,7 +151,7 @@ export class UsersController {
},
})
async updatePreferences(
@Request() req: any,
@Request() req: AuthRequest,
@Body('preferences') preferences: any,
): Promise<{ preferences: any }> {
const userId = req.user?.id;
@ -194,7 +194,7 @@ export class UsersController {
},
})
async uploadAvatar(
@Request() req: any,
@Request() req: AuthRequest,
@UploadedFile() file: any,
): Promise<{ avatar_url: string }> {
const userId = req.user?.id;
@ -230,7 +230,7 @@ export class UsersController {
},
})
@ApiResponse({ status: 401, description: 'No autenticado' })
async getStatistics(@Request() req: any): Promise<any> {
async getStatistics(@Request() req: AuthRequest): Promise<any> {
const userId = req.user?.id;
const statistics = await this.authService.getUserStatistics(userId);
return statistics;

View File

@ -52,7 +52,7 @@ export class AssignRoleDto {
*/
@IsObject({ message: 'permissions debe ser un objeto JSON válido' })
@IsOptional()
permissions?: Record<string, any>;
permissions?: Record<string, unknown>;
/**
* Fecha y hora de expiración del rol (opcional)
@ -81,5 +81,5 @@ export class AssignRoleDto {
*/
@IsObject({ message: 'metadata debe ser un objeto JSON válido' })
@IsOptional()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
}

View File

@ -205,7 +205,7 @@ export class CreateProfileDto {
*/
@IsObject()
@IsOptional()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
/**
* ID del usuario en auth.users

View File

@ -126,7 +126,7 @@ export class CreateTenantDto {
*/
@IsObject({ message: 'Las configuraciones deben ser un objeto JSON válido' })
@IsOptional()
settings?: Record<string, any>;
settings?: Record<string, unknown>;
/**
* Metadata adicional del tenant (JSONB)
@ -135,5 +135,5 @@ export class CreateTenantDto {
*/
@IsObject({ message: 'La metadata debe ser un objeto JSON válido' })
@IsOptional()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
}

View File

@ -141,5 +141,5 @@ export class CreateUserPreferencesDto {
})
@IsOptional()
@IsObject()
preferences?: Record<string, any>;
preferences?: Record<string, unknown>;
}

View File

@ -55,5 +55,5 @@ export class CreateUserDto {
*/
@IsObject({ message: 'Los metadatos deben ser un objeto JSON' })
@IsOptional()
raw_user_meta_data?: Record<string, any>;
raw_user_meta_data?: Record<string, unknown>;
}

View File

@ -87,7 +87,7 @@ export class ProfileResponseDto {
last_activity_at!: Date | null;
@Expose()
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
@Expose()
created_at!: Date;

View File

@ -39,7 +39,7 @@ export class RegisterUserDto {
*/
@IsObject({ message: 'Los metadatos deben ser un objeto JSON' })
@IsOptional()
raw_user_meta_data?: Record<string, any>;
raw_user_meta_data?: Record<string, unknown>;
// Campos opcionales adicionales para registro:
// Nota: Estos campos se podrían mapear al Profile (auth_management.profiles)

View File

@ -75,13 +75,13 @@ export class TenantResponseDto {
* Configuraciones del tenant (JSONB)
*/
@Expose()
settings!: Record<string, any>;
settings!: Record<string, unknown>;
/**
* Metadata adicional del tenant (JSONB)
*/
@Expose()
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* Fecha de creación del tenant

View File

@ -20,7 +20,7 @@ export class UpdateUserDto extends PartialType(
) {
// Hereda de CreateUserDto excepto password y email:
// - role?: GamilityRoleEnum
// - raw_user_meta_data?: Record<string, any>
// - raw_user_meta_data?: Record<string, unknown>
// Campos opcionales adicionales para actualización:
// (actualmente solo role y raw_user_meta_data son editables)

View File

@ -99,7 +99,7 @@ export class UserPreferencesResponseDto {
dashboard_layout: 'grid',
},
})
preferences!: Record<string, any>;
preferences!: Record<string, unknown>;
/**
* Fecha de creación

View File

@ -99,7 +99,7 @@ export class UserResponseDto {
* NOTA: Filtrar campos sensibles si existen
*/
@Expose()
raw_user_meta_data!: Record<string, any>;
raw_user_meta_data!: Record<string, unknown>;
/**
* Fecha y hora de creación del registro

View File

@ -38,7 +38,7 @@ export class UserRoleResponseDto {
* Permisos específicos asociados a este rol
*/
@Expose()
permissions!: Record<string, any>;
permissions!: Record<string, unknown>;
/**
* ID del usuario (Profile) que asignó este rol (nullable)
@ -80,7 +80,7 @@ export class UserRoleResponseDto {
* Metadata adicional del user_role
*/
@Expose()
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* Fecha de creación del registro

View File

@ -43,7 +43,7 @@ export class AuthAttempt {
attempted_at!: Date;
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
// NOTA: La tabla auth_attempts NO tiene user_id
// Es una tabla de auditoría independiente que solo registra el email

View File

@ -125,7 +125,7 @@ export class Profile {
last_activity_at!: Date | null;
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
@CreateDateColumn({ type: 'timestamp with time zone' })
created_at!: Date;

View File

@ -84,7 +84,7 @@ export class SecurityEvent {
* @example { "failed_attempts": 3, "reason": "invalid_password" }
*/
@Column({ type: 'jsonb', nullable: true })
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
/**
* Fecha y hora de creación del evento

View File

@ -113,14 +113,14 @@ export class Tenant {
timezone: 'America/Mexico_City',
},
})
settings!: Record<string, any>;
settings!: Record<string, unknown>;
/**
* Metadata adicional del tenant (JSONB)
* @example { billing_contact: "admin@example.com", notes: "..." }
*/
@Column({ type: 'jsonb', nullable: false, default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* Fecha de creación del tenant

View File

@ -117,7 +117,7 @@ export class UserPreferences {
*/
@Column({ type: 'jsonb', default: {} })
@Index('idx_user_preferences_preferences', { synchronize: false }) // GIN index creado en DDL
preferences!: Record<string, any>;
preferences!: Record<string, unknown>;
/**
* Fecha de creación

View File

@ -92,7 +92,7 @@ export class UserRole {
nullable: false,
default: { read: true, write: false, admin: false, analytics: false },
})
permissions!: Record<string, any>;
permissions!: Record<string, unknown>;
/**
* ID del usuario (Profile) que asignó este rol (nullable)
@ -143,7 +143,7 @@ export class UserRole {
* @example { notes: "Rol temporal para proyecto X", reason: "..." }
*/
@Column({ type: 'jsonb', nullable: false, default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* Fecha de creación del registro

View File

@ -77,7 +77,7 @@ export class UserSession {
revoked_at!: Date | null;
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
// Relaciones
@ManyToOne(() => User, { onDelete: 'CASCADE' })

View File

@ -137,7 +137,7 @@ export class User {
* Metadatos adicionales del usuario en formato JSON
*/
@Column({ type: 'jsonb', default: {} })
raw_user_meta_data!: Record<string, any>;
raw_user_meta_data!: Record<string, unknown>;
/**
* Fecha y hora de eliminación lógica (soft delete)

View File

@ -658,7 +658,7 @@ export class AuthService {
* @returns UserResponseDto con campos derivados calculados
*/
public toUserResponse(user: User): UserResponseDto {
const { _encrypted_password, ...userWithoutPassword } = user;
const { encrypted_password: _encrypted_password, ...userWithoutPassword } = user;
// Calcular campos derivados para coherencia Frontend-Backend
const emailVerified = !!user.email_confirmed_at;

View File

@ -42,9 +42,9 @@ export class ContentTemplatesController {
@ApiResponse({ status: 200, description: 'Lista de plantillas obtenida exitosamente', type: [ContentTemplateResponseDto] })
async findAll(
@Query('type') type?: string,
@Query('category') category?: string,
@Query('category') _category?: string,
) {
return this.templatesService.findAll(type, category);
return this.templatesService.findAll(type);
}
/**

View File

@ -38,11 +38,11 @@ export class ContentTemplateResponseDto {
@ApiProperty({ description: 'Estructura JSON de la plantilla' })
@Expose()
template_structure!: Record<string, any>;
template_structure!: Record<string, unknown>;
@ApiPropertyOptional({ description: 'Valores predeterminados' })
@Expose()
default_values?: Record<string, any>;
default_values?: Record<string, unknown>;
@ApiPropertyOptional({ description: 'Campos requeridos' })
@Expose()
@ -82,7 +82,7 @@ export class ContentTemplateResponseDto {
@ApiProperty({ description: 'Metadatos adicionales' })
@Expose()
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
@ApiPropertyOptional({ description: 'ID del usuario creador' })
@Expose()

View File

@ -62,7 +62,7 @@ export class CreateContentTemplateDto {
*/
@ApiProperty({ description: 'Estructura JSON de la plantilla', example: { sections: [], fields: [] } })
@IsObject()
template_structure!: Record<string, any>;
template_structure!: Record<string, unknown>;
/**
* Valores predeterminados JSON
@ -70,7 +70,7 @@ export class CreateContentTemplateDto {
@ApiPropertyOptional({ description: 'Valores predeterminados', example: { difficulty: 'medium', duration: 30 } })
@IsOptional()
@IsObject()
default_values?: Record<string, any>;
default_values?: Record<string, unknown>;
/**
* Campos requeridos
@ -141,7 +141,7 @@ export class CreateContentTemplateDto {
@ApiPropertyOptional({ description: 'Metadatos adicionales', example: {} })
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
/**
* ID del creador

View File

@ -72,7 +72,7 @@ export class CreateMarieCurieContentDto {
*/
@ApiProperty({ description: 'Contenido estructurado JSON', example: { introduction: 'Texto introductorio...', main_content: 'Contenido principal...', key_points: [], timeline: [], quotes: [] } })
@IsObject()
content!: Record<string, any>;
content!: Record<string, unknown>;
// =====================================================
// EDUCATIONAL METADATA
@ -196,7 +196,7 @@ export class CreateMarieCurieContentDto {
@ApiPropertyOptional({ description: 'Contexto cultural JSON', example: {} })
@IsOptional()
@IsObject()
cultural_context?: Record<string, any>;
cultural_context?: Record<string, unknown>;
// =====================================================
// PUBLICATION STATUS
@ -286,5 +286,5 @@ export class CreateMarieCurieContentDto {
@ApiPropertyOptional({ description: 'Metadatos adicionales', example: {} })
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
}

View File

@ -260,7 +260,7 @@ export class CreateMediaFileDto {
@ApiPropertyOptional({ description: 'Información de procesamiento JSON', example: {} })
@IsOptional()
@IsObject()
processing_info?: Record<string, any>;
processing_info?: Record<string, unknown>;
// =====================================================
// SEARCH & ORGANIZATION
@ -381,7 +381,7 @@ export class CreateMediaFileDto {
@ApiPropertyOptional({ description: 'Datos EXIF JSON', example: {} })
@IsOptional()
@IsObject()
exif_data?: Record<string, any>;
exif_data?: Record<string, unknown>;
/**
* Metadatos adicionales
@ -389,5 +389,5 @@ export class CreateMediaFileDto {
@ApiPropertyOptional({ description: 'Metadatos adicionales', example: {} })
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
}

View File

@ -45,7 +45,7 @@ export class MarieCurieContentResponseDto {
@ApiProperty({ description: 'Contenido estructurado JSON' })
@Expose()
content!: Record<string, any>;
content!: Record<string, unknown>;
// =====================================================
// EDUCATIONAL METADATA
@ -109,7 +109,7 @@ export class MarieCurieContentResponseDto {
@ApiProperty({ description: 'Contexto cultural JSON' })
@Expose()
cultural_context!: Record<string, any>;
cultural_context!: Record<string, unknown>;
// =====================================================
// PUBLICATION STATUS
@ -161,7 +161,7 @@ export class MarieCurieContentResponseDto {
@ApiProperty({ description: 'Metadatos adicionales' })
@Expose()
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
@ApiProperty({ description: 'Fecha de creación' })
@Expose()

View File

@ -145,7 +145,7 @@ export class MediaFileResponseDto {
@ApiProperty({ description: 'Información de procesamiento' })
@Expose()
processing_info!: Record<string, any>;
processing_info!: Record<string, unknown>;
// =====================================================
// SEARCH & ORGANIZATION
@ -213,11 +213,11 @@ export class MediaFileResponseDto {
@ApiProperty({ description: 'Datos EXIF' })
@Expose()
exif_data!: Record<string, any>;
exif_data!: Record<string, unknown>;
@ApiProperty({ description: 'Metadatos adicionales' })
@Expose()
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
// =====================================================
// AUDIT TIMESTAMPS

View File

@ -75,14 +75,14 @@ export class ContentTemplate {
* Define cómo se estructura el contenido
*/
@Column({ type: 'jsonb', default: {} })
template_structure!: Record<string, any>;
template_structure!: Record<string, unknown>;
/**
* Valores predeterminados JSON
* Valores iniciales al crear contenido desde esta plantilla
*/
@Column({ type: 'jsonb', nullable: true })
default_values?: Record<string, any>;
default_values?: Record<string, unknown>;
/**
* Campos requeridos en el contenido
@ -146,7 +146,7 @@ export class ContentTemplate {
* Metadatos adicionales en formato JSON
*/
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* Fecha y hora de creación del registro

View File

@ -96,7 +96,7 @@ export class MarieCurieContent {
main_content: '',
},
})
content!: Record<string, any>;
content!: Record<string, unknown>;
// =====================================================
// EDUCATIONAL METADATA
@ -190,7 +190,7 @@ export class MarieCurieContent {
* Contexto cultural en formato JSON
*/
@Column({ type: 'jsonb', default: {} })
cultural_context!: Record<string, any>;
cultural_context!: Record<string, unknown>;
// =====================================================
// PUBLICATION STATUS
@ -265,7 +265,7 @@ export class MarieCurieContent {
* Metadatos adicionales en formato JSON
*/
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* Fecha y hora de creación del registro

View File

@ -234,7 +234,7 @@ export class MediaFile {
* Información de procesamiento en formato JSON
*/
@Column({ type: 'jsonb', default: {} })
processing_info!: Record<string, any>;
processing_info!: Record<string, unknown>;
// =====================================================
// SEARCH & ORGANIZATION
@ -326,13 +326,13 @@ export class MediaFile {
* Datos EXIF del archivo (imágenes)
*/
@Column({ type: 'jsonb', default: {} })
exif_data!: Record<string, any>;
exif_data!: Record<string, unknown>;
/**
* Metadatos adicionales en formato JSON
*/
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
// =====================================================
// AUDIT TIMESTAMPS

View File

@ -38,7 +38,7 @@ export class ContentTemplatesService {
* @param category - Categoría (opcional, no usado en DDL pero útil para filtros futuros)
* @returns Lista de plantillas
*/
async findAll(type?: string?: string): Promise<ContentTemplate[]> {
async findAll(type?: string): Promise<ContentTemplate[]> {
const query = this.templateRepo.createQueryBuilder('t');
if (type) {
@ -140,7 +140,7 @@ export class ContentTemplatesService {
* @param category - Categoría de plantilla
* @returns Lista de plantillas de la categoría
*/
async findByCategory(category: string): Promise<ContentTemplate[]> {
async findByCategory(_category: string): Promise<ContentTemplate[]> {
// Actualmente retorna todas ya que no existe el campo category en DDL
// Se puede extender con metadata o agregando el campo en una migración futura
return this.templateRepo.find({

View File

@ -90,7 +90,7 @@ export class ExercisesController {
*/
private normalizeSubmitData(dto: SubmitExerciseDto, req: any): {
userId: string;
answers: Record<string, any>;
answers: Record<string, unknown>;
timeSpentSeconds?: number;
hintsUsed: number;
powerupsUsed: string[];
@ -105,7 +105,7 @@ export class ExercisesController {
}
// 2. Extraer respuestas (nuevo formato tiene prioridad)
let answers: Record<string, any>;
let answers: Record<string, unknown>;
if (dto.answers) {
// Formato nuevo (estándar)
@ -220,7 +220,7 @@ export class ExercisesController {
status: 500,
description: 'Error interno del servidor',
})
async findAll(@Request() req: any) {
async findAll(@Request() req: AuthRequest) {
const userId = req.user.id;
const userRole = req.user.role;
@ -372,7 +372,7 @@ export class ExercisesController {
},
},
})
async findOne(@Param('id') id: string, @Request() req: any) {
async findOne(@Param('id') id: string, @Request() req: AuthRequest) {
const userId = req.user.id;
// Obtener ejercicio
@ -671,7 +671,7 @@ export class ExercisesController {
status: 404,
description: 'Módulo no encontrado',
})
async findByModule(@Param('moduleId') moduleId: string, @Request() req: any) {
async findByModule(@Param('moduleId') moduleId: string, @Request() req: AuthRequest) {
// Obtener ejercicios del módulo
const exercises = await this.exercisesService.findByModuleId(moduleId);
@ -818,7 +818,7 @@ export class ExercisesController {
},
})
async validateContentByExerciseType(
@Body() body: { exercise_type: ExerciseTypeEnum; content: Record<string, any> },
@Body() body: { exercise_type: ExerciseTypeEnum; content: Record<string, unknown> },
) {
this.exercisesService.validateContentByExerciseType(body.exercise_type, body.content);
return {
@ -943,7 +943,7 @@ export class ExercisesController {
async submitExercise(
@Param('id') exerciseId: string,
@Body() dto: SubmitExerciseDto,
@Request() req: any,
@Request() req: AuthRequest,
): Promise<SubmitExerciseResponseDto> {
// ========================================
// 1. NORMALIZACIÓN

View File

@ -80,7 +80,7 @@ export class MediaUploadController {
})
@ApiResponse({ status: 400, description: 'Archivo inválido o excede límite de tamaño' })
async uploadFile(
@Request() req: any,
@Request() req: AuthRequest,
@UploadedFile() file: any,
@Body() dto: UploadMediaDto,
): Promise<MediaAttachment> {

View File

@ -349,7 +349,7 @@ export class MediaController {
})
async updateProcessingStatus(
@Param('id') id: string,
@Body() body: { status: ProcessingStatusEnum; metadata?: Record<string, any> },
@Body() body: { status: ProcessingStatusEnum; metadata?: Record<string, unknown> },
) {
return this.mediaService.updateProcessingStatus(id, body.status, body.metadata);
}

View File

@ -110,7 +110,7 @@ export class ModulesController {
status: 500,
description: 'Error interno del servidor',
})
async findAll(@Request() req: any, @Query() query: GetModulesQueryDto) {
async findAll(@Request() req: AuthRequest, @Query() query: GetModulesQueryDto) {
const userId = req.user.id;
// Reutilizar getUserModules que ya tiene la lógica correcta para ambas tablas
// Ahora acepta classroomId opcional para filtrar

View File

@ -84,7 +84,7 @@ export class CreateExerciseDto {
*/
@IsOptional()
@IsObject()
config?: Record<string, any>;
config?: Record<string, unknown>;
/**
* Contenido del ejercicio (JSONB) (REQUERIDO)
@ -92,21 +92,21 @@ export class CreateExerciseDto {
*/
@IsOptional()
@IsObject()
content?: Record<string, any>;
content?: Record<string, unknown>;
/**
* Solución del ejercicio (JSONB)
*/
@IsOptional()
@IsObject()
solution?: Record<string, any>;
solution?: Record<string, unknown>;
/**
* Rúbrica de evaluación (JSONB)
*/
@IsOptional()
@IsObject()
rubric?: Record<string, any>;
rubric?: Record<string, unknown>;
// =====================================================
// GRADING & SCORING
@ -233,7 +233,7 @@ export class CreateExerciseDto {
*/
@IsOptional()
@IsObject()
comodines_config?: Record<string, any>;
comodines_config?: Record<string, unknown>;
// =====================================================
// GAMIFICATION & REWARDS
@ -345,5 +345,5 @@ export class CreateExerciseDto {
*/
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
}

View File

@ -61,16 +61,16 @@ export class ExerciseResponseDto {
exercise_type!: ExerciseTypeEnum;
@Expose()
config!: Record<string, any>;
config!: Record<string, unknown>;
@Expose()
content!: Record<string, any>;
content!: Record<string, unknown>;
@Expose()
solution?: Record<string, any>;
solution?: Record<string, unknown>;
@Expose()
rubric?: Record<string, any>;
rubric?: Record<string, unknown>;
// =====================================================
// GRADING & SCORING
@ -132,7 +132,7 @@ export class ExerciseResponseDto {
comodines_allowed!: ComodinTypeEnum[];
@Expose()
comodines_config!: Record<string, any>;
comodines_config!: Record<string, unknown>;
// =====================================================
// GAMIFICATION & REWARDS
@ -187,7 +187,7 @@ export class ExerciseResponseDto {
prerequisites?: string[];
@Expose()
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
// =====================================================
// AUDIT FIELDS

View File

@ -60,7 +60,7 @@ export class SubmitExerciseDto {
@IsOptional()
@IsObject({ message: 'answers must be an object' })
@IsNotEmpty({ message: 'answers cannot be empty' })
answers?: Record<string, any>;
answers?: Record<string, unknown>;
/**
* Timestamp de inicio del ejercicio (milisegundos desde epoch)
@ -133,7 +133,7 @@ export class SubmitExerciseDto {
})
@IsOptional()
@IsObject()
submitted_answers?: Record<string, any>;
submitted_answers?: Record<string, unknown>;
/**
* @deprecated Usar 'startedAt' para calcular tiempo

View File

@ -211,7 +211,7 @@ export class MediaResponseDto {
* Metadatos adicionales
*/
@Expose()
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* Fecha de creación

View File

@ -246,5 +246,5 @@ export class UploadMediaDto {
*/
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
}

View File

@ -46,7 +46,7 @@ export class InfografiaInteractivaAnswerDto {
},
})
@IsObject({ message: 'answers must be an object' })
answers: Record<string, any>;
answers: Record<string, unknown>;
@ApiProperty({
description:

View File

@ -59,5 +59,5 @@ export class NavegacionHipertextualAnswerDto {
},
})
@IsObject({ message: 'information_found must be an object' })
information_found: Record<string, any>;
information_found: Record<string, unknown>;
}

View File

@ -66,7 +66,7 @@ export class CreateModuleDto {
*/
@IsOptional()
@IsObject()
content?: Record<string, any>;
content?: Record<string, unknown>;
/**
* Índice de orden para la secuencia de módulos (REQUERIDO)
@ -345,14 +345,14 @@ export class CreateModuleDto {
*/
@IsOptional()
@IsObject()
settings?: Record<string, any>;
settings?: Record<string, unknown>;
/**
* Metadatos adicionales (JSONB)
*/
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
/**
* Total de ejercicios en el módulo

View File

@ -34,7 +34,7 @@ export class ModuleResponseDto {
summary?: string;
@Expose()
content!: Record<string, any>;
content!: Record<string, unknown>;
@Expose()
order_index!: number;
@ -165,10 +165,10 @@ export class ModuleResponseDto {
cover_image_url?: string;
@Expose()
settings!: Record<string, any>;
settings!: Record<string, unknown>;
@Expose()
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
// =====================================================
// AUDIT FIELDS

View File

@ -65,7 +65,7 @@ export class CreateRubricDto {
* Estructura: {"criteria_1": {"name": string, "levels": {}, "weight": number}}
*/
@IsObject()
criteria!: Record<string, any>;
criteria!: Record<string, unknown>;
/**
* Escala de puntuación en formato JSONB
@ -73,7 +73,7 @@ export class CreateRubricDto {
*/
@IsOptional()
@IsObject()
scoring_scale?: Record<string, any>;
scoring_scale?: Record<string, unknown>;
/**
* Peso porcentual de esta rúbrica (1-100%)
@ -125,7 +125,7 @@ export class CreateRubricDto {
*/
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
metadata?: Record<string, unknown>;
/**
* ID del usuario que crea la rúbrica

View File

@ -55,13 +55,13 @@ export class RubricResponseDto {
* Criterios de evaluación en formato JSONB
*/
@Expose()
criteria!: Record<string, any>;
criteria!: Record<string, unknown>;
/**
* Escala de puntuación
*/
@Expose()
scoring_scale!: Record<string, any>;
scoring_scale!: Record<string, unknown>;
/**
* Peso porcentual de la rúbrica
@ -105,7 +105,7 @@ export class RubricResponseDto {
* Metadatos adicionales
*/
@Expose()
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* ID del usuario que creó la rúbrica

View File

@ -76,14 +76,14 @@ export class AssessmentRubric {
* Incluye niveles de logro con puntos y descripciones
*/
@Column({ type: 'jsonb', default: {} })
criteria: Record<string, any> = {};
criteria: Record<string, unknown> = {};
/**
* Escala de puntuación en formato JSONB
* Estructura: {"min": number, "max": number, "passing": number}
*/
@Column({ type: 'jsonb', default: { min: 0, max: 100, passing: 70 } })
scoring_scale!: Record<string, any>;
scoring_scale!: Record<string, unknown>;
/**
* Peso porcentual de esta rúbrica en la evaluación total (1-100%)
@ -120,7 +120,7 @@ export class AssessmentRubric {
* Puede incluir configuraciones específicas de evaluación
*/
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* ID del usuario que creó la rúbrica

View File

@ -150,7 +150,7 @@ export class Exercise {
* - etc.
*/
@Column({ type: 'jsonb', default: {} })
config!: Record<string, any>;
config!: Record<string, unknown>;
/**
* Contenido del ejercicio (JSONB)
@ -165,20 +165,20 @@ export class Exercise {
correct_answers: [],
},
})
content!: Record<string, any>;
content!: Record<string, unknown>;
/**
* Solución del ejercicio (JSONB)
* Información privada no visible para estudiantes durante la resolución
*/
@Column({ type: 'jsonb', nullable: true })
solution?: Record<string, any>;
solution?: Record<string, unknown>;
/**
* Rúbrica de evaluación (JSONB)
*/
@Column({ type: 'jsonb', nullable: true })
rubric?: Record<string, any>;
rubric?: Record<string, unknown>;
// =====================================================
// GRADING & SCORING
@ -328,7 +328,7 @@ export class Exercise {
segunda_oportunidad: { cost: 40, enabled: true },
},
})
comodines_config!: Record<string, any>;
comodines_config!: Record<string, unknown>;
// =====================================================
// GAMIFICATION & REWARDS
@ -423,7 +423,7 @@ export class Exercise {
* Metadatos adicionales (JSONB)
*/
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
// =====================================================
// AUDIT FIELDS

View File

@ -241,7 +241,7 @@ export class MediaResource {
* Puede incluir información técnica, codec, bitrate, etc.
*/
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
/**
* Fecha y hora de creación del registro

View File

@ -94,7 +94,7 @@ export class Module {
multimedia_resources: [],
},
})
content!: Record<string, any>;
content!: Record<string, unknown>;
/**
* Índice de orden para la secuencia de módulos
@ -350,13 +350,13 @@ export class Module {
* Configuraciones del módulo (JSONB)
*/
@Column({ type: 'jsonb', default: {} })
settings!: Record<string, any>;
settings!: Record<string, unknown>;
/**
* Metadatos adicionales (JSONB)
*/
@Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>;
metadata!: Record<string, unknown>;
// =====================================================
// AUDIT FIELDS

View File

@ -195,8 +195,8 @@ export class ExercisesService {
*/
validateContentByExerciseType(
exerciseType: ExerciseTypeEnum,
content: Record<string, any>,
config?: Record<string, any>,
content: Record<string, unknown>,
config?: Record<string, unknown>,
): void {
if (!content) {
throw new BadRequestException('Content is required');
@ -474,10 +474,10 @@ export class ExercisesService {
* @returns Sanitized content without correct answers
*/
private sanitizeContent(
content: Record<string, any>,
config: Record<string, any>,
content: Record<string, unknown>,
config: Record<string, unknown>,
exerciseType: ExerciseTypeEnum,
): Record<string, any> {
): Record<string, unknown> {
if (!content) {
return content;
}

View File

@ -85,7 +85,7 @@ export class MediaService {
async updateProcessingStatus(
id: string,
status: ProcessingStatusEnum,
metadata?: Record<string, any>,
metadata?: Record<string, unknown>,
): Promise<MediaResource> {
const media = await this.findById(id);
if (!media) {

View File

@ -141,7 +141,7 @@ export class ClassroomMissionsController {
async assignMissionToClassroom(
@Param('classroomId') classroomId: string,
@Body() dto: AssignClassroomMissionDto,
@Request() req: any,
@Request() req: AuthRequest,
) {
const teacherId = req.user.id;
return this.classroomMissionsService.assignMissionToClassroom(classroomId, teacherId, dto);

Some files were not shown because too many files have changed in this diff Show More