@vue-skuilder/db 0.1.7 → 0.1.8-0
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/{SyncStrategy-DnJRj-Xp.d.mts → SyncStrategy-CyATpyLQ.d.mts} +6 -0
- package/dist/{SyncStrategy-DnJRj-Xp.d.ts → SyncStrategy-CyATpyLQ.d.ts} +6 -0
- package/dist/core/index.d.mts +5 -5
- package/dist/core/index.d.ts +5 -5
- package/dist/core/index.js +131 -118
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +128 -115
- package/dist/core/index.mjs.map +1 -1
- package/dist/{dataLayerProvider-BbW9EnZK.d.mts → dataLayerProvider-BInqI_RF.d.mts} +1 -1
- package/dist/{dataLayerProvider-6stCgDME.d.ts → dataLayerProvider-DqtNroSh.d.ts} +1 -1
- package/dist/impl/couch/index.d.mts +6 -6
- package/dist/impl/couch/index.d.ts +6 -6
- package/dist/impl/couch/index.js +1365 -1252
- package/dist/impl/couch/index.js.map +1 -1
- package/dist/impl/couch/index.mjs +1359 -1246
- package/dist/impl/couch/index.mjs.map +1 -1
- package/dist/impl/static/index.d.mts +8 -6
- package/dist/impl/static/index.d.ts +8 -6
- package/dist/impl/static/index.js +253 -843
- package/dist/impl/static/index.js.map +1 -1
- package/dist/impl/static/index.mjs +250 -842
- package/dist/impl/static/index.mjs.map +1 -1
- package/dist/index-CLL31bEy.d.ts +137 -0
- package/dist/index-CUNnL38E.d.mts +137 -0
- package/dist/index.d.mts +10 -55
- package/dist/index.d.ts +10 -55
- package/dist/index.js +343 -170
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +340 -167
- package/dist/index.mjs.map +1 -1
- package/dist/{types-BvzcRAys.d.ts → types-BefDGkKa.d.ts} +1 -1
- package/dist/{types-CQQ80R5N.d.mts → types-DC-ckZug.d.mts} +1 -1
- package/dist/{types-legacy-CtrmkOLu.d.mts → types-legacy-Birv-Jx6.d.mts} +2 -2
- package/dist/{types-legacy-CtrmkOLu.d.ts → types-legacy-Birv-Jx6.d.ts} +2 -2
- package/dist/{userDB-DUY63VMN.d.ts → userDB-C33Hzjgn.d.mts} +10 -3
- package/dist/{userDB-7fM4tpgr.d.mts → userDB-DusL7OXe.d.ts} +10 -3
- package/dist/util/packer/index.d.mts +3 -63
- package/dist/util/packer/index.d.ts +3 -63
- package/dist/util/packer/index.js +53 -1
- package/dist/util/packer/index.js.map +1 -1
- package/dist/util/packer/index.mjs +53 -1
- package/dist/util/packer/index.mjs.map +1 -1
- package/package.json +7 -4
- package/src/core/types/types-legacy.ts +13 -1
- package/src/core/types/user.ts +9 -2
- package/src/core/util/index.ts +5 -4
- package/src/impl/common/BaseUserDB.ts +33 -22
- package/src/impl/common/SyncStrategy.ts +7 -0
- package/src/impl/common/index.ts +0 -1
- package/src/impl/common/userDBHelpers.ts +4 -4
- package/src/impl/couch/CouchDBSyncStrategy.ts +10 -0
- package/src/impl/couch/courseAPI.ts +7 -6
- package/src/impl/couch/index.ts +10 -5
- package/src/impl/couch/updateQueue.ts +12 -8
- package/src/impl/couch/user-course-relDB.ts +17 -27
- package/src/impl/static/NoOpSyncStrategy.ts +5 -0
- package/src/impl/static/StaticDataUnpacker.ts +18 -36
- package/src/impl/static/courseDB.ts +135 -17
- package/src/util/migrator/FileSystemAdapter.ts +20 -0
- package/src/util/migrator/StaticToCouchDBMigrator.ts +6 -0
- package/src/util/packer/CouchDBToStaticPacker.ts +92 -2
|
@@ -30,6 +30,12 @@ interface SyncStrategy {
|
|
|
30
30
|
* @returns PouchDB database instance (may be same as local for no-op)
|
|
31
31
|
*/
|
|
32
32
|
setupRemoteDB(username: string): PouchDB.Database;
|
|
33
|
+
/**
|
|
34
|
+
* Get the database to use for write operations (local-first approach)
|
|
35
|
+
* @param username The username to get write DB for
|
|
36
|
+
* @returns PouchDB database instance for write operations
|
|
37
|
+
*/
|
|
38
|
+
getWriteDB?(username: string): PouchDB.Database;
|
|
33
39
|
/**
|
|
34
40
|
* Start synchronization between local and remote databases
|
|
35
41
|
* @param localDB The local PouchDB instance
|
|
@@ -30,6 +30,12 @@ interface SyncStrategy {
|
|
|
30
30
|
* @returns PouchDB database instance (may be same as local for no-op)
|
|
31
31
|
*/
|
|
32
32
|
setupRemoteDB(username: string): PouchDB.Database;
|
|
33
|
+
/**
|
|
34
|
+
* Get the database to use for write operations (local-first approach)
|
|
35
|
+
* @param username The username to get write DB for
|
|
36
|
+
* @returns PouchDB database instance for write operations
|
|
37
|
+
*/
|
|
38
|
+
getWriteDB?(username: string): PouchDB.Database;
|
|
33
39
|
/**
|
|
34
40
|
* Start synchronization between local and remote databases
|
|
35
41
|
* @param localDB The local PouchDB instance
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { h as StudyContentSource, U as UserDBInterface, C as CourseDBInterface, d as ContentNavigationStrategyData, e as StudySessionReviewItem, f as ScheduledCard, S as StudySessionNewItem } from '../userDB-
|
|
2
|
-
export { B as ActivityRecord, A as AdminDBInterface, s as AssignedCard, g as AssignedContent, r as AssignedCourse, q as AssignedTag, b as ClassroomDBInterface, x as ClassroomRegistration, w as ClassroomRegistrationDesignation, y as ClassroomRegistrationDoc, o as ContentSourceID, c as CourseInfo, E as CourseRegistration, F as CourseRegistrationDoc, a as CoursesDBInterface, i as StudentClassroomDBInterface, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, j as StudySessionItem, T as TeacherClassroomDBInterface, z as UserConfig, u as UserCourseSetting, t as UserCourseSettings, v as UsrCrsDataInterface, p as getStudySource, n as isReview } from '../userDB-
|
|
3
|
-
export { D as DataLayerProvider } from '../dataLayerProvider-
|
|
4
|
-
import { g as CardHistory, C as CardRecord, h as QuestionRecord } from '../types-legacy-
|
|
5
|
-
export { b as CardData, c as CourseListData, e as DataShapeData, d as DisplayableData, D as DocType, F as Field, G as GuestUsername, Q as QuestionData, S as SkuilderCourseData, a as Tag, T as TagStub,
|
|
1
|
+
import { h as StudyContentSource, U as UserDBInterface, C as CourseDBInterface, d as ContentNavigationStrategyData, e as StudySessionReviewItem, f as ScheduledCard, S as StudySessionNewItem } from '../userDB-C33Hzjgn.mjs';
|
|
2
|
+
export { B as ActivityRecord, A as AdminDBInterface, s as AssignedCard, g as AssignedContent, r as AssignedCourse, q as AssignedTag, b as ClassroomDBInterface, x as ClassroomRegistration, w as ClassroomRegistrationDesignation, y as ClassroomRegistrationDoc, o as ContentSourceID, c as CourseInfo, E as CourseRegistration, F as CourseRegistrationDoc, a as CoursesDBInterface, i as StudentClassroomDBInterface, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, j as StudySessionItem, T as TeacherClassroomDBInterface, z as UserConfig, u as UserCourseSetting, t as UserCourseSettings, v as UsrCrsDataInterface, p as getStudySource, n as isReview } from '../userDB-C33Hzjgn.mjs';
|
|
3
|
+
export { D as DataLayerProvider } from '../dataLayerProvider-BInqI_RF.mjs';
|
|
4
|
+
import { g as CardHistory, C as CardRecord, h as QuestionRecord } from '../types-legacy-Birv-Jx6.mjs';
|
|
5
|
+
export { b as CardData, c as CourseListData, e as DataShapeData, d as DisplayableData, D as DocType, f as DocTypePrefixes, F as Field, G as GuestUsername, Q as QuestionData, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from '../types-legacy-Birv-Jx6.mjs';
|
|
6
6
|
import { DataShape, ParsedCard } from '@vue-skuilder/common';
|
|
7
7
|
import 'moment';
|
|
8
8
|
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { h as StudyContentSource, U as UserDBInterface, C as CourseDBInterface, d as ContentNavigationStrategyData, e as StudySessionReviewItem, f as ScheduledCard, S as StudySessionNewItem } from '../userDB-
|
|
2
|
-
export { B as ActivityRecord, A as AdminDBInterface, s as AssignedCard, g as AssignedContent, r as AssignedCourse, q as AssignedTag, b as ClassroomDBInterface, x as ClassroomRegistration, w as ClassroomRegistrationDesignation, y as ClassroomRegistrationDoc, o as ContentSourceID, c as CourseInfo, E as CourseRegistration, F as CourseRegistrationDoc, a as CoursesDBInterface, i as StudentClassroomDBInterface, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, j as StudySessionItem, T as TeacherClassroomDBInterface, z as UserConfig, u as UserCourseSetting, t as UserCourseSettings, v as UsrCrsDataInterface, p as getStudySource, n as isReview } from '../userDB-
|
|
3
|
-
export { D as DataLayerProvider } from '../dataLayerProvider-
|
|
4
|
-
import { g as CardHistory, C as CardRecord, h as QuestionRecord } from '../types-legacy-
|
|
5
|
-
export { b as CardData, c as CourseListData, e as DataShapeData, d as DisplayableData, D as DocType, F as Field, G as GuestUsername, Q as QuestionData, S as SkuilderCourseData, a as Tag, T as TagStub,
|
|
1
|
+
import { h as StudyContentSource, U as UserDBInterface, C as CourseDBInterface, d as ContentNavigationStrategyData, e as StudySessionReviewItem, f as ScheduledCard, S as StudySessionNewItem } from '../userDB-DusL7OXe.js';
|
|
2
|
+
export { B as ActivityRecord, A as AdminDBInterface, s as AssignedCard, g as AssignedContent, r as AssignedCourse, q as AssignedTag, b as ClassroomDBInterface, x as ClassroomRegistration, w as ClassroomRegistrationDesignation, y as ClassroomRegistrationDoc, o as ContentSourceID, c as CourseInfo, E as CourseRegistration, F as CourseRegistrationDoc, a as CoursesDBInterface, i as StudentClassroomDBInterface, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, j as StudySessionItem, T as TeacherClassroomDBInterface, z as UserConfig, u as UserCourseSetting, t as UserCourseSettings, v as UsrCrsDataInterface, p as getStudySource, n as isReview } from '../userDB-DusL7OXe.js';
|
|
3
|
+
export { D as DataLayerProvider } from '../dataLayerProvider-DqtNroSh.js';
|
|
4
|
+
import { g as CardHistory, C as CardRecord, h as QuestionRecord } from '../types-legacy-Birv-Jx6.js';
|
|
5
|
+
export { b as CardData, c as CourseListData, e as DataShapeData, d as DisplayableData, D as DocType, f as DocTypePrefixes, F as Field, G as GuestUsername, Q as QuestionData, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from '../types-legacy-Birv-Jx6.js';
|
|
6
6
|
import { DataShape, ParsedCard } from '@vue-skuilder/common';
|
|
7
7
|
import 'moment';
|
|
8
8
|
|
package/dist/core/index.js
CHANGED
|
@@ -102,7 +102,7 @@ var init_logger = __esm({
|
|
|
102
102
|
});
|
|
103
103
|
|
|
104
104
|
// src/core/types/types-legacy.ts
|
|
105
|
-
var GuestUsername, log, DocType,
|
|
105
|
+
var GuestUsername, log, DocType, DocTypePrefixes;
|
|
106
106
|
var init_types_legacy = __esm({
|
|
107
107
|
"src/core/types/types-legacy.ts"() {
|
|
108
108
|
"use strict";
|
|
@@ -124,7 +124,19 @@ var init_types_legacy = __esm({
|
|
|
124
124
|
DocType2["NAVIGATION_STRATEGY"] = "NAVIGATION_STRATEGY";
|
|
125
125
|
return DocType2;
|
|
126
126
|
})(DocType || {});
|
|
127
|
-
|
|
127
|
+
DocTypePrefixes = {
|
|
128
|
+
["CARD" /* CARD */]: "c",
|
|
129
|
+
["DISPLAYABLE_DATA" /* DISPLAYABLE_DATA */]: "dd",
|
|
130
|
+
["TAG" /* TAG */]: "TAG",
|
|
131
|
+
["CARDRECORD" /* CARDRECORD */]: "cardH",
|
|
132
|
+
["SCHEDULED_CARD" /* SCHEDULED_CARD */]: "card_review_",
|
|
133
|
+
// Add other doctypes here as they get prefixed IDs
|
|
134
|
+
["DATASHAPE" /* DATASHAPE */]: "DATASHAPE",
|
|
135
|
+
["QUESTION" /* QUESTIONTYPE */]: "QUESTION",
|
|
136
|
+
["VIEW" /* VIEW */]: "VIEW",
|
|
137
|
+
["PEDAGOGY" /* PEDAGOGY */]: "PEDAGOGY",
|
|
138
|
+
["NAVIGATION_STRATEGY" /* NAVIGATION_STRATEGY */]: "NAVIGATION_STRATEGY"
|
|
139
|
+
};
|
|
128
140
|
}
|
|
129
141
|
});
|
|
130
142
|
|
|
@@ -136,16 +148,16 @@ function isQuestionRecord(c) {
|
|
|
136
148
|
return c.userAnswer !== void 0;
|
|
137
149
|
}
|
|
138
150
|
function getCardHistoryID(courseID, cardID) {
|
|
139
|
-
return `${
|
|
151
|
+
return `${DocTypePrefixes["CARDRECORD" /* CARDRECORD */]}-${courseID}-${cardID}`;
|
|
140
152
|
}
|
|
141
153
|
function parseCardHistoryID(id) {
|
|
142
154
|
const split = id.split("-");
|
|
143
155
|
let error = "";
|
|
144
156
|
error += split.length === 3 ? "" : `
|
|
145
157
|
given ID has incorrect number of '-' characters`;
|
|
146
|
-
error += split[0] ===
|
|
147
|
-
given ID does not start with ${
|
|
148
|
-
if (split.length === 3 && split[0] ===
|
|
158
|
+
error += split[0] === DocTypePrefixes["CARDRECORD" /* CARDRECORD */] ? "" : `
|
|
159
|
+
given ID does not start with ${DocTypePrefixes["CARDRECORD" /* CARDRECORD */]}`;
|
|
160
|
+
if (split.length === 3 && split[0] === DocTypePrefixes["CARDRECORD" /* CARDRECORD */]) {
|
|
149
161
|
return {
|
|
150
162
|
courseID: split[1],
|
|
151
163
|
cardID: split[2]
|
|
@@ -238,11 +250,11 @@ function scheduleCardReviewLocal(userDB, review) {
|
|
|
238
250
|
const now = import_moment.default.utc();
|
|
239
251
|
logger.info(`Scheduling for review in: ${review.time.diff(now, "h") / 24} days`);
|
|
240
252
|
void userDB.put({
|
|
241
|
-
_id:
|
|
253
|
+
_id: DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */] + review.time.format(REVIEW_TIME_FORMAT),
|
|
242
254
|
cardId: review.card_id,
|
|
243
|
-
reviewTime: review.time,
|
|
255
|
+
reviewTime: review.time.toISOString(),
|
|
244
256
|
courseId: review.course_id,
|
|
245
|
-
scheduledAt: now,
|
|
257
|
+
scheduledAt: now.toISOString(),
|
|
246
258
|
scheduledFor: review.scheduledFor,
|
|
247
259
|
schedulingAgentId: review.schedulingAgentId
|
|
248
260
|
});
|
|
@@ -258,15 +270,15 @@ async function removeScheduledCardReviewLocal(userDB, reviewDocID) {
|
|
|
258
270
|
${JSON.stringify(err)}`);
|
|
259
271
|
});
|
|
260
272
|
}
|
|
261
|
-
var import_moment,
|
|
273
|
+
var import_moment, REVIEW_TIME_FORMAT, log2;
|
|
262
274
|
var init_userDBHelpers = __esm({
|
|
263
275
|
"src/impl/common/userDBHelpers.ts"() {
|
|
264
276
|
"use strict";
|
|
265
277
|
import_moment = __toESM(require("moment"));
|
|
278
|
+
init_core();
|
|
266
279
|
init_logger();
|
|
267
280
|
init_pouchdb_setup();
|
|
268
281
|
init_dataDirectory();
|
|
269
|
-
REVIEW_PREFIX = "card_review_";
|
|
270
282
|
REVIEW_TIME_FORMAT = "YYYY-MM-DD--kk:mm:ss-SSS";
|
|
271
283
|
log2 = (s) => {
|
|
272
284
|
logger.info(s);
|
|
@@ -301,7 +313,10 @@ var init_updateQueue = __esm({
|
|
|
301
313
|
_className = "UpdateQueue";
|
|
302
314
|
pendingUpdates = {};
|
|
303
315
|
inprogressUpdates = {};
|
|
304
|
-
|
|
316
|
+
readDB;
|
|
317
|
+
// Database for read operations
|
|
318
|
+
writeDB;
|
|
319
|
+
// Database for write operations (local-first)
|
|
305
320
|
update(id, update) {
|
|
306
321
|
logger.debug(`Update requested on doc: ${id}`);
|
|
307
322
|
if (this.pendingUpdates[id]) {
|
|
@@ -311,24 +326,25 @@ var init_updateQueue = __esm({
|
|
|
311
326
|
}
|
|
312
327
|
return this.applyUpdates(id);
|
|
313
328
|
}
|
|
314
|
-
constructor(
|
|
329
|
+
constructor(readDB, writeDB) {
|
|
315
330
|
super();
|
|
316
|
-
this.
|
|
331
|
+
this.readDB = readDB;
|
|
332
|
+
this.writeDB = writeDB || readDB;
|
|
317
333
|
logger.debug(`UpdateQ initialized...`);
|
|
318
|
-
void this.
|
|
334
|
+
void this.readDB.info().then((i) => {
|
|
319
335
|
logger.debug(`db info: ${JSON.stringify(i)}`);
|
|
320
336
|
});
|
|
321
337
|
}
|
|
322
338
|
async applyUpdates(id) {
|
|
323
339
|
logger.debug(`Applying updates on doc: ${id}`);
|
|
324
340
|
if (this.inprogressUpdates[id]) {
|
|
325
|
-
await this.
|
|
341
|
+
await this.readDB.info();
|
|
326
342
|
return this.applyUpdates(id);
|
|
327
343
|
} else {
|
|
328
344
|
if (this.pendingUpdates[id] && this.pendingUpdates[id].length > 0) {
|
|
329
345
|
this.inprogressUpdates[id] = true;
|
|
330
346
|
try {
|
|
331
|
-
let doc = await this.
|
|
347
|
+
let doc = await this.readDB.get(id);
|
|
332
348
|
logger.debug(`Retrieved doc: ${id}`);
|
|
333
349
|
while (this.pendingUpdates[id].length !== 0) {
|
|
334
350
|
const update = this.pendingUpdates[id].splice(0, 1)[0];
|
|
@@ -341,7 +357,7 @@ var init_updateQueue = __esm({
|
|
|
341
357
|
};
|
|
342
358
|
}
|
|
343
359
|
}
|
|
344
|
-
await this.
|
|
360
|
+
await this.writeDB.put(doc);
|
|
345
361
|
logger.debug(`Put doc: ${id}`);
|
|
346
362
|
if (this.pendingUpdates[id].length === 0) {
|
|
347
363
|
this.inprogressUpdates[id] = false;
|
|
@@ -367,6 +383,60 @@ var init_updateQueue = __esm({
|
|
|
367
383
|
}
|
|
368
384
|
});
|
|
369
385
|
|
|
386
|
+
// src/impl/couch/user-course-relDB.ts
|
|
387
|
+
var import_moment2, UsrCrsData;
|
|
388
|
+
var init_user_course_relDB = __esm({
|
|
389
|
+
"src/impl/couch/user-course-relDB.ts"() {
|
|
390
|
+
"use strict";
|
|
391
|
+
import_moment2 = __toESM(require("moment"));
|
|
392
|
+
init_logger();
|
|
393
|
+
UsrCrsData = class {
|
|
394
|
+
user;
|
|
395
|
+
_courseId;
|
|
396
|
+
constructor(user, courseId) {
|
|
397
|
+
this.user = user;
|
|
398
|
+
this._courseId = courseId;
|
|
399
|
+
}
|
|
400
|
+
async getReviewsForcast(daysCount) {
|
|
401
|
+
const time = import_moment2.default.utc().add(daysCount, "days");
|
|
402
|
+
return this.getReviewstoDate(time);
|
|
403
|
+
}
|
|
404
|
+
async getPendingReviews() {
|
|
405
|
+
const now = import_moment2.default.utc();
|
|
406
|
+
return this.getReviewstoDate(now);
|
|
407
|
+
}
|
|
408
|
+
async getScheduledReviewCount() {
|
|
409
|
+
return (await this.getPendingReviews()).length;
|
|
410
|
+
}
|
|
411
|
+
async getCourseSettings() {
|
|
412
|
+
const regDoc = await this.user.getCourseRegistrationsDoc();
|
|
413
|
+
const crsDoc = regDoc.courses.find((c) => c.courseID === this._courseId);
|
|
414
|
+
if (crsDoc && crsDoc.settings) {
|
|
415
|
+
return crsDoc.settings;
|
|
416
|
+
} else {
|
|
417
|
+
logger.warn(`no settings found during lookup on course ${this._courseId}`);
|
|
418
|
+
return {};
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
updateCourseSettings(updates) {
|
|
422
|
+
if ("updateCourseSettings" in this.user) {
|
|
423
|
+
void this.user.updateCourseSettings(this._courseId, updates);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
async getReviewstoDate(targetDate) {
|
|
427
|
+
const allReviews = await this.user.getPendingReviews(this._courseId);
|
|
428
|
+
logger.debug(
|
|
429
|
+
`Fetching ${this.user.getUsername()}'s scheduled reviews for course ${this._courseId}.`
|
|
430
|
+
);
|
|
431
|
+
return allReviews.filter((review) => {
|
|
432
|
+
const reviewTime = import_moment2.default.utc(review.reviewTime);
|
|
433
|
+
return targetDate.isAfter(reviewTime);
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
|
|
370
440
|
// src/impl/couch/clientCache.ts
|
|
371
441
|
async function GET_CACHED(k, f) {
|
|
372
442
|
if (CLIENT_CACHE[k]) {
|
|
@@ -390,7 +460,8 @@ var init_clientCache = __esm({
|
|
|
390
460
|
async function addNote55(courseID, codeCourse, shape, data, author, tags, uploads, elo = (0, import_common2.blankCourseElo)()) {
|
|
391
461
|
const db = getCourseDB(courseID);
|
|
392
462
|
const payload = (0, import_common3.prepareNote55)(courseID, codeCourse, shape, data, author, tags, uploads);
|
|
393
|
-
const
|
|
463
|
+
const _id = `${DocTypePrefixes["DISPLAYABLE_DATA" /* DISPLAYABLE_DATA */]}-${(0, import_uuid.v4)()}`;
|
|
464
|
+
const result = await db.put({ ...payload, _id });
|
|
394
465
|
const dataShapeId = import_common.NameSpacer.getDataShapeString({
|
|
395
466
|
course: codeCourse,
|
|
396
467
|
dataShape: shape.name
|
|
@@ -461,7 +532,9 @@ async function createCard(questionViewName, courseID, dsDescriptor, noteID, tags
|
|
|
461
532
|
}
|
|
462
533
|
async function addCard(courseID, course, id_displayable_data, id_view, elo, tags, author) {
|
|
463
534
|
const db = getCourseDB(courseID);
|
|
464
|
-
const
|
|
535
|
+
const _id = `${DocTypePrefixes["CARD" /* CARD */]}-${(0, import_uuid.v4)()}`;
|
|
536
|
+
const card = await db.put({
|
|
537
|
+
_id,
|
|
465
538
|
course,
|
|
466
539
|
id_displayable_data,
|
|
467
540
|
id_view,
|
|
@@ -554,7 +627,7 @@ function getCourseDB(courseID) {
|
|
|
554
627
|
pouchDBincludeCredentialsConfig
|
|
555
628
|
);
|
|
556
629
|
}
|
|
557
|
-
var import_common, import_common2, import_common3, AlreadyTaggedErr;
|
|
630
|
+
var import_common, import_common2, import_common3, import_uuid, AlreadyTaggedErr;
|
|
558
631
|
var init_courseAPI = __esm({
|
|
559
632
|
"src/impl/couch/courseAPI.ts"() {
|
|
560
633
|
"use strict";
|
|
@@ -568,6 +641,7 @@ var init_courseAPI = __esm({
|
|
|
568
641
|
import_common3 = require("@vue-skuilder/common");
|
|
569
642
|
init_common();
|
|
570
643
|
init_logger();
|
|
644
|
+
import_uuid = require("uuid");
|
|
571
645
|
AlreadyTaggedErr = class extends Error {
|
|
572
646
|
constructor(message) {
|
|
573
647
|
super(message);
|
|
@@ -1211,13 +1285,13 @@ ${above.rows.map((r) => ` ${r.id}-${r.key}
|
|
|
1211
1285
|
});
|
|
1212
1286
|
|
|
1213
1287
|
// src/impl/couch/classroomDB.ts
|
|
1214
|
-
var
|
|
1288
|
+
var import_moment3, CLASSROOM_CONFIG, ClassroomDBBase, StudentClassroomDB;
|
|
1215
1289
|
var init_classroomDB2 = __esm({
|
|
1216
1290
|
"src/impl/couch/classroomDB.ts"() {
|
|
1217
1291
|
"use strict";
|
|
1218
1292
|
init_factory();
|
|
1219
1293
|
init_logger();
|
|
1220
|
-
|
|
1294
|
+
import_moment3 = __toESM(require("moment"));
|
|
1221
1295
|
init_pouchdb_setup();
|
|
1222
1296
|
init_couch();
|
|
1223
1297
|
init_courseDB();
|
|
@@ -1311,9 +1385,9 @@ var init_classroomDB2 = __esm({
|
|
|
1311
1385
|
}
|
|
1312
1386
|
async getNewCards() {
|
|
1313
1387
|
const activeCards = await this._user.getActiveCards();
|
|
1314
|
-
const now =
|
|
1388
|
+
const now = import_moment3.default.utc();
|
|
1315
1389
|
const assigned = await this.getAssignedContent();
|
|
1316
|
-
const due = assigned.filter((c) => now.isAfter(
|
|
1390
|
+
const due = assigned.filter((c) => now.isAfter(import_moment3.default.utc(c.activeOn, REVIEW_TIME_FORMAT2)));
|
|
1317
1391
|
logger.info(`Due content: ${JSON.stringify(due)}`);
|
|
1318
1392
|
let ret = [];
|
|
1319
1393
|
for (let i = 0; i < due.length; i++) {
|
|
@@ -1424,13 +1498,13 @@ function getStartAndEndKeys2(key) {
|
|
|
1424
1498
|
endkey: key + "\uFFF0"
|
|
1425
1499
|
};
|
|
1426
1500
|
}
|
|
1427
|
-
var
|
|
1501
|
+
var import_moment4, import_process, isBrowser, GUEST_LOCAL_DB, localUserDB, pouchDBincludeCredentialsConfig, REVIEW_TIME_FORMAT2;
|
|
1428
1502
|
var init_couch = __esm({
|
|
1429
1503
|
"src/impl/couch/index.ts"() {
|
|
1430
1504
|
"use strict";
|
|
1431
1505
|
init_factory();
|
|
1432
1506
|
init_types_legacy();
|
|
1433
|
-
|
|
1507
|
+
import_moment4 = __toESM(require("moment"));
|
|
1434
1508
|
init_logger();
|
|
1435
1509
|
init_pouchdb_setup();
|
|
1436
1510
|
import_process = __toESM(require("process"));
|
|
@@ -1452,78 +1526,10 @@ var init_couch = __esm({
|
|
|
1452
1526
|
return pouchdb_setup_default.fetch(url, opts);
|
|
1453
1527
|
}
|
|
1454
1528
|
};
|
|
1455
|
-
REVIEW_PREFIX2 = "card_review_";
|
|
1456
1529
|
REVIEW_TIME_FORMAT2 = "YYYY-MM-DD--kk:mm:ss-SSS";
|
|
1457
1530
|
}
|
|
1458
1531
|
});
|
|
1459
1532
|
|
|
1460
|
-
// src/impl/couch/user-course-relDB.ts
|
|
1461
|
-
var import_moment4, UsrCrsData;
|
|
1462
|
-
var init_user_course_relDB = __esm({
|
|
1463
|
-
"src/impl/couch/user-course-relDB.ts"() {
|
|
1464
|
-
"use strict";
|
|
1465
|
-
import_moment4 = __toESM(require("moment"));
|
|
1466
|
-
init_couch();
|
|
1467
|
-
init_courseDB();
|
|
1468
|
-
init_logger();
|
|
1469
|
-
UsrCrsData = class {
|
|
1470
|
-
user;
|
|
1471
|
-
course;
|
|
1472
|
-
_courseId;
|
|
1473
|
-
constructor(user, courseId) {
|
|
1474
|
-
this.user = user;
|
|
1475
|
-
this.course = new CourseDB(courseId, async () => this.user);
|
|
1476
|
-
this._courseId = courseId;
|
|
1477
|
-
}
|
|
1478
|
-
async getReviewsForcast(daysCount) {
|
|
1479
|
-
const time = import_moment4.default.utc().add(daysCount, "days");
|
|
1480
|
-
return this.getReviewstoDate(time);
|
|
1481
|
-
}
|
|
1482
|
-
async getPendingReviews() {
|
|
1483
|
-
const now = import_moment4.default.utc();
|
|
1484
|
-
return this.getReviewstoDate(now);
|
|
1485
|
-
}
|
|
1486
|
-
async getScheduledReviewCount() {
|
|
1487
|
-
return (await this.getPendingReviews()).length;
|
|
1488
|
-
}
|
|
1489
|
-
async getCourseSettings() {
|
|
1490
|
-
const regDoc = await this.user.getCourseRegistrationsDoc();
|
|
1491
|
-
const crsDoc = regDoc.courses.find((c) => c.courseID === this._courseId);
|
|
1492
|
-
if (crsDoc && crsDoc.settings) {
|
|
1493
|
-
return crsDoc.settings;
|
|
1494
|
-
} else {
|
|
1495
|
-
logger.warn(`no settings found during lookup on course ${this._courseId}`);
|
|
1496
|
-
return {};
|
|
1497
|
-
}
|
|
1498
|
-
}
|
|
1499
|
-
updateCourseSettings(updates) {
|
|
1500
|
-
void this.user.updateCourseSettings(this._courseId, updates);
|
|
1501
|
-
}
|
|
1502
|
-
async getReviewstoDate(targetDate) {
|
|
1503
|
-
const keys = getStartAndEndKeys2(REVIEW_PREFIX2);
|
|
1504
|
-
const reviews = await this.user.remote().allDocs({
|
|
1505
|
-
startkey: keys.startkey,
|
|
1506
|
-
endkey: keys.endkey,
|
|
1507
|
-
include_docs: true
|
|
1508
|
-
});
|
|
1509
|
-
logger.debug(
|
|
1510
|
-
`Fetching ${this.user.getUsername()}'s scheduled reviews for course ${this._courseId}.`
|
|
1511
|
-
);
|
|
1512
|
-
return reviews.rows.filter((r) => {
|
|
1513
|
-
if (r.id.startsWith(REVIEW_PREFIX2)) {
|
|
1514
|
-
const date = import_moment4.default.utc(r.id.substr(REVIEW_PREFIX2.length), REVIEW_TIME_FORMAT2);
|
|
1515
|
-
if (targetDate.isAfter(date)) {
|
|
1516
|
-
if (this._courseId === void 0 || r.doc.courseId === this._courseId) {
|
|
1517
|
-
return true;
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
}).map((r) => r.doc);
|
|
1522
|
-
}
|
|
1523
|
-
};
|
|
1524
|
-
}
|
|
1525
|
-
});
|
|
1526
|
-
|
|
1527
1533
|
// src/impl/common/BaseUserDB.ts
|
|
1528
1534
|
async function getOrCreateClassroomRegistrationsDoc(user) {
|
|
1529
1535
|
let ret;
|
|
@@ -1617,10 +1623,11 @@ async function dropUserFromClassroom(user, classID) {
|
|
|
1617
1623
|
async function getUserClassrooms(user) {
|
|
1618
1624
|
return getOrCreateClassroomRegistrationsDoc(user);
|
|
1619
1625
|
}
|
|
1620
|
-
var import_common8, import_moment5, log3,
|
|
1626
|
+
var import_common8, import_moment5, log3, BaseUser, userCoursesDoc, userClassroomsDoc;
|
|
1621
1627
|
var init_BaseUserDB = __esm({
|
|
1622
1628
|
"src/impl/common/BaseUserDB.ts"() {
|
|
1623
1629
|
"use strict";
|
|
1630
|
+
init_core();
|
|
1624
1631
|
init_util();
|
|
1625
1632
|
import_common8 = require("@vue-skuilder/common");
|
|
1626
1633
|
import_moment5 = __toESM(require("moment"));
|
|
@@ -1633,7 +1640,6 @@ var init_BaseUserDB = __esm({
|
|
|
1633
1640
|
log3 = (s) => {
|
|
1634
1641
|
logger.info(s);
|
|
1635
1642
|
};
|
|
1636
|
-
cardHistoryPrefix2 = "cardH-";
|
|
1637
1643
|
BaseUser = class _BaseUser {
|
|
1638
1644
|
static _instance;
|
|
1639
1645
|
static _initialized = false;
|
|
@@ -1654,11 +1660,13 @@ var init_BaseUserDB = __esm({
|
|
|
1654
1660
|
isLoggedIn() {
|
|
1655
1661
|
return !this._username.startsWith(GuestUsername);
|
|
1656
1662
|
}
|
|
1657
|
-
remoteDB;
|
|
1658
1663
|
remote() {
|
|
1659
1664
|
return this.remoteDB;
|
|
1660
1665
|
}
|
|
1661
1666
|
localDB;
|
|
1667
|
+
remoteDB;
|
|
1668
|
+
writeDB;
|
|
1669
|
+
// Database to use for write operations (local-first approach)
|
|
1662
1670
|
updateQueue;
|
|
1663
1671
|
async createAccount(username, password) {
|
|
1664
1672
|
if (!this.syncStrategy.canCreateAccount()) {
|
|
@@ -1722,8 +1730,8 @@ Currently logged-in as ${this._username}.`
|
|
|
1722
1730
|
const allDocs = await localDB.allDocs({ include_docs: false });
|
|
1723
1731
|
const docsToDelete = allDocs.rows.filter((row) => {
|
|
1724
1732
|
const id = row.id;
|
|
1725
|
-
return id.startsWith(
|
|
1726
|
-
id.startsWith(
|
|
1733
|
+
return id.startsWith(DocTypePrefixes["CARDRECORD" /* CARDRECORD */]) || // Card interaction history
|
|
1734
|
+
id.startsWith(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */]) || // Scheduled reviews
|
|
1727
1735
|
id === _BaseUser.DOC_IDS.COURSE_REGISTRATIONS || // Course registrations
|
|
1728
1736
|
id === _BaseUser.DOC_IDS.CLASSROOM_REGISTRATIONS || // Classroom registrations
|
|
1729
1737
|
id === _BaseUser.DOC_IDS.CONFIG;
|
|
@@ -1792,7 +1800,7 @@ Currently logged-in as ${this._username}.`
|
|
|
1792
1800
|
*
|
|
1793
1801
|
*/
|
|
1794
1802
|
async getActiveCards() {
|
|
1795
|
-
const keys = getStartAndEndKeys(
|
|
1803
|
+
const keys = getStartAndEndKeys(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */]);
|
|
1796
1804
|
const reviews = await this.remoteDB.allDocs({
|
|
1797
1805
|
startkey: keys.startkey,
|
|
1798
1806
|
endkey: keys.endkey,
|
|
@@ -1864,7 +1872,7 @@ Currently logged-in as ${this._username}.`
|
|
|
1864
1872
|
}
|
|
1865
1873
|
}
|
|
1866
1874
|
async getReviewstoDate(targetDate, course_id) {
|
|
1867
|
-
const keys = getStartAndEndKeys(
|
|
1875
|
+
const keys = getStartAndEndKeys(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */]);
|
|
1868
1876
|
const reviews = await this.remoteDB.allDocs({
|
|
1869
1877
|
startkey: keys.startkey,
|
|
1870
1878
|
endkey: keys.endkey,
|
|
@@ -1874,8 +1882,11 @@ Currently logged-in as ${this._username}.`
|
|
|
1874
1882
|
`Fetching ${this._username}'s scheduled reviews${course_id ? ` for course ${course_id}` : ""}.`
|
|
1875
1883
|
);
|
|
1876
1884
|
return reviews.rows.filter((r) => {
|
|
1877
|
-
if (r.id.startsWith(
|
|
1878
|
-
const date = import_moment5.default.utc(
|
|
1885
|
+
if (r.id.startsWith(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */])) {
|
|
1886
|
+
const date = import_moment5.default.utc(
|
|
1887
|
+
r.id.substr(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */].length),
|
|
1888
|
+
REVIEW_TIME_FORMAT
|
|
1889
|
+
);
|
|
1879
1890
|
if (targetDate.isAfter(date)) {
|
|
1880
1891
|
if (course_id === void 0 || r.doc.courseId === course_id) {
|
|
1881
1892
|
return true;
|
|
@@ -1990,7 +2001,8 @@ Currently logged-in as ${this._username}.`
|
|
|
1990
2001
|
const defaultConfig = {
|
|
1991
2002
|
_id: _BaseUser.DOC_IDS.CONFIG,
|
|
1992
2003
|
darkMode: false,
|
|
1993
|
-
likesConfetti: false
|
|
2004
|
+
likesConfetti: false,
|
|
2005
|
+
sessionTimeLimit: 5
|
|
1994
2006
|
};
|
|
1995
2007
|
try {
|
|
1996
2008
|
const cfg = await this.localDB.get(_BaseUser.DOC_IDS.CONFIG);
|
|
@@ -2063,7 +2075,8 @@ Currently logged-in as ${this._username}.`
|
|
|
2063
2075
|
setDBandQ() {
|
|
2064
2076
|
this.localDB = getLocalUserDB(this._username);
|
|
2065
2077
|
this.remoteDB = this.syncStrategy.setupRemoteDB(this._username);
|
|
2066
|
-
this.
|
|
2078
|
+
this.writeDB = this.syncStrategy.getWriteDB ? this.syncStrategy.getWriteDB(this._username) : this.localDB;
|
|
2079
|
+
this.updateQueue = new UpdateQueue(this.localDB, this.writeDB);
|
|
2067
2080
|
}
|
|
2068
2081
|
async init() {
|
|
2069
2082
|
_BaseUser._initialized = false;
|
|
@@ -2181,8 +2194,8 @@ Currently logged-in as ${this._username}.`
|
|
|
2181
2194
|
streak: 0,
|
|
2182
2195
|
bestInterval: 0
|
|
2183
2196
|
};
|
|
2184
|
-
|
|
2185
|
-
return initCardHistory;
|
|
2197
|
+
const putResult = await this.writeDB.put(initCardHistory);
|
|
2198
|
+
return { ...initCardHistory, _rev: putResult.rev };
|
|
2186
2199
|
} else {
|
|
2187
2200
|
throw new Error(`putCardRecord failed because of:
|
|
2188
2201
|
name:${reason.name}
|
|
@@ -2217,7 +2230,7 @@ Currently logged-in as ${this._username}.`
|
|
|
2217
2230
|
const deletePromises = duplicateDocIds.map(async (docId) => {
|
|
2218
2231
|
try {
|
|
2219
2232
|
const doc = await this.remoteDB.get(docId);
|
|
2220
|
-
await this.
|
|
2233
|
+
await this.writeDB.remove(doc);
|
|
2221
2234
|
log3(`Successfully removed duplicate review: ${docId}`);
|
|
2222
2235
|
} catch (error) {
|
|
2223
2236
|
log3(`Failed to remove duplicate review ${docId}: ${error}`);
|
|
@@ -2239,7 +2252,7 @@ Currently logged-in as ${this._username}.`
|
|
|
2239
2252
|
* @param course_id optional specification of individual course
|
|
2240
2253
|
*/
|
|
2241
2254
|
async getSeenCards(course_id) {
|
|
2242
|
-
let prefix =
|
|
2255
|
+
let prefix = DocTypePrefixes["CARDRECORD" /* CARDRECORD */];
|
|
2243
2256
|
if (course_id) {
|
|
2244
2257
|
prefix += course_id;
|
|
2245
2258
|
}
|
|
@@ -2248,8 +2261,8 @@ Currently logged-in as ${this._username}.`
|
|
|
2248
2261
|
});
|
|
2249
2262
|
const ret = [];
|
|
2250
2263
|
docs.rows.forEach((row) => {
|
|
2251
|
-
if (row.id.startsWith(
|
|
2252
|
-
ret.push(row.id.substr(
|
|
2264
|
+
if (row.id.startsWith(DocTypePrefixes["CARDRECORD" /* CARDRECORD */])) {
|
|
2265
|
+
ret.push(row.id.substr(DocTypePrefixes["CARDRECORD" /* CARDRECORD */].length));
|
|
2253
2266
|
}
|
|
2254
2267
|
});
|
|
2255
2268
|
return ret;
|
|
@@ -2261,7 +2274,7 @@ Currently logged-in as ${this._username}.`
|
|
|
2261
2274
|
async getHistory() {
|
|
2262
2275
|
const cards = await filterAllDocsByPrefix(
|
|
2263
2276
|
this.remoteDB,
|
|
2264
|
-
|
|
2277
|
+
DocTypePrefixes["CARDRECORD" /* CARDRECORD */],
|
|
2265
2278
|
{
|
|
2266
2279
|
include_docs: true,
|
|
2267
2280
|
attachments: false
|
|
@@ -2302,7 +2315,7 @@ Currently logged-in as ${this._username}.`
|
|
|
2302
2315
|
} catch (e) {
|
|
2303
2316
|
const err = e;
|
|
2304
2317
|
if (err.status === 404) {
|
|
2305
|
-
await this.
|
|
2318
|
+
await this.writeDB.put({
|
|
2306
2319
|
_id: _BaseUser.DOC_IDS.CLASSROOM_REGISTRATIONS,
|
|
2307
2320
|
registrations: []
|
|
2308
2321
|
});
|
|
@@ -2350,10 +2363,10 @@ Currently logged-in as ${this._username}.`
|
|
|
2350
2363
|
}
|
|
2351
2364
|
}
|
|
2352
2365
|
async scheduleCardReview(review) {
|
|
2353
|
-
return scheduleCardReviewLocal(this.
|
|
2366
|
+
return scheduleCardReviewLocal(this.writeDB, review);
|
|
2354
2367
|
}
|
|
2355
2368
|
async removeScheduledCardReview(reviewId) {
|
|
2356
|
-
return removeScheduledCardReviewLocal(this.
|
|
2369
|
+
return removeScheduledCardReviewLocal(this.writeDB, reviewId);
|
|
2357
2370
|
}
|
|
2358
2371
|
async registerForClassroom(_classId, _registerAs) {
|
|
2359
2372
|
return registerUserForClassroom(this._username, _classId, _registerAs);
|
|
@@ -2607,11 +2620,11 @@ var core_exports = {};
|
|
|
2607
2620
|
__export(core_exports, {
|
|
2608
2621
|
ContentNavigator: () => ContentNavigator,
|
|
2609
2622
|
DocType: () => DocType,
|
|
2623
|
+
DocTypePrefixes: () => DocTypePrefixes,
|
|
2610
2624
|
GuestUsername: () => GuestUsername,
|
|
2611
2625
|
Loggable: () => Loggable,
|
|
2612
2626
|
Navigators: () => Navigators,
|
|
2613
2627
|
areQuestionRecords: () => areQuestionRecords,
|
|
2614
|
-
cardHistoryPrefix: () => cardHistoryPrefix,
|
|
2615
2628
|
docIsDeleted: () => docIsDeleted,
|
|
2616
2629
|
getCardHistoryID: () => getCardHistoryID,
|
|
2617
2630
|
getStudySource: () => getStudySource,
|
|
@@ -2639,11 +2652,11 @@ init_core();
|
|
|
2639
2652
|
0 && (module.exports = {
|
|
2640
2653
|
ContentNavigator,
|
|
2641
2654
|
DocType,
|
|
2655
|
+
DocTypePrefixes,
|
|
2642
2656
|
GuestUsername,
|
|
2643
2657
|
Loggable,
|
|
2644
2658
|
Navigators,
|
|
2645
2659
|
areQuestionRecords,
|
|
2646
|
-
cardHistoryPrefix,
|
|
2647
2660
|
docIsDeleted,
|
|
2648
2661
|
getCardHistoryID,
|
|
2649
2662
|
getStudySource,
|