Skip to content

Commit 6a1f6c2

Browse files
author
Andy Ford
committed
feat: discord messages sent by services
1 parent d9332a9 commit 6a1f6c2

File tree

45 files changed

+1135
-175
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1135
-175
lines changed

.env.example

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,13 @@ DISCORD_AUTH_TOKEN=abc
6262
DISCORD_WEBHOOK_URL=def
6363
DISCORD_USERNAME=FlowBot
6464
DISCORD_AVATAR_URL="${APP_URL}/images/logo.png"
65+
DISCORD_ECFMP_CHANNEL_ID="971531731096203364"
6566

6667
# Sentry monitoring
6768
SENTRY_LARAVEL_DSN=
6869
SENTRY_TRACES_SAMPLE_RATE=1.0
6970

7071
# Discord bot
71-
DISCORD_BOT_SERVICE_URL="discord_bot:80"
72+
DISCORD_BOT_SERVICE_URL="discord-bot:80"
7273
DISCORD_BOT_JWT="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlY2ZtcC1mbG93IiwiYXVkIjoiZWNmbXAtZGlzY29yZC1kZXYiLCJpYXQiOjIxMzg0NTQ1NTUsImlzcyI6ImVjZm1wLWF1dGgifQ.PqbCEe_zW1WBLio6aD0P5OksRI1H-hoRRA8168OJg-h11SjyZeDCAAf0CjgZAUy6vUpSdfgN9KH1SgCSM4J38-2txpZLr_VlJTu9_W1mGEVr1_pGjMgbkwx8PMTP1f3J2R0BwGz-324vpPVB9zu6NG9ujS48AD28mDoqMpqc7UOK0_e9WJ7cQBb8BxU10w4TQXbwhjUMyZBIpdiaDK5OsQeXJruo0OjSlltiFJkXPmESTz_DwwTSvIqzmhjzQfNW62RVcnBrnbWaaCg1mC6FSIMffjrEgian_AyAg1iftjy_fa3f-sU-z65xMh8vVwAvJEhYJCA0CZO4lKn_OV0RXqYjCLI4t-Rp6MYULyLbp6QZ88MOvSXd-8GnYnxDE5o5-rLFnQ04LCGx2-yBDPZ80brdxZR26Im1DrNiPyUFadINGf8wwZ4-iWqmY6_QSfJYU1C3Y5s7TxMBFfa934NHICg53gVSEdfCHQIaciOSu91P1FnGIvdtOQV_n7urF5HRYyxOUomSa4MY4m5C1-TJqpBkCsAXbMdC_mIllFWnUCB5uBj5T18mxW1mrGQiF3Vy6_MrSeFoY0LEnd58QpvnG7-OuZWnrIbDDTAnTcI1IMVUA4zcoUvkUcCcRvBQD2bXsPgL9Lh8RmYvjrR2hWhmlJU-k_CPiQOLfW9qOFGp5rA"
74+
DISCORD_CLIENT_REQUEST_APP_ID="ecfmpdev"
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use Illuminate\Console\Command;
6+
use Illuminate\Support\Facades\Log;
7+
use App\Discord\FlowMeasure\Generator\EcfmpFlowMeasureMessageGenerator;
8+
9+
class SendEcfmpDiscordMessages extends Command
10+
{
11+
/**
12+
* The name and signature of the console command.
13+
*
14+
* @var string
15+
*/
16+
protected $signature = 'discord:send-ecfmp-messages';
17+
18+
/**
19+
* The console command description.
20+
*
21+
* @var string
22+
*/
23+
protected $description = 'Send ECFMP Discord messages';
24+
25+
public function handle(EcfmpFlowMeasureMessageGenerator $generator): int
26+
{
27+
if (!config('discord.enabled')) {
28+
Log::info('Skipping discord notifications, disabled in config');
29+
return 0;
30+
}
31+
32+
Log::info('Sending discord notifications');
33+
$generator->generateAndSend();
34+
Log::info('Discord notification sending complete');
35+
36+
return 0;
37+
}
38+
}

