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/database/postgres/site-license/search.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 { PostgreSQL } from "../types";
7
import {
8
is_valid_uuid_string,
9
search_match,
10
search_split,
11
} from "@cocalc/util/misc";
12
import { query } from "../query";
13
14
// This works and does the entire search in the database.
15
// Unfortunately, it is unusably slow and I just don't have
16
// the time to do something better right now:
17
/*
18
export async function matching_site_licenses(
19
db: PostgreSQL,
20
search: string,
21
limit: number = 5
22
): Promise<{ id: string }[]> {
23
const where: any[] = [];
24
const params: (string | number)[] = [];
25
let i = 1;
26
for (const s of search_split(search.toLowerCase())) {
27
where.push(
28
`(lower(site_licenses.title) LIKE $${i}::TEXT OR lower(site_licenses.description) LIKE $${i}::TEXT OR site_licenses.id::TEXT LIKE $${i}::TEXT OR lower(site_licenses.info::TEXT) LIKE $${i}::TEXT OR lower(accounts.first_name) LIKE $${i}::TEXT OR lower(accounts.last_name) LIKE $${i}::TEXT OR lower(accounts.email_address) LIKE $${i}::TEXT)`
29
);
30
params.push(`%${s}%`);
31
i += 1;
32
}
33
let query =
34
"SELECT DISTINCT(site_licenses.id) AS id, site_licenses.last_used FROM site_licenses, accounts WHERE accounts.account_id::TEXT = ANY(site_licenses.managers) AND";
35
query += ` (${where.join(" AND ")})`;
36
37
// recently active licenses are much more relevant than old ones
38
query += " ORDER BY site_licenses.last_used DESC NULLS LAST";
39
query += ` LIMIT $${i}::INTEGER`;
40
params.push(limit);
41
i += 1;
42
43
return (await db.async_query({ query, params })).rows;
44
}
45
*/
46
47
// This is dumb but will be sufficiently fast up to probably 5K licenses.
48
// This is not user facing functionality. We could maybe restrict to last_used
49
// in the few months by default (optionally anything) and this would last
50
// much longer...
51
export async function matching_site_licenses(
52
db: PostgreSQL,
53
search: string,
54
limit: number = 5
55
): Promise<{ id: string }[]> {
56
if (is_valid_uuid_string(search)) {
57
return (
58
await db.async_query<{id :string}>({
59
cache: true,
60
query: "SELECT id FROM site_licenses WHERE id=$1",
61
params: [search],
62
})
63
).rows;
64
}
65
// Get them all.
66
const licenses = (
67
await db.async_query({
68
query:
69
"SELECT id, id || ' ' || coalesce(lower(title),'') || ' ' || coalesce(lower(description),'') || ' ' || coalesce(lower(info::TEXT),'') AS info, managers FROM site_licenses ORDER BY last_used DESC NULLS LAST",
70
})
71
).rows;
72
// Replace manager account ids by name and email
73
const managers: Set<string> = new Set();
74
for (const x of licenses) {
75
if (x.managers != null) {
76
for (const account_id of x.managers) {
77
managers.add(account_id);
78
}
79
}
80
}
81
const accounts: { [account_id: string]: string } = {};
82
for (const row of (
83
await db.async_query({
84
cache: true,
85
query:
86
"SELECT account_id, coalesce(lower(first_name),'') || ' ' || coalesce(lower(last_name),'') || ' ' || coalesce(lower(email_address),'') AS info FROM accounts WHERE account_id=ANY($1)",
87
params: [Array.from(managers)],
88
})
89
).rows) {
90
accounts[row.account_id] = row.info;
91
}
92
93
const v = search_split(search.toLowerCase());
94
const matches: { id: string }[] = [];
95
for (const license of licenses) {
96
let s = license.info;
97
if (license.managers) {
98
for (const account_id of license.managers) {
99
s += " " + accounts[account_id];
100
}
101
}
102
if (search_match(s, v)) {
103
matches.push({ id: license.id as string });
104
}
105
if (matches.length >= limit) break;
106
}
107
108
return matches;
109
}
110
111
export async function manager_site_licenses(
112
db: PostgreSQL,
113
account_id: string
114
): Promise<object[]> {
115
const query = "SELECT * FROM site_licenses WHERE $1=ANY(managers)";
116
const params = [account_id];
117
return (await db.async_query({ query, params })).rows;
118
}
119
120
// Return true if the given user is a manager of any site licenses.
121
export async function is_a_site_license_manager(
122
db: PostgreSQL,
123
account_id: string
124
): Promise<boolean> {
125
return (
126
(
127
await query({
128
db,
129
query: "SELECT COUNT(*)::INT FROM site_licenses WHERE $1=ANY(managers)",
130
one: true,
131
params: [account_id],
132
})
133
).count > 0
134
);
135
}
136
137