Completed
Push — master ( c09f30...aef5a7 )
by Patrick
01:39
created

ShiftAPI::validateCreate()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 0
loc 12
rs 9.8666
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/ForceShiftEmpty[/]', array($this, 'forceEmpty'));
24
    }
25
26
    protected function canCreate($request)
27
    {
28
        //Check is handled by validateCreate...
29
        return true;
30
    }
31
32
    protected function canUpdate($request, $entity)
33
    {
34
 	if($this->isVolunteerAdmin($request))
35
        {
36
            return true;
37
        }
38
        return $this->isUserDepartmentLead($entity['departmentID'], $this->user);
39
    }
40
41
    protected function canDelete($request, $entity)
42
    {
43
        return $this->canUpdate($request, $entity);
44
    }
45
46
    protected function validateCreate(&$obj, $request)
47
    {
48
        if($this->isVolunteerAdmin($request))
49
        {
50
            return true;
51
        }
52
        if(!isset($obj['departmentID']))
53
        {
54
             return false;
55
        }
56
        return $this->isUserDepartmentLead($obj['departmentID'], $this->user);
57
    }
58
59
    protected function processEntry($entry, $request)
60
    {
61
        return $this->processShift($entry, $request);
62
    }
63
64
    protected function genUUID()
65
    {
66
        return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
67
            // 32 bits for "time_low"
68
            mt_rand(0, 0xffff), mt_rand(0, 0xffff),
69
70
            // 16 bits for "time_mid"
71
            mt_rand(0, 0xffff),
72
73
            // 16 bits for "time_hi_and_version",
74
            // four most significant bits holds version number 4
75
            mt_rand(0, 0x0fff) | 0x4000,
76
77
            // 16 bits, 8 bits for "clk_seq_hi_res",
78
            // 8 bits for "clk_seq_low",
79
            // two most significant bits holds zero and one for variant DCE1.1
80
            mt_rand(0, 0x3fff) | 0x8000,
81
82
            // 48 bits for "node"
83
            mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
84
        );
85
    }
86
87
    public function createGroup($request, $response)
88
    {
89
        $array = $request->getParsedBody();
90
        $count = count($array);
91
        $entArray = array();
92
        $uuid = $this->genUUID();
93
        $dataTable = $this->getDataTable();
94
        //User must be able to edit all shifts
95
        for($i = 0; $i < $count; $i++)
96
        {
97
            $filter = $this->getFilterForPrimaryKey($array[$i]);
98
            $entity = $dataTable->read($filter);
99
            if($entity === false || !isset($entity[0]))
100
            {
101
                return $response->withStatus(404);
102
            }
103
            $entity = $entity[0];
104
            if(!$this->canUpdate($request, $entity))
105
            {
106
                return $response->withStatus(401);
107
            }
108
            $entity['groupID'] = $uuid;
109
            array_push($entArray, $entity);
110
        }
111
        //If we got here we can update them all
112
        $myRet = true;
113
        $errors = array();
114
        for($i = 0; $i < $count; $i++)
115
        {
116
            $filter = $this->getFilterForPrimaryKey($array[$i]);
117
            $ret = $dataTable->update($filter, $entArray[$i]);
118
            if($ret === false)
119
            {
120
               $myRet = false;
121
               array_push($errors, $array[$i]);
122
            }
123
        }
124
        if($myRet)
125
        {
126
            return $response->withJson($myRet);
127
        }
128
        else
129
        {
130
            return $response->withJson(array('res'=>$myRet, 'errors'=>$errors));
131
        }
132
    }
133
134
    public function newGroup($request, $response)
