diff --git a/app/Actions/Notifications/BuildProjectNotificationSettingsPayload.php b/app/Actions/Notifications/BuildProjectNotificationSettingsPayload.php index 995a4f3..ea021c9 100644 --- a/app/Actions/Notifications/BuildProjectNotificationSettingsPayload.php +++ b/app/Actions/Notifications/BuildProjectNotificationSettingsPayload.php @@ -2,6 +2,7 @@ namespace App\Actions\Notifications; +use App\Enums\DiscordAllowedMentionType; use App\Enums\NotificationChannel; use App\Enums\NotificationEventType; use App\Http\Resources\NotificationActionResource; @@ -22,6 +23,7 @@ class BuildProjectNotificationSettingsPayload return [ 'channelOptions' => NotificationChannel::options(), 'eventTypeOptions' => NotificationEventType::options(), + 'discordAllowedMentionOptions' => DiscordAllowedMentionType::options(), 'notificationActions' => NotificationActionResource::collection( $this->listProjectNotificationActions->handle($project), )->resolve(), diff --git a/app/Actions/Notifications/DeliverNotificationAction.php b/app/Actions/Notifications/DeliverNotificationAction.php index a5d229f..37bbf75 100644 --- a/app/Actions/Notifications/DeliverNotificationAction.php +++ b/app/Actions/Notifications/DeliverNotificationAction.php @@ -2,6 +2,7 @@ namespace App\Actions\Notifications; +use App\Enums\DiscordAllowedMentionType; use App\Enums\NotificationChannel; use App\Enums\NotificationDeliveryStatus; use App\Models\NotificationAction; @@ -21,11 +22,6 @@ class DeliverNotificationAction implements ShouldQueue private const int DISCORD_CONTENT_LIMIT = 2000; - /** - * @var list - */ - private const array DISCORD_ALLOWED_MENTION_TYPES = ['everyone', 'roles', 'users']; - public int $tries = 3; public int $timeout = 15; @@ -318,7 +314,7 @@ class DeliverNotificationAction implements ShouldQueue continue; } - if (! in_array($allowedMention, self::DISCORD_ALLOWED_MENTION_TYPES, true)) { + if (! in_array($allowedMention, DiscordAllowedMentionType::values(), true)) { continue; } diff --git a/app/Enums/DiscordAllowedMentionType.php b/app/Enums/DiscordAllowedMentionType.php new file mode 100644 index 0000000..50ea956 --- /dev/null +++ b/app/Enums/DiscordAllowedMentionType.php @@ -0,0 +1,45 @@ + '@everyone and @here', + self::Roles => 'Role mentions (@role)', + self::Users => 'User mentions (@username)', + }; + } + + /** + * @return array + */ + public static function options(): array + { + return array_map( + fn (self $eventType): array => [ + 'label' => $eventType->label(), + 'value' => $eventType->value, + ], + self::cases(), + ); + } + + /** + * @param array|null $discordAllowedMentionTypes + * @return array + */ + public static function values(?array $discordAllowedMentionTypes = null): array + { + return array_map( + fn (self $discordAllowedMentionType): string => $discordAllowedMentionType->value, + $discordAllowedMentionTypes ?? self::cases(), + ); + } +} diff --git a/app/Enums/NotificationChannel.php b/app/Enums/NotificationChannel.php index a869ce7..902f647 100644 --- a/app/Enums/NotificationChannel.php +++ b/app/Enums/NotificationChannel.php @@ -28,4 +28,16 @@ enum NotificationChannel: string self::cases(), ); } + + /** + * @param array|null $notificationChannels + * @return array + */ + public static function values(?array $notificationChannels = null): array + { + return array_map( + fn (self $notificationChannel): string => $notificationChannel->value, + $notificationChannels ?? self::cases(), + ); + } } diff --git a/app/Enums/NotificationEventType.php b/app/Enums/NotificationEventType.php index c9e120b..a97e52d 100644 --- a/app/Enums/NotificationEventType.php +++ b/app/Enums/NotificationEventType.php @@ -26,4 +26,16 @@ enum NotificationEventType: string self::cases(), ); } + + /** + * @param array|null $notificationEventTypes + * @return array + */ + public static function values(?array $notificationEventTypes = null): array + { + return array_map( + fn (self $notificationEventType): string => $notificationEventType->value, + $notificationEventTypes ?? self::cases(), + ); + } } diff --git a/app/Http/Requests/StoreProjectNotificationActionRequest.php b/app/Http/Requests/StoreProjectNotificationActionRequest.php index be63954..2ca4a03 100644 --- a/app/Http/Requests/StoreProjectNotificationActionRequest.php +++ b/app/Http/Requests/StoreProjectNotificationActionRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests; +use App\Enums\DiscordAllowedMentionType; use App\Enums\NotificationChannel; use App\Enums\NotificationEventType; use Illuminate\Contracts\Validation\ValidationRule; @@ -10,11 +11,6 @@ use Illuminate\Validation\Rule; class StoreProjectNotificationActionRequest extends FormRequest { - /** - * @var list - */ - private const array DISCORD_ALLOWED_MENTION_TYPES = ['everyone', 'roles', 'users']; - /** * Determine if the user is authorized to make this request. */ @@ -32,60 +28,14 @@ class StoreProjectNotificationActionRequest extends FormRequest { return [ 'name' => ['required', 'string', 'max:255'], - 'event_type' => ['required', 'string', Rule::in($this->eventTypes())], - 'channel' => ['required', 'string', Rule::in($this->channels())], + 'event_type' => ['required', 'string', Rule::in(NotificationEventType::values())], + 'channel' => ['required', 'string', Rule::in(NotificationChannel::values())], 'channel_configuration' => ['nullable', 'array'], 'channel_configuration.allowed_mentions' => ['nullable', 'array'], - 'channel_configuration.allowed_mentions.*' => $this->allowedMentionRules(), + 'channel_configuration.allowed_mentions.*' => ['nullable', 'string', Rule::in(DiscordAllowedMentionType::values())], 'enabled' => ['required', 'boolean'], 'delivery_url' => ['required', 'string', 'max:2048', 'url'], - 'message_template' => $this->messageTemplateRules(), - ]; - } - - /** - * @return array - */ - private function channels(): array - { - return array_map( - static fn (NotificationChannel $channel): string => $channel->value, - NotificationChannel::cases(), - ); - } - - /** - * @return array - */ - private function eventTypes(): array - { - return array_map( - static fn (NotificationEventType $eventType): string => $eventType->value, - NotificationEventType::cases(), - ); - } - - /** - * @return array - */ - private function messageTemplateRules(): array - { - if ($this->input('channel') === NotificationChannel::Discord->value) { - return ['required', 'string', 'max:2000']; - } - - return ['nullable', 'string', 'max:2000']; - } - - /** - * @return array - */ - private function allowedMentionRules(): array - { - return [ - 'nullable', - 'string', - Rule::in(self::DISCORD_ALLOWED_MENTION_TYPES), + 'message_template' => [Rule::requiredIf($this->input('channel') === NotificationChannel::Discord->value), 'string', 'max:2000'], ]; } } diff --git a/app/Http/Requests/UpdateProjectNotificationActionRequest.php b/app/Http/Requests/UpdateProjectNotificationActionRequest.php index d2ea824..6011acc 100644 --- a/app/Http/Requests/UpdateProjectNotificationActionRequest.php +++ b/app/Http/Requests/UpdateProjectNotificationActionRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests; +use App\Enums\DiscordAllowedMentionType; use App\Enums\NotificationChannel; use App\Enums\NotificationEventType; use Illuminate\Contracts\Validation\ValidationRule; @@ -10,10 +11,6 @@ use Illuminate\Validation\Rule; class UpdateProjectNotificationActionRequest extends FormRequest { - /** - * @var list - */ - private const array DISCORD_ALLOWED_MENTION_TYPES = ['everyone', 'roles', 'users']; /** * Determine if the user is authorized to make this request. @@ -32,60 +29,14 @@ class UpdateProjectNotificationActionRequest extends FormRequest { return [ 'name' => ['required', 'string', 'max:255'], - 'event_type' => ['required', 'string', Rule::in($this->eventTypes())], - 'channel' => ['required', 'string', Rule::in($this->channels())], + 'event_type' => ['required', 'string', Rule::in(NotificationEventType::values())], + 'channel' => ['required', 'string', Rule::in(NotificationChannel::values())], 'channel_configuration' => ['nullable', 'array'], 'channel_configuration.allowed_mentions' => ['nullable', 'array'], - 'channel_configuration.allowed_mentions.*' => $this->allowedMentionRules(), + 'channel_configuration.allowed_mentions.*' => ['nullable', 'string', Rule::in(DiscordAllowedMentionType::values())], 'enabled' => ['required', 'boolean'], 'delivery_url' => ['nullable', 'string', 'max:2048', 'url'], - 'message_template' => $this->messageTemplateRules(), - ]; - } - - /** - * @return array - */ - private function channels(): array - { - return array_map( - static fn (NotificationChannel $channel): string => $channel->value, - NotificationChannel::cases(), - ); - } - - /** - * @return array - */ - private function eventTypes(): array - { - return array_map( - static fn (NotificationEventType $eventType): string => $eventType->value, - NotificationEventType::cases(), - ); - } - - /** - * @return array - */ - private function messageTemplateRules(): array - { - if ($this->input('channel') === NotificationChannel::Discord->value) { - return ['required', 'string', 'max:2000']; - } - - return ['nullable', 'string', 'max:2000']; - } - - /** - * @return array - */ - private function allowedMentionRules(): array - { - return [ - 'nullable', - 'string', - Rule::in(self::DISCORD_ALLOWED_MENTION_TYPES), + 'message_template' => [Rule::requiredIf($this->input('channel') === NotificationChannel::Discord->value), 'string', 'max:2000'], ]; } } diff --git a/resources/js/pages/projects/settings/Notifications.vue b/resources/js/pages/projects/settings/Notifications.vue index ceca8a0..d415a48 100644 --- a/resources/js/pages/projects/settings/Notifications.vue +++ b/resources/js/pages/projects/settings/Notifications.vue @@ -44,23 +44,6 @@ const timestampFormatter = new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeStyle: 'short', }); -const discordAllowedMentionOptions: Array<{ - value: string; - label: string; -}> = [ - { - value: 'users', - label: 'User mentions (@username)', - }, - { - value: 'roles', - label: 'Role mentions (@role)', - }, - { - value: 'everyone', - label: '@everyone and @here', - }, -]; const breadcrumbs: BreadcrumbItem[] = [ { @@ -203,8 +186,8 @@ const notificationActionTimestamp = ( Create notification - Add a project-scoped notification action for - the supported ticket status change event. + Add a project-scoped notification action for the + supported ticket status change event. @@ -262,7 +245,9 @@ const notificationActionTimestamp = (
-
@@ -491,7 +480,11 @@ const notificationActionTimestamp = (
- {{ notificationActionTimestamp(notificationAction) }} + {{ + notificationActionTimestamp( + notificationAction, + ) + }} @@ -503,25 +496,19 @@ const notificationActionTimestamp = ( [project.id, notificationAction.id], ) " - :error-bag=" - `updateNotificationAction-${notificationAction.id}` - " + :error-bag="`updateNotificationAction-${notificationAction.id}`" class="space-y-4" v-slot="{ errors, processing }" >
@@ -669,8 +646,9 @@ const notificationActionTimestamp = (

{{ - selectedChannel(notificationAction) === - 'discord' + selectedChannel( + notificationAction, + ) === 'discord' ? 'Pick which Discord mention types are allowed. Leave all unchecked to keep mentions fully disabled.' : 'Allowed mentions are only used when the channel is Discord.' }} @@ -682,16 +660,12 @@ const notificationActionTimestamp = (