Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
DB_DATABASE: externals_test
DB_USERNAME: root
DB_PASSWORD: ''
run: vendor/bin/phpunit --colors=always
run: vendor/bin/pest --colors=always

- name: PHPStan
run: vendor/bin/phpstan analyse --memory-limit=1G --no-progress
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@

declare(strict_types=1);

namespace App\Http\Controllers;
namespace App\Http\Controllers\Auth;

use App\Actions\GetOrCreateUser;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\InvalidStateException;
use Symfony\Component\HttpFoundation\Response;
use Throwable;

class LoginController extends Controller
class GithubController extends Controller
{
/**
* GitHub redirects back to this same URL after authorization, so this
* entry point handles both phases: sending the user to GitHub, and
* processing the callback once GitHub returns with a `code`.
*/
public function __invoke(Request $request): Response
{
if ($request->user()) {
Expand All @@ -24,6 +30,14 @@ public function __invoke(Request $request): Response
return Socialite::driver('github')->redirect();
}

return $this->handleCallback($request);
}

/**
* Handle the callback from GitHub after authorization.
*/
private function handleCallback(Request $request): Response
{
try {
$githubUser = Socialite::driver('github')->user();
} catch (InvalidStateException) {
Expand Down
38 changes: 0 additions & 38 deletions app/Http/Controllers/HomeController.php

This file was deleted.

16 changes: 0 additions & 16 deletions app/Http/Controllers/NewsController.php

This file was deleted.

26 changes: 0 additions & 26 deletions app/Http/Controllers/StatsController.php

This file was deleted.

50 changes: 0 additions & 50 deletions app/Http/Controllers/ThreadController.php

This file was deleted.

26 changes: 0 additions & 26 deletions app/Http/Controllers/TopController.php

This file was deleted.

30 changes: 0 additions & 30 deletions app/Http/Controllers/VoteController.php

This file was deleted.

10 changes: 1 addition & 9 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use App\Services\Search\AlgoliaSearchIndex;
use App\Services\Search\ReadOnlySearchIndex;
use App\Services\Search\SearchIndex;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use League\CommonMark\CommonMarkConverter;
use VStelmakh\UrlHighlight\Highlighter\HtmlHighlighter;
Expand Down Expand Up @@ -59,12 +58,5 @@ public function register(): void
$this->app->singleton(RssRfcBuilder::class, fn() => new RssRfcBuilder((string) config('externals.rss_host')));
}

public function boot(): void
{
View::share('version', (string) config('externals.version'));
View::share('assetsBaseUrl', (string) config('externals.assets_base_url'));
View::share('algoliaIndex', config('services.algolia.index_prefix') . 'emails');
View::share('noIndex', (bool) config('externals.no_index'));
View::share('debug', (bool) config('app.debug'));
}
public function boot(): void {}
}
25 changes: 25 additions & 0 deletions app/Providers/VoltServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php declare(strict_types=1);

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Livewire\Volt\Volt;

class VoltServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void {}

/**
* Bootstrap services.
*/
public function boot(): void
{
Volt::mount([
config('livewire.view_path', resource_path('views/livewire')),
resource_path('views/pages'),
]);
}
}
35 changes: 21 additions & 14 deletions app/Services/Email/ThreadQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,41 @@
use App\Models\Email;
use App\Models\User;
use App\Support\Email\ThreadItem;
use App\Support\Email\ThreadSummary;
use Illuminate\Support\Facades\DB;

/**
* Holds the multi-join thread aggregation queries that don't translate
* cleanly to Eloquent. Returns plain arrays for thread listings (consumed
* by views) and Email model instances for the threaded view.
* cleanly to Eloquent. Returns ThreadSummary value objects for thread
* listings and Email model instances for the threaded view.
*/
class ThreadQuery
{
/**
* @return array<int, array<string, mixed>>
* @return ThreadSummary[]
*/
public function findLatestThreads(int $page, ?User $user): array
{
return $this->findThreads('', 'ORDER BY threads.lastUpdate DESC', $page, $user);
return $this->findThreads('', [], 'ORDER BY threads.lastUpdate DESC', $page, $user);
}

/**
* @return array<int, array<string, mixed>>
* @return ThreadSummary[]
*/
public function findTopThreads(int $page, ?User $user): array
{
$where = 'WHERE threads.votes > 0 AND threads.lastUpdate > DATE_SUB(NOW(), INTERVAL 1 MONTH)';
$where = 'WHERE threads.votes > 0 AND threads.lastUpdate > ?';
$oneMonthAgo = now()->subMonth()->toDateTimeString();

return $this->findThreads($where, 'ORDER BY threads.votes DESC, threads.lastUpdate DESC', $page, $user);
return $this->findThreads($where, [$oneMonthAgo], 'ORDER BY threads.votes DESC, threads.lastUpdate DESC', $page, $user);
}

/**
* @return array<int, array<string, mixed>>
* @return ThreadSummary[]
*/
public function findLatestRfcThreads(): array
{
return $this->findThreads("WHERE threadInfos.subject LIKE '%RFC%'", 'ORDER BY threadInfos.date DESC', 1, null);
return $this->findThreads("WHERE threadInfos.subject LIKE '%RFC%'", [], 'ORDER BY threadInfos.date DESC', 1, null);
}

/**
Expand Down Expand Up @@ -94,9 +96,13 @@ public function getThreadView(Email $email, ?User $user = null): array
}

/**
* @return array<int, array<string, mixed>>
* @return ThreadSummary[]
*/
private function findThreads(string $where, string $orderBy, int $page, ?User $user): array
/**
* @param list<mixed> $whereBindings Bindings for any `?` placeholders in $where.
* @return ThreadSummary[]
*/
private function findThreads(string $where, array $whereBindings, string $orderBy, int $page, ?User $user): array
{
$page = max(1, $page);
$offset = ($page - 1) * 20;
Expand All @@ -121,14 +127,15 @@ private function findThreads(string $where, string $orderBy, int $page, ?User $u
$orderBy
LIMIT 20 OFFSET $offset
SQL;
$parameters = [$user->id, $user->id];
$parameters = [$user->id, $user->id, ...$whereBindings];
} else {
$query = <<<SQL
SELECT
threads.emailNumber as number,
threadInfos.subject,
threadInfos.date,
threadInfos.fromName,
threadInfos.fromEmail,
threads.emailCount,
threads.lastUpdate,
threads.votes,
Expand All @@ -140,9 +147,9 @@ private function findThreads(string $where, string $orderBy, int $page, ?User $u
$orderBy
LIMIT 20 OFFSET $offset
SQL;
$parameters = [];
$parameters = $whereBindings;
}

return array_map(fn($row) => (array) $row, DB::select($query, $parameters));
return array_map(ThreadSummary::fromRow(...), DB::select($query, $parameters));
}
}
Loading
Loading