changes for detail agents and erp-suite
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
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:
parent
513a86ceee
commit
3a44cad22e
@ -7,7 +7,7 @@
|
||||
* Sprint 0 - P0-008: Test Infrastructure
|
||||
*/
|
||||
|
||||
import { Repository, SelectQueryBuilder } from 'typeorm';
|
||||
import { Repository, SelectQueryBuilder, ObjectLiteral } from 'typeorm';
|
||||
|
||||
/**
|
||||
* Creates a mock TypeORM Repository with all common methods
|
||||
@ -15,7 +15,7 @@ import { Repository, SelectQueryBuilder } from 'typeorm';
|
||||
* @template T - Entity type
|
||||
* @returns Mocked Repository<T>
|
||||
*/
|
||||
export function createMockRepository<T>(): jest.Mocked<Repository<T>> {
|
||||
export function createMockRepository<T extends ObjectLiteral>(): jest.Mocked<Repository<T>> {
|
||||
return {
|
||||
find: jest.fn(),
|
||||
findOne: jest.fn(),
|
||||
@ -58,7 +58,7 @@ export function createMockRepository<T>(): jest.Mocked<Repository<T>> {
|
||||
* @template T - Entity type
|
||||
* @returns Mocked SelectQueryBuilder<T>
|
||||
*/
|
||||
export function createMockQueryBuilder<T>(): jest.Mocked<SelectQueryBuilder<T>> {
|
||||
export function createMockQueryBuilder<T extends ObjectLiteral>(): jest.Mocked<SelectQueryBuilder<T>> {
|
||||
const queryBuilder = {
|
||||
select: jest.fn().mockReturnThis(),
|
||||
addSelect: jest.fn().mockReturnThis(),
|
||||
|
||||
@ -24,6 +24,7 @@ import {
|
||||
AlertsStatsDto,
|
||||
PaginatedAlertsDto,
|
||||
} from '../dto/alerts';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* AdminAlertsController
|
||||
@ -154,7 +155,7 @@ export class AdminAlertsController {
|
||||
@Body() createDto: CreateAlertDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<AlertResponseDto> {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
const userId = req.user!.id;
|
||||
return this.alertsService.createAlert(createDto, userId);
|
||||
}
|
||||
|
||||
@ -186,7 +187,7 @@ export class AdminAlertsController {
|
||||
@Body() dto: AcknowledgeAlertDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<AlertResponseDto> {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
const userId = req.user!.id;
|
||||
return this.alertsService.acknowledgeAlert(id, dto.acknowledgment_note, userId);
|
||||
}
|
||||
|
||||
@ -218,7 +219,7 @@ export class AdminAlertsController {
|
||||
@Body() dto: ResolveAlertDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<AlertResponseDto> {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
const userId = req.user!.id;
|
||||
return this.alertsService.resolveAlert(id, dto.resolution_note, userId);
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
BulkDeleteUsersDto,
|
||||
BulkOperationStatusDto,
|
||||
} from '../dto/bulk-operations';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* AdminBulkOperationsController
|
||||
@ -62,7 +63,7 @@ export class AdminBulkOperationsController {
|
||||
@Body() dto: BulkSuspendUsersDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<BulkOperationStatusDto> {
|
||||
const adminId = req.user.sub; // JWT payload contiene sub = user.id
|
||||
const adminId = req.user!.id; // JWT payload contiene sub = user.id
|
||||
return this.bulkOpsService.bulkSuspendUsers(dto, adminId);
|
||||
}
|
||||
|
||||
@ -84,7 +85,7 @@ export class AdminBulkOperationsController {
|
||||
@Body() dto: BulkActivateUsersDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<BulkOperationStatusDto> {
|
||||
const adminId = req.user.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.bulkOpsService.bulkActivateUsers(dto, adminId);
|
||||
}
|
||||
|
||||
@ -106,7 +107,7 @@ export class AdminBulkOperationsController {
|
||||
@Body() dto: BulkUpdateRoleDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<BulkOperationStatusDto> {
|
||||
const adminId = req.user.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.bulkOpsService.bulkUpdateRole(dto, adminId);
|
||||
}
|
||||
|
||||
@ -128,7 +129,7 @@ export class AdminBulkOperationsController {
|
||||
@Body() dto: BulkDeleteUsersDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<BulkOperationStatusDto> {
|
||||
const adminId = req.user.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.bulkOpsService.bulkDeleteUsers(dto, adminId);
|
||||
}
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@ import {
|
||||
ListApprovalHistoryDto,
|
||||
PaginatedApprovalHistoryDto,
|
||||
} from '../dto/content';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
@ApiTags('Admin - Content')
|
||||
@Controller('admin/content')
|
||||
@ -71,7 +72,7 @@ export class AdminContentController {
|
||||
@Body() approvalDto: ApproveContentDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<ContentDto> {
|
||||
const adminId = req.user?.id || req.user?.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.adminContentService.approveContent(
|
||||
id,
|
||||
approvalDto,
|
||||
@ -89,7 +90,7 @@ export class AdminContentController {
|
||||
@Body() approvalDto: ApproveContentDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<ContentDto> {
|
||||
const adminId = req.user?.id || req.user?.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.adminContentService.approveContent(
|
||||
id,
|
||||
approvalDto,
|
||||
@ -108,7 +109,7 @@ export class AdminContentController {
|
||||
@Body() rejectionDto: RejectContentDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<ContentDto> {
|
||||
const adminId = req.user?.id || req.user?.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.adminContentService.rejectContent(
|
||||
id,
|
||||
rejectionDto,
|
||||
@ -126,7 +127,7 @@ export class AdminContentController {
|
||||
@Body() rejectionDto: RejectContentDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<ContentDto> {
|
||||
const adminId = req.user?.id || req.user?.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.adminContentService.rejectContent(
|
||||
id,
|
||||
rejectionDto,
|
||||
@ -159,7 +160,7 @@ export class AdminContentController {
|
||||
@Body() dto: CreateVersionDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<VersionResponseDto> {
|
||||
const adminId = req.user?.id || req.user?.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.adminContentService.createVersion(dto, adminId);
|
||||
}
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@ import {
|
||||
UpdateMayaRankDto,
|
||||
UpdateMayaRankResponseDto,
|
||||
} from '../dto/gamification-config';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* AdminGamificationConfigController
|
||||
@ -177,7 +178,7 @@ export class AdminGamificationConfigController {
|
||||
@Body() dto: UpdateGamificationSettingsDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<GamificationSettingsResponseDto> {
|
||||
const adminId = req.user.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.gamificationConfigService.updateGamificationSettings(
|
||||
dto,
|
||||
adminId,
|
||||
@ -284,7 +285,7 @@ export class AdminGamificationConfigController {
|
||||
async restoreDefaults(
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<RestoreDefaultsResultDto> {
|
||||
const adminId = req.user.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.gamificationConfigService.restoreDefaults(adminId);
|
||||
}
|
||||
|
||||
@ -325,7 +326,7 @@ export class AdminGamificationConfigController {
|
||||
async restoreDefaultsAlternative(
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<RestoreDefaultsResultDto> {
|
||||
const adminId = req.user.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.gamificationConfigService.restoreDefaults(adminId);
|
||||
}
|
||||
|
||||
@ -505,7 +506,7 @@ export class AdminGamificationConfigController {
|
||||
@Body() dto: UpdateParameterDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<UpdateParameterResponseDto> {
|
||||
const adminId = req.user.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.gamificationConfigService.updateParameterById(
|
||||
id,
|
||||
dto,
|
||||
@ -637,7 +638,7 @@ export class AdminGamificationConfigController {
|
||||
@Body() dto: UpdateMayaRankDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<UpdateMayaRankResponseDto> {
|
||||
const adminId = req.user.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.gamificationConfigService.updateMayaRank(
|
||||
rankName,
|
||||
dto,
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
InterventionAlertDto,
|
||||
PaginatedInterventionsDto,
|
||||
} from '../dto/interventions';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* AdminInterventionsController
|
||||
@ -165,7 +166,7 @@ export class AdminInterventionsController {
|
||||
@Body() dto: AcknowledgeInterventionDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<InterventionAlertDto> {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
const userId = req.user!.id;
|
||||
return this.interventionsService.acknowledgeIntervention(id, dto.acknowledgment_note, userId);
|
||||
}
|
||||
|
||||
@ -213,7 +214,7 @@ export class AdminInterventionsController {
|
||||
@Body() dto: ResolveInterventionDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<InterventionAlertDto> {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
const userId = req.user!.id;
|
||||
return this.interventionsService.resolveIntervention(id, dto.resolution_notes, userId);
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ import {
|
||||
ListReportsDto,
|
||||
PaginatedReportsDto,
|
||||
} from '../dto/reports';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
@ApiTags('Admin - Reports')
|
||||
@Controller('admin/reports')
|
||||
@ -39,7 +40,7 @@ export class AdminReportsController {
|
||||
@Body() generateDto: GenerateReportDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<ReportDto> {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
const userId = req.user!.id;
|
||||
return this.adminReportsService.generateReport(generateDto, userId);
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
CacheClearResultDto,
|
||||
SessionCleanupResultDto,
|
||||
} from '../dto/system';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
@ApiTags('Admin - System')
|
||||
@Controller('admin/system')
|
||||
@ -73,7 +74,7 @@ export class AdminSystemController {
|
||||
@Body() configDto: UpdateSystemConfigDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<SystemConfigDto> {
|
||||
const adminId = req.user?.id || req.user?.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.adminSystemService.updateSystemConfig(configDto, adminId);
|
||||
}
|
||||
|
||||
@ -109,7 +110,7 @@ export class AdminSystemController {
|
||||
@Body() configDto: Record<string, unknown>,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<Record<string, unknown>> {
|
||||
const adminId = req.user?.id || req.user?.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.adminSystemService.updateConfigByCategory(
|
||||
category,
|
||||
configDto,
|
||||
@ -127,7 +128,7 @@ export class AdminSystemController {
|
||||
@Body() toggleDto: ToggleMaintenanceDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<MaintenanceStatusDto> {
|
||||
const adminId = req.user?.id || req.user?.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.adminSystemService.toggleMaintenance(
|
||||
toggleDto,
|
||||
adminId,
|
||||
|
||||
@ -32,6 +32,7 @@ import {
|
||||
BulkOperationStatusDto,
|
||||
} from '../dto/bulk-operations';
|
||||
import { User } from '@modules/auth/entities/user.entity';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
@ApiTags('Admin - Users')
|
||||
@Controller('admin/users')
|
||||
@ -139,7 +140,7 @@ export class AdminUsersController {
|
||||
@Body() dto: BulkSuspendUsersDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<BulkOperationStatusDto> {
|
||||
const adminId = req.user?.id || req.user?.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.bulkOpsService.bulkSuspendUsers(dto, adminId);
|
||||
}
|
||||
|
||||
@ -153,7 +154,7 @@ export class AdminUsersController {
|
||||
@Body() dto: BulkDeleteUsersDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<BulkOperationStatusDto> {
|
||||
const adminId = req.user?.id || req.user?.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.bulkOpsService.bulkDeleteUsers(dto, adminId);
|
||||
}
|
||||
|
||||
@ -167,7 +168,7 @@ export class AdminUsersController {
|
||||
@Body() dto: BulkUpdateRoleDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<BulkOperationStatusDto> {
|
||||
const adminId = req.user?.id || req.user?.sub;
|
||||
const adminId = req.user!.id;
|
||||
return this.bulkOpsService.bulkUpdateRole(dto, adminId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
FeatureFlagCheckResultDto
|
||||
} from '../dto/feature-flags';
|
||||
import { FeatureFlag } from '../entities/feature-flag.entity';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* FeatureFlagsController
|
||||
|
||||
@ -103,11 +103,11 @@ export class GamificationConfigService {
|
||||
)?.updated_by;
|
||||
|
||||
return {
|
||||
xp: config.xp || DEFAULT_GAMIFICATION_CONFIG.xp,
|
||||
ranks: config.ranks || DEFAULT_GAMIFICATION_CONFIG.ranks,
|
||||
coins: config.coins || DEFAULT_GAMIFICATION_CONFIG.coins,
|
||||
xp: (config.xp as Record<string, unknown>) || (DEFAULT_GAMIFICATION_CONFIG.xp as Record<string, unknown>),
|
||||
ranks: (config.ranks as Record<string, unknown>) || (DEFAULT_GAMIFICATION_CONFIG.ranks as Record<string, unknown>),
|
||||
coins: (config.coins as Record<string, unknown>) || (DEFAULT_GAMIFICATION_CONFIG.coins as Record<string, unknown>),
|
||||
achievements:
|
||||
config.achievements || DEFAULT_GAMIFICATION_CONFIG.achievements,
|
||||
(config.achievements as Record<string, unknown>) || (DEFAULT_GAMIFICATION_CONFIG.achievements as Record<string, unknown>),
|
||||
defaults: defaults,
|
||||
last_updated: lastUpdated.toISOString(),
|
||||
updated_by: updatedBy,
|
||||
@ -131,15 +131,15 @@ export class GamificationConfigService {
|
||||
|
||||
// Update each category
|
||||
if (dto.xp) {
|
||||
await this.updateXpSettings(dto.xp, adminId);
|
||||
await this.updateXpSettings(dto.xp as unknown as Record<string, unknown>, adminId);
|
||||
}
|
||||
|
||||
if (dto.ranks) {
|
||||
await this.updateRankSettings(dto.ranks, adminId);
|
||||
await this.updateRankSettings(dto.ranks as unknown as Record<string, unknown>, adminId);
|
||||
}
|
||||
|
||||
if (dto.coins) {
|
||||
await this.updateCoinsSettings(dto.coins, adminId);
|
||||
await this.updateCoinsSettings(dto.coins as unknown as Record<string, unknown>, adminId);
|
||||
}
|
||||
|
||||
if (dto.achievements) {
|
||||
@ -456,7 +456,7 @@ export class GamificationConfigService {
|
||||
|
||||
// Assign to config structure
|
||||
if (category === 'xp' || category === 'coins') {
|
||||
config[category][key] = value;
|
||||
(config[category] as Record<string, unknown>)[key] = value;
|
||||
} else if (category === 'ranks' && key === 'thresholds') {
|
||||
config.ranks = value;
|
||||
} else if (category === 'achievements' && key === 'criteria') {
|
||||
|
||||
@ -32,6 +32,7 @@ import { AssignmentGradeDto } from '../dto/grade-submission.dto';
|
||||
import { PatchAssignmentDto } from '../dto/patch-assignment.dto';
|
||||
import { DistributeAssignmentDto, DistributeAssignmentResponseDto } from '../dto/distribute-assignment.dto';
|
||||
import { DuplicateAssignmentDto, DuplicateAssignmentResponseDto } from '../dto/duplicate-assignment.dto';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
@Controller('teacher/assignments')
|
||||
@ApiTags('Assignments')
|
||||
@ -70,7 +71,7 @@ export class AssignmentsController {
|
||||
})
|
||||
@ApiResponse({ status: 400, description: 'Datos inválidos' })
|
||||
async create(@Body() createDto: CreateAssignmentDto, @Request() req: AuthRequest) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.create(createDto, teacherId);
|
||||
}
|
||||
|
||||
@ -117,7 +118,7 @@ export class AssignmentsController {
|
||||
},
|
||||
})
|
||||
async findAll(@Query() query: any, @Request() req: AuthRequest) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.findAll(teacherId, {
|
||||
isPublished: query.isPublished !== undefined ? query.isPublished === 'true' : undefined,
|
||||
assignmentType: query.type,
|
||||
@ -165,7 +166,7 @@ export class AssignmentsController {
|
||||
description: 'Asignación no encontrada o acceso denegado',
|
||||
})
|
||||
async findOne(@Param('id') id: string, @Request() req: AuthRequest) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.findOne(id, teacherId);
|
||||
}
|
||||
|
||||
@ -201,7 +202,7 @@ export class AssignmentsController {
|
||||
@Body() updateDto: UpdateAssignmentDto,
|
||||
@Request() req: AuthRequest,
|
||||
) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.update(id, updateDto, teacherId);
|
||||
}
|
||||
|
||||
@ -229,7 +230,7 @@ export class AssignmentsController {
|
||||
description: 'Asignación no encontrada o acceso denegado',
|
||||
})
|
||||
async remove(@Param('id') id: string, @Request() req: AuthRequest) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
await this.assignmentsService.remove(id, teacherId);
|
||||
}
|
||||
|
||||
@ -268,7 +269,7 @@ export class AssignmentsController {
|
||||
@Body() dto: AssignToClassroomsDto,
|
||||
@Request() req: AuthRequest,
|
||||
) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.assignToClassrooms(id, dto, teacherId);
|
||||
}
|
||||
|
||||
@ -322,7 +323,7 @@ export class AssignmentsController {
|
||||
@Query() query: any,
|
||||
@Request() req: AuthRequest,
|
||||
) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.getSubmissions(id, teacherId, {
|
||||
status: query.status,
|
||||
classroomId: query.classroomId,
|
||||
@ -375,7 +376,7 @@ export class AssignmentsController {
|
||||
@Body() dto: AssignmentGradeDto,
|
||||
@Request() req: AuthRequest,
|
||||
) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.gradeSubmission(submissionId, dto, teacherId);
|
||||
}
|
||||
|
||||
@ -409,7 +410,7 @@ export class AssignmentsController {
|
||||
@Body() patchDto: PatchAssignmentDto,
|
||||
@Request() req: AuthRequest,
|
||||
) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.patchAssignment(id, patchDto, teacherId);
|
||||
}
|
||||
|
||||
@ -443,7 +444,7 @@ export class AssignmentsController {
|
||||
@Body() distributeDto: DistributeAssignmentDto,
|
||||
@Request() req: AuthRequest,
|
||||
) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.distributeAssignment(id, distributeDto, teacherId);
|
||||
}
|
||||
|
||||
@ -474,7 +475,7 @@ export class AssignmentsController {
|
||||
@Body() duplicateDto: DuplicateAssignmentDto,
|
||||
@Request() req: AuthRequest,
|
||||
) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.duplicateAssignment(id, duplicateDto, teacherId);
|
||||
}
|
||||
|
||||
@ -530,7 +531,7 @@ export class AssignmentsController {
|
||||
@Body('notifyStudents') notifyStudents: boolean = false,
|
||||
@Request() req: AuthRequest,
|
||||
) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.publishAssignment(id, teacherId, notifyStudents);
|
||||
}
|
||||
|
||||
@ -570,7 +571,7 @@ export class AssignmentsController {
|
||||
description: 'Assignment not found or access denied',
|
||||
})
|
||||
async close(@Param('id') id: string, @Request() req: AuthRequest) {
|
||||
const teacherId = req.user?.userId || req.user?.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.assignmentsService.closeAssignment(id, teacherId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ import { RolesGuard } from '../../auth/guards/roles.guard';
|
||||
import { Roles } from '../../auth/decorators/roles.decorator';
|
||||
import { GamilityRoleEnum } from '@/shared/constants';
|
||||
import { AssignmentsService } from '../services/assignments.service';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
@Controller('student/assignments')
|
||||
@ApiTags('Student Assignments')
|
||||
@ -74,7 +75,7 @@ export class StudentAssignmentsController {
|
||||
},
|
||||
})
|
||||
async getMyAssignments(@Query() query: any, @Request() req: AuthRequest) {
|
||||
const studentId = req.user?.userId || req.user?.sub;
|
||||
const studentId = req.user!.id;
|
||||
return this.assignmentsService.findStudentAssignments(studentId, {
|
||||
status: query.status,
|
||||
classroomId: query.classroomId,
|
||||
@ -105,7 +106,7 @@ export class StudentAssignmentsController {
|
||||
description: 'Tarea no encontrada o no asignada a este estudiante',
|
||||
})
|
||||
async getAssignmentDetails(@Param('id') id: string, @Request() req: AuthRequest) {
|
||||
const studentId = req.user?.userId || req.user?.sub;
|
||||
const studentId = req.user!.id;
|
||||
return this.assignmentsService.findStudentAssignmentById(id, studentId);
|
||||
}
|
||||
|
||||
@ -138,7 +139,7 @@ export class StudentAssignmentsController {
|
||||
},
|
||||
})
|
||||
async getGradesSummary(@Request() req: AuthRequest) {
|
||||
const studentId = req.user?.userId || req.user?.sub;
|
||||
const studentId = req.user!.id;
|
||||
return this.assignmentsService.getStudentGradesSummary(studentId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ import {
|
||||
UserSessionResponseDto,
|
||||
} from '../dto';
|
||||
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* AuthController
|
||||
@ -131,8 +132,8 @@ export class AuthController {
|
||||
@ApiResponse({ status: 401, description: 'No autenticado' })
|
||||
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';
|
||||
const userId = req.user!.id;
|
||||
const sessionId = req.user!.sessionId || 'current-session';
|
||||
|
||||
await this.authService.logout(userId, sessionId);
|
||||
return { message: 'Sesión cerrada exitosamente' };
|
||||
@ -177,7 +178,7 @@ export class AuthController {
|
||||
@ApiResponse({ status: 401, description: 'No autenticado' })
|
||||
async getProfile(@Request() req: AuthRequest): Promise<UserResponseDto> {
|
||||
// Extraer userId del token JWT
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
const user = await this.authService.validateUser(userId);
|
||||
|
||||
if (!user) {
|
||||
@ -210,7 +211,7 @@ export class AuthController {
|
||||
@Body() dto: UpdateProfileDto,
|
||||
): Promise<UserResponseDto> {
|
||||
// Extraer userId del token JWT
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
|
||||
// Actualizar perfil usando el servicio de auth
|
||||
const updatedUser = await this.authService.updateUserProfile(userId, dto);
|
||||
@ -344,7 +345,7 @@ export class AuthController {
|
||||
@Body('currentPassword') _currentPassword: string,
|
||||
@Body('newPassword') _newPassword: string,
|
||||
): Promise<{ message: string }> {
|
||||
const _userId = req.user?.id;
|
||||
const _userId = req.user!.id;
|
||||
// TODO: Implementar lógica de cambio de contraseña
|
||||
return { message: 'Contraseña cambiada exitosamente' };
|
||||
}
|
||||
@ -364,7 +365,7 @@ export class AuthController {
|
||||
})
|
||||
@ApiResponse({ status: 401, description: 'No autenticado' })
|
||||
async getSessions(@Request() req: AuthRequest): Promise<UserSessionResponseDto[]> {
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
return this.sessionService.getSessions(userId);
|
||||
}
|
||||
|
||||
@ -394,7 +395,7 @@ export class AuthController {
|
||||
@Request() req: AuthRequest,
|
||||
@Param('sessionId') sessionId: string,
|
||||
): Promise<{ message: string }> {
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
return this.sessionService.revokeSession(sessionId, userId);
|
||||
}
|
||||
|
||||
@ -421,8 +422,8 @@ export class AuthController {
|
||||
})
|
||||
@ApiResponse({ status: 401, description: 'No autenticado' })
|
||||
async revokeAllSessions(@Request() req: AuthRequest): Promise<{ message: string; count: number }> {
|
||||
const userId = req.user?.id;
|
||||
const currentSessionId = req.user?.sessionId || 'unknown';
|
||||
const userId = req.user!.id;
|
||||
const currentSessionId = req.user!.sessionId || 'unknown';
|
||||
return this.sessionService.revokeAllSessions(userId, currentSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ import {
|
||||
import { API_ROUTES, extractBasePath } from '@/shared/constants';
|
||||
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* PasswordController
|
||||
@ -144,7 +145,7 @@ export class PasswordController {
|
||||
@Body() dto: ChangePasswordDto,
|
||||
): Promise<{ message: string }> {
|
||||
// Extraer userId del token JWT
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
return this.authService.changePassword(
|
||||
userId,
|
||||
dto.current_password,
|
||||
@ -203,7 +204,7 @@ export class PasswordController {
|
||||
@ApiResponse({ status: 409, description: 'Email ya verificado' })
|
||||
async resendVerification(@Request() req: AuthRequest): Promise<{ message: string }> {
|
||||
// Extraer userId del token JWT
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
return this.emailVerificationService.resendVerification(userId);
|
||||
}
|
||||
|
||||
@ -228,7 +229,7 @@ export class PasswordController {
|
||||
@ApiResponse({ status: 401, description: 'No autenticado' })
|
||||
async checkVerificationStatus(@Request() req: AuthRequest): Promise<{ verified: boolean }> {
|
||||
// Extraer userId del token JWT
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
return this.emailVerificationService.checkVerificationStatus(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ import {
|
||||
UserResponseDto,
|
||||
} from '../dto';
|
||||
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* UsersController
|
||||
@ -60,7 +61,7 @@ export class UsersController {
|
||||
})
|
||||
@ApiResponse({ status: 401, description: 'No autenticado' })
|
||||
async getProfile(@Request() req: AuthRequest): Promise<UserResponseDto> {
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
const user = await this.authService.validateUser(userId);
|
||||
|
||||
if (!user) {
|
||||
@ -91,7 +92,7 @@ export class UsersController {
|
||||
@Request() req: AuthRequest,
|
||||
@Body() dto: UpdateProfileDto,
|
||||
): Promise<UserResponseDto> {
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
const updatedUser = await this.authService.updateUserProfile(userId, dto);
|
||||
|
||||
if (!updatedUser) {
|
||||
@ -120,7 +121,7 @@ export class UsersController {
|
||||
})
|
||||
@ApiResponse({ status: 401, description: 'No autenticado' })
|
||||
async getPreferences(@Request() req: AuthRequest): Promise<{ preferences: any }> {
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
const preferences = await this.authService.getUserPreferences(userId);
|
||||
return { preferences };
|
||||
}
|
||||
@ -154,7 +155,7 @@ export class UsersController {
|
||||
@Request() req: AuthRequest,
|
||||
@Body('preferences') preferences: any,
|
||||
): Promise<{ preferences: any }> {
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
const updatedPreferences = await this.authService.updateUserPreferences(
|
||||
userId,
|
||||
preferences,
|
||||
@ -197,7 +198,7 @@ export class UsersController {
|
||||
@Request() req: AuthRequest,
|
||||
@UploadedFile() file: any,
|
||||
): Promise<{ avatar_url: string }> {
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
|
||||
if (!file) {
|
||||
throw new UnauthorizedException('No se proporcionó archivo');
|
||||
@ -231,7 +232,7 @@ export class UsersController {
|
||||
})
|
||||
@ApiResponse({ status: 401, description: 'No autenticado' })
|
||||
async getStatistics(@Request() req: AuthRequest): Promise<any> {
|
||||
const userId = req.user?.id;
|
||||
const userId = req.user!.id;
|
||||
const statistics = await this.authService.getUserStatistics(userId);
|
||||
return statistics;
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ import { ExerciseSubmissionService, ExerciseAttemptService } from '@/modules/pro
|
||||
import { ExerciseAnswerValidator } from '@/modules/progress/dto/answers/exercise-answer.validator';
|
||||
import { JwtAuthGuard } from '@/modules/auth/guards/jwt-auth.guard';
|
||||
import { Profile } from '@/modules/auth/entities';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* ExercisesController
|
||||
@ -221,8 +222,8 @@ export class ExercisesController {
|
||||
description: 'Error interno del servidor',
|
||||
})
|
||||
async findAll(@Request() req: AuthRequest) {
|
||||
const userId = req.user.id;
|
||||
const userRole = req.user.role;
|
||||
const userId = req.user!.id;
|
||||
const userRole = req.user!.role;
|
||||
|
||||
// GAP-C06: Aplicar RLS según el rol del usuario
|
||||
let exercises: any[];
|
||||
@ -373,7 +374,7 @@ export class ExercisesController {
|
||||
},
|
||||
})
|
||||
async findOne(@Param('id') id: string, @Request() req: AuthRequest) {
|
||||
const userId = req.user.id;
|
||||
const userId = req.user!.id;
|
||||
|
||||
// Obtener ejercicio
|
||||
const exercise = await this.exercisesService.findById(id);
|
||||
@ -676,7 +677,7 @@ export class ExercisesController {
|
||||
const exercises = await this.exercisesService.findByModuleId(moduleId);
|
||||
|
||||
// FIX 2025-11-29: Convert auth.users.id → profiles.id
|
||||
const userId = req.user.id;
|
||||
const userId = req.user!.id;
|
||||
const profileId = await this.getProfileId(userId);
|
||||
|
||||
// Obtener todas las submissions del usuario de una sola vez para eficiencia
|
||||
|
||||
@ -18,6 +18,7 @@ import { UploadMediaDto } from '../dto/upload-media.dto';
|
||||
import { MediaAttachment } from '../entities/media-attachment.entity';
|
||||
import { JwtAuthGuard } from '@modules/auth/guards/jwt-auth.guard';
|
||||
import { Response } from 'express';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* Controller para gestión de archivos multimedia
|
||||
@ -84,7 +85,7 @@ export class MediaUploadController {
|
||||
@UploadedFile() file: any,
|
||||
@Body() dto: UploadMediaDto,
|
||||
): Promise<MediaAttachment> {
|
||||
const userId = req.user.profileId;
|
||||
const userId = req.user!.profile?.id || req.user!.id;
|
||||
return this.mediaService.uploadFile(file, userId, dto);
|
||||
}
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ import { CreateModuleDto, ModuleResponseDto, GetModulesQueryDto } from '../dto';
|
||||
import { API_ROUTES, extractBasePath } from '@/shared/constants';
|
||||
import { DifficultyLevelEnum } from '@/shared/constants/enums.constants';
|
||||
import { JwtAuthGuard } from '@/modules/auth/guards/jwt-auth.guard';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* ModulesController
|
||||
@ -111,7 +112,7 @@ export class ModulesController {
|
||||
description: 'Error interno del servidor',
|
||||
})
|
||||
async findAll(@Request() req: AuthRequest, @Query() query: GetModulesQueryDto) {
|
||||
const userId = req.user.id;
|
||||
const userId = req.user!.id;
|
||||
// Reutilizar getUserModules que ya tiene la lógica correcta para ambas tablas
|
||||
// Ahora acepta classroomId opcional para filtrar
|
||||
return this.modulesService.getUserModules(userId, query.classroomId);
|
||||
|
||||
@ -173,7 +173,7 @@ export class ExercisesService {
|
||||
this.validateContentByExerciseType(exerciseType, content, config);
|
||||
}
|
||||
|
||||
await this.exerciseRepo.update(id, exerciseData);
|
||||
await this.exerciseRepo.update(id, exerciseData as any);
|
||||
const updated = await this.findById(id);
|
||||
if (!updated) {
|
||||
throw new NotFoundException(`Exercise with ID ${id} not found after update`);
|
||||
@ -230,8 +230,9 @@ export class ExercisesService {
|
||||
}
|
||||
|
||||
// Validar que grid tenga dimensiones correctas
|
||||
const rows = config?.gridSize?.rows || 0;
|
||||
const cols = config?.gridSize?.cols || 0;
|
||||
const gridSize = config?.gridSize as { rows?: number; cols?: number } | undefined;
|
||||
const rows = gridSize?.rows || 0;
|
||||
const cols = gridSize?.cols || 0;
|
||||
|
||||
if (content.grid.length !== rows) {
|
||||
throw new BadRequestException(
|
||||
@ -526,11 +527,13 @@ export class ExercisesService {
|
||||
}
|
||||
|
||||
// ✅ FE-060: Use config.gridSize directly (passed as parameter)
|
||||
const gridSize = config?.gridSize || { rows: 15, cols: 15 };
|
||||
const gridSizeRaw = config?.gridSize as { rows?: number; cols?: number } | undefined;
|
||||
const gridSize = gridSizeRaw || { rows: 15, cols: 15 };
|
||||
const cluesArray = (sanitized.clues || []) as Array<{ startRow: number; startCol: number; direction: string; length: number; number?: number }>;
|
||||
sanitized.grid = this.generateEmptyGrid(
|
||||
gridSize.rows || 15,
|
||||
gridSize.cols || 15,
|
||||
sanitized.clues || [],
|
||||
cluesArray,
|
||||
);
|
||||
sanitized.gridConfig = gridSize;
|
||||
|
||||
@ -539,11 +542,11 @@ export class ExercisesService {
|
||||
hasConfig: !!config,
|
||||
gridSizeFromConfig: config?.gridSize,
|
||||
gridSizeUsed: gridSize,
|
||||
gridGenerated: `${gridSize.rows}x${gridSize.cols}`,
|
||||
gridGenerated: `${gridSize.rows || 15}x${gridSize.cols || 15}`,
|
||||
hasGrid: !!sanitized.grid,
|
||||
gridIsArray: Array.isArray(sanitized.grid),
|
||||
gridDimensions: sanitized.grid?.length ? `${sanitized.grid.length}x${sanitized.grid[0]?.length}` : 'N/A',
|
||||
cluesCount: sanitized.clues?.length,
|
||||
gridDimensions: sanitized.grid?.length ? `${(sanitized.grid as unknown[]).length}x${(sanitized.grid as unknown[][])[0]?.length}` : 'N/A',
|
||||
cluesCount: cluesArray.length,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ export class MediaService {
|
||||
throw new NotFoundException(`Media resource with ID ${id} not found`);
|
||||
}
|
||||
|
||||
await this.mediaRepo.update(id, mediaData);
|
||||
await this.mediaRepo.update(id, mediaData as any);
|
||||
const updated = await this.findById(id);
|
||||
if (!updated) {
|
||||
throw new NotFoundException(`Media resource with ID ${id} not found after update`);
|
||||
@ -107,7 +107,7 @@ export class MediaService {
|
||||
};
|
||||
}
|
||||
|
||||
await this.mediaRepo.update(id, updateData);
|
||||
await this.mediaRepo.update(id, updateData as any);
|
||||
const updated = await this.findById(id);
|
||||
if (!updated) {
|
||||
throw new NotFoundException(`Media resource with ID ${id} not found after update`);
|
||||
|
||||
@ -57,7 +57,7 @@ export class ModulesService {
|
||||
* Actualizar un módulo existente
|
||||
*/
|
||||
async update(id: string, moduleData: Partial<Module>): Promise<Module | null> {
|
||||
await this.moduleRepo.update(id, moduleData);
|
||||
await this.moduleRepo.update(id, moduleData as any);
|
||||
return this.findById(id);
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ import { ClassroomMissionsService } from '../services/classroom-missions.service
|
||||
import { AssignClassroomMissionDto } from '../dto/missions/assign-classroom-mission.dto';
|
||||
import { ClassroomMissionResponseDto } from '../dto/missions/classroom-mission-response.dto';
|
||||
import { JwtAuthGuard } from '@/modules/auth/guards';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* ClassroomMissionsController
|
||||
@ -143,7 +144,7 @@ export class ClassroomMissionsController {
|
||||
@Body() dto: AssignClassroomMissionDto,
|
||||
@Request() req: AuthRequest,
|
||||
) {
|
||||
const teacherId = req.user.id;
|
||||
const teacherId = req.user!.id;
|
||||
return this.classroomMissionsService.assignMissionToClassroom(classroomId, teacherId, dto);
|
||||
}
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
} from '../dto/mission-templates';
|
||||
import { JwtAuthGuard } from '@/modules/auth/guards';
|
||||
import { AdminGuard } from '@/modules/admin/guards/admin.guard';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* MissionTemplatesController
|
||||
@ -205,7 +206,7 @@ export class MissionTemplatesController {
|
||||
description: 'Datos inválidos',
|
||||
})
|
||||
async create(@Body() dto: CreateMissionTemplateDto, @Request() req: AuthRequest) {
|
||||
const createdBy = req.user.id;
|
||||
const createdBy = req.user!.id;
|
||||
return this.templatesService.create(dto, createdBy);
|
||||
}
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ import { MissionResponseDto } from '../dto/missions/mission-response.dto';
|
||||
import { MissionStatsDto } from '../dto/missions/mission-stats.dto';
|
||||
import { UpdateMissionProgressDto } from '../dto/missions/update-mission-progress.dto';
|
||||
import { JwtAuthGuard } from '@/modules/auth/guards';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* MissionsController
|
||||
@ -111,7 +112,7 @@ export class MissionsController {
|
||||
description: 'No autenticado - Token JWT inválido o ausente',
|
||||
})
|
||||
async getDailyMissions(@Request() req: AuthRequest) {
|
||||
const userId = req.user.id;
|
||||
const userId = req.user!.id;
|
||||
return this.missionsService.findByTypeAndUser(userId, MissionTypeEnum.DAILY);
|
||||
}
|
||||
|
||||
@ -180,7 +181,7 @@ export class MissionsController {
|
||||
description: 'No autenticado - Token JWT inválido o ausente',
|
||||
})
|
||||
async getWeeklyMissions(@Request() req: AuthRequest) {
|
||||
const userId = req.user.id;
|
||||
const userId = req.user!.id;
|
||||
return this.missionsService.findByTypeAndUser(userId, MissionTypeEnum.WEEKLY);
|
||||
}
|
||||
|
||||
@ -235,7 +236,7 @@ export class MissionsController {
|
||||
description: 'No autenticado - Token JWT inválido o ausente',
|
||||
})
|
||||
async getSpecialMissions(@Request() req: AuthRequest) {
|
||||
const userId = req.user.id;
|
||||
const userId = req.user!.id;
|
||||
return this.missionsService.findByTypeAndUser(userId, MissionTypeEnum.SPECIAL);
|
||||
}
|
||||
|
||||
@ -299,7 +300,7 @@ export class MissionsController {
|
||||
})
|
||||
async getStats(@Param('userId') userId: string, @Request() req: AuthRequest) {
|
||||
// Validar que el userId coincide con el usuario autenticado
|
||||
if (userId !== req.user.id) {
|
||||
if (userId !== req.user!.id) {
|
||||
throw new HttpException('Forbidden: Cannot access stats of another user', HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@ -361,7 +362,7 @@ export class MissionsController {
|
||||
description: 'Misión no encontrada',
|
||||
})
|
||||
async startMission(@Param('id') missionId: string, @Request() req: AuthRequest) {
|
||||
const userId = req.user.id;
|
||||
const userId = req.user!.id;
|
||||
return this.missionsService.startMission(missionId, userId);
|
||||
}
|
||||
|
||||
@ -449,7 +450,7 @@ export class MissionsController {
|
||||
@Body() dto: UpdateMissionProgressDto,
|
||||
@Request() req: AuthRequest,
|
||||
) {
|
||||
const userId = req.user.id;
|
||||
const userId = req.user!.id;
|
||||
return this.missionsService.updateProgress(
|
||||
missionId,
|
||||
userId,
|
||||
@ -567,7 +568,7 @@ export class MissionsController {
|
||||
description: 'Misión no encontrada',
|
||||
})
|
||||
async claimRewards(@Param('id') missionId: string, @Request() req: AuthRequest) {
|
||||
const userId = req.user.id;
|
||||
const userId = req.user!.id;
|
||||
const result = await this.missionsService.claimRewards(missionId, userId);
|
||||
return { success: true, data: result };
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ import { JwtAuthGuard } from '@modules/auth/guards/jwt-auth.guard';
|
||||
import { RolesGuard } from '@shared/guards/roles.guard';
|
||||
import { Roles } from '@shared/decorators/roles.decorator';
|
||||
import { UserRank } from '../entities';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* RankMetadataDto
|
||||
@ -111,7 +112,7 @@ export class RanksController {
|
||||
@ApiResponse({ status: 401, description: 'No autenticado' })
|
||||
@ApiResponse({ status: 404, description: 'Usuario sin rango inicializado' })
|
||||
async getCurrentRank(@Request() req: AuthRequest): Promise<UserRank> {
|
||||
const userId = req.user.sub;
|
||||
const userId = req.user!.id;
|
||||
return this.ranksService.getCurrentRank(userId);
|
||||
}
|
||||
|
||||
|
||||
@ -287,23 +287,25 @@ export class UserStatsController {
|
||||
const stats = await this.userStatsService.findByUserId(userId);
|
||||
|
||||
// Handle total_xp_increment
|
||||
if (updateData.total_xp_increment !== undefined) {
|
||||
const newXP = stats.total_xp + updateData.total_xp_increment;
|
||||
updateData.total_xp = newXP;
|
||||
if (updateData.total_xp_increment !== undefined && updateData.total_xp_increment !== null) {
|
||||
const increment = Number(updateData.total_xp_increment) || 0;
|
||||
updateData.total_xp = stats.total_xp + increment;
|
||||
delete updateData.total_xp_increment;
|
||||
}
|
||||
|
||||
// Handle ml_coins_increment
|
||||
if (updateData.ml_coins_increment !== undefined) {
|
||||
updateData.ml_coins = stats.ml_coins + updateData.ml_coins_increment;
|
||||
updateData.ml_coins_earned_total = stats.ml_coins_earned_total + updateData.ml_coins_increment;
|
||||
if (updateData.ml_coins_increment !== undefined && updateData.ml_coins_increment !== null) {
|
||||
const increment = Number(updateData.ml_coins_increment) || 0;
|
||||
updateData.ml_coins = stats.ml_coins + increment;
|
||||
updateData.ml_coins_earned_total = stats.ml_coins_earned_total + increment;
|
||||
delete updateData.ml_coins_increment;
|
||||
}
|
||||
|
||||
// Handle ml_coins_decrement
|
||||
if (updateData.ml_coins_decrement !== undefined) {
|
||||
updateData.ml_coins = stats.ml_coins - updateData.ml_coins_decrement;
|
||||
updateData.ml_coins_spent_total = stats.ml_coins_spent_total + updateData.ml_coins_decrement;
|
||||
if (updateData.ml_coins_decrement !== undefined && updateData.ml_coins_decrement !== null) {
|
||||
const decrement = Number(updateData.ml_coins_decrement) || 0;
|
||||
updateData.ml_coins = stats.ml_coins - decrement;
|
||||
updateData.ml_coins_spent_total = stats.ml_coins_spent_total + decrement;
|
||||
delete updateData.ml_coins_decrement;
|
||||
}
|
||||
|
||||
|
||||
@ -228,8 +228,9 @@ export class AchievementsService {
|
||||
const grantDto = new GrantAchievementDto();
|
||||
grantDto.user_id = userId;
|
||||
grantDto.achievement_id = achievement.id;
|
||||
grantDto.progress = achievement.conditions.progress || achievement.conditions.max_progress || 100;
|
||||
grantDto.max_progress = achievement.conditions.max_progress || 100;
|
||||
const conditionsTyped = achievement.conditions as { progress?: number; max_progress?: number };
|
||||
grantDto.progress = conditionsTyped.progress || conditionsTyped.max_progress || 100;
|
||||
grantDto.max_progress = conditionsTyped.max_progress || 100;
|
||||
grantDto.is_completed = true;
|
||||
grantDto.progress_data = { auto_detected: true };
|
||||
|
||||
@ -245,32 +246,44 @@ export class AchievementsService {
|
||||
* Evalúa si las estadísticas del usuario cumplen con las condiciones del logro
|
||||
*/
|
||||
private meetsConditions(userStats: UserStats, conditions: Record<string, unknown>): boolean {
|
||||
const type = conditions.type || 'generic';
|
||||
// Type cast for accessing condition properties
|
||||
const cond = conditions as {
|
||||
type?: string;
|
||||
exercises_completed?: number;
|
||||
modules_completed?: number;
|
||||
min_streak?: number;
|
||||
min_level?: number;
|
||||
min_average_score?: number;
|
||||
min_perfect_scores?: number;
|
||||
target_rank?: string;
|
||||
min_coins_earned?: number;
|
||||
};
|
||||
const type = cond.type || 'generic';
|
||||
|
||||
switch (type) {
|
||||
case 'progress':
|
||||
return (
|
||||
userStats.exercises_completed >= (conditions.exercises_completed || 0) &&
|
||||
userStats.modules_completed >= (conditions.modules_completed || 0)
|
||||
userStats.exercises_completed >= (cond.exercises_completed || 0) &&
|
||||
userStats.modules_completed >= (cond.modules_completed || 0)
|
||||
);
|
||||
|
||||
case 'streak':
|
||||
return userStats.current_streak >= (conditions.min_streak || 0);
|
||||
return userStats.current_streak >= (cond.min_streak || 0);
|
||||
|
||||
case 'level':
|
||||
return userStats.level >= (conditions.min_level || 0);
|
||||
return userStats.level >= (cond.min_level || 0);
|
||||
|
||||
case 'score':
|
||||
return (
|
||||
(userStats.average_score || 0) >= (conditions.min_average_score || 0) &&
|
||||
userStats.perfect_scores >= (conditions.min_perfect_scores || 0)
|
||||
(userStats.average_score || 0) >= (cond.min_average_score || 0) &&
|
||||
userStats.perfect_scores >= (cond.min_perfect_scores || 0)
|
||||
);
|
||||
|
||||
case 'rank':
|
||||
return this.userReachedRank(userStats.current_rank, conditions.target_rank);
|
||||
return this.userReachedRank(userStats.current_rank, cond.target_rank || '');
|
||||
|
||||
case 'ml_coins':
|
||||
return userStats.ml_coins_earned_total >= (conditions.min_coins_earned || 0);
|
||||
return userStats.ml_coins_earned_total >= (cond.min_coins_earned || 0);
|
||||
|
||||
default:
|
||||
return false;
|
||||
|
||||
@ -108,16 +108,14 @@ export class MissionClaimService {
|
||||
const mlCoinsReward = mission.rewards?.ml_coins || 0;
|
||||
if (mlCoinsReward > 0) {
|
||||
try {
|
||||
await this.mlCoinsService.addTransaction({
|
||||
user_id: profileId,
|
||||
amount: mlCoinsReward,
|
||||
type: TransactionTypeEnum.REWARD,
|
||||
description: `Mission completed: ${mission.title}`,
|
||||
metadata: {
|
||||
mission_id: mission.id,
|
||||
mission_type: mission.mission_type,
|
||||
},
|
||||
});
|
||||
await this.mlCoinsService.addCoins(
|
||||
profileId,
|
||||
mlCoinsReward,
|
||||
TransactionTypeEnum.EARNED_BONUS,
|
||||
`Mission completed: ${mission.title}`,
|
||||
mission.id,
|
||||
'mission',
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to add ML Coins for mission ${missionId}: ${error}`,
|
||||
@ -132,7 +130,7 @@ export class MissionClaimService {
|
||||
|
||||
if (xpReward > 0) {
|
||||
try {
|
||||
const statsUpdate = await this.userStatsService.addXP(profileId, xpReward);
|
||||
const statsUpdate = await this.userStatsService.addXp(profileId, xpReward);
|
||||
|
||||
if (statsUpdate.rankUp) {
|
||||
rankUp = {
|
||||
|
||||
@ -27,7 +27,7 @@ import {
|
||||
MissionObjective,
|
||||
MissionRewards,
|
||||
} from '../../entities/mission.entity';
|
||||
import { MissionTemplate } from '../../entities/mission-template.entity';
|
||||
import { MissionTemplate, MissionTemplateTypeEnum } from '../../entities/mission-template.entity';
|
||||
import { MissionTemplatesService } from '../mission-templates.service';
|
||||
|
||||
/**
|
||||
@ -67,8 +67,8 @@ export class MissionGeneratorService {
|
||||
await this.expireMissions(profileId, MissionTypeEnum.DAILY);
|
||||
|
||||
// Get available templates for user's level
|
||||
const templates = await this.templatesService.getActiveByTypeAndLevel(
|
||||
'daily',
|
||||
const templates = await this.templatesService.getActiveByType(
|
||||
'daily' as MissionTemplateTypeEnum,
|
||||
userLevel,
|
||||
);
|
||||
|
||||
@ -116,8 +116,8 @@ export class MissionGeneratorService {
|
||||
await this.expireMissions(profileId, MissionTypeEnum.WEEKLY);
|
||||
|
||||
// Get available weekly templates
|
||||
const templates = await this.templatesService.getActiveByTypeAndLevel(
|
||||
'weekly',
|
||||
const templates = await this.templatesService.getActiveByType(
|
||||
'weekly' as MissionTemplateTypeEnum,
|
||||
userLevel,
|
||||
);
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@ import {
|
||||
DeviceResponseDto,
|
||||
DevicesListResponseDto,
|
||||
} from '../dto/devices';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* NotificationDevicesController
|
||||
@ -146,7 +147,7 @@ export class NotificationDevicesController {
|
||||
@Body() registerDto: RegisterDeviceDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<DeviceResponseDto> {
|
||||
const userId = req.user.sub;
|
||||
const userId = req.user!.id;
|
||||
|
||||
const device = await this.deviceService.registerDevice({
|
||||
userId,
|
||||
@ -186,7 +187,7 @@ export class NotificationDevicesController {
|
||||
description: 'No autenticado',
|
||||
})
|
||||
async getUserDevices(@Request() req: AuthRequest): Promise<DevicesListResponseDto> {
|
||||
const userId = req.user.sub;
|
||||
const userId = req.user!.id;
|
||||
const devices = await this.deviceService.getUserDevices(userId, false);
|
||||
|
||||
// Ocultar parcialmente los tokens
|
||||
@ -236,7 +237,7 @@ export class NotificationDevicesController {
|
||||
@Param('id') deviceId: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<DeviceResponseDto> {
|
||||
const userId = req.user.sub;
|
||||
const userId = req.user!.id;
|
||||
const device = await this.deviceService.getDeviceById(deviceId, userId);
|
||||
|
||||
return {
|
||||
@ -288,7 +289,7 @@ export class NotificationDevicesController {
|
||||
@Body() updateDto: UpdateDeviceNameDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<DeviceResponseDto> {
|
||||
const userId = req.user.sub;
|
||||
const userId = req.user!.id;
|
||||
|
||||
const device = await this.deviceService.updateDeviceName(
|
||||
deviceId,
|
||||
@ -347,7 +348,7 @@ export class NotificationDevicesController {
|
||||
@Param('id') deviceId: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<void> {
|
||||
const userId = req.user.sub;
|
||||
const userId = req.user!.id;
|
||||
await this.deviceService.deleteDevice(deviceId, userId);
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
SendFromTemplateDto,
|
||||
NotificationResponseDto,
|
||||
} from '../dto/notifications';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* NotificationMultiChannelController
|
||||
@ -111,7 +112,7 @@ export class NotificationMultiChannelController {
|
||||
): Promise<NotificationResponseDto> {
|
||||
// Validar que el usuario solo crea notificaciones para sí mismo
|
||||
// (a menos que sea admin - validación futura)
|
||||
if (createDto.userId !== req.user.sub) {
|
||||
if (createDto.userId !== req.user!.id) {
|
||||
// TODO: Permitir si es admin
|
||||
throw new Error('Cannot create notifications for other users');
|
||||
}
|
||||
@ -195,7 +196,7 @@ export class NotificationMultiChannelController {
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<NotificationResponseDto> {
|
||||
// Validar ownership
|
||||
if (sendDto.userId !== req.user.sub) {
|
||||
if (sendDto.userId !== req.user!.id) {
|
||||
// TODO: Permitir si es admin
|
||||
throw new Error('Cannot create notifications for other users');
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ import {
|
||||
PreferenceResponseDto,
|
||||
PreferencesListResponseDto,
|
||||
} from '../dto/preferences';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* NotificationPreferencesController
|
||||
@ -84,7 +85,7 @@ export class NotificationPreferencesController {
|
||||
async getUserPreferences(
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<PreferencesListResponseDto> {
|
||||
const userId = req.user.sub;
|
||||
const userId = req.user!.id;
|
||||
const preferences = await this.preferenceService.getUserPreferences(userId);
|
||||
|
||||
return {
|
||||
@ -130,7 +131,7 @@ export class NotificationPreferencesController {
|
||||
@Body() updateDto: UpdatePreferenceDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<PreferenceResponseDto> {
|
||||
const userId = req.user.sub;
|
||||
const userId = req.user!.id;
|
||||
|
||||
const preference = await this.preferenceService.updatePreference(
|
||||
userId,
|
||||
@ -177,7 +178,7 @@ export class NotificationPreferencesController {
|
||||
@Body() updateDto: UpdateMultiplePreferencesDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<PreferencesListResponseDto> {
|
||||
const userId = req.user.sub;
|
||||
const userId = req.user!.id;
|
||||
|
||||
const preferences = await this.preferenceService.updateMultiple(
|
||||
userId,
|
||||
|
||||
@ -32,6 +32,7 @@ import { JwtAuthGuard } from '@/modules/auth/guards/jwt-auth.guard';
|
||||
import { RolesGuard } from '@/shared/guards/roles.guard';
|
||||
import { Roles } from '@/shared/decorators/roles.decorator';
|
||||
import { GamilityRoleEnum } from '@/shared/constants/enums.constants';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* ExerciseSubmissionController
|
||||
|
||||
@ -31,6 +31,7 @@ import {
|
||||
AttemptDetailDto,
|
||||
AttemptsListResponseDto,
|
||||
} from '../dto/exercise-responses.dto';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* Controller for Teacher Exercise Responses
|
||||
|
||||
@ -17,6 +17,7 @@ import { JwtAuthGuard } from '@modules/auth/guards/jwt-auth.guard';
|
||||
import { RolesGuard } from '@modules/auth/guards/roles.guard';
|
||||
import { Roles } from '@modules/auth/decorators/roles.decorator';
|
||||
import { GamilityRoleEnum } from '@shared/constants/enums.constants';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
|
||||
/**
|
||||
* Controller para gestión de evaluaciones manuales (ManualReview)
|
||||
@ -114,7 +115,10 @@ export class ManualReviewController {
|
||||
@Request() req: AuthRequest,
|
||||
@Body() dto: CreateReviewDto,
|
||||
): Promise<ManualReview> {
|
||||
const teacherId = req.user.profileId;
|
||||
const teacherId = req.user?.profile?.id || req.user?.sub || req.user?.id;
|
||||
if (!teacherId) {
|
||||
throw new Error('Teacher ID not found in request');
|
||||
}
|
||||
return this.reviewService.createReview(teacherId, dto);
|
||||
}
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@ import {
|
||||
UpdatePermissionsDto,
|
||||
StudentPermissionsResponseDto,
|
||||
} from '../dto/student-blocking';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
import {
|
||||
CreateTeacherClassroomDto,
|
||||
UpdateTeacherClassroomDto,
|
||||
@ -119,7 +120,7 @@ export class TeacherClassroomsController {
|
||||
@Query() query: GetClassroomsQueryDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<PaginatedTeacherClassroomsResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.classroomsCrudService.getClassrooms(teacherId, query);
|
||||
}
|
||||
|
||||
@ -154,7 +155,7 @@ export class TeacherClassroomsController {
|
||||
@Body() dto: CreateTeacherClassroomDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<TeacherClassroomResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.classroomsCrudService.createClassroom(teacherId, dto);
|
||||
}
|
||||
|
||||
@ -194,7 +195,7 @@ export class TeacherClassroomsController {
|
||||
@Param('id') id: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<TeacherClassroomDetailResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.classroomsCrudService.getClassroomById(id, teacherId);
|
||||
}
|
||||
|
||||
@ -240,7 +241,7 @@ export class TeacherClassroomsController {
|
||||
@Body() dto: UpdateTeacherClassroomDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<TeacherClassroomResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.classroomsCrudService.updateClassroom(id, teacherId, dto);
|
||||
}
|
||||
|
||||
@ -289,7 +290,7 @@ export class TeacherClassroomsController {
|
||||
@Param('id') id: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<{ success: boolean; message: string }> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.classroomsCrudService.deleteClassroom(id, teacherId);
|
||||
}
|
||||
|
||||
@ -345,7 +346,7 @@ export class TeacherClassroomsController {
|
||||
@Query() query: GetClassroomStudentsQueryDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<PaginatedStudentsResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.classroomsCrudService.getClassroomStudents(id, teacherId, query);
|
||||
}
|
||||
|
||||
@ -385,7 +386,7 @@ export class TeacherClassroomsController {
|
||||
@Param('id') id: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<ClassroomStatsDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.classroomsCrudService.getClassroomStats(id, teacherId);
|
||||
}
|
||||
|
||||
@ -425,7 +426,7 @@ export class TeacherClassroomsController {
|
||||
@Param('classroomId') classroomId: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<TeacherInClassroomDto[]> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.classroomsCrudService.getClassroomTeachers(classroomId, teacherId);
|
||||
}
|
||||
|
||||
@ -490,7 +491,7 @@ export class TeacherClassroomsController {
|
||||
@Param('id') id: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<any> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.classroomsCrudService.getClassroomProgress(id, teacherId);
|
||||
}
|
||||
|
||||
@ -546,7 +547,7 @@ export class TeacherClassroomsController {
|
||||
@Body() dto: BlockStudentDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<StudentPermissionsResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.studentBlockingService.blockStudent(
|
||||
classroomId,
|
||||
studentId,
|
||||
@ -601,7 +602,7 @@ export class TeacherClassroomsController {
|
||||
@Param('studentId') studentId: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<StudentPermissionsResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.studentBlockingService.unblockStudent(
|
||||
classroomId,
|
||||
studentId,
|
||||
@ -651,7 +652,7 @@ export class TeacherClassroomsController {
|
||||
@Param('studentId') studentId: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<StudentPermissionsResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.studentBlockingService.getStudentPermissions(
|
||||
classroomId,
|
||||
studentId,
|
||||
@ -707,7 +708,7 @@ export class TeacherClassroomsController {
|
||||
@Body() dto: UpdatePermissionsDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<StudentPermissionsResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.studentBlockingService.updateStudentPermissions(
|
||||
classroomId,
|
||||
studentId,
|
||||
|
||||
@ -29,6 +29,7 @@ import {
|
||||
import { JwtAuthGuard } from '@modules/auth/guards/jwt-auth.guard';
|
||||
import { TeacherGuard } from '../guards';
|
||||
import { TeacherContentService } from '../services/teacher-content.service';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
import {
|
||||
CreateTeacherContentDto,
|
||||
UpdateTeacherContentDto,
|
||||
@ -115,7 +116,7 @@ export class TeacherContentController {
|
||||
@Query() query: GetTeacherContentQueryDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<PaginatedTeacherContentResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.contentService.findAll(teacherId, query);
|
||||
}
|
||||
|
||||
@ -152,7 +153,7 @@ export class TeacherContentController {
|
||||
description: 'Forbidden - Teacher is not the owner of this content',
|
||||
})
|
||||
async findOne(@Param('id') id: string, @Request() req: AuthRequest): Promise<TeacherContentResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.contentService.findOne(id, teacherId);
|
||||
}
|
||||
|
||||
@ -195,7 +196,7 @@ export class TeacherContentController {
|
||||
@Body() dto: CreateTeacherContentDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<TeacherContentResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.contentService.create(teacherId, dto);
|
||||
}
|
||||
|
||||
@ -245,7 +246,7 @@ export class TeacherContentController {
|
||||
@Body() dto: UpdateTeacherContentDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<TeacherContentResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.contentService.update(id, teacherId, dto);
|
||||
}
|
||||
|
||||
@ -294,7 +295,7 @@ export class TeacherContentController {
|
||||
@Param('id') id: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<{ success: boolean; message: string }> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.contentService.delete(id, teacherId);
|
||||
}
|
||||
|
||||
@ -340,7 +341,7 @@ export class TeacherContentController {
|
||||
@Body() dto: CloneTeacherContentDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<TeacherContentResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.contentService.clone(id, teacherId, dto);
|
||||
}
|
||||
|
||||
@ -388,7 +389,7 @@ export class TeacherContentController {
|
||||
@Param('id') id: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<TeacherContentResponseDto> {
|
||||
const teacherId = req.user.sub;
|
||||
const teacherId = req.user!.id;
|
||||
return this.contentService.publish(id, teacherId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ import { JwtAuthGuard } from '@/modules/auth/guards/jwt-auth.guard';
|
||||
import { RolesGuard } from '@/modules/auth/guards/roles.guard';
|
||||
import { Roles } from '@/modules/auth/decorators/roles.decorator';
|
||||
import { GamilityRoleEnum } from '@/shared/constants/enums.constants';
|
||||
import { AuthRequest } from '@shared/types';
|
||||
import {
|
||||
TeacherDashboardService,
|
||||
StudentProgressService,
|
||||
@ -80,14 +81,14 @@ export class TeacherController {
|
||||
@Get('dashboard/stats')
|
||||
@ApiOperation({ summary: 'Get classroom statistics' })
|
||||
async getClassroomStats(@Request() req: AuthRequest) {
|
||||
const teacherId = req.user.id;
|
||||
const teacherId = req.user!.id;
|
||||
return this.dashboardService.getClassroomStats(teacherId);
|
||||
}
|
||||
|
||||
@Get('dashboard/activities')
|
||||
@ApiOperation({ summary: 'Get recent activities' })
|
||||
async getRecentActivities(@Request() req: AuthRequest, @Query('limit') limit?: number) {
|
||||
const teacherId = req.user.id;
|
||||
const teacherId = req.user!.id;
|
||||
return this.dashboardService.getRecentActivities(
|
||||
teacherId,
|
||||
limit ? parseInt(limit as any) : 10,
|
||||
@ -97,14 +98,14 @@ export class TeacherController {
|
||||
@Get('dashboard/alerts')
|
||||
@ApiOperation({ summary: 'Get student alerts' })
|
||||
async getStudentAlerts(@Request() req: AuthRequest) {
|
||||
const teacherId = req.user.id;
|
||||
const teacherId = req.user!.id;
|
||||
return this.dashboardService.getStudentAlerts(teacherId);
|
||||
}
|
||||
|
||||
@Get('dashboard/top-performers')
|
||||
@ApiOperation({ summary: 'Get top performing students' })
|
||||
async getTopPerformers(@Request() req: AuthRequest, @Query('limit') limit?: number) {
|
||||
const teacherId = req.user.id;
|
||||
const teacherId = req.user!.id;
|
||||
return this.dashboardService.getTopPerformers(
|
||||
teacherId,
|
||||
limit ? parseInt(limit as any) : 5,
|
||||
@ -114,7 +115,7 @@ export class TeacherController {
|
||||
@Get('dashboard/module-progress')
|
||||
@ApiOperation({ summary: 'Get module progress summary' })
|
||||
async getModuleProgressSummary(@Request() req: AuthRequest) {
|
||||
const teacherId = req.user.id;
|
||||
const teacherId = req.user!.id;
|
||||
return this.dashboardService.getModuleProgressSummary(teacherId);
|
||||
}
|
||||
|
||||
@ -152,7 +153,7 @@ export class TeacherController {
|
||||
@Param('studentId') studentId: string,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<StudentNoteResponseDto[]> {
|
||||
const teacherId = req.user.profile.id;
|
||||
const teacherId = req.user!.profile!.id;
|
||||
return this.studentProgressService.getStudentNotes(studentId, teacherId);
|
||||
}
|
||||
|
||||
@ -166,7 +167,7 @@ export class TeacherController {
|
||||
@Body() noteDto: AddTeacherNoteDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<StudentNoteResponseDto> {
|
||||
const teacherId = req.user.profile.id;
|
||||
const teacherId = req.user!.profile!.id;
|
||||
return this.studentProgressService.addStudentNote(
|
||||
studentId,
|
||||
teacherId,
|
||||
@ -266,7 +267,7 @@ export class TeacherController {
|
||||
@Request() req: AuthRequest,
|
||||
@Query() query: GetEngagementMetricsDto,
|
||||
) {
|
||||
const teacherId = req.user.profile.id;
|
||||
const teacherId = req.user!.profile!.id;
|
||||
return this.analyticsService.getEngagementMetrics(teacherId, query);
|
||||
}
|
||||
|
||||
@ -280,7 +281,7 @@ export class TeacherController {
|
||||
@Request() req: AuthRequest,
|
||||
@Query() query: GenerateReportsDto,
|
||||
) {
|
||||
const teacherId = req.user.profile.id;
|
||||
const teacherId = req.user!.profile!.id;
|
||||
return this.analyticsService.generateReports(teacherId, query);
|
||||
}
|
||||
|
||||
@ -301,7 +302,7 @@ export class TeacherController {
|
||||
@Request() req: AuthRequest,
|
||||
@Query('classroom_id') classroomId?: string,
|
||||
): Promise<EconomyAnalyticsDto> {
|
||||
const teacherId = req.user.profile.id;
|
||||
const teacherId = req.user!.profile!.id;
|
||||
return this.analyticsService.getEconomyAnalytics(teacherId, classroomId);
|
||||
}
|
||||
|
||||
@ -322,7 +323,7 @@ export class TeacherController {
|
||||
@Request() req: AuthRequest,
|
||||
@Query('classroom_id') classroomId?: string,
|
||||
): Promise<StudentsEconomyResponseDto> {
|
||||
const teacherId = req.user.profile.id;
|
||||
const teacherId = req.user!.profile!.id;
|
||||
return this.analyticsService.getStudentsEconomy(teacherId, classroomId);
|
||||
}
|
||||
|
||||
@ -343,7 +344,7 @@ export class TeacherController {
|
||||
@Request() req: AuthRequest,
|
||||
@Query('classroom_id') classroomId?: string,
|
||||
): Promise<AchievementsStatsResponseDto> {
|
||||
const teacherId = req.user.profile.id;
|
||||
const teacherId = req.user!.profile!.id;
|
||||
return this.analyticsService.getAchievementsStats(teacherId, classroomId);
|
||||
}
|
||||
|
||||
@ -365,7 +366,7 @@ export class TeacherController {
|
||||
@Body() dto: GenerateReportDto,
|
||||
@Res() res: Response,
|
||||
) {
|
||||
const userId = req.user.profile.id;
|
||||
const userId = req.user!.profile!.id;
|
||||
const tenantId = req.user.tenantId || req.user.tenant_id || 'default';
|
||||
|
||||
// Generate report (now persists to storage and database)
|
||||
@ -424,7 +425,7 @@ export class TeacherController {
|
||||
@Body() dto: GrantBonusDto,
|
||||
@Request() req: AuthRequest,
|
||||
): Promise<GrantBonusResponseDto> {
|
||||
const teacherId = req.user.profile.id;
|
||||
const teacherId = req.user!.profile!.id;
|
||||
return this.bonusCoinsService.grantBonus(teacherId, studentId, dto);
|
||||
}
|
||||
|
||||
@ -446,7 +447,7 @@ export class TeacherController {
|
||||
@Request() req: AuthRequest,
|
||||
@Query() query: GetRecentReportsQueryDto,
|
||||
): Promise<ReportMetadataDto[]> {
|
||||
const teacherId = req.user.profile.id;
|
||||
const teacherId = req.user!.profile!.id;
|
||||
const limit = query.limit || 10;
|
||||
return this.teacherReportsService.getRecentReports(teacherId, limit);
|
||||
}
|
||||
@ -462,7 +463,7 @@ export class TeacherController {
|
||||
type: ReportStatsDto,
|
||||
})
|
||||
async getReportStats(@Request() req: AuthRequest): Promise<ReportStatsDto> {
|
||||
const teacherId = req.user.profile.id;
|
||||
const teacherId = req.user!.profile!.id;
|
||||
return this.teacherReportsService.getReportStats(teacherId);
|
||||
}
|
||||
|
||||
@ -489,7 +490,7 @@ export class TeacherController {
|
||||
@Request() req: AuthRequest,
|
||||
@Res() res: Response,
|
||||
) {
|
||||
const teacherId = req.user.profile.id;
|
||||
const teacherId = req.user!.profile!.id;
|
||||
|
||||
// Get report with ownership validation
|
||||
const report = await this.teacherReportsService.getReportById(reportId, teacherId);
|
||||
|
||||
@ -76,6 +76,7 @@ export interface AuthUser {
|
||||
rank?: string;
|
||||
tenant_id?: string;
|
||||
tenantId?: string; // Alternative naming
|
||||
sessionId?: string; // Session ID from JWT payload
|
||||
profile?: {
|
||||
id: string;
|
||||
tenant_id?: string;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user