Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions app/Actions/Discord/Channels/CreateChannel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Actions\Discord\Channels;

use ReflectionException;
use Saloon\Contracts\Response;
use App\Enums\Discord\ChannelType;
use App\Actions\Discord\DiscordAction;
use Saloon\Exceptions\PendingRequestException;
use Saloon\Exceptions\InvalidResponseClassException;
use App\Http\Integrations\Discord\Channel\Requests\CreateGuildChannel;

class CreateChannel
{
use DiscordAction;

/**
* @throws InvalidResponseClassException
* @throws ReflectionException
* @throws PendingRequestException
*/
public function execute(
string $name,
ChannelType $channelType = ChannelType::TEXT,
?string $parentId = null

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is your opinion on union types?

I think its more readable and clear using it, like null|string

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for null its ok to use "?"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string|int|null ok
bcuz ?string|int not readable and may not work

): Response {
$request = new CreateGuildChannel(
name: $name,
channelType: $channelType,
parentId: $parentId,
);

return $this->connector->send($request);
}
}
49 changes: 49 additions & 0 deletions app/Actions/Discord/Channels/CreateThreadFromRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace App\Actions\Discord\Channels;

use Exception;
use App\Models\Channel;
use App\Models\Repository;
use Illuminate\Support\Str;
use App\DTO\Discord\ChannelData;
use App\Enums\Discord\ChannelType;
use Illuminate\Database\Eloquent\Model;

class CreateThreadFromRepository
{
public function execute(Repository $repository): Model|bool
{
try {
/** @var ChannelData $threadData */
$threadData = app(CreateChannel::class)->execute(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it ok to create a forum on discord per repository?!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes ! but we have to re work this pr, lot of change since and i want to make a lot of new thing.

My idea was : One Forum per repo and one thread into the forum per pr

name: $this->generateChannelName($repository->full_name),
channelType: ChannelType::FORUM,
parentId: config('services.discord.channels.code_reviews'),
)->dtoOrFail();

return $repository->channels()->save(
new Channel([
'channel_id' => $threadData->channelId,
'parent_id' => $threadData->parentId,
'guild_id' => $threadData->guildId,
'type' => $threadData->type,
'name' => $threadData->name,
]),
);
} catch (Exception) {
return false;
}
}

private function generateChannelName(string $name): string
{
return Str::slug(
title: Str::replace(
search: '/',
replace: '-',
subject: $name,
),
);
}
}
15 changes: 15 additions & 0 deletions app/Actions/Discord/DiscordAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace App\Actions\Discord;

use App\Http\Integrations\Discord\DiscordAPIConnector;

trait DiscordAction
{
protected DiscordAPIConnector $connector;

public function __construct()
{
$this->connector = new DiscordAPIConnector;
}
}
15 changes: 8 additions & 7 deletions app/Actions/Github/Repository/CreateWebhook.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

namespace App\Actions\Github\Repository;

