diff --git a/app/Architecture/Providers/AuthServiceProvider.php b/app/Architecture/Providers/AuthServiceProvider.php index 62d21c7..7c7631a 100644 --- a/app/Architecture/Providers/AuthServiceProvider.php +++ b/app/Architecture/Providers/AuthServiceProvider.php @@ -35,5 +35,6 @@ class AuthServiceProvider extends ServiceProvider Gate::define("manageVacationLimits", fn(User $user): bool => $user->role === Role::AdministrativeApprover); Gate::define("generateTimesheet", fn(User $user): bool => $user->role === Role::AdministrativeApprover); Gate::define("listMonthlyUsage", fn(User $user): bool => $user->role === Role::AdministrativeApprover); + Gate::define("manageResumes", fn(User $user): bool => $user->role === Role::AdministrativeApprover); } } diff --git a/app/Infrastructure/Http/Controllers/ResumeController.php b/app/Infrastructure/Http/Controllers/ResumeController.php index 6f4907d..5b60cc5 100644 --- a/app/Infrastructure/Http/Controllers/ResumeController.php +++ b/app/Infrastructure/Http/Controllers/ResumeController.php @@ -20,6 +20,8 @@ class ResumeController extends Controller { public function index(): Response { + $this->authorize("manageResumes"); + $resumes = Resume::query() ->paginate(); @@ -30,6 +32,8 @@ class ResumeController extends Controller public function create(): Response { + $this->authorize("manageResumes"); + $users = User::query() ->orderByProfileField("last_name") ->orderByProfileField("first_name") @@ -43,6 +47,8 @@ class ResumeController extends Controller public function show(Resume $resume, ResumeGenerator $generator): BinaryFileResponseAlias { + $this->authorize("manageResumes"); + $path = $generator->generate($resume); return response() @@ -52,6 +58,8 @@ class ResumeController extends Controller public function store(ResumeRequest $request): RedirectResponse { + $this->authorize("manageResumes"); + $resume = new Resume(); if ($request->hasEmployee()) { @@ -76,6 +84,8 @@ class ResumeController extends Controller public function edit(Resume $resume): Response { + $this->authorize("manageResumes"); + $users = User::query() ->orderByProfileField("last_name") ->orderByProfileField("first_name") @@ -90,6 +100,8 @@ class ResumeController extends Controller public function update(Resume $resume, ResumeRequest $request): RedirectResponse { + $this->authorize("manageResumes"); + if ($request->hasEmployee()) { $resume->user()->associate($request->getEmployee()); } else { @@ -113,6 +125,8 @@ class ResumeController extends Controller public function destroy(Resume $resume): RedirectResponse { + $this->authorize("manageResumes"); + $resume->delete(); return redirect() diff --git a/app/Infrastructure/Http/Middleware/HandleInertiaRequests.php b/app/Infrastructure/Http/Middleware/HandleInertiaRequests.php index 15cb0dd..664c065 100644 --- a/app/Infrastructure/Http/Middleware/HandleInertiaRequests.php +++ b/app/Infrastructure/Http/Middleware/HandleInertiaRequests.php @@ -39,6 +39,7 @@ class HandleInertiaRequests extends Middleware "manageUsers" => $user ? $user->can("manageUsers") : false, "listAllVacationRequests" => $user ? $user->can("listAll", VacationRequest::class) : false, "listMonthlyUsage" => $user ? $user->can("listMonthlyUsage") : false, + "manageResumes" => $user ? $user->can("manageResumes") : false, ], ]; } diff --git a/config/vacation_types.php b/config/vacation_types.php index 806cbbc..4bae98d 100644 --- a/config/vacation_types.php +++ b/config/vacation_types.php @@ -109,7 +109,7 @@ return [ VacationTypeConfigRetriever::KEY_IS_VACATION => true, ], VacationType::Absence->value => [ - VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => true, + VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => false, VacationTypeConfigRetriever::KEY_ADMINISTRATIVE_APPROVAL => false, VacationTypeConfigRetriever::KEY_BILLABLE => false, VacationTypeConfigRetriever::KEY_HAS_LIMIT => false, diff --git a/resources/js/Composables/useLevels.js b/resources/js/Composables/useLevels.js index a08a44a..ef0197f 100644 --- a/resources/js/Composables/useLevels.js +++ b/resources/js/Composables/useLevels.js @@ -35,6 +35,7 @@ const technologyLevels = [ textColor: 'text-blumilk-400', }, ] + const languageLevels = [ { level: 1, @@ -74,9 +75,9 @@ const languageLevels = [ { level: 6, name: 'C2', - activeColor: 'bg-gray-600', + activeColor: 'bg-gray-700', backgroundColor: 'bg-gray-200', - textColor: 'text-gray-600', + textColor: 'text-gray-700', }, ] diff --git a/resources/js/Pages/Resumes/Create.vue b/resources/js/Pages/Resumes/Create.vue index a5898a6..c9f1585 100644 --- a/resources/js/Pages/Resumes/Create.vue +++ b/resources/js/Pages/Resumes/Create.vue @@ -309,7 +309,7 @@ @@ -545,7 +545,7 @@ const languages = [ 'German', ] -const form = useForm({ +const form = useForm('createResume',{ user: props.users.data[0], name: null, educations: [], @@ -597,7 +597,7 @@ function hasAnyErrorInSection(section, index) { function submitResume() { form .transform((data) => ({ - user: data.user.id, + user: data.user?.id, name: data.name, education: data.educations, languages: data.languages.map(language => ({ diff --git a/resources/js/Pages/Resumes/Edit.vue b/resources/js/Pages/Resumes/Edit.vue index 33dffb5..ced18f8 100644 --- a/resources/js/Pages/Resumes/Edit.vue +++ b/resources/js/Pages/Resumes/Edit.vue @@ -309,7 +309,7 @@ @@ -444,10 +444,10 @@ :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`educations.${index}.startDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`educations.${index}.startDate`] }" />

- {{ form.errors[`educations.${index}.startDate`] }} + {{ form.errors[`projects.${index}.startDate`] }}

@@ -467,10 +467,10 @@ :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`educations.${index}.endDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`educations.${index}.endDate`] }" />

- {{ form.errors[`educations.${index}.endDate`] }} + {{ form.errors[`projects.${index}.endDate`] }}

@@ -546,7 +546,7 @@ const languages = [ 'German', ] -const form = useForm({ +const form = useForm(`EditResume:${props.resume.id}`,{ user: props.users.data.find((user) => user.id === props.resume.user) ?? null, name: props.resume.name ?? null , educations: props.resume.education ?? [], @@ -604,7 +604,7 @@ function hasAnyErrorInSection(section, index) { function submitResume() { form .transform((data) => ({ - user: data.user.id, + user: data.user?.id, name: data.name, education: data.educations, languages: data.languages.map(language => ({ diff --git a/resources/js/Shared/MainMenu.vue b/resources/js/Shared/MainMenu.vue index 22a2c05..010c6a7 100644 --- a/resources/js/Shared/MainMenu.vue +++ b/resources/js/Shared/MainMenu.vue @@ -378,7 +378,7 @@ const navigation = computed(() => href: '/resumes', section: 'Resumes', icon: TemplateIcon, - can: true, + can: props.auth.can.manageResumes, }, ].filter(item => item.can)) diff --git a/resources/lang/pl.json b/resources/lang/pl.json index 8485773..24611be 100644 --- a/resources/lang/pl.json +++ b/resources/lang/pl.json @@ -73,5 +73,8 @@ "Key no :number has been taken from :user.": "Klucz nr :number został zabrany użytkownikowi :user.", "Key no :number has been given to :user.": "Klucz nr :number został przekazany użytkownikowi :user.", ":sender gives key no :key to :recipient": ":sender przekazuje klucz nr :key :recipient", - ":recipient takes key no :key from :sender": ":recipient zabiera klucz nr :key :sender" + ":recipient takes key no :key from :sender": ":recipient zabiera klucz nr :key :sender", + "Resume has been updated.": "CV zostało zaktualizowane.", + "Resume has been deleted.": "CV zostało usunięte.", + "Resume has been created.": "CV zostało utworzone." } diff --git a/resources/lang/pl/resume.php b/resources/lang/pl/resume.php index 8521dcf..05385f5 100644 --- a/resources/lang/pl/resume.php +++ b/resources/lang/pl/resume.php @@ -18,4 +18,4 @@ return [ 4 => "Advanced", 5 => "Expert", ], -]; \ No newline at end of file +]; diff --git a/resources/lang/pl/validation.php b/resources/lang/pl/validation.php index 733418d..6fd7629 100644 --- a/resources/lang/pl/validation.php +++ b/resources/lang/pl/validation.php @@ -114,6 +114,43 @@ return [ "uploaded" => "Nie udało się wgrać pliku :attribute.", "url" => "Format pola :attribute jest nieprawidłowy.", "uuid" => "Pole :attribute musi być poprawnym identyfikatorem UUID.", + "custom" => [ + "education.*.school" => [ + "required" => "Nazwa szkoły jest wymagana.", + ], + "education.*.degree" => [ + "required" => "Stopień jest wymagany.", + ], + "education.*.fieldOfStudy" => [ + "required" => "Kierunek jest wymagany.", + ], + "education.*.startDate" => [ + "required" => "Data rozpoczęcia jest wymagana.", + ], + "education.*.endDate" => [ + "required" => "Data zakończenia jest wymagana.", + ], + "languages.*.name" => [ + "distinct" => "Języki nie mogą się powtarzać.", + "required" => "Język jest wymagany.", + ], + "technologies.*.name" => [ + "distinct" => "Technologie nie mogą się powtarzać.", + "required" => "Technologia jest wymagana.", + ], + "projects.*.description" => [ + "required" => "Opis projektu jest wymagany.", + ], + "projects.*.startDate" => [ + "required" => "Data rozpoczęcia jest wymagana.", + ], + "projects.*.endDate" => [ + "required" => "Data zakończenia jest wymagana.", + ], + "projects.*.tasks" => [ + "required" => "Zadania w projekcie są wymagane.", + ], + ], "attributes" => [ "to" => "do", "from" => "od",