Skip to content

Commit 378d0b7

Browse files
authored
Merge pull request #630 from EotvosCollegium/staging
Deploy recent changes
2 parents abc80bd + 1eb5f44 commit 378d0b7

22 files changed

+776
-219
lines changed

app/Http/Controllers/Auth/AdmissionController.php

Lines changed: 85 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
use App\Mail\ApplicationFileUploaded;
88
use App\Mail\ApplicationNoteChanged;
99
use App\Models\Application;
10+
use App\Models\ApplicationWorkshop;
1011
use App\Models\Semester;
12+
use App\Models\SemesterStatus;
1113
use App\Models\User;
1214
use App\Models\RoleUser;
1315
use App\Models\File;
@@ -17,6 +19,7 @@
1719
use App\Utils\HasPeriodicEvent;
1820
use Carbon\Carbon;
1921
use Illuminate\Auth\Access\AuthorizationException;
22+
use Illuminate\Database\Eloquent\Builder;
2023
use Illuminate\Database\Eloquent\Collection;
2124
use Illuminate\Http\RedirectResponse;
2225
use Illuminate\Http\Request;
@@ -178,54 +181,78 @@ public function update(Request $request, Application $application): RedirectResp
178181
return redirect()->back();
179182
}
180183

184+
/**
185+
* Show the finalize page with final names and statistics
186+
*/
187+
public function indexFinalize(): View
188+
{
189+
$this->authorize('finalize', Application::class);
190+
if(!($this->getDeadline() < now())) {
191+
throw new \InvalidArgumentException('The application deadline has not passed yet.');
192+
}
193+
[$admitted, $not_admitted, $users_to_delete] = $this->getApplications();
194+
return view('auth.admission.finalize', [
195+
'semester' => $this->semester(),
196+
'admitted_applications' => $admitted,
197+
'users_to_delete' => $users_to_delete
198+
->with('application')
199+
->orderBy('name')
200+
->get()
201+
]);
202+
}
203+
204+
181205
/**
182206
* Accept and delete applciations.
183207
* @return RedirectResponse
184208
* @throws AuthorizationException
185209
*/
186210
public function finalize(): RedirectResponse
187211
{
188-
// $this->authorize('finalizeApplicationProcess', User::class);
189-
// Cache::forget('collegists');
190-
// $not_handled_applicants = User::query()->withoutGlobalScope('verified')
191-
// ->where('verified', 0)
192-
// ->whereHas('application', function ($query) {
193-
// $query->where('submitted', true);
194-
// })
195-
// ->count();
196-
// if ($not_handled_applicants > 0) {
197-
// return redirect()->back()->with('error', 'Még vannak feldolgozatlan jelentkezések!');
198-
// }
199-
// DB::transaction(function () {
200-
// User::query()->withoutGlobalScope('verified')
201-
// ->where('verified', 0)
202-
// ->whereHas('application', function ($query) {
203-
// $query->where('status', Application::STATUS_ACCEPTED);
204-
// })
205-
// ->update(['verified' => true]);
206-
// $usersToDelete = User::query()->withoutGlobalScope('verified')
207-
// ->where('verified', 0)->whereHas('application');
208-
// foreach ($usersToDelete->get() as $user) {
209-
// if ($user->profilePicture!=null) {
210-
// Storage::delete($user->profilePicture->path);
211-
// $user->profilePicture()->delete();
212-
// }
213-
// }
214-
// $files = File::where('application_id', '!=', null);
215-
// foreach ($files->get() as $file) {
216-
// Storage::delete($file->path);
217-
// }
218-
// $files->delete();
219-
// Application::query()->delete();
220-
// $usersToDelete->forceDelete();
221-
//
222-
// RoleUser::where('role_id', Role::get(Role::APPLICATION_COMMITTEE_MEMBER)->id)->delete();
223-
// RoleUser::where('role_id', Role::get(Role::AGGREGATED_APPLICATION_COMMITTEE_MEMBER)->id)->delete();
224-
// });
225-
//
226-
// Cache::clear();
227-
// return back()->with('message', 'Sikeresen jóváhagyta az elfogadott jelentkezőket');
228-
return back()->with('error', 'Még nincs implementálva.');
212+
$this->authorize('finalize', Application::class);
213+
if(!($this->getDeadline() < now())) {
214+
throw new \InvalidArgumentException('The application deadline has not passed yet.');
215+
}
216+
if(!$this->semester()) {
217+
throw new \InvalidArgumentException('No semester can be retrieved from the application periodic event.');
218+
}
219+
DB::transaction(function () {
220+
[$admitted, $not_admitted, $users_to_delete] = $this->getApplications();
221+
// admit users
222+
foreach ($admitted as $application) {
223+
$application->user->update(['verified' => true]);
224+
if($application->admitted_for_resident_status) {
225+
$application->user->setResident();
226+
} else {
227+
$application->user->setExtern();
228+
}
229+
$application->user->workshops()->sync($application->admittedWorkshops);
230+
$application->user->setStatusFor($this->semester(), SemesterStatus::ACTIVE);
231+
$application->user->internetAccess->extendInternetAccess($this->semester()->getStartDate()->addMonth());
232+
}
233+
// delete data for not admitted users
234+
$files = File::query()
235+
->whereIn('application_id', $not_admitted->pluck('id')) // application files
236+
->orWhereIn('user_id', $not_admitted->pluck('user_id')); // profile pictures
237+
foreach ($files->get() as $file) {
238+
Storage::delete($file->path);
239+
}
240+
$files->delete();
241+
// soft deletes application, keep them for future reference
242+
// (see https://github.com/EotvosCollegium/mars/issues/332#issuecomment-2014058021)
243+
Application::whereIn('id', $admitted->pluck('id'))->delete();
244+
Application::whereNotIn('id', $admitted->pluck('id'))->forceDelete();
245+
ApplicationWorkshop::query()->delete();
246+
247+
// Note: users with not submitted applications will also be deleted
248+
$users_to_delete->forceDelete();
249+
250+
RoleUser::where('role_id', Role::get(Role::APPLICATION_COMMITTEE_MEMBER)->id)->delete();
251+
RoleUser::where('role_id', Role::get(Role::AGGREGATED_APPLICATION_COMMITTEE_MEMBER)->id)->delete();
252+
});
253+
254+
Cache::clear();
255+
return back()->with('message', __('general.successful_modification'));
229256
}
230257

