Skip to content

Commit

Permalink
add likes for frameworks
Browse files Browse the repository at this point in the history
  • Loading branch information
butschster committed Apr 25, 2024
1 parent 2c50173 commit 3d14617
Show file tree
Hide file tree
Showing 19 changed files with 366 additions and 20 deletions.
3 changes: 3 additions & 0 deletions app/app/src/Application/Bootloader/GithubBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use App\Github\Client;
use App\Github\ClientInterface;
use App\Github\WebhookGate;
use Psr\Log\LoggerInterface;
use Spiral\Boot\Bootloader\Bootloader;
use Spiral\Boot\EnvironmentInterface;
use Spiral\Cache\CacheStorageProviderInterface;
Expand All @@ -19,6 +20,7 @@ public function defineSingletons(): array
return [
ClientInterface::class => static fn(
CacheStorageProviderInterface $cache,
LoggerInterface $logger,
EnvironmentInterface $env,
) => new CacheableClient(
client: new Client(
Expand All @@ -29,6 +31,7 @@ public function defineSingletons(): array
'Authorization' => 'Bearer ' . $env->get('GITHUB_TOKEN'),
],
]),
logger: $logger,
),
cache: $cache->storage('github'),
ttl: 300,
Expand Down
34 changes: 34 additions & 0 deletions app/app/src/Application/Event/Liked.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace App\Application\Event;

use App\Application\Broadcasting\Channel\EventsChannel;
use App\Application\Broadcasting\ShouldBroadcastInterface;
use Stringable;

final readonly class Liked implements ShouldBroadcastInterface
{
public function __construct(
public string $key,
) {
}

public function getEventName(): string
{
return 'liked';
}

public function getBroadcastTopics(): iterable|Stringable
{
return new EventsChannel();
}

public function jsonSerialize(): array
{
return [
'key' => $this->key,
];
}
}
3 changes: 2 additions & 1 deletion app/app/src/Endpoint/Centrifugo/RPCService.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public function createHttpRequest(Request\RPC $request): ServerRequestInterface
[$method, $uri] = \explode(':', $request->method, 2);
$method = \strtoupper($method);

$httpRequest = $this->requestFactory->createServerRequest(\strtoupper($method), \ltrim($uri, '/'))
$httpRequest = $this->requestFactory
->createServerRequest(\strtoupper($method), \ltrim($uri, '/'))
->withHeader('Content-Type', 'application/json');

$data = $request->getData();
Expand Down
132 changes: 132 additions & 0 deletions app/app/src/Endpoint/Event/LikeListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php

declare(strict_types=1);

namespace App\Endpoint\Event;

use App\Application\Event\Liked;
use Spiral\Events\Attribute\Listener;

