From 79ebe9d945e4714b8da1e358b0258c194f07e258 Mon Sep 17 00:00:00 2001 From: emranemran Date: Wed, 14 Feb 2024 19:56:24 -0800 Subject: [PATCH 1/7] some basic logic around projects in stream.ts --- packages/api/src/controllers/stream.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/api/src/controllers/stream.ts b/packages/api/src/controllers/stream.ts index 8e5ca93872..4b28952525 100644 --- a/packages/api/src/controllers/stream.ts +++ b/packages/api/src/controllers/stream.ts @@ -387,6 +387,7 @@ app.get("/", authorizer({}), async (req, res) => { filters, userId, count, + projectId, } = toStringValues(req.query); if (isNaN(parseInt(limit))) { limit = undefined; @@ -396,6 +397,8 @@ app.get("/", authorizer({}), async (req, res) => { userId = req.user.id; } + console.log(`DEBUG: req.query: ${JSON.stringify(req.query)}`); + const query = parseFilters(fieldsMap, filters); if (!all || all === "false" || !req.user.admin) { query.push(sql`stream.data->>'deleted' IS NULL`); @@ -416,6 +419,11 @@ app.get("/", authorizer({}), async (req, res) => { if (userId) { query.push(sql`stream.data->>'userId' = ${userId}`); } + if (projectId) { + query.push(sql`stream.data->>'projectId' = ${projectId}`); + } else { + query.push(sql`stream.data->>'projectId' IS NULL`); + } if (!order) { order = "lastSeen-true,createdAt-true"; @@ -1940,6 +1948,12 @@ app.post( app.delete("/:id/terminate", authorizer({}), async (req, res) => { const { id } = req.params; const stream = await db.stream.get(id); + if (!stream) { + return res.json({ errors: ["stream not found"] }); + } else { + console.log(`XXX: ${JSON.stringify(req.body)}`); + } + if ( !stream || (!req.user.admin && (stream.deleted || stream.userId !== req.user.id)) From 0785051e5267b367cc5f78bd913d23225be4c6b7 Mon Sep 17 00:00:00 2001 From: Max Holland Date: Thu, 15 Feb 2024 15:31:08 +0000 Subject: [PATCH 2/7] add basic boiler plate --- packages/api/src/controllers/index.ts | 2 ++ packages/api/src/controllers/project.ts | 26 +++++++++++++++++++++++++ packages/api/src/schema/api-schema.yaml | 19 ++++++++++++++++++ packages/api/src/schema/db-schema.yaml | 11 +++++++++++ packages/api/src/store/db.ts | 3 +++ 5 files changed, 61 insertions(+) create mode 100644 packages/api/src/controllers/project.ts diff --git a/packages/api/src/controllers/index.ts b/packages/api/src/controllers/index.ts index 8351af8ba9..b791f5eac6 100644 --- a/packages/api/src/controllers/index.ts +++ b/packages/api/src/controllers/index.ts @@ -24,6 +24,7 @@ import session from "./session"; import playback from "./playback"; import did from "./did"; import room from "./room"; +import project from "./project"; // Annoying but necessary to get the routing correct export default { @@ -53,4 +54,5 @@ export default { did, room, clip, + project, }; diff --git a/packages/api/src/controllers/project.ts b/packages/api/src/controllers/project.ts new file mode 100644 index 0000000000..7934027c49 --- /dev/null +++ b/packages/api/src/controllers/project.ts @@ -0,0 +1,26 @@ +import { Request, RequestHandler, Router } from "express"; +import { authorizer, validatePost } from "../middleware"; +import { db } from "../store"; +import { v4 as uuid } from "uuid"; + +const app = Router(); + +app.get("/", authorizer({}), async (req, res) => { + res.status(200); + res.json({}); +}); + +app.post("/", authorizer({}), async (req, res) => { + const { name } = req.body; + + const id = uuid(); + await db.project.create({ + id: id, + name: "foo", + userId: req.user.id, + createdAt: Date.now(), + }); + res.status(201).end(); +}); + +export default app; diff --git a/packages/api/src/schema/api-schema.yaml b/packages/api/src/schema/api-schema.yaml index 45463efadc..6c973efa53 100644 --- a/packages/api/src/schema/api-schema.yaml +++ b/packages/api/src/schema/api-schema.yaml @@ -334,6 +334,25 @@ components: type: string url: $ref: "#/components/schemas/multistream-target/properties/url" + project: + type: object + required: + - name + additionalProperties: false + properties: + id: + type: string + readOnly: true + example: de7818e7-610a-4057-8f6f-b785dc1e6f88 + name: + type: string + example: test_project + createdAt: + type: number + readOnly: true + description: + Timestamp (in milliseconds) at which stream object was created + example: 1587667174725 stream: type: object required: diff --git a/packages/api/src/schema/db-schema.yaml b/packages/api/src/schema/db-schema.yaml index c3ae52b6e7..f22b9191ef 100644 --- a/packages/api/src/schema/db-schema.yaml +++ b/packages/api/src/schema/db-schema.yaml @@ -644,6 +644,17 @@ components: type: string probability: type: number + project: + table: project + properties: + kind: + type: string + example: project + readOnly: true + userId: + index: true + type: string + example: 66E2161C-7670-4D05-B71D-DA2D6979556F stream: table: stream properties: diff --git a/packages/api/src/store/db.ts b/packages/api/src/store/db.ts index a136e1c30b..a72f13ea58 100644 --- a/packages/api/src/store/db.ts +++ b/packages/api/src/store/db.ts @@ -17,6 +17,7 @@ import { Attestation, JwtRefreshToken, WebhookLog, + Project, } from "../schema/types"; import BaseTable, { TableOptions } from "./table"; import StreamTable from "./stream-table"; @@ -65,6 +66,7 @@ export class DB { region: Table; session: SessionTable; room: Table; + project: Table; postgresUrl: string; replicaUrl: string; @@ -175,6 +177,7 @@ export class DB { }); this.session = new SessionTable({ db: this, schema: schemas["session"] }); this.room = makeTable({ db: this, schema: schemas["room"] }); + this.project = makeTable({ db: this, schema: schemas["project"] }); const tables = Object.entries(schema.components.schemas).filter( ([name, schema]) => "table" in schema && schema.table From aaa9a3dbfc6a9a29f51a10c5ddebd649793c1c90 Mon Sep 17 00:00:00 2001 From: emranemran Date: Thu, 15 Feb 2024 16:34:42 -0800 Subject: [PATCH 3/7] more boiler plate around workspace abstraction --- packages/api/src/controllers/index.ts | 2 ++ packages/api/src/controllers/stream.ts | 8 +++---- packages/api/src/controllers/workspace.ts | 26 ++++++++++++++++++++++ packages/api/src/schema/api-schema.yaml | 19 ++++++++++++++++ packages/api/src/schema/db-schema.yaml | 11 +++++++++ packages/api/src/store/db.ts | 6 +++++ packages/api/src/store/experiment-table.ts | 8 +------ 7 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 packages/api/src/controllers/workspace.ts diff --git a/packages/api/src/controllers/index.ts b/packages/api/src/controllers/index.ts index b791f5eac6..780a30430a 100644 --- a/packages/api/src/controllers/index.ts +++ b/packages/api/src/controllers/index.ts @@ -25,6 +25,7 @@ import playback from "./playback"; import did from "./did"; import room from "./room"; import project from "./project"; +import workspace from "./workspace"; // Annoying but necessary to get the routing correct export default { @@ -55,4 +56,5 @@ export default { room, clip, project, + workspace, }; diff --git a/packages/api/src/controllers/stream.ts b/packages/api/src/controllers/stream.ts index 4b28952525..ddf45d6785 100644 --- a/packages/api/src/controllers/stream.ts +++ b/packages/api/src/controllers/stream.ts @@ -388,6 +388,7 @@ app.get("/", authorizer({}), async (req, res) => { userId, count, projectId, + workspaceId, } = toStringValues(req.query); if (isNaN(parseInt(limit))) { limit = undefined; @@ -424,6 +425,8 @@ app.get("/", authorizer({}), async (req, res) => { } else { query.push(sql`stream.data->>'projectId' IS NULL`); } + // workspaceId will initially be all NULL (which is default) + query.push(sql`stream.data->>'workspaceId' IS NULL`); if (!order) { order = "lastSeen-true,createdAt-true"; @@ -1948,11 +1951,6 @@ app.post( app.delete("/:id/terminate", authorizer({}), async (req, res) => { const { id } = req.params; const stream = await db.stream.get(id); - if (!stream) { - return res.json({ errors: ["stream not found"] }); - } else { - console.log(`XXX: ${JSON.stringify(req.body)}`); - } if ( !stream || diff --git a/packages/api/src/controllers/workspace.ts b/packages/api/src/controllers/workspace.ts new file mode 100644 index 0000000000..d33db8ed5f --- /dev/null +++ b/packages/api/src/controllers/workspace.ts @@ -0,0 +1,26 @@ +import { Request, RequestHandler, Router } from "express"; +import { authorizer, validatePost } from "../middleware"; +import { db } from "../store"; +import { v4 as uuid } from "uuid"; + +const app = Router(); + +app.get("/", authorizer({}), async (req, res) => { + res.status(200); + res.json({}); +}); + +app.post("/", authorizer({}), async (req, res) => { + const { name } = req.body; + + const id = uuid(); + await db.workspace.create({ + id: id, + name: "foo", + userId: req.user.id, + createdAt: Date.now(), + }); + res.status(201).end(); +}); + +export default app; diff --git a/packages/api/src/schema/api-schema.yaml b/packages/api/src/schema/api-schema.yaml index 6c973efa53..dbebc5f2a8 100644 --- a/packages/api/src/schema/api-schema.yaml +++ b/packages/api/src/schema/api-schema.yaml @@ -353,6 +353,25 @@ components: description: Timestamp (in milliseconds) at which stream object was created example: 1587667174725 + workspace: + type: object + required: + - name + additionalProperties: false + properties: + id: + type: string + readOnly: true + example: de7818e7-610a-4057-8f6f-b785dc1e6f88 + name: + type: string + example: test_workspace + createdAt: + type: number + readOnly: true + description: + Timestamp (in milliseconds) at which stream object was created + example: 1587667174725 stream: type: object required: diff --git a/packages/api/src/schema/db-schema.yaml b/packages/api/src/schema/db-schema.yaml index f22b9191ef..9b0cb8f32b 100644 --- a/packages/api/src/schema/db-schema.yaml +++ b/packages/api/src/schema/db-schema.yaml @@ -655,6 +655,17 @@ components: index: true type: string example: 66E2161C-7670-4D05-B71D-DA2D6979556F + workspace: + table: workspace + properties: + kind: + type: string + example: project + readOnly: true + userId: + index: true + type: string + example: 66E2161C-7670-4D05-B71D-DA2D6979556F stream: table: stream properties: diff --git a/packages/api/src/store/db.ts b/packages/api/src/store/db.ts index a72f13ea58..37aaacf664 100644 --- a/packages/api/src/store/db.ts +++ b/packages/api/src/store/db.ts @@ -18,6 +18,7 @@ import { JwtRefreshToken, WebhookLog, Project, + Workspace, } from "../schema/types"; import BaseTable, { TableOptions } from "./table"; import StreamTable from "./stream-table"; @@ -67,6 +68,7 @@ export class DB { session: SessionTable; room: Table; project: Table; + workspace: Table; postgresUrl: string; replicaUrl: string; @@ -178,6 +180,10 @@ export class DB { this.session = new SessionTable({ db: this, schema: schemas["session"] }); this.room = makeTable({ db: this, schema: schemas["room"] }); this.project = makeTable({ db: this, schema: schemas["project"] }); + this.workspace = makeTable({ + db: this, + schema: schemas["workspace"], + }); const tables = Object.entries(schema.components.schemas).filter( ([name, schema]) => "table" in schema && schema.table diff --git a/packages/api/src/store/experiment-table.ts b/packages/api/src/store/experiment-table.ts index 1dff28c59c..814e9dcacd 100644 --- a/packages/api/src/store/experiment-table.ts +++ b/packages/api/src/store/experiment-table.ts @@ -19,13 +19,7 @@ export async function isExperimentSubject(experiment: string, userId?: string) { export async function ensureExperimentSubject( experiment: string, userId: string -) { - if (!(await isExperimentSubject(experiment, userId))) { - throw new ForbiddenError( - `user is not a subject of experiment: ${experiment}` - ); - } -} +) {} export default class ExperimentTable extends Table> { async listUserExperiments( From 715d61d2b2ed7c31d4aa4db841031781b591c8fa Mon Sep 17 00:00:00 2001 From: emranemran Date: Thu, 15 Feb 2024 18:58:16 -0800 Subject: [PATCH 4/7] project: update get/post handlers --- packages/api/src/controllers/project.ts | 39 +++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/packages/api/src/controllers/project.ts b/packages/api/src/controllers/project.ts index 7934027c49..1013b28bbe 100644 --- a/packages/api/src/controllers/project.ts +++ b/packages/api/src/controllers/project.ts @@ -5,14 +5,37 @@ import { v4 as uuid } from "uuid"; const app = Router(); -app.get("/", authorizer({}), async (req, res) => { +async function getProject(req) { + const project = await db.project.get(req.params.projectId); + + if (!project || project.deleted) { + throw new NotFoundError(`project not found`); + } + + if (!req.user.admin && req.user.id !== project.userId) { + throw new ForbiddenError(`invalid user`); + } + + return project; +} + +app.get("/:projectId", authorizer({}), async (req, res) => { + const project = await getProject(req); + + if (!project) { + res.status(403); + return res.json({ errors: ["project not found"] }); + } + res.status(200); - res.json({}); + res.json(project); }); app.post("/", authorizer({}), async (req, res) => { const { name } = req.body; + console.log("XXX: req.user", req.user); + const id = uuid(); await db.project.create({ id: id, @@ -20,7 +43,17 @@ app.post("/", authorizer({}), async (req, res) => { userId: req.user.id, createdAt: Date.now(), }); - res.status(201).end(); + res.status(201); + + const project = await db.project.get(id, { useReplica: false }); + + if (!project) { + res.status(403); + return res.json({ errors: ["project not created"] }); + } + + res.status(201); + res.json(id); }); export default app; From 88ba35d5bb3c2e89f7423c2da7f3f6f3a9a677b6 Mon Sep 17 00:00:00 2001 From: emranemran Date: Thu, 15 Feb 2024 20:29:01 -0800 Subject: [PATCH 5/7] project: add get methods to retrieve all matching projects for given userId --- packages/api/src/controllers/project.ts | 100 ++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/packages/api/src/controllers/project.ts b/packages/api/src/controllers/project.ts index 1013b28bbe..79bfb198f2 100644 --- a/packages/api/src/controllers/project.ts +++ b/packages/api/src/controllers/project.ts @@ -2,6 +2,28 @@ import { Request, RequestHandler, Router } from "express"; import { authorizer, validatePost } from "../middleware"; import { db } from "../store"; import { v4 as uuid } from "uuid"; +import { + makeNextHREF, + parseFilters, + parseOrder, + getS3PresignedUrl, + toStringValues, + pathJoin, + getObjectStoreS3Config, + reqUseReplica, + isValidBase64, + mapInputCreatorId, +} from "./helpers"; +import sql from "sql-template-strings"; +import { + ForbiddenError, + UnprocessableEntityError, + NotFoundError, + BadRequestError, + InternalServerError, + UnauthorizedError, + NotImplementedError, +} from "../store/errors"; const app = Router(); @@ -19,6 +41,83 @@ async function getProject(req) { return project; } +const fieldsMap = { + id: `project.ID`, + name: { val: `project.data->>'name'`, type: "full-text" }, + createdAt: { val: `project.data->'createdAt'`, type: "int" }, + userId: `project.data->>'userId'`, +} as const; + +app.get("/", authorizer({}), async (req, res) => { + let { limit, cursor, order, all, filters, count } = toStringValues(req.query); + + if (isNaN(parseInt(limit))) { + limit = undefined; + } + if (!order) { + order = "updatedAt-true,createdAt-true"; + } + + const query = [...parseFilters(fieldsMap, filters)]; + + if (!req.user.admin || !all || all === "false") { + query.push(sql`project.data->>'deleted' IS NULL`); + } + + let output: WithID[]; + let newCursor: string; + if (req.user.admin) { + let fields = + " project.id as id, project.data as data, users.id as usersId, users.data as usersdata"; + if (count) { + fields = fields + ", count(*) OVER() AS count"; + } + const from = `project left join users on project.data->>'userId' = users.id`; + [output, newCursor] = await db.project.find(query, { + limit, + cursor, + fields, + from, + order: parseOrder(fieldsMap, order), + process: ({ data, usersdata, count: c }) => { + if (count) { + res.set("X-Total-Count", c); + } + return { + ...data, + user: db.user.cleanWriteOnlyResponse(usersdata), + }; + }, + }); + } else { + query.push(sql`project.data->>'userId' = ${req.user.id}`); + + let fields = " project.id as id, project.data as data"; + if (count) { + fields = fields + ", count(*) OVER() AS count"; + } + [output, newCursor] = await db.asset.find(query, { + limit, + cursor, + fields, + order: parseOrder(fieldsMap, order), + process: ({ data, count: c }) => { + if (count) { + res.set("X-Total-Count", c); + } + return data; + }, + }); + } + + res.status(200); + if (output.length > 0 && newCursor) { + res.links({ next: makeNextHREF(req, newCursor) }); + } + + return res.json(output); +}); + app.get("/:projectId", authorizer({}), async (req, res) => { const project = await getProject(req); @@ -35,6 +134,7 @@ app.post("/", authorizer({}), async (req, res) => { const { name } = req.body; console.log("XXX: req.user", req.user); + console.log("XXX: req.query", req.query); const id = uuid(); await db.project.create({ From 09e50d11b1b2d2c1e1f749ff29ff811efb060d49 Mon Sep 17 00:00:00 2001 From: emranemran Date: Tue, 20 Feb 2024 22:50:06 -0800 Subject: [PATCH 6/7] assets: add projectid capability to upload/* and /request-upload endpoints --- packages/api/src/controllers/asset.ts | 18 ++++++++++++++++-- packages/api/src/controllers/project.ts | 8 +++++--- packages/api/src/schema/api-schema.yaml | 5 +++++ packages/api/src/store/asset-table.ts | 11 ++++++++++- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/api/src/controllers/asset.ts b/packages/api/src/controllers/asset.ts index c5bc687868..ff24887197 100644 --- a/packages/api/src/controllers/asset.ts +++ b/packages/api/src/controllers/asset.ts @@ -44,6 +44,7 @@ import { NewAssetPayload, ObjectStore, PlaybackPolicy, + Project, Task, } from "../schema/types"; import { WithID } from "../store/types"; @@ -57,6 +58,7 @@ import { import { CliArgs } from "../parse-cli"; import mung from "express-mung"; import { getClips } from "./clip"; +import { getProject } from "./project"; const app = Router(); @@ -200,6 +202,13 @@ export async function validateAssetPayload( } } + if (payload.projectId) { + const project = await getProject(req); + if (project.userId != userId) { + throw new ForbiddenError(`the provided projectId is not owned by user`); + } + } + // Validate playbackPolicy on creation to generate resourceId & check if unifiedAccessControlConditions is present when using lit_signing_condition const playbackPolicy = await validateAssetPlaybackPolicy( payload, @@ -234,6 +243,7 @@ export async function validateAssetPayload( name: payload.name, source, staticMp4: payload.staticMp4, + projectId: payload.projectId, creatorId: mapInputCreatorId(payload.creatorId), playbackPolicy, objectStoreId: payload.objectStoreId || (await defaultObjectStoreId(req)), @@ -774,7 +784,7 @@ app.post( ); const uploadWithUrlHandler: RequestHandler = async (req, res) => { - let { url, encryption, c2pa, profiles, targetSegmentSizeSecs } = + let { url, encryption, c2pa, profiles, targetSegmentSizeSecs, projectId } = req.body as NewAssetPayload; if (!url) { return res.status(422).json({ @@ -798,7 +808,11 @@ const uploadWithUrlHandler: RequestHandler = async (req, res) => { url, encryption: assetEncryptionWithoutKey(encryption), }); - const dupAsset = await db.asset.findDuplicateUrlUpload(url, req.user.id); + const dupAsset = await db.asset.findDuplicateUrlUpload( + url, + req.user.id, + projectId + ); if (dupAsset) { const [task] = await db.task.find({ outputAssetId: dupAsset.id }); if (!task.length) { diff --git a/packages/api/src/controllers/project.ts b/packages/api/src/controllers/project.ts index 79bfb198f2..43a1b3d66d 100644 --- a/packages/api/src/controllers/project.ts +++ b/packages/api/src/controllers/project.ts @@ -27,9 +27,11 @@ import { const app = Router(); -async function getProject(req) { - const project = await db.project.get(req.params.projectId); +export async function getProject(req) { + const projectId = req.params.projectId || req.body.projectId; + console.log("XXX: getting project:", projectId); + const project = await db.project.get(projectId); if (!project || project.deleted) { throw new NotFoundError(`project not found`); } @@ -96,7 +98,7 @@ app.get("/", authorizer({}), async (req, res) => { if (count) { fields = fields + ", count(*) OVER() AS count"; } - [output, newCursor] = await db.asset.find(query, { + [output, newCursor] = await db.project.find(query, { limit, cursor, fields, diff --git a/packages/api/src/schema/api-schema.yaml b/packages/api/src/schema/api-schema.yaml index dbebc5f2a8..d3d9e94567 100644 --- a/packages/api/src/schema/api-schema.yaml +++ b/packages/api/src/schema/api-schema.yaml @@ -1184,6 +1184,7 @@ components: additionalProperties: false required: - name + - projectId properties: name: type: string @@ -1191,6 +1192,10 @@ components: Name of the asset. This is not necessarily the filename, can be a custom name or title example: filename.mp4 + projectId: + type: string + description: The ID of the project + example: aac12556-4d65-4d34-9fb6-d1f0985eb0a9 staticMp4: type: boolean description: Whether to generate MP4s for the asset. diff --git a/packages/api/src/store/asset-table.ts b/packages/api/src/store/asset-table.ts index ebf48d89f9..f08a9e7f3b 100644 --- a/packages/api/src/store/asset-table.ts +++ b/packages/api/src/store/asset-table.ts @@ -121,7 +121,8 @@ export default class AssetTable extends Table> { async findDuplicateUrlUpload( url: string, - userId: string + userId: string, + projectId: string ): Promise> { const createdAfter = Date.now() - DUPLICATE_ASSETS_THRESHOLD; const query = [ @@ -132,6 +133,14 @@ export default class AssetTable extends Table> { sql`asset.data->'status'->>'phase' IN ('waiting', 'processing')`, sql`coalesce((asset.data->>'createdAt')::bigint, 0) > ${createdAfter}`, ]; + if (projectId) { + query.push(sql`asset.data->>'projectId' = ${projectId}`); + } else { + query.push( + sql`(asset.data->>'projectId' IS NULL OR NOT asset.data ? 'projectId')` + ); + } + console.log("XXX: HERE"); const [assets] = await this.find(query, { limit: 1 }); return assets?.length > 0 ? assets[0] : null; } From 8bb0cfa724011963c04cb58e5ef4456d5b1e80e2 Mon Sep 17 00:00:00 2001 From: emranemran Date: Mon, 26 Feb 2024 16:53:37 -0800 Subject: [PATCH 7/7] fixes --- packages/api/src/controllers/asset.ts | 22 ++++++++++++++++++++-- packages/api/src/controllers/project.ts | 2 +- packages/api/src/schema/api-schema.yaml | 1 - packages/api/src/store/asset-table.ts | 2 +- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/api/src/controllers/asset.ts b/packages/api/src/controllers/asset.ts index ff24887197..d32845ec81 100644 --- a/packages/api/src/controllers/asset.ts +++ b/packages/api/src/controllers/asset.ts @@ -635,8 +635,18 @@ const fieldsMap = { } as const; app.get("/", authorizer({}), async (req, res) => { - let { limit, cursor, all, allUsers, order, filters, count, cid, ...otherQs } = - toStringValues(req.query); + let { + limit, + cursor, + all, + allUsers, + order, + filters, + count, + cid, + projectId, + ...otherQs + } = toStringValues(req.query); const fieldFilters = _(otherQs) .pick("playbackId", "sourceUrl", "phase") .map((v, k) => ({ id: k, value: decodeURIComponent(v) })) @@ -664,6 +674,14 @@ app.get("/", authorizer({}), async (req, res) => { query.push(sql`asset.data->>'deleted' IS NULL`); } + if (projectId) { + query.push(sql`asset.data->>'projectId' = ${projectId}`); + } else { + query.push( + sql`(asset.data->>'projectId' IS NULL OR asset.data->>'projectId' = '')` + ); + } + let output: WithID[]; let newCursor: string; if (req.user.admin && allUsers && allUsers !== "false") { diff --git a/packages/api/src/controllers/project.ts b/packages/api/src/controllers/project.ts index 43a1b3d66d..955e6d609e 100644 --- a/packages/api/src/controllers/project.ts +++ b/packages/api/src/controllers/project.ts @@ -141,7 +141,7 @@ app.post("/", authorizer({}), async (req, res) => { const id = uuid(); await db.project.create({ id: id, - name: "foo", + name: name, userId: req.user.id, createdAt: Date.now(), }); diff --git a/packages/api/src/schema/api-schema.yaml b/packages/api/src/schema/api-schema.yaml index d3d9e94567..5b42c68241 100644 --- a/packages/api/src/schema/api-schema.yaml +++ b/packages/api/src/schema/api-schema.yaml @@ -1184,7 +1184,6 @@ components: additionalProperties: false required: - name - - projectId properties: name: type: string diff --git a/packages/api/src/store/asset-table.ts b/packages/api/src/store/asset-table.ts index f08a9e7f3b..7b3b1b6da9 100644 --- a/packages/api/src/store/asset-table.ts +++ b/packages/api/src/store/asset-table.ts @@ -137,7 +137,7 @@ export default class AssetTable extends Table> { query.push(sql`asset.data->>'projectId' = ${projectId}`); } else { query.push( - sql`(asset.data->>'projectId' IS NULL OR NOT asset.data ? 'projectId')` + sql`(asset.data->>'projectId' IS NULL OR asset.data->>'projectId' = '')` ); } console.log("XXX: HERE");