Completed
Push — master ( 934cbe...61fa21 )
by
unknown
01:55
created

UserController::getUserTrainings()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 50
rs 8.7797
c 0
b 0
f 0
ccs 0
cts 36
cp 0
cc 5
nc 8
nop 2
crap 30
1
<?php
2
3
namespace SET\Http\Controllers;
4
5
use Carbon\Carbon;
6
use Illuminate\Support\Facades\DB;
7
use Illuminate\Support\Facades\File;
8
use Illuminate\Support\Facades\Gate;
9
use Illuminate\Support\Facades\Storage;
10
use Krucas\Notification\Facades\Notification;
11
use SET\Duty;
12
use SET\Group;
13
use SET\Handlers\Excel\JpasImport;
14
use SET\Http\Requests\StoreUserRequest;
15
use SET\Http\Requests\UpdateUserRequest;
16
use SET\Setting;
17
use SET\Training;
18
use SET\User;
19
20
/**
21
 * Class UserController.
22
 */
23
class UserController extends Controller
24
{
25
    /**
26
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
27
     */
28
    public function index($userStatus = null)
29
    {
30
        $this->authorize('view');
31
32
        session(['userStatus' => $userStatus]);
33
        if ($userStatus) {
34
            $users = User::with([
35
                'assignedTrainings' => function ($q) {
36
                    $q->whereNull('completed_date')
37
                        ->whereBetween('due_date', [Carbon::now()->subYear(), Carbon::now()->addWeeks(4)]);
38
                },
39
                'trainings',
40
            ])
41
                ->skipSystem()
42
                ->where('status', $userStatus)
43
                ->orderBy('last_name')->get();
44
        } else {
45
            $users = User::with([
46
                'assignedTrainings' => function ($q) {
47
                    $q->whereNull('completed_date')
48
                        ->whereBetween('due_date', [Carbon::now()->subYear(), Carbon::now()->addWeeks(4)]);
49
                },
50
                'trainings',
51
            ])
52
            ->skipSystem()
53
            ->orderBy('last_name')->get();
54
        }
55
56
        return view('user.index', compact('users', 'userStatus'));
57
    }
58
59 View Code Duplication
    public function create()
60
    {
61
        $this->authorize('edit');
62
63
        $supervisors = User::skipSystem()->active()->orderBy('last_name')->get()->pluck('userFullName', 'id')->toArray();
64
        $groups = Group::all();
65
66
        return view('user.create', compact('supervisors', 'groups'));
67
    }
68
69
    /**
70
     * @param StoreUserRequest $request
71
     *
72
     * @return \Illuminate\Http\RedirectResponse
73
     */
74
    public function store(StoreUserRequest $request)
75
    {
76
        $data = $request->all();
77
        $data['status'] = 'active';
78
        $user = User::create($data);
79
        
80 View Code Duplication
        if ($data['accessTokens']['cac_return_date'] = "") 
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...
81
        $data['accessTokens']['cac_return_date'] = null;
82
        
83 View Code Duplication
        if ($data['accessTokens']['sipr_return_date'] = "") 
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...
84
        $data['accessTokens']['sipr_return_date'] = null;
85
86
        $user->accessTokens()->create($data['accessTokens']);
87
88
        if (array_key_exists('groups', $data)) {
89
            settype($data['groups'], 'array');
90
            $user->groups()->sync($data['groups']);
91
        }
92
93
        return redirect()->action('UserController@index');
94
    }
95
96
    /**
97
     * @param $userId
98
     *
99
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
100
     */
101
    public function show($userId, $sectionId = null)
102
    {
103
        $user = User::with(['subordinates' => function ($query) {
104
            $query->active();
105
        },
106
                            'groups', 'duties', 'attachments',
107
                            'visits', 'notes.author', 'notes.attachments',
108
                            'travels.author', 'travels.attachments',
109
                            'accessTokens'])
110
                    ->findOrFail($userId);
111
112
        //Make sure the user can't access other people's pages.
113
        $this->authorize('show_user', $user);
114
115
        $user['clearance'] = $this->spellOutClearance($user['clearance']);
116
        $user['access_level'] = $this->spellOutClearance($user['access_level']);
117
118
        $trainings = $this->getUserTrainings($user, $sectionId);
119
        $user_training_types = $this->getUserTrainingTypes($trainings);
120
        $training_user_types = $user_training_types[0]; // List of the user's training types
121
        $training_blocks = $user_training_types[1]; // List of training block titles for user
122
123
        $activityLog = [];
124
        if (Gate::allows('view')) {
125
            $activityLog = $user->getUserLog($user);
126
        }
127
        
128
        $this->previousAndNextUsers($user, $previous, $next);
129
130
        //This mess is just so that we can output the Security Check list or show none. Mainly just to show none.
131
        $duties = Duty::whereHas('users', function ($q) use ($userId) {
132
            $q->where('id', $userId);
133
        })->orWhereHas('groups.users', function ($q) use ($userId) {
134
            $q->where('id', $userId);
135
        })->get();
136
137
        return view('user.show', compact('user', 'duties', 'previous', 'next',
138
            'trainings', 'activityLog', 'training_blocks', 'training_user_types'));
139
    }
140
141 View Code Duplication
    public function edit(User $user)
142
    {
143
        $this->authorize('edit');
144
145
        $supervisors = User::skipSystem()->active()->orderBy('last_name')->get()->pluck('userFullName', 'id')->toArray();
146
        $groups = Group::all();
147
148
        return view('user.edit', compact('user', 'supervisors', 'groups'));
149
    }
150
151
    public function update(UpdateUserRequest $request, User $user)
152
    {
153
        $this->authorize('edit');
154
        $data = $request->all();
155
156
        //$data['destroyed_date'] = $user->getDestroyDate($data['status']);
157
158
        // If continuous evaluation is false, there should be no date associated with it
159
        if ($data['cont_eval'] == 0)
160
            $data['cont_eval_date'] = null;
161
        
162 View Code Duplication
        if ($data['accessTokens']['cac_return_date'] = "") 
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...
163
        $data['accessTokens']['cac_return_date'] = null;
164
        
165 View Code Duplication
        if ($data['accessTokens']['sipr_return_date'] = "") 
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...
166
        $data['accessTokens']['sipr_return_date'] = null;
167
168
        $user->update($data);
169
170
        //Handle user groups
171
        if (!array_key_exists('groups', $data)) {
172
            $data['groups'] = [];
173
        }
174
        $user->groups()->sync($data['groups']);
175
        
176
        $user->accessTokens()->updateOrCreate(['user_id' => $user->id], $data['accessTokens']);
177
178
        //Handled closed area access (MUST come AFTER syncing groups).
179
        if (array_key_exists('access', $data)) {
180
            foreach ($data['access'] as $group_id => $accessLevel) {
181
                $user->groups()->updateExistingPivot($group_id, ['access' => $accessLevel]);
182
            }
183
        }
184
185
        return redirect()->action('UserController@show', $user->id);
186
    }
187
188
    /**
189
     * @param $userId
190
     *
191
     * @return string
192
     */
193
    public function destroy($userId)
194
    {
195
        $this->authorize('edit');
196
197
        Storage::deleteDirectory('user_'.$userId);
198
        User::findOrFail($userId)->delete();
199
200
        return 'success';
201
    }
202
203
    /**
204
     * Get all the scheduled trainings for the user and either the most recent completed
205
     * trainings or all completed trainings for the desired training type based on data values.
206
     *
207
     * @param $user
208
     * @param $data
209
     *
210
     * @return array trainings
211
     */
212
    private function getUserTrainings($user, $sectionId)
213
    {
214
        // Get the scheduled trainings and the completed trainings separately, so it will be easier to get either
215
        // the full list of completed trainings or the most recently completed training for each training type.
216
        // Fetch scheduled trainings only if the user is active.
217
        if ($user->status == 'active') {
218
            $scheduledTrainings = $user->assignedTrainings()->with('author', 'training.attachments', 'attachments')
219
                                ->whereNull('completed_date');
220
        }
221
222
        // Now fetch the recently completed training records for the specified  user
223
        $recentCompletedTrainings = DB::table('training_user as t1')
224
                                    ->where('id', function ($query) use ($user) {
225
                                        $query->from('training_user as t2')
226
                                              ->selectRaw('t2.id')
227
                                              ->where('t2.user_id', '=', $user->id)
228
                                              ->whereRaw('t1.training_id = t2.training_id')
229
                                              ->whereNotNull('completed_date')
230
                                              ->orderBy('completed_date', 'DESC')->limit(1);
231
                                    });
232
233
        // If the user clicks the showAll button for a particular type of training,
234
        // show all the trainings completed by that user for that training type.
235
        if ($sectionId != null) {
236
            $selectedTraining = Training::trainingByType($sectionId)->get()->pluck('id')->toArray();
0 ignored issues
show
Bug introduced by
The method trainingByType() does not exist on SET\Training. Did you maybe mean scopeTrainingByType()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
237
238
            $completedTrainings = $user->assignedTrainings()->with('author', 'training.attachments', 'attachments')
239
                                    ->whereIn('training_id', $selectedTraining)->whereNotNull('completed_date');
240
241
            if (isset($scheduledTrainings)) {
242
                $trainings = $scheduledTrainings->union($completedTrainings)->union($recentCompletedTrainings)
243
                                        ->orderBy('completed_date', 'DESC')->get();
244
            } else {
245
                $trainings = $completedTrainings->union($recentCompletedTrainings)
246
                                ->orderBy('completed_date', 'DESC')->get();
247
            }
248
        } else {
249
            if (isset($scheduledTrainings)) {
250
                $trainings = $scheduledTrainings->union($recentCompletedTrainings)
251
                                ->orderBy('completed_date', 'DESC')->get();
252
            } else {
253
                $rcTrainingIds = $recentCompletedTrainings->get()->pluck('training_id')->toArray();
254
                $trainings = $user->assignedTrainings()->with('author', 'training.attachments', 'attachments')
255
                                    ->whereIn('training_id', $rcTrainingIds)
256
                                    ->orderBy('completed_date', 'DESC')->get();
257
            }
258
        }
259
260
        return $trainings;
261
    }
262
263
    /**
264
     * @param $trainings[]
265
     * From the User's trainings, a list of the training types is determined and
266
     * a list of the training block titles is determined.
267
     *
268
     * @return user_training_types[], training_block_titles[]
0 ignored issues
show
Documentation introduced by
The doc-type user_training_types[], could not be parsed: Expected "|" or "end of type", but got "," at position 21. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
269
     */
270
    public function getUserTrainingTypes($trainings = [])
271
    {
272
        $training_block_titles = $user_training_types = [];
273
        foreach ($trainings as $trainingUser) {
274
            if (is_null($trainingUser->completed_date)) {
275
                $training_block_titles['AAA'] = 'Scheduled';
276
                $user_training_types[$trainingUser->id] = 'Scheduled';
277
            } elseif ($trainingUser->Training->trainingType) {
278
                $typeName = $trainingUser->Training->trainingType->name;
279
                $training_block_titles[$typeName] = $typeName;
280
                $user_training_types[$trainingUser->id] = $typeName;
281
            } else { // No training type
282
                $training_block_titles['999'] = 'Miscellaneous';
283
                $user_training_types[$trainingUser->id] = 'Miscellaneous';
284
            }
285
        }
286
        ksort($training_block_titles);  // Order by key
287
        return [$user_training_types, $training_block_titles];
288
    }
289
290
    /**
291
     * Process our JPAS import. Once that has been handled, we pass the file, changes,
292
     * unique/unmapped users & a user list to the user.import view.
293
     * That way we keep all this data for the resolve phase.
294
     *
295
     * @param JpasImport $import
296
     *
297
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
298
     */
299
    public function import(JpasImport $import)
300
    {
301
        $results = $import->handleImport();
302
        $uploadedFile = $import->getFile('file');
303
304
        $changes = $results['changes'];
305
        $unique = $results['unique'];
306
307
        $userList = User::orderBy('last_name')->get()->pluck('UserFullName', 'id')->toArray();
308
309
        return view('user.import', compact('unique', 'changes', 'userList', 'uploadedFile'));
310
    }
311
312
    /**
313
     * @param JpasImport $import
314
     *
315
     * @return \Illuminate\Http\RedirectResponse
316
     */
317
    public function resolveImport(JpasImport $import)
318
    {
319
        $import->handleImport();
320
321
        Notification::container()->success('Import Complete');
322
323
        File::delete($import->getFile('file'));
324
325
        return redirect()->action('HomeController@index');
326
    }
327
328
    /**
329
     * Generate the grab the previous and next user if our users are sorted alphabetically.
330
     *
331
     * @param $user
332
     * @param $previous
333
     * @param $next
334
     */
335
    private function previousAndNextUsers($user, &$previous, &$next)
336
    {  
337
          //Build the previous/next user that are in alphabetical order, with respect to admin's preference
338
        if(Setting::get('full_name_format') == 'first_last'){
339
            $users = User::skipSystem()->userStatus()->orderBy( 'first_name ')->orderBy( 'last_name' )->get();
340
        } else{
341
            $users = User::skipSystem()->userStatus()->orderBy( 'last_name' )->orderBy( 'first_name' )->get();
342
        }
343
        
344
        
345
        $previous = null; // set to null by default in case we are at the start of the list.
346
        while ($users->first()->id != $user->id) {
347
            $previous = $users->shift()->id;
348
        }
349
        //check if we have a record aft the current user. If not, then we are at the end.
350
        if ($users->count() > 1) {
351
            $users->shift();
352
            $next = $users->shift()->id;
353
        } else {
354
            $next = null;
355
        }
356
    }
357
358
    /**
359
     * @param $clearance
360
     *
361
     * @return mixed
362
     */
363
    private function spellOutClearance($clearance)
364
    {
365
        //fully spell out user's clearance.
366
        switch ($clearance) {
367
            case 'S':
368
                $clearance = 'Secret';
369
                break;
370
            case 'TS':
371
                $clearance = 'Top Secret';
372
                break;
373
            case 'Int S':
374
                $clearance = 'Interim Secret';
375
                break;
376
            case 'Int TS':
377
                $clearance = 'Interim Top Secret';
378
                break;
379
        }
380
381
        return $clearance;
382
    }
383
}
384