Skip to content

Commit

Permalink
feat: manage vault in api (monicahq/chandler#313)
Browse files Browse the repository at this point in the history
  • Loading branch information
djaiss authored Dec 2, 2022
1 parent 4fab9bd commit 5ccfdd3
Show file tree
Hide file tree
Showing 20 changed files with 479 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
use App\Http\Controllers\ApiController;
use App\Http\Resources\UserResource;
use App\Models\User;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Knuckles\Scribe\Attributes\QueryParam;
use Knuckles\Scribe\Attributes\Response;
use Knuckles\Scribe\Attributes\ResponseFromApiResource;
Expand Down Expand Up @@ -46,12 +43,8 @@ public function user(Request $request)
#[ResponseFromApiResource(UserResource::class, User::class)]
public function show(Request $request, int $userId)
{
try {
$user = User::where('account_id', Auth::user()->account_id)
->findOrFail($userId);
} catch (ModelNotFoundException) {
return $this->respondNotFound();
}
$user = $request->user()->account->users()
->findOrFail($userId);

return new UserResource($user);
}
Expand All @@ -65,12 +58,8 @@ public function show(Request $request, int $userId)
#[ResponseFromApiResource(UserResource::class, User::class, collection: true)]
public function index(Request $request)
{
try {
$users = Auth::user()->account->users()
->paginate($this->getLimitPerPage());
} catch (QueryException $e) {
return $this->respondInvalidQuery();
}
$users = $request->user()->account->users()
->paginate($this->getLimitPerPage());

return UserResource::collection($users);
}
Expand Down
128 changes: 128 additions & 0 deletions app/Domains/Vault/ManageVault/Api/Controllers/VaultController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?php

namespace App\Domains\Vault\ManageVault\Api\Controllers;

use App\Domains\Vault\ManageVault\Services\CreateVault;
use App\Domains\Vault\ManageVault\Services\DestroyVault;
use App\Domains\Vault\ManageVault\Services\UpdateVault;
use App\Http\Controllers\ApiController;
use App\Http\Resources\VaultResource;
use App\Models\Vault;
use Illuminate\Http\Request;
use Knuckles\Scribe\Attributes\BodyParam;
use Knuckles\Scribe\Attributes\QueryParam;
use Knuckles\Scribe\Attributes\Response;
use Knuckles\Scribe\Attributes\ResponseFromApiResource;

/**
* @group Vault management
* @subgroup Vaults
*/
class VaultController extends ApiController
{
public function __construct()
{
$this->middleware('abilities:read')->only(['index', 'show']);
$this->middleware('abilities:write')->only(['store', 'update', 'delete']);

parent::__construct();
}

/**
* List all vaults
*
* Get all the vaults in the account.
*/
#[QueryParam('limit', 'int', description: 'A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.', required: false, example: 10)]
#[ResponseFromApiResource(VaultResource::class, Vault::class, collection: true)]
public function index(Request $request)
{
$vaults = $request->user()->account->vaults()
->paginate($this->getLimitPerPage());

return VaultResource::collection($vaults);
}

/**
* Create a vault
*
* Creates a vault object.
*/
#[BodyParam('name', description: 'The name of the vault. Max 255 characters.')]
#[BodyParam('description', description: 'The description of the vault. Max 65535 characters.', required: false)]
#[ResponseFromApiResource(VaultResource::class, Vault::class, status: 201)]
public function store(Request $request)
{
$data = [
'account_id' => $request->user()->account_id,
'author_id' => $request->user()->id,
'type' => Vault::TYPE_PERSONAL,
'name' => $request->input('name'),
'description' => $request->input('description'),
];

$vault = (new CreateVault())->execute($data);

return new VaultResource($vault);
}

/**
* Retrieve a vault
*
* Get a specific vault object.
*/
#[ResponseFromApiResource(VaultResource::class, Vault::class)]
public function show(Request $request, int $vaultId)
{
$vault = $request->user()->account->vaults()
->findOrFail($vaultId);

return new VaultResource($vault);
}

/**
* Update a vault
*
* Updates a vault object.
*
* If the call succeeds, the response is the same as the one for the
* Retrieve a vault endpoint.
*/
#[BodyParam('name', description: 'The name of the vault. Max 255 characters.')]
#[BodyParam('description', description: 'The description of the vault. Max 65535 characters.', required: false)]
#[ResponseFromApiResource(VaultResource::class, Vault::class)]
public function update(Request $request, int $vaultId)
{
$data = [
'account_id' => $request->user()->account_id,
'author_id' => $request->user()->id,
'vault_id' => $vaultId,
'name' => $request->input('name'),
'description' => $request->input('description'),
];

$vault = (new UpdateVault())->execute($data);

return new VaultResource($vault);
}

/**
* Delete a vault
*
* Destroys a vault object.
* Warning: everything in the vault will be immediately deleted.
*/
#[Response(['deleted' => true, 'id' => 1])]
public function destroy(Request $request, int $vaultId)
{
$data = [
'account_id' => $request->user()->account_id,
'author_id' => $request->user()->id,
'vault_id' => $vaultId,
];

(new DestroyVault())->execute($data);

return $this->respondObjectDeleted($vaultId);
}
}
23 changes: 23 additions & 0 deletions app/Http/Controllers/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

use App\Traits\JsonRespondController;
use Closure;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;

class ApiController extends Controller
{
Expand Down Expand Up @@ -40,4 +43,24 @@ public function setLimitPerPage(int $limit): static

return $this;
}

/**
* Execute an action on the controller.
*
* @param string $method
* @param array $parameters
* @return \Symfony\Component\HttpFoundation\Response
*/
public function callAction($method, $parameters)
{
try {
return $this->{$method}(...array_values($parameters));
} catch (ModelNotFoundException) {
return $this->respondNotFound();
} catch (QueryException) {
return $this->respondInvalidQuery();
} catch (ValidationException $e) {
return $this->respondValidatorFailed($e->validator);
}
}
}
3 changes: 3 additions & 0 deletions app/Http/Resources/UserResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
use App\Helpers\DateHelper;
use Illuminate\Http\Resources\Json\JsonResource;

