streamby-core 0.25.6 → 0.25.8
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/dist/middleware/createRouter.js +4 -0
- package/dist/middleware/routes/member.d.ts +3 -0
- package/dist/middleware/routes/member.js +181 -0
- package/dist/middleware/routes/project.js +0 -32
- package/dist/middleware/routes/storage.js +38 -0
- package/dist/middleware/routes/user.d.ts +3 -0
- package/dist/middleware/routes/user.js +33 -0
- package/package.json +1 -1
|
@@ -15,6 +15,8 @@ const project_1 = require("./routes/project");
|
|
|
15
15
|
const export_1 = require("./routes/export");
|
|
16
16
|
const credential_1 = require("./routes/credential");
|
|
17
17
|
const apiConnection_1 = require("./routes/apiConnection");
|
|
18
|
+
const member_1 = require("./routes/member");
|
|
19
|
+
const user_1 = require("./routes/user");
|
|
18
20
|
const auth_2 = require("../services/auth");
|
|
19
21
|
const encryption_1 = require("../utils/encryption");
|
|
20
22
|
function createStreamByRouter(config) {
|
|
@@ -42,5 +44,7 @@ function createStreamByRouter(config) {
|
|
|
42
44
|
router.use((0, export_1.exportRouter)(config));
|
|
43
45
|
router.use((0, credential_1.credentialRouter)(config));
|
|
44
46
|
router.use((0, apiConnection_1.apiConnectionRouter)(config));
|
|
47
|
+
router.use((0, member_1.memberRouter)(config));
|
|
48
|
+
router.use((0, user_1.userRouter)(config));
|
|
45
49
|
return router;
|
|
46
50
|
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.memberRouter = memberRouter;
|
|
4
|
+
const express_1 = require("express");
|
|
5
|
+
const manager_1 = require("../../models/manager");
|
|
6
|
+
const auth_1 = require("../../utils/auth");
|
|
7
|
+
const connectionManager_1 = require("../../adapters/database/connectionManager");
|
|
8
|
+
const sql_1 = require("../../adapters/database/sql");
|
|
9
|
+
const VALID_ROLES = ['viewer', 'editor', 'admin'];
|
|
10
|
+
function memberRouter(config) {
|
|
11
|
+
const router = (0, express_1.Router)();
|
|
12
|
+
const Project = (0, manager_1.getModel)('projects');
|
|
13
|
+
const getSqlConnection = () => {
|
|
14
|
+
const sqlDb = config.databases?.find(db => db.type === 'sql');
|
|
15
|
+
if (!sqlDb || !(0, connectionManager_1.getConnectedIds)().includes(sqlDb.id))
|
|
16
|
+
return null;
|
|
17
|
+
return (0, connectionManager_1.getConnection)(sqlDb.id).client;
|
|
18
|
+
};
|
|
19
|
+
router.get('/projects/:id/members', async (req, res) => {
|
|
20
|
+
try {
|
|
21
|
+
const auth = req.auth;
|
|
22
|
+
const projectId = req.params.id;
|
|
23
|
+
const project = await Project.findOne({ _id: projectId });
|
|
24
|
+
if (!project) {
|
|
25
|
+
return res.status(404).json({ message: 'Project not found' });
|
|
26
|
+
}
|
|
27
|
+
if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
|
|
28
|
+
return res.status(403).json({ message: 'Unauthorized project access' });
|
|
29
|
+
}
|
|
30
|
+
const mainDb = config.databases?.find(db => db.main);
|
|
31
|
+
if (!mainDb) {
|
|
32
|
+
return res.status(500).json({ message: 'Main database not configured' });
|
|
33
|
+
}
|
|
34
|
+
const User = (0, manager_1.getModel)('users');
|
|
35
|
+
const membersWithUsernames = await Promise.all(project.members.map(async (member) => {
|
|
36
|
+
const user = await User.findOne({ _id: member.userId });
|
|
37
|
+
return {
|
|
38
|
+
userId: member.userId,
|
|
39
|
+
username: user ? user.username : 'Unknown',
|
|
40
|
+
role: member.role,
|
|
41
|
+
profilePic: user ? user.profilePic : '',
|
|
42
|
+
};
|
|
43
|
+
}));
|
|
44
|
+
res.json({ members: membersWithUsernames, message: 'Project members fetched successfully' });
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
res.status(500).json({ message: 'Failed to fetch project members', details: err.message });
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
router.post('/projects/:id/members', async (req, res) => {
|
|
51
|
+
try {
|
|
52
|
+
const auth = req.auth;
|
|
53
|
+
if (auth.role !== 'admin') {
|
|
54
|
+
return res.status(403).json({ message: 'Only admins can invite members' });
|
|
55
|
+
}
|
|
56
|
+
const projectId = req.params.id;
|
|
57
|
+
const { userId, role } = req.body;
|
|
58
|
+
if (!userId || !role) {
|
|
59
|
+
return res.status(400).json({ message: 'userId and role are required' });
|
|
60
|
+
}
|
|
61
|
+
if (!VALID_ROLES.includes(role)) {
|
|
62
|
+
return res.status(400).json({ message: `role must be one of: ${VALID_ROLES.join(', ')}` });
|
|
63
|
+
}
|
|
64
|
+
const project = await Project.findOne({ _id: projectId });
|
|
65
|
+
if (!project) {
|
|
66
|
+
return res.status(404).json({ message: 'Project not found' });
|
|
67
|
+
}
|
|
68
|
+
if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
|
|
69
|
+
return res.status(403).json({ message: 'Unauthorized project access' });
|
|
70
|
+
}
|
|
71
|
+
const alreadyMember = project.members?.some((m) => m.userId?.toString() === userId?.toString());
|
|
72
|
+
if (alreadyMember) {
|
|
73
|
+
return res.status(400).json({ message: 'User is already a member of this project' });
|
|
74
|
+
}
|
|
75
|
+
const User = (0, manager_1.getModel)('users');
|
|
76
|
+
const user = await User.findOne({ _id: userId });
|
|
77
|
+
if (!user) {
|
|
78
|
+
return res.status(404).json({ message: 'User not found' });
|
|
79
|
+
}
|
|
80
|
+
const newMember = { userId, username: user.username, role, archived: false };
|
|
81
|
+
if (project.dbType === 'sql') {
|
|
82
|
+
const connection = getSqlConnection();
|
|
83
|
+
if (!connection) {
|
|
84
|
+
return res.status(503).json({ message: 'SQL connection not available' });
|
|
85
|
+
}
|
|
86
|
+
await sql_1.sqlAdapter.create(connection, 'project_members', {
|
|
87
|
+
projectId,
|
|
88
|
+
userId,
|
|
89
|
+
role,
|
|
90
|
+
archived: false,
|
|
91
|
+
}, 'streamby');
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
await Project.update({ _id: projectId }, { $push: { members: newMember } });
|
|
95
|
+
}
|
|
96
|
+
res.status(201).json({ member: newMember, message: 'Member invited successfully' });
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
res.status(500).json({ message: 'Failed to invite member', details: err.message });
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
router.patch('/projects/:id/members/:userId', async (req, res) => {
|
|
103
|
+
try {
|
|
104
|
+
const auth = req.auth;
|
|
105
|
+
if (auth.role !== 'admin') {
|
|
106
|
+
return res.status(403).json({ message: 'Only admins can update member roles' });
|
|
107
|
+
}
|
|
108
|
+
const projectId = req.params.id;
|
|
109
|
+
const targetUserId = req.params.userId;
|
|
110
|
+
const { role } = req.body;
|
|
111
|
+
if (!role || !VALID_ROLES.includes(role)) {
|
|
112
|
+
return res.status(400).json({ message: `role must be one of: ${VALID_ROLES.join(', ')}` });
|
|
113
|
+
}
|
|
114
|
+
const project = await Project.findOne({ _id: projectId });
|
|
115
|
+
if (!project) {
|
|
116
|
+
return res.status(404).json({ message: 'Project not found' });
|
|
117
|
+
}
|
|
118
|
+
if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
|
|
119
|
+
return res.status(403).json({ message: 'Unauthorized project access' });
|
|
120
|
+
}
|
|
121
|
+
const memberExists = project.members?.some((m) => m.userId?.toString() === targetUserId?.toString());
|
|
122
|
+
if (!memberExists) {
|
|
123
|
+
return res.status(404).json({ message: 'Member not found in project' });
|
|
124
|
+
}
|
|
125
|
+
if (project.dbType === 'sql') {
|
|
126
|
+
const connection = getSqlConnection();
|
|
127
|
+
if (!connection) {
|
|
128
|
+
return res.status(503).json({ message: 'SQL connection not available' });
|
|
129
|
+
}
|
|
130
|
+
await sql_1.sqlAdapter.update(connection, 'project_members', { projectId, userId: targetUserId }, { role }, 'streamby');
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
const updatedMembers = project.members.map((m) => m.userId?.toString() === targetUserId?.toString() ? { ...m, role } : m);
|
|
134
|
+
await Project.update({ _id: projectId }, { members: updatedMembers });
|
|
135
|
+
}
|
|
136
|
+
res.status(200).json({ message: 'Member role updated successfully' });
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
res.status(500).json({ message: 'Failed to update member role', details: err.message });
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
router.delete('/projects/:id/members/:userId', async (req, res) => {
|
|
143
|
+
try {
|
|
144
|
+
const auth = req.auth;
|
|
145
|
+
if (auth.role !== 'admin') {
|
|
146
|
+
return res.status(403).json({ message: 'Only admins can remove members' });
|
|
147
|
+
}
|
|
148
|
+
const projectId = req.params.id;
|
|
149
|
+
const targetUserId = req.params.userId;
|
|
150
|
+
if (targetUserId === auth.userId) {
|
|
151
|
+
return res.status(400).json({ message: 'Cannot remove yourself from the project' });
|
|
152
|
+
}
|
|
153
|
+
const project = await Project.findOne({ _id: projectId });
|
|
154
|
+
if (!project) {
|
|
155
|
+
return res.status(404).json({ message: 'Project not found' });
|
|
156
|
+
}
|
|
157
|
+
if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
|
|
158
|
+
return res.status(403).json({ message: 'Unauthorized project access' });
|
|
159
|
+
}
|
|
160
|
+
const memberExists = project.members?.some((m) => m.userId?.toString() === targetUserId?.toString());
|
|
161
|
+
if (!memberExists) {
|
|
162
|
+
return res.status(404).json({ message: 'Member not found in project' });
|
|
163
|
+
}
|
|
164
|
+
if (project.dbType === 'sql') {
|
|
165
|
+
const connection = getSqlConnection();
|
|
166
|
+
if (!connection) {
|
|
167
|
+
return res.status(503).json({ message: 'SQL connection not available' });
|
|
168
|
+
}
|
|
169
|
+
await sql_1.sqlAdapter.delete(connection, 'project_members', { projectId, userId: targetUserId }, 'streamby');
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
await Project.update({ _id: projectId }, { $pull: { members: { userId: targetUserId } } });
|
|
173
|
+
}
|
|
174
|
+
res.status(200).json({ message: 'Member removed successfully' });
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
res.status(500).json({ message: 'Failed to remove member', details: err.message });
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
return router;
|
|
181
|
+
}
|
|
@@ -234,38 +234,6 @@ function projectRouter(config) {
|
|
|
234
234
|
res.status(500).json({ message: 'Failed to unarchive project', details: err.message });
|
|
235
235
|
}
|
|
236
236
|
});
|
|
237
|
-
router.get('/projects/:id/members', async (req, res) => {
|
|
238
|
-
try {
|
|
239
|
-
const auth = req.auth;
|
|
240
|
-
const projectId = req.params.id;
|
|
241
|
-
const project = await Project.findOne({ _id: projectId });
|
|
242
|
-
if (!project) {
|
|
243
|
-
return res.status(404).json({ message: 'Project not found' });
|
|
244
|
-
}
|
|
245
|
-
if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
|
|
246
|
-
return res.status(403).json({ message: 'Unauthorized project access' });
|
|
247
|
-
}
|
|
248
|
-
const mainDb = config.databases?.find(db => db.main);
|
|
249
|
-
if (!mainDb) {
|
|
250
|
-
return res.status(500).json({ message: 'Main database not configured' });
|
|
251
|
-
}
|
|
252
|
-
const userDbType = mainDb.type;
|
|
253
|
-
const User = (0, manager_1.getModel)('users', userDbType);
|
|
254
|
-
const membersWithUsernames = await Promise.all(project.members.map(async (member) => {
|
|
255
|
-
const user = await User.findOne({ _id: member.userId });
|
|
256
|
-
return {
|
|
257
|
-
userId: member.userId,
|
|
258
|
-
username: user ? user.username : 'Unknown',
|
|
259
|
-
role: member.role,
|
|
260
|
-
profilePic: user ? user.profilePic : ''
|
|
261
|
-
};
|
|
262
|
-
}));
|
|
263
|
-
res.json({ members: membersWithUsernames, message: 'Project members fetched successfully' });
|
|
264
|
-
}
|
|
265
|
-
catch (err) {
|
|
266
|
-
res.status(500).json({ message: 'Failed to fetch project members', details: err.message });
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
237
|
router.post('/projects/:id/image', async (req, res) => {
|
|
270
238
|
try {
|
|
271
239
|
const auth = req.auth;
|
|
@@ -170,6 +170,44 @@ function storageRouter(config) {
|
|
|
170
170
|
res.status(500).json({ message: 'Failed to list files', details: err.message });
|
|
171
171
|
}
|
|
172
172
|
});
|
|
173
|
+
router.patch('/projects/:projectId/storage/:category/:key', async (req, res) => {
|
|
174
|
+
try {
|
|
175
|
+
const auth = await config.authProvider(req);
|
|
176
|
+
if (!auth || !auth.userId || !auth.role) {
|
|
177
|
+
return res.status(401).json({ message: 'Unauthorized' });
|
|
178
|
+
}
|
|
179
|
+
const { projectId, category } = req.params;
|
|
180
|
+
const key = decodeURIComponent(req.params.key);
|
|
181
|
+
const { contentType } = req.body;
|
|
182
|
+
if (!VALID_CATEGORIES.includes(category)) {
|
|
183
|
+
return res.status(400).json({ message: `Invalid category. Must be one of: ${VALID_CATEGORIES.join(', ')}` });
|
|
184
|
+
}
|
|
185
|
+
if (!contentType) {
|
|
186
|
+
return res.status(400).json({ message: 'contentType is required' });
|
|
187
|
+
}
|
|
188
|
+
if (!validateContentType(contentType, key, category)) {
|
|
189
|
+
const hint = category === '3d-models'
|
|
190
|
+
? '.glb, .gltf, .obj, .fbx, .stl, or .ply'
|
|
191
|
+
: `${category.slice(0, -1)}/* content type`;
|
|
192
|
+
return res.status(400).json({ message: `Files in the ${category} category must match ${hint}` });
|
|
193
|
+
}
|
|
194
|
+
const project = await Project.findOne({ _id: projectId });
|
|
195
|
+
if (!project) {
|
|
196
|
+
return res.status(404).json({ message: 'Project not found' });
|
|
197
|
+
}
|
|
198
|
+
if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
|
|
199
|
+
return res.status(403).json({ message: 'Unauthorized access' });
|
|
200
|
+
}
|
|
201
|
+
if (!adapter.getPresignedUploadUrl) {
|
|
202
|
+
return res.status(501).json({ message: 'Storage adapter does not support presigned uploads' });
|
|
203
|
+
}
|
|
204
|
+
const url = await adapter.getPresignedUploadUrl(key, contentType);
|
|
205
|
+
res.json({ url });
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
res.status(500).json({ message: 'Failed to generate overwrite URL', details: err.message });
|
|
209
|
+
}
|
|
210
|
+
});
|
|
173
211
|
router.delete('/projects/:projectId/storage/:category/:key', async (req, res) => {
|
|
174
212
|
try {
|
|
175
213
|
const auth = await config.authProvider(req);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.userRouter = userRouter;
|
|
4
|
+
const express_1 = require("express");
|
|
5
|
+
const manager_1 = require("../../models/manager");
|
|
6
|
+
function userRouter(config) {
|
|
7
|
+
const router = (0, express_1.Router)();
|
|
8
|
+
const User = (0, manager_1.getModel)('users');
|
|
9
|
+
router.get('/users/search', async (req, res) => {
|
|
10
|
+
try {
|
|
11
|
+
const auth = req.auth;
|
|
12
|
+
const q = (req.query.q || '').trim();
|
|
13
|
+
if (!q) {
|
|
14
|
+
return res.status(400).json({ message: 'Query param q is required' });
|
|
15
|
+
}
|
|
16
|
+
const allUsers = await User.find({});
|
|
17
|
+
const lower = q.toLowerCase();
|
|
18
|
+
const users = allUsers
|
|
19
|
+
.filter((u) => u.username?.toLowerCase().includes(lower))
|
|
20
|
+
.slice(0, 20)
|
|
21
|
+
.map((u) => ({
|
|
22
|
+
id: u._id || u.id,
|
|
23
|
+
username: u.username,
|
|
24
|
+
profilePic: u.profilePic || '',
|
|
25
|
+
}));
|
|
26
|
+
res.json({ users });
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
res.status(500).json({ message: 'Failed to search users', details: err.message });
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return router;
|
|
33
|
+
}
|