135
    {
136
        if(!$this->canCreate($request))
137
        {
138
            return $response->withStatus(401);
139
        }
140
        $data = $request->getParsedBody();
141
        $shift = array();
142
        $shift['groupID'] = $this->genUUID();
143
        $shift['departmentID'] = $data['groupDepartmentID'];
144
        $shift['earlyLate'] = $data['groupEarlyLate'];
145
        $shift['enabled'] = $data['groupEnabled'];
146
        $shift['endTime'] = $data['groupEndTime'];
147
        $shift['eventID'] = $data['groupEvent'];
148
        $shift['name'] = $data['groupName'];
149
        $shift['startTime'] = $data['groupStartTime'];
150
        $dataTable = $this->getDataTable();
151
        $ret = true;
152
        foreach($data['roles'] as $role=>$count)
153
        {
154
            $count = intval($count);
155
            for($i = 0; $i < $count; $i++)
156
            {
157
                $shift['roleID'] = $role;
158
                if($dataTable->create($shift) === false)
159
                {
160
                    $ret = false;
161
                }
162
            }
163
        }
164
        return $response->withJSON($ret);
165
    }
166
167
    public function deleteGroup($request, $response)
168
    {
169
        $data = $request->getParsedBody();
170
        $dataTable = $this->getDataTable();
171
        $filter = new \Data\Filter('groupID eq '.$data['groupID']);
172
        $entities = $dataTable->read($filter);
173
        if(empty($entities))
174
        {
175
            return $response->withStatus(404);
176
        }
177
        if(!$this->canUpdate($request, $entities[0]))
178
        {
179
            return $response->withStatus(401);
180
        }
181
        $res = $dataTable->delete($filter);
182
        if($res)
183
        {
184
            return $response->withJSON($res);
185
        }
186
        return $response->withJSON($res, 500);
187
    }
188
189
    public function signup($request, $response, $args)
190
    {
191
        $this->validateLoggedIn($request);
192
        $shiftId = $args['shift'];
193
        $dataTable = $this->getDataTable();
194
        $filter = $this->getFilterForPrimaryKey($shiftId);
195
        $entity = $dataTable->read($filter);
196
        if(empty($entity))
197
        {
198
            return $response->withStatus(404);
199
        }
200
        $entity = $entity[0];
201 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...
202
        {
203
            return $response->withStatus(401);
204
        }
205
        $shift = new \VolunteerShift($shiftId, $entity);
206
        $entity = $this->processShift($entity, $request);
207
        if(isset($entity['minShifts']) && $entity['minShifts'] > 0)
208
        {
209
          $shift->makeCopy($dataTable);
210
        }
211
        if(isset($entity['overlap']) && $entity['overlap'])
212
        {
213
            $overlaps = $shift->findOverlaps($this->user->uid);
214
            $count = count($overlaps);
215
            $leads = array();
216
            for($i = 0; $i < $count; $i++)
217
            {
218
                $dept = new \VolunteerDepartment($overlaps[$i]->departmentID);
219
                $leads = array_merge($leads, $dept->getLeadEmails());
220
                $overlaps[$i]->status = 'pending';
221
                $tmp = new \Data\Filter('_id eq '.$overlaps[$i]->{'_id'});
222
                $res = $dataTable->update($tmp, $overlaps[$i]);
223
                if($res === false)
224
                {
225
                    return $response->withJSON(array('err'=>'Unable to update overlap with id '.$overlaps[$i]->{'_id'}));
226
                }
227
            }
228
            $dept = new \VolunteerDepartment($entity['departmentID']);
229
            $leads = array_merge($leads, $dept->getLeadEmails());
230
            $leads = array_unique($leads);
231
            $entity['participant'] = $this->user->uid;
232
            $entity['status'] = 'pending';
233
            $profile = new \VolunteerProfile($this->user->uid);
234
            $email = new \Emails\TwoShiftsAtOnceEmail($profile);
235
            $email->addLeads($leads);
236
            $emailProvider = \EmailProvider::getInstance();
237
            if($emailProvider->sendEmail($email) === false)
238
            {
239
                throw new \Exception('Unable to send duplicate email!');
240
            }
241
            return $response->withJSON($dataTable->update($filter, $entity));
242
        }
243 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...
244
        {
245
            $entity['participant'] = $this->user->uid;
246
            $entity['status'] = 'filled';
247
            return $response->withJSON($dataTable->update($filter, $entity));
248
        }
249 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...
250
        {
251
            $entity['participant'] = $this->user->uid;
252
            $entity['status'] = 'filled';
253
            return $response->withJSON($dataTable->update($filter, $entity));
254
        }
255
        print_r($entity); die();
256
    }
