Skip to content

Commit

Permalink
#282 - wip
Browse files Browse the repository at this point in the history
  • Loading branch information
EwelinaSkrzypacz committed Sep 7, 2023
1 parent f35558b commit 39e6973
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,49 @@

namespace Toby\Domain\Notifications;

use Spatie\SlashCommand\AttachmentAction;
use Toby\Domain\States\VacationRequest\WaitingForAdministrative;
use Toby\Domain\States\VacationRequest\WaitingForTechnical;
use Toby\Infrastructure\Slack\Elements\Attachment;
use Toby\Infrastructure\Slack\Elements\SlackMessage;

class VacationRequestWaitsForApprovalNotification extends VacationRequestNotification
{
public function toSlack(): SlackMessage
{
$url = route("vacation.requests.show", ["vacationRequest" => $this->vacationRequest->id]);
$seeDetails = __("See details");

if ($this->vacationRequest->state->equals(WaitingForTechnical::class)) {
$actions = [
AttachmentAction::create("technical_approval", __("Approve"), "button")
->setValue("technical_approval")
->setStyle("primary"),
AttachmentAction::create("reject", __("Reject"), "button")
->setValue("reject")
->setStyle("danger"),
];
} elseif ($this->vacationRequest->state->equals(WaitingForAdministrative::class)) {
$actions = [
AttachmentAction::create("administrative_approval", __("Approve"), "button")
->setValue("administrative_approval")
->setStyle("primary"),
AttachmentAction::create("reject", __("Reject"), "button")
->setValue("reject")
->setStyle("danger"),
];
}

$attachment = Attachment::create()
->setCallbackId((string)$this->vacationRequest->id)
->setText(__("Available actions:"))
->setActions($actions);

return (new SlackMessage())
->text("{$this->buildDescription()}\n <{$url}|{$seeDetails}>")
->withAttachment($attachment);
}

protected function buildDescription(): string
{
$title = $this->vacationRequest->name;
Expand Down
14 changes: 11 additions & 3 deletions app/Infrastructure/Slack/Elements/KeysAttachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@ public function __construct(Collection $keys)
->setColor("#3c5f97")
->setItems($keys->map(function (Key $key): string {
if ($key->user === null) {
return "Klucz nr {$key->id} - jest w biurze";
return __("Key no. :number - is in the office.", [
"number" => $key->id,
]);
}

if ($key->user->profile->slack_id === null) {
return "Klucz nr {$key->id} - {$key->user->profile->full_name}";
return __("Key no. :number - :user", [
"number" => $key->id,
"user" => $key->user->profile->full_name,
]);
}

return "Klucz nr {$key->id} - <@{$key->user->profile->slack_id}>";
return __("Key no. :number - :user", [
"number" => $key->id,
"user" => "<@{$key->user->profile->slack_id}>",
]);
}))
->setEmptyText(__("There are no keys in toby"));
}
Expand Down
120 changes: 120 additions & 0 deletions app/Infrastructure/Slack/SlackActionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php

declare(strict_types=1);

namespace Toby\Infrastructure\Slack;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request as IlluminateRequest;
use Spatie\SlashCommand\Controller as SlackController;
use Toby\Domain\Actions\VacationRequest\AcceptAsAdministrativeAction;
use Toby\Domain\Actions\VacationRequest\AcceptAsTechnicalAction;
use Toby\Domain\Actions\VacationRequest\RejectAction;
use Toby\Domain\States\VacationRequest\WaitingForAdministrative;
use Toby\Domain\States\VacationRequest\WaitingForTechnical;
use Toby\Eloquent\Models\VacationRequest;
use Toby\Infrastructure\Slack\Traits\FindsUserBySlackId;

class SlackActionController extends SlackController
{
use FindsUserBySlackId;
use AuthorizesRequests;

public function handleVacationRequestAction(IlluminateRequest $request, AcceptAsTechnicalAction $acceptAsTechnical, AcceptAsAdministrativeAction $acceptAsAdministrative, RejectAction $reject): JsonResponse
{
$this->verifyWithSigning($request);

$payload = json_decode($request->payload, true);

$userSlackId = $payload["user"]["id"];

$user = $this->findUserBySlackId($userSlackId);

$vacationRequestId = $payload["callback_id"];

$action = $payload["actions"][0]["value"];

$vacationRequest = VacationRequest::query()->findOrFail($vacationRequestId);

switch ($action) {
case "technical_approval":
if ($user->cannot("acceptAsTechApprover", $vacationRequest)) {
return $this->prepareAuthorizationError();
}

if (!$vacationRequest->state->equals(WaitingForTechnical::class)) {
return $this->prepareActionError($vacationRequest);
}
$acceptAsTechnical->execute($vacationRequest, $user);
$responseText = __("The request :title from user :requester has been approved by you as a technical approver.", [
"title" => $vacationRequest->name,
"requester" => $vacationRequest->user->profile->full_name,
"technical" => $user->profile->full_name,
]);

break;
case "administrative_approval":
if ($user->cannot("acceptAsAdminApprover", $vacationRequest)) {
return $this->prepareAuthorizationError();
}

if (!$vacationRequest->state->equals(WaitingForAdministrative::class)) {
return $this->prepareActionError($vacationRequest);
}
$acceptAsAdministrative->execute($vacationRequest, $user);
$responseText = __("The request :title from user :requester has been approved by you as an administrative approver.", [
"title" => $vacationRequest->name,
"requester" => $vacationRequest->user->profile->full_name,
]);

break;
case "reject":
if ($user->cannot("reject", $vacationRequest)) {
return $this->prepareAuthorizationError();
}

if (!$vacationRequest->state->equals(WaitingForTechnical::class, WaitingForAdministrative::class)) {
return $this->prepareActionError($vacationRequest);
}
$reject->execute($vacationRequest, $user);
$responseText = __("The request :title from user :requester has been rejected by you.", [
"title" => $vacationRequest->name,
"requester" => $vacationRequest->user->profile->full_name,
]);

break;
default:
return $this->prepareUnrecognizedActionError();
}

return response()->json([
"text" => $responseText,
]);
}

protected function prepareAuthorizationError(): JsonResponse
{
return response()->json([
"text" => __("You do not have permission to perform this action."),
]);
}

protected function prepareActionError(VacationRequest $vacationRequest): JsonResponse
{
return response()->json([
"text" => __("You cannot perform this action because the current status of the request :title by user :requester is :status.", [
"title" => $vacationRequest->name,
"requester" => $vacationRequest->user->profile->full_name,
"status" => $vacationRequest->state->label(),
]),
]);
}

protected function prepareUnrecognizedActionError(): JsonResponse
{
return response()->json([
"text" => __("Unrecognized action."),
]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use Spatie\SlashCommand\Exceptions\SlackSlashCommandException;
use Spatie\SlashCommand\Response;

class Controller extends SlackController
class SlackCommandController extends SlackController
{
/**
* @throws InvalidRequest|RequestCouldNotBeHandled
Expand Down Expand Up @@ -50,7 +50,10 @@ protected function prepareValidationResponse(ValidationException $exception): Re
);

return Response::create($this->request)
->withText(":x: Polecenie `/{$this->request->command} {$this->request->text}` jest niepoprawne:")
->withText(__(":x: Command /:command :text is incorrect:", [
"command" => $this->request->command,
"text" => $this->request->text,
]))
->withAttachments($errors->all());
}
}
16 changes: 15 additions & 1 deletion lang/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,5 +143,19 @@
"The deadline for OHS training for some employees is about to expire.": "Niedługo mija termin szkolenia BHP dla części pracowników.",
"Below is a list of employees with upcoming OHS training:": "Poniżej znajduje się lista pracowników ze zbliżającym się terminem szkolenia BHP:",
"The deadline for OHS training for some employees has passed.": "Termin szkolenia BHP dla części pracowników minął.",
"Below is a list of employees with overdue OHS training:": "Poniżej znajduje się lista pracowników z przeterminowanym szkoleniem BHP:"
"Below is a list of employees with overdue OHS training:": "Poniżej znajduje się lista pracowników z przeterminowanym szkoleniem BHP:",
"Approve": "Zaakceptuj",
"Reject": "Odrzuć",
"Available actions:": "Dostępne akcje:",
"The request :title from user :requester has been approved by you as a technical approver.": "Wniosek :title użytkownika :requester został zaakceptowany przez Ciebie jako przełożonego technicznego.",
"The request :title from user :requester has been approved by you as an administrative approver.": "Wniosek :title użytkownika :requester został zaakceptowany przez Ciebie jako przełożonego administracyjnego.",
"The request :title from user :requester has been rejected by you.": "Wniosek :title użytkownika :requester został odrzucony przez Ciebie.",
"Unrecognized action": "Nieznana akcja",
":x: Command /:command :text is incorrect:": ":x: Polecenie /:command :text jest niepoprawne:",
"Key no. :number - is in the office.": "Klucz nr :number - jest w biurze",
"Key no. :number - :user": "Klucz nr :number - :user",
"waiting_for_administrative": "czeka na akceptację od przełożonego administracyjnego",
"You do not have permission to perform this action.": "Nie masz uprawnień, aby wykonać tę akcję.",
"waiting_for_technical": "czeka na akceptację od przełożonego technicznego",
"You cannot perform this action because the current status of the request :title by user :requester is :status.": "Nie możesz wykonać tej akcji, ponieważ aktualny status wniosku :title użytkownika :requester to :status"
}
6 changes: 4 additions & 2 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
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 SlackCommandController;
use Toby\Infrastructure\Slack\SlackActionController;
use Toby\Infrastructure\Slack\SlackCommandController;

Route::post("slack", [SlackCommandController::class, "getResponse"]);
Route::post("slack/commands", [SlackCommandController::class, "getResponse"]);
Route::post("slack/actions", [SlackActionController::class, "handleVacationRequestAction"]);

Route::middleware("auth:sanctum")->group(function (): void {
Route::post("vacation/calculate-days", CalculateVacationDaysController::class);
Expand Down

0 comments on commit 39e6973

Please sign in to comment.