Passed
Push — feature/screen-candidates-emai... ( a0a58c...49e0ac )
by Yonathan
07:48 queued 04:01
created

JobController::populateDefaultQuestions()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 28
rs 9.7666
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
3
namespace App\Http\Controllers;
4
5
use App\Http\Controllers\Controller;
6
use App\Models\JobApplication;
7
use App\Models\JobPoster;
8
use App\Models\JobPosterQuestion;
9
use App\Models\Lookup\ApplicationStatus;
10
use App\Models\Lookup\CitizenshipDeclaration;
11
use App\Models\Lookup\JobPosterStatus;
12
use App\Models\Lookup\VeteranStatus;
13
use App\Models\Manager;
14
use App\Services\JobPosterDefaultQuestions;
15
use App\Services\Validation\JobPosterValidator;
16
use Carbon\Carbon;
17
use Facades\App\Services\WhichPortal;
18
use Illuminate\Http\Request;
19
use Illuminate\Support\Facades\Auth;
20
use Illuminate\Support\Facades\Lang;
21
use Illuminate\Support\Facades\Response;
22
use Illuminate\Support\Facades\Validator;
23
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
24
25
class JobController extends Controller
26
{
27
    /**
28
     * Display a listing of JobPosters.
29
     *
30
     * @return \Illuminate\Http\Response
31
     */
32
    public function index()
33
    {
34
        // If true, show the Paused due to COVID-19 message.
35
        $emergency_response = config('seasonal.is_covid_emergency');
0 ignored issues
show
Bug introduced by
The function config was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

35
        $emergency_response = /** @scrutinizer ignore-call */ config('seasonal.is_covid_emergency');
Loading history...
36
37
        // Find published jobs that are currently open for applications.
38
        // Eager load required relationships: Department, Province, JobTerm.
39
        // Eager load the count of submitted applications, to prevent the relationship
40
        // from being actually loaded and firing off events.
41
        $jobs = JobPoster::where('internal_only', false)
42
            ->where('department_id', '!=', config('app.strategic_response_department_id'))
43
            ->where('job_poster_status_id', JobPosterStatus::where('key', 'live')->first()->id)
44
            ->with([
45
                'department',
46
                'province',
47
                'job_term',
48
            ])
49
            ->withCount([
50
                'submitted_applications',
51
            ])
52
            ->get();
53
54
        $null_alert = $emergency_response
55
            ? Lang::get('applicant/job_index.index.covid_null_alert')
56
            : Lang::get('applicant/job_index.index.null_alert');
57
        return view('applicant/job_index', [
0 ignored issues
show
Bug introduced by
The function view was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

57
        return /** @scrutinizer ignore-call */ view('applicant/job_index', [
Loading history...
58
            'job_index' => Lang::get('applicant/job_index'),
59
            'null_alert' => $null_alert,
60
            'jobs' => $jobs
61
        ]);
62
    }
63
64
    /**
65
     * Display a listing of a manager's JobPosters.
66
     *
67
     * @return \Illuminate\Http\Response
68
     */
69
    public function managerIndex()
70
    {
71
        $manager = Auth::user()->manager;
72
73
        $jobs = JobPoster::where('manager_id', $manager->id)
74
            ->with('classification')
75
            ->withCount('submitted_applications')
76
            ->get();
77
78
        foreach ($jobs as &$job) {
79
            // If the chosen language is null then set to english.
80
            $chosen_lang = $job->chosen_lang ?: 'en';
81
82
            // Show chosen lang title if current title is empty.
83
            if (empty($job->title)) {
84
                $job->title = $job->getTranslation('title', $chosen_lang);
85
                $job->trans_required = true;
86
            }
87
88
            // Always preview and edit in the chosen language.
89
            $job->preview_link = LaravelLocalization::getLocalizedURL($chosen_lang, route('manager.jobs.preview', $job));
0 ignored issues
show
Bug introduced by
The function route was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

89
            $job->preview_link = LaravelLocalization::getLocalizedURL($chosen_lang, /** @scrutinizer ignore-call */ route('manager.jobs.preview', $job));
Loading history...
90
            $job->edit_link = LaravelLocalization::getLocalizedURL($chosen_lang, route('manager.jobs.edit', $job));
91
        }
92
93
94
        return view('manager/job_index', [
0 ignored issues
show
Bug introduced by
The function view was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

94
        return /** @scrutinizer ignore-call */ view('manager/job_index', [
Loading history...
95
            // Localization Strings.
96
            'jobs_l10n' => Lang::get('manager/job_index'),
97
            // Data.
98
            'jobs' => $jobs,
99
        ]);
100
    }
101
102
    /**
103
     * Display a listing of a hr advisor's JobPosters.
104
     *
105
     * @return \Illuminate\Http\Response
106
     */
107
    public function hrIndex(Request $request)
108
    {
109
        $hrAdvisor = $request->user()->hr_advisor;
110
        return view('hr_advisor/job_index', [
0 ignored issues
show
Bug introduced by
The function view was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

110
        return /** @scrutinizer ignore-call */ view('hr_advisor/job_index', [
Loading history...
111
            'jobs_l10n' => Lang::get('hr_advisor/job_index'),
112
            'hr_advisor_id' => $hrAdvisor->id
113
        ]);
114
    }
115
116
117
118
119
    /**
120
     * Delete a draft Job Poster.
121
     *
122
     * @param  \Illuminate\Http\Request $request   Incoming request object.
123
     * @param  \App\Models\JobPoster    $jobPoster Job Poster object.
124
     * @return \Illuminate\Http\Response
125
     */
126
    public function destroy(Request $request, JobPoster $jobPoster)
127
    {
128
        $jobPoster->delete();
129
    }
130
131
    /**
132
     * Display the specified job poster.
133
     *
134
     * @param  \Illuminate\Http\Request $request   Incoming request object.
135
     * @param  \App\Models\JobPoster    $jobPoster Job Poster object.
136
     * @return \Illuminate\Http\Response
137
     */
138
    public function show(Request $request, JobPoster $jobPoster)
139
    {
140
        $jobPoster->load([
141
            'department',
142
            'criteria.skill.skill_type',
143
            'manager.team_culture',
144
            'manager.work_environment'
145
        ]);
146
147
        $user = Auth::user();
148
149
        // TODO: Improve workplace photos, and reference them in template direction from WorkEnvironment model.
150
        $workplacePhotos = [];
151
        foreach ($jobPoster->manager->work_environment->workplace_photo_captions as $photoCaption) {
152
            $workplacePhotos[] = [
153
                'description' => $photoCaption->description,
154
                'url' => '/images/user.png'
155
            ];
156
        }
157
158
        // TODO: replace route('manager.show',manager.id) in templates with link using slug.
159
        $essential = $jobPoster->criteria->filter(
160
            function ($value, $key) {
161
                return $value->criteria_type->name == 'essential';
162
            }
163
        )->sortBy('id');
164
        $asset = $jobPoster->criteria->filter(
165
            function ($value, $key) {
166
                return $value->criteria_type->name == 'asset';
167
            }
168
        )->sortBy('id');
169
        $criteria = [
170
            'essential' => $essential,
171
            'asset' => $asset,
172
        ];
173
174
        $jobLang = Lang::get('applicant/job_post');
175
176
        $applyButton = [];
177
        if (WhichPortal::isManagerPortal()) {
178
            $applyButton = [
179
                'href' => route('manager.jobs.edit', $jobPoster->id),
0 ignored issues
show
Bug introduced by
The function route was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

179
                'href' => /** @scrutinizer ignore-call */ route('manager.jobs.edit', $jobPoster->id),
Loading history...
180
                'title' => $jobLang['apply']['edit_link_title'],
181
                'text' => $jobLang['apply']['edit_link_label'],
182
            ];
183
        } elseif (WhichPortal::isHrPortal()) {
184
            if ($jobPoster->hr_advisors->contains('user_id', $user->id)) {
185
                $applyButton = [
186
                    'href' => route('hr_advisor.jobs.summary', $jobPoster->id),
187
                    'title' => null,
188
                    'text' => Lang::get('hr_advisor/job_summary.summary_title'),
189
                ];
190
            } else {
191
                $applyButton = [
192
                    'href' => route('hr_advisor.jobs.index'),
193
                    'title' => null,
194
                    'text' => Lang::get('hr_advisor/job_index.title'),
195
                ];
196
            }
197
        } elseif (Auth::check() && $jobPoster->isOpen()) {
198
            $application = JobApplication::where('applicant_id', Auth::user()->applicant->id)
199
                ->where('job_poster_id', $jobPoster->id)->first();
200
            // If applicants job application is not draft anymore then link to application preview page.
201
            if ($application != null && $application->application_status->name != 'draft') {
202
                $applyButton = [
203
                    'href' => route('applications.show', $application->id),
204
                    'title' => $jobLang['apply']['view_link_title'],
205
                    'text' => $jobLang['apply']['view_link_label'],
206
                ];
207
            } else {
208
                $applyButton = [
209
                    'href' => route('job.application.edit.1', $jobPoster->id),
210
                    'title' => $jobLang['apply']['apply_link_title'],
211
                    'text' => $jobLang['apply']['apply_link_label'],
212
                ];
213
            }
214
        } elseif (Auth::guest() && $jobPoster->isOpen()) {
215
            $applyButton = [
216
                'href' => route('job.application.edit.1', $jobPoster->id),
217
                'title' => $jobLang['apply']['login_link_title'],
218
                'text' => $jobLang['apply']['login_link_label'],
219
            ];
220
        } else {
221
            $applyButton = [
222
                'href' => null,
223
                'title' => null,
224
                'text' => $jobLang['apply']['job_closed_label'],
225
            ];
226
        }
227
228
        $jpb_release_date = strtotime('2019-08-21 16:18:17');
229
        $job_created_at = strtotime($jobPoster->created_at);
230
231
        $custom_breadcrumbs = [
232
            'home' => route('home'),
233
            'jobs' => route(WhichPortal::prefixRoute('jobs.index')),
234
            $jobPoster->title ?: 'job-title-missing' => route(WhichPortal::prefixRoute('jobs.summary'), $jobPoster),
235
            'preview' => '',
236
        ];
237
238
        // If the poster is part of the Strategic Talent Response dept, use the talent stream template.
239
        // Else, If the job poster is created after the release of the JPB.
240
        // Then, render with updated poster template.
241
        // Else, render with old poster template.
242
        if ($jobPoster->isInStrategicResponseDepartment()) {
243
            return view(
0 ignored issues
show
Bug introduced by
The function view was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

243
            return /** @scrutinizer ignore-call */ view(
Loading history...
244
                'applicant/strategic_response_job_post',
245
                [
246
                    'job_post' => $jobLang,
247
                    'frequencies' => Lang::get('common/lookup/frequency'),
248
                    'skill_template' => Lang::get('common/skills'),
249
                    'job' => $jobPoster,
250
                    'manager' => $jobPoster->manager,
251
                    'criteria' => $criteria,
252
                    'apply_button' => $applyButton,
253
                    'custom_breadcrumbs' => $custom_breadcrumbs,
254
                ]
255
            );
256
        } elseif ($job_created_at > $jpb_release_date) {
257
            // Updated job poster (JPB).
258
            return view(
259
                'applicant/jpb_job_post',
260
                [
261
                    'job_post' => $jobLang,
262
                    'frequencies' => Lang::get('common/lookup/frequency'),
263
                    'skill_template' => Lang::get('common/skills'),
264
                    'job' => $jobPoster,
265
                    'manager' => $jobPoster->manager,
266
                    'criteria' => $criteria,
267
                    'apply_button' => $applyButton,
268
                    'custom_breadcrumbs' => $custom_breadcrumbs,
269
                ]
270
            );
271
        } else {
272
            // Old job poster.
273
            return view(
274
                'applicant/job_post',
275
                [
276
                    'job_post' => $jobLang,
277
                    'frequencies' => Lang::get('common/lookup/frequency'),
278
                    'manager' => $jobPoster->manager,
279
                    'manager_profile_photo_url' => '/images/user.png', // TODO get real photo.
280
                    'team_culture' => $jobPoster->manager->team_culture,
281
                    'work_environment' => $jobPoster->manager->work_environment,
282
                    'workplace_photos' => $workplacePhotos,
283
                    'job' => $jobPoster,
284
                    'criteria' => $criteria,
285
                    'apply_button' => $applyButton,
286
                    'skill_template' => Lang::get('common/skills'),
287
                    'custom_breadcrumbs' => $custom_breadcrumbs,
288
                ]
289
            );
290
        }
291
    }
292
293
    /**
294
     * Display the form for editing an existing Job Poster
295
     * Only allows editing fields that don't appear on the react-built Job Poster Builder.
296
     *
297
     * @param  \Illuminate\Http\Request $request   Incoming request object.
298
     * @param  \App\Models\JobPoster    $jobPoster Job Poster object.
299
     * @return \Illuminate\Http\Response
300
     */
301
    public function edit(Request $request, JobPoster $jobPoster)
302
    {
303
        $manager = $jobPoster->manager;
304
305
        $defaultQuestionManager = new JobPosterDefaultQuestions();
306
        $defaultQuestionManager->initializeQuestionsIfEmpty($jobPoster);
307
308
        return view(
0 ignored issues
show
Bug introduced by
The function view was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

308
        return /** @scrutinizer ignore-call */ view(
Loading history...
309
            'manager/job_create',
310
            [
311
                // Localization Strings.
312
                'job_l10n' => Lang::get('manager/job_edit'),
313
                // Data.
314
                'manager' => $manager,
315
                'job' => $jobPoster,
316
                'form_action_url' => route('admin.jobs.update', $jobPoster),
0 ignored issues
show
Bug introduced by
The function route was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

316
                'form_action_url' => /** @scrutinizer ignore-call */ route('admin.jobs.update', $jobPoster),
Loading history...
317
            ]
318
        );
319
    }
320
321
    /**
322
     * Create a blank job poster for the specified manager
323
     *
324
     * @param  \App\Models\Manager $manager Incoming Manager object.
325
     * @return \Illuminate\Http\Response Job Create view
326
     */
327
    public function createAsManager(Manager $manager)
328
    {
329
        $jobPoster = new JobPoster();
330
        $jobPoster->manager_id = $manager->id;
331
332
        // Save manager-specific info to the job poster - equivalent to the intro step of the JPB
333
        $divisionEn = $manager->getTranslation('division', 'en');
334
        $divisionFr = $manager->getTranslation('division', 'fr');
335
        $jobPoster->fill([
336
            'department_id' => $manager->user->department_id,
337
            'division' => ['en' => $divisionEn],
338
            'division' => ['fr' => $divisionFr],
339
        ]);
340
341
        $jobPoster->save();
342
343
        return redirect()->route('manager.jobs.edit', $jobPoster->id);
0 ignored issues
show
Bug introduced by
The function redirect was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

343
        return /** @scrutinizer ignore-call */ redirect()->route('manager.jobs.edit', $jobPoster->id);
Loading history...
344
    }
345
346
    /**
347
     * Update a resource in storage
348
     * NOTE: Only saves fields that are not on the react-built Job Poster Builder
349
     *
350
     * @param  \Illuminate\Http\Request $request   Incoming request object.
351
     * @param  \App\Models\JobPoster    $jobPoster Optional Job Poster object.
352
     * @return \Illuminate\Http\Response
353
     */
354
    public function store(Request $request, JobPoster $jobPoster)
355
    {
356
        // Don't allow edits for published Job Posters
357
        // Also check auth while we're at it.
358
        $this->authorize('update', $jobPoster);
359
        JobPosterValidator::validateUnpublished($jobPoster);
360
361
        $input = $request->input();
362
363
        if ($jobPoster->manager_id == null) {
364
            $jobPoster->manager_id = $request->user()->manager->id;
365
            $jobPoster->save();
366
        }
367
368
        if ($request->input('question')) {
369
            $validator = Validator::make($request->input('question'), [
370
                '*.question.*' => 'required|string',
371
            ], [
372
                'required' => Lang::get('validation.custom.job_poster_question.required'),
373
                'string' => Lang::get('validation.custom.job_poster_question.string')
374
            ]);
375
376
            if ($validator->fails()) {
377
                $request->session()->flash('errors', $validator->errors());
378
                return redirect(route('admin.jobs.edit', $jobPoster->id));
0 ignored issues
show
Bug introduced by
The function route was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

378
                return redirect(/** @scrutinizer ignore-call */ route('admin.jobs.edit', $jobPoster->id));
Loading history...
Bug introduced by
The function redirect was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

378
                return /** @scrutinizer ignore-call */ redirect(route('admin.jobs.edit', $jobPoster->id));
Loading history...
379
            }
380
        }
381
382
        $this->fillAndSaveJobPosterQuestions($input, $jobPoster, true);
383
384
        return redirect(route('manager.jobs.preview', $jobPoster->id));
385
    }
386
387
    /**
388
     * Fill Job Poster's questions and save
389
     *
390
     * @param  mixed[]               $input     Field values.
391
     * @param  \App\Models\JobPoster $jobPoster Job Poster object.
392
     * @param  boolean               $replace   Remove existing relationships.
393
     * @return void
394
     */
395
    protected function fillAndSaveJobPosterQuestions(array $input, JobPoster $jobPoster, bool $replace): void
396
    {
397
        if ($replace) {
398
            $jobPoster->job_poster_questions()->delete();
399
        }
400
401
        if (!array_key_exists('question', $input) || !is_array($input['question'])) {
402
            return;
403
        }
404
405
        foreach ($input['question'] as $question) {
406
            $jobQuestion = new JobPosterQuestion();
407
            $jobQuestion->job_poster_id = $jobPoster->id;
408
            $jobQuestion->fill(
409
                [
410
                    'question' => [
411
                        'en' => $question['question']['en'],
412
                        'fr' => $question['question']['fr']
413
414
                    ],
415
                    'description' => [
416
                        'en' => $question['description']['en'],
417
                        'fr' => $question['description']['fr']
418
                    ]
419
                ]
420
            );
421
            $jobPoster->save();
422
            $jobQuestion->save();
423
        }
424
    }
425
426
    /**
427
     * Downloads a CSV file with the applicants who have applied to the job poster.
428
     *
429
     * @param  \App\Models\JobPoster $jobPoster Job Poster object.
430
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
431
     */
432
    protected function downloadApplicants(JobPoster $jobPoster)
433
    {
434
        $tables = [];
435
        // The first row in the array represents the names of the columns in the spreadsheet.
436
        $tables[0] = ['Status', 'Applicant Name', 'Email', 'Language'];
437
438
        $application_status_id = ApplicationStatus::where('name', 'submitted')->first()->id;
439
        $applications = JobApplication::where('job_poster_id', $jobPoster->id)
440
            ->where('application_status_id', $application_status_id)
441
            ->get();
442
443
        $index = 1;
444
        foreach ($applications as $application) {
445
            $status = '';
446
            $username = $application->user_name;
447
            $user_email = $application->user_email;
448
            $language = strtoupper($application->preferred_language->name);
449
            // If the applicants veteran status name is NOT 'none' then set status to veteran.
450
            $non_veteran = VeteranStatus::where('name', 'none')->first()->id;
451
            if ($application->veteran_status_id != $non_veteran) {
452
                $status = 'Veteran';
453
            } else {
454
                // Check if the applicant is a canadian citizen.
455
                $canadian_citizen = CitizenshipDeclaration::where('name', 'citizen')->first()->id;
456
                if ($application->citizenship_declaration->id == $canadian_citizen) {
457
                    $status = 'Citizen';
458
                } else {
459
                    $status = 'Non-citizen';
460
                }
461
            }
462
            $tables[$index] = [$status, $username, $user_email, $language];
463
            $index++;
464
        }
465
466
        $filename = $jobPoster->id . '-' . 'applicants-data.csv';
467
468
        // Open file.
469
        $file = fopen($filename, 'w');
470
        // Iterate through tables and add each line to csv file.
471
        foreach ($tables as $line) {
472
            fputcsv($file, $line);
0 ignored issues
show
Bug introduced by
It seems like $file can also be of type false; however, parameter $handle of fputcsv() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

472
            fputcsv(/** @scrutinizer ignore-type */ $file, $line);
Loading history...
473
        }
474
        // Close open file.
475
        fclose($file);
0 ignored issues
show
Bug introduced by
It seems like $file can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

475
        fclose(/** @scrutinizer ignore-type */ $file);
Loading history...
476
477
        $headers = [
478
            'Content-Type' => 'text/csv',
479
            'Content-Disposition' => 'attachment; filename=' . $filename,
480
        ];
481
482
        return Response::download($filename, $filename, $headers);
483
    }
484
}
485