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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": null,
"lines": null
},
"generated_at": "2025-10-30T07:06:07Z",
"generated_at": "2025-11-15T04:48:47Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -317,15 +317,6 @@
"verified_result": null
}
],
"apps/api/src/middleware/__tests__/data-transform.middleware.test.ts": [
{
"hashed_secret": "c43b74f82f891e351ea8d73c4cac9988f05fa49f",
"is_verified": false,
"line_number": 41,
"type": "Base64 High Entropy String",
"verified_result": null
}
],
"apps/web/.env.template": [
{
"hashed_secret": "d08f88df745fa7950b104e4a707a31cfce7b5841",
Expand Down Expand Up @@ -443,49 +434,49 @@
{
"hashed_secret": "b7e41a1408b0de53b6a18b0383983df52151bffd",
"is_verified": false,
"line_number": 60,
"line_number": 57,
"type": "Base64 High Entropy String",
"verified_result": null
},
{
"hashed_secret": "7f8a4c8efb7a9d741a4131e6382406d04920a55c",
"is_verified": false,
"line_number": 75,
"line_number": 72,
"type": "Base64 High Entropy String",
"verified_result": null
},
{
"hashed_secret": "ef584f952dbcdb807b1f2a5b688a6b2ac7beaf76",
"is_verified": false,
"line_number": 158,
"line_number": 155,
"type": "Base64 High Entropy String",
"verified_result": null
},
{
"hashed_secret": "fca9f0a000cc0d99a6b89eff22b280d43b3dc23a",
"is_verified": false,
"line_number": 168,
"line_number": 164,
"type": "Base64 High Entropy String",
"verified_result": null
},
{
"hashed_secret": "ad5a4eb98aace66b683002aa7038bb800f8b0a65",
"is_verified": false,
"line_number": 174,
"line_number": 170,
"type": "Base64 High Entropy String",
"verified_result": null
},
{
"hashed_secret": "28681ff8a70bc722645c0ebe5c21fbd8a2ee904a",
"is_verified": false,
"line_number": 183,
"line_number": 179,
"type": "Base64 High Entropy String",
"verified_result": null
},
{
"hashed_secret": "dd65cdacb216bbeca512abfb1ecd15d1c53ac7bd",
"is_verified": false,
"line_number": 431,
"line_number": 427,
"type": "Base64 High Entropy String",
"verified_result": null
}
Expand Down Expand Up @@ -564,21 +555,21 @@
{
"hashed_secret": "e1166e6dd837019ab04f130ab34c425e04161645",
"is_verified": false,
"line_number": 384,
"line_number": 391,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "f0c5bc5473fd2f959bdac630e625aa33346fd12a",
"is_verified": false,
"line_number": 431,
"line_number": 438,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "29080f1c58f9859ddaa6aeda7d2c410c12e222dc",
"is_verified": false,
"line_number": 463,
"line_number": 470,
"type": "Secret Keyword",
"verified_result": null
}
Expand All @@ -596,10 +587,19 @@
{
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
"is_verified": false,
"line_number": 135,
"line_number": 138,
"type": "Basic Auth Credentials",
"verified_result": null
}
],
"scripts/validate-env.sh": [
{
"hashed_secret": "8da52328e314a37358f9758f38d5bb0e8687b6ab",
"is_verified": false,
"line_number": 74,
"type": "Secret Keyword",
"verified_result": null
}
]
},
"version": "0.13.1+ibm.64.dss",
Expand Down
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
nodejs 22.12.0
nodejs 22.0.0
yarn 1.22.22
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@ export class MockJwtCookieAuthGuard extends AuthGuard("cookie-strategy") {
const request: RequestWithUserSession = context.switchToHttp().getRequest();

request.user = {
userId: "dev-user",
role: UserRole.LEARNER,
groupId: "string",
assignmentId: 1888,
userId: "[email protected]",
role: UserRole.AUTHOR,
groupId: "autogen-faculty-v1-course-v1-IND-AI0103EN-v1",
assignmentId: 1,
gradingCallbackRequired: false,
returnUrl: "https://skills.network",
launch_presentation_locale: "en",
};

return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "Assignment" ADD COLUMN "questionControls" JSONB;

-- AlterTable
ALTER TABLE "AssignmentVersion" ADD COLUMN "questionControls" JSONB;
2 changes: 2 additions & 0 deletions apps/api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ model Assignment {
showSubmissionFeedback Boolean @default(true) /// Should the AI provide feedback when the learner submits a question
showQuestions Boolean @default(true) /// Should the questions be shown to the learner
correctAnswerVisibility CorrectAnswerVisibility @default(ALWAYS) /// When should correct answers be shown to learners
questionControls Json? /// Question-level controls (e.g., allowCopy, allowPaste, allowRightClick)
updatedAt DateTime @default(now()) @updatedAt /// The DateTime at which the assignment was last updated
languageCode String? /// The language code for the assignment
currentVersionId Int? /// The ID of the current active version
Expand Down Expand Up @@ -287,6 +288,7 @@ model AssignmentVersion {
showSubmissionFeedback Boolean @default(true) /// Show submission feedback
showQuestions Boolean @default(true) /// Show questions
correctAnswerVisibility CorrectAnswerVisibility @default(ALWAYS) /// When to show correct answers to learners
questionControls Json? /// Question-level controls (e.g., allowCopy, allowPaste, allowRightClick)
languageCode String? /// Language code
createdBy String /// User who created this version
createdAt DateTime @default(now()) /// When version was created
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,19 @@ import {
IsEnum,
IsInt,
IsNumber,
IsObject,
IsOptional,
IsString,
} from "class-validator";

export interface QuestionControls {
allowCopy?: boolean;
allowPaste?: boolean;
allowRightClick?: boolean;
preventPrint?: boolean;
[key: string]: boolean | undefined;
}

export class UpdateAssignmentRequestDto {
@ApiProperty({
description: "The name of the assignment.",
Expand Down Expand Up @@ -227,4 +236,13 @@ export class UpdateAssignmentRequestDto {
})
@IsOptional()
correctAnswerVisibility: CorrectAnswerVisibility;

@ApiProperty({
description: "Question-level controls (copy, paste, right-click)",
required: false,
type: "object",
})
@IsOptional()
@IsObject()
questionControls?: QuestionControls;
}
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ export class AssignmentServiceV1 {
},
});

return authoredAssignments;
return authoredAssignments as AssignmentResponseDto[];
}

const results = await this.prisma.assignmentGroup.findMany({
Expand All @@ -322,7 +322,7 @@ export class AssignmentServiceV1 {

return results.map((result) => ({
...result.assignment,
}));
})) as AssignmentResponseDto[];
}