final readonly class LikeListener
{
#[Listener]
public function __invoke(Liked $event): void
{
$phrases = [
"%s doesn't need documentation. It documents itself out of fear.",
"When %s autoloads classes, the classes come running.",
"Every time %s is mentioned, a junior developer gets their wings.",
"When %s is included, it includes itself in the conversation.",
"%s doesn't have to handle sessions. Sessions handle themselves.",
"When %s handles errors, errors apologize.",
"Frameworks wish they were as flexible as %s.",
"When %s routes requests, the requests take the scenic route.",
"When %s is updated, bugs quiver in fear.",
"Unit tests don't test framework. %s tests unit tests.",
"When %s handles databases, databases handle themselves with care.",
"When %s caches data, data stays cached out of respect.",
"When %s deploys, servers deploy themselves.",
"Every time %s echoes, the universe listens.",
"When %s handles requests, the requests handle themselves with care.",
"When %s optimizes code, the code becomes a better version of itself.",
"%s's security is so tight, hackers get locked out of reality.",
"When %s handles forms, the forms handle themselves with grace.",
"When %s validates input, input validates its own existence.",
"%s doesn't need MVC. MVC needs it.",
"When %s is installed, servers throw a party in it's honor.",
"When %s resolves dependencies, dependencies resolve to be better.",
"When %s handles exceptions, exceptions make excuses.",
"When %s sanitizes input, input feels cleaner.",
"%s's routing is so efficient, traffic patterns envy it.",
"When %s generates code, code generates admiration.",
"When %s manages configurations, configurations manage themselves.",
"When %s interacts with APIs, APIs beg for more.",
"When %s serializes data, data feels special.",
"When %s uses ORM, databases dream of being it's ORM.",
"When %s compiles assets, assets become works of art.",
"%s doesn't debug. It enlightens.",
"When %s handles cookies, cookies never crumble.",
"When %s handles assets, assets feel secured.",
"When %s handles authentication, passwords get stronger.",
"When %s manages sessions, sessions become unforgettable experiences.",
"When %s renders views, views see the world differently.",
"When %s manages dependencies, dependencies become interdependent on it.",
"When %s generates URLs, URLs find their way home.",
"When %s compiles templates, templates compile themselves out of admiration.",
"%s doesn't use ORM. ORM aspires to be like it.",
"When %s handles events, events plan to happen again next year.",
"When %s caches data, data gets preserved for posterity.",
"When %s handles files, files organize themselves alphabetically for it.",
"When %s interacts with databases, databases feel honored.",
"When %s validates inputs, inputs become validated members of society.",
"When %s manages configurations, configurations configure themselves.",
"When %s handles exceptions, exceptions rethink their life choices.",
"%s's documentation is so thorough, it's considered a literary masterpiece.",
"When %s generates forms, forms fill themselves out.",
"When %s optimizes code, code becomes an Olympic athlete.",
"When %s handles requests, the requests never go unfulfilled.",
"When %s handles caching, caches never forget their purpose.",
"When %s processes XML, XML becomes self-aware.",
"When %s compiles assets, assets become the envy of the digital world.",
"When %s interacts with databases, databases become more efficient.",
"When %s manages sessions, sessions feel like they've been to therapy.",
"When %s handles forms, forms fill themselves out with gratitude.",
"When %s handles cookies, cookies become gourmet treats.",
"When %s handles permissions, permissions become privileges.",
"%s doesn't need frameworks. Frameworks need it.",
"When %s optimizes images, images become timeless masterpieces.",
"When %s validates data, data feels validated.",
"When %s manages caching, caches never feel forgotten.",
"When %s compiles CSS, stylesheets become fashion statements.",
"When %s handles assets, assets feel like they're on the red carpet.",
"When %s handles events, events are remembered for centuries.",
"When %s handles cron jobs, time itself bends to its will.",
"When %s optimizes queries, databases become telepathic.",
"When %s manages dependencies, dependencies become lifelong friends.",
"When %s generates documentation, documentation becomes a bestseller.",
"%s doesn't have bugs. It has unexpected features.",
"%s can divide by zero.",
"All arrays in %s are associative.",
"When %s runs a foreach loop, the items actually foreach themselves.",
"%s doesn't need garbage collection because it doesn't litter.",
"The only way to stop %s from running is to wait for the heat death of the universe.",
"%s doesn't use try-catch blocks. It uses try-terminate blocks.",
"Instead of error messages, %s just writes 'I'm sorry, Dave' and continues.",
"If you code something wrong in %s, it apologizes to you.",
"%s doesn't follow PSR standards. PSR standards follow it.",
"When %s runs, the CPU watches in awe.",
"Rumor has it %s once compiled itself.",
"There is no such thing as an infinite loop in %s. They are called 'forever loops'.",
"The only design pattern %s follows is 'The Pattern'.",
"When %s throws an error, the entire internet hears it.",
"The shortest distance between two points is %s.",
"When %s writes code comments, the code listens.",
"The only thing %s can't do is fail.",
"When %s starts, the universe initializes.",
"The speed of light is measured in %s per second.",
"The Big Bang was just %s compiling.",
"When %s writes code, the compiler learns from it.",
"If %s were a superhero, it would be 'Infinite Man'.",
"The only framework %s uses is the Framework of Reality.",
"%s once solved the halting problem. With a while loop.",
"The only way to kill %s is to delete the universe.",
"When %s develops, other frameworks take notes.",
"%s doesn't have a repository. It has the Source of Truth.",
"When %s runs, RAM begs for mercy.",
"When %s starts, the internet slows down to watch.",
"If %s were a language, it would be called 'The Code'.",
"%s doesn't need version control. It controls versions.",
"The only framework %s fears is itself.",
"%s doesn't have bugs. It has features waiting to be discovered.",
"When %s is mentioned, servers shudder in excitement.",
"When %s compiles, time stops to admire.",
"The only test %s fails is the test of time.",
"%s doesn't need to optimize. It's already perfect.",
"When %s runs, CPU usage drops out of respect."
];

$phrase = $phrases[\array_rand($phrases)];

dump(\sprintf($phrase, $event->key));
}
}
32 changes: 32 additions & 0 deletions app/app/src/Endpoint/Http/Controller/LikeAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace App\Endpoint\Http\Controller;

