diff --git a/app/Actions/UpdateUserProfile.php b/app/Actions/UpdateUserProfile.php index 3333eb16f..5274f9656 100644 --- a/app/Actions/UpdateUserProfile.php +++ b/app/Actions/UpdateUserProfile.php @@ -7,6 +7,7 @@ use App\Dto\GitHubProfile; use App\Jobs\LookUpUserOrganizations; use App\Models\User; +use App\Queries\GitHubReadmeQuery; use App\Services\GitHub; use Illuminate\Database\UniqueConstraintViolationException; use Illuminate\Http\Client\ConnectionException; @@ -14,8 +15,8 @@ use Illuminate\Support\Facades\DB; /** - * Mirrors the GitHub profile and SSH keys of a user again, without them having to sign in, and looks the organizations - * their bio and company mention up. + * Mirrors the GitHub profile, profile README and SSH keys of a user again, without them having to sign in, and looks + * the organizations their bio and company mention up. */ final readonly class UpdateUserProfile { @@ -23,6 +24,7 @@ public function __construct( private GitHub $github, private UpdateUserSshKeys $updateUserSshKeys, private UpdateStaleHandles $updateStaleHandles, + private GitHubReadmeQuery $readme, ) { // } @@ -51,6 +53,8 @@ public function handle(User $user): bool }); LookUpUserOrganizations::dispatchFor($user); + + $this->readme->forget($user); } catch (ConnectionException|RequestException|UniqueConstraintViolationException $exception) { report($exception); diff --git a/app/Queries/GitHubReadmeQuery.php b/app/Queries/GitHubReadmeQuery.php index 92f25ff6d..e2d21b7b1 100644 --- a/app/Queries/GitHubReadmeQuery.php +++ b/app/Queries/GitHubReadmeQuery.php @@ -40,8 +40,8 @@ public function __construct(private GitHub $github) */ public function get(User $user): string|false|null { - $key = "github-readme:{$user->github_id}"; - $failedKey = "github-readme-failed:{$user->github_id}"; + $key = $this->key($user); + $failedKey = $this->failedKey($user); /** @var string|null $html */ $html = Cache::get($key); @@ -65,6 +65,25 @@ public function get(User $user): string|false|null return $html === '' ? null : $html; } + /** + * Read the README from GitHub again on the next view, as someone who syncs their profile expects to see theirs. + */ + public function forget(User $user): void + { + Cache::forget($this->key($user)); + Cache::forget($this->failedKey($user)); + } + + private function key(User $user): string + { + return "github-readme:{$user->github_id}"; + } + + private function failedKey(User $user): string + { + return "github-readme-failed:{$user->github_id}"; + } + /** * @throws HttpClientException */ diff --git a/tests/Unit/Actions/UpdateUserProfileTest.php b/tests/Unit/Actions/UpdateUserProfileTest.php index 28c8d84e2..9f05dfdc3 100644 --- a/tests/Unit/Actions/UpdateUserProfileTest.php +++ b/tests/Unit/Actions/UpdateUserProfileTest.php @@ -6,6 +6,7 @@ use App\Jobs\LookUpUserOrganizations; use App\Models\SshKey; use App\Models\User; +use App\Queries\GitHubReadmeQuery; use Illuminate\Http\Client\Request; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Queue; @@ -99,6 +100,34 @@ ->and($user->sshKeys()->sole()->fingerprint)->toBe($publicKey->fingerprint()); }); +it('reads the readme from github again, so an edited one shows after syncing', function (): void { + $user = User::factory()->create(); + + fakeGitHubAccount($user); + Http::fake(['api.github.com/repos/octocat/octocat/readme' => Http::sequence()->push('
Old
')->push('New
')]); + + expect(resolve(GitHubReadmeQuery::class)->get($user))->toBe('Old
'); + + resolve(UpdateUserProfile::class)->handle($user); + + expect(resolve(GitHubReadmeQuery::class)->get($user))->toBe('New
'); +}); + +it('keeps the cached readme when the sync fails', function (): void { + $user = User::factory()->create(); + + Http::fake([ + "api.github.com/user/{$user->github_id}" => Http::sequence()->push(['login' => 'octocat'])->push(['message' => 'Error'], 500), + 'api.github.com/repos/octocat/octocat/readme' => Http::sequence()->push('Old
')->push('New
'), + ]); + + expect(resolve(GitHubReadmeQuery::class)->get($user))->toBe('Old
'); + + resolve(UpdateUserProfile::class)->handle($user); + + expect(resolve(GitHubReadmeQuery::class)->get($user))->toBe('Old
'); +}); + it('looks the account up by its github id, so a renamed handle cannot be claimed', function (): void { $user = User::factory()->create(['github_id' => '583231', 'handle' => 'old-handle']); diff --git a/tests/Unit/Queries/GitHubReadmeQueryTest.php b/tests/Unit/Queries/GitHubReadmeQueryTest.php index a03d2be14..5b8ed2e76 100644 --- a/tests/Unit/Queries/GitHubReadmeQueryTest.php +++ b/tests/Unit/Queries/GitHubReadmeQueryTest.php @@ -98,6 +98,22 @@ function fakeGitHubReadme(User $user, mixed $readme): void expect(resolve(GitHubReadmeQuery::class)->get($user))->toBe('Hi
'); }); +it('reads the readme again once forgotten, a failed read included', function (): void { + $user = User::factory()->create(); + + Http::fake([ + "api.github.com/user/{$user->github_id}" => Http::response(['login' => 'octocat']), + 'api.github.com/repos/octocat/octocat/readme' => Http::sequence()->push('Old
')->pushStatus(502)->push('New
'), + ]); + $readme = resolve(GitHubReadmeQuery::class); + + expect($readme->get($user))->toBe('Old
'); + $readme->forget($user); + expect($readme->get($user))->toBeFalse(); + $readme->forget($user); + expect($readme->get($user))->toBe('New
'); +}); + it('keeps a readme with uploaded images for a few minutes, as their links expire', function (string $html, int $minutes, bool $isFetchedAgain): void { $user = User::factory()->create();