Completed
Push — master ( ba97ae...9147af )
by Patrick
01:45
created

ShiftAPI::canUpdate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
class ShiftAPI extends VolunteerAPI
3
{
4
    use Processor;
5
6
    public function __construct()
7
    {
8
        parent::__construct('shifts');
9
    }
10
11
    public function setup($app)
12
    {
13
        parent::setup($app);
14
        $app->post('/Actions/CreateGroup', array($this, 'createGroup'));
15
        $app->post('/Actions/NewGroup', array($this, 'newGroup'));
16
        $app->post('/Actions/DeleteGroup', array($this, 'deleteGroup'));
17
        $app->post('/{shift}/Actions/Signup[/]', array($this, 'signup'));
18
        $app->post('/{shift}/Actions/Abandon[/]', array($this, 'abandon'));
19
        $app->post('/{shift}/Actions/Approve[/]', array($this, 'approvePending'));
20
        $app->post('/{shift}/Actions/Disapprove[/]', array($this, 'disapprovePending')); 
21
        $app->post('/{shift}/Actions/StartGroupSignup', array($this, 'startGroupSignup'));
22
        $app->post('/{shift}/Actions/GenerateGroupLink', array($this, 'generateGroupLink'));
23
        $app->post('/{shift}/Actions/EmptyShift[/]', array($this, 'emptyShift'));
24
        $app->post('/{shift}/Actions/ForceShiftEmpty[/]', array($this, 'forceEmpty'));
25
    }
26
27
    protected function canCreate($request)
28
    {
29
        //Check is handled by validateCreate...
30
        return true;
31
    }
32
33
    protected function canUpdate($request, $entity)
34
    {
35
 	if($this->isVolunteerAdmin($request))
36
        {
37
            return true;
38
        }
39
        return $this->isUserDepartmentLead($entity['departmentID'], $this->user);
40
    }
41
42
    protected function canDelete($request, $entity)
43
    {
44
        return $this->canUpdate($request, $entity);
45
    }
46
47
    protected function validateCreate(&$obj, $request)
48
    {
49
        if($this->isVolunteerAdmin($request))
50
        {
51
            return true;
52
        }
53
        if(!isset($obj['departmentID']))
54
        {
55
             return false;
56
        }
57
        return $this->isUserDepartmentLead($obj['departmentID'], $this->user);
58
    }
59
60
    protected function processEntry($entry, $request)
61
    {
62
        return $this->processShift($entry, $request);
63
    }
64
65
    protected function genUUID()
66
    {
67
        return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
68
            // 32 bits for "time_low"
69
            mt_rand(0, 0xffff), mt_rand(0, 0xffff),
70
71
            // 16 bits for "time_mid"
72
            mt_rand(0, 0xffff),
73
74
            // 16 bits for "time_hi_and_version",
75
            // four most significant bits holds version number 4
76
            mt_rand(0, 0x0fff) | 0x4000,
77
78
            // 16 bits, 8 bits for "clk_seq_hi_res",
79
            // 8 bits for "clk_seq_low",
80
            // two most significant bits holds zero and one for variant DCE1.1
81
            mt_rand(0, 0x3fff) | 0x8000,
82
83
            // 48 bits for "node"
84
            mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
85
        );
86
    }
87
88
    public function createGroup($request, $response)
89
    {
90
        $array = $request->getParsedBody();
91
        $count = count($array);
92
        $entArray = array();
93
        $uuid = $this->genUUID();
94
        $dataTable = $this->getDataTable();
95
        //User must be able to edit all shifts
96
        for($i = 0; $i < $count; $i++)
97
        {
98
            $filter = $this->getFilterForPrimaryKey($array[$i]);
99
            $entity = $dataTable->read($filter);
100
            if($entity === false || !isset($entity[0]))
101
            {
102
                return $response->withStatus(404);
103
            }
104
            $entity = $entity[0];
105
            if(!$this->canUpdate($request, $entity))
106
            {
107
                return $response->withStatus(401);
108
            }
109
            $entity['groupID'] = $uuid;
110
            array_push($entArray, $entity);
111
        }
112
        //If we got here we can update them all
113
        $myRet = true;
114
        $errors = array();
115
        for($i = 0; $i < $count; $i++)
116
        {
117
            $filter = $this->getFilterForPrimaryKey($array[$i]);
118
            $ret = $dataTable->update($filter, $entArray[$i]);
119
            if($ret === false)
120
            {
121
               $myRet = false;
122
               array_push($errors, $array[$i]);
123
            }
124
        }
125
        if($myRet)
126
        {
127
            return $response->withJson($myRet);
128
        }
129
        else
130
        {
131
            return $response->withJson(array('res'=>$myRet, 'errors'=>$errors));
132
        }
133
    }
134
135
    public function newGroup($request, $response)