app/Discord/DiscordServiceInterface.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace App\Discord;
44

55
use App\Discord\Exception\DiscordServiceException;
6-
use App\Discord\Message\MessageInterface;
6+
use App\Discord\Message\EcfmpMessageInterface;
77

88
interface DiscordServiceInterface
99
{
@@ -12,5 +12,5 @@ interface DiscordServiceInterface
1212
*
1313
* @throws DiscordServiceException
1414
*/
15-
public function sendMessage(string $clientRequestId, MessageInterface $message): string;
15+
public function sendMessage(string $clientRequestId, EcfmpMessageInterface $message): string;
1616
}

app/Discord/DiscordServiceMessageSender.php

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use App\Discord\Client\ClientFactoryInterface;
66
use App\Discord\Exception\DiscordServiceException;
7-
use App\Discord\Message\MessageInterface;
7+
use App\Discord\Message\EcfmpMessageInterface;
88
use Ecfmp_discord\CreateRequest;
99
use Log;
1010

@@ -19,7 +19,7 @@ public function __construct(ClientFactoryInterface $discordClientFactory)
1919
$this->discordClientFactory = $discordClientFactory;
2020
}
2121

22-
public function sendMessage(string $clientRequestId, MessageInterface $message): string
22+
public function sendMessage(string $clientRequestId, EcfmpMessageInterface $message): string
2323
{
2424
$client = $this->discordClientFactory->create();
2525

@@ -36,6 +36,7 @@ public function sendMessage(string $clientRequestId, MessageInterface $message):
3636
[$response, $status] = $client->Create(
3737
new CreateRequest(
3838
[
39+
'channel' => $message->channel(),
3940
'content' => $message->content(),
4041
'embeds' => $message->embeds()->toProtobuf(),
4142
]
@@ -55,16 +56,6 @@ public function sendMessage(string $clientRequestId, MessageInterface $message):
5556
throw new DiscordServiceException('Discord grpc call failed');
5657
}
5758

58-
// TODO:
59-
// Discord message sender can remain the same...
60-
// The "new" sender can remain the same, but of course we give it an "update" method
61-
62-
// The class "Sender" now only handles division webhooks
63-
64-
// We create a new set of filters that filter out messages to send based on its ECFMP bot status
65-
// We create a new "associator" type for ECFMP messages
66-
// We create a new sender class for ECFMP messages (for first time sending)
67-
// Updates, we handle outside of the normal flow (e.g. a job)
6859
return $response->getId();
6960
}
7061
}

app/Discord/FlowMeasure/Content/FlowMeasureRecipientsFactory.php

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
namespace App\Discord\FlowMeasure\Content;
44

55
use App\Discord\FlowMeasure\Provider\PendingMessageInterface;
6+
use App\Discord\FlowMeasure\Provider\PendingWebhookMessageInterface;
67
use App\Discord\Message\Tag\Tag;
78
use App\Enums\DiscordNotificationType;
9+
use App\Models\DiscordNotification;
810
use App\Models\DivisionDiscordNotification;
911
use App\Models\DiscordTag;
1012
use App\Models\DivisionDiscordWebhook;
@@ -13,18 +15,25 @@
1315

