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
6 changes: 3 additions & 3 deletions app/Actions/CreateOrganizationAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace App\Actions;

use App\Enums\OrganizationRole;
use App\Models\Profile;
use App\Models\Organization;
use App\Models\User;
use Illuminate\Support\Facades\DB;

Expand All @@ -16,10 +16,10 @@
* claimed it first. The organization is locked while it's checked, as two members coming back from GitHub at once
* can both pass the request's check: the second claim then just doesn't happen.
*/
public function handle(Profile $organization, User $user): bool
public function handle(Organization $organization, User $user): bool
{
return DB::transaction(function () use ($organization, $user): bool {
Profile::query()->whereKey($organization->id)->lockForUpdate()->first();
Organization::query()->whereKey($organization->id)->lockForUpdate()->first();

if ($organization->admins()->exists()) {
return false;
Expand Down
4 changes: 2 additions & 2 deletions app/Actions/CreateOrganizationMember.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
namespace App\Actions;

use App\Enums\OrganizationRole;
use App\Models\Profile;
use App\Models\Organization;
use App\Models\User;

final readonly class CreateOrganizationMember
{
/**
* Adds the user to the organization as a member, whom an admin can then make an admin.
*/
public function handle(Profile $organization, User $user): void
public function handle(Organization $organization, User $user): void
{
$organization->members()->attach($user->id, ['role' => OrganizationRole::Member]);
}
Expand Down
6 changes: 3 additions & 3 deletions app/Actions/CreateOrganizationOpenGraphImage.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace App\Actions;

use App\Contracts\Services\GitHubProvider;
use App\Models\Profile;
use App\Models\Organization;
use App\Services\OpenGraphCanvas;
use Illuminate\Support\Facades\Cache;

Expand All @@ -24,7 +24,7 @@ public function __construct(private GitHubProvider $github)
//
}

public function handle(Profile $organization): string
public function handle(Organization $organization): string
{
return Cache::remember(
"open-graph-image:organization:{$organization->id}:{$organization->openGraphImageVersion()}",
Expand All @@ -36,7 +36,7 @@ public function handle(Profile $organization): string
/**
* Drawn like a profile's card, in the organization's lane, /dev/null's blue until its admins choose one.
*/
private function render(Profile $organization): string
private function render(Organization $organization): string
{
$canvas = new OpenGraphCanvas($this->github);
$lane = $organization->lane() === null ? OpenGraphCanvas::PRIMARY : $canvas->lane($organization->lane());
Expand Down
5 changes: 3 additions & 2 deletions app/Actions/DeleteOrganization.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace App\Actions;

use App\Enums\TopicType;
use App\Models\Profile;
use App\Models\Organization;
use Illuminate\Support\Facades\DB;

final readonly class DeleteOrganization
Expand All @@ -14,7 +14,7 @@
* Deletes an organization GitHub no longer has, with its members, and unlinks the commits that mention it, so none
* links to a page that is gone.
*/
public function handle(Profile $organization): void
public function handle(Organization $organization): void
{
DB::transaction(function () use ($organization): void {
DB::table('commit_topics')
Expand All @@ -24,6 +24,7 @@ public function handle(Profile $organization): void

$organization->members()->detach();
$organization->delete();
$organization->profile->delete();
});
}
}
9 changes: 4 additions & 5 deletions app/Actions/DeleteOrganizationMember.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

namespace App\Actions;

use App\Enums\OrganizationRole;
use App\Exceptions\OrganizationMustHaveAnAdmin;
use App\Models\Profile;
use App\Models\Organization;
use App\Models\User;
use Illuminate\Support\Facades\DB;

Expand All @@ -19,12 +18,12 @@
*
* @throws OrganizationMustHaveAnAdmin
*/
public function handle(Profile $organization, User $member): void
public function handle(Organization $organization, User $member): void
{
DB::transaction(function () use ($organization, $member): void {
Profile::query()->whereKey($organization->id)->lockForUpdate()->first();
Organization::query()->whereKey($organization->id)->lockForUpdate()->first();

if ($organization->roleOf($member) === OrganizationRole::Admin && $organization->admins()->whereKeyNot($member->id)->doesntExist()) {
if ($organization->isAdmin($member) && $organization->admins()->whereKeyNot($member->id)->doesntExist()) {
throw new OrganizationMustHaveAnAdmin($organization);
}

Expand Down
9 changes: 5 additions & 4 deletions app/Actions/UpdateMentionedOrganizations.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use App\Contracts\Services\GitHubProvider;
use App\Enums\ProfileType;
use App\Models\Organization;
use App\Models\Profile;
use Carbon\CarbonImmutable;
use Closure;
Expand Down Expand Up @@ -47,7 +48,7 @@ public function __construct(
public function handle(array $handles): ?CarbonImmutable
{
$profiles = Profile::query()->whereIn(DB::raw('LOWER(handle)'), $handles)->get();
$known = $profiles->where('type', ProfileType::Organization);
$known = Organization::query()->whereKey($profiles->where('type', ProfileType::Organization)->modelKeys())->get();

/** @var list<array{Closure(): (array<array-key, mixed>|null), Closure(): mixed}> $lookups */
$lookups = collect($handles)
Expand All @@ -58,9 +59,9 @@ public function handle(array $handles): ?CarbonImmutable
fn (): bool => Cache::put("github-organizations:not-found:{$handle}", true, now()->addDays(self::NotFoundDays)),
])
->merge($known
->filter(fn (Profile $organization): bool => $organization->github_synced_at?->addHours(Profile::FRESH_FOR_HOURS)->isPast() ?? true)
->map(fn (Profile $organization): array => [
fn (): ?array => $this->github->account($organization->github_id),
->filter(fn (Organization $organization): bool => $organization->github_synced_at?->addHours(Organization::FRESH_FOR_HOURS)->isPast() ?? true)
->map(fn (Organization $organization): array => [
fn (): ?array => $this->github->account($organization->profile->github_id),
function () use ($organization): void {
$this->deleteOrganization->handle($organization);
},
Expand Down
12 changes: 8 additions & 4 deletions app/Actions/UpdateOrCreateOrganization.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use App\Dto\GitHubProfile;
use App\Enums\ProfileType;
use App\Models\Organization;
use App\Models\Profile;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
Expand All @@ -23,20 +24,23 @@ public function __construct(private UpdateStaleHandles $updateStaleHandles)
*
* @param array<array-key, mixed> $account
*/
public function handle(array $account): Profile
public function handle(array $account): Organization
{
$profile = GitHubProfile::fromAccount($account);
$githubId = Arr::get($account, 'id');
assert(is_int($githubId));

return DB::transaction(function () use ($profile, $githubId): Profile {
return DB::transaction(function () use ($profile, $githubId): Organization {
$this->updateStaleHandles->handle($profile->handle, (string) $githubId);

return Profile::query()->updateOrCreate(['github_id' => (string) $githubId], [
// A profile never changes type: a user's account GitHub has since turned into an organization fails on its
// GitHub ID, until that case is handled...
$organization = Profile::query()->updateOrCreate(['github_id' => (string) $githubId, 'type' => ProfileType::Organization], [
...$profile->attributes(),
'type' => ProfileType::Organization,
'github_synced_at' => now(),
]);

return Organization::query()->firstOrCreate(['id' => $organization->id]);
});
}
}
3 changes: 2 additions & 1 deletion app/Actions/UpdateOrCreateUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ public function handle(GitHubUser $githubUser): User
return DB::transaction(function () use ($githubId, $profile, $email, $hasSponsorsListing): User {
$this->updateStaleHandles->handle($profile->handle, $githubId);

// A profile never changes type, so an organization's GitHub ID would fail here, but GitHub never signs one in...
Profile::query()->updateOrCreate([
'github_id' => $githubId,
], [
'type' => ProfileType::User,
], [
...$profile->attributes(),
'github_synced_at' => now(),
]);
Expand Down
4 changes: 2 additions & 2 deletions app/Actions/UpdateOrganizationLane.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

namespace App\Actions;

use App\Models\Profile;
use App\Models\Organization;

final readonly class UpdateOrganizationLane
{
public function handle(Profile $organization, ?int $lane, ?string $color): void
public function handle(Organization $organization, ?int $lane, ?string $color): void
{
$organization->update(['preferred_lane' => $lane, 'lane_color' => $color]);
}
Expand Down
6 changes: 3 additions & 3 deletions app/Actions/UpdateOrganizationMemberRole.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use App\Enums\OrganizationRole;
use App\Exceptions\OrganizationMustHaveAnAdmin;
use App\Models\Profile;
use App\Models\Organization;
use App\Models\User;
use Illuminate\Support\Facades\DB;

Expand All @@ -19,10 +19,10 @@
*
* @throws OrganizationMustHaveAnAdmin
*/
public function handle(Profile $organization, User $member, OrganizationRole $role): void
public function handle(Organization $organization, User $member, OrganizationRole $role): void
{
DB::transaction(function () use ($organization, $member, $role): void {
Profile::query()->whereKey($organization->id)->lockForUpdate()->first();
Organization::query()->whereKey($organization->id)->lockForUpdate()->first();

if ($role === OrganizationRole::Member && $organization->admins()->whereKeyNot($member->id)->doesntExist()) {
throw new OrganizationMustHaveAnAdmin($organization);
Expand Down
4 changes: 2 additions & 2 deletions app/Exceptions/OrganizationMustHaveAnAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace App\Exceptions;

use App\Models\Profile;
use App\Models\Organization;
use RuntimeException;

/**
Expand All @@ -13,7 +13,7 @@
*/
final class OrganizationMustHaveAnAdmin extends RuntimeException
{
public function __construct(public readonly Profile $organization)
public function __construct(public readonly Organization $organization)
{
parent::__construct(__('@:handle needs at least one admin.', ['handle' => $organization->handle]));
}
Expand Down
4 changes: 2 additions & 2 deletions app/Http/Controllers/Api/OrganizationMentionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use App\Http\Requests\ListApiOrganizationMentionsRequest;
use App\Http\Resources\CommitResource;
use App\Models\Commit;
use App\Models\Profile;
use App\Models\Organization;
use App\Models\User;
use App\Queries\OrganizationMentionsQuery;
use App\Queries\ReplyPreviewsQuery;
Expand All @@ -22,7 +22,7 @@
public function index(ListApiOrganizationMentionsRequest $request, #[CurrentUser] ?User $currentUser, OrganizationMentionsQuery $mentions, ReplyPreviewsQuery $replyPreviews): AnonymousResourceCollection
{
$organization = $request->organization();
assert($organization instanceof Profile);
assert($organization instanceof Organization);

if ($currentUser instanceof User) {
$signedCommits = $mentions->builder($organization, $currentUser)->cursorPaginate(20);
Expand Down
14 changes: 6 additions & 8 deletions app/Http/Controllers/OrganizationAdminController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
use App\Actions\CreateOrganizationAdmin;
use App\Contracts\Services\GitHubProvider;
use App\Enums\GitHubOrganizationMembership;
use App\Enums\ProfileType;
use App\Http\Requests\CreateOrganizationAdminRequest;
use App\Models\Profile;
use App\Models\Organization;
use App\Models\User;
use Illuminate\Container\Attributes\CurrentUser;
use Illuminate\Http\RedirectResponse;
Expand All @@ -32,7 +31,7 @@
/**
* Claiming starts from a form, so no other site can send a user who already granted the scope through it.
*/
public function create(CreateOrganizationAdminRequest $request, Profile $organization): SymfonyResponse
public function create(CreateOrganizationAdminRequest $request, Organization $organization): SymfonyResponse
{
$claimed = $this->claimed($organization);

Expand All @@ -50,11 +49,10 @@ public function create(CreateOrganizationAdminRequest $request, Profile $organiz
*/
public function store(Request $request, #[CurrentUser] User $user, GitHubProvider $github, CreateOrganizationAdmin $action): RedirectResponse
{
$organization = Profile::query()
->where('type', ProfileType::Organization)
$organization = Organization::query()
->find($request->session()->pull(self::CLAIMING));

if (! $organization instanceof Profile) {
if (! $organization instanceof Organization) {
Inertia::flash('toast', ['type' => 'error', 'message' => __('Unable to claim this organization. Please try again.')]);

return to_route('log.show', $user->log);
Expand Down Expand Up @@ -92,7 +90,7 @@ public function store(Request $request, #[CurrentUser] User $user, GitHubProvide

// An organization restricting OAuth apps hides its members from those its owners haven't approved, which they
// do from the app's page in their settings, where members request it.
$failure = match ($github->organizationMembership($githubUser->token, $handle, $organization->github_id)) {
$failure = match ($github->organizationMembership($githubUser->token, $handle, $organization->profile->github_id)) {
GitHubOrganizationMembership::Member => null,
GitHubOrganizationMembership::NotMember => [__('GitHub says you are not a member of @:handle.', ['handle' => $handle]), null],
GitHubOrganizationMembership::Restricted => [
Expand Down Expand Up @@ -132,7 +130,7 @@ private function github(): GitHubOAuthProvider
/**
* Only the first claim through GitHub makes an admin. Why another one fails, if the page was claimed.
*/
private function claimed(Profile $organization): ?string
private function claimed(Organization $organization): ?string
{
$admin = $organization->admins()->oldest('organization_members.created_at')->first();

Expand Down
4 changes: 2 additions & 2 deletions app/Http/Controllers/OrganizationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use App\Enums\OrganizationRole;
use App\Http\Requests\ShowOrganizationRequest;
use App\Models\Profile;
use App\Models\Organization;
use App\Models\User;
use App\Queries\OrganizationMentionsQuery;
use App\Services\PageMetadata;
Expand All @@ -27,7 +27,7 @@
public function show(ShowOrganizationRequest $request, #[CurrentUser] ?User $currentUser, OrganizationMentionsQuery $mentions, PageMetadata $metadata): RedirectResponse|Response
{
$organization = $request->organization();
assert($organization instanceof Profile);
assert($organization instanceof Organization);

if ($request->route('user') !== $organization->handle) {
// The raw query, since Symfony's normalized one keeps only the last value of a repeated key...
Expand Down
4 changes: 2 additions & 2 deletions app/Http/Controllers/OrganizationLaneController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use App\Actions\UpdateOrganizationLane;
use App\Http\Requests\UpdateOrganizationLaneRequest;
use App\Models\Profile;
use App\Models\Organization;
use Illuminate\Http\RedirectResponse;
use Inertia\Inertia;

Expand All @@ -15,7 +15,7 @@
*/
final readonly class OrganizationLaneController
{
public function update(UpdateOrganizationLaneRequest $request, Profile $organization, UpdateOrganizationLane $action): RedirectResponse
public function update(UpdateOrganizationLaneRequest $request, Organization $organization, UpdateOrganizationLane $action): RedirectResponse
{
$action->handle($organization, $request->lane(), $request->color());

Expand Down
Loading
Loading