@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.
- package/CHANGELOG.md +8 -3
- package/app.js +4 -0
- package/channels/chat21/chat21WebHook.js +6 -1
- package/docs/routes-answered.md +153 -0
- package/event/authEvent.js +16 -0
- package/event/projectUserEvent.js +39 -0
- package/event/roleEvent.js +9 -0
- package/middleware/has-role.js +160 -121
- package/middleware/passport.js +180 -179
- package/migrations/1757601159298-project_user_role_type.js +104 -0
- package/models/department.js +3 -0
- package/models/groupMemberSchama.js +19 -0
- package/models/kb_setting.js +74 -4
- package/models/permissionConstants.js +19 -0
- package/models/project_user.js +86 -8
- package/models/request.js +1 -0
- package/models/role.js +31 -0
- package/models/roleConstants.js +2 -0
- package/package.json +1 -1
- package/pubmodules/analytics/analytics.js +2 -2
- package/pubmodules/cache/mongoose-cachegoose-fn.js +37 -0
- package/pubmodules/canned/cannedResponseRoute.js +34 -6
- package/pubmodules/routing-queue/listener.js +7 -1
- package/pubmodules/trigger/rulesTrigger.js +1 -6
- package/routes/answered.js +227 -0
- package/routes/auth.js +3 -1
- package/routes/department.js +7 -1
- package/routes/message.js +4 -1
- package/routes/project.js +41 -3
- package/routes/project_user.js +62 -11
- package/routes/request.js +32 -30
- package/routes/roles.js +151 -0
- package/routes/unanswered.js +32 -19
- package/routes/widget.js +3 -1
- package/services/cacheEnabler.js +5 -8
- package/services/departmentService.js +39 -11
- package/services/emailService.js +2 -2
- package/services/pendingInvitationService.js +2 -0
- package/services/projectService.js +3 -1
- package/services/projectUserService.js +67 -4
- package/services/subscriptionNotifierQueued.js +8 -0
- package/services/updateRequestSnapshotQueued.js +0 -3
- package/test/departmentService.js +5 -0
- package/test/messageRoute.js +7 -4
- package/test/projectUserRoute.js +116 -0
- package/test/requestService.js +7 -3
- package/test-int/bot.js +3 -2
- package/websocket/webSocketServer.js +273 -225
- package/routes/auth_newjwt.js +0 -648
package/CHANGELOG.md
CHANGED
|
@@ -5,11 +5,16 @@
|
|
|
5
5
|
🚀 IN PRODUCTION 🚀
|
|
6
6
|
(https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
|
|
7
7
|
|
|
8
|
-
# 2.
|
|
9
|
-
-
|
|
8
|
+
# 2.18.3
|
|
9
|
+
- Added permissions logic
|
|
10
|
+
- Added custom roles support
|
|
11
|
+
- Add answered questions functionality
|
|
12
|
+
- Added AnsweredQuestion schema with TTL index for automatic deletion.
|
|
13
|
+
- Updated UnansweredQuestion schema to include additional fields and improved query handling for searching and sorting.
|
|
14
|
+
- Enhanced the deletion process for unanswered questions.
|
|
10
15
|
|
|
11
16
|
# 2.17.4
|
|
12
|
-
-
|
|
17
|
+
- Refactor error handling and code structure in webhook.js
|
|
13
18
|
|
|
14
19
|
# 2.17.3
|
|
15
20
|
- Added missing import path on kb route
|
package/app.js
CHANGED
|
@@ -130,6 +130,7 @@ var integration = require('./routes/integration')
|
|
|
130
130
|
var kbsettings = require('./routes/kbsettings');
|
|
131
131
|
var kb = require('./routes/kb');
|
|
132
132
|
var unanswered = require('./routes/unanswered');
|
|
133
|
+
var answered = require('./routes/answered');
|
|
133
134
|
|
|
134
135
|
// var admin = require('./routes/admin');
|
|
135
136
|
var faqpub = require('./routes/faqpub');
|
|
@@ -149,6 +150,7 @@ var property = require('./routes/property');
|
|
|
149
150
|
var segment = require('./routes/segment');
|
|
150
151
|
var webhook = require('./routes/webhook');
|
|
151
152
|
var webhooks = require('./routes/webhooks');
|
|
153
|
+
var roles = require('./routes/roles');
|
|
152
154
|
var copilot = require('./routes/copilot');
|
|
153
155
|
var mcp = require('./routes/mcp');
|
|
154
156
|
|
|
@@ -642,12 +644,14 @@ app.use('/:projectid/mcp', [passport.authenticate(['basic', 'jwt'], { session: f
|
|
|
642
644
|
|
|
643
645
|
app.use('/:projectid/kbsettings', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], kbsettings);
|
|
644
646
|
app.use('/:projectid/kb/unanswered', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('admin', ['bot','subscription'])], unanswered);
|
|
647
|
+
app.use('/:projectid/kb/answered', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('admin', ['bot','subscription'])], answered);
|
|
645
648
|
app.use('/:projectid/kb', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('admin', ['bot','subscription'])], kb);
|
|
646
649
|
|
|
647
650
|
app.use('/:projectid/logs', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('agent')], logs);
|
|
648
651
|
|
|
649
652
|
app.use('/:projectid/webhooks', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('admin')], webhooks);
|
|
650
653
|
app.use('/:projectid/copilot', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('agent')], copilot);
|
|
654
|
+
app.use('/:projectid/roles', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('agent')], roles);
|
|
651
655
|
|
|
652
656
|
app.use('/:projectid/files', filesp);
|
|
653
657
|
|
|
@@ -307,7 +307,12 @@ router.post('/', function (req, res) {
|
|
|
307
307
|
// TODO se stato = 50 e scrive visitatotre sposto a stato 100 poi queuue lo smista
|
|
308
308
|
|
|
309
309
|
// TOOD update also request attributes and sourcePage
|
|
310
|
-
|
|
310
|
+
if (message.sender !== 'system') {
|
|
311
|
+
Request.findOneAndUpdate({request_id: request.request_id, id_project: request.id_project}, { "attributes.last_message": savedMessage}).catch((err) => {
|
|
312
|
+
winston.error("Create message - saving last message in request error: ", err);
|
|
313
|
+
})
|
|
314
|
+
}
|
|
315
|
+
|
|
311
316
|
// return requestService.incrementMessagesCountByRequestId(request.request_id, request.id_project).then(function(savedRequest) {
|
|
312
317
|
// winston.debug("savedRequest.participants.indexOf(message.sender)", savedRequest.participants.indexOf(message.sender));
|
|
313
318
|
winston.debug("before updateWaitingTimeByRequestId*******",request.participants, message.sender);
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Route `kb/answered` — domande con risposta (Knowledge Base)
|
|
2
|
+
|
|
3
|
+
Documentazione per [`routes/answered.js`](../routes/answered.js).
|
|
4
|
+
|
|
5
|
+
## Scopo
|
|
6
|
+
|
|
7
|
+
API REST per gestire le **domande già risposte** associate a un **namespace** della Knowledge Base del progetto. I documenti sono persistiti nel modello Mongoose `AnsweredQuestion` (vedi [`models/kb_setting.js`](../models/kb_setting.js)).
|
|
8
|
+
|
|
9
|
+
Ogni operazione è vincolata al **progetto corrente** (`req.projectid`, derivato dal segmento `:projectid` nell’URL) e alla validità del **namespace** (deve esistere un `Namespace` con `id` uguale al `namespace` richiesto e `id_project` uguale al progetto).
|
|
10
|
+
|
|
11
|
+
## Montaggio e autenticazione
|
|
12
|
+
|
|
13
|
+
In [`app.js`](../app.js) il router è montato così:
|
|
14
|
+
|
|
15
|
+
- **Path base:** `/:projectid/kb/answered`
|
|
16
|
+
- **Middleware:** `passport.authenticate(['basic', 'jwt'])`, `validtoken`, `roleChecker.hasRoleOrTypes('admin', ['bot','subscription'])`
|
|
17
|
+
|
|
18
|
+
Sono quindi richiesti autenticazione (Basic o JWT), token valido e ruolo **admin** oppure tipi **bot** / **subscription**.
|
|
19
|
+
|
|
20
|
+
Esempio di URL completo (sviluppo locale):
|
|
21
|
+
|
|
22
|
+
```http
|
|
23
|
+
GET http://localhost:3000/{projectId}/kb/answered/{namespace}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Sostituire `{projectId}` con l’ID MongoDB del progetto.
|
|
27
|
+
|
|
28
|
+
## Modello dati (`AnsweredQuestion`)
|
|
29
|
+
|
|
30
|
+
| Campo | Tipo | Note |
|
|
31
|
+
|---------------|----------|-------------------------------------------|
|
|
32
|
+
| `id_project` | string | Impostato dal server dal contesto progetto |
|
|
33
|
+
| `namespace` | string | ID del namespace (validato contro `Namespace`) |
|
|
34
|
+
| `question` | string | Obbligatorio |
|
|
35
|
+
| `answer` | string | Obbligatorio |
|
|
36
|
+
| `tokens` | number | Opzionale |
|
|
37
|
+
| `request_id` | string | Opzionale |
|
|
38
|
+
| `created_at` / `updated_at` | date | Da `timestamps: true` |
|
|
39
|
+
|
|
40
|
+
Indici rilevanti: TTL su `created_at`, indice composto `(id_project, namespace, created_at)`, indice **testo** su `question` e `answer` (pesi question 5, answer 1) per la ricerca full-text.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Endpoint
|
|
45
|
+
|
|
46
|
+
Tutti i path qui sotto sono relativi a `/:projectid/kb/answered`.
|
|
47
|
+
|
|
48
|
+
### `POST /`
|
|
49
|
+
|
|
50
|
+
Aggiunge una nuova domanda risposta.
|
|
51
|
+
|
|
52
|
+
**Body JSON**
|
|
53
|
+
|
|
54
|
+
| Campo | Obbligatorio | Descrizione |
|
|
55
|
+
|-------------|--------------|--------------------|
|
|
56
|
+
| `namespace` | sì | ID namespace |
|
|
57
|
+
| `question` | sì | Testo domanda |
|
|
58
|
+
| `answer` | sì | Testo risposta |
|
|
59
|
+
| `tokens` | no | Numero opzionale |
|
|
60
|
+
| `request_id`| no | Riferimento richiesta |
|
|
61
|
+
|
|
62
|
+
**Risposte**
|
|
63
|
+
|
|
64
|
+
| HTTP | Significato |
|
|
65
|
+
|------|-------------|
|
|
66
|
+
| 200 | Documento salvato (corpo = documento MongoDB creato) |
|
|
67
|
+
| 400 | Parametri mancanti (`namespace`, `question`, `answer`) |
|
|
68
|
+
| 403 | Namespace non appartenente al progetto |
|
|
69
|
+
| 500 | Errore server |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
### `GET /:namespace`
|
|
74
|
+
|
|
75
|
+
Elenco paginato delle domande risposte per il namespace.
|
|
76
|
+
|
|
77
|
+
**Query**
|
|
78
|
+
|
|
79
|
+
| Parametro | Default | Descrizione |
|
|
80
|
+
|--------------|---------|-------------|
|
|
81
|
+
| `page` | `0` | Pagina (0-based) |
|
|
82
|
+
| `limit` | `20` | Elementi per pagina |
|
|
83
|
+
| `sortField` | `created_at` | Campo ordinamento |
|
|
84
|
+
| `direction` | `-1` | `1` crescente, `-1` decrescente |
|
|
85
|
+
| `search` | — | Se presente, attiva ricerca **full-text** (`$text`); l’ordinamento usa lo score di testo |
|
|
86
|
+
|
|
87
|
+
**Risposta 200**
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"count": 0,
|
|
92
|
+
"questions": [],
|
|
93
|
+
"query": {
|
|
94
|
+
"page": 0,
|
|
95
|
+
"limit": 20,
|
|
96
|
+
"sortField": "created_at",
|
|
97
|
+
"direction": -1,
|
|
98
|
+
"search": "..."
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Altri codici:** `400` (namespace mancante), `403` (namespace non valido per il progetto), `500`.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### `DELETE /:id`
|
|
108
|
+
|
|
109
|
+
Elimina una singola domanda per `_id` MongoDB.
|
|
110
|
+
|
|
111
|
+
**Risposte:** `200` con `{ success, message }`, `404` se non trovata (o non del progetto), `500`.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
### `DELETE /namespace/:namespace`
|
|
116
|
+
|
|
117
|
+
Elimina **tutte** le domande risposte per `namespace` nel progetto corrente.
|
|
118
|
+
|
|
119
|
+
**Risposta 200:** `{ success, count: <deletedCount>, message }`.
|
|
120
|
+
|
|
121
|
+
**403** se il namespace non appartiene al progetto. **500** in errore.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
### `GET /count/:namespace`
|
|
126
|
+
|
|
127
|
+
Restituisce il conteggio documenti per `id_project` + `namespace`.
|
|
128
|
+
|
|
129
|
+
**Risposta 200:** `{ count: <number> }`.
|
|
130
|
+
|
|
131
|
+
**400** / **403** / **500** come negli altri endpoint con validazione namespace.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Funzione interna `validateNamespace(id_project, namespace_id)`
|
|
136
|
+
|
|
137
|
+
Verifica che esista un documento `Namespace` con `id_project` e `id: namespace_id`. Usata in creazione, lettura elenco, cancellazione bulk e conteggio.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Nota sull’ordine delle route Express
|
|
142
|
+
|
|
143
|
+
Nel file è definito `GET /:namespace` **prima** di `GET /count/:namespace`. In Express la prima route che corrisponde vince: una richiesta del tipo `GET .../kb/answered/count/<namespace>` può essere interpretata come `GET /:namespace` con `namespace` uguale alla stringa letterale `count`, invece che come endpoint di conteggio.
|
|
144
|
+
|
|
145
|
+
Per far funzionare l’URL `GET /count/:namespace` come previsto dal codice, in genere occorre registrare **`GET /count/:namespace` prima di `GET /:namespace`**, oppure usare un prefisso path diverso per uno dei due. Verificare il comportamento in ambiente reale o adeguare l’ordine delle route se il conteggio non risponde come atteso.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Riferimenti
|
|
150
|
+
|
|
151
|
+
- Router: [`routes/answered.js`](../routes/answered.js)
|
|
152
|
+
- Modello e indici: [`models/kb_setting.js`](../models/kb_setting.js) (`AnsweredQuestionSchema`)
|
|
153
|
+
- Montaggio app: [`app.js`](../app.js) (`/:projectid/kb/answered`)
|
package/event/authEvent.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const EventEmitter = require('events');
|
|
2
|
+
var RoleConstants = require("../models/roleConstants");
|
|
2
3
|
|
|
3
4
|
class AuthEvent extends EventEmitter {
|
|
4
5
|
constructor() {
|
|
@@ -9,6 +10,21 @@ class AuthEvent extends EventEmitter {
|
|
|
9
10
|
|
|
10
11
|
const authEvent = new AuthEvent();
|
|
11
12
|
|
|
13
|
+
var projectuserUpdateKey = 'project_user.update';
|
|
14
|
+
if (process.env.QUEUE_ENABLED === "true") {
|
|
15
|
+
projectuserUpdateKey = 'project_user.update.queue';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
authEvent.on(projectuserUpdateKey, function(event) {
|
|
19
|
+
if (event.updatedProject_userPopulated) {
|
|
20
|
+
var pu = event.updatedProject_userPopulated;
|
|
21
|
+
if (pu.roleType === RoleConstants.TYPE_AGENTS) {
|
|
22
|
+
authEvent.emit("project_user.update.agent", event);
|
|
23
|
+
} else {
|
|
24
|
+
authEvent.emit("project_user.update.user", event);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
12
28
|
|
|
13
29
|
//listen for sigin and signup event
|
|
14
30
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const EventEmitter = require('events');
|
|
2
|
+
const winston = require('../config/winston');
|
|
3
|
+
const Group = require("../models/group");
|
|
4
|
+
|
|
5
|
+
class ProjectUserEvent extends EventEmitter {
|
|
6
|
+
constructor() {
|
|
7
|
+
super();
|
|
8
|
+
this.registerListeners();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
registerListeners() {
|
|
12
|
+
|
|
13
|
+
this.on('project_user.deleted', async (pu) => {
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
winston.debug('[project_user.deleted] Event catched:', pu);
|
|
17
|
+
|
|
18
|
+
const id_project = pu.id_project;
|
|
19
|
+
let id_user = pu.id_user.toString();
|
|
20
|
+
if (typeof id_user === 'object' && id_user._id) {
|
|
21
|
+
id_user = id_user._id.toString();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const result = await Group.updateMany({ id_project: id_project }, { $pull: { members: id_user }});
|
|
25
|
+
winston.verbose(`Event project_user.deleted: User ${id_user} removed from ${result?.nModified} groups.`)
|
|
26
|
+
|
|
27
|
+
} catch (err) {
|
|
28
|
+
winston.verbose(`Event project_user.deleted: Error removing user ${id_user} from groups: `, err);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Istanza singleton
|
|
37
|
+
const puEvent = new ProjectUserEvent();
|
|
38
|
+
|
|
39
|
+
module.exports = puEvent;
|
package/middleware/has-role.js
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
var Project_user = require("../models/project_user");
|
|
2
1
|
var Faq_kb = require("../models/faq_kb");
|
|
3
2
|
var Subscription = require("../models/subscription");
|
|
4
3
|
var winston = require('../config/winston');
|
|
5
4
|
|
|
6
|
-
var
|
|
7
|
-
var cacheEnabler = require("../services/cacheEnabler");
|
|
8
|
-
|
|
5
|
+
var projectUserService = require("../services/projectUserService");
|
|
9
6
|
class RoleChecker {
|
|
10
7
|
|
|
11
8
|
|
|
12
9
|
|
|
13
10
|
constructor() {
|
|
11
|
+
winston.debug("RoleChecker");
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
this.ROLES = {
|
|
16
14
|
"guest": ["guest"],
|
|
17
15
|
"user": ["guest","user"],
|
|
18
16
|
"teammate": ["guest","user","teammate"],
|
|
@@ -20,7 +18,7 @@ class RoleChecker {
|
|
|
20
18
|
"supervisor": ["guest","user","teammate","agent","supervisor"],
|
|
21
19
|
"admin": ["guest","user","teammate","agent", "supervisor", "admin"],
|
|
22
20
|
"owner": ["guest","user","teammate","agent", "supervisor", "admin", "owner"],
|
|
23
|
-
|
|
21
|
+
}
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
isType(type) {
|
|
@@ -87,18 +85,90 @@ class RoleChecker {
|
|
|
87
85
|
}
|
|
88
86
|
|
|
89
87
|
|
|
88
|
+
hasPermission(permission) {
|
|
89
|
+
var that = this;
|
|
90
|
+
return async(req, res, next) => {
|
|
91
|
+
if (!req.params.projectid && !req.projectid) {
|
|
92
|
+
return res.status(400).send({success: false, msg: 'req.params.projectid is not defined.'});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let projectid = req.params.projectid || req.projectid;
|
|
96
|
+
|
|
97
|
+
var project_user = req.projectuser;
|
|
98
|
+
winston.debug("hasPermission project_user hasPermission", project_user);
|
|
99
|
+
|
|
100
|
+
if (!project_user) {
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
project_user = await projectUserService.getWithPermissions(req.user._id, projectid, req.user.sub);
|
|
104
|
+
} catch(err) {
|
|
105
|
+
winston.error("Error getting project_user for hasrole",err);
|
|
106
|
+
return next(err);
|
|
107
|
+
}
|
|
108
|
+
winston.debug("project_user: ", JSON.stringify(project_user));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (project_user) {
|
|
112
|
+
|
|
113
|
+
req.projectuser = project_user;
|
|
114
|
+
winston.debug("hasPermission req.projectuser", req.projectuser);
|
|
115
|
+
|
|
116
|
+
var permissions = project_user._doc.rolePermissions;
|
|
117
|
+
|
|
118
|
+
winston.debug("hasPermission permissions", permissions);
|
|
119
|
+
|
|
120
|
+
winston.debug("hasPermission permission: "+ permission);
|
|
121
|
+
|
|
122
|
+
if (permission==undefined) {
|
|
123
|
+
winston.debug("permission is empty go next");
|
|
124
|
+
return next();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (permissions!=undefined && permissions.length>0) {
|
|
128
|
+
if (permissions.includes(permission)) {
|
|
129
|
+
next();
|
|
130
|
+
}else {
|
|
131
|
+
res.status(403).send({success: false, msg: 'you dont have the required permission.'});
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
res.status(403).send({success: false, msg: 'you dont have the required permission. Is is empty'});
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Updated by Johnny - 29mar2024 - START
|
|
140
|
+
*/
|
|
141
|
+
// console.log("req.user: ", req.user);
|
|
142
|
+
if (req.user.email === process.env.ADMIN_EMAIL) {
|
|
143
|
+
req.user.attributes = { isSuperadmin: true };
|
|
144
|
+
next();
|
|
145
|
+
} else {
|
|
146
|
+
res.status(403).send({success: false, msg: 'you dont belong to the project.'});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Updated by Johnny - 29mar2024 - END
|
|
150
|
+
*/
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
}
|
|
90
159
|
|
|
91
160
|
|
|
92
161
|
hasRole(role) {
|
|
93
162
|
return this.hasRoleOrTypes(role);
|
|
94
163
|
}
|
|
95
164
|
|
|
96
|
-
hasRoleOrTypes(role, types) {
|
|
97
|
-
|
|
165
|
+
hasRoleOrTypes(role, types, permission) {
|
|
166
|
+
// console.log("hasRoleOrTypes",role,types);
|
|
167
|
+
|
|
98
168
|
var that = this;
|
|
99
169
|
|
|
100
170
|
// winston.debug("HasRole");
|
|
101
|
-
return
|
|
171
|
+
return async(req, res, next) => {
|
|
102
172
|
|
|
103
173
|
// winston.debug("req.originalUrl" + req.originalUrl);
|
|
104
174
|
// winston.debug("req.params" + JSON.stringify(req.params));
|
|
@@ -111,7 +181,7 @@ class RoleChecker {
|
|
|
111
181
|
|
|
112
182
|
let projectid = req.params.projectid || req.projectid;
|
|
113
183
|
|
|
114
|
-
|
|
184
|
+
// winston.info("req.user._id: " + req.user._id);
|
|
115
185
|
|
|
116
186
|
// winston.info("req.projectuser: " + req.projectuser);
|
|
117
187
|
//winston.debug("req.user", req.user);
|
|
@@ -135,138 +205,107 @@ class RoleChecker {
|
|
|
135
205
|
// res.status(403).send({success: false, msg: 'req.user._id not defined.'});
|
|
136
206
|
// }
|
|
137
207
|
winston.debug("hasRoleOrType req.user._id " +req.user._id);
|
|
138
|
-
// project_user_qui_importante
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
208
|
+
// project_user_qui_importante
|
|
209
|
+
|
|
210
|
+
var project_user = req.projectuser;
|
|
211
|
+
winston.debug("hasRoleOrTypes project_user hasRoleOrTypes", project_user);
|
|
212
|
+
|
|
213
|
+
if (!project_user) {
|
|
214
|
+
winston.debug("load project_user");
|
|
215
|
+
try {
|
|
216
|
+
project_user = await projectUserService.getWithPermissions(req.user._id, projectid, req.user.sub);
|
|
217
|
+
} catch(err) {
|
|
218
|
+
winston.error("Error getting project_user for hasrole",err);
|
|
219
|
+
return next(err);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
winston.debug("project_user: ", JSON.stringify(project_user));
|
|
223
|
+
|
|
147
224
|
}
|
|
148
|
-
winston.debug("hasRoleOrType query " + JSON.stringify(query));
|
|
149
225
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
winston.debug("
|
|
226
|
+
if (project_user) {
|
|
227
|
+
|
|
228
|
+
req.projectuser = project_user;
|
|
229
|
+
winston.debug("hasRoleOrTypes req.projectuser", req.projectuser.toJSON());
|
|
154
230
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (err) {
|
|
158
|
-
winston.error("Error on Request path: " + req.originalUrl);
|
|
159
|
-
winston.error("Error getting project_user for hasrole",err);
|
|
160
|
-
return next(err);
|
|
161
|
-
}
|
|
162
|
-
winston.debug("project_user: ", JSON.stringify(project_user));
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (project_user) {
|
|
167
|
-
|
|
168
|
-
req.projectuser = project_user;
|
|
169
|
-
winston.debug("req.projectuser", req.projectuser);
|
|
231
|
+
var userRole = project_user.role;
|
|
232
|
+
winston.debug("userRole", userRole);
|
|
170
233
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
next();
|
|
183
|
-
}else {
|
|
184
|
-
res.status(403).send({success: false, msg: 'you dont have the required role.'});
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
} else {
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Updated by Johnny - 29mar2024 - START
|
|
191
|
-
*/
|
|
192
|
-
// console.log("req.user: ", req.user);
|
|
193
|
-
if (req.user.email === process.env.ADMIN_EMAIL) {
|
|
194
|
-
req.user.attributes = { isSuperadmin: true };
|
|
234
|
+
|
|
235
|
+
if (!role) { //????
|
|
236
|
+
next();
|
|
237
|
+
}else {
|
|
238
|
+
|
|
239
|
+
var hierarchicalRoles = that.ROLES[userRole];
|
|
240
|
+
winston.debug("hierarchicalRoles", hierarchicalRoles);
|
|
241
|
+
|
|
242
|
+
if ( hierarchicalRoles ) { //standard role
|
|
243
|
+
winston.debug("standard role: "+ userRole);
|
|
244
|
+
if (hierarchicalRoles.includes(role)) {
|
|
195
245
|
next();
|
|
196
246
|
} else {
|
|
197
|
-
res.status(403).send({success: false, msg: 'you dont
|
|
247
|
+
res.status(403).send({success: false, msg: 'you dont have the required role.'});
|
|
198
248
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
249
|
+
} else { //custom role
|
|
250
|
+
|
|
251
|
+
winston.debug("custom role: "+ userRole);
|
|
252
|
+
return that.hasPermission(permission)(req, res, next);
|
|
202
253
|
|
|
203
|
-
// if (
|
|
204
|
-
//
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
}
|
|
254
|
+
// if (permission==undefined) {
|
|
255
|
+
// winston.debug("permission is empty go next");
|
|
256
|
+
// return next();
|
|
257
|
+
// }
|
|
212
258
|
|
|
213
|
-
//
|
|
214
|
-
|
|
259
|
+
// // invece di questo codice richiama hasPermission()
|
|
260
|
+
// var permissions = project_user._doc.rolePermissions;
|
|
215
261
|
|
|
216
|
-
|
|
262
|
+
// winston.debug("hasPermission permissions", permissions);
|
|
263
|
+
|
|
264
|
+
// winston.debug("hasPermission permission: "+ permission);
|
|
217
265
|
|
|
218
|
-
|
|
219
|
-
|
|
266
|
+
// if (permissions!=undefined && permissions.length>0) {
|
|
267
|
+
// if (permissions.includes(permission)) {
|
|
268
|
+
// next();
|
|
269
|
+
// }else {
|
|
270
|
+
// res.status(403).send({success: false, msg: 'you dont have the required permission.'});
|
|
271
|
+
// }
|
|
272
|
+
// } else {
|
|
273
|
+
// res.status(403).send({success: false, msg: 'you dont have the required permission. Is is empty'});
|
|
274
|
+
// }
|
|
220
275
|
|
|
221
|
-
// JWT_HERE
|
|
222
|
-
var query = { id_project: req.params.projectid, id_user: req.user._id, status: "active"};
|
|
223
|
-
if (req.user.sub && (req.user.sub=="userexternal" || req.user.sub=="guest")) {
|
|
224
|
-
query = { id_project: req.params.projectid, uuid_user: req.user._id};
|
|
225
|
-
}
|
|
226
276
|
|
|
227
|
-
Project_user.find(query).
|
|
228
|
-
exec(function (err, project_users) {
|
|
229
|
-
if (err) {
|
|
230
|
-
winston.error(err);
|
|
231
|
-
return reject(err);
|
|
232
277
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (project_users && project_users.length>0) {
|
|
236
278
|
|
|
237
|
-
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
} else {
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Updated by Johnny - 29mar2024 - START
|
|
285
|
+
*/
|
|
286
|
+
// console.log("req.user: ", req.user);
|
|
287
|
+
if (req.user.email === process.env.ADMIN_EMAIL) {
|
|
288
|
+
req.user.attributes = { isSuperadmin: true };
|
|
289
|
+
next();
|
|
290
|
+
} else {
|
|
291
|
+
res.status(403).send({success: false, msg: 'you dont belong to the project.'});
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Updated by Johnny - 29mar2024 - END
|
|
295
|
+
*/
|
|
238
296
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
if (!role) {
|
|
243
|
-
resolve(project_user);
|
|
244
|
-
}else {
|
|
245
|
-
|
|
246
|
-
var hierarchicalRoles = that.ROLES[userRole];
|
|
247
|
-
// winston.debug("hierarchicalRoles", hierarchicalRoles);
|
|
248
|
-
|
|
249
|
-
if ( hierarchicalRoles.includes(role)) {
|
|
250
|
-
resolve(project_user);
|
|
251
|
-
}else {
|
|
252
|
-
reject({success: false, msg: 'you dont have the required role.'});
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
} else {
|
|
256
|
-
|
|
257
|
-
// if (req.user) equals super admin next()
|
|
258
|
-
reject({success: false, msg: 'you dont belong to the project.'});
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
});
|
|
297
|
+
// if (req.user) equals super admin next()
|
|
298
|
+
//res.status(403).send({success: false, msg: 'you dont belong to the project.'});
|
|
299
|
+
}
|
|
262
300
|
|
|
263
|
-
});
|
|
264
301
|
|
|
265
|
-
|
|
266
|
-
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
267
305
|
}
|
|
268
306
|
|
|
269
307
|
|
|
308
|
+
|
|
270
309
|
var roleChecker = new RoleChecker();
|
|
271
310
|
module.exports = roleChecker;
|
|
272
311
|
|