underpost 2.8.86 → 2.8.88

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.
Files changed (116) hide show
  1. package/.env.development +39 -2
  2. package/.env.production +42 -2
  3. package/.env.test +39 -2
  4. package/.github/workflows/ghpkg.ci.yml +1 -1
  5. package/.github/workflows/npmpkg.ci.yml +1 -1
  6. package/.github/workflows/pwa-microservices-template-page.cd.yml +6 -5
  7. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  8. package/.github/workflows/release.cd.yml +3 -3
  9. package/README.md +76 -2
  10. package/bin/build.js +5 -0
  11. package/bin/deploy.js +93 -27
  12. package/bin/file.js +8 -4
  13. package/bin/util.js +1 -56
  14. package/cli.md +16 -5
  15. package/conf.js +33 -7
  16. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  17. package/manifests/deployment/dd-test-development/deployment.yaml +174 -0
  18. package/manifests/deployment/dd-test-development/proxy.yaml +51 -0
  19. package/manifests/deployment/mongo-express/deployment.yaml +12 -12
  20. package/manifests/maas/nvim.sh +91 -0
  21. package/package.json +8 -15
  22. package/src/api/core/core.router.js +2 -1
  23. package/src/api/default/default.controller.js +6 -1
  24. package/src/api/default/default.router.js +6 -2
  25. package/src/api/default/default.service.js +10 -1
  26. package/src/api/document/document.controller.js +66 -0
  27. package/src/api/document/document.model.js +51 -0
  28. package/src/api/document/document.router.js +24 -0
  29. package/src/api/document/document.service.js +125 -0
  30. package/src/api/file/file.controller.js +15 -1
  31. package/src/api/file/file.router.js +2 -1
  32. package/src/api/file/file.service.js +28 -8
  33. package/src/api/test/test.router.js +1 -1
  34. package/src/api/user/postman_collection.json +216 -0
  35. package/src/api/user/user.controller.js +25 -60
  36. package/src/api/user/user.model.js +29 -7
  37. package/src/api/user/user.router.js +40 -8
  38. package/src/api/user/user.service.js +86 -35
  39. package/src/cli/baremetal.js +33 -3
  40. package/src/cli/cloud-init.js +11 -0
  41. package/src/cli/cluster.js +4 -23
  42. package/src/cli/cron.js +0 -1
  43. package/src/cli/db.js +0 -19
  44. package/src/cli/deploy.js +67 -52
  45. package/src/cli/fs.js +1 -0
  46. package/src/cli/index.js +9 -1
  47. package/src/cli/lxd.js +7 -0
  48. package/src/cli/repository.js +44 -6
  49. package/src/cli/run.js +56 -9
  50. package/src/cli/ssh.js +20 -6
  51. package/src/client/Default.index.js +42 -1
  52. package/src/client/components/core/Account.js +10 -2
  53. package/src/client/components/core/AgGrid.js +30 -8
  54. package/src/client/components/core/Auth.js +99 -56
  55. package/src/client/components/core/BtnIcon.js +3 -2
  56. package/src/client/components/core/CalendarCore.js +2 -3
  57. package/src/client/components/core/CommonJs.js +1 -2
  58. package/src/client/components/core/Content.js +15 -12
  59. package/src/client/components/core/Css.js +2 -1
  60. package/src/client/components/core/CssCore.js +18 -1
  61. package/src/client/components/core/Docs.js +5 -5
  62. package/src/client/components/core/FileExplorer.js +3 -3
  63. package/src/client/components/core/FullScreen.js +19 -28
  64. package/src/client/components/core/Input.js +22 -16
  65. package/src/client/components/core/JoyStick.js +2 -2
  66. package/src/client/components/core/LoadingAnimation.js +2 -2
  67. package/src/client/components/core/LogIn.js +16 -23
  68. package/src/client/components/core/LogOut.js +5 -1
  69. package/src/client/components/core/Logger.js +4 -1
  70. package/src/client/components/core/Modal.js +102 -87
  71. package/src/client/components/core/ObjectLayerEngine.js +229 -4
  72. package/src/client/components/core/ObjectLayerEngineModal.js +442 -0
  73. package/src/client/components/core/Pagination.js +207 -0
  74. package/src/client/components/core/Panel.js +10 -10
  75. package/src/client/components/core/PanelForm.js +130 -33
  76. package/src/client/components/core/Recover.js +2 -2
  77. package/src/client/components/core/Router.js +210 -34
  78. package/src/client/components/core/SignUp.js +1 -2
  79. package/src/client/components/core/Stream.js +1 -1
  80. package/src/client/components/core/ToggleSwitch.js +15 -1
  81. package/src/client/components/core/VanillaJs.js +3 -84
  82. package/src/client/components/core/Worker.js +2 -2
  83. package/src/client/components/default/LogInDefault.js +0 -6
  84. package/src/client/components/default/LogOutDefault.js +0 -16
  85. package/src/client/components/default/MenuDefault.js +97 -44
  86. package/src/client/components/default/RoutesDefault.js +5 -2
  87. package/src/client/public/default/assets/mailer/api-user-default-avatar.png +0 -0
  88. package/src/client/services/core/core.service.js +8 -20
  89. package/src/client/services/default/default.management.js +115 -18
  90. package/src/client/services/default/default.service.js +13 -4
  91. package/src/client/services/document/document.service.js +97 -0
  92. package/src/client/services/file/file.service.js +2 -0
  93. package/src/client/services/test/test.service.js +3 -0
  94. package/src/client/services/user/user.management.js +6 -0
  95. package/src/client/services/user/user.service.js +15 -4
  96. package/src/client/ssr/Render.js +1 -1
  97. package/src/client/ssr/head/DefaultScripts.js +3 -0
  98. package/src/client/ssr/head/Seo.js +1 -0
  99. package/src/index.js +24 -2
  100. package/src/runtime/lampp/Lampp.js +89 -2
  101. package/src/runtime/xampp/Xampp.js +48 -1
  102. package/src/server/auth.js +519 -155
  103. package/src/server/backup.js +2 -2
  104. package/src/server/client-build-docs.js +1 -1
  105. package/src/server/client-build.js +4 -12
  106. package/src/server/client-icons.js +6 -78
  107. package/src/server/conf.js +144 -141
  108. package/src/server/process.js +2 -1
  109. package/src/server/proxy.js +1 -1
  110. package/src/server/runtime.js +136 -288
  111. package/src/server/ssl.js +1 -2
  112. package/src/server/ssr.js +85 -0
  113. package/src/server/start.js +4 -4
  114. package/src/server/valkey.js +2 -1
  115. package/test/api.test.js +3 -2
  116. package/bin/cyberia0.js +0 -78