1416
class FlowMeasureRecipientsFactory
1517
{
16-
public function makeRecipients(PendingMessageInterface $pendingMessage): FlowMeasureRecipientsInterface
18+
public function makeRecipients(PendingWebhookMessageInterface $pendingMessage): FlowMeasureRecipientsInterface
19+
{
20+
if ($this->hasRecentlyBeenNotifiedToWebhook($pendingMessage)) {
21+
return new NoRecipients();
22+
}
23+
24+
return $this->divisionRecipients($pendingMessage);
25+
}
26+
27+
public function makeEcfmpRecipients(PendingMessageInterface $pendingMessage): FlowMeasureRecipientsInterface
1728
{
1829
if ($this->hasRecentlyBeenNotified($pendingMessage)) {
1930
return new NoRecipients();
2031
}
2132

22-
return $pendingMessage->webhook() === null
23-
? $this->ecfmpRecipients($pendingMessage)
24-
: $this->divisionRecipients($pendingMessage);
33+
return $this->ecfmpRecipients($pendingMessage);
2534
}
2635

27-
private function hasRecentlyBeenNotified(PendingMessageInterface $pendingMessage): bool
36+
private function hasRecentlyBeenNotifiedToWebhook(PendingWebhookMessageInterface $pendingMessage): bool
2837
{
2938
$measure = $pendingMessage->flowMeasure();
3039
return $pendingMessage->type(
@@ -34,6 +43,16 @@ private function hasRecentlyBeenNotified(PendingMessageInterface $pendingMessage
3443
) !== null;
3544
}
3645

46+
private function hasRecentlyBeenNotified(PendingMessageInterface $pendingMessage): bool
47+
{
48+
$measure = $pendingMessage->flowMeasure();
49+
return $pendingMessage->type(
50+
) === DiscordNotificationType::FLOW_MEASURE_ACTIVATED && $measure->notifiedEcfmpNotifications->firstWhere(
51+
fn (DiscordNotification $notification) => $notification->created_at > Carbon::now()->subHour() &&
52+
$notification->pivot->notified_as === $measure->identifier
53+
) !== null;
54+
}
55+
3756
private function ecfmpRecipients(PendingMessageInterface $pendingMessage): FlowMeasureRecipientsInterface
3857
{
3958
return new EcfmpInterestedParties(
@@ -44,7 +63,7 @@ private function ecfmpRecipients(PendingMessageInterface $pendingMessage): FlowM
4463
);
4564
}
4665

47-
private function divisionRecipients(PendingMessageInterface $pendingMessage): FlowMeasureRecipientsInterface
66+
private function divisionRecipients(PendingWebhookMessageInterface $pendingMessage): FlowMeasureRecipientsInterface
4867
{
4968
$recipients = DivisionDiscordWebhook::find($pendingMessage->webhook()->id())
5069
->flightInformationRegions

app/Discord/FlowMeasure/Embed/ActivatedEmbeds.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function embeds(): EmbedCollection
3939
: IdentifierAndActiveStatus::create($this->pendingMessage->flowMeasure())
4040
)
4141
->withDescription(new EventName($this->pendingMessage->flowMeasure()))
42-
->withField(Field::make(new IssuingUser($this->pendingMessage->flowMeasure())), is_null($this->pendingMessage->webhook()->id()))
42+
->withField(Field::make(new IssuingUser($this->pendingMessage->flowMeasure())), $this->pendingMessage->isEcfmp())
4343
->withField(Field::makeInline(new Restriction($this->pendingMessage->flowMeasure())))
4444
->withField(Field::makeInline(new StartTime($this->pendingMessage->flowMeasure())))
4545
->withField(Field::makeInline(new EndTime($this->pendingMessage->flowMeasure())))

app/Discord/FlowMeasure/Embed/NotifiedEmbeds.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function embeds(): EmbedCollection
3939
: IdentifierAndNotifiedStatus::create($this->pendingMessage->flowMeasure())
4040
)
4141
->withDescription(new EventName($this->pendingMessage->flowMeasure()))
42-
->withField(Field::make(new IssuingUser($this->pendingMessage->flowMeasure())), is_null($this->pendingMessage->webhook()))
42+
->withField(Field::make(new IssuingUser($this->pendingMessage->flowMeasure())), $this->pendingMessage->isEcfmp())
4343
->withField(Field::makeInline(new Restriction($this->pendingMessage->flowMeasure())))
4444
->withField(Field::makeInline(new StartTime($this->pendingMessage->flowMeasure())))
4545
->withField(Field::makeInline(new EndTime($this->pendingMessage->flowMeasure())))
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace App\Discord\FlowMeasure\Generator;
4+
5+
use App\Discord\FlowMeasure\Helper\EcfmpNotificationReissuer;
6+
use App\Discord\FlowMeasure\Provider\PendingEcfmpMessage;
7+
use App\Discord\FlowMeasure\Sender\EcfmpFlowMeasureSender;
8+
use App\Repository\FlowMeasureNotification\RepositoryInterface;
9+
10+
class EcfmpFlowMeasureMessageGenerator
11+
{
12+
private readonly EcfmpFlowMeasureSender $sender;
13+
14+
/** @var RepositoryInterface[] */
15+
private readonly array $repositories;
16+
17+
public function __construct(EcfmpFlowMeasureSender $sender, array $repositories)
18+
{
19+
$this->sender = $sender;
20+
$this->repositories = $repositories;
21+
}
22+
23+
public function generateAndSend(): void
24+
{
25+
foreach ($this->repositories as $repository) {
26+
foreach ($repository->flowMeasuresToBeSentToEcfmp() as $measure) {
27+
$pendingMessage = new PendingEcfmpMessage(
28+
$measure->measure,
29+
$repository->notificationType(),
30+
new EcfmpNotificationReissuer($measure, $repository->notificationType())
31+
);
32+
33+
$this->sender->send($pendingMessage);
34+
}
35+
}
36+
}
37+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace App\Discord\FlowMeasure\Helper;
4+
5+
use App\Discord\FlowMeasure\Helper\NotificationReissuerInterface;
6+
use App\Enums\DiscordNotificationType;
7+
use App\Repository\FlowMeasureNotification\FlowMeasureForNotification;
8+
9+
class EcfmpNotificationReissuer implements NotificationReissuerInterface
10+
{
11+
private readonly FlowMeasureForNotification $flowMeasureForNotification;
12+
private readonly DiscordNotificationType $type;
13+
14+
public function __construct(FlowMeasureForNotification $flowMeasureForNotification, DiscordNotificationType $type)
15+
{
16+
$this->flowMeasureForNotification = $flowMeasureForNotification;
17+
$this->type = $type;
18+
}
19+
20+
public function isReissuedNotification(): bool
21+
{
22+
return ($this->type === DiscordNotificationType::FLOW_MEASURE_ACTIVATED || $this->type === DiscordNotificationType::FLOW_MEASURE_NOTIFIED)
23+
&& $this->flowMeasureForNotification->isReissuedNotification;
24+
}
25+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace App\Discord\FlowMeasure\Message;
4+
5+
use App\Discord\FlowMeasure\Content\FlowMeasureRecipientsInterface;
6+
use App\Discord\FlowMeasure\Embed\FlowMeasureEmbedInterface;
7+
use App\Discord\Message\EcfmpMessageInterface;
8+
use App\Discord\Message\Embed\EmbedCollection;
9+
10+
class EcfmpFlowMeasureMessage implements EcfmpMessageInterface
11+
{
12+
private readonly string $channel;
13+
private readonly FlowMeasureRecipientsInterface $recipients;
14+
private readonly FlowMeasureEmbedInterface $embeds;
15+
16+
public function __construct(string $channel, FlowMeasureRecipientsInterface $recipients, FlowMeasureEmbedInterface $embeds)
17+
{
18+
$this->channel = $channel;
19+
$this->recipients = $recipients;
20+
$this->embeds = $embeds;
21+
}
22+
23+
public function channel(): string
24+
{
25+
return $this->channel;
26+
}
27+
28+
public function content(): string
29+
{
30+
return $this->recipients->toString();
31+
}
32+
33+
public function embeds(): EmbedCollection
34+
{
35+
return $this->embeds->embeds();
36+
}
37+
}

0 commit comments

Comments
 (0)