* wip * wip * wip * wip * fix * wip * wip * fix * fix * cs fix * #116 - fix * #116 - changed home-office icon * Apply suggestions from code review Co-authored-by: Krzysztof Rewak <krzysztof.rewak@gmail.com> * #116 - cr fix * #116 - cs fix * #116 - cs fix * Apply suggestions from code review Co-authored-by: Ewelina Lasowy <56546832+EwelinaLasowy@users.noreply.github.com> * #5 - bump codestyle Co-authored-by: EwelinaLasowy <ewelina.lasowy@blumilk.pl> Co-authored-by: Krzysztof Rewak <krzysztof.rewak@gmail.com> Co-authored-by: Ewelina Lasowy <56546832+EwelinaLasowy@users.noreply.github.com>
This commit is contained in:
		| @@ -16,7 +16,6 @@ class ExceptionHandler extends Handler | ||||
|         "password", | ||||
|         "password_confirmation", | ||||
|     ]; | ||||
|  | ||||
|     protected array $handleByInertia = [ | ||||
|         Response::HTTP_INTERNAL_SERVER_ERROR, | ||||
|         Response::HTTP_SERVICE_UNAVAILABLE, | ||||
|   | ||||
| @@ -4,13 +4,24 @@ declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Architecture\Providers; | ||||
|  | ||||
| use Illuminate\Contracts\Foundation\Application; | ||||
| use Illuminate\Notifications\ChannelManager; | ||||
| use Illuminate\Support\Carbon; | ||||
| use Illuminate\Support\Facades\Notification; | ||||
| use Illuminate\Support\ServiceProvider; | ||||
| use Toby\Infrastructure\Slack\Channels\SlackApiChannel; | ||||
|  | ||||
| class AppServiceProvider extends ServiceProvider | ||||
| { | ||||
|     public function register(): void | ||||
|     { | ||||
|         Notification::resolved(function (ChannelManager $service): void { | ||||
|             $service->extend("slack", fn(Application $app): SlackApiChannel => $app->make(SlackApiChannel::class)); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     public function boot(): void | ||||
|     { | ||||
|         Carbon::macro("toDisplayString", fn() => $this->translatedFormat("d.m.Y")); | ||||
|         Carbon::macro("toDisplayString", fn(): string => $this->translatedFormat("d.m.Y")); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -30,10 +30,10 @@ class AuthServiceProvider extends ServiceProvider | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         Gate::define("manageUsers", fn(User $user) => $user->role === Role::AdministrativeApprover); | ||||
|         Gate::define("manageHolidays", fn(User $user) => $user->role === Role::AdministrativeApprover); | ||||
|         Gate::define("manageVacationLimits", fn(User $user) => $user->role === Role::AdministrativeApprover); | ||||
|         Gate::define("generateTimesheet", fn(User $user) => $user->role === Role::AdministrativeApprover); | ||||
|         Gate::define("listMonthlyUsage", fn(User $user) => $user->role === Role::AdministrativeApprover); | ||||
|         Gate::define("manageUsers", fn(User $user): bool => $user->role === Role::AdministrativeApprover); | ||||
|         Gate::define("manageHolidays", fn(User $user): bool => $user->role === Role::AdministrativeApprover); | ||||
|         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); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -28,6 +28,6 @@ class RouteServiceProvider extends ServiceProvider | ||||
|  | ||||
|     protected function configureRateLimiting(): void | ||||
|     { | ||||
|         RateLimiter::for("api", fn(Request $request) => Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip())); | ||||
|         RateLimiter::for("api", fn(Request $request): Limit => Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip())); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -53,7 +53,6 @@ class CreateAction | ||||
|         $vacationRequest->save(); | ||||
|  | ||||
|         $days = $this->vacationDaysCalculator->calculateDays( | ||||
|             $vacationRequest->yearPeriod, | ||||
|             $vacationRequest->from, | ||||
|             $vacationRequest->to, | ||||
|         ); | ||||
|   | ||||
| @@ -57,6 +57,6 @@ class CalendarGenerator | ||||
|             ->approved() | ||||
|             ->with("vacationRequest") | ||||
|             ->get() | ||||
|             ->groupBy(fn(Vacation $vacation) => $vacation->date->toDateString()); | ||||
|             ->groupBy(fn(Vacation $vacation): string => $vacation->date->toDateString()); | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										49
									
								
								app/Domain/DailySummaryRetriever.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								app/Domain/DailySummaryRetriever.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Domain; | ||||
|  | ||||
| use Illuminate\Support\Carbon; | ||||
| use Illuminate\Support\Collection; | ||||
| use Toby\Domain\Enums\VacationType; | ||||
| use Toby\Eloquent\Models\User; | ||||
| use Toby\Eloquent\Models\Vacation; | ||||
|  | ||||
| class DailySummaryRetriever | ||||
| { | ||||
|     public function __construct( | ||||
|         protected VacationTypeConfigRetriever $configRetriever, | ||||
|     ) {} | ||||
|  | ||||
|     public function getAbsences(Carbon $date): Collection | ||||
|     { | ||||
|         return Vacation::query() | ||||
|             ->with(["user", "vacationRequest"]) | ||||
|             ->whereDate("date", $date) | ||||
|             ->approved() | ||||
|             ->whereTypes( | ||||
|                 VacationType::all()->filter(fn(VacationType $type): bool => $this->configRetriever->isVacation($type)), | ||||
|             ) | ||||
|             ->get(); | ||||
|     } | ||||
|  | ||||
|     public function getRemoteDays(Carbon $date): Collection | ||||
|     { | ||||
|         return Vacation::query() | ||||
|             ->with(["user", "vacationRequest"]) | ||||
|             ->whereDate("date", $date) | ||||
|             ->approved() | ||||
|             ->whereTypes( | ||||
|                 VacationType::all()->filter(fn(VacationType $type): bool => !$this->configRetriever->isVacation($type)), | ||||
|             ) | ||||
|             ->get(); | ||||
|     } | ||||
|  | ||||
|     public function getBirthdays(Carbon $date): Collection | ||||
|     { | ||||
|         return User::query() | ||||
|             ->whereRelation("profile", "birthday", $date) | ||||
|             ->get(); | ||||
|     } | ||||
| } | ||||
| @@ -21,7 +21,7 @@ enum EmploymentForm: string | ||||
|         $cases = collect(EmploymentForm::cases()); | ||||
|  | ||||
|         return $cases->map( | ||||
|             fn(EmploymentForm $enum) => [ | ||||
|             fn(EmploymentForm $enum): array => [ | ||||
|                 "label" => $enum->label(), | ||||
|                 "value" => $enum->value, | ||||
|             ], | ||||
|   | ||||
| @@ -21,7 +21,7 @@ enum Role: string | ||||
|         $cases = collect(Role::cases()); | ||||
|  | ||||
|         return $cases->map( | ||||
|             fn(Role $enum) => [ | ||||
|             fn(Role $enum): array => [ | ||||
|                 "label" => $enum->label(), | ||||
|                 "value" => $enum->value, | ||||
|             ], | ||||
|   | ||||
| @@ -30,7 +30,7 @@ enum VacationType: string | ||||
|         $cases = VacationType::all(); | ||||
|  | ||||
|         return $cases->map( | ||||
|             fn(VacationType $enum) => [ | ||||
|             fn(VacationType $enum): array => [ | ||||
|                 "label" => $enum->label(), | ||||
|                 "value" => $enum->value, | ||||
|             ], | ||||
|   | ||||
							
								
								
									
										11
									
								
								app/Domain/Notifications/Channels.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/Domain/Notifications/Channels.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Domain\Notifications; | ||||
|  | ||||
| class Channels | ||||
| { | ||||
|     public const MAIL = "mail"; | ||||
|     public const SLACK = "slack"; | ||||
| } | ||||
							
								
								
									
										42
									
								
								app/Domain/Notifications/KeyHasBeenGivenNotification.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								app/Domain/Notifications/KeyHasBeenGivenNotification.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Domain\Notifications; | ||||
|  | ||||
| use Illuminate\Bus\Queueable; | ||||
| use Illuminate\Notifications\Notification; | ||||
| use Toby\Eloquent\Models\User; | ||||
|  | ||||
| class KeyHasBeenGivenNotification extends Notification | ||||
| { | ||||
|     use Queueable; | ||||
|  | ||||
|     public function __construct( | ||||
|         protected User $sender, | ||||
|         protected User $recipient, | ||||
|     ) {} | ||||
|  | ||||
|     public function via(): array | ||||
|     { | ||||
|         return [Channels::SLACK]; | ||||
|     } | ||||
|  | ||||
|     public function toSlack(Notifiable $notifiable): string | ||||
|     { | ||||
|         return __(":sender gives key no :key to :recipient", [ | ||||
|             "sender" => $this->getName($this->sender), | ||||
|             "recipient" => $this->getName($this->recipient), | ||||
|             "key" => $notifiable->id, | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     protected function getName(User $user): string | ||||
|     { | ||||
|         if ($user->profile->slack_id !== null) { | ||||
|             return "<@{$user->profile->slack_id}>"; | ||||
|         } | ||||
|  | ||||
|         return $user->profile->full_name; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										42
									
								
								app/Domain/Notifications/KeyHasBeenTakenNotification.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								app/Domain/Notifications/KeyHasBeenTakenNotification.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Domain\Notifications; | ||||
|  | ||||
| use Illuminate\Bus\Queueable; | ||||
| use Illuminate\Notifications\Notification; | ||||
| use Toby\Eloquent\Models\User; | ||||
|  | ||||
| class KeyHasBeenTakenNotification extends Notification | ||||
| { | ||||
|     use Queueable; | ||||
|  | ||||
|     public function __construct( | ||||
|         protected User $recipient, | ||||
|         protected User $sender, | ||||
|     ) {} | ||||
|  | ||||
|     public function via(): array | ||||
|     { | ||||
|         return [Channels::SLACK]; | ||||
|     } | ||||
|  | ||||
|     public function toSlack(Notifiable $notifiable): string | ||||
|     { | ||||
|         return __(":recipient takes key no :key from :sender", [ | ||||
|             "recipient" => $this->getName($this->recipient), | ||||
|             "sender" => $this->getName($this->sender), | ||||
|             "key" => $notifiable->id, | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     protected function getName(User $user): string | ||||
|     { | ||||
|         if ($user->profile->slack_id !== null) { | ||||
|             return "<@{$user->profile->slack_id}>"; | ||||
|         } | ||||
|  | ||||
|         return $user->profile->full_name; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										10
									
								
								app/Domain/Notifications/Notifiable.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/Domain/Notifications/Notifiable.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Domain\Notifications; | ||||
|  | ||||
| interface Notifiable | ||||
| { | ||||
|     public function notify($instance); | ||||
| } | ||||
| @@ -20,7 +20,17 @@ class VacationRequestCreatedNotification extends Notification | ||||
|  | ||||
|     public function via(): array | ||||
|     { | ||||
|         return ["mail"]; | ||||
|         return [Channels::MAIL, Channels::SLACK]; | ||||
|     } | ||||
|  | ||||
|     public function toSlack(): string | ||||
|     { | ||||
|         $url = route("vacation.requests.show", ["vacationRequest" => $this->vacationRequest->id]); | ||||
|  | ||||
|         return implode("\n", [ | ||||
|             $this->buildDescription(), | ||||
|             "<${url}|Zobacz szczegóły>", | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -80,18 +90,16 @@ class VacationRequestCreatedNotification extends Notification | ||||
|     protected function buildDescription(): string | ||||
|     { | ||||
|         $name = $this->vacationRequest->name; | ||||
|         $appName = config("app.name"); | ||||
|  | ||||
|         if ($this->vacationRequest->creator()->is($this->vacationRequest->user)) { | ||||
|             return __("The vacation request :title has been created correctly in the :appName.", [ | ||||
|             return __("The vacation request :title from user :user has been created successfully.", [ | ||||
|                 "user" => $this->vacationRequest->user->profile->full_name, | ||||
|                 "title" => $name, | ||||
|                 "appName" => $appName, | ||||
|             ]); | ||||
|         } | ||||
|  | ||||
|         return __("The vacation request :title has been created correctly by user :creator on your behalf in the :appName.", [ | ||||
|         return __("The vacation request :title has been created successfully by user :creator on your behalf.", [ | ||||
|             "title" => $this->vacationRequest->name, | ||||
|             "appName" => $appName, | ||||
|             "creator" => $this->vacationRequest->creator->profile->full_name, | ||||
|         ]); | ||||
|     } | ||||
|   | ||||
| @@ -22,7 +22,17 @@ class VacationRequestStatusChangedNotification extends Notification | ||||
|  | ||||
|     public function via(): array | ||||
|     { | ||||
|         return ["mail"]; | ||||
|         return [Channels::MAIL, Channels::SLACK]; | ||||
|     } | ||||
|  | ||||
|     public function toSlack(): string | ||||
|     { | ||||
|         $url = route("vacation.requests.show", ["vacationRequest" => $this->vacationRequest->id]); | ||||
|  | ||||
|         return implode("\n", [ | ||||
|             $this->buildDescription(), | ||||
|             "<${url}|Zobacz szczegóły>", | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -43,27 +53,17 @@ class VacationRequestStatusChangedNotification extends Notification | ||||
|     protected function buildMailMessage(string $url): MailMessage | ||||
|     { | ||||
|         $user = $this->user->profile->first_name; | ||||
|         $title = $this->vacationRequest->name; | ||||
|         $type = $this->vacationRequest->type->label(); | ||||
|         $status = $this->vacationRequest->state->label(); | ||||
|         $from = $this->vacationRequest->from->toDisplayString(); | ||||
|         $to = $this->vacationRequest->to->toDisplayString(); | ||||
|         $days = $this->vacationRequest->vacations()->count(); | ||||
|         $requester = $this->vacationRequest->user->profile->full_name; | ||||
|  | ||||
|         return (new MailMessage()) | ||||
|             ->greeting(__("Hi :user!", [ | ||||
|                 "user" => $user, | ||||
|             ])) | ||||
|             ->subject(__("Vacation request :title has been :status", [ | ||||
|                 "title" => $title, | ||||
|                 "status" => $status, | ||||
|             ])) | ||||
|             ->line(__("The vacation request :title from user :requester has been :status.", [ | ||||
|                 "title" => $title, | ||||
|                 "requester" => $requester, | ||||
|                 "status" => $status, | ||||
|             ])) | ||||
|             ->subject($this->buildSubject()) | ||||
|             ->line($this->buildDescription()) | ||||
|             ->line(__("Vacation type: :type", [ | ||||
|                 "type" => $type, | ||||
|             ])) | ||||
| @@ -74,4 +74,21 @@ class VacationRequestStatusChangedNotification extends Notification | ||||
|             ])) | ||||
|             ->action(__("Click here for details"), $url); | ||||
|     } | ||||
|  | ||||
|     protected function buildSubject(): string | ||||
|     { | ||||
|         return __("Vacation request :title has been :status", [ | ||||
|             "title" => $this->vacationRequest->name, | ||||
|             "status" => $this->vacationRequest->state->label(), | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     protected function buildDescription(): string | ||||
|     { | ||||
|         return __("The vacation request :title from user :requester has been :status.", [ | ||||
|             "title" => $this->vacationRequest->name, | ||||
|             "requester" => $this->vacationRequest->user->profile->full_name, | ||||
|             "status" => $this->vacationRequest->state->label(), | ||||
|         ]); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -23,7 +23,17 @@ class VacationRequestWaitsForApprovalNotification extends Notification | ||||
|  | ||||
|     public function via(): array | ||||
|     { | ||||
|         return ["mail"]; | ||||
|         return [Channels::MAIL, Channels::SLACK]; | ||||
|     } | ||||
|  | ||||
|     public function toSlack(): string | ||||
|     { | ||||
|         $url = route("vacation.requests.show", ["vacationRequest" => $this->vacationRequest->id]); | ||||
|  | ||||
|         return implode("\n", [ | ||||
|             $this->buildDescription(), | ||||
|             "<${url}|Zobacz szczegóły>", | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -99,4 +109,3 @@ class VacationRequestWaitsForApprovalNotification extends Notification | ||||
|         ]); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ class PolishHolidaysRetriever | ||||
|  | ||||
|     protected function prepareHolidays(array $holidays): Collection | ||||
|     { | ||||
|         return collect($holidays)->map(fn(Holiday $holiday) => [ | ||||
|         return collect($holidays)->map(fn(Holiday $holiday): array => [ | ||||
|             "name" => $holiday->getName([static::LANG_KEY]), | ||||
|             "date" => Carbon::createFromTimestamp($holiday->getTimestamp()), | ||||
|         ])->values(); | ||||
|   | ||||
| @@ -18,7 +18,7 @@ class TimesheetExport implements WithMultipleSheets | ||||
|     public function sheets(): array | ||||
|     { | ||||
|         return $this->users | ||||
|             ->map(fn(User $user) => new TimesheetPerUserSheet($user, $this->month, $this->types)) | ||||
|             ->map(fn(User $user): TimesheetPerUserSheet => new TimesheetPerUserSheet($user, $this->month, $this->types)) | ||||
|             ->toArray(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -193,8 +193,8 @@ class TimesheetPerUserSheet implements WithTitle, WithHeadings, WithEvents, With | ||||
|             ->get() | ||||
|             ->groupBy( | ||||
|                 [ | ||||
|                     fn(Vacation $vacation) => $vacation->date->toDateString(), | ||||
|                     fn(Vacation $vacation) => $vacation->vacationRequest->type->value, | ||||
|                     fn(Vacation $vacation): string => $vacation->date->toDateString(), | ||||
|                     fn(Vacation $vacation): string => $vacation->vacationRequest->type->value, | ||||
|                 ], | ||||
|             ); | ||||
|     } | ||||
|   | ||||
| @@ -42,8 +42,8 @@ class UserVacationStatsRetriever | ||||
|                     ->states(VacationRequestStatesRetriever::successStates()), | ||||
|             ) | ||||
|             ->get() | ||||
|             ->groupBy(fn(Vacation $vacation) => strtolower($vacation->date->englishMonth)) | ||||
|             ->map(fn(Collection $items) => $items->count()); | ||||
|             ->groupBy(fn(Vacation $vacation): string => strtolower($vacation->date->englishMonth)) | ||||
|             ->map(fn(Collection $items): int => $items->count()); | ||||
|     } | ||||
|  | ||||
|     public function getPendingVacationDays(User $user, YearPeriod $yearPeriod): int | ||||
| @@ -107,13 +107,13 @@ class UserVacationStatsRetriever | ||||
|     { | ||||
|         $types = VacationType::all(); | ||||
|  | ||||
|         return $types->filter(fn(VacationType $type) => $this->configRetriever->hasLimit($type)); | ||||
|         return $types->filter(fn(VacationType $type): bool => $this->configRetriever->hasLimit($type)); | ||||
|     } | ||||
|  | ||||
|     protected function getNotLimitableVacationTypes(): Collection | ||||
|     { | ||||
|         $types = VacationType::all(); | ||||
|  | ||||
|         return $types->filter(fn(VacationType $type) => !$this->configRetriever->hasLimit($type)); | ||||
|         return $types->filter(fn(VacationType $type): bool => !$this->configRetriever->hasLimit($type)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -11,9 +11,10 @@ use Toby\Eloquent\Models\YearPeriod; | ||||
|  | ||||
| class VacationDaysCalculator | ||||
| { | ||||
|     public function calculateDays(YearPeriod $yearPeriod, CarbonInterface $from, CarbonInterface $to): Collection | ||||
|     public function calculateDays(CarbonInterface $from, CarbonInterface $to): Collection | ||||
|     { | ||||
|         $period = CarbonPeriod::create($from, $to); | ||||
|         $yearPeriod = YearPeriod::findByYear($from->year); | ||||
|         $holidays = $yearPeriod->holidays()->pluck("date"); | ||||
|  | ||||
|         $validDays = new Collection(); | ||||
|   | ||||
| @@ -29,7 +29,7 @@ class DoesNotExceedLimitRule implements VacationRequestRule | ||||
|  | ||||
|         $limit = $this->getUserVacationLimit($vacationRequest->user, $vacationRequest->yearPeriod); | ||||
|         $vacationDays = $this->getVacationDaysWithLimit($vacationRequest->user, $vacationRequest->yearPeriod); | ||||
|         $estimatedDays = $this->vacationDaysCalculator->calculateDays($vacationRequest->yearPeriod, $vacationRequest->from, $vacationRequest->to)->count(); | ||||
|         $estimatedDays = $this->vacationDaysCalculator->calculateDays($vacationRequest->from, $vacationRequest->to)->count(); | ||||
|  | ||||
|         return $limit >= ($vacationDays + $estimatedDays); | ||||
|     } | ||||
| @@ -64,6 +64,6 @@ class DoesNotExceedLimitRule implements VacationRequestRule | ||||
|     { | ||||
|         $types = VacationType::all(); | ||||
|  | ||||
|         return $types->filter(fn(VacationType $type) => $this->configRetriever->hasLimit($type)); | ||||
|         return $types->filter(fn(VacationType $type): bool => $this->configRetriever->hasLimit($type)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -16,7 +16,7 @@ class MinimumOneVacationDayRule implements VacationRequestRule | ||||
|     public function check(VacationRequest $vacationRequest): bool | ||||
|     { | ||||
|         return $this->vacationDaysCalculator | ||||
|             ->calculateDays($vacationRequest->yearPeriod, $vacationRequest->from, $vacationRequest->to) | ||||
|             ->calculateDays($vacationRequest->from, $vacationRequest->to) | ||||
|             ->isNotEmpty(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -9,5 +9,6 @@ use Toby\Eloquent\Models\VacationRequest; | ||||
| interface VacationRequestRule | ||||
| { | ||||
|     public function check(VacationRequest $vacationRequest): bool; | ||||
|  | ||||
|     public function errorMessage(): string; | ||||
| } | ||||
|   | ||||
| @@ -19,7 +19,7 @@ class VacationTypeCanBeSelected implements VacationRequestRule | ||||
|         $employmentForm = $vacationRequest->user->profile->employment_form; | ||||
|  | ||||
|         $availableTypes = VacationType::all() | ||||
|             ->filter(fn(VacationType $type) => $this->configRetriever->isAvailableFor($type, $employmentForm)); | ||||
|             ->filter(fn(VacationType $type): bool => $this->configRetriever->isAvailableFor($type, $employmentForm)); | ||||
|  | ||||
|         return $availableTypes->contains($vacationRequest->type); | ||||
|     } | ||||
|   | ||||
| @@ -35,7 +35,7 @@ class YearPeriodRetriever | ||||
|  | ||||
|         $years = YearPeriod::all(); | ||||
|  | ||||
|         $navigation = $years->map(fn(YearPeriod $yearPeriod) => $this->toNavigation($yearPeriod)); | ||||
|         $navigation = $years->map(fn(YearPeriod $yearPeriod): array => $this->toNavigation($yearPeriod)); | ||||
|  | ||||
|         return [ | ||||
|             "current" => $this->toNavigation($current), | ||||
|   | ||||
| @@ -21,7 +21,6 @@ class Holiday extends Model | ||||
|     use HasFactory; | ||||
|  | ||||
|     protected $guarded = []; | ||||
|  | ||||
|     protected $casts = [ | ||||
|         "date" => "date", | ||||
|     ]; | ||||
|   | ||||
| @@ -8,14 +8,17 @@ use Database\Factories\KeyFactory; | ||||
| use Illuminate\Database\Eloquent\Factories\HasFactory; | ||||
| use Illuminate\Database\Eloquent\Model; | ||||
| use Illuminate\Database\Eloquent\Relations\BelongsTo; | ||||
| use Illuminate\Notifications\Notifiable; | ||||
| use Toby\Domain\Notifications\Notifiable as NotifiableInterface; | ||||
|  | ||||
| /** | ||||
|  * @property int $id | ||||
|  * @property User $user | ||||
|  */ | ||||
| class Key extends Model | ||||
| class Key extends Model implements NotifiableInterface | ||||
| { | ||||
|     use HasFactory; | ||||
|     use Notifiable; | ||||
|  | ||||
|     protected $guarded = []; | ||||
|  | ||||
| @@ -24,6 +27,11 @@ class Key extends Model | ||||
|         return $this->belongsTo(User::class); | ||||
|     } | ||||
|  | ||||
|     public function routeNotificationForSlack(): string | ||||
|     { | ||||
|         return config("services.slack.default_channel"); | ||||
|     } | ||||
|  | ||||
|     protected static function newFactory(): KeyFactory | ||||
|     { | ||||
|         return KeyFactory::new(); | ||||
|   | ||||
| @@ -19,6 +19,7 @@ use Toby\Eloquent\Helpers\ColorGenerator; | ||||
|  * @property string $position | ||||
|  * @property EmploymentForm $employment_form | ||||
|  * @property Carbon $employment_date | ||||
|  * @property Carbon $birthday | ||||
|  */ | ||||
| class Profile extends Model | ||||
| { | ||||
| @@ -26,12 +27,11 @@ class Profile extends Model | ||||
|     use HasAvatar; | ||||
|  | ||||
|     protected $primaryKey = "user_id"; | ||||
|  | ||||
|     protected $guarded = []; | ||||
|  | ||||
|     protected $casts = [ | ||||
|         "employment_form" => EmploymentForm::class, | ||||
|         "employment_date" => "date", | ||||
|         "birthday" => "date", | ||||
|     ]; | ||||
|  | ||||
|     public function user(): BelongsTo | ||||
|   | ||||
| @@ -15,6 +15,7 @@ use Illuminate\Notifications\Notifiable; | ||||
| use Illuminate\Support\Collection; | ||||
| use Toby\Domain\Enums\EmploymentForm; | ||||
| use Toby\Domain\Enums\Role; | ||||
| use Toby\Domain\Notifications\Notifiable as NotifiableInterface; | ||||
|  | ||||
| /** | ||||
|  * @property int $id | ||||
| @@ -26,25 +27,22 @@ use Toby\Domain\Enums\Role; | ||||
|  * @property Collection $vacationRequests | ||||
|  * @property Collection $vacations | ||||
|  */ | ||||
| class User extends Authenticatable | ||||
| class User extends Authenticatable implements NotifiableInterface | ||||
| { | ||||
|     use HasFactory; | ||||
|     use Notifiable; | ||||
|     use SoftDeletes; | ||||
|  | ||||
|     protected $guarded = []; | ||||
|  | ||||
|     protected $casts = [ | ||||
|         "role" => Role::class, | ||||
|         "last_active_at" => "datetime", | ||||
|         "employment_form" => EmploymentForm::class, | ||||
|         "employment_date" => "date", | ||||
|     ]; | ||||
|  | ||||
|     protected $hidden = [ | ||||
|         "remember_token", | ||||
|     ]; | ||||
|  | ||||
|     protected $with = [ | ||||
|         "profile", | ||||
|     ]; | ||||
| @@ -102,7 +100,7 @@ class User extends Authenticatable | ||||
|             ->where("email", "ILIKE", "%{$text}%") | ||||
|             ->orWhereRelation( | ||||
|                 "profile", | ||||
|                 fn(Builder $query) => $query | ||||
|                 fn(Builder $query): Builder => $query | ||||
|                     ->where("first_name", "ILIKE", "%{$text}%") | ||||
|                     ->orWhere("last_name", "ILIKE", "%{$text}%"), | ||||
|             ); | ||||
| @@ -125,6 +123,11 @@ class User extends Authenticatable | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public function routeNotificationForSlack() | ||||
|     { | ||||
|         return $this->profile->slack_id; | ||||
|     } | ||||
|  | ||||
|     protected static function newFactory(): UserFactory | ||||
|     { | ||||
|         return UserFactory::new(); | ||||
|   | ||||
| @@ -41,7 +41,6 @@ class VacationRequest extends Model | ||||
|     use HasStates; | ||||
|  | ||||
|     protected $guarded = []; | ||||
|  | ||||
|     protected $casts = [ | ||||
|         "type" => VacationType::class, | ||||
|         "state" => VacationRequestState::class, | ||||
|   | ||||
| @@ -22,7 +22,6 @@ class VacationRequestActivity extends Model | ||||
|     use HasFactory; | ||||
|  | ||||
|     protected $guarded = []; | ||||
|  | ||||
|     protected $casts = [ | ||||
|         "from" => VacationRequestState::class, | ||||
|         "to" => VacationRequestState::class, | ||||
|   | ||||
| @@ -0,0 +1,79 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Console\Commands; | ||||
|  | ||||
| use Carbon\CarbonInterface; | ||||
| use Illuminate\Console\Command; | ||||
| use Illuminate\Support\Carbon; | ||||
| use Illuminate\Support\Collection; | ||||
| use Illuminate\Support\Facades\Http; | ||||
| use Toby\Domain\DailySummaryRetriever; | ||||
| use Toby\Eloquent\Models\Holiday; | ||||
| use Toby\Infrastructure\Slack\Elements\AbsencesAttachment; | ||||
| use Toby\Infrastructure\Slack\Elements\BirthdaysAttachment; | ||||
| use Toby\Infrastructure\Slack\Elements\RemotesAttachment; | ||||
|  | ||||
| class SendDailySummaryToSlack extends Command | ||||
| { | ||||
|     protected $signature = "toby:slack:daily-summary {--f|force}"; | ||||
|     protected $description = "Sent daily summary to slack"; | ||||
|  | ||||
|     public function handle(DailySummaryRetriever $dailySummaryRetriever): void | ||||
|     { | ||||
|         $now = Carbon::today(); | ||||
|  | ||||
|         if (!$this->option("force") && !$this->shouldHandle($now)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         $attachments = new Collection([ | ||||
|             new AbsencesAttachment($dailySummaryRetriever->getAbsences($now)), | ||||
|             new RemotesAttachment($dailySummaryRetriever->getRemoteDays($now)), | ||||
|             new BirthdaysAttachment($dailySummaryRetriever->getBirthdays($now)), | ||||
|         ]); | ||||
|  | ||||
|         Http::withToken($this->getSlackClientToken()) | ||||
|             ->post($this->getUrl(), [ | ||||
|                 "channel" => $this->getSlackChannel(), | ||||
|                 "text" => "Podsumowanie dla dnia {$now->toDisplayString()}", | ||||
|                 "attachments" => $attachments, | ||||
|             ]); | ||||
|     } | ||||
|  | ||||
|     protected function shouldHandle(CarbonInterface $day): bool | ||||
|     { | ||||
|         $holidays = Holiday::query()->whereDate("date", $day)->pluck("date"); | ||||
|  | ||||
|         if ($day->isWeekend()) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if ($holidays->contains($day)) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     protected function getUrl(): string | ||||
|     { | ||||
|         return "{$this->getSlackBaseUrl()}/chat.postMessage"; | ||||
|     } | ||||
|  | ||||
|     protected function getSlackBaseUrl(): ?string | ||||
|     { | ||||
|         return config("services.slack.url"); | ||||
|     } | ||||
|  | ||||
|     protected function getSlackClientToken(): ?string | ||||
|     { | ||||
|         return config("services.slack.client_token"); | ||||
|     } | ||||
|  | ||||
|     protected function getSlackChannel(): ?string | ||||
|     { | ||||
|         return config("services.slack.default_channel"); | ||||
|     } | ||||
| } | ||||
| @@ -14,8 +14,8 @@ class CalculateVacationDaysController extends Controller | ||||
| { | ||||
|     public function __invoke(CalculateVacationDaysRequest $request, VacationDaysCalculator $calculator): JsonResponse | ||||
|     { | ||||
|         $days = $calculator->calculateDays($request->yearPeriod(), $request->from(), $request->to()); | ||||
|         $days = $calculator->calculateDays($request->from(), $request->to()); | ||||
|  | ||||
|         return new JsonResponse($days->map(fn(Carbon $day) => $day->toDateString())->all()); | ||||
|         return new JsonResponse($days->map(fn(Carbon $day): string => $day->toDateString())->all()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -21,8 +21,8 @@ class GetAvailableVacationTypesController extends Controller | ||||
|         $user = User::query()->find($request->get("user")); | ||||
|  | ||||
|         $types = VacationType::all() | ||||
|             ->filter(fn(VacationType $type) => $configRetriever->isAvailableFor($type, $user->profile->employment_form)) | ||||
|             ->map(fn(VacationType $type) => [ | ||||
|             ->filter(fn(VacationType $type): bool => $configRetriever->isAvailableFor($type, $user->profile->employment_form)) | ||||
|             ->map(fn(VacationType $type): array => [ | ||||
|                 "label" => $type->label(), | ||||
|                 "value" => $type->value, | ||||
|             ]) | ||||
|   | ||||
| @@ -7,12 +7,11 @@ namespace Toby\Infrastructure\Http\Controllers; | ||||
| use Illuminate\Http\Request; | ||||
| use Illuminate\Support\Carbon; | ||||
| use Inertia\Response; | ||||
| use Toby\Domain\Enums\VacationType; | ||||
| use Toby\Domain\DailySummaryRetriever; | ||||
| use Toby\Domain\UserVacationStatsRetriever; | ||||
| use Toby\Domain\VacationRequestStatesRetriever; | ||||
| use Toby\Domain\VacationTypeConfigRetriever; | ||||
| use Toby\Eloquent\Helpers\YearPeriodRetriever; | ||||
| use Toby\Eloquent\Models\Vacation; | ||||
| use Toby\Eloquent\Models\VacationRequest; | ||||
| use Toby\Infrastructure\Http\Resources\HolidayResource; | ||||
| use Toby\Infrastructure\Http\Resources\VacationRequestResource; | ||||
| @@ -25,24 +24,14 @@ class DashboardController extends Controller | ||||
|         YearPeriodRetriever $yearPeriodRetriever, | ||||
|         UserVacationStatsRetriever $vacationStatsRetriever, | ||||
|         VacationTypeConfigRetriever $configRetriever, | ||||
|         DailySummaryRetriever $dailySummaryRetriever, | ||||
|     ): Response { | ||||
|         $user = $request->user(); | ||||
|         $now = Carbon::now(); | ||||
|         $yearPeriod = $yearPeriodRetriever->selected(); | ||||
|  | ||||
|         $absences = Vacation::query() | ||||
|             ->with(["user", "vacationRequest"]) | ||||
|             ->whereDate("date", $now) | ||||
|             ->approved() | ||||
|             ->whereTypes(VacationType::all()->filter(fn(VacationType $type) => $configRetriever->isVacation($type))) | ||||
|             ->get(); | ||||
|  | ||||
|         $remoteDays = Vacation::query() | ||||
|             ->with(["user", "vacationRequest"]) | ||||
|             ->whereDate("date", $now) | ||||
|             ->approved() | ||||
|             ->whereTypes(VacationType::all()->filter(fn(VacationType $type) => !$configRetriever->isVacation($type))) | ||||
|             ->get(); | ||||
|         $absences = $dailySummaryRetriever->getAbsences($now); | ||||
|         $remoteDays = $dailySummaryRetriever->getRemoteDays($now); | ||||
|  | ||||
|         if ($user->can("listAll", VacationRequest::class)) { | ||||
|             $vacationRequests = $yearPeriod->vacationRequests() | ||||
|   | ||||
| @@ -8,6 +8,8 @@ use Illuminate\Auth\Access\AuthorizationException; | ||||
| use Illuminate\Http\Request; | ||||
| use Inertia\Response; | ||||
| use Symfony\Component\HttpFoundation\RedirectResponse; | ||||
| use Toby\Domain\Notifications\KeyHasBeenGivenNotification; | ||||
| use Toby\Domain\Notifications\KeyHasBeenTakenNotification; | ||||
| use Toby\Eloquent\Models\Key; | ||||
| use Toby\Eloquent\Models\User; | ||||
| use Toby\Infrastructure\Http\Requests\GiveKeyRequest; | ||||
| @@ -60,6 +62,8 @@ class KeysController extends Controller | ||||
|  | ||||
|         $key->save(); | ||||
|  | ||||
|         $key->notify(new KeyHasBeenTakenNotification($request->user(), $previousUser)); | ||||
|  | ||||
|         return redirect() | ||||
|             ->back() | ||||
|             ->with("success", __("Key no :number has been taken from :user.", [ | ||||
| @@ -81,6 +85,8 @@ class KeysController extends Controller | ||||
|  | ||||
|         $key->save(); | ||||
|  | ||||
|         $key->notify(new KeyHasBeenGivenNotification($request->user(), $recipient)); | ||||
|  | ||||
|         return redirect() | ||||
|             ->back() | ||||
|             ->with("success", __("Key no :number has been given to :user.", [ | ||||
|   | ||||
| @@ -35,8 +35,10 @@ class TimesheetController extends Controller | ||||
|  | ||||
|         $types = VacationType::all() | ||||
|             ->filter( | ||||
|                 fn(VacationType $type) => $configRetriever->isAvailableFor($type, EmploymentForm::EmploymentContract) | ||||
|                     && $configRetriever->isVacation($type), | ||||
|                 fn(VacationType $type): bool => $configRetriever->isAvailableFor( | ||||
|                     $type, | ||||
|                     EmploymentForm::EmploymentContract, | ||||
|                 ) && $configRetriever->isVacation($type), | ||||
|             ); | ||||
|  | ||||
|         $filename = "{$carbonMonth->translatedFormat("F Y")}.xlsx"; | ||||
|   | ||||
| @@ -30,7 +30,7 @@ class VacationLimitController extends Controller | ||||
|             ->sortBy(fn(VacationLimit $limit): string => "{$limit->user->profile->last_name} {$limit->user->profile->first_name}") | ||||
|             ->values(); | ||||
|  | ||||
|         $limitsResource = $limits->map(fn(VacationLimit $limit) => [ | ||||
|         $limitsResource = $limits->map(fn(VacationLimit $limit): array => [ | ||||
|             "id" => $limit->id, | ||||
|             "user" => new UserResource($limit->user), | ||||
|             "hasVacation" => $limit->hasVacation(), | ||||
|   | ||||
| @@ -40,7 +40,6 @@ class Kernel extends HttpKernel | ||||
|         TrimStrings::class, | ||||
|         ConvertEmptyStringsToNull::class, | ||||
|     ]; | ||||
|  | ||||
|     protected $middlewareGroups = [ | ||||
|         "web" => [ | ||||
|             EncryptCookies::class, | ||||
| @@ -58,7 +57,6 @@ class Kernel extends HttpKernel | ||||
|             SubstituteBindings::class, | ||||
|         ], | ||||
|     ]; | ||||
|  | ||||
|     protected $routeMiddleware = [ | ||||
|         "auth" => Authenticate::class, | ||||
|         "auth.basic" => AuthenticateWithBasicAuth::class, | ||||
|   | ||||
| @@ -32,7 +32,7 @@ class HandleInertiaRequests extends Middleware | ||||
|     { | ||||
|         $user = $request->user(); | ||||
|  | ||||
|         return fn() => [ | ||||
|         return fn(): array => [ | ||||
|             "user" => $user ? new UserResource($user) : null, | ||||
|             "can" => [ | ||||
|                 "manageVacationLimits" => $user ? $user->can("manageVacationLimits") : false, | ||||
| @@ -45,7 +45,7 @@ class HandleInertiaRequests extends Middleware | ||||
|  | ||||
|     protected function getFlashData(Request $request): Closure | ||||
|     { | ||||
|         return fn() => [ | ||||
|         return fn(): array => [ | ||||
|             "success" => $request->session()->get("success"), | ||||
|             "error" => $request->session()->get("error"), | ||||
|             "info" => $request->session()->get("info"), | ||||
|   | ||||
| @@ -22,6 +22,8 @@ class UserRequest extends FormRequest | ||||
|             "position" => ["required"], | ||||
|             "employmentForm" => ["required", new Enum(EmploymentForm::class)], | ||||
|             "employmentDate" => ["required", "date_format:Y-m-d"], | ||||
|             "birthday" => ["nullable", "date_format:Y-m-d"], | ||||
|             "slackId" => [], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
| @@ -41,6 +43,8 @@ class UserRequest extends FormRequest | ||||
|             "position" => $this->get("position"), | ||||
|             "employment_form" => $this->get("employmentForm"), | ||||
|             "employment_date" => $this->get("employmentDate"), | ||||
|             "birthday" => $this->get("birthday"), | ||||
|             "slack_id" => $this->get("slackId"), | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -21,6 +21,8 @@ class UserFormDataResource extends JsonResource | ||||
|             "position" => $this->profile->position, | ||||
|             "employmentForm" => $this->profile->employment_form, | ||||
|             "employmentDate" => $this->profile->employment_date->toDateString(), | ||||
|             "birthday" => $this->profile->birthday?->toDateString(), | ||||
|             "slackId" => $this->profile->slack_id, | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										36
									
								
								app/Infrastructure/Slack/Channels/SlackApiChannel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								app/Infrastructure/Slack/Channels/SlackApiChannel.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Channels; | ||||
|  | ||||
| use Illuminate\Http\Client\Response; | ||||
| use Illuminate\Notifications\Notification; | ||||
| use Illuminate\Support\Facades\Http; | ||||
| use Toby\Domain\Notifications\Notifiable; | ||||
|  | ||||
| class SlackApiChannel | ||||
| { | ||||
|     public function send(Notifiable $notifiable, Notification $notification): Response | ||||
|     { | ||||
|         $baseUrl = $this->getBaseUrl(); | ||||
|         $url = "{$baseUrl}/chat.postMessage"; | ||||
|         $channel = $notifiable->routeNotificationFor("slack", $notification); | ||||
|  | ||||
|         return Http::withToken($this->getClientToken()) | ||||
|             ->post($url, [ | ||||
|                 "channel" => $channel, | ||||
|                 "text" => $notification->toSlack($notifiable), | ||||
|             ]); | ||||
|     } | ||||
|  | ||||
|     protected function getClientToken(): string | ||||
|     { | ||||
|         return config("services.slack.client_token"); | ||||
|     } | ||||
|  | ||||
|     protected function getBaseUrl(): string | ||||
|     { | ||||
|         return config("services.slack.url"); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										56
									
								
								app/Infrastructure/Slack/Controller.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								app/Infrastructure/Slack/Controller.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack; | ||||
|  | ||||
| use Exception; | ||||
| use Illuminate\Http\Request as IlluminateRequest; | ||||
| use Illuminate\Http\Response as IlluminateResponse; | ||||
| use Illuminate\Support\Collection; | ||||
| use Illuminate\Validation\ValidationException; | ||||
| use Spatie\SlashCommand\Attachment; | ||||
| use Spatie\SlashCommand\Controller as SlackController; | ||||
| use Spatie\SlashCommand\Exceptions\InvalidRequest; | ||||
| use Spatie\SlashCommand\Exceptions\RequestCouldNotBeHandled; | ||||
| use Spatie\SlashCommand\Exceptions\SlackSlashCommandException; | ||||
| use Spatie\SlashCommand\Response; | ||||
|  | ||||
| class Controller extends SlackController | ||||
| { | ||||
|     /** | ||||
|      * @throws InvalidRequest|RequestCouldNotBeHandled | ||||
|      */ | ||||
|     public function getResponse(IlluminateRequest $request): IlluminateResponse | ||||
|     { | ||||
|         $this->verifyWithSigning($request); | ||||
|  | ||||
|         $handler = $this->determineHandler(); | ||||
|  | ||||
|         try { | ||||
|             $response = $handler->handle($this->request); | ||||
|         } catch (SlackSlashCommandException $exception) { | ||||
|             $response = $exception->getResponse($this->request); | ||||
|         } catch (ValidationException $exception) { | ||||
|             $response = $this->prepareValidationResponse($exception); | ||||
|         } catch (Exception $exception) { | ||||
|             $response = $this->convertToResponse($exception); | ||||
|         } | ||||
|  | ||||
|         return $response->getIlluminateResponse(); | ||||
|     } | ||||
|  | ||||
|     protected function prepareValidationResponse(ValidationException $exception): Response | ||||
|     { | ||||
|         $errors = (new Collection($exception->errors())) | ||||
|             ->map( | ||||
|                 fn(array $message): Attachment => Attachment::create() | ||||
|                     ->setColor("danger") | ||||
|                     ->setText($message[0]), | ||||
|             ); | ||||
|  | ||||
|         return Response::create($this->request) | ||||
|             ->withText(":x: Polecenie `/{$this->request->command} {$this->request->text}` jest niepoprawne:") | ||||
|             ->withAttachments($errors->all()); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										22
									
								
								app/Infrastructure/Slack/Elements/AbsencesAttachment.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/Infrastructure/Slack/Elements/AbsencesAttachment.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Elements; | ||||
|  | ||||
| use Illuminate\Support\Collection; | ||||
| use Toby\Eloquent\Models\Vacation; | ||||
|  | ||||
| class AbsencesAttachment extends ListAttachment | ||||
| { | ||||
|     public function __construct(Collection $absences) | ||||
|     { | ||||
|         parent::__construct(); | ||||
|  | ||||
|         $this | ||||
|             ->setTitle("Nieobecności :palm_tree:") | ||||
|             ->setColor("#eab308") | ||||
|             ->setItems($absences->map(fn(Vacation $vacation): string => $vacation->user->profile->full_name)) | ||||
|             ->setEmptyText("Wszyscy dzisiaj pracują :muscle:"); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								app/Infrastructure/Slack/Elements/Attachment.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								app/Infrastructure/Slack/Elements/Attachment.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Elements; | ||||
|  | ||||
| use Illuminate\Contracts\Support\Arrayable; | ||||
| use Spatie\SlashCommand\Attachment as BaseAttachment; | ||||
|  | ||||
| class Attachment extends BaseAttachment implements Arrayable | ||||
| { | ||||
| } | ||||
							
								
								
									
										22
									
								
								app/Infrastructure/Slack/Elements/BirthdaysAttachment.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/Infrastructure/Slack/Elements/BirthdaysAttachment.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Elements; | ||||
|  | ||||
| use Illuminate\Support\Collection; | ||||
| use Toby\Eloquent\Models\User; | ||||
|  | ||||
| class BirthdaysAttachment extends ListAttachment | ||||
| { | ||||
|     public function __construct(Collection $birthdays) | ||||
|     { | ||||
|         parent::__construct(); | ||||
|  | ||||
|         $this | ||||
|             ->setTitle("Urodziny :birthday:") | ||||
|             ->setColor("#3c5f97") | ||||
|             ->setItems($birthdays->map(fn(User $user): string => $user->profile->full_name)) | ||||
|             ->setEmptyText("Dzisiaj nikt nie ma urodzin :cry:"); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										21
									
								
								app/Infrastructure/Slack/Elements/KeysAttachment.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/Infrastructure/Slack/Elements/KeysAttachment.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Elements; | ||||
|  | ||||
| use Illuminate\Support\Collection; | ||||
| use Toby\Eloquent\Models\Key; | ||||
|  | ||||
| class KeysAttachment extends ListAttachment | ||||
| { | ||||
|     public function __construct(Collection $keys) | ||||
|     { | ||||
|         parent::__construct(); | ||||
|  | ||||
|         $this | ||||
|             ->setColor("#3c5f97") | ||||
|             ->setItems($keys->map(fn(Key $key): string => "Klucz nr {$key->id} - <@{$key->user->profile->slack_id}>")) | ||||
|             ->setEmptyText("Nie ma żadnych kluczy w tobym"); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										36
									
								
								app/Infrastructure/Slack/Elements/ListAttachment.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								app/Infrastructure/Slack/Elements/ListAttachment.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Elements; | ||||
|  | ||||
| use Illuminate\Support\Collection; | ||||
|  | ||||
| class ListAttachment extends Attachment | ||||
| { | ||||
|     protected Collection $items; | ||||
|     protected string $emptyText = ""; | ||||
|  | ||||
|     public function setItems(Collection $items): static | ||||
|     { | ||||
|         $this->items = $items; | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     public function setEmptyText(string $emptyText): static | ||||
|     { | ||||
|         $this->emptyText = $emptyText; | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     public function toArray(): array | ||||
|     { | ||||
|         $fields = parent::toArray(); | ||||
|  | ||||
|         return array_merge($fields, [ | ||||
|             "text" => $this->items->isNotEmpty() ? $this->items->implode("\n") : $this->emptyText, | ||||
|         ]); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										22
									
								
								app/Infrastructure/Slack/Elements/RemotesAttachment.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/Infrastructure/Slack/Elements/RemotesAttachment.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Elements; | ||||
|  | ||||
| use Illuminate\Support\Collection; | ||||
| use Toby\Eloquent\Models\Vacation; | ||||
|  | ||||
| class RemotesAttachment extends ListAttachment | ||||
| { | ||||
|     public function __construct(Collection $remoteDays) | ||||
|     { | ||||
|         parent::__construct(); | ||||
|  | ||||
|         $this | ||||
|             ->setTitle("Praca zdalna :house_with_garden:") | ||||
|             ->setColor("#527aba") | ||||
|             ->setItems($remoteDays->map(fn(Vacation $vacation): string => $vacation->user->profile->full_name)) | ||||
|             ->setEmptyText("Wszyscy dzisiaj są w biurze :boom:"); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,11 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Exceptions; | ||||
|  | ||||
| use Spatie\SlashCommand\Exceptions\SlackSlashCommandException; | ||||
|  | ||||
| class UserNotFoundException extends SlackSlashCommandException | ||||
| { | ||||
| } | ||||
							
								
								
									
										35
									
								
								app/Infrastructure/Slack/Handlers/CatchAll.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								app/Infrastructure/Slack/Handlers/CatchAll.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Handlers; | ||||
|  | ||||
| use Spatie\SlashCommand\Handlers\BaseHandler; | ||||
| use Spatie\SlashCommand\Request; | ||||
| use Spatie\SlashCommand\Response; | ||||
| use Toby\Infrastructure\Slack\Elements\Attachment; | ||||
| use Toby\Infrastructure\Slack\Traits\ListsHandlers; | ||||
|  | ||||
| class CatchAll extends BaseHandler | ||||
| { | ||||
|     use ListsHandlers; | ||||
|  | ||||
|     public function canHandle(Request $request): bool | ||||
|     { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public function handle(Request $request): Response | ||||
|     { | ||||
|         $handlers = $this->findAvailableHandlers(); | ||||
|         $attachmentFields = $this->mapHandlersToAttachments($handlers); | ||||
|  | ||||
|         return $this->respondToSlack(":x: Nie rozpoznaję polecenia. Lista wszystkich poleceń:") | ||||
|             ->withAttachment( | ||||
|                 Attachment::create() | ||||
|                     ->setColor("danger") | ||||
|                     ->useMarkdown() | ||||
|                     ->setFields($attachmentFields), | ||||
|             ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										36
									
								
								app/Infrastructure/Slack/Handlers/DailySummary.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								app/Infrastructure/Slack/Handlers/DailySummary.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Handlers; | ||||
|  | ||||
| use Illuminate\Support\Carbon; | ||||
| use Illuminate\Support\Collection; | ||||
| use Spatie\SlashCommand\Request; | ||||
| use Spatie\SlashCommand\Response; | ||||
| use Toby\Domain\DailySummaryRetriever; | ||||
| use Toby\Infrastructure\Slack\Elements\AbsencesAttachment; | ||||
| use Toby\Infrastructure\Slack\Elements\BirthdaysAttachment; | ||||
| use Toby\Infrastructure\Slack\Elements\RemotesAttachment; | ||||
|  | ||||
| class DailySummary extends SignatureHandler | ||||
| { | ||||
|     protected $signature = "toby dzisiaj"; | ||||
|     protected $description = "Codzienne podsumowanie"; | ||||
|  | ||||
|     public function handle(Request $request): Response | ||||
|     { | ||||
|         $dailySummaryRetriever = app()->make(DailySummaryRetriever::class); | ||||
|  | ||||
|         $now = Carbon::today(); | ||||
|  | ||||
|         $attachments = new Collection([ | ||||
|             new AbsencesAttachment($dailySummaryRetriever->getAbsences($now)), | ||||
|             new RemotesAttachment($dailySummaryRetriever->getRemoteDays($now)), | ||||
|             new BirthdaysAttachment($dailySummaryRetriever->getBirthdays($now)), | ||||
|         ]); | ||||
|  | ||||
|         return $this->respondToSlack("Podsumowanie dla dnia {$now->toDisplayString()}") | ||||
|             ->withAttachments($attachments->all()); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										71
									
								
								app/Infrastructure/Slack/Handlers/GiveKeysTo.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								app/Infrastructure/Slack/Handlers/GiveKeysTo.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Handlers; | ||||
|  | ||||
| use Illuminate\Validation\ValidationException; | ||||
| use Spatie\SlashCommand\Request; | ||||
| use Spatie\SlashCommand\Response; | ||||
| use Toby\Domain\Notifications\KeyHasBeenGivenNotification; | ||||
| use Toby\Eloquent\Models\Key; | ||||
| use Toby\Infrastructure\Slack\Exceptions\UserNotFoundException; | ||||
| use Toby\Infrastructure\Slack\Rules\SlackUserExistsRule; | ||||
| use Toby\Infrastructure\Slack\Traits\FindsUserBySlackId; | ||||
|  | ||||
| class GiveKeysTo extends SignatureHandler | ||||
| { | ||||
|     use FindsUserBySlackId; | ||||
|  | ||||
|     protected $signature = "toby klucze:dla {user}"; | ||||
|     protected $description = "Przekaż klucze wskazanemu użytkownikowi"; | ||||
|  | ||||
|     /** | ||||
|      * @throws UserNotFoundException | ||||
|      * @throws ValidationException | ||||
|      */ | ||||
|     public function handle(Request $request): Response | ||||
|     { | ||||
|         ["user" => $from] = $this->validate(); | ||||
|  | ||||
|         $authUser = $this->findUserBySlackIdOrFail($request->userId); | ||||
|         $user = $this->findUserBySlackId($from); | ||||
|  | ||||
|         /** @var Key $key */ | ||||
|         $key = $authUser->keys()->first(); | ||||
|  | ||||
|         if (!$key) { | ||||
|             throw ValidationException::withMessages(["key" => "Nie masz żadnego klucza do przekazania"]); | ||||
|         } | ||||
|  | ||||
|         if ($user->is($authUser)) { | ||||
|             throw ValidationException::withMessages([ | ||||
|                 "key" => "Nie możesz przekazać sobie kluczy :dzban:", | ||||
|             ]); | ||||
|         } | ||||
|  | ||||
|         $key->user()->associate($user); | ||||
|  | ||||
|         $key->save(); | ||||
|  | ||||
|         $key->notify(new KeyHasBeenGivenNotification($authUser, $user)); | ||||
|  | ||||
|         return $this->respondToSlack( | ||||
|             ":white_check_mark: Klucz nr {$key->id} został przekazany użytkownikowi <@{$user->profile->slack_id}>", | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     protected function getRules(): array | ||||
|     { | ||||
|         return [ | ||||
|             "user" => ["required", new SlackUserExistsRule()], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     protected function getMessages(): array | ||||
|     { | ||||
|         return [ | ||||
|             "user.required" => "Musisz podać użytkownika, któremu chcesz przekazać klucze", | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										33
									
								
								app/Infrastructure/Slack/Handlers/Help.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								app/Infrastructure/Slack/Handlers/Help.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Handlers; | ||||
|  | ||||
| use Spatie\SlashCommand\Request; | ||||
| use Spatie\SlashCommand\Response; | ||||
| use Toby\Infrastructure\Slack\Elements\Attachment; | ||||
| use Toby\Infrastructure\Slack\Traits\ListsHandlers; | ||||
|  | ||||
| class Help extends SignatureHandler | ||||
| { | ||||
|     use ListsHandlers; | ||||
|  | ||||
|     protected $signature = "toby pomoc"; | ||||
|     protected $description = "Wyświetl wszystkie dostępne polecenia"; | ||||
|  | ||||
|     public function handle(Request $request): Response | ||||
|     { | ||||
|         $handlers = $this->findAvailableHandlers(); | ||||
|  | ||||
|         $attachmentFields = $this->mapHandlersToAttachments($handlers); | ||||
|  | ||||
|         return $this->respondToSlack("Dostępne polecenia:") | ||||
|             ->withAttachment( | ||||
|                 Attachment::create() | ||||
|                     ->setColor("good") | ||||
|                     ->useMarkdown() | ||||
|                     ->setFields($attachmentFields), | ||||
|             ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								app/Infrastructure/Slack/Handlers/HomeOffice.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								app/Infrastructure/Slack/Handlers/HomeOffice.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Handlers; | ||||
|  | ||||
| use Illuminate\Support\Carbon; | ||||
| use Spatie\SlashCommand\Request; | ||||
| use Spatie\SlashCommand\Response; | ||||
| use Toby\Domain\Actions\VacationRequest\CreateAction; | ||||
| use Toby\Domain\Enums\VacationType; | ||||
| use Toby\Eloquent\Models\User; | ||||
| use Toby\Eloquent\Models\YearPeriod; | ||||
| use Toby\Infrastructure\Slack\Traits\FindsUserBySlackId; | ||||
|  | ||||
| class HomeOffice extends SignatureHandler | ||||
| { | ||||
|     use FindsUserBySlackId; | ||||
|  | ||||
|     protected $signature = "toby zdalnie"; | ||||
|     protected $description = "Pracuj dzisiaj zdalnie"; | ||||
|  | ||||
|     public function handle(Request $request): Response | ||||
|     { | ||||
|         $user = $this->findUserBySlackId($request->userId); | ||||
|  | ||||
|         $this->createRemoteday($user, Carbon::today()); | ||||
|  | ||||
|         return $this->respondToSlack(":white_check_mark: Pracujesz dzisiaj zdalnie"); | ||||
|     } | ||||
|  | ||||
|     protected function createRemoteday(User $user, Carbon $date): void | ||||
|     { | ||||
|         $yearPeriod = YearPeriod::findByYear($date->year); | ||||
|  | ||||
|         app(CreateAction::class)->execute([ | ||||
|             "user_id" => $user->id, | ||||
|             "type" => VacationType::HomeOffice, | ||||
|             "from" => $date, | ||||
|             "to" => $date, | ||||
|             "year_period_id" => $yearPeriod->id, | ||||
|             "flow_skipped" => false, | ||||
|         ], $user); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										26
									
								
								app/Infrastructure/Slack/Handlers/KeyList.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								app/Infrastructure/Slack/Handlers/KeyList.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Handlers; | ||||
|  | ||||
| use Spatie\SlashCommand\Request; | ||||
| use Spatie\SlashCommand\Response; | ||||
| use Toby\Eloquent\Models\Key; | ||||
| use Toby\Infrastructure\Slack\Elements\KeysAttachment; | ||||
|  | ||||
| class KeyList extends SignatureHandler | ||||
| { | ||||
|     protected $signature = "toby klucze"; | ||||
|     protected $description = "Lista wszystkich kluczy"; | ||||
|  | ||||
|     public function handle(Request $request): Response | ||||
|     { | ||||
|         $keys = Key::query() | ||||
|             ->orderBy("id") | ||||
|             ->get(); | ||||
|  | ||||
|         return $this->respondToSlack("Lista kluczy :key:") | ||||
|             ->withAttachment(new KeysAttachment($keys)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										26
									
								
								app/Infrastructure/Slack/Handlers/SignatureHandler.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								app/Infrastructure/Slack/Handlers/SignatureHandler.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Handlers; | ||||
|  | ||||
| use Illuminate\Support\Facades\Validator; | ||||
| use Spatie\SlashCommand\Handlers\SignatureHandler as BaseSignatureHandler; | ||||
|  | ||||
| abstract class SignatureHandler extends BaseSignatureHandler | ||||
| { | ||||
|     public function validate() | ||||
|     { | ||||
|         return Validator::validate($this->getArguments(), $this->getRules(), $this->getMessages()); | ||||
|     } | ||||
|  | ||||
|     protected function getRules(): array | ||||
|     { | ||||
|         return []; | ||||
|     } | ||||
|  | ||||
|     protected function getMessages(): array | ||||
|     { | ||||
|         return []; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										70
									
								
								app/Infrastructure/Slack/Handlers/TakeKeysFrom.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								app/Infrastructure/Slack/Handlers/TakeKeysFrom.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Handlers; | ||||
|  | ||||
| use Illuminate\Validation\ValidationException; | ||||
| use Spatie\SlashCommand\Request; | ||||
| use Spatie\SlashCommand\Response; | ||||
| use Toby\Domain\Notifications\KeyHasBeenTakenNotification; | ||||
| use Toby\Eloquent\Models\Key; | ||||
| use Toby\Infrastructure\Slack\Exceptions\UserNotFoundException; | ||||
| use Toby\Infrastructure\Slack\Rules\SlackUserExistsRule; | ||||
| use Toby\Infrastructure\Slack\Traits\FindsUserBySlackId; | ||||
|  | ||||
| class TakeKeysFrom extends SignatureHandler | ||||
| { | ||||
|     use FindsUserBySlackId; | ||||
|  | ||||
|     protected $signature = "toby klucze:od {user}"; | ||||
|     protected $description = "Zabierz klucze wskazanemu użytkownikowi"; | ||||
|  | ||||
|     /** | ||||
|      * @throws UserNotFoundException|ValidationException | ||||
|      */ | ||||
|     public function handle(Request $request): Response | ||||
|     { | ||||
|         ["user" => $from] = $this->validate(); | ||||
|  | ||||
|         $authUser = $this->findUserBySlackIdOrFail($request->userId); | ||||
|         $user = $this->findUserBySlackId($from); | ||||
|  | ||||
|         /** @var Key $key */ | ||||
|         $key = $user->keys()->first(); | ||||
|  | ||||
|         if (!$key) { | ||||
|             throw ValidationException::withMessages([ | ||||
|                 "key" => "Użytkownik <@{$user->profile->slack_id}> nie ma żadnych kluczy", | ||||
|             ]); | ||||
|         } | ||||
|  | ||||
|         if ($key->user()->is($authUser)) { | ||||
|             throw ValidationException::withMessages([ | ||||
|                 "key" => "Nie możesz zabrać sobie kluczy :dzban:", | ||||
|             ]); | ||||
|         } | ||||
|  | ||||
|         $key->user()->associate($authUser); | ||||
|  | ||||
|         $key->save(); | ||||
|  | ||||
|         $key->notify(new KeyHasBeenTakenNotification($authUser, $user)); | ||||
|  | ||||
|         return $this->respondToSlack(":white_check_mark: Klucz nr {$key->id} został zabrany użytkownikowi <@{$user->profile->slack_id}>"); | ||||
|     } | ||||
|  | ||||
|     protected function getRules(): array | ||||
|     { | ||||
|         return [ | ||||
|             "user" => ["required", new SlackUserExistsRule()], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     protected function getMessages(): array | ||||
|     { | ||||
|         return [ | ||||
|             "user.required" => "Musisz podać użytkownika, któremu chcesz zabrać klucze", | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										24
									
								
								app/Infrastructure/Slack/Rules/SlackUserExistsRule.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								app/Infrastructure/Slack/Rules/SlackUserExistsRule.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Rules; | ||||
|  | ||||
| use Illuminate\Contracts\Validation\Rule; | ||||
| use Illuminate\Support\Str; | ||||
| use Toby\Eloquent\Models\Profile; | ||||
|  | ||||
| class SlackUserExistsRule implements Rule | ||||
| { | ||||
|     public function passes($attribute, $value): bool | ||||
|     { | ||||
|         $slackId = Str::between($value, "<@", "|"); | ||||
|  | ||||
|         return Profile::query()->where("slack_id", $slackId)->exists(); | ||||
|     } | ||||
|  | ||||
|     public function message(): string | ||||
|     { | ||||
|         return "Użytkownik :input nie istnieje w tobym"; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										43
									
								
								app/Infrastructure/Slack/Traits/FindsUserBySlackId.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								app/Infrastructure/Slack/Traits/FindsUserBySlackId.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Traits; | ||||
|  | ||||
| use Illuminate\Support\Str; | ||||
| use Toby\Eloquent\Models\User; | ||||
| use Toby\Infrastructure\Slack\Exceptions\UserNotFoundException; | ||||
|  | ||||
| trait FindsUserBySlackId | ||||
| { | ||||
|     protected function findUserBySlackId(string $slackId): ?User | ||||
|     { | ||||
|         $id = $this->prepareSlackIdFromString($slackId); | ||||
|  | ||||
|         /** @var User $user */ | ||||
|         $user = User::query() | ||||
|             ->whereRelation("profile", "slack_id", $id) | ||||
|             ->first(); | ||||
|  | ||||
|         return $user; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @throws UserNotFoundException | ||||
|      */ | ||||
|     protected function findUserBySlackIdOrFail(string $slackId): ?User | ||||
|     { | ||||
|         $user = $this->findUserBySlackId($slackId); | ||||
|  | ||||
|         if (!$user) { | ||||
|             throw new UserNotFoundException("Użytkownik {$slackId} nie istnieje w tobym"); | ||||
|         } | ||||
|  | ||||
|         return $user; | ||||
|     } | ||||
|  | ||||
|     protected function prepareSlackIdFromString(string $slackId): string | ||||
|     { | ||||
|         return Str::between($slackId, "<@", "|"); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										46
									
								
								app/Infrastructure/Slack/Traits/ListsHandlers.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								app/Infrastructure/Slack/Traits/ListsHandlers.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Infrastructure\Slack\Traits; | ||||
|  | ||||
| use Illuminate\Support\Collection; | ||||
| use Illuminate\Support\Str; | ||||
| use Spatie\SlashCommand\AttachmentField; | ||||
| use Spatie\SlashCommand\Handlers\BaseHandler; | ||||
| use Spatie\SlashCommand\Handlers\SignatureHandler; | ||||
| use Spatie\SlashCommand\Handlers\SignatureParts; | ||||
| use Spatie\SlashCommand\HandlesSlashCommand; | ||||
|  | ||||
| trait ListsHandlers | ||||
| { | ||||
|     protected function findAvailableHandlers(): Collection | ||||
|     { | ||||
|         return collect(config("laravel-slack-slash-command.handlers")) | ||||
|             ->map(fn(string $handlerClassName): BaseHandler => new $handlerClassName($this->request)) | ||||
|             ->filter(fn(HandlesSlashCommand $handler): bool => $handler instanceof SignatureHandler) | ||||
|             ->filter(function (SignatureHandler $handler) { | ||||
|                 $signatureParts = new SignatureParts($handler->getSignature()); | ||||
|  | ||||
|                 return Str::is($signatureParts->getSlashCommandName(), $this->request->command); | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     protected function mapHandlersToAttachments(Collection $handlers): array | ||||
|     { | ||||
|         return $handlers | ||||
|             ->sort( | ||||
|                 fn(SignatureHandler $handlerA, SignatureHandler $handlerB): int => strcmp( | ||||
|                     $handlerA->getFullCommand(), | ||||
|                     $handlerB->getFullCommand(), | ||||
|                 ), | ||||
|             ) | ||||
|             ->map( | ||||
|                 fn(SignatureHandler $handler): AttachmentField => AttachmentField::create( | ||||
|                     $handler->getDescription(), | ||||
|                     "`/{$handler->getSignature()}`", | ||||
|                 ), | ||||
|             ) | ||||
|             ->all(); | ||||
|     } | ||||
| } | ||||
| @@ -21,7 +21,8 @@ | ||||
|         "maatwebsite/excel": "^3.1", | ||||
|         "rackbeat/laravel-ui-avatars": "^1.0", | ||||
|         "spatie/laravel-google-calendar": "^3.5", | ||||
|         "spatie/laravel-model-states": "^2.1" | ||||
|         "spatie/laravel-model-states": "^2.1", | ||||
|         "spatie/laravel-slack-slash-command": "^1.11" | ||||
|     }, | ||||
|     "require-dev": { | ||||
|         "blumilksoftware/codestyle": "^1.0.0", | ||||
| @@ -61,7 +62,8 @@ | ||||
|     "extra": { | ||||
|         "laravel": { | ||||
|             "dont-discover": [ | ||||
|                 "laravel/telescope" | ||||
|                 "laravel/telescope", | ||||
|                 "spatie/laravel-slack-slash-command" | ||||
|             ] | ||||
|         } | ||||
|     }, | ||||
|   | ||||
							
								
								
									
										402
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										402
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", | ||||
|         "This file is @generated automatically" | ||||
|     ], | ||||
|     "content-hash": "414a1fc13e0731e59605248bd4e39de6", | ||||
|     "content-hash": "24a1b3a5dd7c4d4f50d521dda4b6654e", | ||||
|     "packages": [ | ||||
|         { | ||||
|             "name": "asm89/stack-cors", | ||||
| @@ -815,23 +815,23 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "firebase/php-jwt", | ||||
|             "version": "v5.5.1", | ||||
|             "version": "v6.1.2", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/firebase/php-jwt.git", | ||||
|                 "reference": "83b609028194aa042ea33b5af2d41a7427de80e6" | ||||
|                 "reference": "c297139da7c6873dbd67cbd1093f09ec0bbd0c50" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/firebase/php-jwt/zipball/83b609028194aa042ea33b5af2d41a7427de80e6", | ||||
|                 "reference": "83b609028194aa042ea33b5af2d41a7427de80e6", | ||||
|                 "url": "https://api.github.com/repos/firebase/php-jwt/zipball/c297139da7c6873dbd67cbd1093f09ec0bbd0c50", | ||||
|                 "reference": "c297139da7c6873dbd67cbd1093f09ec0bbd0c50", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "php": ">=5.3.0" | ||||
|                 "php": "^7.1||^8.0" | ||||
|             }, | ||||
|             "require-dev": { | ||||
|                 "phpunit/phpunit": ">=4.8 <=9" | ||||
|                 "phpunit/phpunit": "^7.5||9.5" | ||||
|             }, | ||||
|             "suggest": { | ||||
|                 "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" | ||||
| @@ -866,9 +866,9 @@ | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/firebase/php-jwt/issues", | ||||
|                 "source": "https://github.com/firebase/php-jwt/tree/v5.5.1" | ||||
|                 "source": "https://github.com/firebase/php-jwt/tree/v6.1.2" | ||||
|             }, | ||||
|             "time": "2021-11-08T20:18:51+00:00" | ||||
|             "time": "2022-04-21T14:37:18+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "fruitcake/laravel-cors", | ||||
| @@ -1022,16 +1022,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "google/apiclient", | ||||
|             "version": "v2.12.2", | ||||
|             "version": "v2.12.4", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/googleapis/google-api-php-client.git", | ||||
|                 "reference": "a18b0e1ef5618523c607c01a41ec137c7f9af3b1" | ||||
|                 "reference": "702eed9ae7022ba20dc7118c8161060cb50ee9f8" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/a18b0e1ef5618523c607c01a41ec137c7f9af3b1", | ||||
|                 "reference": "a18b0e1ef5618523c607c01a41ec137c7f9af3b1", | ||||
|                 "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/702eed9ae7022ba20dc7118c8161060cb50ee9f8", | ||||
|                 "reference": "702eed9ae7022ba20dc7118c8161060cb50ee9f8", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -1087,22 +1087,22 @@ | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/googleapis/google-api-php-client/issues", | ||||
|                 "source": "https://github.com/googleapis/google-api-php-client/tree/v2.12.2" | ||||
|                 "source": "https://github.com/googleapis/google-api-php-client/tree/v2.12.4" | ||||
|             }, | ||||
|             "time": "2022-04-05T16:19:05+00:00" | ||||
|             "time": "2022-04-20T16:44:03+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "google/apiclient-services", | ||||
|             "version": "v0.242.0", | ||||
|             "version": "v0.246.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/googleapis/google-api-php-client-services.git", | ||||
|                 "reference": "73d4c0ed4b241e7396699e0ee1d1cdebabac25e8" | ||||
|                 "reference": "33aef1ccce34799a1124c39951fed8ad0b16aced" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/73d4c0ed4b241e7396699e0ee1d1cdebabac25e8", | ||||
|                 "reference": "73d4c0ed4b241e7396699e0ee1d1cdebabac25e8", | ||||
|                 "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/33aef1ccce34799a1124c39951fed8ad0b16aced", | ||||
|                 "reference": "33aef1ccce34799a1124c39951fed8ad0b16aced", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -1131,30 +1131,30 @@ | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/googleapis/google-api-php-client-services/issues", | ||||
|                 "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.242.0" | ||||
|                 "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.246.0" | ||||
|             }, | ||||
|             "time": "2022-04-03T01:24:10+00:00" | ||||
|             "time": "2022-04-24T00:58:37+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "google/auth", | ||||
|             "version": "v1.19.0", | ||||
|             "version": "v1.21.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/googleapis/google-auth-library-php.git", | ||||
|                 "reference": "31e5d24d5fa0eaf6adc7e596292dc4732f4b60c5" | ||||
|                 "reference": "73392bad2eb6852eea9084b6bbdec752515cb849" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/31e5d24d5fa0eaf6adc7e596292dc4732f4b60c5", | ||||
|                 "reference": "31e5d24d5fa0eaf6adc7e596292dc4732f4b60c5", | ||||
|                 "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/73392bad2eb6852eea9084b6bbdec752515cb849", | ||||
|                 "reference": "73392bad2eb6852eea9084b6bbdec752515cb849", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "firebase/php-jwt": "~5.0", | ||||
|                 "firebase/php-jwt": "^5.5||^6.0", | ||||
|                 "guzzlehttp/guzzle": "^6.2.1|^7.0", | ||||
|                 "guzzlehttp/psr7": "^1.7|^2.0", | ||||
|                 "php": ">=5.6", | ||||
|                 "psr/cache": "^1.0|^2.0", | ||||
|                 "php": "^7.1||^8.0", | ||||
|                 "psr/cache": "^1.0|^2.0|^3.0", | ||||
|                 "psr/http-message": "^1.0" | ||||
|             }, | ||||
|             "require-dev": { | ||||
| @@ -1162,7 +1162,7 @@ | ||||
|                 "kelvinmo/simplejwt": "^0.2.5|^0.5.1", | ||||
|                 "phpseclib/phpseclib": "^2.0.31", | ||||
|                 "phpspec/prophecy-phpunit": "^1.1", | ||||
|                 "phpunit/phpunit": "^5.7||^8.5.13", | ||||
|                 "phpunit/phpunit": "^7.5||^8.5", | ||||
|                 "sebastian/comparator": ">=1.2.3", | ||||
|                 "squizlabs/php_codesniffer": "^3.5" | ||||
|             }, | ||||
| @@ -1189,9 +1189,9 @@ | ||||
|             "support": { | ||||
|                 "docs": "https://googleapis.github.io/google-auth-library-php/main/", | ||||
|                 "issues": "https://github.com/googleapis/google-auth-library-php/issues", | ||||
|                 "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.19.0" | ||||
|                 "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.21.0" | ||||
|             }, | ||||
|             "time": "2022-03-24T21:22:45+00:00" | ||||
|             "time": "2022-04-13T20:35:52+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "graham-campbell/result-type", | ||||
| @@ -1733,16 +1733,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "laravel/framework", | ||||
|             "version": "v9.7.0", | ||||
|             "version": "v9.9.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/laravel/framework.git", | ||||
|                 "reference": "54c9696ee3e558ab29317ed6e0cb16bb9db5aad4" | ||||
|                 "reference": "4d5a07640891b772188d7737348886a0222737d8" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/laravel/framework/zipball/54c9696ee3e558ab29317ed6e0cb16bb9db5aad4", | ||||
|                 "reference": "54c9696ee3e558ab29317ed6e0cb16bb9db5aad4", | ||||
|                 "url": "https://api.github.com/repos/laravel/framework/zipball/4d5a07640891b772188d7737348886a0222737d8", | ||||
|                 "reference": "4d5a07640891b772188d7737348886a0222737d8", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -1908,20 +1908,76 @@ | ||||
|                 "issues": "https://github.com/laravel/framework/issues", | ||||
|                 "source": "https://github.com/laravel/framework" | ||||
|             }, | ||||
|             "time": "2022-04-05T15:07:51+00:00" | ||||
|             "time": "2022-04-19T15:01:23+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "laravel/sanctum", | ||||
|             "version": "v2.15.0", | ||||
|             "name": "laravel/helpers", | ||||
|             "version": "v1.5.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/laravel/sanctum.git", | ||||
|                 "reference": "5be160413b6f37dcf8758663edeab12d0e806f56" | ||||
|                 "url": "https://github.com/laravel/helpers.git", | ||||
|                 "reference": "c28b0ccd799d58564c41a62395ac9511a1e72931" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/laravel/sanctum/zipball/5be160413b6f37dcf8758663edeab12d0e806f56", | ||||
|                 "reference": "5be160413b6f37dcf8758663edeab12d0e806f56", | ||||
|                 "url": "https://api.github.com/repos/laravel/helpers/zipball/c28b0ccd799d58564c41a62395ac9511a1e72931", | ||||
|                 "reference": "c28b0ccd799d58564c41a62395ac9511a1e72931", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "illuminate/support": "~5.8.0|^6.0|^7.0|^8.0|^9.0", | ||||
|                 "php": "^7.1.3|^8.0" | ||||
|             }, | ||||
|             "require-dev": { | ||||
|                 "phpunit/phpunit": "^7.0|^8.0|^9.0" | ||||
|             }, | ||||
|             "type": "library", | ||||
|             "extra": { | ||||
|                 "branch-alias": { | ||||
|                     "dev-master": "1.x-dev" | ||||
|                 } | ||||
|             }, | ||||
|             "autoload": { | ||||
|                 "files": [ | ||||
|                     "src/helpers.php" | ||||
|                 ] | ||||
|             }, | ||||
|             "notification-url": "https://packagist.org/downloads/", | ||||
|             "license": [ | ||||
|                 "MIT" | ||||
|             ], | ||||
|             "authors": [ | ||||
|                 { | ||||
|                     "name": "Taylor Otwell", | ||||
|                     "email": "taylor@laravel.com" | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "Dries Vints", | ||||
|                     "email": "dries@laravel.com" | ||||
|                 } | ||||
|             ], | ||||
|             "description": "Provides backwards compatibility for helpers in the latest Laravel release.", | ||||
|             "keywords": [ | ||||
|                 "helpers", | ||||
|                 "laravel" | ||||
|             ], | ||||
|             "support": { | ||||
|                 "source": "https://github.com/laravel/helpers/tree/v1.5.0" | ||||
|             }, | ||||
|             "time": "2022-01-12T15:58:51+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "laravel/sanctum", | ||||
|             "version": "v2.15.1", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/laravel/sanctum.git", | ||||
|                 "reference": "31fbe6f85aee080c4dc2f9b03dc6dd5d0ee72473" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/laravel/sanctum/zipball/31fbe6f85aee080c4dc2f9b03dc6dd5d0ee72473", | ||||
|                 "reference": "31fbe6f85aee080c4dc2f9b03dc6dd5d0ee72473", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -1973,7 +2029,7 @@ | ||||
|                 "issues": "https://github.com/laravel/sanctum/issues", | ||||
|                 "source": "https://github.com/laravel/sanctum" | ||||
|             }, | ||||
|             "time": "2022-03-28T13:53:05+00:00" | ||||
|             "time": "2022-04-08T13:39:49+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "laravel/serializable-closure", | ||||
| @@ -2105,16 +2161,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "laravel/telescope", | ||||
|             "version": "v4.8.2", | ||||
|             "version": "v4.8.3", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/laravel/telescope.git", | ||||
|                 "reference": "88e3ded3e1fc301a82403820b2f68ec5a9e092e3" | ||||
|                 "reference": "bb23d58161032c8745d38348452afcbcd8adfc78" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/laravel/telescope/zipball/88e3ded3e1fc301a82403820b2f68ec5a9e092e3", | ||||
|                 "reference": "88e3ded3e1fc301a82403820b2f68ec5a9e092e3", | ||||
|                 "url": "https://api.github.com/repos/laravel/telescope/zipball/bb23d58161032c8745d38348452afcbcd8adfc78", | ||||
|                 "reference": "bb23d58161032c8745d38348452afcbcd8adfc78", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -2167,9 +2223,9 @@ | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/laravel/telescope/issues", | ||||
|                 "source": "https://github.com/laravel/telescope/tree/v4.8.2" | ||||
|                 "source": "https://github.com/laravel/telescope/tree/v4.8.3" | ||||
|             }, | ||||
|             "time": "2022-04-01T14:27:12+00:00" | ||||
|             "time": "2022-04-11T14:29:02+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "laravel/tinker", | ||||
| @@ -2404,16 +2460,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "league/commonmark", | ||||
|             "version": "2.2.3", | ||||
|             "version": "2.3.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/thephpleague/commonmark.git", | ||||
|                 "reference": "47b015bc4e50fd4438c1ffef6139a1fb65d2ab71" | ||||
|                 "reference": "32a49eb2b38fe5e5c417ab748a45d0beaab97955" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/47b015bc4e50fd4438c1ffef6139a1fb65d2ab71", | ||||
|                 "reference": "47b015bc4e50fd4438c1ffef6139a1fb65d2ab71", | ||||
|                 "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/32a49eb2b38fe5e5c417ab748a45d0beaab97955", | ||||
|                 "reference": "32a49eb2b38fe5e5c417ab748a45d0beaab97955", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -2422,17 +2478,19 @@ | ||||
|                 "php": "^7.4 || ^8.0", | ||||
|                 "psr/event-dispatcher": "^1.0", | ||||
|                 "symfony/deprecation-contracts": "^2.1 || ^3.0", | ||||
|                 "symfony/polyfill-php80": "^1.15" | ||||
|                 "symfony/polyfill-php80": "^1.16" | ||||
|             }, | ||||
|             "require-dev": { | ||||
|                 "cebe/markdown": "^1.0", | ||||
|                 "commonmark/cmark": "0.30.0", | ||||
|                 "commonmark/commonmark.js": "0.30.0", | ||||
|                 "composer/package-versions-deprecated": "^1.8", | ||||
|                 "embed/embed": "^4.4", | ||||
|                 "erusev/parsedown": "^1.0", | ||||
|                 "ext-json": "*", | ||||
|                 "github/gfm": "0.29.0", | ||||
|                 "michelf/php-markdown": "^1.4", | ||||
|                 "nyholm/psr7": "^1.5", | ||||
|                 "phpstan/phpstan": "^0.12.88 || ^1.0.0", | ||||
|                 "phpunit/phpunit": "^9.5.5", | ||||
|                 "scrutinizer/ocular": "^1.8.1", | ||||
| @@ -2447,7 +2505,7 @@ | ||||
|             "type": "library", | ||||
|             "extra": { | ||||
|                 "branch-alias": { | ||||
|                     "dev-main": "2.3-dev" | ||||
|                     "dev-main": "2.4-dev" | ||||
|                 } | ||||
|             }, | ||||
|             "autoload": { | ||||
| @@ -2504,7 +2562,7 @@ | ||||
|                     "type": "tidelift" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2022-02-26T21:24:45+00:00" | ||||
|             "time": "2022-04-07T22:37:05+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "league/config", | ||||
| @@ -2590,16 +2648,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "league/flysystem", | ||||
|             "version": "3.0.14", | ||||
|             "version": "3.0.17", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/thephpleague/flysystem.git", | ||||
|                 "reference": "46a5450352540e89cb8e7eb20c58b5b4aae481f6" | ||||
|                 "reference": "29eb78cac0be0c22237c5e0f6f98234d97037d79" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/46a5450352540e89cb8e7eb20c58b5b4aae481f6", | ||||
|                 "reference": "46a5450352540e89cb8e7eb20c58b5b4aae481f6", | ||||
|                 "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/29eb78cac0be0c22237c5e0f6f98234d97037d79", | ||||
|                 "reference": "29eb78cac0be0c22237c5e0f6f98234d97037d79", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -2660,7 +2718,7 @@ | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/thephpleague/flysystem/issues", | ||||
|                 "source": "https://github.com/thephpleague/flysystem/tree/3.0.14" | ||||
|                 "source": "https://github.com/thephpleague/flysystem/tree/3.0.17" | ||||
|             }, | ||||
|             "funding": [ | ||||
|                 { | ||||
| @@ -2676,20 +2734,20 @@ | ||||
|                     "type": "tidelift" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2022-04-06T18:17:37+00:00" | ||||
|             "time": "2022-04-14T14:57:13+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "league/mime-type-detection", | ||||
|             "version": "1.9.0", | ||||
|             "version": "1.11.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/thephpleague/mime-type-detection.git", | ||||
|                 "reference": "aa70e813a6ad3d1558fc927863d47309b4c23e69" | ||||
|                 "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/aa70e813a6ad3d1558fc927863d47309b4c23e69", | ||||
|                 "reference": "aa70e813a6ad3d1558fc927863d47309b4c23e69", | ||||
|                 "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd", | ||||
|                 "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -2720,7 +2778,7 @@ | ||||
|             "description": "Mime-type detection for Flysystem", | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/thephpleague/mime-type-detection/issues", | ||||
|                 "source": "https://github.com/thephpleague/mime-type-detection/tree/1.9.0" | ||||
|                 "source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0" | ||||
|             }, | ||||
|             "funding": [ | ||||
|                 { | ||||
| @@ -2732,20 +2790,20 @@ | ||||
|                     "type": "tidelift" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2021-11-21T11:48:40+00:00" | ||||
|             "time": "2022-04-17T13:12:02+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "league/oauth1-client", | ||||
|             "version": "v1.10.0", | ||||
|             "version": "v1.10.1", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/thephpleague/oauth1-client.git", | ||||
|                 "reference": "88dd16b0cff68eb9167bfc849707d2c40ad91ddc" | ||||
|                 "reference": "d6365b901b5c287dd41f143033315e2f777e1167" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/88dd16b0cff68eb9167bfc849707d2c40ad91ddc", | ||||
|                 "reference": "88dd16b0cff68eb9167bfc849707d2c40ad91ddc", | ||||
|                 "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/d6365b901b5c287dd41f143033315e2f777e1167", | ||||
|                 "reference": "d6365b901b5c287dd41f143033315e2f777e1167", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -2806,22 +2864,22 @@ | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/thephpleague/oauth1-client/issues", | ||||
|                 "source": "https://github.com/thephpleague/oauth1-client/tree/v1.10.0" | ||||
|                 "source": "https://github.com/thephpleague/oauth1-client/tree/v1.10.1" | ||||
|             }, | ||||
|             "time": "2021-08-15T23:05:49+00:00" | ||||
|             "time": "2022-04-15T14:02:14+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "maatwebsite/excel", | ||||
|             "version": "3.1.38", | ||||
|             "version": "3.1.39", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/SpartnerNL/Laravel-Excel.git", | ||||
|                 "reference": "dff132ce4d30b19863f4e84de1613fca99604992" | ||||
|                 "reference": "5165334de44c6f7788a5818a1d019aa71a43e092" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/dff132ce4d30b19863f4e84de1613fca99604992", | ||||
|                 "reference": "dff132ce4d30b19863f4e84de1613fca99604992", | ||||
|                 "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/5165334de44c6f7788a5818a1d019aa71a43e092", | ||||
|                 "reference": "5165334de44c6f7788a5818a1d019aa71a43e092", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -2874,7 +2932,7 @@ | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/SpartnerNL/Laravel-Excel/issues", | ||||
|                 "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.38" | ||||
|                 "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.39" | ||||
|             }, | ||||
|             "funding": [ | ||||
|                 { | ||||
| @@ -2886,7 +2944,7 @@ | ||||
|                     "type": "github" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2022-03-24T16:00:29+00:00" | ||||
|             "time": "2022-04-23T11:44:18+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "maennchen/zipstream-php", | ||||
| @@ -3118,16 +3176,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "monolog/monolog", | ||||
|             "version": "2.4.0", | ||||
|             "version": "2.5.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/Seldaek/monolog.git", | ||||
|                 "reference": "d7fd7450628561ba697b7097d86db72662f54aef" | ||||
|                 "reference": "4192345e260f1d51b365536199744b987e160edc" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/Seldaek/monolog/zipball/d7fd7450628561ba697b7097d86db72662f54aef", | ||||
|                 "reference": "d7fd7450628561ba697b7097d86db72662f54aef", | ||||
|                 "url": "https://api.github.com/repos/Seldaek/monolog/zipball/4192345e260f1d51b365536199744b987e160edc", | ||||
|                 "reference": "4192345e260f1d51b365536199744b987e160edc", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -3201,7 +3259,7 @@ | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/Seldaek/monolog/issues", | ||||
|                 "source": "https://github.com/Seldaek/monolog/tree/2.4.0" | ||||
|                 "source": "https://github.com/Seldaek/monolog/tree/2.5.0" | ||||
|             }, | ||||
|             "funding": [ | ||||
|                 { | ||||
| @@ -3213,7 +3271,7 @@ | ||||
|                     "type": "tidelift" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2022-03-14T12:44:37+00:00" | ||||
|             "time": "2022-04-08T15:43:54+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "myclabs/php-enum", | ||||
| @@ -3856,16 +3914,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "phpoffice/phpspreadsheet", | ||||
|             "version": "1.22.0", | ||||
|             "version": "1.23.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", | ||||
|                 "reference": "3a9e29b4f386a08a151a33578e80ef1747037a48" | ||||
|                 "reference": "21e4cf62699eebf007db28775f7d1554e612ed9e" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/3a9e29b4f386a08a151a33578e80ef1747037a48", | ||||
|                 "reference": "3a9e29b4f386a08a151a33578e80ef1747037a48", | ||||
|                 "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/21e4cf62699eebf007db28775f7d1554e612ed9e", | ||||
|                 "reference": "21e4cf62699eebf007db28775f7d1554e612ed9e", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -3889,7 +3947,7 @@ | ||||
|                 "php": "^7.3 || ^8.0", | ||||
|                 "psr/http-client": "^1.0", | ||||
|                 "psr/http-factory": "^1.0", | ||||
|                 "psr/simple-cache": "^1.0" | ||||
|                 "psr/simple-cache": "^1.0 || ^2.0" | ||||
|             }, | ||||
|             "require-dev": { | ||||
|                 "dealerdirect/phpcodesniffer-composer-installer": "dev-master", | ||||
| @@ -3954,9 +4012,9 @@ | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", | ||||
|                 "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.22.0" | ||||
|                 "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.23.0" | ||||
|             }, | ||||
|             "time": "2022-02-18T12:57:07+00:00" | ||||
|             "time": "2022-04-24T13:53:10+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "phpoption/phpoption", | ||||
| @@ -4140,16 +4198,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "psr/cache", | ||||
|             "version": "2.0.0", | ||||
|             "version": "3.0.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/php-fig/cache.git", | ||||
|                 "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b" | ||||
|                 "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/php-fig/cache/zipball/213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", | ||||
|                 "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", | ||||
|                 "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", | ||||
|                 "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -4183,9 +4241,9 @@ | ||||
|                 "psr-6" | ||||
|             ], | ||||
|             "support": { | ||||
|                 "source": "https://github.com/php-fig/cache/tree/2.0.0" | ||||
|                 "source": "https://github.com/php-fig/cache/tree/3.0.0" | ||||
|             }, | ||||
|             "time": "2021-02-03T23:23:37+00:00" | ||||
|             "time": "2021-02-03T23:26:27+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "psr/container", | ||||
| @@ -4502,25 +4560,25 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "psr/simple-cache", | ||||
|             "version": "1.0.1", | ||||
|             "version": "2.0.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/php-fig/simple-cache.git", | ||||
|                 "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" | ||||
|                 "reference": "8707bf3cea6f710bf6ef05491234e3ab06f6432a" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", | ||||
|                 "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", | ||||
|                 "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/8707bf3cea6f710bf6ef05491234e3ab06f6432a", | ||||
|                 "reference": "8707bf3cea6f710bf6ef05491234e3ab06f6432a", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "php": ">=5.3.0" | ||||
|                 "php": ">=8.0.0" | ||||
|             }, | ||||
|             "type": "library", | ||||
|             "extra": { | ||||
|                 "branch-alias": { | ||||
|                     "dev-master": "1.0.x-dev" | ||||
|                     "dev-master": "2.0.x-dev" | ||||
|                 } | ||||
|             }, | ||||
|             "autoload": { | ||||
| @@ -4535,7 +4593,7 @@ | ||||
|             "authors": [ | ||||
|                 { | ||||
|                     "name": "PHP-FIG", | ||||
|                     "homepage": "http://www.php-fig.org/" | ||||
|                     "homepage": "https://www.php-fig.org/" | ||||
|                 } | ||||
|             ], | ||||
|             "description": "Common interfaces for simple caching", | ||||
| @@ -4547,9 +4605,9 @@ | ||||
|                 "simple-cache" | ||||
|             ], | ||||
|             "support": { | ||||
|                 "source": "https://github.com/php-fig/simple-cache/tree/master" | ||||
|                 "source": "https://github.com/php-fig/simple-cache/tree/2.0.0" | ||||
|             }, | ||||
|             "time": "2017-10-23T01:57:42+00:00" | ||||
|             "time": "2021-10-29T13:22:09+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "psy/psysh", | ||||
| @@ -5040,16 +5098,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "spatie/laravel-model-states", | ||||
|             "version": "2.2.0", | ||||
|             "version": "2.3.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/spatie/laravel-model-states.git", | ||||
|                 "reference": "7b31a63c0bd8b33d7dc5e12e6b16d2535d9b31a8" | ||||
|                 "reference": "bfa12486558952eca4d6c81d4dd803b83f065297" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/spatie/laravel-model-states/zipball/7b31a63c0bd8b33d7dc5e12e6b16d2535d9b31a8", | ||||
|                 "reference": "7b31a63c0bd8b33d7dc5e12e6b16d2535d9b31a8", | ||||
|                 "url": "https://api.github.com/repos/spatie/laravel-model-states/zipball/bfa12486558952eca4d6c81d4dd803b83f065297", | ||||
|                 "reference": "bfa12486558952eca4d6c81d4dd803b83f065297", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -5098,7 +5156,7 @@ | ||||
|                 "state" | ||||
|             ], | ||||
|             "support": { | ||||
|                 "source": "https://github.com/spatie/laravel-model-states/tree/2.2.0" | ||||
|                 "source": "https://github.com/spatie/laravel-model-states/tree/2.3.0" | ||||
|             }, | ||||
|             "funding": [ | ||||
|                 { | ||||
| @@ -5110,7 +5168,7 @@ | ||||
|                     "type": "github" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2022-03-03T11:22:16+00:00" | ||||
|             "time": "2022-04-21T12:09:37+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "spatie/laravel-package-tools", | ||||
| @@ -5171,6 +5229,71 @@ | ||||
|             ], | ||||
|             "time": "2022-03-15T20:01:36+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "spatie/laravel-slack-slash-command", | ||||
|             "version": "1.11.3", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/spatie/laravel-slack-slash-command.git", | ||||
|                 "reference": "8e507653054ff08581b28d6ddf5bb4ce8c2e2335" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/spatie/laravel-slack-slash-command/zipball/8e507653054ff08581b28d6ddf5bb4ce8c2e2335", | ||||
|                 "reference": "8e507653054ff08581b28d6ddf5bb4ce8c2e2335", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "guzzlehttp/guzzle": "^7.0", | ||||
|                 "illuminate/config": "~5.8.0|^6.0|^7.0|^8.0|^9.0", | ||||
|                 "illuminate/queue": "~5.8.0|^6.0|^7.0|^8.0|^9.0", | ||||
|                 "illuminate/routing": "~5.8.0|^6.0|^7.0|^8.0|^9.0", | ||||
|                 "illuminate/support": "~5.8.0|^6.0|^7.0|^8.0|^9.0", | ||||
|                 "laravel/helpers": "^1.0", | ||||
|                 "php": "^7.3|^8.0" | ||||
|             }, | ||||
|             "require-dev": { | ||||
|                 "mockery/mockery": "^1.0", | ||||
|                 "orchestra/testbench": "~3.8.0|^4.0|^5.0|^6.0|^7.0", | ||||
|                 "phpunit/phpunit": "^9.2" | ||||
|             }, | ||||
|             "type": "library", | ||||
|             "extra": { | ||||
|                 "laravel": { | ||||
|                     "providers": [ | ||||
|                         "Spatie\\SlashCommand\\SlashCommandServiceProvider" | ||||
|                     ] | ||||
|                 } | ||||
|             }, | ||||
|             "autoload": { | ||||
|                 "psr-4": { | ||||
|                     "Spatie\\SlashCommand\\": "src" | ||||
|                 } | ||||
|             }, | ||||
|             "notification-url": "https://packagist.org/downloads/", | ||||
|             "license": [ | ||||
|                 "MIT" | ||||
|             ], | ||||
|             "authors": [ | ||||
|                 { | ||||
|                     "name": "Freek Van der Herten", | ||||
|                     "email": "freek@spatie.be", | ||||
|                     "homepage": "https://spatie.be", | ||||
|                     "role": "Developer" | ||||
|                 } | ||||
|             ], | ||||
|             "description": "Make a Laravel app respond to a slash command from Slack", | ||||
|             "homepage": "https://github.com/spatie/laravel-slack-slash-command", | ||||
|             "keywords": [ | ||||
|                 "laravel-slack", | ||||
|                 "spatie" | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/spatie/laravel-slack-slash-command/issues", | ||||
|                 "source": "https://github.com/spatie/laravel-slack-slash-command/tree/1.11.3" | ||||
|             }, | ||||
|             "time": "2022-02-09T07:58:01+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "symfony/console", | ||||
|             "version": "v6.0.7", | ||||
| @@ -7529,21 +7652,21 @@ | ||||
|     "packages-dev": [ | ||||
|         { | ||||
|             "name": "blumilksoftware/codestyle", | ||||
|             "version": "v1.0.1", | ||||
|             "version": "v1.1.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/blumilksoftware/codestyle.git", | ||||
|                 "reference": "e86ebcd5175bc435d9c8d4f83bf201a6f5a9fc60" | ||||
|                 "reference": "3f2248859562afe7d7b2b16aa25e83dc73236fcc" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/blumilksoftware/codestyle/zipball/e86ebcd5175bc435d9c8d4f83bf201a6f5a9fc60", | ||||
|                 "reference": "e86ebcd5175bc435d9c8d4f83bf201a6f5a9fc60", | ||||
|                 "url": "https://api.github.com/repos/blumilksoftware/codestyle/zipball/3f2248859562afe7d7b2b16aa25e83dc73236fcc", | ||||
|                 "reference": "3f2248859562afe7d7b2b16aa25e83dc73236fcc", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "friendsofphp/php-cs-fixer": "^3.8.0", | ||||
|                 "kubawerlos/php-cs-fixer-custom-fixers": "^3.7", | ||||
|                 "kubawerlos/php-cs-fixer-custom-fixers": "^3.10.1", | ||||
|                 "php": "^8.0" | ||||
|             }, | ||||
|             "require-dev": { | ||||
| @@ -7551,6 +7674,9 @@ | ||||
|                 "phpunit/phpunit": "^9.5", | ||||
|                 "symfony/console": "^6.0" | ||||
|             }, | ||||
|             "bin": [ | ||||
|                 "bin/codestyle" | ||||
|             ], | ||||
|             "type": "library", | ||||
|             "autoload": { | ||||
|                 "psr-4": { | ||||
| @@ -7570,9 +7696,9 @@ | ||||
|             "description": "Blumilk codestyle configurator", | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/blumilksoftware/codestyle/issues", | ||||
|                 "source": "https://github.com/blumilksoftware/codestyle/tree/v1.0.1" | ||||
|                 "source": "https://github.com/blumilksoftware/codestyle/tree/v1.1.0" | ||||
|             }, | ||||
|             "time": "2022-04-04T06:25:21+00:00" | ||||
|             "time": "2022-04-25T06:04:51+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "composer/pcre", | ||||
| @@ -8262,16 +8388,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "laravel/dusk", | ||||
|             "version": "v6.22.3", | ||||
|             "version": "v6.23.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/laravel/dusk.git", | ||||
|                 "reference": "f42844d5a7eace45d199d276bb2bc23fec788256" | ||||
|                 "reference": "98901d49176977c96330fd8c2ca5460eee50a246" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/laravel/dusk/zipball/f42844d5a7eace45d199d276bb2bc23fec788256", | ||||
|                 "reference": "f42844d5a7eace45d199d276bb2bc23fec788256", | ||||
|                 "url": "https://api.github.com/repos/laravel/dusk/zipball/98901d49176977c96330fd8c2ca5460eee50a246", | ||||
|                 "reference": "98901d49176977c96330fd8c2ca5460eee50a246", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -8329,9 +8455,9 @@ | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/laravel/dusk/issues", | ||||
|                 "source": "https://github.com/laravel/dusk/tree/v6.22.3" | ||||
|                 "source": "https://github.com/laravel/dusk/tree/v6.23.0" | ||||
|             }, | ||||
|             "time": "2022-04-04T15:12:34+00:00" | ||||
|             "time": "2022-04-11T18:55:12+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "mockery/mockery", | ||||
| @@ -10519,16 +10645,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "spatie/ignition", | ||||
|             "version": "1.2.7", | ||||
|             "version": "1.2.9", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/spatie/ignition.git", | ||||
|                 "reference": "2f059cf42b48f7c522efbba1c05ad59fc2c1a3f2" | ||||
|                 "reference": "db25202fab2d5c14613b8914a1bb374998bbf870" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/spatie/ignition/zipball/2f059cf42b48f7c522efbba1c05ad59fc2c1a3f2", | ||||
|                 "reference": "2f059cf42b48f7c522efbba1c05ad59fc2c1a3f2", | ||||
|                 "url": "https://api.github.com/repos/spatie/ignition/zipball/db25202fab2d5c14613b8914a1bb374998bbf870", | ||||
|                 "reference": "db25202fab2d5c14613b8914a1bb374998bbf870", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -10585,20 +10711,20 @@ | ||||
|                     "type": "github" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2022-03-29T08:48:34+00:00" | ||||
|             "time": "2022-04-23T20:37:21+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "spatie/laravel-ignition", | ||||
|             "version": "1.2.0", | ||||
|             "version": "1.2.2", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/spatie/laravel-ignition.git", | ||||
|                 "reference": "2b54c8c66f2d280f25e15064ebe3d5e3eda19820" | ||||
|                 "reference": "924d1ae878874ad0bb49f63b69a9af759a34ee78" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/2b54c8c66f2d280f25e15064ebe3d5e3eda19820", | ||||
|                 "reference": "2b54c8c66f2d280f25e15064ebe3d5e3eda19820", | ||||
|                 "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/924d1ae878874ad0bb49f63b69a9af759a34ee78", | ||||
|                 "reference": "924d1ae878874ad0bb49f63b69a9af759a34ee78", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -10675,7 +10801,7 @@ | ||||
|                     "type": "github" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2022-04-01T21:01:58+00:00" | ||||
|             "time": "2022-04-14T18:04:51+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "symfony/filesystem", | ||||
| @@ -10931,5 +11057,5 @@ | ||||
|         "ext-redis": "*" | ||||
|     }, | ||||
|     "platform-dev": [], | ||||
|     "plugin-api-version": "2.1.0" | ||||
|     "plugin-api-version": "2.2.0" | ||||
| } | ||||
|   | ||||
| @@ -37,12 +37,12 @@ return [ | ||||
|         Illuminate\Translation\TranslationServiceProvider::class, | ||||
|         Illuminate\Validation\ValidationServiceProvider::class, | ||||
|         Illuminate\View\ViewServiceProvider::class, | ||||
|         Barryvdh\DomPDF\ServiceProvider::class, | ||||
|         Toby\Architecture\Providers\AppServiceProvider::class, | ||||
|         Toby\Architecture\Providers\AuthServiceProvider::class, | ||||
|         Toby\Architecture\Providers\EventServiceProvider::class, | ||||
|         Toby\Architecture\Providers\RouteServiceProvider::class, | ||||
|         Toby\Architecture\Providers\TelescopeServiceProvider::class, | ||||
|         Toby\Architecture\Providers\ObserverServiceProvider::class, | ||||
|         Barryvdh\DomPDF\ServiceProvider::class, | ||||
|     ], | ||||
| ]; | ||||
|   | ||||
							
								
								
									
										24
									
								
								config/laravel-slack-slash-command.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								config/laravel-slack-slash-command.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| use Toby\Infrastructure\Slack\Handlers\CatchAll; | ||||
| use Toby\Infrastructure\Slack\Handlers\DailySummary; | ||||
| use Toby\Infrastructure\Slack\Handlers\GiveKeysTo; | ||||
| use Toby\Infrastructure\Slack\Handlers\Help; | ||||
| use Toby\Infrastructure\Slack\Handlers\HomeOffice; | ||||
| use Toby\Infrastructure\Slack\Handlers\KeyList; | ||||
| use Toby\Infrastructure\Slack\Handlers\TakeKeysFrom; | ||||
|  | ||||
| return [ | ||||
|     "signing_secret" => env("SLACK_SIGNING_SECRET"), | ||||
|     "handlers" => [ | ||||
|         TakeKeysFrom::class, | ||||
|         GiveKeysTo::class, | ||||
|         KeyList::class, | ||||
|         HomeOffice::class, | ||||
|         DailySummary::class, | ||||
|         Help::class, | ||||
|         CatchAll::class, | ||||
|     ], | ||||
| ]; | ||||
| @@ -8,4 +8,9 @@ return [ | ||||
|         "client_secret" => env("GOOGLE_CLIENT_SECRET"), | ||||
|         "redirect" => env("GOOGLE_REDIRECT"), | ||||
|     ], | ||||
|     "slack" => [ | ||||
|         "url" => "https://slack.com/api", | ||||
|         "client_token" => env("SLACK_CLIENT_TOKEN"), | ||||
|         "default_channel" => env("SLACK_DEFAULT_CHANNEL"), | ||||
|     ], | ||||
| ]; | ||||
|   | ||||
| @@ -23,6 +23,7 @@ class ProfileFactory extends Factory | ||||
|             "employment_form" => $this->faker->randomElement(EmploymentForm::cases()), | ||||
|             "position" => $this->faker->jobTitle(), | ||||
|             "employment_date" => Carbon::createFromInterface($this->faker->dateTimeBetween("2020-10-27"))->toDateString(), | ||||
|             "birthday" => Carbon::createFromInterface($this->faker->dateTimeBetween("1970-01-01", "1998-01-01"))->toDateString(), | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,25 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| use Illuminate\Database\Migrations\Migration; | ||||
| use Illuminate\Database\Schema\Blueprint; | ||||
| use Illuminate\Support\Facades\Schema; | ||||
|  | ||||
| return new class() extends Migration { | ||||
|     public function up(): void | ||||
|     { | ||||
|         Schema::table("profiles", function (Blueprint $table): void { | ||||
|             $table->string("slack_id")->nullable(); | ||||
|             $table->date("birthday")->nullable(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     public function down(): void | ||||
|     { | ||||
|         Schema::table("profiles", function (Blueprint $table): void { | ||||
|             $table->dropColumn("slack_id"); | ||||
|             $table->dropColumn("birthday"); | ||||
|         }); | ||||
|     } | ||||
| }; | ||||
| @@ -8,7 +8,7 @@ import HandHeartOutlineIcon from 'vue-material-design-icons/HandHeartOutline.vue | ||||
| import CalendarCheckIcon from 'vue-material-design-icons/CalendarCheck.vue' | ||||
| import MedicalBagIcon from 'vue-material-design-icons/MedicalBag.vue' | ||||
| import CalendarRemoveIcon from 'vue-material-design-icons/CalendarRemove.vue' | ||||
| import LaptopIcon from 'vue-material-design-icons/Laptop.vue' | ||||
| import HomeCityIcon from 'vue-material-design-icons/HomeCity.vue' | ||||
|  | ||||
| const types = [ | ||||
|   { | ||||
| @@ -43,8 +43,8 @@ const types = [ | ||||
|     text: 'Urlop szkoleniowy', | ||||
|     value: 'training_vacation', | ||||
|     icon: HumanMaleBoardIcon, | ||||
|     color: 'text-blumilk-500', | ||||
|     border: 'border-blumilk-500', | ||||
|     color: 'text-indigo-500', | ||||
|     border: 'border-indigo-500', | ||||
|   }, | ||||
|   { | ||||
|     text: 'Urlop bezpłatny', | ||||
| @@ -84,9 +84,9 @@ const types = [ | ||||
|   { | ||||
|     text: 'Praca zdalna', | ||||
|     value: 'home_office', | ||||
|     icon: LaptopIcon, | ||||
|     color: 'text-fuchsia-500', | ||||
|     border: 'border-fuchsia-500', | ||||
|     icon: HomeCityIcon, | ||||
|     color: 'text-blumilk-500', | ||||
|     border: 'border-blumilk-500', | ||||
|   }, | ||||
| ] | ||||
|  | ||||
|   | ||||
| @@ -234,6 +234,52 @@ | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="items-center py-4 sm:grid sm:grid-cols-3"> | ||||
|         <label | ||||
|           for="slackId" | ||||
|           class="block text-sm font-medium text-gray-700 sm:mt-px" | ||||
|         > | ||||
|           Slack ID | ||||
|         </label> | ||||
|         <div class="mt-1 sm:col-span-2 sm:mt-0"> | ||||
|           <input | ||||
|             id="position" | ||||
|             v-model="form.slackId" | ||||
|             type="text" | ||||
|             class="block w-full max-w-lg rounded-md shadow-sm sm:text-sm" | ||||
|             :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.slackId, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.slackId }" | ||||
|           > | ||||
|           <p | ||||
|             v-if="form.errors.slackId" | ||||
|             class="mt-2 text-sm text-red-600" | ||||
|           > | ||||
|             {{ form.errors.slackId }} | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="items-center py-4 sm:grid sm:grid-cols-3"> | ||||
|         <label | ||||
|           for="birthday" | ||||
|           class="block text-sm font-medium text-gray-700 sm:mt-px" | ||||
|         > | ||||
|           Data urodzenia | ||||
|         </label> | ||||
|         <div class="mt-1 sm:col-span-2 sm:mt-0"> | ||||
|           <FlatPickr | ||||
|             id="birthday" | ||||
|             v-model="form.birthday" | ||||
|             placeholder="Wybierz datę" | ||||
|             class="block w-full max-w-lg rounded-md shadow-sm sm:text-sm" | ||||
|             :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.birthday, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.birthday }" | ||||
|           /> | ||||
|           <p | ||||
|             v-if="form.errors.birthday" | ||||
|             class="mt-2 text-sm text-red-600" | ||||
|           > | ||||
|             {{ form.errors.birthday }} | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="flex justify-end py-3"> | ||||
|         <div class="space-x-3"> | ||||
|           <InertiaLink | ||||
| @@ -274,6 +320,8 @@ const form = useForm({ | ||||
|   role: props.roles[0], | ||||
|   position: null, | ||||
|   employmentDate: null, | ||||
|   birthday: null, | ||||
|   slackId: null, | ||||
| }) | ||||
|  | ||||
| function createUser() { | ||||
|   | ||||
| @@ -241,6 +241,52 @@ | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="items-center py-4 sm:grid sm:grid-cols-3"> | ||||
|         <label | ||||
|           for="birthday" | ||||
|           class="block text-sm font-medium text-gray-700 sm:mt-px" | ||||
|         > | ||||
|           Data urodzenia | ||||
|         </label> | ||||
|         <div class="mt-1 sm:col-span-2 sm:mt-0"> | ||||
|           <FlatPickr | ||||
|             id="birthday" | ||||
|             v-model="form.birthday" | ||||
|             placeholder="Wybierz datę" | ||||
|             class="block w-full max-w-lg rounded-md shadow-sm sm:text-sm" | ||||
|             :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.birthday, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.birthday }" | ||||
|           /> | ||||
|           <p | ||||
|             v-if="form.errors.birthday" | ||||
|             class="mt-2 text-sm text-red-600" | ||||
|           > | ||||
|             {{ form.errors.birthday }} | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="items-center py-4 sm:grid sm:grid-cols-3"> | ||||
|         <label | ||||
|           for="slackId" | ||||
|           class="block text-sm font-medium text-gray-700 sm:mt-px" | ||||
|         > | ||||
|           Slack ID | ||||
|         </label> | ||||
|         <div class="mt-1 sm:col-span-2 sm:mt-0"> | ||||
|           <input | ||||
|             id="position" | ||||
|             v-model="form.slackId" | ||||
|             type="text" | ||||
|             class="block w-full max-w-lg rounded-md shadow-sm sm:text-sm" | ||||
|             :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.slackId, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.slackId }" | ||||
|           > | ||||
|           <p | ||||
|             v-if="form.errors.slackId" | ||||
|             class="mt-2 text-sm text-red-600" | ||||
|           > | ||||
|             {{ form.errors.slackId }} | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="flex justify-end py-3"> | ||||
|         <div class="space-x-3"> | ||||
|           <InertiaLink | ||||
| @@ -282,6 +328,8 @@ const form = useForm({ | ||||
|   position: props.user.position, | ||||
|   employmentForm: props.employmentForms.find(form => form.value === props.user.employmentForm), | ||||
|   employmentDate: props.user.employmentDate, | ||||
|   birthday: props.user.birthday, | ||||
|   slackId: props.user.slackId, | ||||
| }) | ||||
|  | ||||
| function editUser() { | ||||
|   | ||||
| @@ -23,11 +23,11 @@ | ||||
|   "cancelled": "anulowany", | ||||
|   "rejected": "odrzucony", | ||||
|   "approved": "zatwierdzony", | ||||
|   "You have pending vacation request in this range.": "Masz oczekujący wniosek urlopowy w tym zakresie dat.", | ||||
|   "You have approved vacation request in this range.": "Masz zaakceptowany wniosek urlopowy w tym zakresie dat.", | ||||
|   "You have pending vacation request in this range.": "Masz oczekujący wniosek w tym zakresie dat.", | ||||
|   "You have approved vacation request in this range.": "Masz zaakceptowany wniosek w tym zakresie dat.", | ||||
|   "Vacation limit has been exceeded.": "Limit urlopu został przekroczony.", | ||||
|   "Vacation needs minimum one day.": "Urlop musi być co najmniej na jeden dzień.", | ||||
|   "The vacation request cannot be created at the turn of the year.": "Wniosek urlopowy nie może zostać złożony na przełomie roku.", | ||||
|   "The vacation request cannot be created at the turn of the year.": "Wniosek nie może zostać złożony na przełomie roku.", | ||||
|   "User has been created.": "Użytkownik został utworzony.", | ||||
|   "User has been updated.": "Użytkownik został zaktualizowany.", | ||||
|   "User has been deleted.": "Użytkownik został usunięty.", | ||||
| @@ -37,11 +37,11 @@ | ||||
|   "Holiday has been deleted.": "Dzień wolny został usunięty.", | ||||
|   "Selected year period has been changed.": "Wybrany rok został zmieniony.", | ||||
|   "Vacation limits have been updated.": "Limity urlopów zostały zaktualizowane.", | ||||
|   "Vacation request has been created.": "Wniosek urlopowy został utworzony.", | ||||
|   "Vacation request has been accepted.": "Wniosek urlopowy został zaakceptowany.", | ||||
|   "Vacation request has been approved.": "Wniosek urlopowy został zatwierdzony.", | ||||
|   "Vacation request has been rejected.": "Wniosek urlopowy został odrzucony.", | ||||
|   "Vacation request has been cancelled.": "Wniosek urlopowy został anulowany.", | ||||
|   "Vacation request has been created.": "Wniosek został utworzony.", | ||||
|   "Vacation request has been accepted.": "Wniosek został zaakceptowany.", | ||||
|   "Vacation request has been approved.": "Wniosek został zatwierdzony.", | ||||
|   "Vacation request has been rejected.": "Wniosek został odrzucony.", | ||||
|   "Vacation request has been cancelled.": "Wniosek został anulowany.", | ||||
|   "Sum:": "Suma:", | ||||
|   "Date": "Data", | ||||
|   "Day of week": "Dzień tygodnia", | ||||
| @@ -56,7 +56,7 @@ | ||||
|   "All rights reserved.": "Wszelkie prawa zastrzeżone", | ||||
|   "Show vacation request": "Pokaż wniosek", | ||||
|   "Vacation request :title has been created" : "Wniosek :title został utworzony", | ||||
|   "The vacation request :title has been created correctly in the :appName.": "W systemie :appName został poprawnie utworzony wniosek urlopowy :title.", | ||||
|   "The vacation request :title from user :requester has been created successfully.": "Wniosek :title użytkownika :requester został utworzony pomyślnie.", | ||||
|   "Vacation type: :type": "Rodzaj wniosku: :type", | ||||
|   "From :from to :to (number of days: :days)": "Od :from do :to (liczba dni: :days)", | ||||
|   "Click here for details": "Kliknij, aby zobaczyć szczegóły", | ||||
| @@ -67,9 +67,11 @@ | ||||
|   "Vacation request :title has been :status": "Wniosek :title został :status", | ||||
|   "The vacation request :title from user :requester has been :status.": "Wniosek urlopowy :title użytkownika :requester został :status.", | ||||
|   "Vacation request :title has been created on your behalf": "Wniosek urlopowy :title został utworzony w Twoim imieniu", | ||||
|   "The vacation request :title has been created correctly by user :creator on your behalf in the :appName.": "W systemie :appName został poprawnie utworzony wniosek urlopowy :title w Twoim imieniu przez użytkownika :creator.", | ||||
|   "The vacation request :title has been created successfully by user :creator on your behalf.": "Wniosek urlopowy :title został pomyślnie utworzony w Twoim imieniu przez użytkownika :creator.", | ||||
|   "Key no :number has been created.": "Klucz nr :number został utworzony.", | ||||
|   "Key no :number has been deleted.": "Klucz nr :number został usunięty.", | ||||
|   "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." | ||||
|   "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" | ||||
| } | ||||
|   | ||||
| @@ -7,6 +7,9 @@ use Toby\Infrastructure\Http\Controllers\Api\CalculateUserUnavailableDaysControl | ||||
| use Toby\Infrastructure\Http\Controllers\Api\CalculateUserVacationStatsController; | ||||
| use Toby\Infrastructure\Http\Controllers\Api\CalculateVacationDaysController; | ||||
| use Toby\Infrastructure\Http\Controllers\Api\GetAvailableVacationTypesController; | ||||
| use Toby\Infrastructure\Slack\Controller as SlackController; | ||||
|  | ||||
| Route::post("slack", [SlackController::class, "getResponse"]); | ||||
|  | ||||
| Route::middleware("auth:sanctum")->group(function (): void { | ||||
|     Route::post("vacation/calculate-days", CalculateVacationDaysController::class); | ||||
|   | ||||
| @@ -5,6 +5,7 @@ declare(strict_types=1); | ||||
| namespace Tests\Feature; | ||||
|  | ||||
| use Illuminate\Foundation\Testing\DatabaseMigrations; | ||||
| use Illuminate\Support\Facades\Notification; | ||||
| use Inertia\Testing\AssertableInertia as Assert; | ||||
| use Tests\FeatureTestCase; | ||||
| use Toby\Eloquent\Models\Key; | ||||
| @@ -14,6 +15,13 @@ class KeyTest extends FeatureTestCase | ||||
| { | ||||
|     use DatabaseMigrations; | ||||
|  | ||||
|     protected function setUp(): void | ||||
|     { | ||||
|         parent::setUp(); | ||||
|  | ||||
|         Notification::fake(); | ||||
|     } | ||||
|  | ||||
|     public function testUserCanSeeKeyList(): void | ||||
|     { | ||||
|         Key::factory()->count(10)->create(); | ||||
|   | ||||
							
								
								
									
										82
									
								
								tests/Unit/SendDailySummaryToSlackTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								tests/Unit/SendDailySummaryToSlackTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Tests\Unit; | ||||
|  | ||||
| use Illuminate\Foundation\Testing\RefreshDatabase; | ||||
| use Illuminate\Support\Carbon; | ||||
| use Illuminate\Support\Facades\Http; | ||||
| use Tests\TestCase; | ||||
| use Tests\Traits\InteractsWithYearPeriods; | ||||
| use Toby\Eloquent\Models\Holiday; | ||||
| use Toby\Infrastructure\Console\Commands\SendDailySummaryToSlack; | ||||
|  | ||||
| class SendDailySummaryToSlackTest extends TestCase | ||||
| { | ||||
|     use RefreshDatabase; | ||||
|     use InteractsWithYearPeriods; | ||||
|  | ||||
|     protected function setUp(): void | ||||
|     { | ||||
|         parent::setUp(); | ||||
|  | ||||
|         Http::fake(); | ||||
|         $this->createCurrentYearPeriod(); | ||||
|     } | ||||
|  | ||||
|     public function testCommandSendsMessageToSlackIfWeekday(): void | ||||
|     { | ||||
|         $weekDay = Carbon::create(2022, 4, 22); | ||||
|         $this->assertTrue($weekDay->isWeekday()); | ||||
|  | ||||
|         $this->travelTo($weekDay); | ||||
|  | ||||
|         $this->artisan(SendDailySummaryToSlack::class) | ||||
|             ->execute(); | ||||
|  | ||||
|         Http::assertSentCount(1); | ||||
|     } | ||||
|  | ||||
|     public function testCommandDoesntSendMessageIfWeekend(): void | ||||
|     { | ||||
|         $weekend = Carbon::create(2022, 4, 23); | ||||
|         $this->assertTrue($weekend->isWeekend()); | ||||
|  | ||||
|         $this->travelTo($weekend); | ||||
|  | ||||
|         $this->artisan(SendDailySummaryToSlack::class) | ||||
|             ->execute(); | ||||
|  | ||||
|         Http::assertNothingSent(); | ||||
|     } | ||||
|  | ||||
|     public function testCommandDoesntSendMessageIfHoliday(): void | ||||
|     { | ||||
|         $holiday = Holiday::factory(["date" => Carbon::create(2022, 4, 22)])->create(); | ||||
|  | ||||
|         $this->assertDatabaseHas("holidays", [ | ||||
|             "date" => $holiday->date->toDateString(), | ||||
|         ]); | ||||
|  | ||||
|         $this->travelTo(Carbon::create(2022, 4, 22)); | ||||
|  | ||||
|         $this->artisan(SendDailySummaryToSlack::class) | ||||
|             ->execute(); | ||||
|  | ||||
|         Http::assertNothingSent(); | ||||
|     } | ||||
|  | ||||
|     public function testCommandForceSendsMessageEvenIsWeekendOrHoliday(): void | ||||
|     { | ||||
|         $weekend = Carbon::create(2022, 4, 23); | ||||
|         $this->assertTrue($weekend->isWeekend()); | ||||
|  | ||||
|         $this->travelTo($weekend); | ||||
|  | ||||
|         $this->artisan(SendDailySummaryToSlack::class, ["--force" => true]) | ||||
|             ->execute(); | ||||
|  | ||||
|         Http::assertSentCount(1); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user