use App\Application\Event\Liked;
use App\Application\Http\Response\ResourceInterface;
use App\Endpoint\Http\Filter\LikeRequest;
use App\Endpoint\Http\Resource\IssueCollection;
use App\Endpoint\Http\Resource\IssueResource;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Http\Message\ResponseInterface;
use Spiral\Http\ResponseWrapper;
use Spiral\Router\Annotation\Route;

final readonly class LikeAction
{
public function __construct(
private EventDispatcherInterface $events,
private ResponseWrapper $response,
) {
}

#[Route(route: 'like', name: 'like', methods: ['POST'], group: 'api')]
public function __invoke(LikeRequest $request): ResponseInterface
{
$this->events->dispatch(new Liked(key: $request->key));

return $this->response->create(200);
}
}
24 changes: 24 additions & 0 deletions app/app/src/Endpoint/Http/Filter/LikeRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace App\Endpoint\Http\Filter;

use Spiral\Filters\Attribute\Input\Post;
use Spiral\Filters\Model\FilterDefinitionInterface;
use Spiral\Filters\Model\HasFilterDefinition;
use Spiral\Filters\Model\Filter;
use Spiral\Validation\Laravel\FilterDefinition;

final class LikeRequest extends Filter implements HasFilterDefinition
{
#[Post]
public string $key;

public function filterDefinition(): FilterDefinitionInterface
{
return new FilterDefinition(validationRules: [
'key' => 'required|string',
]);
}
}
16 changes: 14 additions & 2 deletions app/app/src/Github/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
use App\Github\Entity\Issue;
use Carbon\Carbon;
use GuzzleHttp\Psr7\Request;
use Psr\Log\LoggerInterface;

final readonly class Client implements ClientInterface
{
public function __construct(
private \Psr\Http\Client\ClientInterface $client,
private LoggerInterface $logger,
) {
}

Expand All @@ -26,7 +28,7 @@ public function getStars(string $repository): int

$data = \json_decode($response->getBody()->getContents(), true);

return $data['stargazers_count'];
return $data['stargazers_count'] ?? 0;
}

public function getLastVersion(string $repository): string
Expand All @@ -40,7 +42,7 @@ public function getLastVersion(string $repository): string

$data = \json_decode($response->getBody()->getContents(), true);

return $data['tag_name'];
return $data['tag_name'] ?? '0.0.0';
}

public function getIssuesForContributors(): array
Expand Down Expand Up @@ -71,6 +73,16 @@ private function fetchRepositoryIssues(string $repository): array
),
);

if ($response->getStatusCode() !== 200) {
$this->logger->error('Failed to fetch issues', [
'repository' => $repository,
'status' => $response->getStatusCode(),
'body' => $response->getBody()->getContents(),
]);

return [];
}

$data = \json_decode($response->getBody()->getContents(), true);

return \array_map(
Expand Down
10 changes: 10 additions & 0 deletions spa/app/api/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ type SettingsApi = {
get: () => SettingsResponse,
}

type DataApi = {
like: () => void,
}

type ExamplesApi = {
call: (action: string) => void,
}
Expand All @@ -29,6 +33,12 @@ export default class Api {
this._examples_url = examples_url;
}

get data(): DataApi {
return {
like: apiMethods.like(this.rpc),
}
}

get settings(): SettingsApi {
return {
get: apiMethods.settings(this.rpc),
Expand Down
5 changes: 4 additions & 1 deletion spa/app/api/methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const team = (rpc: RPCClient) => () => rpc.call('get:api/team')
const issuesForContributors = (rpc: RPCClient) => () => rpc.call('get:api/issues/for-contributors')
.then((response: ServerResponse<IssuesResponse>) => response.data.data);

const like = (rpc: RPCClient) => (key: string) => rpc.call('post:api/like', {key});

const callExampleAction = (host: string) => (action: string) => {
action = action.toLowerCase();

Expand All @@ -32,5 +34,6 @@ export default {
settings,
team,
callExampleAction,
issuesForContributors
issuesForContributors,
like
}

0 comments on commit 3d14617

Please sign in to comment.