async replace(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ const FIELDS = [
"showQuestionScore",
"showSubmissionFeedback",
"showQuestions",
"correctAnswerVisibility",
"questionControls",
"languageCode",
] as const;

Expand Down Expand Up @@ -215,7 +217,7 @@ export class AssignmentRepository {
},
});

return authoredAssignments;
return authoredAssignments as AssignmentResponseDto[];
}

const results = await this.prisma.assignmentGroup.findMany({
Expand All @@ -231,7 +233,7 @@ export class AssignmentRepository {

return results.map((result) => ({
...result.assignment,
}));
})) as AssignmentResponseDto[];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
Question,
} from "@prisma/client";
import { WINSTON_MODULE_PROVIDER } from "nest-winston";
import { assign } from "nodemailer/lib/shared";

Check warning on line 20 in apps/api/src/api/assignment/v2/services/version-management.service.ts

View workflow job for this annotation

GitHub Actions / Lint & Test - api

'assign' is defined but never used
import {
UserRole,
UserSession,
} from "src/auth/interfaces/user.session.interface";
import { Logger } from "winston";
import { PrismaService } from "../../../../database/prisma.service";
import { QuestionDto } from "../../dto/update.questions.request.dto";
import { assign } from "nodemailer/lib/shared";

export interface CreateVersionDto {
versionNumber?: string;
Expand Down Expand Up @@ -303,6 +303,7 @@
showSubmissionFeedback: assignment.showSubmissionFeedback,
showQuestions: assignment.showQuestions,
correctAnswerVisibility: assignment.correctAnswerVisibility,
questionControls: assignment.questionControls,
languageCode: assignment.languageCode,
createdBy: userSession.userId,
isDraft: createVersionDto.isDraft ?? true,
Expand Down Expand Up @@ -551,6 +552,7 @@
showSubmissionFeedback: version.showSubmissionFeedback,
showQuestions: version.showQuestions,
correctAnswerVisibility: version.correctAnswerVisibility,
questionControls: version.questionControls,
languageCode: version.languageCode,
questionVersions: questionVersionsWithVariants,
};
Expand Down Expand Up @@ -1066,6 +1068,7 @@
showSubmissionFeedback: assignment.showSubmissionFeedback,
showQuestions: assignment.showQuestions,
correctAnswerVisibility: assignment.correctAnswerVisibility,
questionControls: assignment.questionControls,
languageCode: assignment.languageCode,
},
include: { _count: { select: { questionVersions: true } } },
Expand Down Expand Up @@ -1358,6 +1361,7 @@
showSubmissionFeedback: assignment.showSubmissionFeedback,
showQuestions: assignment.showQuestions,
correctAnswerVisibility: assignment.correctAnswerVisibility,
questionControls: assignment.questionControls,
languageCode: assignment.languageCode,
createdBy: userSession.userId,
isDraft: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,13 @@ export const createMockAssignment = (
updatedAt: new Date(),
languageCode: "en",
currentVersionId: 1,
questionControls: {
allowCopy: true,
allowPaste: true,
allowRightClick: true,
preventPrint: false,
preventScreenshot: false,
},
...overrides,
});

Expand All @@ -990,7 +997,7 @@ export const createMockGetAssignmentResponseDto = (
questions,
success: true,
...overrides,
};
} as GetAssignmentResponseDto;
};

/**
Expand All @@ -1006,7 +1013,7 @@ export const createMockLearnerGetAssignmentResponseDto = (
questions: [] as Question[],
success: true,
...overrides,
};
} as LearnerGetAssignmentResponseDto;
};

/**
Expand All @@ -1020,7 +1027,7 @@ export const createMockAssignmentResponseDto = (
return {
...assignment,
...overrides,
};
} as AssignmentResponseDto;
};

/**
Expand Down
42 changes: 42 additions & 0 deletions apps/api/src/common/interceptors/serialize-dates.interceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* eslint-disable */
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from "@nestjs/common";
import { Observable } from "rxjs";
import { map } from "rxjs/operators";

@Injectable()
export class SerializeDatesInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(map((data) => this.serializeDates(data)));
}

private serializeDates(object: any): any {
if (object === null || object === undefined) {
return object;
}

if (object instanceof Date) {
return object.toISOString();
}

if (Array.isArray(object)) {
return object.map((item) => this.serializeDates(item));
}

if (typeof object === "object") {
const serialized: any = {};
for (const key in object) {
if (object.hasOwnProperty(key)) {
serialized[key] = this.serializeDates(object[key]);
}
}
return serialized;
}

return object;
}
}
Loading
Loading