257
258
    public function abandon($request, $response, $args)
259
    {
260
        $this->validateLoggedIn($request);
261
        $shiftId = $args['shift'];
262
        $dataTable = $this->getDataTable();
263
        $filter = $this->getFilterForPrimaryKey($shiftId);
264
        $entity = $dataTable->read($filter);
265
        if(empty($entity))
266
        {
267
            return $response->withStatus(404);
268
        }
269
        $entity = $entity[0];
270
        if(!isset($entity['participant']) || $entity['participant'] !== $this->user->uid)
271
        {
272
            return $response->withStatus(401);
273
        }
274
        $entity['participant'] = '';
275
        $entity['status'] = 'unfilled';
276
        return $response->withJSON($dataTable->update($filter, $entity));
277
    }
278
279
    public function approvePending($request, $response, $args)
280
    {
281
        if(!$this->canCreate($request))
282
        {
283
            return $response->withStatus(401);
284
        }
285
        $shiftId = $args['shift'];
286
        $dataTable = $this->getDataTable();
287
        $filter = $this->getFilterForPrimaryKey($shiftId);
288
        $entity = $dataTable->read($filter);
289
        if(empty($entity))
290
        {
291
            return $response->withStatus(404);
292
        }
293
        $entity = $entity[0];
294
        $entity['status'] = 'filled';
295
        return $response->withJSON($dataTable->update($filter, $entity));
296
    }
297
298
    public function disapprovePending($request, $response, $args)
299
    {
300
        if(!$this->canCreate($request))
301
        {
302
            return $response->withStatus(401);
303
        }
304
        $shiftId = $args['shift'];
305
        $dataTable = $this->getDataTable();
306
        $filter = $this->getFilterForPrimaryKey($shiftId);
307
        $entity = $dataTable->read($filter);
308
        if(empty($entity))
309
        {
310
            return $response->withStatus(404);
311
        }
312
        $entity['participant'] = '';
313
        $entity['status'] = 'unfilled';
314
        $profile = new \VolunteerProfile($this->user->uid);
315
        $email = new \Emails\PendingRejectedEmail($profile);
316
        $email->setShift($entity);
317
        $emailProvider = \EmailProvider::getInstance();
318
        if($emailProvider->sendEmail($email) === false)
319
        {
320
            throw new \Exception('Unable to send duplicate email!');
321
        }
322
        return $response->withJSON($dataTable->update($filter, $entity));
323
    }
324
325
    public function startGroupSignup($request, $response, $args)
326
    {
327
        $this->validateLoggedIn($request);
328
        $shiftId = $args['shift'];
329
        $dataTable = $this->getDataTable();
330
        $filter = $this->getFilterForPrimaryKey($shiftId);
331
        $entity = $dataTable->read($filter);
332
        if(empty($entity))
333
        {
334
            return $response->withStatus(404);
335
        }
336
        $entity = $entity[0];
337 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...
338
        {
339
            return $response->withStatus(401);
340
        }
341
        $filter = new \Data\Filter('groupID eq '.$entity['groupID'].' and enabled eq true');
342
        $entities = $dataTable->read($filter);
343
        $count = count($entities);
344
        $dept = new \VolunteerDepartment($entity['departmentID']);
345
        $res = array();
346
        $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...
347
        $res['earlyLate'] = $entity['earlyLate'];
348
        $res['endTime'] = $entity['endTime'];
349
        $res['eventID'] = $entity['eventID'];
350
        $res['name'] = $entity['name'];
351
        $res['startTime'] = $entity['startTime'];
352
        $res['groupID'] = $entity['groupID'];
353
        $res['shifts'] = array();
354
        $roles = array();
355
        for($i = 0; $i < $count; $i++)
356
        {
357 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...
358
            {
359
                continue;
360
            }
361
            if(!isset($roles[$entities[$i]['roleID']]))
362
            {
363
                $roles[$entities[$i]['roleID']] = new \VolunteerRole($entities[$i]['roleID']);
364
            }
365
            $role = $roles[$entities[$i]['roleID']];
366
            $entities[$i]['role'] = $role->display_name;
367
            array_push($res['shifts'], $entities[$i]);
368
        }
369
        return $response->withJSON($res);
370
    }
