powr-sdk-api 1.5.2 → 2.0.2
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/README.md +109 -0
- package/dist/index.js +9 -1
- package/dist/routes/admin/index.js +520 -0
- package/dist/routes/index.js +75 -0
- package/package.json +5 -2
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Powr SDK API
|
|
2
|
+
|
|
3
|
+
A shared API core library for PowrStack projects that provides common middleware, error handling, logging, and route management.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install powr-sdk-api
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Basic Setup
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
const express = require('express');
|
|
17
|
+
const {
|
|
18
|
+
createRoutes,
|
|
19
|
+
errorHandler,
|
|
20
|
+
requestHandler,
|
|
21
|
+
logger
|
|
22
|
+
} = require('powr-sdk-api');
|
|
23
|
+
|
|
24
|
+
const app = express();
|
|
25
|
+
|
|
26
|
+
// Add middleware
|
|
27
|
+
app.use(requestHandler);
|
|
28
|
+
app.use(express.json());
|
|
29
|
+
|
|
30
|
+
// Initialize routes
|
|
31
|
+
createRoutes(app, {
|
|
32
|
+
projectId: 'your-project-id',
|
|
33
|
+
baseUrl: '/api',
|
|
34
|
+
logger: logger
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Error handling (should be last)
|
|
38
|
+
app.use(errorHandler);
|
|
39
|
+
|
|
40
|
+
app.listen(3000, () => {
|
|
41
|
+
logger.info('Server running on port 3000');
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Admin Routes Only
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
const express = require('express');
|
|
49
|
+
const { createAdminRoutes } = require('powr-sdk-api');
|
|
50
|
+
|
|
51
|
+
const app = express();
|
|
52
|
+
|
|
53
|
+
// Initialize only admin routes
|
|
54
|
+
createAdminRoutes(app, {
|
|
55
|
+
projectId: 'your-project-id',
|
|
56
|
+
apiUrl: '/admin',
|
|
57
|
+
logger: console
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
app.listen(3000);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### With Custom Middleware
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
const express = require('express');
|
|
67
|
+
const { createRoutes, validateAuth } = require('powr-sdk-api');
|
|
68
|
+
|
|
69
|
+
const app = express();
|
|
70
|
+
|
|
71
|
+
// Custom auth middleware
|
|
72
|
+
const customAuth = (req, res, next) => {
|
|
73
|
+
// Your custom authentication logic
|
|
74
|
+
next();
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
createRoutes(app, {
|
|
78
|
+
projectId: 'your-project-id',
|
|
79
|
+
authMiddleware: customAuth,
|
|
80
|
+
logger: console
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
app.listen(3000);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Available Exports
|
|
87
|
+
|
|
88
|
+
- `createRoutes(app, options)` - Initialize all routes
|
|
89
|
+
- `createAdminRoutes(app, options)` - Initialize only admin routes
|
|
90
|
+
- `errorHandler` - Express error handling middleware
|
|
91
|
+
- `requestHandler` - Request logging middleware
|
|
92
|
+
- `validateAuth` - JWT authentication middleware
|
|
93
|
+
- `generateToken` - JWT token generation utility
|
|
94
|
+
- `logger` - Winston logger instance
|
|
95
|
+
- `createSwaggerSpec` - Swagger documentation generator
|
|
96
|
+
|
|
97
|
+
## Options
|
|
98
|
+
|
|
99
|
+
### createRoutes/createAdminRoutes options:
|
|
100
|
+
|
|
101
|
+
- `projectId` (required) - Your project identifier
|
|
102
|
+
- `baseUrl` (optional) - Base URL for routes (default: '/api')
|
|
103
|
+
- `apiUrl` (optional) - Admin API URL (default: '/admin')
|
|
104
|
+
- `authMiddleware` (optional) - Custom authentication middleware
|
|
105
|
+
- `logger` (optional) - Logger instance (default: console)
|
|
106
|
+
|
|
107
|
+
## Version
|
|
108
|
+
|
|
109
|
+
Current version: 2.0.1
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,11 @@ const {
|
|
|
16
16
|
} = require("./middleware/notfound");
|
|
17
17
|
const createSwaggerSpec = require("./swagger");
|
|
18
18
|
const logger = require("./logger");
|
|
19
|
+
const {
|
|
20
|
+
createRoutes,
|
|
21
|
+
createAdminRoutes,
|
|
22
|
+
getAvailableRoutes
|
|
23
|
+
} = require("./routes");
|
|
19
24
|
module.exports = {
|
|
20
25
|
errorCatcher,
|
|
21
26
|
errorHandler,
|
|
@@ -24,5 +29,8 @@ module.exports = {
|
|
|
24
29
|
createSwaggerSpec,
|
|
25
30
|
generateToken,
|
|
26
31
|
validateAuth,
|
|
27
|
-
notFoundHandler
|
|
32
|
+
notFoundHandler,
|
|
33
|
+
createRoutes,
|
|
34
|
+
createAdminRoutes,
|
|
35
|
+
getAvailableRoutes
|
|
28
36
|
};
|
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Admin routes for powr-sdk-api
|
|
4
|
+
// This file contains the admin route handlers for common admin operations
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
MongoClient
|
|
8
|
+
} = require('mongodb');
|
|
9
|
+
const createAdminRoutes = (app, options = {}) => {
|
|
10
|
+
const {
|
|
11
|
+
projectId,
|
|
12
|
+
apiUrl = '/admin',
|
|
13
|
+
authMiddleware = null,
|
|
14
|
+
logger = console,
|
|
15
|
+
mongoUrl = process.env.MONGODB_URI || 'mongodb://localhost:27017/powrbase'
|
|
16
|
+
} = options;
|
|
17
|
+
let db;
|
|
18
|
+
|
|
19
|
+
// Connect to MongoDB
|
|
20
|
+
const connectDB = async () => {
|
|
21
|
+
try {
|
|
22
|
+
const client = new MongoClient(mongoUrl);
|
|
23
|
+
await client.connect();
|
|
24
|
+
db = client.db();
|
|
25
|
+
logger.info('Connected to MongoDB');
|
|
26
|
+
} catch (error) {
|
|
27
|
+
logger.error('MongoDB connection error:', error);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Initialize database connection
|
|
32
|
+
connectDB();
|
|
33
|
+
|
|
34
|
+
// Forms Admin Routes
|
|
35
|
+
app.get(`${apiUrl}/forms`, async (req, res) => {
|
|
36
|
+
try {
|
|
37
|
+
const forms = await db.collection('forms').find({
|
|
38
|
+
projectId
|
|
39
|
+
}).toArray();
|
|
40
|
+
res.json({
|
|
41
|
+
success: true,
|
|
42
|
+
forms
|
|
43
|
+
});
|
|
44
|
+
} catch (error) {
|
|
45
|
+
logger.error('Error fetching forms:', error);
|
|
46
|
+
res.status(500).json({
|
|
47
|
+
success: false,
|
|
48
|
+
error: 'Failed to fetch forms'
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
app.post(`${apiUrl}/forms`, async (req, res) => {
|
|
53
|
+
try {
|
|
54
|
+
const {
|
|
55
|
+
name,
|
|
56
|
+
fields,
|
|
57
|
+
settings
|
|
58
|
+
} = req.body;
|
|
59
|
+
const form = {
|
|
60
|
+
projectId,
|
|
61
|
+
name,
|
|
62
|
+
fields,
|
|
63
|
+
settings,
|
|
64
|
+
createdAt: new Date(),
|
|
65
|
+
updatedAt: new Date()
|
|
66
|
+
};
|
|
67
|
+
const result = await db.collection('forms').insertOne(form);
|
|
68
|
+
res.json({
|
|
69
|
+
success: true,
|
|
70
|
+
form: {
|
|
71
|
+
...form,
|
|
72
|
+
_id: result.insertedId
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
} catch (error) {
|
|
76
|
+
logger.error('Error creating form:', error);
|
|
77
|
+
res.status(500).json({
|
|
78
|
+
success: false,
|
|
79
|
+
error: 'Failed to create form'
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
app.put(`${apiUrl}/forms/:id`, async (req, res) => {
|
|
84
|
+
try {
|
|
85
|
+
const {
|
|
86
|
+
id
|
|
87
|
+
} = req.params;
|
|
88
|
+
const {
|
|
89
|
+
name,
|
|
90
|
+
fields,
|
|
91
|
+
settings
|
|
92
|
+
} = req.body;
|
|
93
|
+
const result = await db.collection('forms').updateOne({
|
|
94
|
+
_id: id,
|
|
95
|
+
projectId
|
|
96
|
+
}, {
|
|
97
|
+
$set: {
|
|
98
|
+
name,
|
|
99
|
+
fields,
|
|
100
|
+
settings,
|
|
101
|
+
updatedAt: new Date()
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
if (result.matchedCount === 0) {
|
|
105
|
+
return res.status(404).json({
|
|
106
|
+
success: false,
|
|
107
|
+
error: 'Form not found'
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
res.json({
|
|
111
|
+
success: true,
|
|
112
|
+
message: 'Form updated successfully'
|
|
113
|
+
});
|
|
114
|
+
} catch (error) {
|
|
115
|
+
logger.error('Error updating form:', error);
|
|
116
|
+
res.status(500).json({
|
|
117
|
+
success: false,
|
|
118
|
+
error: 'Failed to update form'
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
app.delete(`${apiUrl}/forms/:id`, async (req, res) => {
|
|
123
|
+
try {
|
|
124
|
+
const {
|
|
125
|
+
id
|
|
126
|
+
} = req.params;
|
|
127
|
+
const result = await db.collection('forms').deleteOne({
|
|
128
|
+
_id: id,
|
|
129
|
+
projectId
|
|
130
|
+
});
|
|
131
|
+
if (result.deletedCount === 0) {
|
|
132
|
+
return res.status(404).json({
|
|
133
|
+
success: false,
|
|
134
|
+
error: 'Form not found'
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
res.json({
|
|
138
|
+
success: true,
|
|
139
|
+
message: 'Form deleted successfully'
|
|
140
|
+
});
|
|
141
|
+
} catch (error) {
|
|
142
|
+
logger.error('Error deleting form:', error);
|
|
143
|
+
res.status(500).json({
|
|
144
|
+
success: false,
|
|
145
|
+
error: 'Failed to delete form'
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Waitlists Admin Routes
|
|
151
|
+
app.get(`${apiUrl}/waitlists`, async (req, res) => {
|
|
152
|
+
try {
|
|
153
|
+
const waitlists = await db.collection('waitlists').find({
|
|
154
|
+
projectId
|
|
155
|
+
}).toArray();
|
|
156
|
+
res.json({
|
|
157
|
+
success: true,
|
|
158
|
+
waitlists
|
|
159
|
+
});
|
|
160
|
+
} catch (error) {
|
|
161
|
+
logger.error('Error fetching waitlists:', error);
|
|
162
|
+
res.status(500).json({
|
|
163
|
+
success: false,
|
|
164
|
+
error: 'Failed to fetch waitlists'
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
app.post(`${apiUrl}/waitlists`, async (req, res) => {
|
|
169
|
+
try {
|
|
170
|
+
const {
|
|
171
|
+
email,
|
|
172
|
+
name,
|
|
173
|
+
phone,
|
|
174
|
+
additionalInfo
|
|
175
|
+
} = req.body;
|
|
176
|
+
const entry = {
|
|
177
|
+
projectId,
|
|
178
|
+
email,
|
|
179
|
+
name,
|
|
180
|
+
phone,
|
|
181
|
+
additionalInfo,
|
|
182
|
+
createdAt: new Date()
|
|
183
|
+
};
|
|
184
|
+
const result = await db.collection('waitlists').insertOne(entry);
|
|
185
|
+
res.json({
|
|
186
|
+
success: true,
|
|
187
|
+
entry: {
|
|
188
|
+
...entry,
|
|
189
|
+
_id: result.insertedId
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
} catch (error) {
|
|
193
|
+
logger.error('Error adding waitlist entry:', error);
|
|
194
|
+
res.status(500).json({
|
|
195
|
+
success: false,
|
|
196
|
+
error: 'Failed to add entry'
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Slides Admin Routes
|
|
202
|
+
app.get(`${apiUrl}/slides`, async (req, res) => {
|
|
203
|
+
try {
|
|
204
|
+
const slides = await db.collection('slides').find({
|
|
205
|
+
projectId
|
|
206
|
+
}).toArray();
|
|
207
|
+
res.json({
|
|
208
|
+
success: true,
|
|
209
|
+
slides
|
|
210
|
+
});
|
|
211
|
+
} catch (error) {
|
|
212
|
+
logger.error('Error fetching slides:', error);
|
|
213
|
+
res.status(500).json({
|
|
214
|
+
success: false,
|
|
215
|
+
error: 'Failed to fetch slides'
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
app.post(`${apiUrl}/slides`, async (req, res) => {
|
|
220
|
+
try {
|
|
221
|
+
const {
|
|
222
|
+
title,
|
|
223
|
+
description,
|
|
224
|
+
imageUrl,
|
|
225
|
+
link,
|
|
226
|
+
order
|
|
227
|
+
} = req.body;
|
|
228
|
+
const slide = {
|
|
229
|
+
projectId,
|
|
230
|
+
title,
|
|
231
|
+
description,
|
|
232
|
+
imageUrl,
|
|
233
|
+
link,
|
|
234
|
+
order: order || 0,
|
|
235
|
+
createdAt: new Date(),
|
|
236
|
+
updatedAt: new Date()
|
|
237
|
+
};
|
|
238
|
+
const result = await db.collection('slides').insertOne(slide);
|
|
239
|
+
res.json({
|
|
240
|
+
success: true,
|
|
241
|
+
slide: {
|
|
242
|
+
...slide,
|
|
243
|
+
_id: result.insertedId
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
} catch (error) {
|
|
247
|
+
logger.error('Error creating slide:', error);
|
|
248
|
+
res.status(500).json({
|
|
249
|
+
success: false,
|
|
250
|
+
error: 'Failed to create slide'
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
app.put(`${apiUrl}/slides/:id`, async (req, res) => {
|
|
255
|
+
try {
|
|
256
|
+
const {
|
|
257
|
+
id
|
|
258
|
+
} = req.params;
|
|
259
|
+
const {
|
|
260
|
+
title,
|
|
261
|
+
description,
|
|
262
|
+
imageUrl,
|
|
263
|
+
link,
|
|
264
|
+
order
|
|
265
|
+
} = req.body;
|
|
266
|
+
const result = await db.collection('slides').updateOne({
|
|
267
|
+
_id: id,
|
|
268
|
+
projectId
|
|
269
|
+
}, {
|
|
270
|
+
$set: {
|
|
271
|
+
title,
|
|
272
|
+
description,
|
|
273
|
+
imageUrl,
|
|
274
|
+
link,
|
|
275
|
+
order,
|
|
276
|
+
updatedAt: new Date()
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
if (result.matchedCount === 0) {
|
|
280
|
+
return res.status(404).json({
|
|
281
|
+
success: false,
|
|
282
|
+
error: 'Slide not found'
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
res.json({
|
|
286
|
+
success: true,
|
|
287
|
+
message: 'Slide updated successfully'
|
|
288
|
+
});
|
|
289
|
+
} catch (error) {
|
|
290
|
+
logger.error('Error updating slide:', error);
|
|
291
|
+
res.status(500).json({
|
|
292
|
+
success: false,
|
|
293
|
+
error: 'Failed to update slide'
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
app.delete(`${apiUrl}/slides/:id`, async (req, res) => {
|
|
298
|
+
try {
|
|
299
|
+
const {
|
|
300
|
+
id
|
|
301
|
+
} = req.params;
|
|
302
|
+
const result = await db.collection('slides').deleteOne({
|
|
303
|
+
_id: id,
|
|
304
|
+
projectId
|
|
305
|
+
});
|
|
306
|
+
if (result.deletedCount === 0) {
|
|
307
|
+
return res.status(404).json({
|
|
308
|
+
success: false,
|
|
309
|
+
error: 'Slide not found'
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
res.json({
|
|
313
|
+
success: true,
|
|
314
|
+
message: 'Slide deleted successfully'
|
|
315
|
+
});
|
|
316
|
+
} catch (error) {
|
|
317
|
+
logger.error('Error deleting slide:', error);
|
|
318
|
+
res.status(500).json({
|
|
319
|
+
success: false,
|
|
320
|
+
error: 'Failed to delete slide'
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Invoices Admin Routes
|
|
326
|
+
app.get(`${apiUrl}/invoices`, async (req, res) => {
|
|
327
|
+
try {
|
|
328
|
+
const invoices = await db.collection('invoices').find({
|
|
329
|
+
projectId
|
|
330
|
+
}).toArray();
|
|
331
|
+
res.json({
|
|
332
|
+
success: true,
|
|
333
|
+
invoices
|
|
334
|
+
});
|
|
335
|
+
} catch (error) {
|
|
336
|
+
logger.error('Error fetching invoices:', error);
|
|
337
|
+
res.status(500).json({
|
|
338
|
+
success: false,
|
|
339
|
+
error: 'Failed to fetch invoices'
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
app.post(`${apiUrl}/invoices`, async (req, res) => {
|
|
344
|
+
try {
|
|
345
|
+
const {
|
|
346
|
+
invoiceNumber,
|
|
347
|
+
clientName,
|
|
348
|
+
clientEmail,
|
|
349
|
+
amount,
|
|
350
|
+
description,
|
|
351
|
+
dueDate,
|
|
352
|
+
status = 'pending'
|
|
353
|
+
} = req.body;
|
|
354
|
+
const invoice = {
|
|
355
|
+
projectId,
|
|
356
|
+
invoiceNumber,
|
|
357
|
+
clientName,
|
|
358
|
+
clientEmail,
|
|
359
|
+
amount,
|
|
360
|
+
description,
|
|
361
|
+
dueDate: new Date(dueDate),
|
|
362
|
+
status,
|
|
363
|
+
createdAt: new Date(),
|
|
364
|
+
updatedAt: new Date()
|
|
365
|
+
};
|
|
366
|
+
const result = await db.collection('invoices').insertOne(invoice);
|
|
367
|
+
res.json({
|
|
368
|
+
success: true,
|
|
369
|
+
invoice: {
|
|
370
|
+
...invoice,
|
|
371
|
+
_id: result.insertedId
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
} catch (error) {
|
|
375
|
+
logger.error('Error creating invoice:', error);
|
|
376
|
+
res.status(500).json({
|
|
377
|
+
success: false,
|
|
378
|
+
error: 'Failed to create invoice'
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
app.put(`${apiUrl}/invoices/:id`, async (req, res) => {
|
|
383
|
+
try {
|
|
384
|
+
const {
|
|
385
|
+
id
|
|
386
|
+
} = req.params;
|
|
387
|
+
const {
|
|
388
|
+
invoiceNumber,
|
|
389
|
+
clientName,
|
|
390
|
+
clientEmail,
|
|
391
|
+
amount,
|
|
392
|
+
description,
|
|
393
|
+
dueDate,
|
|
394
|
+
status
|
|
395
|
+
} = req.body;
|
|
396
|
+
const result = await db.collection('invoices').updateOne({
|
|
397
|
+
_id: id,
|
|
398
|
+
projectId
|
|
399
|
+
}, {
|
|
400
|
+
$set: {
|
|
401
|
+
invoiceNumber,
|
|
402
|
+
clientName,
|
|
403
|
+
clientEmail,
|
|
404
|
+
amount,
|
|
405
|
+
description,
|
|
406
|
+
dueDate: new Date(dueDate),
|
|
407
|
+
status,
|
|
408
|
+
updatedAt: new Date()
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
if (result.matchedCount === 0) {
|
|
412
|
+
return res.status(404).json({
|
|
413
|
+
success: false,
|
|
414
|
+
error: 'Invoice not found'
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
res.json({
|
|
418
|
+
success: true,
|
|
419
|
+
message: 'Invoice updated successfully'
|
|
420
|
+
});
|
|
421
|
+
} catch (error) {
|
|
422
|
+
logger.error('Error updating invoice:', error);
|
|
423
|
+
res.status(500).json({
|
|
424
|
+
success: false,
|
|
425
|
+
error: 'Failed to update invoice'
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// Notifications Admin Routes
|
|
431
|
+
app.get(`${apiUrl}/notifications`, async (req, res) => {
|
|
432
|
+
try {
|
|
433
|
+
const notifications = await db.collection('notifications').find({
|
|
434
|
+
projectId
|
|
435
|
+
}).toArray();
|
|
436
|
+
res.json({
|
|
437
|
+
success: true,
|
|
438
|
+
notifications
|
|
439
|
+
});
|
|
440
|
+
} catch (error) {
|
|
441
|
+
logger.error('Error fetching notifications:', error);
|
|
442
|
+
res.status(500).json({
|
|
443
|
+
success: false,
|
|
444
|
+
error: 'Failed to fetch notifications'
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
app.post(`${apiUrl}/notifications`, async (req, res) => {
|
|
449
|
+
try {
|
|
450
|
+
const {
|
|
451
|
+
title,
|
|
452
|
+
message,
|
|
453
|
+
type = 'info',
|
|
454
|
+
priority = 'normal',
|
|
455
|
+
targetUsers = 'all'
|
|
456
|
+
} = req.body;
|
|
457
|
+
const notification = {
|
|
458
|
+
projectId,
|
|
459
|
+
title,
|
|
460
|
+
message,
|
|
461
|
+
type,
|
|
462
|
+
priority,
|
|
463
|
+
targetUsers,
|
|
464
|
+
isRead: false,
|
|
465
|
+
createdAt: new Date()
|
|
466
|
+
};
|
|
467
|
+
const result = await db.collection('notifications').insertOne(notification);
|
|
468
|
+
res.json({
|
|
469
|
+
success: true,
|
|
470
|
+
notification: {
|
|
471
|
+
...notification,
|
|
472
|
+
_id: result.insertedId
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
} catch (error) {
|
|
476
|
+
logger.error('Error creating notification:', error);
|
|
477
|
+
res.status(500).json({
|
|
478
|
+
success: false,
|
|
479
|
+
error: 'Failed to create notification'
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
app.put(`${apiUrl}/notifications/:id/read`, async (req, res) => {
|
|
484
|
+
try {
|
|
485
|
+
const {
|
|
486
|
+
id
|
|
487
|
+
} = req.params;
|
|
488
|
+
const result = await db.collection('notifications').updateOne({
|
|
489
|
+
_id: id,
|
|
490
|
+
projectId
|
|
491
|
+
}, {
|
|
492
|
+
$set: {
|
|
493
|
+
isRead: true,
|
|
494
|
+
updatedAt: new Date()
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
if (result.matchedCount === 0) {
|
|
498
|
+
return res.status(404).json({
|
|
499
|
+
success: false,
|
|
500
|
+
error: 'Notification not found'
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
res.json({
|
|
504
|
+
success: true,
|
|
505
|
+
message: 'Notification marked as read'
|
|
506
|
+
});
|
|
507
|
+
} catch (error) {
|
|
508
|
+
logger.error('Error updating notification:', error);
|
|
509
|
+
res.status(500).json({
|
|
510
|
+
success: false,
|
|
511
|
+
error: 'Failed to update notification'
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
logger.info('Admin routes initialized for project:', projectId);
|
|
516
|
+
return app;
|
|
517
|
+
};
|
|
518
|
+
module.exports = {
|
|
519
|
+
createAdminRoutes
|
|
520
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Main routes index for powr-sdk-api
|
|
4
|
+
// This file exports all route handlers for easy integration
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
createAdminRoutes
|
|
8
|
+
} = require('./admin');
|
|
9
|
+
const createRoutes = (app, options = {}) => {
|
|
10
|
+
const {
|
|
11
|
+
projectId,
|
|
12
|
+
baseUrl = '/api',
|
|
13
|
+
authMiddleware = null,
|
|
14
|
+
logger = console,
|
|
15
|
+
mongoUrl = process.env.MONGODB_URI || 'mongodb://localhost:27017/powrbase'
|
|
16
|
+
} = options;
|
|
17
|
+
|
|
18
|
+
// Apply auth middleware if provided
|
|
19
|
+
if (authMiddleware) {
|
|
20
|
+
app.use(`${baseUrl}/admin`, authMiddleware);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Initialize admin routes
|
|
24
|
+
createAdminRoutes(app, {
|
|
25
|
+
projectId,
|
|
26
|
+
apiUrl: `${baseUrl}/admin`,
|
|
27
|
+
authMiddleware,
|
|
28
|
+
logger,
|
|
29
|
+
mongoUrl
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Health check endpoint
|
|
33
|
+
app.get(`${baseUrl}/health`, (req, res) => {
|
|
34
|
+
res.json({
|
|
35
|
+
success: true,
|
|
36
|
+
message: 'API is running',
|
|
37
|
+
projectId,
|
|
38
|
+
timestamp: new Date().toISOString()
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Project info endpoint
|
|
43
|
+
app.get(`${baseUrl}/info`, (req, res) => {
|
|
44
|
+
res.json({
|
|
45
|
+
success: true,
|
|
46
|
+
projectId,
|
|
47
|
+
version: '2.0.1',
|
|
48
|
+
features: ['forms', 'waitlists', 'slides', 'invoices', 'notifications']
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
logger.info('All routes initialized for project:', projectId);
|
|
52
|
+
return app;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Utility function to get available routes
|
|
56
|
+
const getAvailableRoutes = () => {
|
|
57
|
+
return {
|
|
58
|
+
admin: {
|
|
59
|
+
forms: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
60
|
+
waitlists: ['GET', 'POST'],
|
|
61
|
+
slides: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
62
|
+
invoices: ['GET', 'POST', 'PUT'],
|
|
63
|
+
notifications: ['GET', 'POST', 'PUT']
|
|
64
|
+
},
|
|
65
|
+
utility: {
|
|
66
|
+
health: ['GET'],
|
|
67
|
+
info: ['GET']
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
module.exports = {
|
|
72
|
+
createRoutes,
|
|
73
|
+
createAdminRoutes,
|
|
74
|
+
getAvailableRoutes
|
|
75
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "powr-sdk-api",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Shared API core library for PowrStack projects",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -42,7 +42,10 @@
|
|
|
42
42
|
"jsonwebtoken": "^9.0.2",
|
|
43
43
|
"swagger-jsdoc": "^6.2.8",
|
|
44
44
|
"swagger-ui-express": "^5.0.0",
|
|
45
|
-
"winston": "^3.17.0"
|
|
45
|
+
"winston": "^3.17.0",
|
|
46
|
+
"mongodb": "^6.3.0",
|
|
47
|
+
"multer": "^1.4.5-lts.1",
|
|
48
|
+
"bcrypt": "^5.1.1"
|
|
46
49
|
},
|
|
47
50
|
"devDependencies": {
|
|
48
51
|
"@babel/cli": "^7.23.9",
|