UserController::spellOutClearance()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.2888
c 0
b 0
f 0
ccs 0
cts 5
cp 0
cc 5
nc 5
nop 1
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 View Code Duplication
                'assignedTrainings' => function ($q) {
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...
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 View Code Duplication
                'assignedTrainings' => function ($q) {
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...
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
        $user->accessTokens()->create($data['accessTokens']);
81
82
        if (array_key_exists('groups', $data)) {
83
            settype($data['groups'], 'array');
84
            $user->groups()->sync($data['groups']);
85
        }
86
87
        return redirect()->action('UserController@index');
88
    }
89
90
    /**
91
     * @param $userId
92
     *
93
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
94
     */
95
    public function show($userId, $sectionId = null)
96
    {
97
        $user = User::with(['subordinates' => function ($query) {
98
            $query->active();
99
        },
100
                            'groups', 'duties', 'attachments',
101
                            'visits', 'notes.author', 'notes.attachments',
102
                            'travels.author', 'travels.attachments',
103
                            'accessTokens'])
104
                    ->findOrFail($userId);
105
106
        //Make sure the user can't access other people's pages.
107
        $this->authorize('show_user', $user);
108
109
        $user['clearance'] = $this->spellOutClearance($user['clearance']);
110
        $user['access_level'] = $this->spellOutClearance($user['access_level']);
111
112
        $trainings = $this->getUserTrainings($user, $sectionId);
113
        $user_training_types = $this->getUserTrainingTypes($trainings);
114
        $training_user_types = $user_training_types[0]; // List of the user's training types
115
        $training_blocks = $user_training_types[1]; // List of training block titles for user
116
117
        $activityLog = [];
118
        if (Gate::allows('view')) {
119
            $activityLog = $user->getUserLog($user);
120
        }
121
        
122
        $this->previousAndNextUsers($user, $previous, $next);
123
124
        //This mess is just so that we can output the Security Check list or show none. Mainly just to show none.
125
        $duties = Duty::whereHas('users', function ($q) use ($userId) {
126
            $q->where('id', $userId);
127
        })->orWhereHas('groups.users', function ($q) use ($userId) {
128
            $q->where('id', $userId);
129
        })->get();
130
131
        return view('user.show', compact('user', 'duties', 'previous', 'next',
132
            'trainings', 'activityLog', 'training_blocks', 'training_user_types'));
133
    }
134
135 View Code Duplication
    public function edit(User $user)
136
    {
137
        $this->authorize('edit');
138
139
        $supervisors = User::skipSystem()->active()->orderBy('last_name')->get()->pluck('userFullName', 'id')->toArray();
140
        $groups = Group::all();
141
142
        return view('user.edit', compact('user', 'supervisors', 'groups'));
143
    }
144
145
    public function update(UpdateUserRequest $request, User $user)
146
    {
147
        $this->authorize('edit');
148
        $data = $request->all();
149
150
        //$data['destroyed_date'] = $user->getDestroyDate($data['status']);
151
152
        // If continuous evaluation is false, there should be no date associated with it
153
        if ($data['cont_eval'] == 0)
154
            $data['cont_eval_date'] = null;
155
156
157
        $user->update($data);
158
159
        //Handle user groups
160
        if (!array_key_exists('groups', $data)) {
161
            $data['groups'] = [];
162
        }
163
        $user->groups()->sync($data['groups']);
164
        
165
        $user->accessTokens()->updateOrCreate(['user_id' => $user->id], $data['accessTokens']);
166
167
        //Handled closed area access (MUST come AFTER syncing groups).
168
        if (array_key_exists('access', $data)) {
169
            foreach ($data['access'] as $group_id => $accessLevel) {
170
                $user->groups()->updateExistingPivot($group_id, ['access' => $accessLevel]);
171
            }
172
        }
173
174
        return redirect()->action('UserController@show', $user->id);
175
    }
176
177
    /**
178
     * @param $userId
179
     *
180
     * @return string
181
     */
182
    public function destroy($userId)
183
    {
184
        $this->authorize('edit');
185
186
        Storage::deleteDirectory('user_'.$userId);
187
        User::findOrFail($userId)->delete();
188
189
        return 'success';
190
    }
191
192
    /**
193
     * Get all the scheduled trainings for the user and either the most recent completed
194
     * trainings or all completed trainings for the desired training type based on data values.
195
     *
196
     * @param $user
197
     * @param $data
198
     *
199
     * @return array trainings
200
     */
201
    private function getUserTrainings($user, $sectionId)
202
    {
203
        // Get the scheduled trainings and the completed trainings separately, so it will be easier to get either
204
        // the full list of completed trainings or the most recently completed training for each training type.
205
        // Fetch scheduled trainings only if the user is active.
206
        if ($user->status == 'active') {
207
            $scheduledTrainings = $user->assignedTrainings()->with('author', 'training.attachments', 'attachments')
208
                                ->whereNull('completed_date');
209
        }
210
211
        // Now fetch the recently completed training records for the specified  user
212
        $recentCompletedTrainings = DB::table('training_user as t1')
213
                                    ->where('id', function ($query) use ($user) {
214
                                        $query->from('training_user as t2')
215
                                              ->selectRaw('t2.id')
216
                                              ->where('t2.user_id', '=', $user->id)
217
                                              ->whereRaw('t1.training_id = t2.training_id')
218
                                              ->whereNotNull('completed_date')
219
                                              ->orderBy('completed_date', 'DESC')->limit(1);
220
                                    });
221
222
        // If the user clicks the showAll button for a particular type of training,
223
        // show all the trainings completed by that user for that training type.
224
        if ($sectionId != null) {
225
            $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...
226
227
            $completedTrainings = $user->assignedTrainings()->with('author', 'training.attachments', 'attachments')
228
                                    ->whereIn('training_id', $selectedTraining)->whereNotNull('completed_date');
229
230
            if (isset($scheduledTrainings)) {
231
                $trainings = $scheduledTrainings->union($completedTrainings)->union($recentCompletedTrainings)
232
                                        ->orderBy('completed_date', 'DESC')->get();
233
            } else {
234
                $trainings = $completedTrainings->union($recentCompletedTrainings)
235
                                ->orderBy('completed_date', 'DESC')->get();
236
            }
237
        } else {
238
            if (isset($scheduledTrainings)) {
239
                $trainings = $scheduledTrainings->union($recentCompletedTrainings)
240
                                ->orderBy('completed_date', 'DESC')->get();
241
            } else {
242
                $rcTrainingIds = $recentCompletedTrainings->get()->pluck('training_id')->toArray();
243
                $trainings = $user->assignedTrainings()->with('author', 'training.attachments', 'attachments')
244
                                    ->whereIn('training_id', $rcTrainingIds)
245
                                    ->orderBy('completed_date', 'DESC')->get();
246
            }
247
        }
248
249
        return $trainings;
250
    }
251
252
    /**
253
     * @param $trainings[]
254
     * From the User's trainings, a list of the training types is determined and
255
     * a list of the training block titles is determined.
256
     *
257
     * @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...
258
     */
259
    public function getUserTrainingTypes($trainings = [])
260
    {
261
        $training_block_titles = $user_training_types = [];
262
        foreach ($trainings as $trainingUser) {
263
            if (is_null($trainingUser->completed_date)) {
264
                $training_block_titles['AAA'] = 'Scheduled';
265
                $user_training_types[$trainingUser->id] = 'Scheduled';
266
            } elseif ($trainingUser->Training->trainingType) {
267
                $typeName = $trainingUser->Training->trainingType->name;
268
                $training_block_titles[$typeName] = $typeName;
269
                $user_training_types[$trainingUser->id] = $typeName;
270
            } else { // No training type
271
                $training_block_titles['999'] = 'Miscellaneous';
272
                $user_training_types[$trainingUser->id] = 'Miscellaneous';
273
            }
274
        }
275
        ksort($training_block_titles);  // Order by key
276
        return [$user_training_types, $training_block_titles];
277
    }
278
279
    /**
280
     * Process our JPAS import. Once that has been handled, we pass the file, changes,
281
     * unique/unmapped users & a user list to the user.import view.
282
     * That way we keep all this data for the resolve phase.
283
     *
284
     * @param JpasImport $import
285
     *
286
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
287
     */
288
    public function import(JpasImport $import)
289
    {
290
        $results = $import->handleImport();
291
        $uploadedFile = $import->getFile('file');
292
293
        $changes = $results['changes'];
294
        $unique = $results['unique'];
295
296
        $userList = User::orderBy('last_name')->get()->pluck('UserFullName', 'id')->toArray();
297
298
        return view('user.import', compact('unique', 'changes', 'userList', 'uploadedFile'));
299
    }
300
301
    /**
302
     * @param JpasImport $import
303
     *
304
     * @return \Illuminate\Http\RedirectResponse
305
     */
306
    public function resolveImport(JpasImport $import)
307
    {
308
        $import->handleImport();
309
310
        Notification::container()->success('Import Complete');
311
312
        File::delete($import->getFile('file'));
313
314
        return redirect()->action('HomeController@index');
315
    }
316
317
    /**
318
     * Generate the grab the previous and next user if our users are sorted alphabetically.
319
     *
320
     * @param $user
321
     * @param $previous
322
     * @param $next
323
     */
324
    private function previousAndNextUsers($user, &$previous, &$next)
325
    {  
326
          //Build the previous/next user that are in alphabetical order, with respect to admin's preference
327
        if(Setting::get('full_name_format') == 'first_last'){
328
            $users = User::skipSystem()->userStatus()->orderBy( 'first_name ')->orderBy( 'last_name' )->get();
329
        } else{
330
            $users = User::skipSystem()->userStatus()->orderBy( 'last_name' )->orderBy( 'first_name' )->get();
331
        }
332
        
333
        
334
        $previous = null; // set to null by default in case we are at the start of the list.
335
        while ($users->first()->id != $user->id) {
336
            $previous = $users->shift()->id;
337
        }
338
        //check if we have a record aft the current user. If not, then we are at the end.
339
        if ($users->count() > 1) {
340
            $users->shift();
341
            $next = $users->shift()->id;
342
        } else {
343
            $next = null;
344
        }
345
    }
346
347
    /**
348
     * @param $clearance
349
     *
350
     * @return mixed
351
     */
352
    private function spellOutClearance($clearance)
353
    {
354
        //fully spell out user's clearance.
355
        switch ($clearance) {
356
            case 'S':
357
                $clearance = 'Secret';
358
                break;
359
            case 'TS':
360
                $clearance = 'Top Secret';
361
                break;
362
            case 'Int S':
363
                $clearance = 'Interim Secret';
364
                break;
365
            case 'Int TS':
366
                $clearance = 'Interim Top Secret';
367
                break;
368
        }
369
370
        return $clearance;
371
    }
372
}
373