streamby-core 0.37.0 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/README.md +62 -1
- package/dist/adapters/storage/s3.d.ts +3 -2
- package/dist/adapters/storage/s3.js +18 -5
- package/dist/mcp/server.js +12 -0
- package/dist/mcp/tools.d.ts +2 -0
- package/dist/mcp/tools.js +107 -14
- package/dist/mcp/workflowNodes.d.ts +24 -0
- package/dist/mcp/workflowNodes.js +48 -0
- package/dist/middleware/createRouter.js +2 -0
- package/dist/middleware/routes/deliverable.d.ts +3 -0
- package/dist/middleware/routes/deliverable.js +131 -0
- package/dist/middleware/routes/export.js +2 -0
- package/dist/middleware/routes/production.js +60 -67
- package/dist/middleware/routes/project.js +8 -2
- package/dist/middleware/routes/storage.js +115 -24
- package/dist/services/apiTokenPermissions.js +5 -1
- package/dist/services/assetVersions.d.ts +48 -0
- package/dist/services/assetVersions.js +84 -0
- package/dist/services/deliverables.d.ts +26 -0
- package/dist/services/deliverables.js +55 -0
- package/dist/services/mediaProcessor.js +3 -1
- package/dist/services/production.d.ts +2 -0
- package/dist/services/production.js +13 -0
- package/dist/services/productionFields.d.ts +16 -0
- package/dist/services/productionFields.js +80 -0
- package/dist/services/signedUrls.d.ts +6 -0
- package/dist/services/signedUrls.js +9 -0
- package/dist/types/index.d.ts +7 -2
- package/dist/utils/nosqlDb.d.ts +2 -0
- package/dist/utils/nosqlDb.js +11 -0
- package/package.json +1 -1
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deliverableRouter = deliverableRouter;
|
|
4
|
+
const express_1 = require("express");
|
|
5
|
+
const manager_1 = require("../../models/manager");
|
|
6
|
+
const auth_1 = require("../../utils/auth");
|
|
7
|
+
const nosqlDb_1 = require("../../utils/nosqlDb");
|
|
8
|
+
const assetVersions_1 = require("../../services/assetVersions");
|
|
9
|
+
const deliverables_1 = require("../../services/deliverables");
|
|
10
|
+
const MAX_NOTE = 1000;
|
|
11
|
+
// A project's deliverables (see services/deliverables): marked, listed and removed. Removing
|
|
12
|
+
// one never deletes its asset.
|
|
13
|
+
function deliverableRouter(_config) {
|
|
14
|
+
const router = (0, express_1.Router)();
|
|
15
|
+
const Project = (0, manager_1.getModel)('projects');
|
|
16
|
+
const exportsOf = (project) => project.exports ?? [];
|
|
17
|
+
// What a list shows of each: its asset's name and kind, its version's number, and the name
|
|
18
|
+
// of the shot or export it's for.
|
|
19
|
+
const describe = async (project, deliverables) => {
|
|
20
|
+
const db = (0, nosqlDb_1.nosqlDb)();
|
|
21
|
+
const assetIds = [...new Set(deliverables.map(d => d.assetId))];
|
|
22
|
+
const shotIds = [...new Set(deliverables.map(d => d.shotId).filter(Boolean))];
|
|
23
|
+
const versionIds = [...new Set(deliverables.map(d => d.versionId).filter(Boolean))];
|
|
24
|
+
const [files, shots, versions] = db
|
|
25
|
+
? await Promise.all([
|
|
26
|
+
db.collection('storage_files').find({ projectId: project._id?.toString() ?? project.id, fileId: { $in: assetIds } }).toArray(),
|
|
27
|
+
shotIds.length ? db.collection('production_shots').find({ id: { $in: shotIds } }).toArray() : [],
|
|
28
|
+
versionIds.length ? db.collection('asset_versions').find({ versionId: { $in: versionIds } }).toArray() : [],
|
|
29
|
+
])
|
|
30
|
+
: [[], [], []];
|
|
31
|
+
return deliverables.map(d => {
|
|
32
|
+
const file = files.find((f) => f.fileId === d.assetId);
|
|
33
|
+
const version = versions.find((v) => v.versionId === d.versionId);
|
|
34
|
+
return {
|
|
35
|
+
...d,
|
|
36
|
+
asset: file ? { displayName: file.displayName, category: file.category, contentType: file.contentType ?? null } : null,
|
|
37
|
+
version: version ? version.version : null,
|
|
38
|
+
shotName: d.shotId ? shots.find((s) => s.id === d.shotId)?.name ?? null : null,
|
|
39
|
+
exportName: d.exportId ? exportsOf(project).find((e) => e.id?.toString() === d.exportId)?.name ?? null : null,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
router.get('/projects/:projectId/deliverables', async (req, res) => {
|
|
44
|
+
try {
|
|
45
|
+
const auth = req.auth;
|
|
46
|
+
const { projectId } = req.params;
|
|
47
|
+
const { shotId, exportId } = req.query;
|
|
48
|
+
const project = await Project.findOne({ _id: projectId });
|
|
49
|
+
if (!project)
|
|
50
|
+
return res.status(404).json({ message: 'Project not found' });
|
|
51
|
+
if (!(0, auth_1.isProjectMember)(project, auth.userId))
|
|
52
|
+
return res.status(403).json({ message: 'Unauthorized' });
|
|
53
|
+
const deliverables = await (0, deliverables_1.listDeliverables)(projectId, { shotId, exportId });
|
|
54
|
+
res.json({ deliverables: await describe(project, deliverables) });
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
res.status(500).json({ message: 'Failed to list deliverables', details: err.message });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
router.post('/projects/:projectId/deliverables', async (req, res) => {
|
|
61
|
+
try {
|
|
62
|
+
const auth = req.auth;
|
|
63
|
+
const { projectId } = req.params;
|
|
64
|
+
const { assetId, versionId, shotId, exportId, note } = req.body ?? {};
|
|
65
|
+
if (typeof assetId !== 'string' || !assetId)
|
|
66
|
+
return res.status(400).json({ message: 'assetId is required' });
|
|
67
|
+
if (versionId !== undefined && versionId !== null && typeof versionId !== 'string') {
|
|
68
|
+
return res.status(400).json({ message: 'versionId must be a string' });
|
|
69
|
+
}
|
|
70
|
+
const forShot = typeof shotId === 'string' && shotId !== '';
|
|
71
|
+
const forExport = typeof exportId === 'string' && exportId !== '';
|
|
72
|
+
if (forShot === forExport)
|
|
73
|
+
return res.status(400).json({ message: 'A deliverable is for a shot (shotId) or for an export (exportId), one of them' });
|
|
74
|
+
if (note !== undefined && note !== null && (typeof note !== 'string' || note.length > MAX_NOTE)) {
|
|
75
|
+
return res.status(400).json({ message: `note must be a string of at most ${MAX_NOTE} characters` });
|
|
76
|
+
}
|
|
77
|
+
const project = await Project.findOne({ _id: projectId });
|
|
78
|
+
if (!project)
|
|
79
|
+
return res.status(404).json({ message: 'Project not found' });
|
|
80
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
81
|
+
return res.status(403).json({ message: 'Unauthorized' });
|
|
82
|
+
const db = (0, nosqlDb_1.nosqlDb)();
|
|
83
|
+
if (!db)
|
|
84
|
+
return res.status(500).json({ message: 'Database not available' });
|
|
85
|
+
if (!(await db.collection('storage_files').findOne({ fileId: assetId, projectId }))) {
|
|
86
|
+
return res.status(404).json({ message: 'Asset not found' });
|
|
87
|
+
}
|
|
88
|
+
if (versionId && !(await (0, assetVersions_1.findVersion)(projectId, assetId, versionId))) {
|
|
89
|
+
return res.status(404).json({ message: 'Version not found' });
|
|
90
|
+
}
|
|
91
|
+
if (forShot && !(await db.collection('production_shots').findOne({ id: shotId, projectId }))) {
|
|
92
|
+
return res.status(404).json({ message: 'Shot not found' });
|
|
93
|
+
}
|
|
94
|
+
if (forExport && !exportsOf(project).some((e) => e.id?.toString() === exportId)) {
|
|
95
|
+
return res.status(404).json({ message: 'Export not found' });
|
|
96
|
+
}
|
|
97
|
+
const deliverable = await (0, deliverables_1.createDeliverable)({
|
|
98
|
+
projectId,
|
|
99
|
+
assetId,
|
|
100
|
+
versionId: versionId || null,
|
|
101
|
+
shotId: forShot ? shotId : null,
|
|
102
|
+
exportId: forExport ? exportId : null,
|
|
103
|
+
note: note || null,
|
|
104
|
+
createdBy: auth.userId,
|
|
105
|
+
});
|
|
106
|
+
const [described] = await describe(project, [deliverable]);
|
|
107
|
+
res.status(201).json({ deliverable: described });
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
res.status(500).json({ message: 'Failed to mark the deliverable', details: err.message });
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
router.delete('/projects/:projectId/deliverables/:deliverableId', async (req, res) => {
|
|
114
|
+
try {
|
|
115
|
+
const auth = req.auth;
|
|
116
|
+
const { projectId, deliverableId } = req.params;
|
|
117
|
+
const project = await Project.findOne({ _id: projectId });
|
|
118
|
+
if (!project)
|
|
119
|
+
return res.status(404).json({ message: 'Project not found' });
|
|
120
|
+
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
121
|
+
return res.status(403).json({ message: 'Unauthorized' });
|
|
122
|
+
if (!(await (0, deliverables_1.deleteDeliverable)(projectId, deliverableId)))
|
|
123
|
+
return res.status(404).json({ message: 'Deliverable not found' });
|
|
124
|
+
res.json({ message: 'Deliverable removed' });
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
res.status(500).json({ message: 'Failed to remove the deliverable', details: err.message });
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
return router;
|
|
131
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.exportRouter = exportRouter;
|
|
4
4
|
const express_1 = require("express");
|
|
5
|
+
const deliverables_1 = require("../../services/deliverables");
|
|
5
6
|
const manager_1 = require("../../models/manager");
|
|
6
7
|
const auth_1 = require("../../utils/auth");
|
|
7
8
|
const export_1 = require("../../services/export");
|
|
@@ -292,6 +293,7 @@ function exportRouter(config) {
|
|
|
292
293
|
return res.status(404).json({ message: 'Export not found in this project' });
|
|
293
294
|
}
|
|
294
295
|
await (0, export_1.deleteExport)(config, projectId, exportId, project.dbType);
|
|
296
|
+
await (0, deliverables_1.deleteDeliverablesOf)(projectId, { exportId });
|
|
295
297
|
res.status(200).json({ message: 'Export deleted successfully' });
|
|
296
298
|
}
|
|
297
299
|
catch (err) {
|
|
@@ -9,12 +9,16 @@ const auth_1 = require("../../utils/auth");
|
|
|
9
9
|
const connectionManager_1 = require("../../adapters/database/connectionManager");
|
|
10
10
|
const manager_1 = require("../../models/manager");
|
|
11
11
|
const crypto_1 = __importDefault(require("crypto"));
|
|
12
|
+
const deliverables_1 = require("../../services/deliverables");
|
|
13
|
+
const productionFields_1 = require("../../services/productionFields");
|
|
12
14
|
function getDb() {
|
|
13
15
|
const ids = (0, connectionManager_1.getConnectedIds)().filter(id => (0, connectionManager_1.getConnection)(id).type === 'nosql');
|
|
14
16
|
if (!ids.length)
|
|
15
17
|
return null;
|
|
16
18
|
return (0, connectionManager_1.getConnection)(ids[0]).client.db();
|
|
17
19
|
}
|
|
20
|
+
const SHOT_FIELDS = ['name', 'description', 'status', 'assignees', 'assetId', 'exportId', 'dueDate', 'order'];
|
|
21
|
+
const TASK_FIELDS = ['name', 'status', 'priority', 'assignee', 'dueDate', 'notes'];
|
|
18
22
|
function productionRouter(_config) {
|
|
19
23
|
const router = (0, express_1.Router)();
|
|
20
24
|
const Project = (0, manager_1.getModel)('projects');
|
|
@@ -45,14 +49,15 @@ function productionRouter(_config) {
|
|
|
45
49
|
try {
|
|
46
50
|
const auth = req.auth;
|
|
47
51
|
const { projectId } = req.params;
|
|
48
|
-
const { name, description, order } = req.body;
|
|
49
|
-
if (!name)
|
|
50
|
-
return res.status(400).json({ message: 'name is required' });
|
|
51
52
|
const project = await Project.findOne({ _id: projectId });
|
|
52
53
|
if (!project)
|
|
53
54
|
return res.status(404).json({ message: 'Project not found' });
|
|
54
55
|
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
55
56
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
57
|
+
const checked = (0, productionFields_1.checkProductionFields)(req.body, ['name', 'description', 'order'], project, { creating: true });
|
|
58
|
+
if ('error' in checked)
|
|
59
|
+
return res.status(400).json({ message: checked.error });
|
|
60
|
+
const { values } = checked;
|
|
56
61
|
const db = getDb();
|
|
57
62
|
if (!db)
|
|
58
63
|
return res.status(500).json({ message: 'Database not available' });
|
|
@@ -60,9 +65,9 @@ function productionRouter(_config) {
|
|
|
60
65
|
const sequence = {
|
|
61
66
|
id: crypto_1.default.randomUUID(),
|
|
62
67
|
projectId,
|
|
63
|
-
name,
|
|
64
|
-
description: description ?? null,
|
|
65
|
-
order: order ?? 0,
|
|
68
|
+
name: values.name,
|
|
69
|
+
description: values.description ?? null,
|
|
70
|
+
order: values.order ?? 0,
|
|
66
71
|
createdBy: auth.userId,
|
|
67
72
|
createdAt: now,
|
|
68
73
|
updatedAt: now,
|
|
@@ -86,14 +91,10 @@ function productionRouter(_config) {
|
|
|
86
91
|
const db = getDb();
|
|
87
92
|
if (!db)
|
|
88
93
|
return res.status(500).json({ message: 'Database not available' });
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (description !== undefined)
|
|
94
|
-
$set.description = description;
|
|
95
|
-
if (order !== undefined)
|
|
96
|
-
$set.order = order;
|
|
94
|
+
const checked = (0, productionFields_1.checkProductionFields)(req.body, ['name', 'description', 'order'], project);
|
|
95
|
+
if ('error' in checked)
|
|
96
|
+
return res.status(400).json({ message: checked.error });
|
|
97
|
+
const $set = { ...checked.values, updatedAt: new Date() };
|
|
97
98
|
const result = await db.collection('production_sequences').findOneAndUpdate({ id: seqId, projectId }, { $set }, { returnDocument: 'after' });
|
|
98
99
|
if (!result)
|
|
99
100
|
return res.status(404).json({ message: 'Sequence not found' });
|
|
@@ -115,8 +116,15 @@ function productionRouter(_config) {
|
|
|
115
116
|
const db = getDb();
|
|
116
117
|
if (!db)
|
|
117
118
|
return res.status(500).json({ message: 'Database not available' });
|
|
118
|
-
|
|
119
|
+
// With its shots, and their tasks and deliverables: nothing is left behind.
|
|
120
|
+
const shotIds = (await db.collection('production_shots').find({ sequenceId: seqId, projectId }).toArray()).map(s => s.id);
|
|
121
|
+
const { deletedCount } = await db.collection('production_sequences').deleteOne({ id: seqId, projectId });
|
|
122
|
+
if (!deletedCount)
|
|
123
|
+
return res.status(404).json({ message: 'Sequence not found' });
|
|
119
124
|
await db.collection('production_shots').deleteMany({ sequenceId: seqId, projectId });
|
|
125
|
+
if (shotIds.length)
|
|
126
|
+
await db.collection('production_tasks').deleteMany({ projectId, shotId: { $in: shotIds } });
|
|
127
|
+
await (0, deliverables_1.deleteDeliverablesOf)(projectId, { shotIds });
|
|
120
128
|
res.json({ message: 'Sequence deleted' });
|
|
121
129
|
}
|
|
122
130
|
catch (err) {
|
|
@@ -150,30 +158,34 @@ function productionRouter(_config) {
|
|
|
150
158
|
try {
|
|
151
159
|
const auth = req.auth;
|
|
152
160
|
const { projectId, seqId } = req.params;
|
|
153
|
-
const { name, description, status, assignedTo, assetId, exportId, dueDate, order } = req.body;
|
|
154
|
-
if (!name)
|
|
155
|
-
return res.status(400).json({ message: 'name is required' });
|
|
156
161
|
const project = await Project.findOne({ _id: projectId });
|
|
157
162
|
if (!project)
|
|
158
163
|
return res.status(404).json({ message: 'Project not found' });
|
|
159
164
|
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
160
165
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
166
|
+
const checked = (0, productionFields_1.checkProductionFields)(req.body, SHOT_FIELDS, project, { creating: true });
|
|
167
|
+
if ('error' in checked)
|
|
168
|
+
return res.status(400).json({ message: checked.error });
|
|
169
|
+
const { values } = checked;
|
|
161
170
|
const db = getDb();
|
|
162
171
|
if (!db)
|
|
163
172
|
return res.status(500).json({ message: 'Database not available' });
|
|
173
|
+
if (!(await db.collection('production_sequences').findOne({ id: seqId, projectId }))) {
|
|
174
|
+
return res.status(404).json({ message: 'Sequence not found' });
|
|
175
|
+
}
|
|
164
176
|
const now = new Date();
|
|
165
177
|
const shot = {
|
|
166
178
|
id: crypto_1.default.randomUUID(),
|
|
167
179
|
sequenceId: seqId,
|
|
168
180
|
projectId,
|
|
169
|
-
name,
|
|
170
|
-
description: description ?? null,
|
|
171
|
-
order: order ?? 0,
|
|
172
|
-
status: status ?? 'todo',
|
|
173
|
-
assignedTo: assignedTo ?? [],
|
|
174
|
-
assetId: assetId ?? null,
|
|
175
|
-
exportId: exportId ?? null,
|
|
176
|
-
dueDate: dueDate
|
|
181
|
+
name: values.name,
|
|
182
|
+
description: values.description ?? null,
|
|
183
|
+
order: values.order ?? 0,
|
|
184
|
+
status: values.status ?? 'todo',
|
|
185
|
+
assignedTo: values.assignedTo ?? [],
|
|
186
|
+
assetId: values.assetId ?? null,
|
|
187
|
+
exportId: values.exportId ?? null,
|
|
188
|
+
dueDate: values.dueDate ?? null,
|
|
177
189
|
createdBy: auth.userId,
|
|
178
190
|
createdAt: now,
|
|
179
191
|
updatedAt: now,
|
|
@@ -197,24 +209,10 @@ function productionRouter(_config) {
|
|
|
197
209
|
const db = getDb();
|
|
198
210
|
if (!db)
|
|
199
211
|
return res.status(500).json({ message: 'Database not available' });
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (description !== undefined)
|
|
205
|
-
$set.description = description;
|
|
206
|
-
if (status !== undefined)
|
|
207
|
-
$set.status = status;
|
|
208
|
-
if (assignedTo !== undefined)
|
|
209
|
-
$set.assignedTo = assignedTo;
|
|
210
|
-
if (assetId !== undefined)
|
|
211
|
-
$set.assetId = assetId;
|
|
212
|
-
if (exportId !== undefined)
|
|
213
|
-
$set.exportId = exportId;
|
|
214
|
-
if (dueDate !== undefined)
|
|
215
|
-
$set.dueDate = dueDate ? new Date(dueDate) : null;
|
|
216
|
-
if (order !== undefined)
|
|
217
|
-
$set.order = order;
|
|
212
|
+
const checked = (0, productionFields_1.checkProductionFields)(req.body, SHOT_FIELDS, project);
|
|
213
|
+
if ('error' in checked)
|
|
214
|
+
return res.status(400).json({ message: checked.error });
|
|
215
|
+
const $set = { ...checked.values, updatedAt: new Date() };
|
|
218
216
|
const result = await db.collection('production_shots').findOneAndUpdate({ id: shotId, projectId }, { $set }, { returnDocument: 'after' });
|
|
219
217
|
if (!result)
|
|
220
218
|
return res.status(404).json({ message: 'Shot not found' });
|
|
@@ -238,6 +236,7 @@ function productionRouter(_config) {
|
|
|
238
236
|
return res.status(500).json({ message: 'Database not available' });
|
|
239
237
|
await db.collection('production_shots').deleteOne({ id: shotId, projectId });
|
|
240
238
|
await db.collection('production_tasks').deleteMany({ shotId, projectId });
|
|
239
|
+
await (0, deliverables_1.deleteDeliverablesOf)(projectId, { shotIds: [shotId] });
|
|
241
240
|
res.json({ message: 'Shot deleted' });
|
|
242
241
|
}
|
|
243
242
|
catch (err) {
|
|
@@ -271,28 +270,32 @@ function productionRouter(_config) {
|
|
|
271
270
|
try {
|
|
272
271
|
const auth = req.auth;
|
|
273
272
|
const { projectId, shotId } = req.params;
|
|
274
|
-
const { name, status, priority, assignedTo, dueDate, notes } = req.body;
|
|
275
|
-
if (!name)
|
|
276
|
-
return res.status(400).json({ message: 'name is required' });
|
|
277
273
|
const project = await Project.findOne({ _id: projectId });
|
|
278
274
|
if (!project)
|
|
279
275
|
return res.status(404).json({ message: 'Project not found' });
|
|
280
276
|
if (!(0, auth_1.canEditProject)(project, auth.userId))
|
|
281
277
|
return res.status(403).json({ message: 'Unauthorized' });
|
|
278
|
+
const checked = (0, productionFields_1.checkProductionFields)(req.body, TASK_FIELDS, project, { creating: true });
|
|
279
|
+
if ('error' in checked)
|
|
280
|
+
return res.status(400).json({ message: checked.error });
|
|
281
|
+
const { values } = checked;
|
|
282
282
|
const db = getDb();
|
|
283
283
|
if (!db)
|
|
284
284
|
return res.status(500).json({ message: 'Database not available' });
|
|
285
|
+
if (!(await db.collection('production_shots').findOne({ id: shotId, projectId }))) {
|
|
286
|
+
return res.status(404).json({ message: 'Shot not found' });
|
|
287
|
+
}
|
|
285
288
|
const now = new Date();
|
|
286
289
|
const task = {
|
|
287
290
|
id: crypto_1.default.randomUUID(),
|
|
288
291
|
shotId,
|
|
289
292
|
projectId,
|
|
290
|
-
name,
|
|
291
|
-
status: status ?? 'todo',
|
|
292
|
-
priority: priority ?? 'medium',
|
|
293
|
-
assignedTo: assignedTo ?? null,
|
|
294
|
-
dueDate: dueDate
|
|
295
|
-
notes: notes ?? null,
|
|
293
|
+
name: values.name,
|
|
294
|
+
status: values.status ?? 'todo',
|
|
295
|
+
priority: values.priority ?? 'medium',
|
|
296
|
+
assignedTo: values.assignedTo ?? null,
|
|
297
|
+
dueDate: values.dueDate ?? null,
|
|
298
|
+
notes: values.notes ?? null,
|
|
296
299
|
createdBy: auth.userId,
|
|
297
300
|
createdAt: now,
|
|
298
301
|
updatedAt: now,
|
|
@@ -316,20 +319,10 @@ function productionRouter(_config) {
|
|
|
316
319
|
const db = getDb();
|
|
317
320
|
if (!db)
|
|
318
321
|
return res.status(500).json({ message: 'Database not available' });
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if (status !== undefined)
|
|
324
|
-
$set.status = status;
|
|
325
|
-
if (priority !== undefined)
|
|
326
|
-
$set.priority = priority;
|
|
327
|
-
if (assignedTo !== undefined)
|
|
328
|
-
$set.assignedTo = assignedTo;
|
|
329
|
-
if (dueDate !== undefined)
|
|
330
|
-
$set.dueDate = dueDate ? new Date(dueDate) : null;
|
|
331
|
-
if (notes !== undefined)
|
|
332
|
-
$set.notes = notes;
|
|
322
|
+
const checked = (0, productionFields_1.checkProductionFields)(req.body, TASK_FIELDS, project);
|
|
323
|
+
if ('error' in checked)
|
|
324
|
+
return res.status(400).json({ message: checked.error });
|
|
325
|
+
const $set = { ...checked.values, updatedAt: new Date() };
|
|
333
326
|
const result = await db.collection('production_tasks').findOneAndUpdate({ id: taskId, shotId, projectId }, { $set }, { returnDocument: 'after' });
|
|
334
327
|
if (!result)
|
|
335
328
|
return res.status(404).json({ message: 'Task not found' });
|
|
@@ -10,6 +10,8 @@ const sanitize_1 = require("../../utils/sanitize");
|
|
|
10
10
|
const projectIntegration_1 = require("../../services/projectIntegration");
|
|
11
11
|
const auth_2 = require("../../services/auth");
|
|
12
12
|
const apiTokens_1 = require("../../services/apiTokens");
|
|
13
|
+
const nosqlDb_1 = require("../../utils/nosqlDb");
|
|
14
|
+
const production_1 = require("../../services/production");
|
|
13
15
|
function projectRouter(config) {
|
|
14
16
|
const router = (0, express_1.Router)();
|
|
15
17
|
const Project = (0, manager_1.getModel)('projects');
|
|
@@ -204,7 +206,10 @@ function projectRouter(config) {
|
|
|
204
206
|
useCredentials: e.useCredentials,
|
|
205
207
|
}));
|
|
206
208
|
const sanitized = (0, sanitize_1.sanitizeProject)({ ...project, id: project._id || project.id, _id: undefined, connections: project.connections || [], exports });
|
|
207
|
-
|
|
209
|
+
// Whether it has production data, for its Production section to show even without a
|
|
210
|
+
// production node in its workflow.
|
|
211
|
+
const hasProductionData = !!(await (0, nosqlDb_1.nosqlDb)()?.collection('production_sequences').findOne({ projectId }));
|
|
212
|
+
res.json({ project: { ...sanitized, hasProductionData }, message: 'Project fetched successfully' });
|
|
208
213
|
}
|
|
209
214
|
catch (err) {
|
|
210
215
|
res.status(500).json({ message: 'Failed to fetch project', details: err.message });
|
|
@@ -257,8 +262,9 @@ function projectRouter(config) {
|
|
|
257
262
|
return res.status(403).json({ message: 'Only a project admin can delete it' });
|
|
258
263
|
}
|
|
259
264
|
await Project.useDbType(project.dbType).delete({ _id: projectId });
|
|
260
|
-
// Its tokens have nothing left to reach.
|
|
265
|
+
// Its tokens have nothing left to reach, and its production data nothing to belong to.
|
|
261
266
|
await (0, apiTokens_1.deleteProjectApiTokens)(String(projectId));
|
|
267
|
+
await (0, production_1.deleteProductionData)(String(projectId));
|
|
262
268
|
const allProjects = await Project.find({});
|
|
263
269
|
const projects = allProjects
|
|
264
270
|
.filter(project => {
|