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) { |
|
|
|
|
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) { |
|
|
|
|
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(); |
|
|
|
|
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[] |
|
|
|
|
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
|
|
|
|
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.