@playcademy/vite-plugin 0.2.29-beta.6 → 0.2.30-beta.1
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/index.js +150 -32
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25370,7 +25370,7 @@ var package_default;
|
|
|
25370
25370
|
var init_package = __esm(() => {
|
|
25371
25371
|
package_default = {
|
|
25372
25372
|
name: "@playcademy/sandbox",
|
|
25373
|
-
version: "0.3.
|
|
25373
|
+
version: "0.3.17-beta.34",
|
|
25374
25374
|
description: "Local development server for Playcademy game development",
|
|
25375
25375
|
type: "module",
|
|
25376
25376
|
exports: {
|
|
@@ -54340,6 +54340,13 @@ function resolveAdminEventTime(data) {
|
|
|
54340
54340
|
}
|
|
54341
54341
|
return toAttributionEventTime(data.date);
|
|
54342
54342
|
}
|
|
54343
|
+
function compareEnrollmentsByRecency(a, b) {
|
|
54344
|
+
const dateCompare = (b.beginDate ?? "").localeCompare(a.beginDate ?? "");
|
|
54345
|
+
if (dateCompare !== 0) {
|
|
54346
|
+
return dateCompare;
|
|
54347
|
+
}
|
|
54348
|
+
return (b.dateLastModified ?? "").localeCompare(a.dateLastModified ?? "");
|
|
54349
|
+
}
|
|
54343
54350
|
var init_timeback_admin_util = __esm(() => {
|
|
54344
54351
|
init_errors();
|
|
54345
54352
|
});
|
|
@@ -54851,6 +54858,7 @@ class TimebackAdminService {
|
|
|
54851
54858
|
}
|
|
54852
54859
|
async getStudentEnrollmentsByCourseId(client, studentId, courseIds, options) {
|
|
54853
54860
|
const enrollments = new Map;
|
|
54861
|
+
const allEnrollments = new Map;
|
|
54854
54862
|
const entries = await Promise.all(courseIds.map(async (courseId) => {
|
|
54855
54863
|
const roster = await client.oneroster.enrollments.listByCourse(courseId, {
|
|
54856
54864
|
includeInactive: options?.includeInactive,
|
|
@@ -54862,28 +54870,30 @@ class TimebackAdminService {
|
|
|
54862
54870
|
if (aActive !== bActive) {
|
|
54863
54871
|
return aActive ? -1 : 1;
|
|
54864
54872
|
}
|
|
54865
|
-
return (
|
|
54873
|
+
return compareEnrollmentsByRecency(a.enrollment, b.enrollment);
|
|
54866
54874
|
});
|
|
54867
|
-
return { courseId,
|
|
54875
|
+
return { courseId, matches };
|
|
54868
54876
|
}));
|
|
54869
|
-
for (const { courseId,
|
|
54870
|
-
|
|
54871
|
-
|
|
54872
|
-
|
|
54873
|
-
|
|
54874
|
-
|
|
54875
|
-
|
|
54876
|
-
|
|
54877
|
-
|
|
54878
|
-
|
|
54879
|
-
|
|
54880
|
-
|
|
54881
|
-
|
|
54882
|
-
|
|
54883
|
-
|
|
54877
|
+
for (const { courseId, matches } of entries) {
|
|
54878
|
+
const records = matches.map((match) => ({
|
|
54879
|
+
id: match.enrollment.sourcedId,
|
|
54880
|
+
status: match.enrollment.status ?? "active",
|
|
54881
|
+
role: match.enrollment.role ?? "student",
|
|
54882
|
+
beginDate: match.enrollment.beginDate ?? null,
|
|
54883
|
+
endDate: match.enrollment.endDate ?? null,
|
|
54884
|
+
course: {
|
|
54885
|
+
id: courseId,
|
|
54886
|
+
title: match.class?.title ?? "",
|
|
54887
|
+
subjects: null,
|
|
54888
|
+
grades: null
|
|
54889
|
+
}
|
|
54890
|
+
}));
|
|
54891
|
+
if (records.length > 0) {
|
|
54892
|
+
enrollments.set(courseId, records[0]);
|
|
54884
54893
|
}
|
|
54894
|
+
allEnrollments.set(courseId, records);
|
|
54885
54895
|
}
|
|
54886
|
-
return { enrollments };
|
|
54896
|
+
return { enrollments, allEnrollments };
|
|
54887
54897
|
}
|
|
54888
54898
|
async assertStudentEnrolledInCourse(client, studentId, courseId) {
|
|
54889
54899
|
const enrollments = await client.edubridge.enrollments.listByUser(studentId);
|
|
@@ -54970,7 +54980,7 @@ class TimebackAdminService {
|
|
|
54970
54980
|
const enrollmentId = rosterEntry.enrollment.sourcedId || null;
|
|
54971
54981
|
const summary = enrollmentId ? analyticsByEnrollmentId.get(enrollmentId) : undefined;
|
|
54972
54982
|
const analyticsUnavailable = Boolean(enrollmentId) && summary?.analyticsAvailable !== true;
|
|
54973
|
-
const name3 = rosterEntry.user ? `${rosterEntry.user.givenName} ${rosterEntry.user.familyName}`.trim() :
|
|
54983
|
+
const name3 = rosterEntry.user ? `${rosterEntry.user.givenName} ${rosterEntry.user.familyName}`.trim() || "No name specified" : "No name specified";
|
|
54974
54984
|
const inactive = rosterEntry.enrollment.status === "tobedeleted";
|
|
54975
54985
|
return {
|
|
54976
54986
|
studentId: rosterEntry.enrollment.user.sourcedId,
|
|
@@ -55015,14 +55025,15 @@ class TimebackAdminService {
|
|
|
55015
55025
|
throw new NotFoundError("Timeback integration", gameId);
|
|
55016
55026
|
}
|
|
55017
55027
|
const courseIds = new Set(integrations.map((integration) => integration.courseId));
|
|
55018
|
-
const { enrollments: enrollmentsByCourseId } = await this.getStudentEnrollmentsByCourseId(client, studentId, [...courseIds], {
|
|
55028
|
+
const { enrollments: enrollmentsByCourseId, allEnrollments: allEnrollmentsByCourseId } = await this.getStudentEnrollmentsByCourseId(client, studentId, [...courseIds], {
|
|
55019
55029
|
includeInactive: true
|
|
55020
55030
|
});
|
|
55021
55031
|
if (enrollmentsByCourseId.size === 0) {
|
|
55022
55032
|
throw new NotFoundError("Student enrollment", courseId ? `${studentId}:${courseId}` : `${studentId}:${gameId}`);
|
|
55023
55033
|
}
|
|
55034
|
+
const allEnrollmentIds = [...allEnrollmentsByCourseId.values()].flat().map((enrollment) => enrollment.id);
|
|
55024
55035
|
const studentProfile = await client.oneroster.users.get(studentId);
|
|
55025
|
-
const analyticsByEnrollmentId = await this.loadEnrollmentAnalyticsSummaries(
|
|
55036
|
+
const analyticsByEnrollmentId = await this.loadEnrollmentAnalyticsSummaries(allEnrollmentIds);
|
|
55026
55037
|
const [masterableUnitsByCourse, completionStatusByCourse] = await Promise.all([
|
|
55027
55038
|
this.getMasterableUnitsByCourse(integrations.map((integration) => integration.courseId)),
|
|
55028
55039
|
this.getCompletionStatusByCourse(client, integrations.map((integration) => integration.courseId), studentId)
|
|
@@ -55033,6 +55044,24 @@ class TimebackAdminService {
|
|
|
55033
55044
|
const masterableUnits = masterableUnitsByCourse.get(integration.courseId);
|
|
55034
55045
|
const analyticsUnavailable = Boolean(enrollment?.id) && summary?.analyticsAvailable !== true;
|
|
55035
55046
|
const inactive = enrollment?.status === "tobedeleted";
|
|
55047
|
+
const courseEnrollments = allEnrollmentsByCourseId.get(integration.courseId) ?? [];
|
|
55048
|
+
const enrollmentSummaries = courseEnrollments.length > 1 ? courseEnrollments.map((record) => {
|
|
55049
|
+
const recordSummary = analyticsByEnrollmentId.get(record.id);
|
|
55050
|
+
const recordAnalyticsUnavailable = recordSummary?.analyticsAvailable !== true;
|
|
55051
|
+
return {
|
|
55052
|
+
enrollmentId: record.id,
|
|
55053
|
+
status: record.status === "tobedeleted" ? "tobedeleted" : "active",
|
|
55054
|
+
beginDate: record.beginDate,
|
|
55055
|
+
endDate: record.endDate,
|
|
55056
|
+
analyticsUnavailable: recordAnalyticsUnavailable,
|
|
55057
|
+
totalXp: recordSummary?.totalXp ?? 0,
|
|
55058
|
+
todayXp: recordSummary?.todayXp ?? 0,
|
|
55059
|
+
activeTimeSeconds: recordSummary?.activeTimeSeconds ?? 0,
|
|
55060
|
+
masteredUnits: recordSummary?.masteredUnits ?? 0,
|
|
55061
|
+
pctCompleteApp: TimebackAdminService.computeCompletionPct(recordSummary?.masteredUnits ?? 0, masterableUnits),
|
|
55062
|
+
history: recordSummary?.history ?? []
|
|
55063
|
+
};
|
|
55064
|
+
}) : undefined;
|
|
55036
55065
|
return {
|
|
55037
55066
|
courseId: integration.courseId,
|
|
55038
55067
|
title: enrollment?.course.title || `${integration.subject} Grade ${integration.grade}`,
|
|
@@ -55048,7 +55077,8 @@ class TimebackAdminService {
|
|
|
55048
55077
|
pctCompleteApp: TimebackAdminService.computeCompletionPct(summary?.masteredUnits ?? 0, masterableUnits),
|
|
55049
55078
|
completionStatus: completionStatusByCourse.get(integration.courseId) ?? "none",
|
|
55050
55079
|
history: summary?.history ?? [],
|
|
55051
|
-
...inactive ? { inactive } : {}
|
|
55080
|
+
...inactive ? { inactive } : {},
|
|
55081
|
+
...enrollmentSummaries ? { enrollments: enrollmentSummaries } : {}
|
|
55052
55082
|
};
|
|
55053
55083
|
});
|
|
55054
55084
|
return {
|
|
@@ -55290,17 +55320,34 @@ class TimebackAdminService {
|
|
|
55290
55320
|
});
|
|
55291
55321
|
return { students: [] };
|
|
55292
55322
|
}
|
|
55293
|
-
const
|
|
55323
|
+
const fullRoster = await client.oneroster.enrollments.listByCourse(courseId, {
|
|
55294
55324
|
role: "student",
|
|
55325
|
+
includeInactive: true,
|
|
55295
55326
|
includeUsers: false
|
|
55296
55327
|
});
|
|
55297
|
-
const enrolledStudentIds = new Set(
|
|
55298
|
-
const
|
|
55299
|
-
|
|
55300
|
-
|
|
55301
|
-
|
|
55302
|
-
|
|
55303
|
-
|
|
55328
|
+
const enrolledStudentIds = new Set(fullRoster.filter((entry) => entry.enrollment.status === "active").map((entry) => entry.enrollment.user.sourcedId));
|
|
55329
|
+
const pastEnrollmentsByStudent = new Map;
|
|
55330
|
+
const inactiveEntries = fullRoster.filter((entry) => entry.enrollment.status === "tobedeleted").toSorted((a, b) => compareEnrollmentsByRecency(a.enrollment, b.enrollment));
|
|
55331
|
+
for (const entry of inactiveEntries) {
|
|
55332
|
+
const studentId = entry.enrollment.user.sourcedId;
|
|
55333
|
+
const list = pastEnrollmentsByStudent.get(studentId) ?? [];
|
|
55334
|
+
list.push({
|
|
55335
|
+
enrollmentId: entry.enrollment.sourcedId,
|
|
55336
|
+
beginDate: entry.enrollment.beginDate ?? null,
|
|
55337
|
+
endDate: entry.enrollment.endDate ?? null
|
|
55338
|
+
});
|
|
55339
|
+
pastEnrollmentsByStudent.set(studentId, list);
|
|
55340
|
+
}
|
|
55341
|
+
const students = allUsers.filter((entry) => Boolean(entry.sourcedId) && entry.roles?.some((role) => role.role === "student") === true).map((entry) => {
|
|
55342
|
+
const past = pastEnrollmentsByStudent.get(entry.sourcedId) ?? [];
|
|
55343
|
+
return {
|
|
55344
|
+
studentId: entry.sourcedId,
|
|
55345
|
+
name: `${entry.givenName || ""} ${entry.familyName || ""}`.trim() || "No name specified",
|
|
55346
|
+
email: entry.email || null,
|
|
55347
|
+
alreadyEnrolled: enrolledStudentIds.has(entry.sourcedId),
|
|
55348
|
+
...past.length > 0 ? { pastEnrollments: past } : {}
|
|
55349
|
+
};
|
|
55350
|
+
});
|
|
55304
55351
|
return { students };
|
|
55305
55352
|
}
|
|
55306
55353
|
async enrollStudent(data, user) {
|
|
@@ -55331,6 +55378,48 @@ class TimebackAdminService {
|
|
|
55331
55378
|
client.invalidateEnrollments(data.studentId);
|
|
55332
55379
|
return { status: "ok" };
|
|
55333
55380
|
}
|
|
55381
|
+
async reactivateEnrollment(data, user) {
|
|
55382
|
+
const client = this.requireClient();
|
|
55383
|
+
await this.deps.validateGameManagementAccess(user, data.gameId);
|
|
55384
|
+
const integration = await this.deps.db.query.gameTimebackIntegrations.findFirst({
|
|
55385
|
+
where: and(eq(gameTimebackIntegrations.gameId, data.gameId), eq(gameTimebackIntegrations.courseId, data.courseId))
|
|
55386
|
+
});
|
|
55387
|
+
if (!integration) {
|
|
55388
|
+
throw new NotFoundError("Timeback integration", `${data.gameId}:${data.courseId}`);
|
|
55389
|
+
}
|
|
55390
|
+
const enrollment = await client.oneroster.enrollments.get(data.enrollmentId);
|
|
55391
|
+
if (!enrollment) {
|
|
55392
|
+
throw new NotFoundError("Enrollment", data.enrollmentId);
|
|
55393
|
+
}
|
|
55394
|
+
if (enrollment.user.sourcedId !== data.studentId) {
|
|
55395
|
+
throw new ValidationError("Enrollment does not belong to the specified student");
|
|
55396
|
+
}
|
|
55397
|
+
if (enrollment.status === "active") {
|
|
55398
|
+
throw new ValidationError("Enrollment is already active");
|
|
55399
|
+
}
|
|
55400
|
+
const { allEnrollments } = await this.getStudentEnrollmentsByCourseId(client, data.studentId, [data.courseId], { includeInactive: true });
|
|
55401
|
+
const courseEnrollmentIds = new Set((allEnrollments.get(data.courseId) ?? []).map((e) => e.id));
|
|
55402
|
+
if (!courseEnrollmentIds.has(data.enrollmentId)) {
|
|
55403
|
+
throw new ValidationError("Enrollment does not belong to the specified course");
|
|
55404
|
+
}
|
|
55405
|
+
const activeEnrollments = await client.edubridge.enrollments.listByUser(data.studentId);
|
|
55406
|
+
if (activeEnrollments.some((e) => e.course.id === data.courseId)) {
|
|
55407
|
+
throw new ValidationError("Student already has an active enrollment for this course. Unenroll from the current enrollment before reactivating a past one.");
|
|
55408
|
+
}
|
|
55409
|
+
await client.oneroster.enrollments.update(data.enrollmentId, {
|
|
55410
|
+
role: enrollment.role,
|
|
55411
|
+
primary: enrollment.primary,
|
|
55412
|
+
beginDate: enrollment.beginDate,
|
|
55413
|
+
endDate: enrollment.endDate,
|
|
55414
|
+
user: enrollment.user,
|
|
55415
|
+
class: enrollment.class,
|
|
55416
|
+
school: enrollment.school,
|
|
55417
|
+
sourcedId: data.enrollmentId,
|
|
55418
|
+
status: "active"
|
|
55419
|
+
});
|
|
55420
|
+
client.invalidateEnrollments(data.studentId);
|
|
55421
|
+
return { status: "ok" };
|
|
55422
|
+
}
|
|
55334
55423
|
async getCompletionStatus(client, courseId, studentId) {
|
|
55335
55424
|
const ids = deriveSourcedIds(courseId);
|
|
55336
55425
|
const lineItemId = `${ids.course}-mastery-completion-assessment`;
|
|
@@ -60403,6 +60492,10 @@ function createOneRosterNamespace(client) {
|
|
|
60403
60492
|
}
|
|
60404
60493
|
},
|
|
60405
60494
|
enrollments: {
|
|
60495
|
+
get: async (sourcedId) => {
|
|
60496
|
+
const response = await client["request"](`${ONEROSTER_ENDPOINTS5.enrollments}/${sourcedId}`, "GET");
|
|
60497
|
+
return response.enrollment;
|
|
60498
|
+
},
|
|
60406
60499
|
listByClass: async (classSourcedId, options) => {
|
|
60407
60500
|
const queryParams = new URLSearchParams;
|
|
60408
60501
|
const filters = [`class.sourcedId='${escapeFilterValue2(classSourcedId)}'`];
|
|
@@ -60480,6 +60573,11 @@ function createOneRosterNamespace(client) {
|
|
|
60480
60573
|
}
|
|
60481
60574
|
},
|
|
60482
60575
|
create: async (data) => client["request"](ONEROSTER_ENDPOINTS5.enrollments, "POST", { enrollment: data }),
|
|
60576
|
+
update: async (sourcedId, data) => {
|
|
60577
|
+
await client["request"](`${ONEROSTER_ENDPOINTS5.enrollments}/${sourcedId}`, "PUT", {
|
|
60578
|
+
enrollment: data
|
|
60579
|
+
});
|
|
60580
|
+
},
|
|
60483
60581
|
delete: async (sourcedId) => {
|
|
60484
60582
|
await client["request"](`${ONEROSTER_ENDPOINTS5.enrollments}/${sourcedId}`, "DELETE");
|
|
60485
60583
|
}
|
|
@@ -121699,6 +121797,7 @@ var AdjustTimebackMasteryRequestSchema;
|
|
|
121699
121797
|
var ToggleCourseCompletionRequestSchema;
|
|
121700
121798
|
var EnrollStudentRequestSchema;
|
|
121701
121799
|
var UnenrollStudentRequestSchema;
|
|
121800
|
+
var ReactivateEnrollmentRequestSchema;
|
|
121702
121801
|
var InsertAssessmentTestSchema;
|
|
121703
121802
|
var CreateAssessmentRequestSchema;
|
|
121704
121803
|
var ReorderAssessmentsRequestSchema;
|
|
@@ -121889,6 +121988,12 @@ var init_schemas11 = __esm(() => {
|
|
|
121889
121988
|
courseId: exports_external.string().min(1),
|
|
121890
121989
|
studentId: exports_external.string().min(1)
|
|
121891
121990
|
});
|
|
121991
|
+
ReactivateEnrollmentRequestSchema = exports_external.object({
|
|
121992
|
+
gameId: exports_external.string().uuid(),
|
|
121993
|
+
courseId: exports_external.string().min(1),
|
|
121994
|
+
studentId: exports_external.string().min(1),
|
|
121995
|
+
enrollmentId: exports_external.string().min(1)
|
|
121996
|
+
});
|
|
121892
121997
|
InsertAssessmentTestSchema = createInsertSchema(gameTimebackAssessmentTests).omit({
|
|
121893
121998
|
id: true,
|
|
121894
121999
|
createdAt: true
|
|
@@ -124142,6 +124247,7 @@ var toggleCompletion;
|
|
|
124142
124247
|
var searchStudents;
|
|
124143
124248
|
var enrollStudent;
|
|
124144
124249
|
var unenrollStudent;
|
|
124250
|
+
var reactivateEnrollment;
|
|
124145
124251
|
var listAssessments;
|
|
124146
124252
|
var createAssessment;
|
|
124147
124253
|
var deleteAssessment;
|
|
@@ -124602,6 +124708,17 @@ var init_timeback_controller = __esm(() => {
|
|
|
124602
124708
|
});
|
|
124603
124709
|
return ctx.services.timebackAdmin.unenrollStudent(body2, ctx.user);
|
|
124604
124710
|
});
|
|
124711
|
+
reactivateEnrollment = requireGameManagementAccess(async (ctx) => {
|
|
124712
|
+
const body2 = await parseRequestBody(ctx.request, ReactivateEnrollmentRequestSchema);
|
|
124713
|
+
logger65.debug("Reactivating enrollment", {
|
|
124714
|
+
requesterId: ctx.user.id,
|
|
124715
|
+
gameId: body2.gameId,
|
|
124716
|
+
courseId: body2.courseId,
|
|
124717
|
+
studentId: body2.studentId,
|
|
124718
|
+
enrollmentId: body2.enrollmentId
|
|
124719
|
+
});
|
|
124720
|
+
return ctx.services.timebackAdmin.reactivateEnrollment(body2, ctx.user);
|
|
124721
|
+
});
|
|
124605
124722
|
listAssessments = requireGameManagementAccess(async (ctx) => {
|
|
124606
124723
|
const { gameId, courseId } = ctx.params;
|
|
124607
124724
|
if (!gameId || !courseId) {
|
|
@@ -124751,6 +124868,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124751
124868
|
searchStudents,
|
|
124752
124869
|
enrollStudent,
|
|
124753
124870
|
unenrollStudent,
|
|
124871
|
+
reactivateEnrollment,
|
|
124754
124872
|
listAssessments,
|
|
124755
124873
|
createAssessment,
|
|
124756
124874
|
deleteAssessment,
|
|
@@ -127584,7 +127702,7 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
|
127584
127702
|
// package.json
|
|
127585
127703
|
var package_default2 = {
|
|
127586
127704
|
name: "@playcademy/vite-plugin",
|
|
127587
|
-
version: "0.2.
|
|
127705
|
+
version: "0.2.30-beta.1",
|
|
127588
127706
|
type: "module",
|
|
127589
127707
|
exports: {
|
|
127590
127708
|
".": {
|