smc-hub
Version:
CoCalc: Backend webserver component
105 lines (97 loc) • 2.85 kB
text/typescript
/*
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
* License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
*/
import { callback2 } from "smc-util/async-utils";
import { trunc } from "smc-util/misc";
import { PostgreSQL } from "./types";
export interface Patch {
time_utc: Date;
patch_length?: number;
patch?: string;
user?: string;
account_id?: string;
format?: number;
snapshot?: string;
}
type User = { account_id: string; user: string };
async function get_users(db: PostgreSQL, where): Promise<User[]> {
const query = "SELECT project_id, users FROM syncstrings";
// get the user_id --> account_id map
const results = await callback2(db._query, { query, where });
if (results.rows.length != 1) {
throw Error("no such syncstring");
}
const account_ids: string[] = results.rows[0].users
? results.rows[0].users
: []; // syncdoc exists, but not used yet.
const project_id: string = results.rows[0].project_id;
const project_title: string = trunc(
(
await callback2(db.get_project, {
columns: ["title"],
project_id,
})
).title,
80
);
// get the names of the users
const names = await callback2(db.account_ids_to_usernames, { account_ids });
const users: User[] = [];
for (const account_id of account_ids) {
if (account_id == project_id) {
users.push({ account_id, user: `Project: ${project_title}` });
continue;
}
const name = names[account_id];
if (name == null) continue;
const user = trunc(`${name.first_name} ${name.last_name}`, 80);
users.push({ account_id, user });
}
return users;
}
export async function syncdoc_history(
db: PostgreSQL,
string_id: string,
include_patches: boolean = false
): Promise<Patch[]> {
const where = { "string_id = $::CHAR(40)": string_id };
const users: User[] = await get_users(db, where);
const order_by = "time";
let query: string;
if (include_patches) {
query = "SELECT time, user_id, format, patch, snapshot FROM patches";
} else {
query =
"SELECT time, user_id, format, length(patch) as patch_length FROM patches";
}
const results = await callback2(db._query, {
query,
where,
order_by,
timeout_s: 300,
});
const patches: Patch[] = [];
function format_patch(row): Patch {
const patch: Patch = { time_utc: row.time, format: row.format };
const u = users[row.user_id];
if (u != null) {
for (const k in u) {
patch[k] = u[k];
}
}
if (include_patches) {
patch.patch = row.patch;
if (row.snapshot != null) {
patch.snapshot = row.snapshot;
}
} else {
patch.patch_length = row.patch_length;
}
return patch;
}
for (const row of results.rows) {
patches.push(format_patch(row));
}
return patches;
}