|
| 1 | +/* Updates an existing project's name, title, and/or description. May be |
| 2 | + restricted such that the query is executed as though by a specific account_id. |
| 3 | +*/ |
| 4 | + |
| 5 | +import getPool from "@cocalc/database/pool"; |
| 6 | +import { isValidUUID } from "@cocalc/util/misc"; |
| 7 | + |
| 8 | +import { DBProject } from "./get"; |
| 9 | + |
| 10 | +export default async function setProject({ |
| 11 | + project_id, |
| 12 | + project_update, |
| 13 | + acting_account_id, |
| 14 | +}: { |
| 15 | + project_id: string; |
| 16 | + project_update: Omit<DBProject, "project_id">; |
| 17 | + |
| 18 | + // If this parameter is NOT provided, the specified project will be updated |
| 19 | + // with NO authorization checks. |
| 20 | + // |
| 21 | + // If this parameter IS provided, this function will execute the project update query as |
| 22 | + // though the account id below had made the request; this has the effect of enforcing an |
| 23 | + // authorization check that the acting account is allowed to modify the desired project. |
| 24 | + // |
| 25 | + acting_account_id?: string; |
| 26 | +}): Promise<DBProject | undefined> { |
| 27 | + // Filter out any provided fields which are null or undefined (but allow empty strings) |
| 28 | + // and convert parameter map to an ordered array. |
| 29 | + // |
| 30 | + const updateFields = Object.entries(project_update).filter( |
| 31 | + ([_, v]) => v ?? false, |
| 32 | + ); |
| 33 | + |
| 34 | + if (!updateFields.length) { |
| 35 | + return; |
| 36 | + } |
| 37 | + |
| 38 | + // Create query param array and append project_id |
| 39 | + // |
| 40 | + const queryParams = updateFields.map(([k, v]) => v); |
| 41 | + queryParams.push(project_id); |
| 42 | + |
| 43 | + const updateSubQuery = updateFields |
| 44 | + .map(([k, v], i) => `${k}=$${i + 1}`) |
| 45 | + .join(","); |
| 46 | + |
| 47 | + let query = `UPDATE projects SET ${updateSubQuery} WHERE project_id=$${queryParams.length} AND deleted IS NOT TRUE`; |
| 48 | + |
| 49 | + // If acting_account_id is provided, we restrict the projects which may be updated |
| 50 | + // to those for which the corresponding account is listed as an owner. |
| 51 | + // |
| 52 | + if (acting_account_id) { |
| 53 | + if (!isValidUUID(acting_account_id)) { |
| 54 | + throw Error("acting_account_id must be a UUIDv4"); |
| 55 | + } |
| 56 | + |
| 57 | + queryParams.push(acting_account_id); |
| 58 | + |
| 59 | + // TODO: Update this to execute only on owned projects. |
| 60 | + // |
| 61 | + query += ` AND users ? $${queryParams.length} AND (users#>>'{${acting_account_id},hide}')::BOOLEAN IS NOT TRUE`; |
| 62 | + } |
| 63 | + |
| 64 | + // Return updated fields |
| 65 | + // |
| 66 | + query += `RETURNING project_id, title, description, name`; |
| 67 | + |
| 68 | + // Execute query |
| 69 | + // |
| 70 | + const pool = getPool(); |
| 71 | + const queryResult = await pool.query(query, queryParams); |
| 72 | + console.log(queryResult); |
| 73 | + const { rows } = queryResult; |
| 74 | + return rows?.[0]; |
| 75 | +} |
0 commit comments