xref: /plugin/bez/mdl/Acl.php (revision 53df74e7ac5ae4234aac1fa716a33878a039026f)
1<?php
2
3//if(!defined('DOKU_INC')) die('meh.');
4//
5//include_once DOKU_PLUGIN."bez/models/tokens.php";
6
7namespace dokuwiki\plugin\bez\mdl;
8
9//ACL level defines
10use dokuwiki\plugin\bez\meta\PermissionDeniedException;
11
12define('BEZ_AUTH_NONE', 0);
13define('BEZ_AUTH_VIEWER', 2);
14define('BEZ_AUTH_USER', 5);
15define('BEZ_AUTH_LEADER', 10);
16define('BEZ_AUTH_ADMIN', 20);
17
18define('BEZ_PERMISSION_UNKNOWN', -1);
19define('BEZ_PERMISSION_NONE', 0);
20define('BEZ_PERMISSION_VIEW', 1);
21define('BEZ_PERMISSION_CHANGE', 2);
22define('BEZ_PERMISSION_DELETE', 3);
23
24class Acl {
25    /** @var  Model */
26    private $model;
27
28    private $level = BEZ_AUTH_NONE;
29
30    private function update_level($level) {
31		if ($level > $this->level) {
32			$this->level = $level;
33		}
34	}
35
36    public function get_level() {
37        return $this->level;
38    }
39
40    public function __construct(Model $model) {
41        $this->model = $model;
42
43		$userd = $this->model->dw_auth->getUserData($this->model->user_nick);
44		if ($userd !== false && is_array($userd['grps'])) {
45			$grps = $userd['grps'];
46			if (in_array('admin', $grps ) || in_array('bez_admin', $grps )) {
47				$this->update_level(BEZ_AUTH_ADMIN);
48            } elseif (in_array('bez_leader', $grps )) {
49                $this->update_level(BEZ_AUTH_LEADER);
50			} else {
51				$this->update_level(BEZ_AUTH_USER);
52			}
53        } elseif (isset($_GET['t'])) {
54            $page_id = $this->model->action->id();
55
56            $user_tok = trim($_GET['t']);
57            if ($this->model->authentication_tokenFactory->get_token($page_id) == $user_tok) {
58                $this->update_level(BEZ_AUTH_VIEWER);
59            }
60        }
61    }
62
63    private function static_thread() {
64        $acl = array_fill_keys(Thread::get_columns(), BEZ_PERMISSION_NONE);
65
66        $acl['label_id'] = BEZ_PERMISSION_NONE;
67        $acl['participants'] = BEZ_PERMISSION_NONE;
68
69        //BEZ_AUTH_VIEWER is also token viewer
70        if ($this->level >= BEZ_AUTH_VIEWER) {
71            //user can display everything
72            $acl = array_map(function($value) {
73                return BEZ_PERMISSION_VIEW;
74            }, $acl);
75        }
76
77        if ($this->level >= BEZ_AUTH_USER) {
78            $acl['id'] = BEZ_PERMISSION_CHANGE;
79        }
80
81        if ($this->level >= BEZ_AUTH_LEADER) {
82            $acl['title'] = BEZ_PERMISSION_CHANGE;
83            $acl['content'] = BEZ_PERMISSION_CHANGE;
84            $acl['coordinator'] = BEZ_PERMISSION_CHANGE;
85            $acl['label_id'] = BEZ_PERMISSION_CHANGE;
86            $acl['private'] = BEZ_PERMISSION_CHANGE;
87        }
88
89        if ($this->level >= BEZ_AUTH_ADMIN) {
90            //user can edit everythig
91            $acl = array_map(function($value) {
92                return BEZ_PERMISSION_DELETE;
93            }, $acl);
94        }
95
96        return $acl;
97    }
98
99
100    private function check_thread(Thread $thread) {
101        $acl = $this->static_thread();
102
103        //we create new issue
104        if ($thread->id === NULL) {
105            if ($this->level >= BEZ_AUTH_USER) {
106                $acl['title'] = BEZ_PERMISSION_CHANGE;
107                $acl['content'] = BEZ_PERMISSION_CHANGE;
108                $acl['type'] = BEZ_PERMISSION_CHANGE;
109            }
110
111            if ($this->level >= BEZ_AUTH_LEADER) {
112                $acl['coordinator'] = BEZ_PERMISSION_CHANGE;
113                $acl['label_id'] = BEZ_PERMISSION_CHANGE;
114            }
115
116            return $acl;
117        }
118
119        //private threads
120        if ($this->level < BEZ_AUTH_ADMIN && $thread->private == '1') {
121            if ($thread->get_participant($this->model->user_nick) === false) {
122                return array_fill_keys(Thread::get_columns(), BEZ_PERMISSION_NONE);
123            }
124        }
125
126        if ($this->level <= BEZ_AUTH_LEADER) {
127            $acl['title']       = BEZ_PERMISSION_VIEW;
128            $acl['content']     = BEZ_PERMISSION_VIEW;
129            $acl['coordinator'] = BEZ_PERMISSION_VIEW;
130            $acl['label_id']    = BEZ_PERMISSION_VIEW;
131            $acl['private']     = BEZ_PERMISSION_VIEW;
132        }
133
134
135        if ($thread->state == 'proposal' &&
136            $thread->original_poster == $this->model->user_nick) {
137            $acl['title'] = BEZ_PERMISSION_CHANGE;
138            $acl['content'] = BEZ_PERMISSION_CHANGE;
139        }
140
141        //leader can change coordinator
142        if ($thread->state == 'proposal' &&
143            $this->level >= BEZ_AUTH_LEADER) {
144
145            $acl['title'] = BEZ_PERMISSION_CHANGE;
146            $acl['content'] = BEZ_PERMISSION_CHANGE;
147
148            //coordinator can change coordinator
149            $acl['coordinator'] = BEZ_PERMISSION_CHANGE;
150        }
151
152        if ($thread->coordinator == $this->model->user_nick) {
153            $acl['title'] = BEZ_PERMISSION_CHANGE;
154            $acl['content'] = BEZ_PERMISSION_CHANGE;
155
156            //coordinator can change coordinator
157            $acl['coordinator'] = BEZ_PERMISSION_CHANGE;
158
159            $acl['state'] = BEZ_PERMISSION_CHANGE;
160
161            $acl['label_id'] = BEZ_PERMISSION_CHANGE;
162
163            $acl['private']     = BEZ_PERMISSION_CHANGE;
164        }
165
166        return $acl;
167    }
168
169    private function static_task() {
170        $acl = array_fill_keys(Task::get_columns(), BEZ_PERMISSION_NONE);
171
172        //BEZ_AUTH_VIEWER is also token viewer
173        if ($this->level >= BEZ_AUTH_VIEWER) {
174            //user can display everythig
175            $acl = array_map(function($value) {
176                return BEZ_PERMISSION_VIEW;
177            }, $acl);
178        }
179
180        //user can add tasks
181        if ($this->level >= BEZ_AUTH_USER) {
182            $acl['id'] = BEZ_PERMISSION_CHANGE;
183        }
184
185        if ($this->level >= BEZ_AUTH_ADMIN) {
186            //user can edit everythig
187            $acl = array_map(function($value) {
188                return BEZ_PERMISSION_DELETE;
189            }, $acl);
190        }
191
192        return $acl;
193    }
194
195    //if user can chante id => he can delete record
196    private function check_task($task) {
197        $acl = $this->static_task();
198
199        //we create new task
200        if ($task->id === NULL) {
201
202            if ($task->coordinator == $this->model->user_nick ||
203               ($task->thread_id == '' && $this->level >= BEZ_AUTH_LEADER)) {
204                $acl['content'] = BEZ_PERMISSION_CHANGE;
205                $acl['task_program_id'] = BEZ_PERMISSION_CHANGE;
206                $acl['assignee'] = BEZ_PERMISSION_CHANGE;
207                $acl['cost'] = BEZ_PERMISSION_CHANGE;
208                $acl['plan_date'] = BEZ_PERMISSION_CHANGE;
209                $acl['all_day_event'] = BEZ_PERMISSION_CHANGE;
210                $acl['start_time'] = BEZ_PERMISSION_CHANGE;
211                $acl['finish_time'] = BEZ_PERMISSION_CHANGE;
212            }
213
214            //no assignee
215            if ($task->thread_id == '') {
216                $acl['content'] = BEZ_PERMISSION_CHANGE;
217                $acl['task_program_id'] = BEZ_PERMISSION_CHANGE;
218                $acl['cost'] = BEZ_PERMISSION_CHANGE;
219                $acl['plan_date'] = BEZ_PERMISSION_CHANGE;
220                $acl['all_day_event'] = BEZ_PERMISSION_CHANGE;
221                $acl['start_time'] = BEZ_PERMISSION_CHANGE;
222                $acl['finish_time'] = BEZ_PERMISSION_CHANGE;
223            }
224
225            return $acl;
226        }
227
228
229        if ($task->coordinator == $this->model->user_nick ||
230            ($task->thread_id == '' && $this->level >= BEZ_AUTH_LEADER)) {
231
232            //we can change cause
233            $acl['thread_comment_id'] =  BEZ_PERMISSION_CHANGE;
234
235            $acl['state'] = BEZ_PERMISSION_CHANGE;
236
237            $acl['content'] = BEZ_PERMISSION_CHANGE;
238            $acl['task_program_id'] = BEZ_PERMISSION_CHANGE;
239            $acl['assignee'] = BEZ_PERMISSION_CHANGE;
240            $acl['cost'] = BEZ_PERMISSION_CHANGE;
241
242            $acl['plan_date'] = BEZ_PERMISSION_CHANGE;
243            $acl['all_day_event'] = BEZ_PERMISSION_CHANGE;
244            $acl['start_time'] = BEZ_PERMISSION_CHANGE;
245            $acl['finish_time'] = BEZ_PERMISSION_CHANGE;
246        }
247
248        if ($task->thread_id == '' &&
249            $task->original_poster == $this->model->user_nick &&
250            $task->assignee == $this->model->user_nick) {
251
252
253            $acl['content'] = BEZ_PERMISSION_CHANGE;
254            $acl['task_program_id'] = BEZ_PERMISSION_CHANGE;
255            //no executor
256            $acl['cost'] = BEZ_PERMISSION_CHANGE;
257            $acl['plan_date'] = BEZ_PERMISSION_CHANGE;
258            $acl['all_day_event'] = BEZ_PERMISSION_CHANGE;
259            $acl['start_time'] = BEZ_PERMISSION_CHANGE;
260            $acl['finish_time'] = BEZ_PERMISSION_CHANGE;
261        }
262
263        //user can solve his tasks
264        if ($task->assignee  == $this->model->user_nick) {
265            $acl['state'] = BEZ_PERMISSION_CHANGE;
266        }
267
268        return $acl;
269
270    }
271
272    private function static_thread_comment() {
273        $acl = array_fill_keys(Thread_comment::get_columns(), BEZ_PERMISSION_NONE);
274
275        //virtual columns
276
277        //BEZ_AUTH_VIEWER is also token viewer
278        if ($this->level >= BEZ_AUTH_VIEWER) {
279            //user can display everythig
280            $acl = array_map(function($value) {
281                return BEZ_PERMISSION_VIEW;
282            }, $acl);
283        }
284
285        if ($this->level >= BEZ_AUTH_ADMIN) {
286            //user can edit everythig
287            $acl = array_map(function($value) {
288                return BEZ_PERMISSION_DELETE;
289            }, $acl);
290        }
291
292        return $acl;
293    }
294
295    private function check_thread_comment(Thread_comment $thread_comment) {
296        $acl = $this->static_thread_comment();
297
298        //we create new commcause
299        if ($thread_comment->id === NULL) {
300            if ($this->level >= BEZ_AUTH_USER) {
301                $acl['content'] = BEZ_PERMISSION_CHANGE;
302            }
303
304            if ($thread_comment->coordinator === $this->model->user_nick) {
305                $acl['type'] = BEZ_PERMISSION_CHANGE;
306                $acl['content'] = BEZ_PERMISSION_CHANGE;
307            }
308
309            return $acl;
310        }
311
312
313        if ($thread_comment->coordinator === $this->model->user_nick) {
314            $acl['type'] = BEZ_PERMISSION_CHANGE;
315            $acl['content'] = BEZ_PERMISSION_CHANGE;
316
317            //we can only delete records when there is no tasks subscribed to issue
318            if ($thread_comment->task_count === 0) {
319                 $acl['id'] = BEZ_PERMISSION_CHANGE;
320            }
321
322        }
323
324        //jeżeli ktoś zmieni typ z komentarza na przyczynę, tracimy możliwość edycji
325        if ($thread_comment->author === $this->model->user_nick &&
326            $thread_comment->type == '0') {
327            $acl['content'] = BEZ_PERMISSION_CHANGE;
328
329            //we can only delete records when there is no tasks subscribed to issue
330            if ($thread_comment->task_count === 0) {
331                 $acl['id'] = BEZ_PERMISSION_CHANGE;
332            }
333        }
334
335        return $acl;
336
337    }
338
339    private function static_label() {
340        $acl = array_fill_keys(Label::get_columns(), BEZ_PERMISSION_NONE);
341
342        if ($this->level >= BEZ_AUTH_USER) {
343            //user can display everythig
344            $acl = array_map(function($value) {
345                return BEZ_PERMISSION_VIEW;
346            }, $acl);
347        }
348
349        if ($this->level >= BEZ_AUTH_ADMIN) {
350            //admin can edit everythig
351            $acl = array_map(function($value) {
352                return BEZ_PERMISSION_DELETE;
353            }, $acl);
354        }
355
356        return $acl;
357    }
358
359    private function check_label(Label $label) {
360        return $this->static_label();
361    }
362
363    private function static_task_program() {
364        $acl = array_fill_keys(Task_program::get_columns(), BEZ_PERMISSION_NONE);
365
366        if ($this->level >= BEZ_AUTH_USER) {
367            //user can display everythig
368            $acl = array_map(function($value) {
369                return BEZ_PERMISSION_VIEW;
370            }, $acl);
371        }
372
373        if ($this->level >= BEZ_AUTH_ADMIN) {
374            //admin can edit everythig
375            $acl = array_map(function($value) {
376                return BEZ_PERMISSION_DELETE;
377            }, $acl);
378        }
379
380        return $acl;
381    }
382
383    private function check_task_program(Task_program $task_program) {
384        return $this->static_label();
385    }
386
387    private function static_task_comment() {
388        $acl = array_fill_keys(Task_comment::get_columns(), BEZ_PERMISSION_NONE);
389
390        //BEZ_AUTH_VIEWER is also token viewer
391        if ($this->level >= BEZ_AUTH_VIEWER) {
392            //user can display everythig
393            $acl = array_map(function($value) {
394                return BEZ_PERMISSION_VIEW;
395            }, $acl);
396        }
397
398        if ($this->level >= BEZ_AUTH_ADMIN) {
399            //user can edit everything
400            $acl = array_map(function($value) {
401                return BEZ_PERMISSION_DELETE;
402            }, $acl);
403        }
404
405        return $acl;
406    }
407
408    private function check_task_comment(Task_comment $task_comment) {
409        $acl = $this->static_task_comment();
410
411        //we create new comment
412        if ($task_comment->id == NULL) {
413            if ($this->level >= BEZ_AUTH_USER) {
414                $acl['content'] = BEZ_PERMISSION_CHANGE;
415            }
416
417            return $acl;
418        }
419
420
421        if ($this->level >= BEZ_AUTH_LEADER) {
422            $acl['id'] = BEZ_PERMISSION_DELETE;
423            $acl['content'] = BEZ_PERMISSION_CHANGE;
424        }
425
426
427        if ($task_comment->author === $this->model->user_nick) {
428            $acl['content'] = BEZ_PERMISSION_CHANGE;
429            $acl['id'] = BEZ_PERMISSION_DELETE;
430        }
431
432        return $acl;
433
434    }
435
436    /*returns array */
437    public function check(Entity $obj) {
438        $method = 'check_'.$obj->get_table_name();
439        if (!method_exists($this, $method)) {
440            throw new \Exception('no acl rules set for table: '.$obj->get_table_name());
441        }
442        return $this->$method($obj);
443    }
444
445    public function check_field(Entity $obj, $field) {
446        $acl = $this->check($obj);
447
448        if (isset($acl[$field])) {
449            return $acl[$field];
450        }
451        return BEZ_PERMISSION_UNKNOWN;
452    }
453
454    public function check_static($table) {
455        $method = 'static_'.$table;
456        if (!method_exists($this, $method)) {
457            throw new \Exception('no acl rules set for table: '.$table);
458        }
459        return $this->$method($table);
460    }
461
462    public function check_static_field($table, $field) {
463        $acl = $this->check_static($table);
464        return $acl[$field];
465    }
466
467
468    public function can(Entity $obj, $field, $what=BEZ_PERMISSION_CHANGE) {
469        if ($this->check_field($obj, $field) < $what) {
470            $table = $obj->get_table_name();
471            $id = $obj->id;
472            throw new PermissionDeniedException('user cannot change field "'.$field.'" in table "'.$table.', rowid: "'.$id.'"');
473        }
474    }
475}
476