HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/be.naniguide.com/tests/Feature/FileManagerApiTest.php
<?php

/**
 * FileManagerApi feature test — exercises /api/v1/filemanager/* endpoints
 * consumed by the scalable-filemanager frontend library.
 *
 * DB strategy: DatabaseTransactions so rows auto-rollback. Customers and
 * Users are inserted via forceCreate() because CustomerFactory nests
 * User::factory() which doesn't resolve for App\Model\User.
 */

use App\Model\Asset;
use App\Model\Customer;
use App\Model\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

uses(Tests\TestCase::class);
uses(DatabaseTransactions::class);

function seedApiCustomerAndUser(): array
{
    $customer = Customer::forceCreate([
        'uid'        => 'fmcus_' . Str::random(10),
        'timezone'   => 'UTC',
        'status'     => 'active',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $user = User::forceCreate([
        'uid'         => 'fmusr_' . Str::random(10),
        'email'       => 'fm_' . Str::random(6) . '@example.test',
        'password'    => bcrypt('x'),
        'activated'   => 1,
        'api_token'   => Str::random(60),
        'customer_id' => $customer->id,
    ]);

    return [$customer, $user];
}

function seedApiAsset(Customer $customer, array $overrides = []): Asset
{
    return Asset::forceCreate(array_merge([
        'uid'           => 'fmast_' . Str::random(10),
        'customer_id'   => $customer->id,
        'type'          => Asset::TYPE_MEDIA,
        'visibility'    => Asset::VISIBILITY_PUBLIC,
        'path'          => "customers/{$customer->uid}/home/media/",
        'original_name' => 'photo.png',
        'filename'      => 'photo.png',
        'size'          => 1024,
        'mime_type'     => 'image/png',
    ], $overrides));
}

it('requires authentication for list endpoint', function () {
    $this->getJson('/api/v1/filemanager/list')->assertStatus(401);
});

it('returns the authenticated customers assets only', function () {
    [$customerA, $userA] = seedApiCustomerAndUser();
    [$customerB]         = seedApiCustomerAndUser();

    seedApiAsset($customerA, ['original_name' => 'a1.png']);
    seedApiAsset($customerA, ['original_name' => 'a2.pdf', 'mime_type' => 'application/pdf']);
    seedApiAsset($customerB, ['original_name' => 'b1.png']);

    // seedApiAsset defaults assets into the `media/` subfolder, so list there
    // (no `path` param would query root and surface only the `media/` folder entry).
    $response = $this->actingAs($userA, 'api')
        ->getJson('/api/v1/filemanager/list?scope_type=customer&scope_id=' . $customerA->id . '&path=media');

    $response->assertOk()
        ->assertJsonPath('success', true)
        ->assertJsonPath('data.total', 2)
        ->assertJsonCount(2, 'data.items');

    $names = collect($response->json('data.items'))->pluck('name')->sort()->values()->all();
    expect($names)->toBe(['a1.png', 'a2.pdf']);
});

it('rejects mismatched scope_id', function () {
    [$customer, $user] = seedApiCustomerAndUser();

    $this->actingAs($user, 'api')
        ->getJson('/api/v1/filemanager/list?scope_type=customer&scope_id=' . ($customer->id + 9999))
        ->assertStatus(403);
});

it('uploads a file and returns the entry', function () {
    Storage::fake('local');
    [$customer, $user] = seedApiCustomerAndUser();

    $response = $this->actingAs($user, 'api')
        ->post('/api/v1/filemanager/upload', [
            'scope_type' => 'customer',
            'scope_id'   => $customer->id,
            'file'       => UploadedFile::fake()->image('hero.png', 200, 200),
        ]);

    $response->assertOk()
        ->assertJsonPath('success', true)
        ->assertJsonPath('data.name', 'hero.png')
        ->assertJsonPath('data.kind', 'image');

    expect(Asset::where('customer_id', $customer->id)->count())->toBe(1);
});

it('deletes an asset by uid', function () {
    Storage::fake('local');
    [$customer, $user] = seedApiCustomerAndUser();
    $asset             = seedApiAsset($customer);

    $this->actingAs($user, 'api')
        ->deleteJson('/api/v1/filemanager/delete?scope_type=customer&scope_id=' . $customer->id . '&id=' . $asset->uid)
        ->assertOk()
        ->assertJsonPath('success', true);

    expect(Asset::where('uid', $asset->uid)->exists())->toBeFalse();
});

it('renames an asset', function () {
    [$customer, $user] = seedApiCustomerAndUser();
    $asset             = seedApiAsset($customer);

    $response = $this->actingAs($user, 'api')
        ->patchJson('/api/v1/filemanager/rename', [
            'scope_type' => 'customer',
            'scope_id'   => $customer->id,
            'id'         => $asset->uid,
            'name'       => 'renamed.png',
        ]);

    $response->assertOk()->assertJsonPath('data.name', 'renamed.png');
    expect($asset->fresh()->original_name)->toBe('renamed.png');
});

it('view endpoint redirects to the asset url', function () {
    [$customer, $user] = seedApiCustomerAndUser();
    $asset             = seedApiAsset($customer);

    $this->actingAs($user, 'api')
        ->get('/api/v1/filemanager/view?scope_type=customer&scope_id=' . $customer->id . '&id=' . $asset->uid)
        ->assertRedirect($asset->getUrl());
});

it('rejects unsupported scope_type', function () {
    [$customer, $user] = seedApiCustomerAndUser();

    $this->actingAs($user, 'api')
        ->getJson('/api/v1/filemanager/list?scope_type=system')
        ->assertStatus(400);
});