streamby-core 0.43.0 → 0.44.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
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.43.1
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Inviting a member to a SQL project, or asking to join one, answered 500**: both write who
|
|
8
|
+
invited the member (`invitedBy`), a column `streamby.project_members` didn't have. It's added
|
|
9
|
+
at startup to existing tables, and is in the table made new.
|
|
10
|
+
- **Accepting or rejecting an invitation to a SQL project failed too**: they changed the project's
|
|
11
|
+
`members` as a MongoDB project has them, a field a SQL project doesn't have (its members are
|
|
12
|
+
rows of `project_members`); they change the member's row now. A SQL project's members are read
|
|
13
|
+
with `invitedBy`, so whoever invited them is told the answer.
|
|
14
|
+
|
|
3
15
|
## 0.43.0
|
|
4
16
|
|
|
5
17
|
### Added
|
|
@@ -123,6 +123,7 @@ const createTables = async (pool) => {
|
|
|
123
123
|
archived BOOLEAN NOT NULL DEFAULT FALSE,
|
|
124
124
|
"archivedBy" VARCHAR(255),
|
|
125
125
|
"archivedAt" TIMESTAMP WITH TIME ZONE,
|
|
126
|
+
"invitedBy" VARCHAR(255),
|
|
126
127
|
"createdAt" TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
127
128
|
"updatedAt" TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
128
129
|
UNIQUE ("projectId", "userId")
|
|
@@ -130,6 +131,8 @@ const createTables = async (pool) => {
|
|
|
130
131
|
`);
|
|
131
132
|
await pool.query(`
|
|
132
133
|
ALTER TABLE streamby.project_members ADD COLUMN IF NOT EXISTS status VARCHAR(50) NOT NULL DEFAULT 'active';
|
|
134
|
+
-- Who invited a pending member (or the member, asking to join): told when it's answered.
|
|
135
|
+
ALTER TABLE streamby.project_members ADD COLUMN IF NOT EXISTS "invitedBy" VARCHAR(255);
|
|
133
136
|
`);
|
|
134
137
|
console.log('✅ "project_members" table ensured to exist.');
|
|
135
138
|
// Migrate projectId FK column from UUID to TEXT if table predates this schema version
|
|
@@ -157,9 +157,19 @@ function memberRouter(config) {
|
|
|
157
157
|
if (member.status !== 'pending') {
|
|
158
158
|
return res.status(400).json({ message: 'Invitation is no longer pending' });
|
|
159
159
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
if (project.dbType === 'sql') {
|
|
161
|
+
// A SQL project's members are rows of project_members, not a field of the project.
|
|
162
|
+
const connection = getSqlConnection();
|
|
163
|
+
if (!connection) {
|
|
164
|
+
return res.status(503).json({ message: 'SQL connection not available' });
|
|
165
|
+
}
|
|
166
|
+
await sql_1.sqlAdapter.update(connection, 'project_members', { projectId, userId: targetUserId }, { status: 'active' }, 'streamby');
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
const updatedMembers = project.members.map((m) => m.userId?.toString() === targetUserId ? { ...m, status: 'active' } : m);
|
|
170
|
+
await Project.update({ _id: projectId }, { members: updatedMembers });
|
|
171
|
+
}
|
|
172
|
+
await (0, notification_1.createNotification)(member.invitedBy, 'member_accepted', `${member.username ?? auth.username} aceptó la invitación al proyecto "${project.name}"`, { projectId, userId: targetUserId });
|
|
163
173
|
res.status(200).json({ message: 'Invitation accepted' });
|
|
164
174
|
}
|
|
165
175
|
catch (err) {
|
|
@@ -184,8 +194,17 @@ function memberRouter(config) {
|
|
|
184
194
|
if (member.status !== 'pending') {
|
|
185
195
|
return res.status(400).json({ message: 'Invitation is no longer pending' });
|
|
186
196
|
}
|
|
187
|
-
|
|
188
|
-
|
|
197
|
+
if (project.dbType === 'sql') {
|
|
198
|
+
const connection = getSqlConnection();
|
|
199
|
+
if (!connection) {
|
|
200
|
+
return res.status(503).json({ message: 'SQL connection not available' });
|
|
201
|
+
}
|
|
202
|
+
await sql_1.sqlAdapter.delete(connection, 'project_members', { projectId, userId: targetUserId }, 'streamby');
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
await Project.update({ _id: projectId }, { $pull: { members: { userId: targetUserId } } });
|
|
206
|
+
}
|
|
207
|
+
await (0, notification_1.createNotification)(member.invitedBy, 'member_rejected', `${member.username ?? auth.username} rechazó la invitación al proyecto "${project.name}"`, { projectId, userId: targetUserId });
|
|
189
208
|
res.status(200).json({ message: 'Invitation rejected' });
|
|
190
209
|
}
|
|
191
210
|
catch (err) {
|
|
@@ -19,6 +19,12 @@ function getDb() {
|
|
|
19
19
|
}
|
|
20
20
|
const SHOT_FIELDS = ['name', 'description', 'status', 'assignees', 'assetId', 'exportId', 'dueDate', 'order'];
|
|
21
21
|
const TASK_FIELDS = ['name', 'status', 'priority', 'assignee', 'dueDate', 'notes'];
|
|
22
|
+
const PRIORITY_RANK = { low: 1, medium: 2, high: 3 };
|
|
23
|
+
const summaryOf = (tasks) => {
|
|
24
|
+
const open = tasks.filter(t => t.status !== 'done');
|
|
25
|
+
const priority = open.reduce((top, t) => (t.priority && (PRIORITY_RANK[t.priority] ?? 0) > (top ? PRIORITY_RANK[top] : 0) ? t.priority : top), null);
|
|
26
|
+
return { done: tasks.length - open.length, total: tasks.length, priority };
|
|
27
|
+
};
|
|
22
28
|
function productionRouter(_config) {
|
|
23
29
|
const router = (0, express_1.Router)();
|
|
24
30
|
const Project = (0, manager_1.getModel)('projects');
|
|
@@ -148,7 +154,15 @@ function productionRouter(_config) {
|
|
|
148
154
|
.find({ sequenceId: seqId, projectId })
|
|
149
155
|
.sort({ order: 1, createdAt: 1 })
|
|
150
156
|
.toArray();
|
|
151
|
-
|
|
157
|
+
// Each shot with how its tasks go, as a board's card shows it: how many are done of how
|
|
158
|
+
// many, and the highest priority among those still open.
|
|
159
|
+
const tasks = shots.length
|
|
160
|
+
? await db.collection('production_tasks')
|
|
161
|
+
.find({ projectId, shotId: { $in: shots.map(sh => sh.id) } })
|
|
162
|
+
.project({ shotId: 1, status: 1, priority: 1 })
|
|
163
|
+
.toArray()
|
|
164
|
+
: [];
|
|
165
|
+
res.json({ shots: shots.map(sh => ({ ...sh, taskSummary: summaryOf(tasks.filter(t => t.shotId === sh.id)) })) });
|
|
152
166
|
}
|
|
153
167
|
catch (err) {
|
|
154
168
|
res.status(500).json({ message: err.message });
|
package/dist/models/Model.js
CHANGED
|
@@ -48,27 +48,6 @@ class Model {
|
|
|
48
48
|
const result = await connection.query(`SELECT * FROM "${schema}"."projects" WHERE "dbConnections" @> $1::jsonb OR "storageConnections" @> $1::jsonb OR "integrationConnections" @> $1::jsonb`, [has]);
|
|
49
49
|
sqlResults = result.rows;
|
|
50
50
|
}
|
|
51
|
-
else if (this.tableName === 'projects' && processedFilter.members && processedFilter.members.$elemMatch) {
|
|
52
|
-
// Handle members filter for SQL projects
|
|
53
|
-
const userId = processedFilter.members.$elemMatch.userId;
|
|
54
|
-
const schema = this.schema || 'streamby'; // Default to 'streamby' if schema not provided
|
|
55
|
-
const query = `
|
|
56
|
-
SELECT p.*, pm."userId" as memberUserId, pm.role as memberRole, pm.status as memberStatus, pm.archived as memberArchived
|
|
57
|
-
FROM "${schema}"."projects" p
|
|
58
|
-
JOIN "${schema}"."project_members" pm ON p.id = pm."projectId"
|
|
59
|
-
WHERE pm."userId" = $1
|
|
60
|
-
`;
|
|
61
|
-
const result = await connection.query(query, [userId]);
|
|
62
|
-
sqlResults = result.rows.map(row => ({
|
|
63
|
-
...row,
|
|
64
|
-
members: [{
|
|
65
|
-
userId: row.memberUserId,
|
|
66
|
-
role: row.memberRole,
|
|
67
|
-
status: row.memberStatus,
|
|
68
|
-
archived: row.memberArchived,
|
|
69
|
-
}]
|
|
70
|
-
}));
|
|
71
|
-
}
|
|
72
51
|
else {
|
|
73
52
|
// General SQL find
|
|
74
53
|
sqlResults = await sql_1.sqlAdapter.find(connection, this.tableName, processedFilter, this.schema);
|
|
@@ -76,13 +55,14 @@ class Model {
|
|
|
76
55
|
for (const item of sqlResults) {
|
|
77
56
|
const transformedItem = this.transformResult(item);
|
|
78
57
|
if (this.tableName === 'projects' && !transformedItem.members) {
|
|
79
|
-
//
|
|
58
|
+
// A SQL project's members are rows of project_members, read with it
|
|
80
59
|
const projectMembers = await sql_1.sqlAdapter.find(connection, 'project_members', { projectId: transformedItem.id }, this.schema);
|
|
81
60
|
transformedItem.members = projectMembers.map((member) => ({
|
|
82
61
|
userId: member.userId,
|
|
83
62
|
role: member.role,
|
|
84
63
|
status: member.status,
|
|
85
64
|
archived: member.archived,
|
|
65
|
+
...(member.invitedBy ? { invitedBy: member.invitedBy } : {}),
|
|
86
66
|
}));
|
|
87
67
|
}
|
|
88
68
|
allResults.push(transformedItem);
|
|
@@ -138,6 +118,7 @@ class Model {
|
|
|
138
118
|
role: member.role,
|
|
139
119
|
status: member.status,
|
|
140
120
|
archived: member.archived,
|
|
121
|
+
...(member.invitedBy ? { invitedBy: member.invitedBy } : {}),
|
|
141
122
|
}));
|
|
142
123
|
}
|
|
143
124
|
// Track which connection found this record so update() routes correctly
|