@tiledesk/tiledesk-server 2.17.4 → 2.18.3

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 (49) hide show
  1. package/CHANGELOG.md +8 -3
  2. package/app.js +4 -0
  3. package/channels/chat21/chat21WebHook.js +6 -1
  4. package/docs/routes-answered.md +153 -0
  5. package/event/authEvent.js +16 -0
  6. package/event/projectUserEvent.js +39 -0
  7. package/event/roleEvent.js +9 -0
  8. package/middleware/has-role.js +160 -121
  9. package/middleware/passport.js +180 -179
  10. package/migrations/1757601159298-project_user_role_type.js +104 -0
  11. package/models/department.js +3 -0
  12. package/models/groupMemberSchama.js +19 -0
  13. package/models/kb_setting.js +74 -4
  14. package/models/permissionConstants.js +19 -0
  15. package/models/project_user.js +86 -8
  16. package/models/request.js +1 -0
  17. package/models/role.js +31 -0
  18. package/models/roleConstants.js +2 -0
  19. package/package.json +1 -1
  20. package/pubmodules/analytics/analytics.js +2 -2
  21. package/pubmodules/cache/mongoose-cachegoose-fn.js +37 -0
  22. package/pubmodules/canned/cannedResponseRoute.js +34 -6
  23. package/pubmodules/routing-queue/listener.js +7 -1
  24. package/pubmodules/trigger/rulesTrigger.js +1 -6
  25. package/routes/answered.js +227 -0
  26. package/routes/auth.js +3 -1
  27. package/routes/department.js +7 -1
  28. package/routes/message.js +4 -1
  29. package/routes/project.js +41 -3
  30. package/routes/project_user.js +62 -11
  31. package/routes/request.js +32 -30
  32. package/routes/roles.js +151 -0
  33. package/routes/unanswered.js +32 -19
  34. package/routes/widget.js +3 -1
  35. package/services/cacheEnabler.js +5 -8
  36. package/services/departmentService.js +39 -11
  37. package/services/emailService.js +2 -2
  38. package/services/pendingInvitationService.js +2 -0
  39. package/services/projectService.js +3 -1
  40. package/services/projectUserService.js +67 -4
  41. package/services/subscriptionNotifierQueued.js +8 -0
  42. package/services/updateRequestSnapshotQueued.js +0 -3
  43. package/test/departmentService.js +5 -0
  44. package/test/messageRoute.js +7 -4
  45. package/test/projectUserRoute.js +116 -0
  46. package/test/requestService.js +7 -3
  47. package/test-int/bot.js +3 -2
  48. package/websocket/webSocketServer.js +273 -225
  49. package/routes/auth_newjwt.js +0 -648
@@ -31,6 +31,10 @@ var TagSchema = require("../models/tag");
31
31
  index: true
32
32
  // required: true
33
33
  },
34
+ roleType: {
35
+ type: Number, //1 for agents 2 for users
36
+ index: true
37
+ },
34
38
  user_available: {
35
39
  type: Boolean,
36
40
  default: true,
@@ -63,6 +67,7 @@ var TagSchema = require("../models/tag");
63
67
  type: Object,
64
68
  },
65
69
  tags: [TagSchema],
70
+ permissions: [String],
66
71
  createdBy: {
67
72
  type: String,
68
73
  required: true
@@ -86,14 +91,16 @@ var TagSchema = require("../models/tag");
86
91
  );
87
92
 
88
93
 
89
- Project_userSchema.virtual('events', {
90
- ref: 'event', // The model to use
91
- localField: '_id', // Find people where `localField`
92
- foreignField: 'project_user', // is equal to `foreignField`
93
- justOne: false,
94
- // options: { getters: true }
95
- options: { sort: { createdAt: -1 }, limit: 5 } // Query options, see http://bit.ly/mongoose-query-options
96
- });
94
+
95
+ //TODO COMMENT IT unused. Now events are not saved to the db
96
+ // Project_userSchema.virtual('events', {
97
+ // ref: 'event', // The model to use
98
+ // localField: '_id', // Find people where `localField`
99
+ // foreignField: 'project_user', // is equal to `foreignField`
100
+ // justOne: false,
101
+ // // options: { getters: true }
102
+ // options: { sort: { createdAt: -1 }, limit: 5 } // Query options, see http://bit.ly/mongoose-query-options
103
+ // });
97
104
 