136
    {
137
        if(!$this->canCreate($request))
138
        {
139
            return $response->withStatus(401);
140
        }
141
        $data = $request->getParsedBody();
142
        $shift = array();
143
        $shift['groupID'] = $this->genUUID();
144
        $shift['departmentID'] = $data['groupDepartmentID'];
145
        $shift['earlyLate'] = $data['groupEarlyLate'];
146
        $shift['enabled'] = $data['groupEnabled'];
147
        $shift['endTime'] = $data['groupEndTime'];
148
        $shift['eventID'] = $data['groupEvent'];
149
        $shift['name'] = $data['groupName'];
150
        $shift['startTime'] = $data['groupStartTime'];
151
        $dataTable = $this->getDataTable();
152
        $ret = true;
153
        foreach($data['roles'] as $role=>$count)
154
        {
155
            $count = intval($count);
156
            for($i = 0; $i < $count; $i++)
157
            {
158
                $shift['roleID'] = $role;
159
                if($dataTable->create($shift) === false)
160
                {
161
                    $ret = false;
162
                }
163
            }
164
        }
165
        return $response->withJSON($ret);
166
    }
167
168
    public function deleteGroup($request, $response)
169
    {
170
        $data = $request->getParsedBody();
171
        $dataTable = $this->getDataTable();
172
        $filter = new \Data\Filter('groupID eq '.$data['groupID']);
173
        $entities = $dataTable->read($filter);
174
        if(empty($entities))
175
        {
176
            return $response->withStatus(404);
177
        }
178
        if(!$this->canUpdate($request, $entities[0]))
179
        {
180
            return $response->withStatus(401);
181
        }
182
        $res = $dataTable->delete($filter);
183
        if($res)
184
        {
185
            return $response->withJSON($res);
186
        }
187
        return $response->withJSON($res, 500);
188
    }
189
190
    public function signup($request, $response, $args)
