diff --git a/app/Http/Controllers/StarTagsController.php b/app/Http/Controllers/StarTagsController.php index 2879ca68..1e3541d3 100644 --- a/app/Http/Controllers/StarTagsController.php +++ b/app/Http/Controllers/StarTagsController.php @@ -80,6 +80,9 @@ public function update(Request $request) ['meta' => $meta] ); + $star->meta = $meta; + $star->save(); + $ids = []; if (empty($tags)) { diff --git a/app/Lib/StarsJanitor.php b/app/Lib/StarsJanitor.php index b7ef482f..15616e85 100644 --- a/app/Lib/StarsJanitor.php +++ b/app/Lib/StarsJanitor.php @@ -16,7 +16,14 @@ public function deleteEmptyStars() { throw_unless($this->user); - $this->user->stars()->doesntHave('tags')->whereNull('notes')->get()->each->delete(); + $this + ->user + ->stars() + ->doesntHave('tags') + ->whereNull('notes') + ->get() + ->each + ->delete(); return $this; } diff --git a/tests/Feature/Controllers/StarTagsController/StoreTest.php b/tests/Feature/Controllers/StarTagsController/StoreTest.php index 2c281035..1031cb81 100644 --- a/tests/Feature/Controllers/StarTagsController/StoreTest.php +++ b/tests/Feature/Controllers/StarTagsController/StoreTest.php @@ -2,14 +2,14 @@ declare(strict_types=1); -use App\Models\Tag; use App\Models\Star; +use App\Models\Tag; it('redirects guests to the login page') ->post('/stars/tag') ->assertRedirect('/login'); -it('creates a new `Star` record + pivot entry for each repository passed to the request', function () { +it('creates a new `Star` record for each repository passed to the request', function () { $repoData = [ [ 'databaseId' => 1234, @@ -49,7 +49,7 @@ } }); -it('doesn\'t create a new `Star` if it already exists for that user', function () { +it('does not create a new `Star` record if it already exists for that user', function () { $repoData = [ [ 'databaseId' => 1234, @@ -104,7 +104,7 @@ ['[]', 'repos'], ]); - it('requires a valid `databaseId` field for each repository passed', function ($badData, array|string $errors) { + it('requires a valid `databaseId` value for each repository passed', function ($badData, array|string $errors) { $this ->post(route('star.tags.store'), ['tagId' => $this->tag->id, 'repos' => $badData]) ->assertInvalid($errors); @@ -115,7 +115,7 @@ fn () => [[[...$this->metaWithoutDatabaseId, 'databaseId' => []]], 'repos.0.databaseId'], ]); - it('requires a valid `nameWithOwner` field for each repository passed', function ($badData, array|string $errors) { + it('requires a valid `nameWithOwner` value for each repository passed', function ($badData, array|string $errors) { $this ->post(route('star.tags.store'), ['tagId' => $this->tag->id, 'repos' => $badData]) ->assertInvalid($errors); @@ -126,7 +126,7 @@ fn () => [[[...$this->metaWithoutNameWithOwner, 'nameWithOwner' => []]], 'repos.0.nameWithOwner'], ]); - it('requires a valid `url` field for each repository passed', function ($badData, array|string $errors) { + it('requires a valid `url` value for each repository passed', function ($badData, array|string $errors) { $this ->post(route('star.tags.store'), ['tagId' => $this->tag->id, 'repos' => $badData]) ->assertInvalid($errors); @@ -138,7 +138,7 @@ fn () => [[[...$this->metaWithoutUrl, 'url' => []]], 'repos.0.url'], ]); - it('validates the `description` field if present', function ($badData, array|string $errors) { + it('validates the `description` value if present', function ($badData, array|string $errors) { $this ->post(route('star.tags.store'), ['tagId' => $this->tag->id, 'repos' => $badData]) ->assertInvalid($errors); diff --git a/tests/Feature/Controllers/StarTagsController/UpdateTest.php b/tests/Feature/Controllers/StarTagsController/UpdateTest.php new file mode 100644 index 00000000..ceb7eed0 --- /dev/null +++ b/tests/Feature/Controllers/StarTagsController/UpdateTest.php @@ -0,0 +1,159 @@ +post('/stars/tag') + ->assertRedirect('/login'); + +it('creates a new `Star` record if it does not exist', function () { + $repositoryMeta = [ + 'databaseId' => 1234, + 'nameWithOwner' => 'obsproject/obs-studio', + 'url' => 'https://github.com/obsproject/obs-studio', + ]; + + $this->login(); + + expect(auth()->user()->stars()->count())->toBe(0); + + $this + ->put(route('star.tags.update'), [ + ...$repositoryMeta, + 'tags' => [['name' => 'Livestreaming']], + ]) + ->assertRedirect(route('dashboard.show')); + + $this->assertDatabaseHas('stars', [ + 'repo_id' => 1234, + ]); + + $this->assertDatabaseHas('star_tag', [ + 'tag_id' => auth()->user()->tags()->where('name', 'Livestreaming')->first()->id, + 'star_id' => auth()->user()->stars()->where('repo_id', 1234)->first()->id, + ]); +}); + +it('does not create a new `Star` record if it already exists for that user', function () { + $repositoryMeta = [ + 'databaseId' => 1234, + 'nameWithOwner' => 'obsproject/obs-studio', + 'url' => 'https://github.com/obsproject/obs-studio', + ]; + + $this->login(); + + Star::factory()->create(['repo_id' => 1234, 'user_id' => auth()->id()]); + + expect(auth()->user()->stars()->count())->toBe(1); + + $this + ->put(route('star.tags.update'), [ + ...$repositoryMeta, + 'tags' => [['name' => 'Livestreaming']], + ]); + + expect(auth()->user()->stars()->count())->toBe(1); + expect(auth()->user()->stars()->first()->meta) + ->toEqual(collect($repositoryMeta)->except('databaseId')->toArray()); +}); + +it('creates a new `Tag` record for each tag passed that does not already exist', function () { + $repositoryMeta = [ + 'databaseId' => 1234, + 'nameWithOwner' => 'obsproject/obs-studio', + 'url' => 'https://github.com/obsproject/obs-studio', + ]; + + $this->login(); + + Star::factory()->create(['repo_id' => 1234, 'user_id' => auth()->id()]); + Tag::factory()->create(['name' => 'Livestreaming', 'user_id' => auth()->id()]); + + expect(Tag::where('name', 'Twitch')->exists())->toBeFalse(); + + $this + ->put(route('star.tags.update'), [ + ...$repositoryMeta, + 'tags' => [['name' => 'Livestreaming'], ['name' => 'Twitch']], + ]); + + expect(Tag::where('name', 'Twitch')->exists())->toBeTrue(); +}); + +it('does not create a new `Tag` record for the user if it already exists', function () { + $repositoryMeta = [ + 'databaseId' => 1234, + 'nameWithOwner' => 'obsproject/obs-studio', + 'url' => 'https://github.com/obsproject/obs-studio', + ]; + + $this->login(); + + Star::factory()->create(['repo_id' => 1234, 'user_id' => auth()->id()]); + Tag::factory()->create(['name' => 'Livestreaming', 'user_id' => auth()->id()]); + + expect(Tag::where('name', 'Twitch')->exists())->toBeFalse(); + + $this + ->put(route('star.tags.update'), [ + ...$repositoryMeta, + 'tags' => [['name' => 'Livestreaming'], ['name' => 'Twitch']], + ]); + + expect(Tag::where('name', 'Livestreaming')->count())->toBe(1); +}); + +describe('Validating repository data', function () { + beforeEach(function () { + $this->login(); + + Star::factory()->create(['repo_id' => 1234, 'user_id' => auth()->id()]); + $this->tag = Tag::factory()->create(['name' => 'Laravel', 'user_id' => auth()->id()]); + + $this->meta = [ + 'databaseId' => 1234, + 'nameWithOwner' => 'astralapp/astral', + 'url' => 'https://github.com/astralapp/astral', + ]; + $this->metaWithoutDatabaseId = collect($this->meta)->except(['databaseId'])->toArray(); + $this->metaWithoutNameWithOwner = collect($this->meta)->except(['nameWithOwner'])->toArray(); + $this->metaWithoutUrl = collect($this->meta)->except(['url'])->toArray(); + }); + + it('requires a valid `databaseId` value', function ($badData, array|string $errors) { + $this + ->put(route('star.tags.update'), [ + ...$badData, + 'tags' => [['name' => 'Livestreaming']], + ]) + ->assertInvalid($errors); + })->with([ + fn () => [[$this->metaWithoutDatabaseId], 'databaseId'], + fn () => [[[...$this->metaWithoutDatabaseId, 'databaseId' => 'foobar']], 'databaseId'], + fn () => [[[...$this->metaWithoutDatabaseId, 'databaseId' => null]], 'databaseId'], + fn () => [[[...$this->metaWithoutDatabaseId, 'databaseId' => []]], 'databaseId'], + ]); + + it('requires a valid `nameWithOwner` value', function ($badData, array|string $errors) { + $this + ->put(route('star.tags.update'), [ + ...$badData, + 'tags' => [['name' => 'Livestreaming']], + ]) + ->assertInvalid($errors); + })->with([ + fn () => [[$this->metaWithoutDatabaseId], 'nameWithOwner'], + fn () => [[[...$this->metaWithoutDatabaseId, 'nameWithOwner' => 420]], 'nameWithOwner'], + fn () => [[[...$this->metaWithoutDatabaseId, 'nameWithOwner' => null]], 'nameWithOwner'], + fn () => [[[...$this->metaWithoutDatabaseId, 'nameWithOwner' => []]], 'nameWithOwner'], + ]); +}); + +it('requires a valid `url` value')->todo(); +it('validates the `description` value if present')->todo(); +it('validates the tags are an array')->todo(); +it('validates that each tag has a valid `name` value')->todo();