@playcademy/sandbox 0.4.2-beta.1 → 0.4.2-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +111 -4
- package/dist/constants.js +1 -0
- package/dist/mocks/timeback.d.ts +1 -0
- package/dist/server.js +109 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -249,6 +249,7 @@ var init_timeback2 = __esm(() => {
|
|
|
249
249
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
250
250
|
GET_XP: "/integrations/timeback/xp",
|
|
251
251
|
GET_MASTERY: "/integrations/timeback/mastery",
|
|
252
|
+
GET_HIGHEST_GRADE_MASTERED: "/integrations/timeback/highest-grade-mastered",
|
|
252
253
|
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
253
254
|
ADVANCE_COURSE: "/integrations/timeback/advance-course",
|
|
254
255
|
UNENROLL_COURSE: "/integrations/timeback/unenroll-course"
|
|
@@ -1077,7 +1078,7 @@ var package_default;
|
|
|
1077
1078
|
var init_package = __esm(() => {
|
|
1078
1079
|
package_default = {
|
|
1079
1080
|
name: "@playcademy/sandbox",
|
|
1080
|
-
version: "0.4.2-beta.
|
|
1081
|
+
version: "0.4.2-beta.2",
|
|
1081
1082
|
description: "Local development server for Playcademy game development",
|
|
1082
1083
|
type: "module",
|
|
1083
1084
|
exports: {
|
|
@@ -28248,6 +28249,7 @@ var init_constants3 = __esm(() => {
|
|
|
28248
28249
|
END_ACTIVITY: `/api${TIMEBACK_ROUTES.END_ACTIVITY}`,
|
|
28249
28250
|
GET_XP: `/api${TIMEBACK_ROUTES.GET_XP}`,
|
|
28250
28251
|
GET_MASTERY: `/api${TIMEBACK_ROUTES.GET_MASTERY}`,
|
|
28252
|
+
GET_HIGHEST_GRADE_MASTERED: `/api${TIMEBACK_ROUTES.GET_HIGHEST_GRADE_MASTERED}`,
|
|
28251
28253
|
HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}`,
|
|
28252
28254
|
ADVANCE_COURSE: `/api${TIMEBACK_ROUTES.ADVANCE_COURSE}`,
|
|
28253
28255
|
UNENROLL_COURSE: `/api${TIMEBACK_ROUTES.UNENROLL_COURSE}`
|
|
@@ -29128,6 +29130,7 @@ var init_utils6 = __esm(() => {
|
|
|
29128
29130
|
};
|
|
29129
29131
|
});
|
|
29130
29132
|
init_constants7();
|
|
29133
|
+
init_constants7();
|
|
29131
29134
|
if (process.env.DEBUG === "true") {
|
|
29132
29135
|
process.env.TERM = "dumb";
|
|
29133
29136
|
}
|
|
@@ -33560,6 +33563,25 @@ var init_timeback_service = __esm(() => {
|
|
|
33560
33563
|
});
|
|
33561
33564
|
return result;
|
|
33562
33565
|
}
|
|
33566
|
+
async getStudentHighestGradeMastered(timebackId, user, options) {
|
|
33567
|
+
const client = this.requireClient();
|
|
33568
|
+
const db2 = this.deps.db;
|
|
33569
|
+
await this.deps.validateDeveloperAccess(user, options.gameId);
|
|
33570
|
+
const integration = await db2.query.gameTimebackIntegrations.findFirst({
|
|
33571
|
+
where: and(eq(gameTimebackIntegrations.gameId, options.gameId), eq(gameTimebackIntegrations.subject, options.subject))
|
|
33572
|
+
});
|
|
33573
|
+
if (!integration) {
|
|
33574
|
+
throw new ValidationError(`Subject "${options.subject}" is not configured for game ${options.gameId}`);
|
|
33575
|
+
}
|
|
33576
|
+
const result = await client.getHighestGradeMastered(timebackId, options.subject);
|
|
33577
|
+
logger20.debug("Retrieved student highest grade mastered", {
|
|
33578
|
+
timebackId,
|
|
33579
|
+
gameId: options.gameId,
|
|
33580
|
+
subject: options.subject,
|
|
33581
|
+
highestGradeMastered: result.highestGradeMastered
|
|
33582
|
+
});
|
|
33583
|
+
return result;
|
|
33584
|
+
}
|
|
33563
33585
|
};
|
|
33564
33586
|
});
|
|
33565
33587
|
|
|
@@ -34789,6 +34811,19 @@ async function getTimebackTokenResponse(config2) {
|
|
|
34789
34811
|
function getAuthUrl(environment = "production") {
|
|
34790
34812
|
return TIMEBACK_AUTH_URLS5[environment];
|
|
34791
34813
|
}
|
|
34814
|
+
function parseEduBridgeGrade(value) {
|
|
34815
|
+
if (value === null || value === undefined || value.trim() === "") {
|
|
34816
|
+
return null;
|
|
34817
|
+
}
|
|
34818
|
+
const parsed = Number(value);
|
|
34819
|
+
return isTimebackGrade3(parsed) ? parsed : null;
|
|
34820
|
+
}
|
|
34821
|
+
function normalizeHighestGradeMastered(response, subject) {
|
|
34822
|
+
return {
|
|
34823
|
+
subject,
|
|
34824
|
+
highestGradeMastered: parseEduBridgeGrade(response.grades.highestGradeOverall)
|
|
34825
|
+
};
|
|
34826
|
+
}
|
|
34792
34827
|
function handleHttpError(res, errorBody, attempt, retries, url2) {
|
|
34793
34828
|
const error = new TimebackApiError2(res.status, res.statusText, errorBody);
|
|
34794
34829
|
if (res.status >= HTTP_STATUS5.CLIENT_ERROR_MIN && res.status < HTTP_STATUS5.CLIENT_ERROR_MAX) {
|
|
@@ -35133,7 +35168,8 @@ function createEduBridgeNamespace(client) {
|
|
|
35133
35168
|
const analytics = {
|
|
35134
35169
|
getEnrollmentFacts: async (enrollmentId, options) => client["request"](buildPath(`/edubridge/analytics/enrollment/${enrollmentId}`, {
|
|
35135
35170
|
timezone: options?.timezone
|
|
35136
|
-
}), "GET")
|
|
35171
|
+
}), "GET"),
|
|
35172
|
+
getHighestGradeMastered: async (studentId, subject) => client["request"](`/edubridge/analytics/highestGradeMastered/${encodeURIComponent(studentId)}/${encodeURIComponent(subject)}`, "GET")
|
|
35137
35173
|
};
|
|
35138
35174
|
return {
|
|
35139
35175
|
enrollments,
|
|
@@ -36875,6 +36911,11 @@ class TimebackClient {
|
|
|
36875
36911
|
...options?.include?.perCourse && { courses }
|
|
36876
36912
|
};
|
|
36877
36913
|
}
|
|
36914
|
+
async getHighestGradeMastered(studentId, subject) {
|
|
36915
|
+
await this._ensureAuthenticated();
|
|
36916
|
+
const response = await this.edubridge.analytics.getHighestGradeMastered(studentId, subject);
|
|
36917
|
+
return normalizeHighestGradeMastered(response, subject);
|
|
36918
|
+
}
|
|
36878
36919
|
async getStudentXp(studentId, options) {
|
|
36879
36920
|
await this._ensureAuthenticated();
|
|
36880
36921
|
const enrollments = await this.edubridge.enrollments.listByUser(studentId);
|
|
@@ -94197,7 +94238,7 @@ var init_session_controller = __esm(() => {
|
|
|
94197
94238
|
});
|
|
94198
94239
|
|
|
94199
94240
|
// ../api-core/src/controllers/timeback.controller.ts
|
|
94200
|
-
var logger45, populateStudent, getUser, getUserEnrollments, getUserById, setupIntegration, getIntegrations, updateIntegration, getIntegrationConfig, verifyIntegration, getConfig, deleteIntegrations, endActivity, heartbeat, advanceCourse, unenrollCourse, getStudentXp, getStudentMastery, getRoster, getStudentOverview, getGameMetrics, getStudentActivity, getActivityDetail, grantXp, adjustTime, adjustMastery, reconcileMasteryForConfigChange, searchStudents, enrollStudent, unenrollStudent, reactivateEnrollment, listAssessments, createAssessment, deleteAssessment, reorderAssessments, reorderQuestions, activateAssessment, deactivateAssessment, listQuestions, createQuestion, updateQuestion, deleteQuestion, getAssessmentBankStatus, destroyAssessmentBank, timeback2;
|
|
94241
|
+
var logger45, populateStudent, getUser, getUserEnrollments, getUserById, setupIntegration, getIntegrations, updateIntegration, getIntegrationConfig, verifyIntegration, getConfig, deleteIntegrations, endActivity, heartbeat, advanceCourse, unenrollCourse, getStudentXp, getStudentMastery, getStudentHighestGradeMastered, getRoster, getStudentOverview, getGameMetrics, getStudentActivity, getActivityDetail, grantXp, adjustTime, adjustMastery, reconcileMasteryForConfigChange, searchStudents, enrollStudent, unenrollStudent, reactivateEnrollment, listAssessments, createAssessment, deleteAssessment, reorderAssessments, reorderQuestions, activateAssessment, deactivateAssessment, listQuestions, createQuestion, updateQuestion, deleteQuestion, getAssessmentBankStatus, destroyAssessmentBank, timeback2;
|
|
94201
94242
|
var init_timeback_controller = __esm(() => {
|
|
94202
94243
|
init_esm();
|
|
94203
94244
|
init_schemas_index();
|
|
@@ -94541,6 +94582,33 @@ var init_timeback_controller = __esm(() => {
|
|
|
94541
94582
|
include
|
|
94542
94583
|
});
|
|
94543
94584
|
});
|
|
94585
|
+
getStudentHighestGradeMastered = requireDeveloper(async (ctx) => {
|
|
94586
|
+
const timebackId = ctx.params.timebackId;
|
|
94587
|
+
if (!timebackId) {
|
|
94588
|
+
throw ApiError.badRequest("Missing timebackId parameter");
|
|
94589
|
+
}
|
|
94590
|
+
const gameId = ctx.url.searchParams.get("gameId");
|
|
94591
|
+
if (!gameId) {
|
|
94592
|
+
throw ApiError.badRequest("Missing required gameId query parameter");
|
|
94593
|
+
}
|
|
94594
|
+
const subjectParam = ctx.url.searchParams.get("subject");
|
|
94595
|
+
if (!subjectParam) {
|
|
94596
|
+
throw ApiError.badRequest("Missing required subject query parameter");
|
|
94597
|
+
}
|
|
94598
|
+
if (!isTimebackSubject2(subjectParam)) {
|
|
94599
|
+
throw ApiError.badRequest(`Invalid subject: ${subjectParam}. Valid subjects: ${TIMEBACK_SUBJECTS4.join(", ")}`);
|
|
94600
|
+
}
|
|
94601
|
+
logger45.debug("Getting student highest grade mastered", {
|
|
94602
|
+
requesterId: ctx.user.id,
|
|
94603
|
+
timebackId,
|
|
94604
|
+
gameId,
|
|
94605
|
+
subject: subjectParam
|
|
94606
|
+
});
|
|
94607
|
+
return ctx.services.timeback.getStudentHighestGradeMastered(timebackId, ctx.user, {
|
|
94608
|
+
gameId,
|
|
94609
|
+
subject: subjectParam
|
|
94610
|
+
});
|
|
94611
|
+
});
|
|
94544
94612
|
getRoster = requireGameManagementAccess(async (ctx) => {
|
|
94545
94613
|
const gameId = ctx.params.gameId;
|
|
94546
94614
|
const courseId = ctx.params.courseId;
|
|
@@ -94879,6 +94947,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
94879
94947
|
unenrollCourse,
|
|
94880
94948
|
getStudentXp,
|
|
94881
94949
|
getStudentMastery,
|
|
94950
|
+
getStudentHighestGradeMastered,
|
|
94882
94951
|
getRoster,
|
|
94883
94952
|
getStudentOverview,
|
|
94884
94953
|
getGameMetrics,
|
|
@@ -95087,6 +95156,10 @@ async function getMockTimebackUser(db2, gameId) {
|
|
|
95087
95156
|
const timebackId = config.timeback.timebackId || "mock-student-00000001";
|
|
95088
95157
|
return getMockTimebackData(db2, timebackId, gameId);
|
|
95089
95158
|
}
|
|
95159
|
+
function getMockHighestGradeMastered(enrollments, subject) {
|
|
95160
|
+
const subjectGrades = enrollments.filter((enrollment) => enrollment.subject === subject).map((enrollment) => enrollment.grade);
|
|
95161
|
+
return subjectGrades.length > 0 ? Math.max(...subjectGrades) : null;
|
|
95162
|
+
}
|
|
95090
95163
|
async function buildMockUserResponse(db2, user, gameId) {
|
|
95091
95164
|
const timeback3 = user.timebackId ? await getMockTimebackData(db2, user.timebackId, gameId) : undefined;
|
|
95092
95165
|
if (gameId) {
|
|
@@ -95934,6 +96007,39 @@ var init_timeback6 = __esm(() => {
|
|
|
95934
96007
|
}
|
|
95935
96008
|
return handle2(timeback2.getStudentMastery)(c2);
|
|
95936
96009
|
});
|
|
96010
|
+
timebackRouter.get("/student-highest-grade-mastered/:timebackId", async (c2) => {
|
|
96011
|
+
const user = c2.get("user");
|
|
96012
|
+
if (!user) {
|
|
96013
|
+
const error2 = ApiError.unauthorized("Must be logged in to get student highest grade mastered");
|
|
96014
|
+
return c2.json(createErrorResponse(error2), error2.status);
|
|
96015
|
+
}
|
|
96016
|
+
if (shouldMockTimeback()) {
|
|
96017
|
+
const url2 = new URL(c2.req.url);
|
|
96018
|
+
const subject = url2.searchParams.get("subject");
|
|
96019
|
+
const contextGameId = c2.get("gameId");
|
|
96020
|
+
const gameId = url2.searchParams.get("gameId") || (typeof contextGameId === "string" ? contextGameId : undefined);
|
|
96021
|
+
if (!subject) {
|
|
96022
|
+
const error2 = ApiError.badRequest("Missing required subject query parameter");
|
|
96023
|
+
return c2.json(createErrorResponse(error2), error2.status);
|
|
96024
|
+
}
|
|
96025
|
+
if (!gameId) {
|
|
96026
|
+
const error2 = ApiError.badRequest("Missing required gameId query parameter");
|
|
96027
|
+
return c2.json(createErrorResponse(error2), error2.status);
|
|
96028
|
+
}
|
|
96029
|
+
if (!isTimebackSubject2(subject)) {
|
|
96030
|
+
const error2 = ApiError.badRequest(`Invalid subject: ${subject}. Valid subjects: ${TIMEBACK_SUBJECTS4.join(", ")}`);
|
|
96031
|
+
return c2.json(createErrorResponse(error2), error2.status);
|
|
96032
|
+
}
|
|
96033
|
+
const db2 = c2.get("db");
|
|
96034
|
+
const enrollments = await getMockEnrollments(db2);
|
|
96035
|
+
const gameScopedEnrollments = filterEnrollmentsByGame(enrollments, gameId);
|
|
96036
|
+
return c2.json({
|
|
96037
|
+
subject,
|
|
96038
|
+
highestGradeMastered: getMockHighestGradeMastered(gameScopedEnrollments, subject)
|
|
96039
|
+
});
|
|
96040
|
+
}
|
|
96041
|
+
return handle2(timeback2.getStudentHighestGradeMastered)(c2);
|
|
96042
|
+
});
|
|
95937
96043
|
});
|
|
95938
96044
|
|
|
95939
96045
|
// src/routes/integrations/lti.ts
|
|
@@ -98311,7 +98417,8 @@ program2.name("playcademy-sandbox").description("Local development server for Pl
|
|
|
98311
98417
|
port,
|
|
98312
98418
|
url: `http://localhost:${port}/api`,
|
|
98313
98419
|
startedAt: Date.now(),
|
|
98314
|
-
projectRoot: process.cwd()
|
|
98420
|
+
projectRoot: process.cwd(),
|
|
98421
|
+
gameId: server.gameId
|
|
98315
98422
|
});
|
|
98316
98423
|
const totalCourses = project?.timebackCourses?.length ?? 0;
|
|
98317
98424
|
const excludedCount = options.timebackExcludedCourses ? options.timebackExcludedCourses.split(",").filter(Boolean).length : 0;
|
package/dist/constants.js
CHANGED
|
@@ -84,6 +84,7 @@ var init_timeback = __esm(() => {
|
|
|
84
84
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
85
85
|
GET_XP: "/integrations/timeback/xp",
|
|
86
86
|
GET_MASTERY: "/integrations/timeback/mastery",
|
|
87
|
+
GET_HIGHEST_GRADE_MASTERED: "/integrations/timeback/highest-grade-mastered",
|
|
87
88
|
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
88
89
|
ADVANCE_COURSE: "/integrations/timeback/advance-course",
|
|
89
90
|
UNENROLL_COURSE: "/integrations/timeback/unenroll-course"
|
package/dist/mocks/timeback.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export declare function getMockTimebackData(db: DatabaseInstance, timebackId: st
|
|
|
30
30
|
* Uses the configured timebackId from sandbox config.
|
|
31
31
|
*/
|
|
32
32
|
export declare function getMockTimebackUser(db: DatabaseInstance, gameId?: string): Promise<UserTimebackData>;
|
|
33
|
+
export declare function getMockHighestGradeMastered(enrollments: UserEnrollment[], subject: string): number | null;
|
|
33
34
|
/**
|
|
34
35
|
* Build a complete user response with mock timeback data.
|
|
35
36
|
* Used to bypass api-core when in mock mode (avoids real API calls).
|
package/dist/server.js
CHANGED
|
@@ -248,6 +248,7 @@ var init_timeback2 = __esm(() => {
|
|
|
248
248
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
249
249
|
GET_XP: "/integrations/timeback/xp",
|
|
250
250
|
GET_MASTERY: "/integrations/timeback/mastery",
|
|
251
|
+
GET_HIGHEST_GRADE_MASTERED: "/integrations/timeback/highest-grade-mastered",
|
|
251
252
|
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
252
253
|
ADVANCE_COURSE: "/integrations/timeback/advance-course",
|
|
253
254
|
UNENROLL_COURSE: "/integrations/timeback/unenroll-course"
|
|
@@ -1076,7 +1077,7 @@ var package_default;
|
|
|
1076
1077
|
var init_package = __esm(() => {
|
|
1077
1078
|
package_default = {
|
|
1078
1079
|
name: "@playcademy/sandbox",
|
|
1079
|
-
version: "0.4.2-beta.
|
|
1080
|
+
version: "0.4.2-beta.2",
|
|
1080
1081
|
description: "Local development server for Playcademy game development",
|
|
1081
1082
|
type: "module",
|
|
1082
1083
|
exports: {
|
|
@@ -28247,6 +28248,7 @@ var init_constants3 = __esm(() => {
|
|
|
28247
28248
|
END_ACTIVITY: `/api${TIMEBACK_ROUTES.END_ACTIVITY}`,
|
|
28248
28249
|
GET_XP: `/api${TIMEBACK_ROUTES.GET_XP}`,
|
|
28249
28250
|
GET_MASTERY: `/api${TIMEBACK_ROUTES.GET_MASTERY}`,
|
|
28251
|
+
GET_HIGHEST_GRADE_MASTERED: `/api${TIMEBACK_ROUTES.GET_HIGHEST_GRADE_MASTERED}`,
|
|
28250
28252
|
HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}`,
|
|
28251
28253
|
ADVANCE_COURSE: `/api${TIMEBACK_ROUTES.ADVANCE_COURSE}`,
|
|
28252
28254
|
UNENROLL_COURSE: `/api${TIMEBACK_ROUTES.UNENROLL_COURSE}`
|
|
@@ -29127,6 +29129,7 @@ var init_utils6 = __esm(() => {
|
|
|
29127
29129
|
};
|
|
29128
29130
|
});
|
|
29129
29131
|
init_constants7();
|
|
29132
|
+
init_constants7();
|
|
29130
29133
|
if (process.env.DEBUG === "true") {
|
|
29131
29134
|
process.env.TERM = "dumb";
|
|
29132
29135
|
}
|
|
@@ -33559,6 +33562,25 @@ var init_timeback_service = __esm(() => {
|
|
|
33559
33562
|
});
|
|
33560
33563
|
return result;
|
|
33561
33564
|
}
|
|
33565
|
+
async getStudentHighestGradeMastered(timebackId, user, options) {
|
|
33566
|
+
const client = this.requireClient();
|
|
33567
|
+
const db2 = this.deps.db;
|
|
33568
|
+
await this.deps.validateDeveloperAccess(user, options.gameId);
|
|
33569
|
+
const integration = await db2.query.gameTimebackIntegrations.findFirst({
|
|
33570
|
+
where: and(eq(gameTimebackIntegrations.gameId, options.gameId), eq(gameTimebackIntegrations.subject, options.subject))
|
|
33571
|
+
});
|
|
33572
|
+
if (!integration) {
|
|
33573
|
+
throw new ValidationError(`Subject "${options.subject}" is not configured for game ${options.gameId}`);
|
|
33574
|
+
}
|
|
33575
|
+
const result = await client.getHighestGradeMastered(timebackId, options.subject);
|
|
33576
|
+
logger20.debug("Retrieved student highest grade mastered", {
|
|
33577
|
+
timebackId,
|
|
33578
|
+
gameId: options.gameId,
|
|
33579
|
+
subject: options.subject,
|
|
33580
|
+
highestGradeMastered: result.highestGradeMastered
|
|
33581
|
+
});
|
|
33582
|
+
return result;
|
|
33583
|
+
}
|
|
33562
33584
|
};
|
|
33563
33585
|
});
|
|
33564
33586
|
|
|
@@ -34788,6 +34810,19 @@ async function getTimebackTokenResponse(config2) {
|
|
|
34788
34810
|
function getAuthUrl(environment = "production") {
|
|
34789
34811
|
return TIMEBACK_AUTH_URLS5[environment];
|
|
34790
34812
|
}
|
|
34813
|
+
function parseEduBridgeGrade(value) {
|
|
34814
|
+
if (value === null || value === undefined || value.trim() === "") {
|
|
34815
|
+
return null;
|
|
34816
|
+
}
|
|
34817
|
+
const parsed = Number(value);
|
|
34818
|
+
return isTimebackGrade3(parsed) ? parsed : null;
|
|
34819
|
+
}
|
|
34820
|
+
function normalizeHighestGradeMastered(response, subject) {
|
|
34821
|
+
return {
|
|
34822
|
+
subject,
|
|
34823
|
+
highestGradeMastered: parseEduBridgeGrade(response.grades.highestGradeOverall)
|
|
34824
|
+
};
|
|
34825
|
+
}
|
|
34791
34826
|
function handleHttpError(res, errorBody, attempt, retries, url2) {
|
|
34792
34827
|
const error = new TimebackApiError2(res.status, res.statusText, errorBody);
|
|
34793
34828
|
if (res.status >= HTTP_STATUS5.CLIENT_ERROR_MIN && res.status < HTTP_STATUS5.CLIENT_ERROR_MAX) {
|
|
@@ -35132,7 +35167,8 @@ function createEduBridgeNamespace(client) {
|
|
|
35132
35167
|
const analytics = {
|
|
35133
35168
|
getEnrollmentFacts: async (enrollmentId, options) => client["request"](buildPath(`/edubridge/analytics/enrollment/${enrollmentId}`, {
|
|
35134
35169
|
timezone: options?.timezone
|
|
35135
|
-
}), "GET")
|
|
35170
|
+
}), "GET"),
|
|
35171
|
+
getHighestGradeMastered: async (studentId, subject) => client["request"](`/edubridge/analytics/highestGradeMastered/${encodeURIComponent(studentId)}/${encodeURIComponent(subject)}`, "GET")
|
|
35136
35172
|
};
|
|
35137
35173
|
return {
|
|
35138
35174
|
enrollments,
|
|
@@ -36874,6 +36910,11 @@ class TimebackClient {
|
|
|
36874
36910
|
...options?.include?.perCourse && { courses }
|
|
36875
36911
|
};
|
|
36876
36912
|
}
|
|
36913
|
+
async getHighestGradeMastered(studentId, subject) {
|
|
36914
|
+
await this._ensureAuthenticated();
|
|
36915
|
+
const response = await this.edubridge.analytics.getHighestGradeMastered(studentId, subject);
|
|
36916
|
+
return normalizeHighestGradeMastered(response, subject);
|
|
36917
|
+
}
|
|
36877
36918
|
async getStudentXp(studentId, options) {
|
|
36878
36919
|
await this._ensureAuthenticated();
|
|
36879
36920
|
const enrollments = await this.edubridge.enrollments.listByUser(studentId);
|
|
@@ -94196,7 +94237,7 @@ var init_session_controller = __esm(() => {
|
|
|
94196
94237
|
});
|
|
94197
94238
|
|
|
94198
94239
|
// ../api-core/src/controllers/timeback.controller.ts
|
|
94199
|
-
var logger45, populateStudent, getUser, getUserEnrollments, getUserById, setupIntegration, getIntegrations, updateIntegration, getIntegrationConfig, verifyIntegration, getConfig, deleteIntegrations, endActivity, heartbeat, advanceCourse, unenrollCourse, getStudentXp, getStudentMastery, getRoster, getStudentOverview, getGameMetrics, getStudentActivity, getActivityDetail, grantXp, adjustTime, adjustMastery, reconcileMasteryForConfigChange, searchStudents, enrollStudent, unenrollStudent, reactivateEnrollment, listAssessments, createAssessment, deleteAssessment, reorderAssessments, reorderQuestions, activateAssessment, deactivateAssessment, listQuestions, createQuestion, updateQuestion, deleteQuestion, getAssessmentBankStatus, destroyAssessmentBank, timeback2;
|
|
94240
|
+
var logger45, populateStudent, getUser, getUserEnrollments, getUserById, setupIntegration, getIntegrations, updateIntegration, getIntegrationConfig, verifyIntegration, getConfig, deleteIntegrations, endActivity, heartbeat, advanceCourse, unenrollCourse, getStudentXp, getStudentMastery, getStudentHighestGradeMastered, getRoster, getStudentOverview, getGameMetrics, getStudentActivity, getActivityDetail, grantXp, adjustTime, adjustMastery, reconcileMasteryForConfigChange, searchStudents, enrollStudent, unenrollStudent, reactivateEnrollment, listAssessments, createAssessment, deleteAssessment, reorderAssessments, reorderQuestions, activateAssessment, deactivateAssessment, listQuestions, createQuestion, updateQuestion, deleteQuestion, getAssessmentBankStatus, destroyAssessmentBank, timeback2;
|
|
94200
94241
|
var init_timeback_controller = __esm(() => {
|
|
94201
94242
|
init_esm();
|
|
94202
94243
|
init_schemas_index();
|
|
@@ -94540,6 +94581,33 @@ var init_timeback_controller = __esm(() => {
|
|
|
94540
94581
|
include
|
|
94541
94582
|
});
|
|
94542
94583
|
});
|
|
94584
|
+
getStudentHighestGradeMastered = requireDeveloper(async (ctx) => {
|
|
94585
|
+
const timebackId = ctx.params.timebackId;
|
|
94586
|
+
if (!timebackId) {
|
|
94587
|
+
throw ApiError.badRequest("Missing timebackId parameter");
|
|
94588
|
+
}
|
|
94589
|
+
const gameId = ctx.url.searchParams.get("gameId");
|
|
94590
|
+
if (!gameId) {
|
|
94591
|
+
throw ApiError.badRequest("Missing required gameId query parameter");
|
|
94592
|
+
}
|
|
94593
|
+
const subjectParam = ctx.url.searchParams.get("subject");
|
|
94594
|
+
if (!subjectParam) {
|
|
94595
|
+
throw ApiError.badRequest("Missing required subject query parameter");
|
|
94596
|
+
}
|
|
94597
|
+
if (!isTimebackSubject2(subjectParam)) {
|
|
94598
|
+
throw ApiError.badRequest(`Invalid subject: ${subjectParam}. Valid subjects: ${TIMEBACK_SUBJECTS4.join(", ")}`);
|
|
94599
|
+
}
|
|
94600
|
+
logger45.debug("Getting student highest grade mastered", {
|
|
94601
|
+
requesterId: ctx.user.id,
|
|
94602
|
+
timebackId,
|
|
94603
|
+
gameId,
|
|
94604
|
+
subject: subjectParam
|
|
94605
|
+
});
|
|
94606
|
+
return ctx.services.timeback.getStudentHighestGradeMastered(timebackId, ctx.user, {
|
|
94607
|
+
gameId,
|
|
94608
|
+
subject: subjectParam
|
|
94609
|
+
});
|
|
94610
|
+
});
|
|
94543
94611
|
getRoster = requireGameManagementAccess(async (ctx) => {
|
|
94544
94612
|
const gameId = ctx.params.gameId;
|
|
94545
94613
|
const courseId = ctx.params.courseId;
|
|
@@ -94878,6 +94946,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
94878
94946
|
unenrollCourse,
|
|
94879
94947
|
getStudentXp,
|
|
94880
94948
|
getStudentMastery,
|
|
94949
|
+
getStudentHighestGradeMastered,
|
|
94881
94950
|
getRoster,
|
|
94882
94951
|
getStudentOverview,
|
|
94883
94952
|
getGameMetrics,
|
|
@@ -95086,6 +95155,10 @@ async function getMockTimebackUser(db2, gameId) {
|
|
|
95086
95155
|
const timebackId = config.timeback.timebackId || "mock-student-00000001";
|
|
95087
95156
|
return getMockTimebackData(db2, timebackId, gameId);
|
|
95088
95157
|
}
|
|
95158
|
+
function getMockHighestGradeMastered(enrollments, subject) {
|
|
95159
|
+
const subjectGrades = enrollments.filter((enrollment) => enrollment.subject === subject).map((enrollment) => enrollment.grade);
|
|
95160
|
+
return subjectGrades.length > 0 ? Math.max(...subjectGrades) : null;
|
|
95161
|
+
}
|
|
95089
95162
|
async function buildMockUserResponse(db2, user, gameId) {
|
|
95090
95163
|
const timeback3 = user.timebackId ? await getMockTimebackData(db2, user.timebackId, gameId) : undefined;
|
|
95091
95164
|
if (gameId) {
|
|
@@ -95933,6 +96006,39 @@ var init_timeback6 = __esm(() => {
|
|
|
95933
96006
|
}
|
|
95934
96007
|
return handle2(timeback2.getStudentMastery)(c2);
|
|
95935
96008
|
});
|
|
96009
|
+
timebackRouter.get("/student-highest-grade-mastered/:timebackId", async (c2) => {
|
|
96010
|
+
const user = c2.get("user");
|
|
96011
|
+
if (!user) {
|
|
96012
|
+
const error2 = ApiError.unauthorized("Must be logged in to get student highest grade mastered");
|
|
96013
|
+
return c2.json(createErrorResponse(error2), error2.status);
|
|
96014
|
+
}
|
|
96015
|
+
if (shouldMockTimeback()) {
|
|
96016
|
+
const url2 = new URL(c2.req.url);
|
|
96017
|
+
const subject = url2.searchParams.get("subject");
|
|
96018
|
+
const contextGameId = c2.get("gameId");
|
|
96019
|
+
const gameId = url2.searchParams.get("gameId") || (typeof contextGameId === "string" ? contextGameId : undefined);
|
|
96020
|
+
if (!subject) {
|
|
96021
|
+
const error2 = ApiError.badRequest("Missing required subject query parameter");
|
|
96022
|
+
return c2.json(createErrorResponse(error2), error2.status);
|
|
96023
|
+
}
|
|
96024
|
+
if (!gameId) {
|
|
96025
|
+
const error2 = ApiError.badRequest("Missing required gameId query parameter");
|
|
96026
|
+
return c2.json(createErrorResponse(error2), error2.status);
|
|
96027
|
+
}
|
|
96028
|
+
if (!isTimebackSubject2(subject)) {
|
|
96029
|
+
const error2 = ApiError.badRequest(`Invalid subject: ${subject}. Valid subjects: ${TIMEBACK_SUBJECTS4.join(", ")}`);
|
|
96030
|
+
return c2.json(createErrorResponse(error2), error2.status);
|
|
96031
|
+
}
|
|
96032
|
+
const db2 = c2.get("db");
|
|
96033
|
+
const enrollments = await getMockEnrollments(db2);
|
|
96034
|
+
const gameScopedEnrollments = filterEnrollmentsByGame(enrollments, gameId);
|
|
96035
|
+
return c2.json({
|
|
96036
|
+
subject,
|
|
96037
|
+
highestGradeMastered: getMockHighestGradeMastered(gameScopedEnrollments, subject)
|
|
96038
|
+
});
|
|
96039
|
+
}
|
|
96040
|
+
return handle2(timeback2.getStudentHighestGradeMastered)(c2);
|
|
96041
|
+
});
|
|
95936
96042
|
});
|
|
95937
96043
|
|
|
95938
96044
|
// src/routes/integrations/lti.ts
|