222 lines
7.1 KiB
PHP
222 lines
7.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Feature\Api;
|
|
|
|
use App\Enums\MissingUrlStatus;
|
|
use App\Jobs\SyncRepository;
|
|
use App\Models\MissingUrl;
|
|
use App\Models\Repository;
|
|
use App\Models\Setting;
|
|
use App\Models\User;
|
|
use App\Support\ContentVersion;
|
|
use App\Support\Maintenance;
|
|
use Database\Seeders\RolePermissionSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Queue;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use Tests\FakesPireon;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* Redirects, missing URLs, repositories, settings and maintenance through the
|
|
* admin API — the panel's administration screens.
|
|
*/
|
|
class SiteAdministrationApiTest extends TestCase
|
|
{
|
|
use FakesPireon, RefreshDatabase;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$this->seed(RolePermissionSeeder::class);
|
|
}
|
|
|
|
protected function actingWithRole(string $role): User
|
|
{
|
|
$user = User::factory()->create();
|
|
$user->syncRoles([$role]);
|
|
|
|
$this->withHeaders($this->apiHeadersFor($user));
|
|
|
|
return $user;
|
|
}
|
|
|
|
#[Test]
|
|
public function a_redirect_is_normalised_and_closes_the_report_it_answers(): void
|
|
{
|
|
$this->actingWithRole('editor');
|
|
|
|
MissingUrl::report('/proyectos/viejo', 'es');
|
|
|
|
$this->postJson('/api/v1/redirects', [
|
|
'from' => 'proyectos/viejo/',
|
|
'to' => '/proyectos/nuevo?x=1',
|
|
])
|
|
->assertCreated()
|
|
->assertJsonPath('data.from', '/proyectos/viejo')
|
|
->assertJsonPath('data.to', '/proyectos/nuevo')
|
|
->assertJsonPath('data.status', 301)
|
|
->assertJsonPath('data.automatic', false);
|
|
|
|
$this->assertSame(MissingUrlStatus::Resolved, MissingUrl::query()->sole()->status);
|
|
|
|
// The same address in the same language is one rule, not two.
|
|
$this->postJson('/api/v1/redirects', ['from' => '/proyectos/viejo', 'to' => '/otra'])
|
|
->assertUnprocessable()
|
|
->assertJsonValidationErrors('from');
|
|
|
|
$this->postJson('/api/v1/redirects', ['from' => '/a', 'to' => '/a/'])
|
|
->assertUnprocessable()
|
|
->assertJsonValidationErrors('to');
|
|
}
|
|
|
|
#[Test]
|
|
public function a_missing_url_is_given_a_destination(): void
|
|
{
|
|
$this->actingWithRole('editor');
|
|
|
|
MissingUrl::report('/en/old', 'en');
|
|
$missing = MissingUrl::query()->sole();
|
|
|
|
$this->getJson('/api/v1/missing-urls')->assertJsonCount(1, 'data');
|
|
|
|
$this->postJson("/api/v1/missing-urls/{$missing->id}/redirect", ['to' => '/en/new'])
|
|
->assertCreated()
|
|
->assertJsonPath('data.from', '/en/old')
|
|
->assertJsonPath('data.locale', 'en');
|
|
|
|
$this->assertSame(MissingUrlStatus::Resolved, $missing->fresh()->status);
|
|
$this->getJson('/api/v1/missing-urls')->assertJsonCount(0, 'data');
|
|
|
|
$this->postJson("/api/v1/missing-urls/{$missing->id}/redirect", ['to' => '/en/other'])
|
|
->assertUnprocessable()
|
|
->assertJsonValidationErrors('locale');
|
|
}
|
|
|
|
#[Test]
|
|
public function a_missing_url_can_be_ignored_but_not_declared_resolved(): void
|
|
{
|
|
$this->actingWithRole('editor');
|
|
|
|
$missing = MissingUrl::factory()->create();
|
|
|
|
$this->patchJson("/api/v1/missing-urls/{$missing->id}", ['status' => 'ignored'])
|
|
->assertOk()
|
|
->assertJsonPath('data.status', 'ignored');
|
|
|
|
$this->patchJson("/api/v1/missing-urls/{$missing->id}", ['status' => 'resolved'])
|
|
->assertUnprocessable();
|
|
}
|
|
|
|
#[Test]
|
|
public function a_repository_is_added_and_synced_on_the_queue(): void
|
|
{
|
|
Queue::fake();
|
|
|
|
$this->actingWithRole('admin');
|
|
|
|
$id = $this->postJson('/api/v1/repositories', [
|
|
'provider' => 'github',
|
|
'full_name' => 'pireon/landing',
|
|
'show_publicly' => true,
|
|
// Synced columns are not the caller's to set.
|
|
'stars' => 9999,
|
|
])
|
|
->assertCreated()
|
|
->assertJsonPath('data.full_name', 'pireon/landing')
|
|
->assertJsonPath('data.stars', 0)
|
|
->json('data.id');
|
|
|
|
$this->postJson('/api/v1/repositories', ['provider' => 'github', 'full_name' => 'pireon/landing'])
|
|
->assertUnprocessable()
|
|
->assertJsonValidationErrors('full_name');
|
|
|
|
$this->postJson("/api/v1/repositories/{$id}/sync")->assertAccepted();
|
|
|
|
Queue::assertPushed(SyncRepository::class);
|
|
}
|
|
|
|
#[Test]
|
|
public function an_editor_reads_repositories_but_cannot_sync_them(): void
|
|
{
|
|
Queue::fake();
|
|
|
|
$this->actingWithRole('editor');
|
|
|
|
$repository = Repository::factory()->create();
|
|
|
|
$this->getJson('/api/v1/repositories')->assertOk();
|
|
$this->postJson("/api/v1/repositories/{$repository->id}/sync")->assertForbidden();
|
|
|
|
Queue::assertNothingPushed();
|
|
}
|
|
|
|
#[Test]
|
|
public function a_setting_is_replaced_whole(): void
|
|
{
|
|
$this->actingWithRole('admin');
|
|
|
|
Setting::set('site.contact', ['email' => 'hola@example.org']);
|
|
|
|
$this->getJson('/api/v1/settings')->assertOk()->assertJsonPath('data.0.key', 'site.contact');
|
|
|
|
$this->patchJson('/api/v1/settings/site.contact', ['value' => ['email' => 'nuevo@example.org']])
|
|
->assertOk()
|
|
->assertJsonPath('data.value.email', 'nuevo@example.org');
|
|
|
|
$this->assertSame(['email' => 'nuevo@example.org'], Setting::get('site.contact'));
|
|
}
|
|
|
|
#[Test]
|
|
public function the_content_version_is_not_edited_by_hand(): void
|
|
{
|
|
$this->actingWithRole('admin');
|
|
|
|
ContentVersion::bump();
|
|
|
|
$this->patchJson('/api/v1/settings/'.ContentVersion::KEY, ['value' => 1])->assertForbidden();
|
|
}
|
|
|
|
#[Test]
|
|
public function an_editor_sees_settings_but_changes_none(): void
|
|
{
|
|
$this->actingWithRole('editor');
|
|
|
|
Setting::set(Maintenance::KEY, ['enabled' => false]);
|
|
|
|
$this->getJson('/api/v1/settings')->assertOk();
|
|
$this->getJson('/api/v1/maintenance')->assertOk()->assertJsonPath('data.enabled', false);
|
|
|
|
$this->patchJson('/api/v1/settings/'.Maintenance::KEY, ['value' => ['enabled' => true]])->assertForbidden();
|
|
$this->putJson('/api/v1/maintenance', ['enabled' => true])->assertForbidden();
|
|
|
|
$this->assertFalse(Maintenance::isEnabled());
|
|
}
|
|
|
|
#[Test]
|
|
public function maintenance_is_switched_on_and_off_keeping_its_wording(): void
|
|
{
|
|
$this->actingWithRole('admin');
|
|
|
|
$this->putJson('/api/v1/maintenance', [
|
|
'enabled' => true,
|
|
'message' => ['es' => 'Volvemos enseguida.', 'en' => ''],
|
|
'until' => now()->addHour()->toIso8601String(),
|
|
])
|
|
->assertOk()
|
|
->assertJsonPath('data.enabled', true)
|
|
->assertJsonPath('data.message', ['es' => 'Volvemos enseguida.']);
|
|
|
|
$this->assertTrue(Maintenance::isEnabled());
|
|
|
|
$this->putJson('/api/v1/maintenance', ['enabled' => false])
|
|
->assertOk()
|
|
->assertJsonPath('data.enabled', false)
|
|
->assertJsonPath('data.until', null)
|
|
->assertJsonPath('data.message.es', 'Volvemos enseguida.');
|
|
}
|
|
}
|