Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adopt new modern dialog #1519

Merged
merged 20 commits into from
Oct 19, 2022
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
36 changes: 30 additions & 6 deletions app/Actions/Sharing/ListShare.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@

use App\DTO\Shares;
use App\Exceptions\Internal\QueryBuilderException;
use App\Models\Extensions\BaseAlbum;
use App\Models\User;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class ListShare
{
/**
* @param int $userId
* @param User|null $user
* @param BaseAlbum|null $baseAlbum
*
* @return Shares
*
* @throws QueryBuilderException
*/
public function do(int $userId): Shares
public function do(?User $user, ?BaseAlbum $baseAlbum): Shares
{
try {
// prepare query
Expand All @@ -37,9 +40,13 @@ public function do(int $userId): Shares
->orderBy('title', 'ASC');

// apply filter
if ($userId !== 0) {
$shared_query = $shared_query->where('base_albums.owner_id', '=', $userId);
$albums_query = $albums_query->where('owner_id', '=', $userId);
if ($user !== null) {
$shared_query->where('base_albums.owner_id', '=', $user->id);
$albums_query->where('owner_id', '=', $user->id);
}
if ($baseAlbum !== null) {
$shared_query->where('base_albums.id', '=', $baseAlbum->id);
$albums_query->where('base_albums.id', '=', $baseAlbum->id);
}

// get arrays
Expand Down Expand Up @@ -103,7 +110,24 @@ private function linkAlbums(Collection $albums): void
$groupedAlbums = $albums->groupBy('parent_id');

foreach ($albums as $album) {
if (!$album->parent_id) {
// We must ensure that for each album the property `parent` is
// defined as `breadcrumbPath` accesses this property.
// At the same time, we must not _unconditionally_ initialize this
// property with `null`, as the `parent` property might already
// have been set to its final value in case the parent of current
// object has already been processed earlier and has initialized
// the property (see `foreach` below).
// Keep in mind that the order of albums is arbitrary, hence
// we cannot guarantee whether parents are processed before its
// children or vice versa.
// However, we must not use `$album->parent_id !== null` to check
// whether there is such a parent object eventually.
// An album may have a parent (i.e. `$album->parent_id !== null`
// holds), but the parent might not be part of the result set,
// if the query has been restricted to a particular album and
// the album tree has become disintegrated into a forest of
// subtrees.
if (!isset($album->parent)) {
$album->parent = null;
}
$childAlbums = $groupedAlbums->get($album->id, []);
Expand Down
48 changes: 25 additions & 23 deletions app/Http/Controllers/Administration/SharingController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,42 @@
use App\Actions\Sharing\ListShare;
use App\DTO\Shares;
use App\Exceptions\Internal\QueryBuilderException;
use App\Exceptions\UnauthenticatedException;
use App\Exceptions\UnauthorizedException;
use App\Http\Requests\Sharing\AddSharesRequest;
use App\Http\Requests\Sharing\DeleteSharingRequest;
use App\Http\Requests\Sharing\SetSharingRequest;
use App\Http\Requests\Sharing\ListSharingRequest;
use App\Http\Requests\Sharing\SetSharesByAlbumRequest;
use App\Models\User;
use App\Policies\UserPolicy;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;

class SharingController extends Controller
{
/**
* Returns the list of sharing permissions wrt. the authenticated user.
*
* @param ListShare $listShare
* @param ListSharingRequest $request
* @param ListShare $listShare
*
* @return Shares
*
* @throws QueryBuilderException
* @throws UnauthenticatedException
* @throws UnauthorizedException
*/
public function list(ListShare $listShare): Shares
public function list(ListSharingRequest $request, ListShare $listShare): Shares
{
/** @var int */
$userId = Auth::id() ?? throw new UnauthenticatedException();

// TODO: move this to Request authorization.
// Note: This test is part of the request validation for the other
// methods of this class.
if (!Gate::check(UserPolicy::CAN_UPLOAD, User::class)) {
throw new UnauthorizedException('Upload privilege required');
}

return $listShare->do($userId);
return $listShare->do($request->user2(), $request->album());
}

/**
* Add a sharing between selected users and selected albums.
*
* @param SetSharingRequest $request
* @param AddSharesRequest $request
*
* @return void
*
* @throws QueryBuilderException
*/
public function add(SetSharingRequest $request): void
public function add(AddSharesRequest $request): void
{
/** @var Collection<User> $users */
$users = User::query()
Expand All @@ -67,6 +53,22 @@ public function add(SetSharingRequest $request): void
}
}

/**
* Set the shares for the given album.
*
* Note: This method *sets* the shares (in contrast to *add*).
* This means, any user not given in the list of user IDs is removed
* if the album has been shared with this user before.
*
* @param SetSharesByAlbumRequest $request
*
* @return void
*/
public function setByAlbum(SetSharesByAlbumRequest $request): void
{
$request->album()->shared_with()->sync($request->userIDs());
}

/**
* Given a list of shared ID we delete them
* This function is the only reason why we test SharedIDs in
Expand Down
23 changes: 23 additions & 0 deletions app/Http/Requests/Contracts/HasOptionalUser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace App\Http\Requests\Contracts;

use App\Models\User;

interface HasOptionalUser
{
public const USER_ID_ATTRIBUTE = 'userID';

/**
* Returns an _additional_ {@link User} object associated with this request.
*
* This method is called `user2`, because Laravel already defines
* {@link \Illuminate\Http\Request::user()} which returns the user which
* is currently authenticated within the HTTP session.
* This method returns another user object which is explicitly part of the
* request.
*
* @return User|null
*/
public function user2(): ?User;
kamil4 marked this conversation as resolved.
Show resolved Hide resolved
}
12 changes: 2 additions & 10 deletions app/Http/Requests/Contracts/HasUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,10 @@

use App\Models\User;

interface HasUser
interface HasUser extends HasOptionalUser
{
public const USER_ID_ATTRIBUTE = 'userID';

/**
* Returns an _additional_ {@link User} object associated with this request.
*
* This method is called `user2`, because Laravel already defines
* {@link \Illuminate\Http\Request::user()} which returns the user which
* is currently authenticated within the HTTP session.
* This method returns another user object which is part of the request
* and shall be manipulated as part of the user management.
* {@inheritDoc}
*
* @return User
*/
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Requests/Contracts/HasUserIDs.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace App\Http\Requests\Contracts;

interface HasUserIDs extends HasAlbumIDs
interface HasUserIDs
{
public const USER_IDS_ATTRIBUTE = 'userIDs';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use App\Rules\RandomIDRule;
use Illuminate\Support\Facades\Gate;

class SetSharingRequest extends BaseApiRequest implements HasAlbumIDs, HasUserIDs
class AddSharesRequest extends BaseApiRequest implements HasAlbumIDs, HasUserIDs
{
use HasAlbumIDsTrait;
use HasUserIDsTrait;
Expand Down
83 changes: 83 additions & 0 deletions app/Http/Requests/Sharing/ListSharingRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

namespace App\Http\Requests\Sharing;

use App\Http\Requests\BaseApiRequest;
use App\Http\Requests\Contracts\HasAbstractAlbum;
use App\Http\Requests\Contracts\HasBaseAlbum;
use App\Http\Requests\Contracts\HasOptionalUser;
use App\Http\Requests\Traits\HasBaseAlbumTrait;
use App\Http\Requests\Traits\HasOptionalUserTrait;
use App\Models\User;
use App\Policies\AlbumPolicy;
use App\Policies\UserPolicy;
use App\Rules\IntegerIDRule;
use App\Rules\RandomIDRule;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;

/**
* Represents a request for listing shares.
*
* The result can be filtered by a specific album or user if the respective
* ID is included in the request.
*
* Non-admin user must only query for shares of albums they own or for
* all shares they participate in.
* In other words, non-admin user must include at least their own user ID or
* an album ID they own in the request.
* Only the admin is allowed to make an unrestricted query.
*/
class ListSharingRequest extends BaseApiRequest implements HasBaseAlbum, HasOptionalUser
{
use HasBaseAlbumTrait;
use HasOptionalUserTrait;

/**
* {@inheritDoc}
*/
public function authorize(): bool
{
if (Gate::check(UserPolicy::IS_ADMIN)) {
return true;
}

if (!Gate::check(UserPolicy::CAN_UPLOAD, User::class)) {
return false;
}

if ($this->album !== null && Gate::check(AlbumPolicy::IS_OWNER, $this->album)) {
return true;
}

if ($this->user2 !== null && $this->user2->id === Auth::id()) {
return true;
}

return false;
}

/**
* {@inheritDoc}
*/
public function rules(): array
{
return [
HasAbstractAlbum::ALBUM_ID_ATTRIBUTE => ['sometimes', new RandomIDRule(false)],
HasOptionalUser::USER_ID_ATTRIBUTE => ['sometimes', new IntegerIDRule(false)],
];
}

/**
* {@inheritDoc}
*/
protected function processValidatedValues(array $values, array $files): void
{
$this->album = key_exists(HasAbstractAlbum::ALBUM_ID_ATTRIBUTE, $values) ?
$this->albumFactory->findBaseAlbumOrFail($values[HasAbstractAlbum::ALBUM_ID_ATTRIBUTE]) :
null;
$this->user2 = key_exists(HasOptionalUser::USER_ID_ATTRIBUTE, $values) ?
User::query()->find($values[HasOptionalUser::USER_ID_ATTRIBUTE]) :
null;
}
}
54 changes: 54 additions & 0 deletions app/Http/Requests/Sharing/SetSharesByAlbumRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace App\Http\Requests\Sharing;

use App\Http\Requests\BaseApiRequest;
use App\Http\Requests\Contracts\HasAbstractAlbum;
use App\Http\Requests\Contracts\HasBaseAlbum;
use App\Http\Requests\Contracts\HasUserIDs;
use App\Http\Requests\Traits\HasBaseAlbumTrait;
use App\Http\Requests\Traits\HasUserIDsTrait;
use App\Policies\AlbumPolicy;
use App\Rules\IntegerIDRule;
use App\Rules\RandomIDRule;
use Illuminate\Support\Facades\Gate;

/**
* Represents a request for setting the shares of a specific album.
*
* Only the owner (or the admin) of the album can set the shares.
*/
class SetSharesByAlbumRequest extends BaseApiRequest implements HasBaseAlbum, HasUserIDs
{
use HasBaseAlbumTrait;
use HasUserIDsTrait;

/**
* {@inheritDoc}
*/
public function authorize(): bool
{
return Gate::check(AlbumPolicy::IS_OWNER, $this->album);
}

/**
* {@inheritDoc}
*/
public function rules(): array
{
return [
HasAbstractAlbum::ALBUM_ID_ATTRIBUTE => ['required', new RandomIDRule(false)],
HasUserIDs::USER_IDS_ATTRIBUTE => 'present|array',
HasUserIDs::USER_IDS_ATTRIBUTE . '.*' => ['required', new IntegerIDRule(false)],
];
}

/**
* {@inheritDoc}
*/
protected function processValidatedValues(array $values, array $files): void
{
$this->album = $this->albumFactory->findBaseAlbumOrFail($values[HasAbstractAlbum::ALBUM_ID_ATTRIBUTE]);
$this->userIDs = $values[HasUserIDs::USER_IDS_ATTRIBUTE];
}
}
29 changes: 29 additions & 0 deletions app/Http/Requests/Traits/HasOptionalUserTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace App\Http\Requests\Traits;

use App\Models\User;

trait HasOptionalUserTrait
{
/**
* @var User|null
*/
protected ?User $user2;

/**
* Returns an _additional_ {@link User} object associated with this request.
*
* This method is called `user2`, because Laravel already defines
* {@link \Illuminate\Http\Request::user()} which returns the user which
* is currently authenticated within the HTTP session.
* This method returns another user object which is explicitly part of the
* request.
*
* @return User|null
*/
public function user2(): ?User
{
return $this->user2;
}
}
Loading