191
    {
192
        $this->validateLoggedIn($request);
193
        $shiftId = $args['shift'];
194
        $dataTable = $this->getDataTable();
195
        $filter = $this->getFilterForPrimaryKey($shiftId);
196
        $entity = $dataTable->read($filter);
197
        if(empty($entity))
198
        {
199
            return $response->withStatus(404);
200
        }
201
        $entity = $entity[0];
202 View Code Duplication
        if(isset($entity['participant']) && strlen($entity['participant']) > 0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
203
        {
204
            return $response->withStatus(401);
205
        }
206
        $shift = new \VolunteerShift($shiftId, $entity);
207
        $entity = $this->processShift($entity, $request);
208
        if(isset($entity['minShifts']) && $entity['minShifts'] > 0)
209
        {
210
          $shift->makeCopy($dataTable);
211
        }
212
        if(isset($entity['overlap']) && $entity['overlap'])
213
        {
214
            $overlaps = $shift->findOverlaps($this->user->uid);
215
            $count = count($overlaps);
216
            $leads = array();
217
            for($i = 0; $i < $count; $i++)
218
            {
219
                $dept = new \VolunteerDepartment($overlaps[$i]->departmentID);
220
                $leads = array_merge($leads, $dept->getLeadEmails());
221
                $overlaps[$i]->status = 'pending';
222
                $tmp = new \Data\Filter('_id eq '.$overlaps[$i]->{'_id'});
223
                $res = $dataTable->update($tmp, $overlaps[$i]);
224
                if($res === false)
225
                {
226
                    return $response->withJSON(array('err'=>'Unable to update overlap with id '.$overlaps[$i]->{'_id'}));
227
                }
228
            }
229
            $dept = new \VolunteerDepartment($entity['departmentID']);
230
            $leads = array_merge($leads, $dept->getLeadEmails());
231
            $leads = array_unique($leads);
232
            $entity['participant'] = $this->user->uid;
233
            $entity['status'] = 'pending';
234
            $profile = new \VolunteerProfile($this->user->uid);
235
            $email = new \Emails\TwoShiftsAtOnceEmail($profile);
236
            $email->addLeads($leads);
237
            $emailProvider = \EmailProvider::getInstance();
238
            if($emailProvider->sendEmail($email) === false)
239
            {
240
                throw new \Exception('Unable to send duplicate email!');
241
            }
242
            return $response->withJSON($dataTable->update($filter, $entity));
243
        }
244 View Code Duplication
        if(isset($entity['available']) && $entity['available'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
245
        {
246
            $entity['participant'] = $this->user->uid;
247
            $entity['status'] = 'filled';
248
            return $response->withJSON($dataTable->update($filter, $entity));
249
        }
250 View Code Duplication
        if(isset($entity['status']) && $entity['status'] === 'groupPending')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
251
        {
252
            $entity['participant'] = $this->user->uid;
253
            $entity['status'] = 'filled';
254
            return $response->withJSON($dataTable->update($filter, $entity));
255
        }
256
        print_r($entity); die();
257
    }
258
259
    public function abandon($request, $response, $args)
260
    {
261
        $this->validateLoggedIn($request);
262
        $shiftId = $args['shift'];
263
        $dataTable = $this->getDataTable();
264
        $filter = $this->getFilterForPrimaryKey($shiftId);
265
        $entity = $dataTable->read($filter);
266
        if(empty($entity))
267
        {
268
            return $response->withStatus(404);
269
        }
270
        $entity = $entity[0];
271
        if(!isset($entity['participant']) || $entity['participant'] !== $this->user->uid)
272
        {
273
            return $response->withStatus(401);
274
        }
275
        $entity['participant'] = '';
276
        $entity['status'] = 'unfilled';
277
        return $response->withJSON($dataTable->update($filter, $entity));
278
    }
279
280
    public function approvePending($request, $response, $args)
281
    {
282
        if(!$this->canCreate($request))
283
        {
284
            return $response->withStatus(401);
285
        }
286
        $shiftId = $args['shift'];
287
        $dataTable = $this->getDataTable();
288
        $filter = $this->getFilterForPrimaryKey($shiftId);
289
        $entity = $dataTable->read($filter);
290
        if(empty($entity))
291
        {
292
            return $response->withStatus(404);
293
        }
294
        $entity = $entity[0];
295
        $entity['status'] = 'filled';
296
        return $response->withJSON($dataTable->update($filter, $entity));
297
    }
298
299
    public function disapprovePending($request, $response, $args)
300
    {
301
        if(!$this->canCreate($request))
302
        {
303
            return $response->withStatus(401);
304
        }
305
        $shiftId = $args['shift'];
306
        $dataTable = $this->getDataTable();
307
        $filter = $this->getFilterForPrimaryKey($shiftId);
308
        $entity = $dataTable->read($filter);
309
        if(empty($entity))
310
        {
311
            return $response->withStatus(404);
312
        }
313
        $entity['participant'] = '';
314
        $entity['status'] = 'unfilled';
315
        $profile = new \VolunteerProfile($this->user->uid);
316
        $email = new \Emails\PendingRejectedEmail($profile);
317
        $email->setShift($entity);
318
        $emailProvider = \EmailProvider::getInstance();
319
        if($emailProvider->sendEmail($email) === false)
320
        {
321
            throw new \Exception('Unable to send duplicate email!');
322
        }
323
        return $response->withJSON($dataTable->update($filter, $entity));
324
    }
325
326
    public function startGroupSignup($request, $response, $args)
327
    {
328
        $this->validateLoggedIn($request);
329
        $shiftId = $args['shift'];
330
        $dataTable = $this->getDataTable();
331
        $filter = $this->getFilterForPrimaryKey($shiftId);
332
        $entity = $dataTable->read($filter);
333
        if(empty($entity))
334
        {
335
            return $response->withStatus(404);
336
        }
337
        $entity = $entity[0];
338 View Code Duplication
        if(isset($entity['participant']) && strlen($entity['participant']) > 0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
339
        {
340
            return $response->withStatus(401);
341
        }
342
        $filter = new \Data\Filter('groupID eq '.$entity['groupID'].' and enabled eq true');
343
        $entities = $dataTable->read($filter);
344
        $count = count($entities);
345
        $dept = new \VolunteerDepartment($entity['departmentID']);
346
        $res = array();
347
        $res['department'] = $dept->departmentName;
0 ignored issues
show
Bug introduced by
The property departmentName does not seem to exist in VolunteerDepartment.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
348
        $res['earlyLate'] = $entity['earlyLate'];
349
        $res['endTime'] = $entity['endTime'];
350
        $res['eventID'] = $entity['eventID'];
351
        $res['name'] = $entity['name'];
352
        $res['startTime'] = $entity['startTime'];
353
        $res['groupID'] = $entity['groupID'];
354
        $res['shifts'] = array();
355
        $roles = array();
356
        for($i = 0; $i < $count; $i++)
357
        {
358 View Code Duplication
            if(isset($entities[$i]['status']) && ($entities[$i]['status'] === 'filled' || $entities[$i]['status'] === 'pending'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
359
            {
360
                continue;
361
            }
362
            if(!isset($roles[$entities[$i]['roleID']]))
363
            {
364
                $roles[$entities[$i]['roleID']] = new \VolunteerRole($entities[$i]['roleID']);
365
            }
366
            $role = $roles[$entities[$i]['roleID']];
367
            $entities[$i]['role'] = $role->display_name;
368
            array_push($res['shifts'], $entities[$i]);
369
        }
370
        return $response->withJSON($res);
371
    }
372
373
    public function generateGroupLink($request, $response, $args)
374
    {
375
        $this->validateLoggedIn($request);
376
        $shiftId = $args['shift'];
377
        $dataTable = $this->getDataTable();
378
        $filter = $this->getFilterForPrimaryKey($shiftId);
379
        $entity = $dataTable->read($filter);
380
        if(empty($entity))
381
        {
382
            return $response->withStatus(404);
383
        }
384
        $entity = $entity[0];
385 View Code Duplication
        if(isset($entity['participant']) && strlen($entity['participant']) > 0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
386
        {
387
            return $response->withStatus(401);
388
        }
389
        $data = $request->getParsedBody();
390
        $myShift = $data['myshift'];
391
        $roles = array();
392
        foreach($data as $key => $value)
393
        {
394
            if(substr($key, 0, 6) === "roles.")
395
            {
396
                $roles[substr($key, 6)] = $value;
397
            }
398
        }
399
        $filter = new \Data\Filter('groupID eq '.$entity['groupID'].' and enabled eq true');
400
        $entities = $dataTable->read($filter);
401
        $count = count($entities);
402
        $uuid = $this->genUUID();
403
        for($i = 0; $i < $count; $i++)
404
        {
405 View Code Duplication
            if(isset($entities[$i]['status']) && ($entities[$i]['status'] === 'filled' || $entities[$i]['status'] === 'pending'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
406
            {
407
                $entities[$i] = false;
408
                continue;
409
            }
410
            if((string)$entities[$i]['_id'] === (string)new \MongoDB\BSON\ObjectId($myShift))
411
            {
412
                $entities[$i]['participant'] = $this->user->uid;
413
                $entities[$i]['status'] = 'filled';
414
                $entities[$i]['signupLink'] = $uuid;
415
            }
416
            else if(isset($roles[$entities[$i]['roleID']]))
417
            {
418
                $entities[$i]['status'] = 'groupPending';
419
                $entities[$i]['signupLink'] = $uuid;
420
                $roles[$entities[$i]['roleID']]--;
421
                if($roles[$entities[$i]['roleID']] === 0)
422
                {
423
                    unset($roles[$entities[$i]['roleID']]);
424
                }
425
            }
426
            else
427
            {
428
                $entities[$i] = false;
429
            }
430
        }
431
        if(count($roles) !== 0)
432
        {
433
            throw new \Exception('Not enough shifts to fullfill requests');
434
        }
435
        for($i = 0; $i < $count; $i++)
436
        {
437
            if($entities[$i] === false)
438
            {
439
                continue;
440
            }
441
            $filter = new \Data\Filter('_id eq '.$entities[$i]['_id']);
442
            $res = $dataTable->update($filter, $entities[$i]);
443
            if($res === false)
444
            {
445
                throw new \Exception('Not able to save shift '.$entities[$i]['_id']);
446
            }
447
        }
448
        return $response->withJSON(array('uuid' => $uuid));
449
    }
450
451
    function emptyShift($request, $response, $args)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
452
    {
453
        $this->validateLoggedIn($request);
454
        $shiftId = $args['shift'];
455
        $dataTable = $this->getDataTable();
456
        $filter = $this->getFilterForPrimaryKey($shiftId);
457
        $entity = $dataTable->read($filter);
458
        if(empty($entity))
459
        {
460
            return $response->withStatus(404);
461
        }
462
        $entity = $entity[0];
463
        if(!$this->canUpdate($request, $entity))
464
        {
465
            return $response->withStatus(401);
466
        }
467
        $shift = new \VolunteerShift(false, $entity);
468
        $entity['participant'] = '';
469
        $entity['status'] = 'unfilled';
470
        $ret = $dataTable->update($filter, $entity);
471
        if($ret)
472
        {
473
            $email = new \Emails\ShiftEmail($shift, 'shiftEmptiedSource');
474
            $emailProvider = \EmailProvider::getInstance();
475
            if($emailProvider->sendEmail($email) === false)
476
            {
477
                throw new \Exception('Unable to send email!');
478
            }
479
        }
480
        return $response->withJSON($ret);
481
    }
482
483
    function forceEmpty($request, $response, $args)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
484
    {
485
        $this->validateLoggedIn($request);
486
        $shiftId = $args['shift'];
487
        $dataTable = $this->getDataTable();
488
        $filter = $this->getFilterForPrimaryKey($shiftId);
489
        $entity = $dataTable->read($filter);
490
        if(empty($entity))
491
        {
492
            return $response->withStatus(404);
493
        }
494
        $entity = $entity[0];
495
        if(!$this->canUpdate($request, $entity))
496
        {
497
            return $response->withStatus(401);
498
        }
499
        $entity['participant'] = '';
500
        $entity['status'] = 'unfilled';
501
        return $response->withJSON($dataTable->update($filter, $entity));
502
    }
503
}
504