CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/course/export/file-use-times.ts
Views: 687
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
query,
10
write_text_file_to_project,
11
} from "../../frame-editors/generic/client";
12
import { splitlines } from "@cocalc/util/misc";
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 q = await query({
40
query: {
41
file_use_times: {
42
project_id,
43
account_id,
44
path,
45
access_times: null,
46
edit_times: null,
47
},
48
},
49
options: [{ limit }],
50
});
51
const { edit_times, access_times } = q.query.file_use_times;
52
times[path] = { edit_times, access_times };
53
}
54
return times;
55
}
56
57
function student_info(
58
assignment_path: string,
59
student: StudentRecord,
60
get_name: Function,
61
): StudentUseTimes {
62
const student_id = student.get("student_id");
63
const x: StudentUseTimes = {
64
student_id,
65
student_name: get_name(student_id),
66
assignment_path,
67
};
68
for (const field of ["account_id", "project_id"]) {
69
if (student.has(field)) {
70
x[field] = student.get(field);
71
}
72
}
73
return x;
74
}
75
76
async function paths_to_scan(
77
project_id: string,
78
src_path: string,
79
target_path: string,
80
): Promise<string[]> {
81
const { stdout } = await exec({
82
command: "find",
83
args: ["."],
84
path: src_path,
85
err_on_exit: true,
86
project_id,
87
});
88
const v: string[] = [];
89
for (const path of splitlines(stdout)) {
90
const path2 = path.slice(2);
91
if (path2) {
92
v.push(target_path + "/" + path2);
93
}
94
}
95
return v;
96
}
97
98
export async function all_students_file_use_times(
99
course_project_id: string,
100
src_path: string,
101
target_path: string,
102
students: StudentsMap,
103
get_name: Function,
104
): Promise<{ [student_id: string]: StudentUseTimes }> {
105
const paths = await paths_to_scan(course_project_id, src_path, target_path);
106
107
// Iterate through the (nondeleted) students determining to what extent
108
// they used files in the given path in their projects.
109
const times: { [student_id: string]: StudentUseTimes } = {};
110
for (const [student_id, student] of students) {
111
if (student.get("deleted")) continue;
112
const info = (times[student_id] = student_info(
113
target_path,
114
student,
115
get_name,
116
));
117
if (info.project_id == null || info.account_id == null) {
118
// nothing more to do, since no account or project
119
continue;
120
}
121
try {
122
info.paths = await one_student_file_use_times(
123
paths,
124
info.project_id,
125
info.account_id,
126
);
127
} catch (err) {
128
info.error = `${err}`;
129
}
130
}
131
return times;
132
}
133
134
export async function export_student_file_use_times(
135
course_project_id: string,
136
src_path: string,
137
target_path: string,
138
students: StudentsMap,
139
target_json: string,
140
get_name: Function,
141
): Promise<void> {
142
const x = await all_students_file_use_times(
143
course_project_id,
144
src_path,
145
target_path,
146
students,
147
get_name,
148
);
149
await write_text_file_to_project({
150
project_id: course_project_id,
151
path: target_json,
152
content: JSON.stringify(x, null, 2),
153
});
154
}
155
156