powr-sdk-api 2.3.7 → 2.4.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/dist/config.js +1 -3
- package/dist/index.js +1 -17
- package/dist/middleware/jwtToken.js +6 -3
- package/dist/middleware/projectId.js +42 -0
- package/dist/routes/auth.js +28 -17
- package/dist/routes/files.js +13 -14
- package/dist/routes/forms.js +49 -1
- package/dist/routes/index.js +10 -25
- package/dist/routes/plexx.js +0 -5
- package/dist/routes/profiles.js +60 -0
- package/dist/routes/routes.js +1 -1
- package/dist/routes/users.js +165 -109
- package/dist/routes/waitlists.js +60 -45
- package/dist/services/dbService.js +25 -23
- package/package.json +1 -1
package/dist/config.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -7,36 +7,20 @@ const {
|
|
|
7
7
|
const {
|
|
8
8
|
requestHandler
|
|
9
9
|
} = require("./middleware/request");
|
|
10
|
-
const {
|
|
11
|
-
validateAuth,
|
|
12
|
-
generateToken
|
|
13
|
-
} = require("./middleware/auth");
|
|
14
10
|
const {
|
|
15
11
|
notFoundHandler
|
|
16
12
|
} = require("./middleware/notfound");
|
|
17
13
|
const {
|
|
18
14
|
createSwaggerSpec
|
|
19
15
|
} = require("./swagger");
|
|
20
|
-
const {
|
|
21
|
-
cloudLogger
|
|
22
|
-
} = require("./logger");
|
|
23
16
|
const {
|
|
24
17
|
createPowrRoutes
|
|
25
18
|
} = require("./routes");
|
|
26
|
-
const {
|
|
27
|
-
generateJWTToken,
|
|
28
|
-
verifyToken
|
|
29
|
-
} = require("./middleware/jwtToken");
|
|
30
19
|
module.exports = {
|
|
31
20
|
errorCatcher,
|
|
32
21
|
errorHandler,
|
|
33
22
|
requestHandler,
|
|
34
|
-
cloudLogger,
|
|
35
23
|
createSwaggerSpec,
|
|
36
|
-
generateToken,
|
|
37
|
-
validateAuth,
|
|
38
24
|
notFoundHandler,
|
|
39
|
-
createPowrRoutes
|
|
40
|
-
generateJWTToken,
|
|
41
|
-
verifyToken
|
|
25
|
+
createPowrRoutes
|
|
42
26
|
};
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const jwt = require('jsonwebtoken');
|
|
4
|
-
const {
|
|
5
|
-
ObjectId
|
|
6
|
-
} = require('mongodb');
|
|
7
4
|
const config = require('../config');
|
|
8
5
|
const generateJWTToken = (user, profile = null) => {
|
|
9
6
|
return jwt.sign({
|
|
@@ -29,6 +26,12 @@ const verifyToken = async (req, res, next) => {
|
|
|
29
26
|
|
|
30
27
|
// Extract token (remove 'Bearer ' if present)
|
|
31
28
|
const token = authHeader.startsWith("Bearer ") ? authHeader.slice(7) : authHeader;
|
|
29
|
+
if (!token) {
|
|
30
|
+
return res.status(401).json({
|
|
31
|
+
success: false,
|
|
32
|
+
message: 'No token provided'
|
|
33
|
+
});
|
|
34
|
+
}
|
|
32
35
|
|
|
33
36
|
// Verify JWT token
|
|
34
37
|
const decoded = jwt.verify(token, config.jwtToken);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const config = require('../config');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Middleware to inject projectId into requests
|
|
7
|
+
* @param {Object} options - Configuration options
|
|
8
|
+
* @param {boolean} options.isCentralService - Whether this is a central service (like powr-base-cloud)
|
|
9
|
+
* @returns {Function} Express middleware function
|
|
10
|
+
*/
|
|
11
|
+
const injectProjectId = (options = {}) => {
|
|
12
|
+
const isCentralService = options.isCentralService || false;
|
|
13
|
+
return (req, res, next) => {
|
|
14
|
+
try {
|
|
15
|
+
if (isCentralService) {
|
|
16
|
+
// For central services, get projectId from request
|
|
17
|
+
const projectId = req.query.projectId || req.body.projectId;
|
|
18
|
+
if (!projectId) {
|
|
19
|
+
return res.status(400).json({
|
|
20
|
+
success: false,
|
|
21
|
+
message: 'projectId is required for central services'
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
req.projectId = projectId;
|
|
25
|
+
} else {
|
|
26
|
+
// For individual APIs, use config.projectId
|
|
27
|
+
req.projectId = config.projectId;
|
|
28
|
+
}
|
|
29
|
+
next();
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('❌ ProjectId injection error:', error.message);
|
|
32
|
+
return res.status(500).json({
|
|
33
|
+
success: false,
|
|
34
|
+
message: 'Configuration error',
|
|
35
|
+
error: error.message
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
module.exports = {
|
|
41
|
+
injectProjectId
|
|
42
|
+
};
|
package/dist/routes/auth.js
CHANGED
|
@@ -4,14 +4,13 @@ const express = require("express");
|
|
|
4
4
|
const router = express.Router();
|
|
5
5
|
const {
|
|
6
6
|
getDb
|
|
7
|
-
} = require("../services/
|
|
7
|
+
} = require("../services/mongo");
|
|
8
8
|
const {
|
|
9
9
|
ObjectId
|
|
10
10
|
} = require("mongodb");
|
|
11
11
|
const bcrypt = require("bcrypt");
|
|
12
12
|
const {
|
|
13
|
-
generateJWTToken
|
|
14
|
-
verifyToken
|
|
13
|
+
generateJWTToken
|
|
15
14
|
} = require("../middleware/jwtToken");
|
|
16
15
|
const {
|
|
17
16
|
config
|
|
@@ -23,9 +22,10 @@ router.post("/register", async (req, res) => {
|
|
|
23
22
|
fullName,
|
|
24
23
|
username,
|
|
25
24
|
phoneOrEmail,
|
|
26
|
-
password
|
|
27
|
-
projectId
|
|
25
|
+
password
|
|
28
26
|
} = req.body;
|
|
27
|
+
const projectId = req.projectId; // Use middleware-injected projectId
|
|
28
|
+
|
|
29
29
|
try {
|
|
30
30
|
if (!(username || phoneOrEmail)) {
|
|
31
31
|
return res.status(400).json({
|
|
@@ -45,14 +45,6 @@ router.post("/register", async (req, res) => {
|
|
|
45
45
|
message: "Full name is required"
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
// if (!projectId) {
|
|
50
|
-
// return res.status(400).json({
|
|
51
|
-
// success: false,
|
|
52
|
-
// message: "Project ID is required"
|
|
53
|
-
// });
|
|
54
|
-
// }
|
|
55
|
-
|
|
56
48
|
let q = username ? {
|
|
57
49
|
username: username
|
|
58
50
|
} : {
|
|
@@ -109,9 +101,10 @@ router.post("/login", async (req, res) => {
|
|
|
109
101
|
const {
|
|
110
102
|
username,
|
|
111
103
|
phoneOrEmail,
|
|
112
|
-
password
|
|
113
|
-
projectId
|
|
104
|
+
password
|
|
114
105
|
} = req.body;
|
|
106
|
+
const projectId = req.projectId; // Use middleware-injected projectId
|
|
107
|
+
|
|
115
108
|
try {
|
|
116
109
|
if (!(username || phoneOrEmail)) {
|
|
117
110
|
return res.status(400).json({
|
|
@@ -185,13 +178,31 @@ router.post("/login", async (req, res) => {
|
|
|
185
178
|
const token = generateJWTToken(user, profile);
|
|
186
179
|
const {
|
|
187
180
|
password: _,
|
|
181
|
+
_id,
|
|
188
182
|
...userWithoutPassword
|
|
189
183
|
} = user;
|
|
184
|
+
let mergedUser = {
|
|
185
|
+
...userWithoutPassword,
|
|
186
|
+
powrId: user._id
|
|
187
|
+
};
|
|
188
|
+
if (profile) {
|
|
189
|
+
const {
|
|
190
|
+
_id,
|
|
191
|
+
userId,
|
|
192
|
+
projectId,
|
|
193
|
+
createdAt,
|
|
194
|
+
updatedAt,
|
|
195
|
+
...profileData
|
|
196
|
+
} = profile;
|
|
197
|
+
mergedUser = {
|
|
198
|
+
...mergedUser,
|
|
199
|
+
...profileData
|
|
200
|
+
};
|
|
201
|
+
}
|
|
190
202
|
return res.status(200).json({
|
|
191
203
|
success: true,
|
|
192
204
|
message: "Login successful",
|
|
193
|
-
user:
|
|
194
|
-
profile: profile,
|
|
205
|
+
user: mergedUser,
|
|
195
206
|
token: token
|
|
196
207
|
});
|
|
197
208
|
} catch (error) {
|
package/dist/routes/files.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const express = require('express');
|
|
4
|
+
const router = express.Router();
|
|
4
5
|
const multer = require('multer');
|
|
5
6
|
// const { uploadToGCS, bucket } = require('../uploadToGCS')
|
|
6
|
-
const {
|
|
7
|
-
bucket,
|
|
8
|
-
uploadToGCS,
|
|
9
|
-
bucketName
|
|
10
|
-
} = require('../uploadToGCS.js');
|
|
7
|
+
// const { bucket, uploadToGCS, bucketName } = require('../uploadToGCS.js')
|
|
11
8
|
// const uploadToGCS = require('../uploadToGCS.js')
|
|
12
9
|
|
|
13
|
-
const router = express.Router();
|
|
14
10
|
const upload = multer();
|
|
15
11
|
router.post('/', upload.single('file'), async (req, res) => {
|
|
16
12
|
try {
|
|
@@ -20,11 +16,13 @@ router.post('/', upload.single('file'), async (req, res) => {
|
|
|
20
16
|
message: 'No file uploaded'
|
|
21
17
|
});
|
|
22
18
|
}
|
|
23
|
-
|
|
19
|
+
|
|
20
|
+
// const url = await uploadToGCS(req.file);
|
|
21
|
+
|
|
24
22
|
return res.status(200).json({
|
|
25
23
|
status: 'success',
|
|
26
|
-
message: 'File uploaded successfully'
|
|
27
|
-
url
|
|
24
|
+
message: 'File uploaded successfully'
|
|
25
|
+
// url,
|
|
28
26
|
});
|
|
29
27
|
} catch (err) {
|
|
30
28
|
console.error('Error uploading file:', err);
|
|
@@ -37,12 +35,13 @@ router.post('/', upload.single('file'), async (req, res) => {
|
|
|
37
35
|
});
|
|
38
36
|
router.get('/', async (req, res) => {
|
|
39
37
|
try {
|
|
40
|
-
const [files] = await bucket.getFiles();
|
|
41
|
-
const bucketName = bucket.name;
|
|
42
|
-
const imageUrls = files.map(file => `https://storage.googleapis.com/${bucketName}/${file.name}`);
|
|
38
|
+
// const [files] = await bucket.getFiles();
|
|
39
|
+
// const bucketName = bucket.name;
|
|
40
|
+
// const imageUrls = files.map(file => `https://storage.googleapis.com/${bucketName}/${file.name}`);
|
|
41
|
+
|
|
43
42
|
return res.status(200).json({
|
|
44
|
-
message: 'Images fetched successfully'
|
|
45
|
-
images: imageUrls
|
|
43
|
+
message: 'Images fetched successfully'
|
|
44
|
+
// images: imageUrls,
|
|
46
45
|
});
|
|
47
46
|
} catch (err) {
|
|
48
47
|
console.error('Error listing files from GCS:', err);
|
package/dist/routes/forms.js
CHANGED
|
@@ -6,7 +6,7 @@ const multer = require('multer');
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const {
|
|
8
8
|
getDb
|
|
9
|
-
} = require(
|
|
9
|
+
} = require("../services/mongo");
|
|
10
10
|
const upload = multer({
|
|
11
11
|
storage: multer.memoryStorage(),
|
|
12
12
|
fileFilter: function (req, file, cb) {
|
|
@@ -239,4 +239,52 @@ router.post('/create-form', upload.single('jsonFile'), async (req, res) => {
|
|
|
239
239
|
});
|
|
240
240
|
}
|
|
241
241
|
});
|
|
242
|
+
|
|
243
|
+
// Get form submissions
|
|
244
|
+
router.get("/submissions", async (req, res) => {
|
|
245
|
+
const projectId = req.projectId; // Use middleware-injected projectId
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
const db = await getDb();
|
|
249
|
+
const submissions = await db.collection("formSubmissions").find({
|
|
250
|
+
projectId
|
|
251
|
+
}).toArray();
|
|
252
|
+
return res.json({
|
|
253
|
+
success: true,
|
|
254
|
+
data: submissions
|
|
255
|
+
});
|
|
256
|
+
} catch (error) {
|
|
257
|
+
console.error("Error fetching form submissions:", error);
|
|
258
|
+
return res.status(500).json({
|
|
259
|
+
success: false,
|
|
260
|
+
message: "Failed to fetch form submissions."
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// Get form submissions by form ID
|
|
266
|
+
router.get("/submissions/:formId", async (req, res) => {
|
|
267
|
+
const {
|
|
268
|
+
formId
|
|
269
|
+
} = req.params;
|
|
270
|
+
const projectId = req.projectId; // Use middleware-injected projectId
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
const db = await getDb();
|
|
274
|
+
const submissions = await db.collection("formSubmissions").find({
|
|
275
|
+
formId,
|
|
276
|
+
projectId
|
|
277
|
+
}).toArray();
|
|
278
|
+
return res.json({
|
|
279
|
+
success: true,
|
|
280
|
+
data: submissions
|
|
281
|
+
});
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.error("Error fetching form submissions:", error);
|
|
284
|
+
return res.status(500).json({
|
|
285
|
+
success: false,
|
|
286
|
+
message: "Failed to fetch form submissions."
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
});
|
|
242
290
|
module.exports = router;
|
package/dist/routes/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const express = require('express');
|
|
4
|
+
const {
|
|
5
|
+
injectProjectId
|
|
6
|
+
} = require('../middleware/projectId');
|
|
4
7
|
|
|
5
8
|
// Import all route modules
|
|
6
9
|
const commentsRoutes = require('./comments');
|
|
7
|
-
|
|
10
|
+
const filesRoutes = require('./files');
|
|
8
11
|
const formsRoutes = require('./forms');
|
|
9
12
|
const invoiceRoutes = require('./invoice');
|
|
10
13
|
const likesRoutes = require('./likes');
|
|
@@ -14,34 +17,16 @@ const usersRoutes = require('./users');
|
|
|
14
17
|
const waitlistsRoutes = require('./waitlists');
|
|
15
18
|
const activitiesRoutes = require('./activities');
|
|
16
19
|
const authRoutes = require('./auth');
|
|
17
|
-
const blogsRoutes = require('./blogs');
|
|
18
20
|
const slidesRoutes = require('./slides');
|
|
19
21
|
const notificationsRoutes = require('./notifications');
|
|
20
|
-
const
|
|
22
|
+
const profilesRoutes = require('./profiles');
|
|
23
|
+
const createPowrRoutes = (options = {}) => {
|
|
21
24
|
const router = express.Router();
|
|
22
25
|
|
|
23
|
-
//
|
|
24
|
-
router.use((
|
|
25
|
-
try {
|
|
26
|
-
const {
|
|
27
|
-
getConfig
|
|
28
|
-
} = require('../config');
|
|
29
|
-
const config = getConfig();
|
|
30
|
-
req.projectId = config.projectId;
|
|
31
|
-
} catch (error) {
|
|
32
|
-
console.error('❌ Config error:', error.message);
|
|
33
|
-
return res.status(500).json({
|
|
34
|
-
success: false,
|
|
35
|
-
message: 'Configuration error',
|
|
36
|
-
error: error.message
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
next();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
// Mount all route modules
|
|
26
|
+
// Use the dedicated projectId injection middleware
|
|
27
|
+
router.use(injectProjectId(options));
|
|
43
28
|
router.use('/comments', commentsRoutes);
|
|
44
|
-
|
|
29
|
+
router.use('/files', filesRoutes);
|
|
45
30
|
router.use('/forms', formsRoutes);
|
|
46
31
|
router.use('/invoice', invoiceRoutes);
|
|
47
32
|
router.use('/likes', likesRoutes);
|
|
@@ -51,9 +36,9 @@ const createPowrRoutes = () => {
|
|
|
51
36
|
router.use('/waitlists', waitlistsRoutes);
|
|
52
37
|
router.use('/activities', activitiesRoutes);
|
|
53
38
|
router.use('/auth', authRoutes);
|
|
54
|
-
router.use('/blogs', blogsRoutes);
|
|
55
39
|
router.use('/slides', slidesRoutes);
|
|
56
40
|
router.use('/notifications', notificationsRoutes);
|
|
41
|
+
router.use('/profiles', profilesRoutes);
|
|
57
42
|
return router;
|
|
58
43
|
};
|
|
59
44
|
module.exports = {
|
package/dist/routes/plexx.js
CHANGED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const express = require("express");
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
const {
|
|
6
|
+
getDb
|
|
7
|
+
} = require("../services/mongo");
|
|
8
|
+
|
|
9
|
+
// Get all users for a project
|
|
10
|
+
router.get("/", async (req, res) => {
|
|
11
|
+
try {
|
|
12
|
+
const {
|
|
13
|
+
projectId
|
|
14
|
+
} = req.query;
|
|
15
|
+
const profiles = await getDb().collection("profiles").find({
|
|
16
|
+
projectId: projectId
|
|
17
|
+
}).toArray();
|
|
18
|
+
if (profiles.length === 0) {
|
|
19
|
+
return res.status(200).json({
|
|
20
|
+
success: true,
|
|
21
|
+
users: []
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Get core user data for all profiles
|
|
26
|
+
const userIds = profiles.map(profile => profile.userId);
|
|
27
|
+
const users = await getDb().collection("users").find({
|
|
28
|
+
_id: {
|
|
29
|
+
$in: userIds
|
|
30
|
+
}
|
|
31
|
+
}).toArray();
|
|
32
|
+
|
|
33
|
+
// Create a map for quick lookup
|
|
34
|
+
const usersMap = users.reduce((acc, user) => {
|
|
35
|
+
const {
|
|
36
|
+
password,
|
|
37
|
+
...userWithoutPassword
|
|
38
|
+
} = user;
|
|
39
|
+
acc[user._id.toString()] = userWithoutPassword;
|
|
40
|
+
return acc;
|
|
41
|
+
}, {});
|
|
42
|
+
|
|
43
|
+
// Merge user and profile data
|
|
44
|
+
const usersWithProfiles = profiles.map(profile => ({
|
|
45
|
+
...usersMap[profile.userId.toString()],
|
|
46
|
+
...profile
|
|
47
|
+
}));
|
|
48
|
+
return res.status(200).json({
|
|
49
|
+
success: true,
|
|
50
|
+
users: usersWithProfiles
|
|
51
|
+
});
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error("Error fetching project users:", error);
|
|
54
|
+
return res.status(500).json({
|
|
55
|
+
success: false,
|
|
56
|
+
message: "Failed to fetch project users"
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
module.exports = router;
|
package/dist/routes/routes.js
CHANGED
package/dist/routes/users.js
CHANGED
|
@@ -8,167 +8,223 @@ const {
|
|
|
8
8
|
const {
|
|
9
9
|
ObjectId
|
|
10
10
|
} = require("mongodb");
|
|
11
|
-
|
|
11
|
+
const {
|
|
12
|
+
verifyToken
|
|
13
|
+
} = require("../middleware/jwtToken");
|
|
14
|
+
|
|
15
|
+
// Create User
|
|
16
|
+
router.post("/", verifyToken, async (req, res) => {
|
|
12
17
|
const {
|
|
13
|
-
projectId,
|
|
14
18
|
phoneNumber,
|
|
15
19
|
email,
|
|
16
20
|
...userData
|
|
17
21
|
} = req.body;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
success: false,
|
|
21
|
-
message: "phoneNumber or email is required."
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
const user = {
|
|
25
|
-
projectId,
|
|
26
|
-
phoneNumber,
|
|
27
|
-
email,
|
|
28
|
-
...userData,
|
|
29
|
-
createdAt: new Date()
|
|
30
|
-
};
|
|
22
|
+
const projectId = req.projectId; // Use middleware-injected projectId
|
|
23
|
+
|
|
31
24
|
try {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
projectId,
|
|
25
|
+
// Check if user already exists
|
|
26
|
+
const existingUser = await getDb().collection("users").findOne({
|
|
27
|
+
$or: [{
|
|
36
28
|
phoneNumber
|
|
37
|
-
}
|
|
38
|
-
if (existingByPhone) {
|
|
39
|
-
return res.status(409).json({
|
|
40
|
-
success: false,
|
|
41
|
-
message: "Phone number already exists."
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (email) {
|
|
46
|
-
const existingByEmail = await usersCollection.findOne({
|
|
47
|
-
projectId,
|
|
29
|
+
}, {
|
|
48
30
|
email
|
|
31
|
+
}]
|
|
32
|
+
});
|
|
33
|
+
if (existingUser) {
|
|
34
|
+
return res.status(400).json({
|
|
35
|
+
success: false,
|
|
36
|
+
message: "User with this phone number or email already exists"
|
|
49
37
|
});
|
|
50
|
-
if (existingByEmail) {
|
|
51
|
-
return res.status(409).json({
|
|
52
|
-
success: false,
|
|
53
|
-
message: "Email already exists."
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
38
|
}
|
|
57
|
-
const
|
|
58
|
-
|
|
39
|
+
const newUser = {
|
|
40
|
+
...userData,
|
|
41
|
+
phoneNumber,
|
|
42
|
+
email,
|
|
43
|
+
createdAt: new Date(),
|
|
44
|
+
updatedAt: new Date()
|
|
45
|
+
};
|
|
46
|
+
const result = await getDb().collection("users").insertOne(newUser);
|
|
47
|
+
|
|
48
|
+
// Create profile for this project
|
|
49
|
+
const newProfile = {
|
|
50
|
+
userId: result.insertedId,
|
|
51
|
+
projectId: projectId,
|
|
52
|
+
access: userData.access || 1,
|
|
53
|
+
createdAt: new Date(),
|
|
54
|
+
updatedAt: new Date()
|
|
55
|
+
};
|
|
56
|
+
await getDb().collection("profiles").insertOne(newProfile);
|
|
57
|
+
return res.status(201).json({
|
|
59
58
|
success: true,
|
|
60
|
-
message: "User created successfully
|
|
59
|
+
message: "User created successfully",
|
|
61
60
|
userId: result.insertedId
|
|
62
61
|
});
|
|
63
62
|
} catch (error) {
|
|
64
63
|
console.error("Error creating user:", error);
|
|
65
64
|
return res.status(500).json({
|
|
66
65
|
success: false,
|
|
67
|
-
message: "
|
|
66
|
+
message: "Failed to create user."
|
|
68
67
|
});
|
|
69
68
|
}
|
|
70
69
|
});
|
|
71
|
-
|
|
70
|
+
|
|
71
|
+
// Get All Users
|
|
72
|
+
router.get("/", verifyToken, async (req, res) => {
|
|
72
73
|
const {
|
|
73
|
-
projectId,
|
|
74
74
|
_id,
|
|
75
75
|
phoneNumber,
|
|
76
76
|
email
|
|
77
77
|
} = req.query;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
success: false,
|
|
81
|
-
message: "no filters provided.",
|
|
82
|
-
users: []
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
const filter = {
|
|
86
|
-
projectId
|
|
87
|
-
};
|
|
88
|
-
if (_id) {
|
|
89
|
-
try {
|
|
90
|
-
filter._id = new ObjectId(_id);
|
|
91
|
-
} catch (e) {
|
|
92
|
-
return res.status(400).json({
|
|
93
|
-
success: false,
|
|
94
|
-
message: "Invalid _id format."
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (phoneNumber) {
|
|
99
|
-
filter.phoneNumber = phoneNumber;
|
|
100
|
-
}
|
|
101
|
-
if (email) {
|
|
102
|
-
filter.email = email;
|
|
103
|
-
}
|
|
78
|
+
const projectId = req.projectId; // Use middleware-injected projectId
|
|
79
|
+
|
|
104
80
|
try {
|
|
105
|
-
|
|
106
|
-
|
|
81
|
+
let query = {};
|
|
82
|
+
|
|
83
|
+
// Add filters if provided
|
|
84
|
+
if (_id) {
|
|
85
|
+
query._id = new ObjectId(_id);
|
|
86
|
+
}
|
|
87
|
+
if (phoneNumber) {
|
|
88
|
+
query.phoneNumber = phoneNumber;
|
|
89
|
+
}
|
|
90
|
+
if (email) {
|
|
91
|
+
query.email = email;
|
|
92
|
+
}
|
|
93
|
+
const users = await getDb().collection("users").find(query).toArray();
|
|
94
|
+
|
|
95
|
+
// Get profiles for this project
|
|
96
|
+
const userIds = users.map(user => user._id);
|
|
97
|
+
const profiles = await getDb().collection("profiles").find({
|
|
98
|
+
userId: {
|
|
99
|
+
$in: userIds
|
|
100
|
+
},
|
|
101
|
+
projectId: projectId
|
|
102
|
+
}).toArray();
|
|
103
|
+
|
|
104
|
+
// Merge user data with profile data
|
|
105
|
+
const usersWithProfiles = users.map(user => {
|
|
106
|
+
const profile = profiles.find(p => p.userId.toString() === user._id.toString());
|
|
107
|
+
return {
|
|
108
|
+
...user,
|
|
109
|
+
access: profile ? profile.access : 1,
|
|
110
|
+
projectId: projectId
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
return res.json({
|
|
107
114
|
success: true,
|
|
108
|
-
|
|
109
|
-
users
|
|
115
|
+
data: usersWithProfiles
|
|
110
116
|
});
|
|
111
117
|
} catch (error) {
|
|
112
118
|
console.error("Error fetching users:", error);
|
|
113
119
|
return res.status(500).json({
|
|
114
120
|
success: false,
|
|
115
|
-
message: "
|
|
121
|
+
message: "Failed to fetch users."
|
|
116
122
|
});
|
|
117
123
|
}
|
|
118
124
|
});
|
|
119
|
-
|
|
125
|
+
|
|
126
|
+
// Update User
|
|
127
|
+
router.put("/:id", verifyToken, async (req, res) => {
|
|
128
|
+
const {
|
|
129
|
+
id
|
|
130
|
+
} = req.params;
|
|
120
131
|
const {
|
|
121
|
-
projectId,
|
|
122
132
|
phoneNumber,
|
|
123
133
|
email,
|
|
124
134
|
...userData
|
|
125
135
|
} = req.body;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
success: false,
|
|
129
|
-
message: "phoneNumber or email is required."
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
const user = {
|
|
133
|
-
projectId,
|
|
134
|
-
phoneNumber,
|
|
135
|
-
email,
|
|
136
|
-
...userData,
|
|
137
|
-
createdAt: new Date()
|
|
138
|
-
};
|
|
136
|
+
const projectId = req.projectId; // Use middleware-injected projectId
|
|
137
|
+
|
|
139
138
|
try {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
139
|
+
// Check if user exists
|
|
140
|
+
const existingUser = await getDb().collection("users").findOne({
|
|
141
|
+
_id: new ObjectId(id)
|
|
142
|
+
});
|
|
143
|
+
if (!existingUser) {
|
|
144
|
+
return res.status(404).json({
|
|
145
|
+
success: false,
|
|
146
|
+
message: "User not found"
|
|
146
147
|
});
|
|
147
148
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
|
|
150
|
+
// Update user
|
|
151
|
+
const updateData = {
|
|
152
|
+
...userData,
|
|
153
|
+
phoneNumber,
|
|
154
|
+
email,
|
|
155
|
+
updatedAt: new Date()
|
|
156
|
+
};
|
|
157
|
+
await getDb().collection("users").updateOne({
|
|
158
|
+
_id: new ObjectId(id)
|
|
159
|
+
}, {
|
|
160
|
+
$set: updateData
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Update profile if access level is provided
|
|
164
|
+
if (userData.access !== undefined) {
|
|
165
|
+
await getDb().collection("profiles").updateOne({
|
|
166
|
+
userId: new ObjectId(id),
|
|
167
|
+
projectId: projectId
|
|
168
|
+
}, {
|
|
169
|
+
$set: {
|
|
170
|
+
access: userData.access,
|
|
171
|
+
updatedAt: new Date()
|
|
172
|
+
}
|
|
173
|
+
}, {
|
|
174
|
+
upsert: true
|
|
152
175
|
});
|
|
153
176
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
177
|
+
return res.json({
|
|
178
|
+
success: true,
|
|
179
|
+
message: "User updated successfully"
|
|
180
|
+
});
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error("Error updating user:", error);
|
|
183
|
+
return res.status(500).json({
|
|
184
|
+
success: false,
|
|
185
|
+
message: "Failed to update user."
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Delete User
|
|
191
|
+
router.delete("/:id", verifyToken, async (req, res) => {
|
|
192
|
+
const {
|
|
193
|
+
id
|
|
194
|
+
} = req.params;
|
|
195
|
+
const projectId = req.projectId; // Use middleware-injected projectId
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
// Check if user exists
|
|
199
|
+
const existingUser = await getDb().collection("users").findOne({
|
|
200
|
+
_id: new ObjectId(id)
|
|
201
|
+
});
|
|
202
|
+
if (!existingUser) {
|
|
203
|
+
return res.status(404).json({
|
|
204
|
+
success: false,
|
|
205
|
+
message: "User not found"
|
|
159
206
|
});
|
|
160
207
|
}
|
|
161
|
-
|
|
162
|
-
|
|
208
|
+
|
|
209
|
+
// Delete user
|
|
210
|
+
await getDb().collection("users").deleteOne({
|
|
211
|
+
_id: new ObjectId(id)
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Delete profile for this project
|
|
215
|
+
await getDb().collection("profiles").deleteOne({
|
|
216
|
+
userId: new ObjectId(id),
|
|
217
|
+
projectId: projectId
|
|
218
|
+
});
|
|
219
|
+
return res.json({
|
|
163
220
|
success: true,
|
|
164
|
-
message: "User
|
|
165
|
-
userId: result.insertedId
|
|
221
|
+
message: "User deleted successfully"
|
|
166
222
|
});
|
|
167
223
|
} catch (error) {
|
|
168
|
-
console.error("Error
|
|
224
|
+
console.error("Error deleting user:", error);
|
|
169
225
|
return res.status(500).json({
|
|
170
226
|
success: false,
|
|
171
|
-
message: "
|
|
227
|
+
message: "Failed to delete user."
|
|
172
228
|
});
|
|
173
229
|
}
|
|
174
230
|
});
|
package/dist/routes/waitlists.js
CHANGED
|
@@ -5,47 +5,47 @@ const router = express.Router();
|
|
|
5
5
|
const {
|
|
6
6
|
getDb
|
|
7
7
|
} = require("../services/mongo");
|
|
8
|
+
const {
|
|
9
|
+
ObjectId
|
|
10
|
+
} = require("mongodb");
|
|
11
|
+
|
|
12
|
+
// Get all waitlists
|
|
13
|
+
router.get("/", async (req, res) => {
|
|
14
|
+
const projectId = req.projectId; // Use middleware-injected projectId
|
|
8
15
|
|
|
9
|
-
// Get waitlist entries
|
|
10
|
-
router.get('/', async (req, res) => {
|
|
11
|
-
const {
|
|
12
|
-
projectId
|
|
13
|
-
} = req.query;
|
|
14
16
|
try {
|
|
15
|
-
const
|
|
17
|
+
const waitlists = await getDb().collection("waitlists").find({
|
|
16
18
|
projectId
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const waitlistData = await getDb().collection("waitlists").find(query).toArray();
|
|
20
|
-
if (!waitlistData || waitlistData.length === 0) {
|
|
21
|
-
console.log("Data not found.");
|
|
22
|
-
return res.status(200).json({
|
|
23
|
-
success: true,
|
|
24
|
-
entries: []
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
const sortedData = waitlistData.sort((a, b) => new Date(b === null || b === void 0 ? void 0 : b.createdAt) - new Date(a === null || a === void 0 ? void 0 : a.createdAt));
|
|
28
|
-
console.log("Waitlist entries retrieved and sorted:", sortedData);
|
|
29
|
-
return res.status(200).json({
|
|
19
|
+
}).toArray();
|
|
20
|
+
return res.json({
|
|
30
21
|
success: true,
|
|
31
|
-
|
|
22
|
+
data: waitlists
|
|
32
23
|
});
|
|
33
24
|
} catch (error) {
|
|
34
|
-
console.error("Error
|
|
25
|
+
console.error("Error fetching waitlists:", error);
|
|
35
26
|
return res.status(500).json({
|
|
36
27
|
success: false,
|
|
37
|
-
message: "Failed to
|
|
28
|
+
message: "Failed to fetch waitlists."
|
|
38
29
|
});
|
|
39
30
|
}
|
|
40
31
|
});
|
|
41
32
|
|
|
42
|
-
//
|
|
33
|
+
// Add email to waitlist
|
|
43
34
|
router.post("/", async (req, res) => {
|
|
44
35
|
const {
|
|
45
|
-
projectId,
|
|
46
36
|
email
|
|
47
37
|
} = req.body;
|
|
38
|
+
const projectId = req.projectId; // Use middleware-injected projectId
|
|
39
|
+
|
|
48
40
|
try {
|
|
41
|
+
if (!email) {
|
|
42
|
+
return res.status(400).json({
|
|
43
|
+
success: false,
|
|
44
|
+
message: "Email is required"
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check if email already exists in waitlist
|
|
49
49
|
const existingEntry = await getDb().collection("waitlists").findOne({
|
|
50
50
|
projectId,
|
|
51
51
|
email
|
|
@@ -53,41 +53,56 @@ router.post("/", async (req, res) => {
|
|
|
53
53
|
if (existingEntry) {
|
|
54
54
|
return res.status(400).json({
|
|
55
55
|
success: false,
|
|
56
|
-
message: "
|
|
56
|
+
message: "Email already exists in waitlist"
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
|
+
const newEntry = {
|
|
60
|
+
projectId,
|
|
61
|
+
email,
|
|
62
|
+
createdAt: new Date()
|
|
63
|
+
};
|
|
64
|
+
const result = await getDb().collection("waitlists").insertOne(newEntry);
|
|
65
|
+
return res.status(201).json({
|
|
66
|
+
success: true,
|
|
67
|
+
message: "Email added to waitlist successfully",
|
|
68
|
+
id: result.insertedId
|
|
69
|
+
});
|
|
59
70
|
} catch (error) {
|
|
60
|
-
console.error("Error
|
|
71
|
+
console.error("Error adding to waitlist:", error);
|
|
61
72
|
return res.status(500).json({
|
|
62
73
|
success: false,
|
|
63
|
-
message: "Failed to
|
|
74
|
+
message: "Failed to add to waitlist."
|
|
64
75
|
});
|
|
65
76
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Remove email from waitlist
|
|
80
|
+
router.delete("/:id", async (req, res) => {
|
|
81
|
+
const {
|
|
82
|
+
id
|
|
83
|
+
} = req.params;
|
|
84
|
+
const projectId = req.projectId; // Use middleware-injected projectId
|
|
85
|
+
|
|
71
86
|
try {
|
|
72
|
-
const result = await getDb().collection("waitlists").
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
79
|
-
} else {
|
|
80
|
-
console.error("Insert operation failed. Result:", result);
|
|
81
|
-
return res.status(500).json({
|
|
87
|
+
const result = await getDb().collection("waitlists").deleteOne({
|
|
88
|
+
_id: new ObjectId(id),
|
|
89
|
+
projectId
|
|
90
|
+
});
|
|
91
|
+
if (result.deletedCount === 0) {
|
|
92
|
+
return res.status(404).json({
|
|
82
93
|
success: false,
|
|
83
|
-
message: "
|
|
94
|
+
message: "Waitlist entry not found"
|
|
84
95
|
});
|
|
85
96
|
}
|
|
97
|
+
return res.json({
|
|
98
|
+
success: true,
|
|
99
|
+
message: "Email removed from waitlist successfully"
|
|
100
|
+
});
|
|
86
101
|
} catch (error) {
|
|
87
|
-
console.error("Error
|
|
102
|
+
console.error("Error removing from waitlist:", error);
|
|
88
103
|
return res.status(500).json({
|
|
89
104
|
success: false,
|
|
90
|
-
message: "Failed to
|
|
105
|
+
message: "Failed to remove from waitlist."
|
|
91
106
|
});
|
|
92
107
|
}
|
|
93
108
|
});
|
|
@@ -3,38 +3,40 @@
|
|
|
3
3
|
const {
|
|
4
4
|
MongoClient
|
|
5
5
|
} = require('mongodb');
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// Connect only when first needed
|
|
6
|
+
const {
|
|
7
|
+
config
|
|
8
|
+
} = require('../config');
|
|
9
|
+
const mongoClient = new MongoClient(config.mongoUri, {
|
|
10
|
+
maxPoolSize: 10,
|
|
11
|
+
serverSelectionTimeoutMS: 5000,
|
|
12
|
+
socketTimeoutMS: 45000
|
|
13
|
+
});
|
|
14
|
+
let db;
|
|
15
|
+
async function connect() {
|
|
17
16
|
try {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
db = client.db();
|
|
22
|
-
console.log('✅ Connected to MongoDB via SDK (lazy connection)');
|
|
23
|
-
return db;
|
|
17
|
+
await mongoClient.connect();
|
|
18
|
+
db = mongoClient.db();
|
|
19
|
+
console.log("Connected to MongoDB via SDK");
|
|
24
20
|
} catch (error) {
|
|
25
|
-
console.error(
|
|
26
|
-
|
|
21
|
+
console.error("Failed to connect to MongoDB:", error);
|
|
22
|
+
process.exit(1);
|
|
27
23
|
}
|
|
28
|
-
}
|
|
24
|
+
}
|
|
25
|
+
function getDb() {
|
|
26
|
+
if (!db) {
|
|
27
|
+
throw new Error("Database not initialized. Call connectToMongo() first.");
|
|
28
|
+
}
|
|
29
|
+
return db;
|
|
30
|
+
}
|
|
29
31
|
const closeConnection = async () => {
|
|
30
|
-
if (
|
|
31
|
-
await
|
|
32
|
-
client = null;
|
|
32
|
+
if (mongoClient) {
|
|
33
|
+
await mongoClient.close();
|
|
33
34
|
db = null;
|
|
34
35
|
console.log('✅ MongoDB connection closed');
|
|
35
36
|
}
|
|
36
37
|
};
|
|
37
38
|
module.exports = {
|
|
39
|
+
connect,
|
|
38
40
|
getDb,
|
|
39
41
|
closeConnection
|
|
40
42
|
};
|