Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/course/export/file-use-times.ts
1503 views
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { StudentsMap, StudentRecord } from "../store";
7
import {
8
exec,
9
write_text_file_to_project,
10
} from "../../frame-editors/generic/client";
11
import { splitlines } from "@cocalc/util/misc";
12
import { webapp_client } from "@cocalc/frontend/webapp-client";
13
14
interface PathUseTimes {
15
edit_times: number[];
16
access_times: number[];
17
}
18
19
interface StudentUseTimes {
20
student_id: string;
21
account_id?: string;
22
project_id?: string;
23
student_name: string;
24
assignment_path: string;
25
paths?: { [path: string]: PathUseTimes };
26
error?: string; // if it fails for some non-obvious reason
27
}
28
29
async function one_student_file_use_times(
30
paths: string[],
31
project_id: string,
32
account_id: string,
33
limit: number = 1000,
34
): Promise<{ [path: string]: PathUseTimes }> {
35
project_id = project_id;
36
account_id = account_id;
37
const times: { [path: string]: PathUseTimes } = {};
38
for (const path of paths) {
39
const { edit_times, access_times } =
40
await webapp_client.conat_client.hub.db.fileUseTimes({
41
project_id,
42
path,
43
target_account_id: account_id,
44
limit,
45
edit_times: true,
46
access_times: true,
47
timeout: 1000 * 60 * 15,
48
});
49
if (edit_times == null || access_times == null) {
50
throw Error("bug");
51
}
52
times[path] = {
53
edit_times: edit_times.filter((x) => !!x) as number[],
54
access_times,
55
};
56
}
57
return times;
58
}
59
60
function student_info(
61
assignment_path: string,
62
student: StudentRecord,
63
get_name: Function,
64
): StudentUseTimes {
65
const student_id = student.get("student_id");
66
const x: StudentUseTimes = {
67
student_id,
68
student_name: get_name(student_id),
69
assignment_path,
70
};
71
for (const field of ["account_id", "project_id"]) {
72
if (student.has(field)) {
73
x[field] = student.get(field);
74
}
75
}
76
return x;
77
}
78
79
async function paths_to_scan(
80
project_id: string,
81
src_path: string,
82
target_path: string,
83
): Promise<string[]> {
84
const { stdout } = await exec({
85
command: "find",
86
args: ["."],
87
path: src_path,
88
err_on_exit: true,
89
project_id,
90
});
91
const v: string[] = [];
92
for (const path of splitlines(stdout)) {
93
const path2 = path.slice(2);
94
if (path2) {
95
v.push(target_path + "/" + path2);
96
}
97
}
98
return v;
99
}
100
101
export async function all_students_file_use_times(
102
course_project_id: string,
103
src_path: string,
104
target_path: string,
105
students: StudentsMap,
106
get_name: Function,
107
): Promise<{ [student_id: string]: StudentUseTimes }> {
108
const paths = await paths_to_scan(course_project_id, src_path, target_path);
109
110
// Iterate through the (nondeleted) students determining to what extent
111
// they used files in the given path in their projects.
112
const times: { [student_id: string]: StudentUseTimes } = {};
113
for (const [student_id, student] of students) {
114
if (student.get("deleted")) continue;
115
const info = (times[student_id] = student_info(
116
target_path,
117
student,
118
get_name,
119
));
120
if (info.project_id == null || info.account_id == null) {
121
// nothing more to do, since no account or project
122
continue;
123
}
124
try {
125
info.paths = await one_student_file_use_times(
126
paths,
127
info.project_id,
128
info.account_id,
129
);
130
} catch (err) {
131
info.error = `${err}`;
132
}
133
}
134
return times;
135
}
136
137
export async function export_student_file_use_times(
138
course_project_id: string,
139
src_path: string,
140
target_path: string,
141
students: StudentsMap,
142
target_json: string,
143
get_name: Function,
144
): Promise<void> {
145
const x = await all_students_file_use_times(
146
course_project_id,
147
src_path,
148
target_path,
149
students,
150
get_name,
151
);
152
await write_text_file_to_project({
153
project_id: course_project_id,
154
path: target_json,
155
content: JSON.stringify(x, null, 2),
156
});
157
}
158
159