231258

@@ -252,4 +279,21 @@ public function getAccessibleWorkshops(User $user): Collection
252279
}
253280
return Workshop::all();
254281
}
282+
283+
/**
284+
* Helper function to get admittted, not admitted applications and users to delete.
285+
* @return array
286+
*/
287+
private function getApplications()
288+
{
289+
$admitted = Application::query()->with(['user', 'applicationWorkshops'])->admitted()->get()->sortBy('user.name');
290+
$not_admitted = Application::query()->whereNotIn('id', $admitted->pluck('id'))->get();
291+
$users_to_delete_query = User::query()
292+
->withoutGlobalScope('verified')
293+
->whereIn('id', $not_admitted->pluck('user_id'))
294+
//ignore users with any existing role
295+
->whereDoesntHave('roles');
296+
297+
return [$admitted, $not_admitted, $users_to_delete_query];
298+
}
255299
}

app/Http/Controllers/Secretariat/SemesterEvaluationController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public function show()
137137
$this->authorize('fillOrManage', SemesterEvaluation::class);
138138

139139
return view('secretariat.evaluation-form.app', [
140-
'phd' => user()->educationalInformation->studyLines()->currentlyEnrolled()->where('type', 'phd')->exists(),
140+
'phd' => user()->educationalInformation->isSenior(),
141141
'user' => user(),
142142
'faculties' => Faculty::all(),
143143
'workshops' => Workshop::all(),
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace App\Livewire;
4+
5+
use App\Models\Application;
6+
use App\Models\ApplicationWorkshop;
7+
use Carbon\Carbon;
8+
use Livewire\Component;
9+
10+
class ApplicationRoleStatusUpdate extends Component
11+
{
12+
public Application $application;
13+
public Carbon $lastUpdated;
14+
15+
/**
16+
* Mount the component
17+
* @param Application $application
18+
* @return void
19+
*/
20+
public function mount(Application $application)
21+
{
22+
$this->application = $application;
23+
$this->lastUpdated = Carbon::now()->subSeconds(2);
24+
}
25+
26+
/**
27+
* Update whether the applicant has been admitted as resident or not.
28+
* @param $workshop
29+
*/
30+
public function switchResidentRole()
31+
{
32+
$this->authorize('finalize', Application::class);
33+
$this->application->update(['admitted_for_resident_status' => !$this->application->admitted_for_resident_status]);
34+
$this->lastUpdated = Carbon::now();
35+
}
36+
37+
/**
38+
* $this->updated
39+
* @return bool
40+
*/
41+
public function getUpdatedProperty()
42+
{
43+
return $this->lastUpdated > Carbon::now()->subSeconds(2);
44+
}
45+
46+
/**
47+
* Render the component
48+
* @return \Illuminate\View\View
49+
*/
50+
public function render()
51+
{
52+
return view('auth.application.role_status_update_component');
53+
}
54+
}

app/Livewire/ApplicationStatusUpdate.php renamed to app/Livewire/ApplicationWorkshopStatusUpdate.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use Carbon\Carbon;
88
use Livewire\Component;
99

10-
class ApplicationStatusUpdate extends Component
10+
class ApplicationWorkshopStatusUpdate extends Component
1111
{
1212
public Application $application;
1313
public ApplicationWorkshop $workshop;
@@ -32,6 +32,7 @@ public function mount(Application $application, ApplicationWorkshop $workshop)
3232
*/
3333
public function callIn($workshop)
3434
{
35+
$this->authorize('editStatus', [\App\Models\Application::class, $this->workshop->workshop]);
3536
$this->application->applicationWorkshops()->where('workshop_id', $workshop)->update(['called_in' => !$this->workshop->called_in]);
3637
$this->lastUpdated = Carbon::now();
3738
}
@@ -42,6 +43,7 @@ public function callIn($workshop)
4243
*/
4344
public function admit($workshop)
4445
{
46+
$this->authorize('editStatus', [\App\Models\Application::class, $this->workshop->workshop]);
4547
$this->application->applicationWorkshops()->where('workshop_id', $workshop)->update(['admitted' => !$this->workshop->admitted]);
4648
$this->lastUpdated = Carbon::now();
4749
}
@@ -61,6 +63,6 @@ public function getUpdatedProperty()
6163
*/
6264
public function render()
6365
{
64-
return view('auth.application.status_update_component');
66+
return view('auth.application.workshop_status_update_component');
6567
}
6668
}

app/Models/Application.php

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
namespace App\Models;
44

55
use App\Utils\DataCompresser;
6+
use Illuminate\Database\Eloquent\Builder;
67
use Illuminate\Database\Eloquent\Casts\Attribute;
78
use Illuminate\Database\Eloquent\Factories\HasFactory;
89
use Illuminate\Database\Eloquent\Model;
910
use Illuminate\Database\Eloquent\Relations\BelongsTo;
1011
use Illuminate\Database\Eloquent\Relations\HasMany;
1112
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
13+
use Illuminate\Database\Eloquent\SoftDeletes;
1214
use Illuminate\Support\Collection;
13-
use Matrix\Builder;
1415

1516
/**
1617
* App\Models\Application
@@ -19,6 +20,8 @@
1920
* @property Collection $files
2021
* @property boolean $submitted
2122
* @property string $graduation_average
23+
* @property boolean $applied_for_resident_status
24+
* @property boolean $admitted_for_resident_status
2225
* @property array $semester_average
2326
* @property array $language_exam
2427
* @property array $competition
@@ -64,11 +67,13 @@
6467
class Application extends Model
6568
{
6669
use HasFactory;
70+
use SoftDeletes;
6771

6872
protected $fillable = [
6973
'user_id',
7074
'submitted',
7175
'applied_for_resident_status',
76+
'admitted_for_resident_status',
7277
'graduation_average',
7378
'semester_average',
7479
'language_exam',
@@ -86,7 +91,8 @@ class Application extends Model
8691

8792
protected $casts = [
8893
'submitted' => 'bool',
89-
'applied_for_resident_status' => 'bool'
94+
'applied_for_resident_status' => 'bool',
95+
'admitted_for_resident_status' => 'bool'
9096
];
9197

9298
public const QUESTION_1 = [
@@ -126,6 +132,7 @@ public function applicationWorkshops(): HasMany
126132
return $this->hasMany(ApplicationWorkshop::class);
127133
}
128134

135+
129136
/**
130137
* The Workshop models that the user applied for.
131138
* @return HasManyThrough
@@ -142,6 +149,14 @@ public function appliedWorkshops(): HasManyThrough
142149
);
143150
}
144151

152+
/**
153+
* The Workshop models that the user admitted to.
154+
*/
155+
public function admittedWorkshops(): HasManyThrough
156+
{
157+
return $this->appliedWorkshops()->where('application_workshops.admitted', true);
158+
}
159+
145160
/**
146161
* Uploaded files
147162
* @return HasMany
@@ -151,12 +166,45 @@ public function files(): HasMany
151166
return $this->hasMany('App\Models\File');
152167
}
153168

169+
170+
/*
171+
|--------------------------------------------------------------------------
172+
| Local scopes
173+
|--------------------------------------------------------------------------
174+
*/
175+
176+
/**
177+
* Scope a query to only include applications admitted to any workshop.
178+
* @param Builder $query
179+
* @return Builder
180+
*/
181+
public function scopeAdmitted(Builder $query): Builder
182+
{
183+
return $query->whereHas('applicationWorkshops', function ($query) {
184+
$query->where('admitted', true);
185+
});
186+
}
187+
188+
154189
/*
155190
|--------------------------------------------------------------------------
156191
| Accessors & Mutators
157192
|--------------------------------------------------------------------------
158193
*/
159194

195+
/**
196+
* Get a bool whether the applicant has been admitted to any workshops.
197+
*
198+
* @return Attribute
199+
*/
200+
protected function admitted(): Attribute
201+
{
202+
return Attribute::make(
203+
get: fn () => $this->applicationWorkshops()->where('admitted', true)->exists(),
204+
);
205+
}
206+
207+
160208
/**
161209
* Get a bool whether the applicant has been called in by any workshops.
162210
*

0 commit comments

Comments
 (0)