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/util/db-schema/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 { Table } from "./types";
7
8
/*
9
This is a virtual table to make it simple from clients to
10
query about all usage ever of a specific file or directory
11
tree by a given user.
12
13
The usage times are the union of times both when patches
14
and times when the file was accessed. Thus this would be
15
useful to see if a user opened a PDF file, say, even though
16
they didn't edit it.
17
*/
18
19
const LIMIT = 1000;
20
21
Table({
22
name: "file_use_times",
23
fields: {
24
project_id: {
25
type: "uuid",
26
desc: "id of a project",
27
},
28
account_id: {
29
type: "uuid",
30
desc: "id of a user",
31
},
32
path: {
33
type: "string",
34
desc: "path to a specific file in the project",
35
},
36
edit_times: {
37
type: "array",
38
desc: `array of times (as ms since epoch) when the file was edited by the given account_id, sorted from newest to oldest. At most ${LIMIT} values are returned.`,
39
},
40
access_times: {
41
type: "array",
42
desc: `array of times (as ms since epoch) when the file was accessed by the given account_id, sorted from newest to oldest. At most ${LIMIT} values are returned.`,
43
},
44
},
45
rules: {
46
virtual: true, // don't make an actual table
47
desc: "File usage information.",
48
anonymous: false,
49
primary_key: ["project_id", "path"],
50
user_query: {
51
get: {
52
options: [{ limit: LIMIT }], // todo -- add an option to trim the number of results by lowering resolution?
53
fields: {
54
project_id: null,
55
account_id: null,
56
path: null,
57
access_times: null,
58
edit_times: null,
59
},
60
// Actual query is implemented using this code below rather than an actual query directly.
61
async instead_of_query(database, opts, cb): Promise<void> {
62
const obj: any = Object.assign({}, opts.query);
63
const { project_id, account_id, path } = obj;
64
if (project_id == null || account_id == null || path == null) {
65
cb("project_id, account_id, and path must all be specified");
66
return;
67
}
68
const edit_times = obj.edit_times === null;
69
const access_times = obj.access_times === null;
70
if (!edit_times && !access_times) {
71
// dumb -- nothing to do; but let's make this edge case work, of course.
72
cb(undefined, obj);
73
return;
74
}
75
let limit = LIMIT;
76
if (opts.options && opts.options[0] && opts.options[0].limit) {
77
// hackishly only support limit option.
78
limit = opts.options[0].limit;
79
}
80
try {
81
const x = await database.file_use_times({
82
project_id,
83
account_id,
84
user_account_id: opts.account_id,
85
path,
86
limit,
87
access_times,
88
edit_times,
89
});
90
if (access_times) {
91
obj.access_times = x.access_times;
92
}
93
if (edit_times) {
94
obj.edit_times = x.edit_times;
95
}
96
cb(undefined, obj);
97
} catch (err) {
98
cb(err);
99
}
100
},
101
},
102
},
103
},
104
});
105
106