|
7 | 7 | Code related to permanently deleting projects.
|
8 | 8 | */
|
9 | 9 |
|
| 10 | +import { promises as fs } from "node:fs"; |
| 11 | +import { join } from "node:path"; |
| 12 | + |
| 13 | +import { pathToFiles } from "@cocalc/backend/files/path-to-files"; |
10 | 14 | import getLogger from "@cocalc/backend/logger";
|
11 | 15 | import { newCounter } from "@cocalc/backend/metrics";
|
12 | 16 | import getPool from "@cocalc/database/pool";
|
@@ -105,7 +109,7 @@ SELECT project_id
|
105 | 109 | FROM projects
|
106 | 110 | WHERE deleted = true
|
107 | 111 | AND users IS NULL
|
108 |
| - AND state ->> 'state' != 'deleted' |
| 112 | + AND coalesce(state ->> 'state', '') != 'deleted' |
109 | 113 | ORDER BY created ASC
|
110 | 114 | LIMIT 1000
|
111 | 115 | `;
|
@@ -169,10 +173,12 @@ export async function cleanup_old_projects_data(
|
169 | 173 |
|
170 | 174 | if (on_prem) {
|
171 | 175 | L2(`delete all project files`);
|
172 |
| - // TODO: this only works on-prem, and requires the project files to be mounted |
| 176 | + await deleteProjectFiles(L2, project_id); |
173 | 177 |
|
174 | 178 | L2(`deleting all shared files`);
|
175 |
| - // TODO: do it directly like above, and also get rid of all those shares in the database |
| 179 | + // this is something like /shared/projects/${project_id} |
| 180 | + const shared_path = pathToFiles(project_id, ""); |
| 181 | + await fs.rm(shared_path, { recursive: true, force: true }); |
176 | 182 |
|
177 | 183 | // for now, on-prem only as well. This gets rid of all sorts of data in tables specific to the given project.
|
178 | 184 | delRows += await delete_associated_project_data(L2, project_id);
|
@@ -261,3 +267,24 @@ async function delete_associated_project_data(
|
261 | 267 |
|
262 | 268 | return total;
|
263 | 269 | }
|
| 270 | + |
| 271 | +async function deleteProjectFiles(L2, project_id: string) { |
| 272 | + // TODO: this only works on-prem, and requires the project files to be mounted |
| 273 | + const projects_root = process.env["MOUNTED_PROJECTS_ROOT"]; |
| 274 | + if (!projects_root) return; |
| 275 | + const project_dir = join(projects_root, project_id); |
| 276 | + try { |
| 277 | + await fs.access(project_dir, fs.constants.F_OK | fs.constants.R_OK); |
| 278 | + const stats = await fs.lstat(project_dir); |
| 279 | + if (stats.isDirectory()) { |
| 280 | + L2(`deleting all files in ${project_dir}`); |
| 281 | + await fs.rm(project_dir, { recursive: true, force: true }); |
| 282 | + } else { |
| 283 | + L2(`is not a directory: ${project_dir}`); |
| 284 | + } |
| 285 | + } catch (err) { |
| 286 | + L2( |
| 287 | + `not deleting project files: either it does not exist or is not accessible`, |
| 288 | + ); |
| 289 | + } |
| 290 | +} |
0 commit comments