@vue-skuilder/express 0.1.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/.env.development +9 -0
- package/.prettierignore +4 -0
- package/.prettierrc +8 -0
- package/.vscode/launch.json +20 -0
- package/assets/classroomDesignDoc.js +24 -0
- package/assets/courseValidateDocUpdate.js +56 -0
- package/assets/get-tagsDesignDoc.json +9 -0
- package/babel.config.js +6 -0
- package/dist/app.d.ts +6 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +194 -0
- package/dist/app.js.map +1 -0
- package/dist/attachment-preprocessing/index.d.ts +11 -0
- package/dist/attachment-preprocessing/index.d.ts.map +1 -0
- package/dist/attachment-preprocessing/index.js +146 -0
- package/dist/attachment-preprocessing/index.js.map +1 -0
- package/dist/attachment-preprocessing/normalize.d.ts +7 -0
- package/dist/attachment-preprocessing/normalize.d.ts.map +1 -0
- package/dist/attachment-preprocessing/normalize.js +90 -0
- package/dist/attachment-preprocessing/normalize.js.map +1 -0
- package/dist/client-requests/classroom-requests.d.ts +26 -0
- package/dist/client-requests/classroom-requests.d.ts.map +1 -0
- package/dist/client-requests/classroom-requests.js +171 -0
- package/dist/client-requests/classroom-requests.js.map +1 -0
- package/dist/client-requests/course-requests.d.ts +10 -0
- package/dist/client-requests/course-requests.d.ts.map +1 -0
- package/dist/client-requests/course-requests.js +135 -0
- package/dist/client-requests/course-requests.js.map +1 -0
- package/dist/client.d.ts +31 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +70 -0
- package/dist/client.js.map +1 -0
- package/dist/couchdb/authentication.d.ts +4 -0
- package/dist/couchdb/authentication.d.ts.map +1 -0
- package/dist/couchdb/authentication.js +64 -0
- package/dist/couchdb/authentication.js.map +1 -0
- package/dist/couchdb/index.d.ts +18 -0
- package/dist/couchdb/index.d.ts.map +1 -0
- package/dist/couchdb/index.js +52 -0
- package/dist/couchdb/index.js.map +1 -0
- package/dist/design-docs.d.ts +63 -0
- package/dist/design-docs.d.ts.map +1 -0
- package/dist/design-docs.js +90 -0
- package/dist/design-docs.js.map +1 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +62 -0
- package/dist/logger.js.map +1 -0
- package/dist/routes/logs.d.ts +3 -0
- package/dist/routes/logs.d.ts.map +1 -0
- package/dist/routes/logs.js +274 -0
- package/dist/routes/logs.js.map +1 -0
- package/dist/utils/env.d.ts +10 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +38 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/processQueue.d.ts +39 -0
- package/dist/utils/processQueue.d.ts.map +1 -0
- package/dist/utils/processQueue.js +175 -0
- package/dist/utils/processQueue.js.map +1 -0
- package/eslint.config.js +19 -0
- package/jest.config.ts +24 -0
- package/package.json +74 -0
- package/src/app.ts +246 -0
- package/src/attachment-preprocessing/index.ts +204 -0
- package/src/attachment-preprocessing/normalize.ts +123 -0
- package/src/client-requests/classroom-requests.ts +234 -0
- package/src/client-requests/course-requests.ts +188 -0
- package/src/client.ts +97 -0
- package/src/couchdb/authentication.ts +85 -0
- package/src/couchdb/index.ts +76 -0
- package/src/design-docs.ts +107 -0
- package/src/logger.ts +75 -0
- package/src/routes/logs.ts +289 -0
- package/src/utils/env.ts +51 -0
- package/src/utils/processQueue.ts +218 -0
- package/test/client.test.ts +144 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ClassroomConfig, Status } from '@vue-skuilder/common';
|
|
2
|
+
import AsyncProcessQueue from '../utils/processQueue.js';
|
|
3
|
+
export declare const CLASSROOM_DB_LOOKUP = "classdb-lookup";
|
|
4
|
+
export declare const ClassroomLeaveQueue: AsyncProcessQueue<{
|
|
5
|
+
classID: string;
|
|
6
|
+
} & {
|
|
7
|
+
username: string;
|
|
8
|
+
}, import("@vue-skuilder/common").IServerResponse | null>;
|
|
9
|
+
export declare const ClassroomJoinQueue: AsyncProcessQueue<{
|
|
10
|
+
joinCode: string;
|
|
11
|
+
registerAs: "student" | "teacher" | "aide" | "admin";
|
|
12
|
+
user: string;
|
|
13
|
+
}, {
|
|
14
|
+
errorText?: string;
|
|
15
|
+
status: Status;
|
|
16
|
+
ok: boolean;
|
|
17
|
+
id_course: string;
|
|
18
|
+
course_name: string;
|
|
19
|
+
} | null>;
|
|
20
|
+
export declare const ClassroomCreationQueue: AsyncProcessQueue<ClassroomConfig, {
|
|
21
|
+
status: Status;
|
|
22
|
+
ok: boolean;
|
|
23
|
+
joincode: string;
|
|
24
|
+
uuid: string;
|
|
25
|
+
} | null>;
|
|
26
|
+
//# sourceMappingURL=classroom-requests.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classroom-requests.d.ts","sourceRoot":"","sources":["../../src/client-requests/classroom-requests.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EAIf,MAAM,EACP,MAAM,sBAAsB,CAAC;AAO9B,OAAO,iBAA6B,MAAM,0BAA0B,CAAC;AAGrE,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAuMpD,eAAO,MAAM,mBAAmB;;;cAEO,MAAM;yDAE5B,CAAC;AAElB,eAAO,MAAM,kBAAkB;;;;;;;;;;SAIf,CAAC;AAEjB,eAAO,MAAM,sBAAsB;;;;;SAIjB,CAAC"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import hashids from 'hashids';
|
|
2
|
+
import { Status, } from '@vue-skuilder/common';
|
|
3
|
+
import { classroomDbDesignDoc } from '../design-docs.js';
|
|
4
|
+
import CouchDB, { docCount, useOrCreateDB, } from '../couchdb/index.js';
|
|
5
|
+
import AsyncProcessQueue from '../utils/processQueue.js';
|
|
6
|
+
import logger from '../logger.js';
|
|
7
|
+
export const CLASSROOM_DB_LOOKUP = 'classdb-lookup';
|
|
8
|
+
const CLASSROOM_CONFIG = 'ClassroomConfig';
|
|
9
|
+
// async function deleteClassroom(_classroom_id: string) {}
|
|
10
|
+
async function getClassID(joinCode) {
|
|
11
|
+
try {
|
|
12
|
+
const doc = await (await useOrCreateDB(CLASSROOM_DB_LOOKUP)).get(joinCode);
|
|
13
|
+
return doc.uuid;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async function getClassroomConfig(id) {
|
|
20
|
+
return (await useOrCreateDB(getClassDBNames(id).studentDB)).get(CLASSROOM_CONFIG);
|
|
21
|
+
}
|
|
22
|
+
async function writeClassroomConfig(config, classID) {
|
|
23
|
+
logger.info(`Writing config for class: ${classID}`);
|
|
24
|
+
const dbNames = getClassDBNames(classID);
|
|
25
|
+
const studentDB = await useOrCreateDB(dbNames.studentDB);
|
|
26
|
+
const teacherDB = await useOrCreateDB(dbNames.teacherDB);
|
|
27
|
+
return Promise.all([
|
|
28
|
+
studentDB
|
|
29
|
+
.get(CLASSROOM_CONFIG)
|
|
30
|
+
.then((doc) => {
|
|
31
|
+
return studentDB.insert({
|
|
32
|
+
_id: CLASSROOM_CONFIG,
|
|
33
|
+
_rev: doc._rev,
|
|
34
|
+
...config,
|
|
35
|
+
});
|
|
36
|
+
})
|
|
37
|
+
.catch((_err) => {
|
|
38
|
+
return studentDB.insert({
|
|
39
|
+
_id: CLASSROOM_CONFIG,
|
|
40
|
+
...config,
|
|
41
|
+
});
|
|
42
|
+
}),
|
|
43
|
+
teacherDB
|
|
44
|
+
.get(CLASSROOM_CONFIG)
|
|
45
|
+
.then((doc) => {
|
|
46
|
+
return teacherDB.insert({
|
|
47
|
+
_id: CLASSROOM_CONFIG,
|
|
48
|
+
_rev: doc._rev,
|
|
49
|
+
...config,
|
|
50
|
+
});
|
|
51
|
+
})
|
|
52
|
+
.catch((_err) => {
|
|
53
|
+
return teacherDB.insert({
|
|
54
|
+
_id: CLASSROOM_CONFIG,
|
|
55
|
+
...config,
|
|
56
|
+
});
|
|
57
|
+
}),
|
|
58
|
+
]);
|
|
59
|
+
}
|
|
60
|
+
function getClassDBNames(classId) {
|
|
61
|
+
return {
|
|
62
|
+
studentDB: `classdb-student-${classId}`,
|
|
63
|
+
teacherDB: `classdb-teacher-${classId}`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
async function createClassroom(config) {
|
|
67
|
+
logger.info(`CreateClass Request:
|
|
68
|
+
${JSON.stringify(config)}`);
|
|
69
|
+
const num = (await docCount(CLASSROOM_DB_LOOKUP)) + 1; //
|
|
70
|
+
const uuid = (await CouchDB.uuids(1)).uuids[0];
|
|
71
|
+
const hasher = new hashids('', 6, 'abcdefghijklmnopqrstuvwxyz123456789');
|
|
72
|
+
const studentDbName = `classdb-student-${uuid}`;
|
|
73
|
+
const teacherDbName = `classdb-teacher-${uuid}`;
|
|
74
|
+
config.joinCode = hasher.encode(num);
|
|
75
|
+
const security = {
|
|
76
|
+
// _id: '_security',
|
|
77
|
+
admins: {
|
|
78
|
+
names: [],
|
|
79
|
+
roles: [],
|
|
80
|
+
},
|
|
81
|
+
members: {
|
|
82
|
+
names: config.teachers,
|
|
83
|
+
roles: [],
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
const [studentdb, teacherdb, lookup] = await Promise.all([
|
|
87
|
+
useOrCreateDB(studentDbName),
|
|
88
|
+
useOrCreateDB(teacherDbName),
|
|
89
|
+
useOrCreateDB('classdb-lookup'),
|
|
90
|
+
]);
|
|
91
|
+
await Promise.all([
|
|
92
|
+
studentdb.insert({
|
|
93
|
+
validate_doc_update: classroomDbDesignDoc,
|
|
94
|
+
}, '_design/_auth'),
|
|
95
|
+
// studentdb.insert(security, '_security'),
|
|
96
|
+
teacherdb.insert(security, '_security'),
|
|
97
|
+
lookup.insert({
|
|
98
|
+
num,
|
|
99
|
+
uuid,
|
|
100
|
+
}, config.joinCode),
|
|
101
|
+
writeClassroomConfig(config, uuid),
|
|
102
|
+
]);
|
|
103
|
+
const res = {
|
|
104
|
+
ok: true,
|
|
105
|
+
status: 'ok',
|
|
106
|
+
};
|
|
107
|
+
const ret = {
|
|
108
|
+
joincode: config.joinCode,
|
|
109
|
+
uuid: uuid,
|
|
110
|
+
...res,
|
|
111
|
+
};
|
|
112
|
+
logger.info(JSON.stringify(ret));
|
|
113
|
+
return ret;
|
|
114
|
+
}
|
|
115
|
+
async function leaveClassroom(req) {
|
|
116
|
+
const cfg = await getClassroomConfig(req.classID);
|
|
117
|
+
if (cfg) {
|
|
118
|
+
const index = cfg.students.indexOf(req.username);
|
|
119
|
+
if (index !== -1) {
|
|
120
|
+
cfg.students.splice(index, 1);
|
|
121
|
+
}
|
|
122
|
+
await writeClassroomConfig(cfg, req.classID);
|
|
123
|
+
return {
|
|
124
|
+
status: Status.ok,
|
|
125
|
+
ok: true,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
return {
|
|
130
|
+
status: Status.error,
|
|
131
|
+
ok: false,
|
|
132
|
+
errorText: 'Course with this ID not found.',
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function joinClassroom(req) {
|
|
137
|
+
const classID = await getClassID(req.joinCode);
|
|
138
|
+
if (classID) {
|
|
139
|
+
const classDBNames = getClassDBNames(classID);
|
|
140
|
+
void (await useOrCreateDB(classDBNames.studentDB)).get('ClassroomConfig');
|
|
141
|
+
logger.info(`joinClassroom running...
|
|
142
|
+
\tRequest: ${JSON.stringify(req)}`);
|
|
143
|
+
const cfg = await getClassroomConfig(classID);
|
|
144
|
+
if (req.registerAs === 'student') {
|
|
145
|
+
if (cfg.students.indexOf(req.user) === -1) {
|
|
146
|
+
cfg.students.push(req.user);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
await writeClassroomConfig(cfg, classID);
|
|
150
|
+
const res = {
|
|
151
|
+
ok: true,
|
|
152
|
+
status: Status.ok,
|
|
153
|
+
id_course: classID,
|
|
154
|
+
course_name: cfg.name,
|
|
155
|
+
};
|
|
156
|
+
return res;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
return {
|
|
160
|
+
ok: false,
|
|
161
|
+
status: Status.error,
|
|
162
|
+
id_course: '',
|
|
163
|
+
course_name: '',
|
|
164
|
+
errorText: 'No course found with this joincode!',
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
export const ClassroomLeaveQueue = new AsyncProcessQueue(leaveClassroom);
|
|
169
|
+
export const ClassroomJoinQueue = new AsyncProcessQueue(joinClassroom);
|
|
170
|
+
export const ClassroomCreationQueue = new AsyncProcessQueue(createClassroom);
|
|
171
|
+
//# sourceMappingURL=classroom-requests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classroom-requests.js","sourceRoot":"","sources":["../../src/client-requests/classroom-requests.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAKL,MAAM,GACP,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,OAAO,EAAE,EAEd,QAAQ,EACR,aAAa,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,iBAA6B,MAAM,0BAA0B,CAAC;AACrE,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AACpD,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAO3C,2DAA2D;AAE3D,KAAK,UAAU,UAAU,CAAC,QAAgB;IACxC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3E,OAAQ,GAA6B,CAAC,IAAI,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,EAAU;IAC1C,OAAO,CAAC,MAAM,aAAa,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAC7D,gBAAgB,CACa,CAAC;AAClC,CAAC;AACD,KAAK,UAAU,oBAAoB,CAAC,MAAuB,EAAE,OAAe;IAC1E,MAAM,CAAC,IAAI,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEzD,OAAO,OAAO,CAAC,GAAG,CAAC;QACjB,SAAS;aACN,GAAG,CAAC,gBAAgB,CAAC;aACrB,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACZ,OAAO,SAAS,CAAC,MAAM,CAAC;gBACtB,GAAG,EAAE,gBAAgB;gBACrB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,GAAG,MAAM;aACV,CAAC,CAAC;QACL,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE;YACd,OAAO,SAAS,CAAC,MAAM,CAAC;gBACtB,GAAG,EAAE,gBAAgB;gBACrB,GAAG,MAAM;aACV,CAAC,CAAC;QACL,CAAC,CAAC;QACJ,SAAS;aACN,GAAG,CAAC,gBAAgB,CAAC;aACrB,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACZ,OAAO,SAAS,CAAC,MAAM,CAAC;gBACtB,GAAG,EAAE,gBAAgB;gBACrB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,GAAG,MAAM;aACV,CAAC,CAAC;QACL,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE;YACd,OAAO,SAAS,CAAC,MAAM,CAAC;gBACtB,GAAG,EAAE,gBAAgB;gBACrB,GAAG,MAAM;aACV,CAAC,CAAC;QACL,CAAC,CAAC;KACL,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,OAAe;IAItC,OAAO;QACL,SAAS,EAAE,mBAAmB,OAAO,EAAE;QACvC,SAAS,EAAE,mBAAmB,OAAO,EAAE;KACxC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,MAAuB;IACpD,MAAM,CAAC,IAAI,CAAC;MACR,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAE9B,MAAM,GAAG,GAAG,CAAC,MAAM,QAAQ,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;IACzD,MAAM,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,qCAAqC,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,mBAAmB,IAAI,EAAE,CAAC;IAChD,MAAM,aAAa,GAAG,mBAAmB,IAAI,EAAE,CAAC;IAChD,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAErC,MAAM,QAAQ,GAAmB;QAC/B,oBAAoB;QACpB,MAAM,EAAE;YACN,KAAK,EAAE,EAAE;YACT,KAAK,EAAE,EAAE;SACV;QACD,OAAO,EAAE;YACP,KAAK,EAAE,MAAM,CAAC,QAAQ;YACtB,KAAK,EAAE,EAAE;SACV;KACF,CAAC;IAEF,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACvD,aAAa,CAAC,aAAa,CAAC;QAC5B,aAAa,CAAC,aAAa,CAAC;QAC5B,aAAa,CAAC,gBAAgB,CAAC;KAChC,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,SAAS,CAAC,MAAM,CACd;YACE,mBAAmB,EAAE,oBAAoB;SACpB,EACvB,eAAe,CAChB;QACD,2CAA2C;QAC3C,SAAS,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC;QACvC,MAAM,CAAC,MAAM,CACX;YACE,GAAG;YACH,IAAI;SACiB,EACvB,MAAM,CAAC,QAAQ,CAChB;QACD,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC;KACnC,CAAC,CAAC;IAEH,MAAM,GAAG,GAAW;QAClB,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,IAAI;KACb,CAAC;IACF,MAAM,GAAG,GAAG;QACV,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,IAAI,EAAE,IAAI;QACV,GAAG,GAAG;KACP,CAAC;IAEF,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IAEjC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,GAAkD;IAElD,MAAM,GAAG,GAAoB,MAAM,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACnE,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAChC,CAAC;QAED,MAAM,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QAE7C,OAAO;YACL,MAAM,EAAE,MAAM,CAAC,EAAE;YACjB,EAAE,EAAE,IAAI;SACT,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO;YACL,MAAM,EAAE,MAAM,CAAC,KAAK;YACpB,EAAE,EAAE,KAAK;YACT,SAAS,EAAE,gCAAgC;SAC5C,CAAC;IACJ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,GAA0B;IACrD,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/C,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QAE9C,KAAK,CAAC,MAAM,aAAa,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAE1E,MAAM,CAAC,IAAI,CAAC;qBACK,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAExC,MAAM,GAAG,GAAoB,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAE/D,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACjC,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC1C,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;QAED,MAAM,oBAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAEzC,MAAM,GAAG,GAA8B;YACrC,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,MAAM,CAAC,EAAE;YACjB,SAAS,EAAE,OAAO;YAClB,WAAW,EAAE,GAAG,CAAC,IAAI;SACtB,CAAC;QACF,OAAO,GAAG,CAAC;IACb,CAAC;SAAM,CAAC;QACN,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,MAAM,CAAC,KAAK;YACpB,SAAS,EAAE,EAAE;YACb,WAAW,EAAE,EAAE;YACf,SAAS,EAAE,qCAAqC;SACjD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,iBAAiB,CAItD,cAAc,CAAC,CAAC;AAElB,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,iBAAiB,CAIrD,aAAa,CAAC,CAAC;AAEjB,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,iBAAiB,CAIzD,eAAe,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CreateCourse } from '@vue-skuilder/common';
|
|
2
|
+
import AsyncProcessQueue from '../utils/processQueue.js';
|
|
3
|
+
export declare function initCourseDBDesignDocInsert(): Promise<void>;
|
|
4
|
+
export type CreateCourseResp = CreateCourse['response'];
|
|
5
|
+
export declare const CourseCreationQueue: AsyncProcessQueue<import("@vue-skuilder/common").CourseConfig, {
|
|
6
|
+
status: import("@vue-skuilder/common").Status;
|
|
7
|
+
ok: boolean;
|
|
8
|
+
courseID: string;
|
|
9
|
+
} | null>;
|
|
10
|
+
//# sourceMappingURL=course-requests.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"course-requests.d.ts","sourceRoot":"","sources":["../../src/client-requests/course-requests.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,iBAA6B,MAAM,0BAA0B,CAAC;AAgDrE,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CA4CjE;AAqFD,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;AAExD,eAAO,MAAM,mBAAmB;;;;SAIjB,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { log } from 'util';
|
|
2
|
+
import CouchDB from '../couchdb/index.js';
|
|
3
|
+
import { postProcessCourse } from '../attachment-preprocessing/index.js';
|
|
4
|
+
import AsyncProcessQueue from '../utils/processQueue.js';
|
|
5
|
+
import logger from '../logger.js';
|
|
6
|
+
import { CourseLookup } from '@vue-skuilder/db';
|
|
7
|
+
import { courseDBDesignDocs } from '../design-docs.js';
|
|
8
|
+
function getCourseDBName(courseID) {
|
|
9
|
+
return `coursedb-${courseID}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Inserts a design document into a course database.
|
|
13
|
+
* @param courseID - The ID of the course database.
|
|
14
|
+
* @param doc
|
|
15
|
+
*/
|
|
16
|
+
function insertDesignDoc(courseID, doc) {
|
|
17
|
+
const courseDB = CouchDB.use(courseID);
|
|
18
|
+
courseDB
|
|
19
|
+
.get(doc._id)
|
|
20
|
+
.then((priorDoc) => {
|
|
21
|
+
void courseDB.insert({
|
|
22
|
+
...doc,
|
|
23
|
+
_rev: priorDoc._rev,
|
|
24
|
+
});
|
|
25
|
+
})
|
|
26
|
+
.catch(() => {
|
|
27
|
+
void courseDB
|
|
28
|
+
.insert(doc)
|
|
29
|
+
.catch((e) => {
|
|
30
|
+
log(`Error inserting design doc ${doc._id} in course-${courseID}: ${e}`);
|
|
31
|
+
})
|
|
32
|
+
.then((resp) => {
|
|
33
|
+
if (resp && resp.ok) {
|
|
34
|
+
log(`CourseDB design doc inserted into course-${courseID}`);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export async function initCourseDBDesignDocInsert() {
|
|
40
|
+
const courses = await CourseLookup.allCourses();
|
|
41
|
+
courses.forEach((c) => {
|
|
42
|
+
// Insert design docs
|
|
43
|
+
courseDBDesignDocs.forEach((dd) => {
|
|
44
|
+
insertDesignDoc(getCourseDBName(c._id), dd);
|
|
45
|
+
});
|
|
46
|
+
// Update security object for public courses
|
|
47
|
+
const courseDB = CouchDB.use(getCourseDBName(c._id));
|
|
48
|
+
courseDB
|
|
49
|
+
.get('CourseConfig')
|
|
50
|
+
.then((configDoc) => {
|
|
51
|
+
if (configDoc.public === true) {
|
|
52
|
+
const secObj = {
|
|
53
|
+
admins: {
|
|
54
|
+
names: [],
|
|
55
|
+
roles: [],
|
|
56
|
+
},
|
|
57
|
+
members: {
|
|
58
|
+
names: [], // Empty array for public courses to allow all users access
|
|
59
|
+
roles: [],
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
courseDB
|
|
63
|
+
// @ts-expect-error allow insertion of _security document.
|
|
64
|
+
// db scoped as ConfigDoc to make the read easier.
|
|
65
|
+
.insert(secObj, '_security')
|
|
66
|
+
.then(() => {
|
|
67
|
+
logger.info(`Updated security settings for public course ${c._id}`);
|
|
68
|
+
})
|
|
69
|
+
.catch((e) => {
|
|
70
|
+
logger.error(`Error updating security for public course ${c._id}: ${e}`);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
.catch((e) => {
|
|
75
|
+
logger.error(`Error getting CourseConfig for ${c._id}: ${e}`);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async function createCourse(cfg) {
|
|
80
|
+
cfg.courseID = await CourseLookup.add(cfg.name);
|
|
81
|
+
if (!cfg.courseID) {
|
|
82
|
+
throw new Error('Course ID not found');
|
|
83
|
+
}
|
|
84
|
+
const courseDBName = getCourseDBName(cfg.courseID);
|
|
85
|
+
const dbCreation = await CouchDB.db.create(courseDBName);
|
|
86
|
+
if (dbCreation.ok) {
|
|
87
|
+
const courseDB = CouchDB.use(courseDBName);
|
|
88
|
+
courseDB
|
|
89
|
+
.insert({
|
|
90
|
+
_id: 'CourseConfig',
|
|
91
|
+
...cfg,
|
|
92
|
+
})
|
|
93
|
+
.catch((e) => {
|
|
94
|
+
logger.error(`Error inserting CourseConfig for course ${cfg.courseID}:`, e);
|
|
95
|
+
});
|
|
96
|
+
// insert the tags, elo, etc view docs
|
|
97
|
+
courseDBDesignDocs.forEach((doc) => {
|
|
98
|
+
courseDB.insert(doc).catch((e) => {
|
|
99
|
+
logger.error(`Error inserting design doc for course ${cfg.courseID}:`, e);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
// Configure security for both public and private courses
|
|
103
|
+
const secObj = {
|
|
104
|
+
admins: {
|
|
105
|
+
names: [],
|
|
106
|
+
roles: [],
|
|
107
|
+
},
|
|
108
|
+
members: {
|
|
109
|
+
names: cfg.public ? [] : [cfg.creator], // Empty array for public courses to allow all users access
|
|
110
|
+
roles: [],
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
courseDB
|
|
114
|
+
.insert(secObj, '_security')
|
|
115
|
+
.then(() => {
|
|
116
|
+
logger.info(`Successfully set security for ${cfg.public ? 'public' : 'private'} course ${cfg.courseID}`);
|
|
117
|
+
})
|
|
118
|
+
.catch((e) => {
|
|
119
|
+
logger.error(`Error inserting security object for course ${cfg.courseID}:`, e);
|
|
120
|
+
});
|
|
121
|
+
// Design documents including validation are inserted via courseDBDesignDocs
|
|
122
|
+
logger.info(`Validation design document will be inserted for course ${cfg.courseID}`);
|
|
123
|
+
}
|
|
124
|
+
// follow the course so that user-uploaded content goes through
|
|
125
|
+
// post-processing
|
|
126
|
+
postProcessCourse(cfg.courseID);
|
|
127
|
+
return {
|
|
128
|
+
ok: dbCreation.ok ?? false,
|
|
129
|
+
status: 'ok',
|
|
130
|
+
// @ts-expect-error courseID required for runtime but not in Result interface - see sideQuest.md
|
|
131
|
+
courseID: cfg.courseID,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
export const CourseCreationQueue = new AsyncProcessQueue(createCourse);
|
|
135
|
+
//# sourceMappingURL=course-requests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"course-requests.js","sourceRoot":"","sources":["../../src/client-requests/course-requests.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AxiosBasicCredentials, AxiosResponse } from 'axios';
|
|
2
|
+
import { AddCourseDataPayload, CourseConfig } from '@vue-skuilder/common';
|
|
3
|
+
import { CreateCourseResp } from './client-requests/course-requests.js';
|
|
4
|
+
export default class SkldrClient {
|
|
5
|
+
server: string;
|
|
6
|
+
constructor(server: string);
|
|
7
|
+
/**
|
|
8
|
+
* Create a new course.
|
|
9
|
+
*/
|
|
10
|
+
createCourse(cfg: CourseConfig, auth?: AxiosBasicCredentials): Promise<AxiosResponse<CreateCourseResp>>;
|
|
11
|
+
/**
|
|
12
|
+
* Creates a client to interact with the specified course.
|
|
13
|
+
*/
|
|
14
|
+
getCourseClient(id: string): SkldrCourseClient;
|
|
15
|
+
/**
|
|
16
|
+
* @returns a list of all courses on the server in `id - name` format.
|
|
17
|
+
*/
|
|
18
|
+
getCourses(): Promise<string[]>;
|
|
19
|
+
getVersion(): Promise<string>;
|
|
20
|
+
getRoles(): Promise<string[]>;
|
|
21
|
+
}
|
|
22
|
+
declare class SkldrCourseClient {
|
|
23
|
+
id: string;
|
|
24
|
+
server: string;
|
|
25
|
+
constructor(server: string, id: string);
|
|
26
|
+
addData(data: AddCourseDataPayload): Promise<Express.Response>;
|
|
27
|
+
deleteCourse(auth?: AxiosBasicCredentials): Promise<Express.Response>;
|
|
28
|
+
getConfig(): Promise<CourseConfig>;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACpE,OAAO,EACL,oBAAoB,EACpB,YAAY,EAGb,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAExE,MAAM,CAAC,OAAO,OAAO,WAAW;IAC9B,MAAM,EAAE,MAAM,CAAC;gBAEH,MAAM,EAAE,MAAM;IAI1B;;OAEG;IACG,YAAY,CAChB,GAAG,EAAE,YAAY,EACjB,IAAI,CAAC,EAAE,qBAAqB,GAC3B,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAmB3C;;OAEG;IACH,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB;IAI9C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAI/B,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7B,QAAQ,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAIpC;AAED,cAAM,iBAAiB;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;gBAEH,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAKtC,OAAO,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;IAOxD,YAAY,CAAC,IAAI,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;IASrE,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;CAMzC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { ServerRequestType, } from '@vue-skuilder/common';
|
|
3
|
+
export default class SkldrClient {
|
|
4
|
+
server;
|
|
5
|
+
constructor(server) {
|
|
6
|
+
this.server = server;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Create a new course.
|
|
10
|
+
*/
|
|
11
|
+
async createCourse(cfg, auth) {
|
|
12
|
+
const request = {
|
|
13
|
+
type: ServerRequestType.CREATE_COURSE,
|
|
14
|
+
data: cfg,
|
|
15
|
+
user: 'apiClient',
|
|
16
|
+
response: null,
|
|
17
|
+
};
|
|
18
|
+
const resp = await axios.post(`${this.server}`, request, {
|
|
19
|
+
auth: auth,
|
|
20
|
+
});
|
|
21
|
+
return resp;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates a client to interact with the specified course.
|
|
25
|
+
*/
|
|
26
|
+
getCourseClient(id) {
|
|
27
|
+
return new SkldrCourseClient(this.server, id);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* @returns a list of all courses on the server in `id - name` format.
|
|
31
|
+
*/
|
|
32
|
+
async getCourses() {
|
|
33
|
+
const resp = await axios.get(`${this.server}/courses`);
|
|
34
|
+
return resp.data;
|
|
35
|
+
}
|
|
36
|
+
async getVersion() {
|
|
37
|
+
const resp = await axios.get(`${this.server}/version`);
|
|
38
|
+
return resp.data;
|
|
39
|
+
}
|
|
40
|
+
async getRoles() {
|
|
41
|
+
const resp = await axios.get(`${this.server}/roles`);
|
|
42
|
+
return resp.data;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
class SkldrCourseClient {
|
|
46
|
+
id;
|
|
47
|
+
server;
|
|
48
|
+
constructor(server, id) {
|
|
49
|
+
this.server = server;
|
|
50
|
+
this.id = id;
|
|
51
|
+
}
|
|
52
|
+
addData(data) {
|
|
53
|
+
return axios.post(`${this.server}/${this.id}`, {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
body: data,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async deleteCourse(auth) {
|
|
59
|
+
// [ ] Consider auth / permanence of "destructive" actions
|
|
60
|
+
return axios.delete(`${this.server}/course/${this.id}`, {
|
|
61
|
+
auth,
|
|
62
|
+
});
|
|
63
|
+
// [ ] remove also from the `coursedb-lookup` database (?)
|
|
64
|
+
}
|
|
65
|
+
async getConfig() {
|
|
66
|
+
const resp = await axios.get(`${this.server}/course/${this.id}/config`);
|
|
67
|
+
return resp.data;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AACpE,OAAO,EAIL,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAG9B,MAAM,CAAC,OAAO,OAAO,WAAW;IAC9B,MAAM,CAAS;IAEf,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAChB,GAAiB,EACjB,IAA4B;QAE5B,MAAM,OAAO,GAAiB;YAC5B,IAAI,EAAE,iBAAiB,CAAC,aAAa;YACrC,IAAI,EAAE,GAAG;YACT,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE,IAAI;SACf,CAAC;QAEF,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAC3B,GAAG,IAAI,CAAC,MAAM,EAAE,EAChB,OAAO,EACP;YACE,IAAI,EAAE,IAAI;SACX,CACF,CAAC;QAEF,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,EAAU;QACxB,OAAO,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAChD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,UAAU,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IACD,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,UAAU,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IACD,KAAK,CAAC,QAAQ;QACZ,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,QAAQ,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,iBAAiB;IACrB,EAAE,CAAS;IACX,MAAM,CAAS;IAEf,YAAY,MAAc,EAAE,EAAU;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACf,CAAC;IAED,OAAO,CAAC,IAA0B;QAChC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,EAAE,EAAE;YAC7C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,IAA4B;QAC7C,0DAA0D;QAC1D,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,WAAW,IAAI,CAAC,EAAE,EAAE,EAAE;YACtD,IAAI;SACL,CAAC,CAAC;QAEH,0DAA0D;IAC5D,CAAC;IAED,KAAK,CAAC,SAAS;QACb,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,CAC1B,GAAG,IAAI,CAAC,MAAM,WAAW,IAAI,CAAC,EAAE,SAAS,CAC1C,CAAC;QACF,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { VueClientRequest } from '../app.js';
|
|
2
|
+
export declare function requestIsAdminAuthenticated(req: VueClientRequest): Promise<boolean>;
|
|
3
|
+
export declare function requestIsAuthenticated(req: VueClientRequest): Promise<boolean>;
|
|
4
|
+
//# sourceMappingURL=authentication.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authentication.d.ts","sourceRoot":"","sources":["../../src/couchdb/authentication.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAgB7C,wBAAsB,2BAA2B,CAAC,GAAG,EAAE,gBAAgB,oBAwBtE;AAMD,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,gBAAgB,oBAoCjE"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import Nano from 'nano';
|
|
2
|
+
import { COUCH_URL_WITH_PROTOCOL } from './index.js';
|
|
3
|
+
import logger from '../logger.js';
|
|
4
|
+
export async function requestIsAdminAuthenticated(req) {
|
|
5
|
+
logRequest(req);
|
|
6
|
+
const username = req.body.user;
|
|
7
|
+
const authCookie = req.cookies.AuthSession ? req.cookies.AuthSession : 'null';
|
|
8
|
+
if (authCookie === 'null') {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
return await Nano({
|
|
13
|
+
cookie: 'AuthSession=' + authCookie,
|
|
14
|
+
url: COUCH_URL_WITH_PROTOCOL,
|
|
15
|
+
})
|
|
16
|
+
.session()
|
|
17
|
+
.then((s) => {
|
|
18
|
+
logger.info(`AuthUser: ${JSON.stringify(s)}`);
|
|
19
|
+
const isAdmin = s.userCtx.roles.indexOf('_admin') !== -1;
|
|
20
|
+
const isLoggedInUser = s.userCtx.name === username;
|
|
21
|
+
return isAdmin && isLoggedInUser;
|
|
22
|
+
})
|
|
23
|
+
.catch((_err) => {
|
|
24
|
+
return false;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function logRequest(req) {
|
|
29
|
+
logger.info(`${req.body.type} request from ${req.body.user}...`);
|
|
30
|
+
}
|
|
31
|
+
export async function requestIsAuthenticated(req) {
|
|
32
|
+
logRequest(req);
|
|
33
|
+
if (req.headers.authorization) {
|
|
34
|
+
const auth = Buffer.from(req.headers.authorization.split(' ')[1], 'base64')
|
|
35
|
+
.toString('ascii')
|
|
36
|
+
.split(':');
|
|
37
|
+
const username = auth[0];
|
|
38
|
+
const password = auth[1];
|
|
39
|
+
const authResult = await Nano({
|
|
40
|
+
url: COUCH_URL_WITH_PROTOCOL,
|
|
41
|
+
}).auth(username, password);
|
|
42
|
+
return authResult.ok;
|
|
43
|
+
}
|
|
44
|
+
const username = req.body.user;
|
|
45
|
+
const authCookie = req.cookies.AuthSession ? req.cookies.AuthSession : 'null';
|
|
46
|
+
if (authCookie === 'null') {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
return await Nano({
|
|
51
|
+
cookie: 'AuthSession=' + authCookie,
|
|
52
|
+
url: COUCH_URL_WITH_PROTOCOL,
|
|
53
|
+
})
|
|
54
|
+
.session()
|
|
55
|
+
.then((s) => {
|
|
56
|
+
logger.info(`AuthUser: ${JSON.stringify(s)}`);
|
|
57
|
+
return s.userCtx.name === username;
|
|
58
|
+
})
|
|
59
|
+
.catch((_err) => {
|
|
60
|
+
return false;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=authentication.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authentication.js","sourceRoot":"","sources":["../../src/couchdb/authentication.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Nano from 'nano';
|
|
2
|
+
declare const CouchDB: Nano.ServerScope;
|
|
3
|
+
export declare function useOrCreateCourseDB(courseID: string): Promise<Nano.DocumentScope<unknown>>;
|
|
4
|
+
export declare function useOrCreateDB<T>(dbName: string): Promise<Nano.DocumentScope<T>>;
|
|
5
|
+
export declare function docCount(dbName: string): Promise<number>;
|
|
6
|
+
export interface SecurityObject extends Nano.MaybeDocument {
|
|
7
|
+
admins: {
|
|
8
|
+
names: string[];
|
|
9
|
+
roles: string[];
|
|
10
|
+
};
|
|
11
|
+
members: {
|
|
12
|
+
names: string[];
|
|
13
|
+
roles: string[];
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export declare const COUCH_URL_WITH_PROTOCOL: string;
|
|
17
|
+
export default CouchDB;
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/couchdb/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAyBxB,QAAA,MAAM,OAAO,kBAA2B,CAAC;AAEzC,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAEhG;AAMD,wBAAsB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAmBrF;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9D;AAED,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,aAAa;IACxD,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;IACF,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;CACH;AAED,eAAO,MAAM,uBAAuB,QAAgD,CAAC;AAErF,eAAe,OAAO,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import Nano from 'nano';
|
|
2
|
+
import process from 'process';
|
|
3
|
+
import ENV from '../utils/env.js';
|
|
4
|
+
import logger from '../logger.js';
|
|
5
|
+
const url = ENV.COUCHDB_SERVER;
|
|
6
|
+
const protocol = ENV.COUCHDB_PROTOCOL;
|
|
7
|
+
const admin = {
|
|
8
|
+
username: ENV.COUCHDB_ADMIN,
|
|
9
|
+
password: ENV.COUCHDB_PASSWORD,
|
|
10
|
+
};
|
|
11
|
+
const credentialCouchURL = `${protocol}://${admin.username}:${admin.password}@${url}`;
|
|
12
|
+
logger.info('WORKING DIRECTORY: ' + process.cwd());
|
|
13
|
+
logger.info(`CouchDB url: ${url}
|
|
14
|
+
protocol: ${protocol}
|
|
15
|
+
credentials:
|
|
16
|
+
\tusername: ${admin.username}
|
|
17
|
+
\tpassword: *****
|
|
18
|
+
credUrl: ${protocol}://${admin.username}:*****@${url}
|
|
19
|
+
`);
|
|
20
|
+
const CouchDB = Nano(credentialCouchURL);
|
|
21
|
+
export async function useOrCreateCourseDB(courseID) {
|
|
22
|
+
return useOrCreateDB(`coursedb-${courseID}`);
|
|
23
|
+
}
|
|
24
|
+
export async function useOrCreateDB(dbName) {
|
|
25
|
+
const ret = CouchDB.use(dbName);
|
|
26
|
+
try {
|
|
27
|
+
await ret.info();
|
|
28
|
+
return ret;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
try {
|
|
32
|
+
await CouchDB.db.create(dbName);
|
|
33
|
+
return ret;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
const createErr = error;
|
|
37
|
+
// If error is "database already exists", return existing db
|
|
38
|
+
if (createErr.statusCode === 412) {
|
|
39
|
+
return ret;
|
|
40
|
+
}
|
|
41
|
+
throw createErr;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export async function docCount(dbName) {
|
|
46
|
+
const db = await useOrCreateDB(dbName);
|
|
47
|
+
const info = await db.info();
|
|
48
|
+
return info.doc_count;
|
|
49
|
+
}
|
|
50
|
+
export const COUCH_URL_WITH_PROTOCOL = protocol + '://' + process.env.COUCHDB_SERVER;
|
|
51
|
+
export default CouchDB;
|
|
52
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/couchdb/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,GAAG,MAAM,iBAAiB,CAAC;AAClC,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC,MAAM,GAAG,GAAG,GAAG,CAAC,cAAc,CAAC;AAC/B,MAAM,QAAQ,GAAW,GAAG,CAAC,gBAAgB,CAAC;AAE9C,MAAM,KAAK,GAAG;IACZ,QAAQ,EAAE,GAAG,CAAC,aAAa;IAC3B,QAAQ,EAAE,GAAG,CAAC,gBAAgB;CAC/B,CAAC;AACF,MAAM,kBAAkB,GAAG,GAAG,QAAQ,MAAM,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,IAAI,GAAG,EAAE,CAAC;AAEtF,MAAM,CAAC,IAAI,CAAC,qBAAqB,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AACnD,MAAM,CAAC,IAAI,CACT,gBAAgB,GAAG;gBACL,QAAQ;;kBAEN,KAAK,CAAC,QAAQ;;eAEjB,QAAQ,MAAM,KAAK,CAAC,QAAQ,UAAU,GAAG;KACnD,CACJ,CAAC;AAEF,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,QAAgB;IACxD,OAAO,aAAa,CAAC,YAAY,QAAQ,EAAE,CAAC,CAAC;AAC/C,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAI,MAAc;IACnD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAI,MAAM,CAAC,CAAC;IAEnC,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAChC,OAAO,GAAG,CAAC;QACX,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,SAAS,GAAG,KAAkB,CAAC;YACrC,4DAA4D;YAC5D,IAAI,SAAS,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;gBACnC,OAAO,GAAG,CAAC;YACb,CAAC;YACD,MAAM,SAAS,CAAC;QAClB,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAc;IAC3C,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;IAC7B,OAAO,IAAI,CAAC,SAAS,CAAC;AACxB,CAAC;AAaD,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AAErF,eAAe,OAAO,CAAC"}
|