371
372
    public function generateGroupLink($request, $response, $args)
373
    {
374
        $this->validateLoggedIn($request);
375
        $shiftId = $args['shift'];
376
        $dataTable = $this->getDataTable();
377
        $filter = $this->getFilterForPrimaryKey($shiftId);
378
        $entity = $dataTable->read($filter);
379
        if(empty($entity))
380
        {
381
            return $response->withStatus(404);
382
        }
383
        $entity = $entity[0];
384 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...
385
        {
386
            return $response->withStatus(401);
387
        }
388
        $data = $request->getParsedBody();
389
        $myShift = $data['myshift'];
390
        $roles = array();
391
        foreach($data as $key => $value)
392
        {
393
            if(substr($key, 0, 6) === "roles.")
394
            {
395
                $roles[substr($key, 6)] = $value;
396
            }
397
        }
398
        $filter = new \Data\Filter('groupID eq '.$entity['groupID'].' and enabled eq true');
399
        $entities = $dataTable->read($filter);
400
        $count = count($entities);
401
        $uuid = $this->genUUID();
402
        for($i = 0; $i < $count; $i++)
403
        {
404 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...
405
            {
406
                $entities[$i] = false;
407
                continue;
408
            }
409
            if((string)$entities[$i]['_id'] === (string)new \MongoDB\BSON\ObjectId($myShift))
410
            {
411
                $entities[$i]['participant'] = $this->user->uid;
412
                $entities[$i]['status'] = 'filled';
413
                $entities[$i]['signupLink'] = $uuid;
414
            }
415
            else if(isset($roles[$entities[$i]['roleID']]))
416
            {
417
                $entities[$i]['status'] = 'groupPending';
418
                $entities[$i]['signupLink'] = $uuid;
419
                $roles[$entities[$i]['roleID']]--;
420
                if($roles[$entities[$i]['roleID']] === 0)
421
                {
422
                    unset($roles[$entities[$i]['roleID']]);
423
                }
424
            }
425
            else
426
            {
427
                $entities[$i] = false;
428
            }
429
        }
430
        if(count($roles) !== 0)
431
        {
432
            throw new \Exception('Not enough shifts to fullfill requests');
433
        }
434
        for($i = 0; $i < $count; $i++)
435
        {
436
            if($entities[$i] === false)
437
            {
438
                continue;
439
            }
440
            $filter = new \Data\Filter('_id eq '.$entities[$i]['_id']);
441
            $res = $dataTable->update($filter, $entities[$i]);
442
            if($res === false)
443
            {
444
                throw new \Exception('Not able to save shift '.$entities[$i]['_id']);
445
            }
446
        }
447
        return $response->withJSON(array('uuid' => $uuid));
448
    }
449
450
    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...
451
    {
452
        $this->validateLoggedIn($request);
453
        $shiftId = $args['shift'];
454
        $dataTable = $this->getDataTable();
455
        $filter = $this->getFilterForPrimaryKey($shiftId);
456
        $entity = $dataTable->read($filter);
457
        if(empty($entity))
458
        {
459
            return $response->withStatus(404);
460
        }
461
        $entity = $entity[0];
462
        if(!$this->canUpdate($request, $entity))
463
        {
464
            return $response->withStatus(401);
465
        }
466
        $entity['participant'] = '';
467
        $entity['status'] = 'unfilled';
468
        return $response->withJSON($dataTable->update($filter, $entity));
469
    }
470
}
471