98
105
  Project_userSchema.virtual('isAuthenticated').get(function () {
99
106
  if (this.role === RoleConstants.GUEST ) {
@@ -103,6 +110,77 @@ Project_userSchema.virtual('isAuthenticated').get(function () {
103
110
  }
104
111
  });
105
112
 
113
+ Project_userSchema.methods.getAllPermissions = function () {
114
+ // console.log("this", this);
115
+ winston.debug("this.permissions", this.permissions);
116
+
117
+ // console.log("this.rolePermissions", this.rolePermissions);
118
+ winston.debug("this._doc.rolePermissions", this._doc.rolePermissions);
119
+
120
+ let all = this.permissions;
121
+
122
+ if (this._doc.rolePermissions) {
123
+ all = [...new Set([...this.permissions, ...this._doc.rolePermissions])]; //https://medium.com/@rivoltafilippo/javascript-merge-arrays-without-duplicates-3fbd8f4881be
124
+ }
125
+ // const all = this.permissions.concat(this._doc.rolePermissions);
126
+ winston.verbose("getAllPermissions all", all);
127
+
128
+ return all;
129
+
130
+ }
131
+
132
+
133
+
134
+ Project_userSchema.methods.hasPermissionOrRole = function (permission, roles) {
135
+ var all_permissions = this.getAllPermissions();
136
+ // var all_permissions = this.getAllPermissions();
137
+ // console.log("hasPermissionOrRole", all_permissions, permission, this.role, roles)
138
+ if (all_permissions && all_permissions.length>0 ) {
139
+ if (all_permissions.includes(permission)) {
140
+ // console.log("hasPermissionOrRole found", permission)
141
+ return true;
142
+ } else {
143
+ return false;
144
+ }
145
+ }else {
146
+ if (roles instanceof Array) {
147
+ // console.log("hasPermissionOrRole roles instanceof Array");
148
+ for (var i = 0; i < roles.length; i++) {
149
+ if (roles[i]==this.role) {
150
+ return true;
151
+ }
152
+ }
153
+ return false;
154
+
155
+ } else {
156
+ // console.log("roles instanceof ", roles instanceof );
157
+ // console.log("this.role instanceof ", this.role instanceof );
158
+
159
+ // console.log("hasPermissionOrRole role ", this.role, roles);
160
+ if (this.role==roles) {
161
+ // console.log("role ok");
162
+ return true;
163
+ } else {
164
+ // console.log("role ko");
165
+ return false;
166
+ }
167
+ }
168
+
169
+
170
+ }
171
+ }
172
+
173
+ Project_userSchema.methods.hasPermission = function (permission) {
174
+ if (this.permissions && this.permissions.length>0 ) {
175
+ if (this.permissions.includes(permission)) {
176
+ return true;
177
+ } else {
178
+ return false;
179
+ }
180
+ }else {
181
+ return false;
182
+ }
183
+ }
106
184
 
107
185
 
108
186
  // var query = { id_project: req.params.projectid, id_user: req.user._id};
package/models/request.js CHANGED
@@ -11,6 +11,7 @@ var ProjectUserSchema = require("../models/project_user").schema;
11
11
  var RequestStatus = require("../models/requestStatus");
12
12
  var LeadSchema = require("../models/lead").schema; //it's not used but i you run test like (mocha departmentService.js) it throws this not blocking exception: error: error getting requestSchema hasn't been registered for model "lead".
13
13
  var NoteSchema = require("../models/note").schema;
14
+
14
15
  var TagSchema = require("../models/tag");
15
16
  var LocationSchema = require("../models/location");
16
17
  var RequestSnapshotSchema = require("../models/requestSnapshot");
package/models/role.js ADDED
@@ -0,0 +1,31 @@
1
+ var mongoose = require('mongoose');
2
+ var Schema = mongoose.Schema;
3
+ var winston = require('../config/winston');
4
+
5
+
6
+ var RoleSchema = new Schema({
7
+ name: {
8
+ type: String,
9
+ required: true,
10
+ index:true
11
+ },
12
+ permissions: [String],
13
+ // permissions: {
14
+ // type: String,
15
+ // required: true
16
+ // },
17
+ id_project: {
18
+ type: String,
19
+ required: true,
20
+ index: true
21
+ },
22
+
23
+ });
24
+ var role = mongoose.model('role', RoleSchema);
25
+
26
+ if (process.env.MONGOOSE_SYNCINDEX) {
27
+ role.syncIndexes();
28
+ winston.verbose("role syncIndexes")
29
+ }
30
+
31
+ module.exports = role;
@@ -1,4 +1,6 @@
1
1
  module.exports = {
2
+ TYPE_AGENTS : 1,
3
+ TYPE_USERS : 2,
2
4
  // SUPERADMIN : 'superadmin',
3
5
  OWNER : 'owner',
4
6
  ADMIN : 'admin',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-server",
3
3
  "description": "The Tiledesk server module",
4
- "version": "2.17.4",
4
+ "version": "2.18.3",
5
5
  "scripts": {
6
6
  "start": "node ./bin/www",
7
7
  "pretest": "mongodb-runner start",
@@ -1780,7 +1780,7 @@ router.get('/tags/:type', async (req, res) => {
1780
1780
  date: { $gte: startDate, $lte: endDate }
1781
1781
  }
1782
1782
 
1783
- console.log("analytics tags query: ", query)
1783
+ winston.debug("analytics tags query: ", query)
1784
1784
 
1785
1785
  let result = await Analytics.find(query).catch((err) => {
1786
1786
  winston.error("Error finding Analytics: ", err);
@@ -1821,7 +1821,7 @@ router.get('/tags/:type', async (req, res) => {
1821
1821
 
1822
1822
  // Assembly final result
1823
1823
  let data = { dates, series };
1824
- console.log(data);
1824
+
1825
1825
 
1826
1826
  return res.status(200).send(data);
1827
1827
 
@@ -10,6 +10,7 @@
10
10
 
11
11
  var triggerEventEmitter = require("../trigger/event/triggerEventEmitter");
12
12
  var subscriptionEvent = require("../../event/subscriptionEvent");
13
+ var roleEvent = require("../../event/roleEvent");
13
14
 
14
15
  var winston = require('../../config/winston');
15
16
 
@@ -837,7 +838,43 @@
837
838
  });
838
839
  });
839
840
  });
841
+
842
+
843
+ roleEvent.on('role.create', function(role) {
844
+ setImmediate(() => {
845
+ var key =role.id_project+":roles:"+role.name;
846
+ winston.verbose("Deleting cache for role.create with key: " + key);
847
+ winston.verbose("Creating cache for department.create with key: " + key);
848
+ client.set(key, role, cacheUtil.defaultTTL, (err, reply) => {
849
+ winston.debug("Created cache for role.create",reply);
850
+ winston.verbose("Created cache for role.create",{err:err});
851
+ });
852
+
853
+ });
854
+ });
855
+
856
+ roleEvent.on('role.update', function(role) {
857
+ setImmediate(() => {
858
+ var key =role.id_project+":roles:"+role.name;
859
+ winston.verbose("Deleting cache for role.update with key: " + key);
860
+ client.set(key, role, cacheUtil.defaultTTL, (err, reply) => {
861
+ winston.debug("Updated cache for role.update",reply);
862
+ winston.verbose("Updated cache for role.update",{err:err});
863
+ });
864
+ });
865
+ });
840
866
 
867
+ roleEvent.on("role.delete", function(role) {
868
+ setImmediate(() => {
869
+ var key =role.id_project+":roles:"+role.name;
870
+ winston.verbose("Deleting cache for role.delete with key: " + key);
871
+ del(client._cache._engine.client, key, function (err, reply) {
872
+ winston.debug("Deleted cache for role.delete",reply);
873
+ winston.verbose("Deleted cache for role.delete",{err:err});
874
+ });
875
+ });
876
+ });
877
+
841
878
  }
842
879
 
843
880
 
@@ -3,6 +3,7 @@ var router = express.Router();
3
3
  var CannedResponse = require("./cannedResponse");
4
4
  var winston = require('../../config/winston');
5
5
  const RoleConstants = require('../../models/roleConstants');
6
+ const roleConstants = require('../../models/roleConstants');
6
7
  // const CannedResponseEvent = require('../event/CannedResponseEvent');
7
8
 
8
9
 
@@ -16,13 +17,18 @@ router.post('/', function (req, res) {
16
17
  text: req.body.text,
17
18
  id_project: req.projectid,
18
19
  createdBy: req.user.id,
19
- updatedBy: req.user.id
20
+ updatedBy: req.user.id,
21
+ shared: false
20
22
  });
21
23
 
22
24
  if (req.projectuser.role == 'owner' || req.projectuser.role == 'admin') {
23
25
  newCannedResponse.shared = true;
24
26
  } else {
25
- newCannedResponse.shared = false;
27
+ if (req.projectuser.roleType === roleConstants.TYPE_AGENTS) {
28
+ if (req.body.shared && req.body.shared === true) {
29
+ newCannedResponse.shared = true;
30
+ }
31
+ }
26
32
  }
27
33
 
28
34
  newCannedResponse.save(function (err, savedCannedResponse) {
@@ -40,8 +46,8 @@ router.put('/:cannedResponseid', async function (req, res) {
40
46
  winston.debug(req.body);
41
47
  const canned_id = req.params.cannedResponseid;
42
48
  const id_project = req.projectid;
43
- let user_role = req.projectuser.role;
44
-
49
+ let user_role = req.projectuser?.role;
50
+ let roleType = req.projectuser?.roleType || null;
45
51
  var update = {};
46
52
 
47
53
  const allowedFields = ['title', 'text', 'attributes']
@@ -79,6 +85,12 @@ router.put('/:cannedResponseid', async function (req, res) {
79
85
  winston.warn("Not allowed. User " + req.user.id + " can't modify a canned response of user " + canned.createdBy);
80
86
  return res.status(403).send({ success: false, error: "Not allowed to modify a non administration canned response"})
81
87
  }
88
+ }
89
+ else if (roleType === RoleConstants.TYPE_AGENTS) {
90
+ if (canned.hasOwnProperty('shared') && canned.shared === false && canned.createdBy !== req.user.id) {
91
+ winston.warn("Not allowed. User " + req.user.id + " can't modify a canned response of user " + canned.createdBy);
92
+ return res.status(403).send({ success: false, error: "Not allowed to modify a non administration canned response"})
93
+ }
82
94
  } else {
83
95
  winston.warn("User " + req.user.id + "trying to modify canned with role " + user_role);
84
96
  return res.status(401).send({ success: false, error: "Unauthorized"})
@@ -100,6 +112,7 @@ router.delete('/:cannedResponseid', async function (req, res) {
100
112
  const canned_id = req.params.cannedResponseid;
101
113
  const id_project = req.projectid;
102
114
  let user_role = req.projectuser.role;
115
+ let roleType = req.projectuser?.roleType || null;
103
116
 
104
117
  let canned = await CannedResponse.findOne({ _id: canned_id, id_project: id_project }).catch((err) => {
105
118
  winston.error("Error finding canned response: ", err);
@@ -128,7 +141,14 @@ router.delete('/:cannedResponseid', async function (req, res) {
128
141
  winston.warn("Not allowed. User " + req.user.id + " can't delete a canned response of user " + canned.createdBy);
129
142
  return res.status(403).send({ success: false, error: "Not allowed to delete a non administration canned response"})
130
143
  }
131
- } else {
144
+ }
145
+ else if (roleType === RoleConstants.TYPE_AGENTS) {
146
+ if (canned.hasOwnProperty('shared') && canned.shared === false && canned.createdBy !== req.user.id) {
147
+ winston.warn("Not allowed. User " + req.user.id + " can't delete a canned response of user " + canned.createdBy);
148
+ return res.status(403).send({ success: false, error: "Not allowed to delete a non administration canned response"})
149
+ }
150
+ }
151
+ else {
132
152
  winston.warn("User " + req.user.id + "trying to delete canned with role " + user_role);
133
153
  return res.status(401).send({ success: false, error: "Unauthorized"})
134
154
  }
@@ -149,6 +169,7 @@ router.delete('/:cannedResponseid/physical', async function (req, res) {
149
169
  const canned_id = req.params.cannedResponseid;
150
170
  const id_project = req.projectid;
151
171
  let user_role = req.projectuser.role;
172
+ let roleType = req.projectuser?.roleType || null;
152
173
 
153
174
  let canned = await CannedResponse.findOne({ _id: canned_id, id_project: id_project }).catch((err) => {
154
175
  winston.error("Error finding canned response: ", err);
@@ -177,7 +198,14 @@ router.delete('/:cannedResponseid/physical', async function (req, res) {
177
198
  winston.warn("Not allowed. User " + req.user.id + " can't delete a canned response of user " + canned.createdBy);
178
199
  return res.status(403).send({ success: false, error: "Not allowed to delete a non administration canned response"})
179
200
  }
180
- } else {
201
+ }
202
+ else if (roleType === RoleConstants.TYPE_AGENTS) {
203
+ if (canned.hasOwnProperty('shared') && canned.shared === false && canned.createdBy !== req.user.id) {
204
+ winston.warn("Not allowed. User " + req.user.id + " can't delete a canned response of user " + canned.createdBy);
205
+ return res.status(403).send({ success: false, error: "Not allowed to delete a non administration canned response"})
206
+ }
207
+ }
208
+ else {
181
209
  winston.warn("User " + req.user.id + "trying to delete canned with role " + user_role);
182
210
  return res.status(401).send({ success: false, error: "Unauthorized"})
183
211
  }
@@ -110,7 +110,13 @@ class Listener {
110
110
  var query = {id_project: operatorsResult.id_project, status: {$lt:1000}};
111
111
  // asyncForEach(operatorsResult.available_agents, async (aa) => {
112
112
  for (const aa of operatorsResult.available_agents) {
113
- query.participants = aa.id_user._id.toString();// attento qui
113
+ let user_id;
114
+ if (aa.id_user._id) {
115
+ user_id = aa.id_user._id.toString();// attento qui
116
+ } else {
117
+ user_id = aa.id_user;// attento qui
118
+ }
119
+ query.participants = user_id;
114
120
  winston.debug("department operators query:" , query);
115
121
 
116
122
 
@@ -1164,11 +1164,8 @@ class RulesTrigger {
1164
1164
  lead: createdLead, requester: puser
1165
1165
  };
1166
1166
 
1167
- //let t1 = Date.now();
1167
+
1168
1168
  return requestService.create(new_request).then(function (savedRequest) {
1169
- //console.log("[Performance] (rulesTrigger) requestService.create time: " + (Date.now() - t1));
1170
- // performance console log
1171
- // console.log("************* request created trigger: "+new Date().toISOString());
1172
1169
 
1173
1170
  if (attributes) {
1174
1171
  attributes.sendnotification = false; // sembra nn funzionae
@@ -1177,9 +1174,7 @@ class RulesTrigger {
1177
1174
  var senderFullname = fullname || 'Guest'; // guest_here
1178
1175
 
1179
1176
  // create(sender, senderFullname, recipient, text, id_project, createdBy, status, attributes, type, metadata, language) {
1180
- //let t2 = Date.now();
1181
1177
  return messageService.create( id_user, senderFullname , savedRequest.request_id, text, id_project, id_user, MessageConstants.CHAT_MESSAGE_STATUS.SENDING, attributes, type, eventTrigger.event.metadata, language).then(function(savedMessage) {
1182
- //console.log("[Performance] (rulesTrigger) messageService.create time: " + (Date.now() - t2));
1183
1178
  return savedMessage;
1184
1179
  });
1185
1180
  }).catch(function (err) {
@@ -0,0 +1,227 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { Namespace, AnsweredQuestion } = require('../models/kb_setting');
4
+ const winston = require('../config/winston');
5
+
6
+ // Add a new unanswerd question
7
+ router.post('/', async (req, res) => {
8
+ try {
9
+ const { namespace, question, answer, tokens, request_id } = req.body;
10
+ const id_project = req.projectid;
11
+
12
+ if (!namespace || !question || !answer) {
13
+ return res.status(400).json({
14
+ success: false,
15
+ error: "Missing required parameters: namespace, question and answer"
16
+ })
17
+ }
18
+
19
+ // Check if namespae belongs to project
20
+ const isValidNamespace = await validateNamespace(id_project, namespace);
21
+ if (!isValidNamespace) {
22
+ return res.status(403).json({
23
+ success: false,
24
+ error: "Not allowed. The namespace does not belong to the current project."
25
+ })
26
+ }
27
+
28
+ const answeredQuestion = new AnsweredQuestion({
29
+ id_project,
30
+ namespace,
31
+ question,
32
+ answer,
33
+ tokens,
34
+ request_id,
35
+ });
36
+
37
+ const savedQuestion = await answeredQuestion.save();
38
+ res.status(200).json(savedQuestion);
39
+
40
+ } catch (error) {
41
+ winston.error('Error adding answered question:', error);
42
+ res.status(500).json({
43
+ success: false,
44
+ error: "Error adding answered question"
45
+ });
46
+ }
47
+ })
48
+
49
+ // Get all answered questions for a namespace
50
+ router.get('/:namespace', async (req, res) => {
51
+
52
+ try {
53
+ const { namespace } = req.params;
54
+ const id_project = req.projectid;
55
+
56
+ if (!namespace) {
57
+ return res.status(400).json({
58
+ success: false,
59
+ error: "Missing required parameter: namespace"
60
+ })
61
+ }
62
+
63
+ // Check if namespace belongs to project
64
+ const isValidNamespace = await validateNamespace(id_project, namespace);
65
+ if (!isValidNamespace) {
66
+ return res.status(403).json({
67
+ success: false,
68
+ error: "Not allowed. The namespace does not belong to the current project."
69
+ })
70
+ }
71
+
72
+ const page = parseInt(req.query.page) || 0;
73
+ const limit = parseInt(req.query.limit) || 20;
74
+ const sortField = req.query.sortField || 'created_at';
75
+ const direction = parseInt(req.query.direction) || -1;
76
+
77
+ const filter = { id_project, namespace };
78
+
79
+ let projection = undefined;
80
+
81
+ if (req.query.search) {
82
+ filter.$text = { $search: req.query.search };
83
+ // Add score to projection if it's a text search
84
+ projection = { score: { $meta: "textScore" } };
85
+ }
86
+
87
+ let sortObj;
88
+ if (projection && projection.score) {
89
+ sortObj = { score: { $meta: "textScore" } };
90
+ } else {
91
+ sortObj = { [sortField]: direction };
92
+ }
93
+
94
+ const questions = await AnsweredQuestion.find(filter, projection)
95
+ .sort(sortObj)
96
+ .skip(page * limit)
97
+ .limit(limit);
98
+
99
+ const count = await AnsweredQuestion.countDocuments(filter);
100
+
101
+ res.status(200).json({
102
+ count,
103
+ questions,
104
+ query: {
105
+ page,
106
+ limit,
107
+ sortField,
108
+ direction,
109
+ search: req.query.search || undefined
110
+ }
111
+ });
112
+
113
+ } catch (error) {
114
+ winston.error('Error getting answered questions:', error);
115
+ res.status(500).json({
116
+ success: false,
117
+ error: "Error getting answered questions"
118
+ });
119
+ }
120
+
121
+ })
122
+
123
+ router.delete('/:id', async (req, res) => {
124
+ try {
125
+ const { id } = req.params;
126
+ const id_project = req.projectid;
127
+
128
+ const deleted = await AnsweredQuestion.findOneAndDelete({ _id: id, id_project });
129
+ if (!deleted) {
130
+ return res.status(404).json({
131
+ success: false,
132
+ error: "Question not found"
133
+ });
134
+ }
135
+
136
+ res.status(200).json({
137
+ success: true,
138
+ message: "Question deleted successfully"
139
+ });
140
+
141
+ } catch (error) {
142
+ winston.error('Error deleting answered question:', error);
143
+ res.status(500).json({
144
+ success: false,
145
+ error: "Error deleting answered question"
146
+ });
147
+ }
148
+ })
149
+
150
+ router.delete('/namespace/:namespace', async (req, res) => {
151
+ try {
152
+ const { namespace } = req.params;
153
+ const id_project = req.projectid;
154
+
155
+ // Check if namespace belongs to project
156
+ const isValidNamespace = await validateNamespace(id_project, namespace);
157
+ if (!isValidNamespace) {
158
+ return res.status(403).json({
159
+ success: false,
160
+ error: "Not allowed. The namespace does not belong to the current project."
161
+ });
162
+ }
163
+
164
+ const result = await AnsweredQuestion.deleteMany({ id_project, namespace });
165
+ res.status(200).json({
166
+ success: true,
167
+ count: result.deletedCount,
168
+ message: "All questions deleted successfully"
169
+ });
170
+
171
+ } catch (error) {
172
+ winston.error('Error deleting answered questions:', error);
173
+ res.status(500).json({
174
+ success: false,
175
+ error: "Error deleting answered questions"
176
+ });
177
+ }
178
+ })
179
+
180
+ router.get('/count/:namespace', async (req, res) => {
181
+ try {
182
+ const { namespace } = req.params;
183
+ const id_project = req.projectid;
184
+
185
+ if (!namespace) {
186
+ return res.status(400).json({
187
+ success: false,
188
+ error: "Missing required parameter: namespace"
189
+ });
190
+ }
191
+
192
+ // Check if namespace belongs to project
193
+ const isValidNamespace = await validateNamespace(id_project, namespace);
194
+ if (!isValidNamespace) {
195
+ return res.status(403).json({
196
+ success: false,
197
+ error: "Not allowed. The namespace does not belong to the current project."
198
+ });
199
+ }
200
+
201
+ const count = await AnsweredQuestion.countDocuments({ id_project, namespace });
202
+ res.status(200).json({ count });
203
+
204
+ } catch (error) {
205
+ winston.error('Error counting answered questions:', error);
206
+ res.status(500).json({
207
+ success: false,
208
+ error: "Error counting answered questions"
209
+ });
210
+ }
211
+ })
212
+
213
+ // Helper function to validate namespace
214
+ async function validateNamespace(id_project, namespace_id) {
215
+ try {
216
+ const namespace = await Namespace.findOne({
217
+ id_project: id_project,
218
+ id: namespace_id
219
+ });
220
+ return !!namespace;
221
+ } catch (err) {
222
+ winston.error('validate namespace error: ', err);
223
+ throw err;
224
+ }
225
+ }
226
+
227
+ module.exports = router;
package/routes/auth.js CHANGED
@@ -197,6 +197,7 @@ function (req, res) {
197
197
  id_project: req.body.id_project, //attentoqui
198
198
  uuid_user: req.user._id,
199
199
  role: RoleConstants.GUEST,
200
+ roleType : RoleConstants.TYPE_USERS,
200
201
  user_available: true,
201
202
  createdBy: req.user._id,
202
203
  updatedBy: req.user._id
@@ -408,6 +409,7 @@ router.post('/signinWithCustomToken', [
408
409
  uuid_user: req.user._id,
409
410
  // id_user: req.user._id,
410
411
  role: role,
412
+ roleType : RoleConstants.TYPE_USERS, //RICONtROLLA QUIA
411
413
  user_available: true,
412
414
  createdBy: req.user._id, //oppure req.user.id attento problema
413
415
  updatedBy: req.user._id
@@ -486,7 +488,7 @@ router.post('/signinWithCustomToken', [
486
488
  } else {
487
489
  winston.debug('different role : '+role + " " + project_user.role);
488
490
  }
489
-
491
+ // rolecheck
490
492
  if (req.user.role && (req.user.role === RoleConstants.OWNER || req.user.role === RoleConstants.ADMIN || req.user.role === RoleConstants.AGENT)) {
491
493
  let userFromDB = await User.findOne({email: req.user.email.toLowerCase(), status: 100}).exec();
492
494
 
@@ -24,6 +24,7 @@ router.post('/', [passport.authenticate(['basic', 'jwt'], { session: false }), v
24
24
  default: req.body.default,
25
25
  status: req.body.status,
26
26
  id_group: req.body.id_group,
27
+ groups: req.body.groups,
27
28
  id_project: req.projectid,
28
29
  createdBy: req.user.id,
29
30
  updatedBy: req.user.id
@@ -79,7 +80,9 @@ router.put('/:departmentid', [passport.authenticate(['basic', 'jwt'], { session:
79
80
  if (req.body.status!=undefined) {
80
81
  update.status = req.body.status;
81
82
  }
82
-
83
+ if (req.body.groups!=undefined) {
84
+ update.groups = req.body.groups;
85
+ }
83
86
 
84
87
 
85
88
  Department.findByIdAndUpdate(req.params.departmentid, update, { new: true, upsert: true }, function (err, updatedDepartment) {
@@ -121,6 +124,9 @@ router.put('/:departmentid', [passport.authenticate(['basic', 'jwt'], { session:
121
124
  if (req.body.id_group!=undefined) {
122
125
  update.id_group = req.body.id_group;
123
126
  }
127
+ if (req.body.groups!=undefined) {
128
+ update.groups = req.body.groups;
129
+ }
124
130
 
125
131
 
126
132
  Department.findByIdAndUpdate(req.params.departmentid, update, { new: true, upsert: true }, function (err, updatedDepartment) {