use App\Models\Webhook;
use ReflectionException;
use App\Models\Repository;
use Saloon\Contracts\Response;
use App\Actions\Github\GithubAction;
use Saloon\Exceptions\PendingRequestException;
Expand All @@ -20,12 +18,15 @@ class CreateWebhook
* @throws ReflectionException
* @throws PendingRequestException
*/
public function execute(Repository $repository): Response
{
public function execute(
string $username,
string $repository,
string $secret,
): Response {
$request = new CreateRepositoryWebhook(
username: $repository->username,
repository: $repository->repository,
secret: $repository->node_id
username: $username,
repository: $repository,
secret: $secret,
);

return $this->connector->send($request);
Expand Down
35 changes: 35 additions & 0 deletions app/Actions/Github/Repository/CreateWebhookFromRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Actions\Github\Repository;

use Exception;
use App\Models\Webhook;
use App\Models\Repository;
use App\Actions\Github\GithubAction;
use Illuminate\Support\Facades\Hash;
use Illuminate\Database\Eloquent\Model;

class CreateWebhookFromRepository
{
use GithubAction;

public function execute(Repository $repository): Model|bool
{
try {
$webhookData = app(CreateWebhook::class)->execute(
username: $repository->username,
repository: $repository->repository,
secret: Hash::make($repository->node_id),
)->dtoOrFail();

return $repository->webhooks()->save(
new Webhook([
'title' => $repository->full_name . ' hook',
'hook_id' => $webhookData->id,
]),
);
} catch (Exception) {
return false;
}
}
}
23 changes: 23 additions & 0 deletions app/DTO/Discord/ChannelData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace App\DTO\Discord;

use Spatie\LaravelData\Data;
use App\Enums\Discord\ChannelType;
use Spatie\LaravelData\Attributes\MapInputName;
use Spatie\LaravelData\Mappers\SnakeCaseMapper;
use Spatie\LaravelData\Attributes\MapOutputName;

#[MapInputName(SnakeCaseMapper::class)]
#[MapOutputName(SnakeCaseMapper::class)]
class ChannelData extends Data
{
public function __construct(
#[MapInputName('id')]
public string $channelId,
public ChannelType $type,
public string $name,
public ?string $parentId,
public string $guildId,
) {}
}
22 changes: 22 additions & 0 deletions app/Enums/Discord/ChannelType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace App\Enums\Discord;

/**
* @link https://discord.com/developers/docs/resources/channel#channel-object-channel-types Documentation
*/
enum ChannelType: int
{
case TEXT = 0; // a text channel within a server
case DM = 1; // a direct message between users
case VOICE = 2; // a voice channel within a server
case GROUP_DM = 3; // a direct message between multiple users
case CATEGORY = 4; // an organizational category that contains up to 50 channels
case ANNOUNCEMENT = 5; // a channel that users can follow and crosspost into their own server (formerly news channels)
case ANNOUNCEMENT_THREAD = 10; // a temporary sub-channel within a ANNOUNCEMENT channel
case PUBLIC_THREAD = 11; // a temporary sub-channel within a TEXT or FORUM channel
case PRIVATE_THREAD = 12; // a temporary sub-channel within a TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission
case STAGE_VOICE = 13; // a voice channel for hosting events with an audience
case DIRECTORY = 14; // the channel in a hub containing the listed servers
case FORUM = 15; // Channel that can only contain threads
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

namespace App\Http\Integrations\Discord\Channel\Requests;

use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Contracts\Response;
use App\DTO\Discord\ChannelData;
use Saloon\Contracts\Body\HasBody;
use App\Enums\Discord\ChannelType;
use Saloon\Traits\Body\HasJsonBody;

class CreateGuildChannel extends Request implements HasBody
{
use HasJsonBody;

/**
* Define the HTTP method
*
* @var Method
*/
protected Method $method = Method::POST;

public function __construct(
public string $name,
public ChannelType $channelType = ChannelType::TEXT,
public string|int|null $parentId = null,
) {}

/**
* Define the endpoint for the request
*
* @return string
*/
public function resolveEndpoint(): string
{
return '/guilds/'
. config('services.discord.guild_id')
. '/channels';
}

protected function defaultBody(): array
{
return [
'name' => $this->name,
'type' => $this->channelType->value,
'parent_id' => $this->parentId,
];
}

/**
* @param Response $response
*
* @return ChannelData
*/
public function createDtoFromResponse(Response $response): ChannelData
{
return ChannelData::from($response->collect());
}
}
48 changes: 48 additions & 0 deletions app/Http/Integrations/Discord/DiscordAPIConnector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace App\Http\Integrations\Discord;

use Saloon\Http\Connector;
use Saloon\Traits\Plugins\AcceptsJson;
use Saloon\Http\Auth\TokenAuthenticator;
use Saloon\Traits\Plugins\AlwaysThrowOnErrors;

/**
* @link https://discord.com/developers/docs/intro Documentation
*/
class DiscordAPIConnector extends Connector
{
use AcceptsJson, AlwaysThrowOnErrors;

/**
* The Base URL of the API
*
* @return string
*/
public function resolveBaseUrl(): string
{
return (string)config('services.discord.base_path');
}

/**
* @return string[]
*/
protected function defaultHeaders(): array
{
return [
'accept' => 'application/json',
'Content-Type' => 'application/json',
];
}

/**
* @return TokenAuthenticator
*/
protected function defaultAuth(): TokenAuthenticator
{
return new TokenAuthenticator(
token: (string)config('services.discord.bot_token'),
prefix: 'Bot'
);
}
}
2 changes: 1 addition & 1 deletion app/Http/Integrations/Github/GithubApiConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class GithubApiConnector extends Connector
*/
public function resolveBaseUrl(): string
{
return (string) config('github.api.base_path');
return (string) config('services.github.base_path');
}

/**
Expand Down
31 changes: 31 additions & 0 deletions app/Jobs/Discord/Channels/CreateThreadFromRepositoryJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace App\Jobs\Discord\Channels;

use App\Models\Repository;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Actions\Discord\Channels\CreateThreadFromRepository;

class CreateThreadFromRepositoryJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

/**
* Create a new job instance.
*/
public function __construct(
protected Repository $repository
) {}

/**
* Execute the job.
*/
public function handle(): void
{
app(CreateThreadFromRepository::class)->execute($this->repository);
}
}
31 changes: 31 additions & 0 deletions app/Jobs/Github/Repository/CreateWebhookFromRepositoryJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace App\Jobs\Github\Repository;

use App\Models\Repository;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Actions\Github\Repository\CreateWebhookFromRepository;

class CreateWebhookFromRepositoryJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

/**
* Create a new job instance.
*/
public function __construct(
protected Repository $repository
) {}

/**
* Execute the job.
*/
public function handle(): void
{
app(CreateWebhookFromRepository::class)->execute($this->repository);
}
}
Loading