/**
* @mixin \App\Models\User
*/
class UserResource extends JsonResource
{
/**
Expand Down
32 changes: 32 additions & 0 deletions app/Http/Resources/VaultResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace App\Http\Resources;

use App\Helpers\DateHelper;
use Illuminate\Http\Resources\Json\JsonResource;

/**
* @mixin \App\Models\Vault
*/
class VaultResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'created_at' => DateHelper::getTimestamp($this->created_at),
'updated_at' => DateHelper::getTimestamp($this->updated_at),
'links' => [
'self' => route('api.vaults.show', $this),
],
];
}
}
6 changes: 3 additions & 3 deletions app/Models/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ public function religion(): BelongsTo
/**
* Get the name of the contact, according to the user preference.
*
* @return Attribute
* @return Attribute<string,never>
*/
protected function name(): Attribute
{
Expand All @@ -395,7 +395,7 @@ protected function name(): Attribute
* The birthdate is stored in a ContactImportantDate object, of the
* TYPE_BIRTHDATE type. So we need to find if a date of this type exists.
*
* @return Attribute
* @return Attribute<?int,never>
*/
protected function age(): Attribute
{
Expand Down Expand Up @@ -423,7 +423,7 @@ protected function age(): Attribute
/**
* Get the avatar of the contact.
*
* @return Attribute
* @return Attribute<array,never>
*/
protected function avatar(): Attribute
{
Expand Down
2 changes: 1 addition & 1 deletion app/Models/ContactInformation.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function contactInformationType(): BelongsTo
* If the contact information type is a phone number or an email, return the
* content. If it's something else, return the contact information type's label.
*
* @return Attribute
* @return Attribute<string,never>
*/
protected function name(): Attribute
{
Expand Down
2 changes: 1 addition & 1 deletion app/Models/LifeEventCategory.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function lifeEventTypes(): HasMany
* Life Event categories have a default label that can be translated.
* Howerer, if a label is set, it will be used instead of the default.
*
* @return Attribute
* @return Attribute<string,never>
*/
protected function label(): Attribute
{
Expand Down
2 changes: 1 addition & 1 deletion app/Models/LifeEventType.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public function lifeEvents(): HasMany
* Life Event categories have a default label that can be translated.
* Howerer, if a label is set, it will be used instead of the default.
*
* @return Attribute
* @return Attribute<string,never>
*/
protected function label(): Attribute
{
Expand Down
5 changes: 5 additions & 0 deletions app/Models/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ public function tags(): BelongsToMany
return $this->belongsToMany(Tag::class);
}

/**
* Get the post's title.
*
* @return Attribute<string,string>
*/
protected function title(): Attribute
{
return Attribute::make(
Expand Down
2 changes: 1 addition & 1 deletion app/Models/Religion.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function account(): BelongsTo
* The name is either the default name that we get from the translation key,
* or the name that the user has entered.
*
* @return Attribute
* @return Attribute<string,string>
*/
protected function name(): Attribute
{
Expand Down
2 changes: 1 addition & 1 deletion app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public function contactTasks(): HasMany
/**
* Get the name of the user.
*
* @return Attribute
* @return Attribute<string,never>
*/
protected function name(): Attribute
{
Expand Down
6 changes: 6 additions & 0 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
use App\Http\Controllers\Profile\WebauthnUpdateResponse;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Illuminate\Testing\TestResponse;
use LaravelWebauthn\Facades\Webauthn;
use Tests\TestResponseMacros;

class AppServiceProvider extends ServiceProvider
{
Expand All @@ -19,6 +22,9 @@ class AppServiceProvider extends ServiceProvider
*/
public function register()
{
if (App::environment('testing')) {
TestResponse::mixin(new TestResponseMacros);
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion config/laravelsabre.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
'middleware' => [
'api',
\App\Http\Middleware\EnsureDavRequestsAreStateful::class,
'abilities:create,read,update,delete',
'abilities:read,write',
],

];
10 changes: 0 additions & 10 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,11 @@ parameters:
inferPrivatePropertyTypeFromConstructor: true
level: 5
ignoreErrors:
# psalm/plugin-laravel doesn't support \Illuminate\Database\Eloquent\Casts\Attribute yet
- '#Access to an undefined property App\\Models\\Contact.*::\$name\.#'
- '#Access to an undefined property App\\Http\\Resources\\UserResource::\$[a-zA-Z0-9_]+\.#'
- '#Access to an undefined property App\\Models\\Contact::\$avatar\.#'
- '#Access to an undefined property App\\Models\\Contact::\$age\.#'
- '#Access to an undefined property App\\Models\\Post::\$excerpt\.#'
- '#Access to an undefined property App\\Models\\Post::\$year\.#'
- '#Access to an undefined property App\\Models\\Label::\$contacts_count\.#'
- '#Access to an undefined property App\\Models\\Tag::\$posts_count\.#'
- '#Access to an undefined property App\\Models\\LifeEventCategory.*::\$label\.#'
- '#Access to an undefined property App\\Models\\LifeEventType.*::\$label.#'
- '#Access to an undefined property App\\Models\\Module::\$position\.#'
- '#Access to an undefined property App\\Models\\Post::\$title\.#'
- '#Access to an undefined property App\\Models\\Religion::\$name\.#'
- '#Access to an undefined property App\\Models\\User::\$name\.#'
- '#Access to an undefined property App\\Models\\.*::\$pivot\.#'
- '#Access to an undefined property Sabre\\VObject\\Component\\VCard::\$.*\.#'

Expand Down
Loading

0 comments on commit 5ccfdd3

Please sign in to comment.