@@ -0,0 +1,66 @@
1
+ import { loggerFactory } from '../../server/logger.js';
2
+ import { DocumentService } from './document.service.js';
3
+ const logger = loggerFactory(import.meta);
4
+
5
+ const DocumentController = {
6
+ post: async (req, res, options) => {
7
+ try {
8
+ return res.status(200).json({
9
+ status: 'success',
10
+ data: await DocumentService.post(req, res, options),
11
+ });
12
+ } catch (error) {
13
+ logger.error(error, error.stack);
14
+ return res.status(400).json({
15
+ status: 'error',
16
+ message: error.message,
17
+ });
18
+ }
19
+ },
20
+ get: async (req, res, options) => {
21
+ try {
22
+ return res.status(200).json({
23
+ status: 'success',
24
+ data: await DocumentService.get(req, res, options),
25
+ });
26
+ } catch (error) {
27
+ logger.error(error, error.stack);
28
+ return res.status(400).json({
29
+ status: 'error',
30
+ message: error.message,
31
+ });
32
+ }
33
+ },
34
+ delete: async (req, res, options) => {
35
+ try {
36
+ const result = await DocumentService.delete(req, res, options);
37
+ return res.status(200).json({
38
+ status: 'success',
39
+ data: result,
40
+ });
41
+ } catch (error) {
42
+ logger.error(error, error.stack);
43
+ return res.status(400).json({
44
+ status: 'error',
45
+ message: error.message,
46
+ });
47
+ }
48
+ },
49
+ put: async (req, res, options) => {
50
+ try {
51
+ const result = await DocumentService.put(req, res, options);
52
+ return res.status(200).json({
53
+ status: 'success',
54
+ data: result,
55
+ });
56
+ } catch (error) {
57
+ logger.error(error, error.stack);
58
+ return res.status(400).json({
59
+ status: 'error',
60
+ message: error.message,
61
+ });
62
+ }
63
+ },
64
+ };
65
+
66
+ export { DocumentController };
@@ -0,0 +1,51 @@
1
+ import { Schema, model, Types } from 'mongoose';
2
+
3
+ // https://mongoosejs.com/docs/2.7.x/docs/schematypes.html
4
+
5
+ const DocumentSchema = new Schema(
6
+ {
7
+ userId: {
8
+ type: Schema.Types.ObjectId,
9
+ ref: 'User',
10
+ },
11
+ location: { type: String },
12
+ title: { type: String },
13
+ tags: [{ type: String }],
14
+ fileId: {
15
+ type: Schema.Types.ObjectId,
16
+ ref: 'File',
17
+ },
18
+ mdFileId: {
19
+ type: Schema.Types.ObjectId,
20
+ ref: 'File',
21
+ },
22
+ },
23
+ {
24
+ timestamps: true,
25
+ },
26
+ );
27
+
28
+ const DocumentModel = model('Document', DocumentSchema);
29
+
30
+ const ProviderSchema = DocumentSchema;
31
+
32
+ const DocumentDto = {
33
+ populate: {
34
+ file: () => {
35
+ return {
36
+ path: 'fileId',
37
+ model: 'File',
38
+ select: '_id name mimetype',
39
+ };
40
+ },
41
+ user: () => {
42
+ return {
43
+ path: 'userId',
44
+ model: 'User',
45
+ select: '_id email username',
46
+ };
47
+ },
48
+ },
49
+ };
50
+
51
+ export { DocumentSchema, DocumentModel, ProviderSchema, DocumentDto };
@@ -0,0 +1,24 @@
1
+ import { loggerFactory } from '../../server/logger.js';
2
+ import { DocumentController } from './document.controller.js';
3
+ import express from 'express';
4
+ import fs from 'fs-extra';
5
+ const logger = loggerFactory(import.meta);
6
+
7
+ const DocumentRouter = (options) => {
8
+ const router = express.Router();
9
+ const authMiddleware = options.authMiddleware;
10
+ router.post(`/:id`, authMiddleware, async (req, res) => await DocumentController.post(req, res, options));
11
+ router.post(`/`, authMiddleware, async (req, res) => await DocumentController.post(req, res, options));
12
+ router.get(`/public`, async (req, res) => await DocumentController.get(req, res, options));
13
+ router.get(`/:id`, authMiddleware, async (req, res) => await DocumentController.get(req, res, options));
14
+ router.get(`/`, authMiddleware, async (req, res) => await DocumentController.get(req, res, options));
15
+ router.put(`/:id`, authMiddleware, async (req, res) => await DocumentController.put(req, res, options));
16
+ router.put(`/`, authMiddleware, async (req, res) => await DocumentController.put(req, res, options));
17
+ router.delete(`/:id`, authMiddleware, async (req, res) => await DocumentController.delete(req, res, options));
18
+ router.delete(`/`, authMiddleware, async (req, res) => await DocumentController.delete(req, res, options));
19
+ return router;
20
+ };
21
+
22
+ const ApiRouter = DocumentRouter;
23
+
24
+ export { ApiRouter, DocumentRouter };
@@ -0,0 +1,125 @@
1
+ import { loggerFactory } from '../../server/logger.js';
2
+ import { DataBaseProvider } from '../../db/DataBaseProvider.js';
3
+ import { DocumentDto } from './document.model.js';
4
+ import { uniqueArray } from '../../client/components/core/CommonJs.js';
5
+ import { getBearerToken, verifyJWT } from '../../server/auth.js';
6
+ import { isValidObjectId } from 'mongoose';
7
+
8
+ const logger = loggerFactory(import.meta);
9
+
10
+ const DocumentService = {
11
+ post: async (req, res, options) => {
12
+ /** @type {import('./document.model.js').DocumentModel} */
13
+ const Document = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Document;
14
+
15
+ switch (req.params.id) {
16
+ default:
17
+ req.body.userId = req.auth.user._id;
18
+ return await new Document(req.body).save();
19
+ }
20
+ },
21
+ get: async (req, res, options) => {
22
+ /** @type {import('./document.model.js').DocumentModel} */
23
+ const Document = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Document;
24
+ /** @type {import('../user/user.model.js').UserModel} */
25
+ const User = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.User;
26
+
27
+ if (req.path.startsWith('/public') && req.query['tags']) {
28
+ const publisherUsers = await User.find({ $or: [{ role: 'admin' }, { role: 'moderator' }] });
29
+
30
+ const token = getBearerToken(req);
31
+ let user;
32
+ if (token) user = verifyJWT(token, options);
33
+
34
+ const queryPayload = {
35
+ userId: {
36
+ $in: publisherUsers.map((p) => p._id).concat(user?.role && user.role !== 'guest' ? [user._id] : []),
37
+ },
38
+ tags: {
39
+ // $in: uniqueArray(['public'].concat(req.query['tags'].split(','))),
40
+ $all: uniqueArray(['public'].concat(req.query['tags'].split(','))),
41
+ },
42
+ ...(req.query.cid
43
+ ? {
44
+ _id: {
45
+ $in: req.query.cid.split(',').filter((cid) => isValidObjectId(cid)),
46
+ },
47
+ }
48
+ : undefined),
49
+ };
50
+ logger.info('queryPayload', queryPayload);
51
+ // sort in descending (-1) order by length
52
+ const sort = { createdAt: -1 };
53
+ const limit = req.query.limit ? parseInt(req.query.limit, 10) : 6;
54
+ const skip = req.query.skip ? parseInt(req.query.skip, 10) : 0;
55
+
56
+ return await Document.find(queryPayload)
57
+ .sort(sort)
58
+ .limit(limit)
59
+ .skip(skip)
60
+ .populate(DocumentDto.populate.file())
61
+ .populate(user && user.role !== 'guest' ? DocumentDto.populate.user() : null);
62
+ }
63
+
64
+ switch (req.params.id) {
65
+ default:
66
+ return await Document.find({
67
+ userId: req.auth.user._id,
68
+ ...(req.params.id ? { _id: req.params.id } : undefined),
69
+ }).populate(DocumentDto.populate.file());
70
+ }
71
+ },
72
+ delete: async (req, res, options) => {
73
+ /** @type {import('./document.model.js').DocumentModel} */
74
+ const Document = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Document;
75
+ /** @type {import('../file/file.model.js').FileModel} */
76
+ const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.File;
77
+
78
+ switch (req.params.id) {
79
+ default: {
80
+ const document = await Document.findOne({ _id: req.params.id });
81
+ if (!document) throw new Error('document not found');
82
+
83
+ if (document.userId.toString() !== req.auth.user._id) throw new Error('invalid user');
84
+
85
+ if (document.mdFileId) {
86
+ const file = await File.findOne({ _id: document.mdFileId });
87
+ if (file) await File.findByIdAndDelete(document.mdFileId);
88
+ }
89
+
90
+ if (document.fileId) {
91
+ const file = await File.findOne({ _id: document.fileId });
92
+ if (file) await File.findByIdAndDelete(document.fileId);
93
+ }
94
+
95
+ return await Document.findByIdAndDelete(req.params.id);
96
+ }
97
+ }
98
+ },
99
+ put: async (req, res, options) => {
100
+ /** @type {import('./document.model.js').DocumentModel} */
101
+ const Document = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Document;
102
+ /** @type {import('../file/file.model.js').FileModel} */
103
+ const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.File;
104
+
105
+ switch (req.params.id) {
106
+ default: {
107
+ const document = await Document.findOne({ _id: req.params.id });
108
+ if (!document) throw new Error(`Document not found`);
109
+
110
+ if (document.mdFileId) {
111
+ const file = await File.findOne({ _id: document.mdFileId });
112
+ if (file) await File.findByIdAndDelete(document.mdFileId);
113
+ }
114
+
115
+ if (document.fileId) {
116
+ const file = await File.findOne({ _id: document.fileId });
117
+ if (file) await File.findByIdAndDelete(document.fileId);
118
+ }
119
+ return await Document.findByIdAndUpdate(req.params.id, req.body);
120
+ }
121
+ }
122
+ },
123
+ };
124
+
125
+ export { DocumentService };
@@ -20,7 +20,21 @@ const FileController = {
20
20
  get: async (req, res, options) => {
21
21
  try {
22
22
  const result = await FileService.get(req, res, options);
23
- if (result instanceof Buffer) return res.status(200).end(result);
23
+ if (result instanceof Buffer) {
24
+ if (
25
+ process.env.NODE_ENV === 'development' ||
26
+ req.hostname === options.host ||
27
+ (options.origins && options.origins.find((o) => o.match(req.hostname)))
28
+ ) {
29
+ res.set('Cross-Origin-Resource-Policy', 'cross-origin');
30
+ return res.status(200).end(result);
31
+ }
32
+ return res.status(403).json({
33
+ status: 'error',
34
+ message: 'Forbidden',
35
+ });
36
+ }
37
+
24
38
  return res.status(200).json({
25
39
  status: 'success',
26
40
  data: result,
@@ -1,4 +1,4 @@
1
- import { adminGuard, authMiddleware } from '../../server/auth.js';
1
+ import { adminGuard } from '../../server/auth.js';
2
2
  import { loggerFactory } from '../../server/logger.js';
3
3
  import { FileController } from './file.controller.js';
4
4
  import express from 'express';
@@ -6,6 +6,7 @@ const logger = loggerFactory(import.meta);
6
6
 
7
7
  const FileRouter = (options) => {
8
8
  const router = express.Router();
9
+ const authMiddleware = options.authMiddleware;
9
10
  router.post(`/:id`, authMiddleware, async (req, res) => await FileController.post(req, res, options));
10
11
  router.post(`/`, authMiddleware, async (req, res) => await FileController.post(req, res, options));
11
12
  router.get(`/blob/:id`, async (req, res) => await FileController.get(req, res, options));
@@ -5,14 +5,18 @@ import crypto from 'crypto';
5
5
  const logger = loggerFactory(import.meta);
6
6
 
7
7
  const FileFactory = {
8
- upload: async function (req, File) {
9
- const results = [];
10
- if (!req.files) throw { message: 'not file found' };
11
- if (Array.isArray(req.files.file)) for (const file of req.files.file) results.push(await new File(file).save());
8
+ filesExtract: (req) => {
9
+ const files = [];
10
+ if (Array.isArray(req.files.file)) for (const file of req.files.file) files.push(file);
12
11
  else if (Object.keys(req.files).length > 0)
13
- for (const keyFile of Object.keys(req.files)) results.push(await new File(req.files[keyFile]).save());
12
+ for (const keyFile of Object.keys(req.files)) files.push(req.files[keyFile]);
13
+ return files;
14
+ },
15
+ upload: async function (req, File) {
16
+ const results = FileFactory.filesExtract(req);
14
17
  let index = -1;
15
- for (const file of results) {
18
+ for (let file of results) {
19
+ file = await new File(file).save();
16
20
  index++;
17
21
  const [result] = await File.find({
18
22
  _id: file._id,
@@ -25,7 +29,23 @@ const FileFactory = {
25
29
  return Buffer.from(raw, 'utf8').toString('hex');
26
30
  // reverse hexValue.toString()
27
31
  },
28
- svg: (data = new Buffer(), name = '') => {
32
+ getMymeTypeFromPath: (path) => {
33
+ switch (path.split('.').pop()) {
34
+ case 'png':
35
+ return 'image/png';
36
+ case 'jpg':
37
+ return 'image/jpeg';
38
+ case 'jpeg':
39
+ return 'image/jpeg';
40
+ case 'gif':
41
+ return 'image/gif';
42
+ case 'svg':
43
+ return 'image/svg+xml';
44
+ default:
45
+ return 'application/octet-stream';
46
+ }
47
+ },
48
+ create: (data = Buffer.from([]), name = '') => {
29
49
  return {
30
50
  name: name,
31
51
  data: data,
@@ -33,7 +53,7 @@ const FileFactory = {
33
53
  encoding: '7bit',
34
54
  tempFilePath: '',
35
55
  truncated: false,
36
- mimetype: 'image/svg+xml',
56
+ mimetype: FileFactory.getMymeTypeFromPath(name),
37
57
  md5: crypto.createHash('md5').update(data).digest('hex'),
38
58
  cid: undefined,
39
59
  };
@@ -1,4 +1,3 @@
1
- import { authMiddleware } from '../../server/auth.js';
2
1
  import { loggerFactory } from '../../server/logger.js';
3
2
  import { TestController } from './test.controller.js';
4
3
  import express from 'express';
@@ -7,6 +6,7 @@ const logger = loggerFactory(import.meta);
7
6
 
8
7
  const TestRouter = (options) => {
9
8
  const router = express.Router();
9
+ const authMiddleware = options.authMiddleware;
10
10
  router.post(`/:id`, async (req, res) => await TestController.post(req, res, options));
11
11
  router.post(`/`, authMiddleware, async (req, res) => await TestController.post(req, res, options));
12
12
  router.get(`/:id`, async (req, res) => await TestController.get(req, res, options));
@@ -0,0 +1,216 @@
1
+ {
2
+ "info": {
3
+ "_postman_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
4
+ "name": "User API",
5
+ "description": "A collection of requests for the User API.",
6
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
7
+ },
8
+ "item": [
9
+ {
10
+ "name": "user",
11
+ "item": [
12
+ {
13
+ "name": "Log in",
14
+ "request": {
15
+ "method": "POST",
16
+ "header": [
17
+ {
18
+ "key": "Content-Type",
19
+ "value": "application/json",
20
+ "type": "text"
21
+ }
22
+ ],
23
+ "body": {
24
+ "mode": "raw",
25
+ "raw": "{\n \"email\": \"user@example.com\",\n \"password\": \"Password123\"\n}",
26
+ "options": {
27
+ "raw": {
28
+ "language": "json"
29
+ }
30
+ }
31
+ },
32
+ "url": {
33
+ "raw": "{{baseUrl}}/user/auth",
34
+ "host": ["{{baseUrl}}"],
35
+ "path": ["user", "auth"]
36
+ },
37
+ "description": "This endpoint get a JWT for authenticated user"
38
+ },
39
+ "response": [
40
+ {
41
+ "name": "User logged in successfully",
42
+ "originalRequest": {
43
+ "method": "POST",
44
+ "header": [],
45
+ "body": {
46
+ "mode": "raw",
47
+ "raw": ""
48
+ },
49
+ "url": {
50
+ "raw": "{{baseUrl}}/user/auth",
51
+ "host": ["{{baseUrl}}"],
52
+ "path": ["user", "auth"]
53
+ }
54
+ },
55
+ "status": "OK",
56
+ "code": 200,
57
+ "_postman_previewlanguage": "json",
58
+ "header": [
59
+ {
60
+ "key": "Content-Type",
61
+ "value": "application/json"
62
+ }
63
+ ],
64
+ "cookie": [],
65
+ "body": "{\n \"status\": \"success\",\n \"data\": {\n \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7Il9pZCI6IjY2YzM3N2Y1N2Y5OWU1OTY5YjgxZG...\",\n \"user\": {\n \"_id\": \"66c377f57f99e5969b81de89\",\n \"email\": \"user@example.com\",\n \"emailConfirmed\": false,\n \"username\": \"user123\",\n \"role\": \"user\",\n \"profileImageId\": \"66c377f57f99e5969b81de87\"\n }\n }\n}"
66
+ }
67
+ ]
68
+ },
69
+ {
70
+ "name": "Create user",
71
+ "request": {
72
+ "method": "POST",
73
+ "header": [
74
+ {
75
+ "key": "Content-Type",
76
+ "value": "application/json",
77
+ "type": "text"
78
+ }
79
+ ],
80
+ "body": {
81
+ "mode": "raw",
82
+ "raw": "{\n \"username\": \"user123\",\n \"password\": \"Password123\",\n \"email\": \"user@example.com\"\n}",
83
+ "options": {
84
+ "raw": {
85
+ "language": "json"
86
+ }
87
+ }
88
+ },
89
+ "url": {
90
+ "raw": "{{baseUrl}}/user",
91
+ "host": ["{{baseUrl}}"],
92
+ "path": ["user"]
93
+ },
94
+ "description": "This endpoint will create a new user account"
95
+ },
96
+ "response": []
97
+ },
98
+ {
99
+ "name": "Get user data by ID",
100
+ "request": {
101
+ "auth": {
102
+ "type": "bearer",
103
+ "bearer": [
104
+ {
105
+ "key": "token",
106
+ "value": "{{authToken}}",
107
+ "type": "string"
108
+ }
109
+ ]
110
+ },
111
+ "method": "GET",
112
+ "header": [],
113
+ "url": {
114
+ "raw": "{{baseUrl}}/user/:id",
115
+ "host": ["{{baseUrl}}"],
116
+ "path": ["user", ":id"],
117
+ "variable": [
118
+ {
119
+ "key": "id",
120
+ "value": "your_user_id"
121
+ }
122
+ ]
123
+ },
124
+ "description": "This endpoint get user data by ID"
125
+ },
126
+ "response": []
127
+ },
128
+ {
129
+ "name": "Update user data by ID",
130
+ "request": {
131
+ "auth": {
132
+ "type": "bearer",
133
+ "bearer": [
134
+ {
135
+ "key": "token",
136
+ "value": "{{authToken}}",
137
+ "type": "string"
138
+ }
139
+ ]
140
+ },
141
+ "method": "PUT",
142
+ "header": [
143
+ {
144
+ "key": "Content-Type",
145
+ "value": "application/json",
146
+ "type": "text"
147
+ }
148
+ ],
149
+ "body": {
150
+ "mode": "raw",
151
+ "raw": "{\n \"username\": \"newuser123\",\n \"password\": \"NewPassword123\",\n \"email\": \"newuser@example.com\"\n}",
152
+ "options": {
153
+ "raw": {
154
+ "language": "json"
155
+ }
156
+ }
157
+ },
158
+ "url": {
159
+ "raw": "{{baseUrl}}/user/:id",
160
+ "host": ["{{baseUrl}}"],
161
+ "path": ["user", ":id"],
162
+ "variable": [
163
+ {
164
+ "key": "id",
165
+ "value": "your_user_id"
166
+ }
167
+ ]
168
+ },
169
+ "description": "This endpoint will update user data by ID"
170
+ },
171
+ "response": []
172
+ },
173
+ {
174
+ "name": "Delete user data by ID",
175
+ "request": {
176
+ "auth": {
177
+ "type": "bearer",
178
+ "bearer": [
179
+ {
180
+ "key": "token",
181
+ "value": "{{authToken}}",
182
+ "type": "string"
183
+ }
184
+ ]
185
+ },
186
+ "method": "DELETE",
187
+ "header": [],
188
+ "url": {
189
+ "raw": "{{baseUrl}}/user/:id",
190
+ "host": ["{{baseUrl}}"],
191
+ "path": ["user", ":id"],
192
+ "variable": [
193
+ {
194
+ "key": "id",
195
+ "value": "your_user_id"
196
+ }
197
+ ]
198
+ },
199
+ "description": "This endpoint deletes user data by ID, the path ID must match with the ID of the authenticated user"
200
+ },
201
+ "response": []
202
+ }
203
+ ]
204
+ }
205
+ ],
206
+ "variable": [
207
+ {
208
+ "key": "baseUrl",
209
+ "value": "http://localhost:3000/api"
210
+ },
211
+ {
212
+ "key": "authToken",
213
+ "value": ""
214
+ }
215
+ ]
216
+ }
@@ -3,68 +3,33 @@ import { UserService } from './user.service.js';
3
3
 
4
4
  const logger = loggerFactory(import.meta);
5
5
 
6
- const UserController = {
7
- post: async (req, res, options) => {
8
- try {
9
- const result = await UserService.post(req, res, options);
10
- return res.status(200).json({
11
- status: 'success',
12
- data: result,
13
- });
14
- } catch (error) {
15
- logger.error(error, error.stack);
16
- return res.status(400).json({
17
- status: 'error',
18
- message: error.message,
19
- });
20
- }
21
- },
22
- get: async (req, res, options) => {
23
- try {
24
- const result = await UserService.get(req, res, options);
25
- if (result instanceof Buffer) return res.status(200).end(result);
26
- return res.status(200).json({
27
- status: 'success',
28
- data: result,
29
- });
30
- } catch (error) {
31
- logger.error(error, error.stack);
32
- return res.status(400).json({
33
- status: 'error',
34
- message: error.message,
35
- });
36
- }
37
- },
38
- delete: async (req, res, options) => {
39
- try {
40
- const result = await UserService.delete(req, res, options);
41
- return res.status(200).json({
42
- status: 'success',
43
- data: result,
44
- });
45
- } catch (error) {
46
- logger.error(error, error.stack);
47
- return res.status(400).json({
48
- status: 'error',
49
- message: error.message,
50
- });
6
+ const handleRequest = (serviceMethod) => async (req, res, options) => {
7
+ try {
8
+ const result = await serviceMethod(req, res, options);
9
+ if (res.headersSent) {
10
+ return;
51
11
  }
52
- },
53
- put: async (req, res, options) => {
54
- try {
55
- const result = await UserService.put(req, res, options);
56
- return res.status(200).json({
57
- status: 'success',
58
- data: result,
59
- });
60
- } catch (error) {
61
- logger.error(error, error.stack);
62
- return res.status(400).json({
63
- status: 'error',
64
- message: error.message,
65
- });
12
+ if (result instanceof Buffer) {
13
+ return res.status(200).end(result);
66
14
  }
67
- },
15
+ return res.status(200).json({
16
+ status: 'success',
17
+ data: result,
18
+ });
19
+ } catch (error) {
20
+ logger.error(error, error.stack);
21
+ return res.status(400).json({
22
+ status: 'error',
23
+ message: error.message,
24
+ });
25
+ }
26
+ };
27
+
28
+ const UserController = {
29
+ post: handleRequest(UserService.post),
30
+ get: handleRequest(UserService.get),
31
+ delete: handleRequest(UserService.delete),
32
+ put: handleRequest(UserService.put),
68
33
  };
69
34
 
70
35
  export { UserController };