diff --git a/app/Http/Controllers/Platform/OrganizationController.php b/app/Http/Controllers/Platform/OrganizationController.php index d0a79ff..04364ee 100644 --- a/app/Http/Controllers/Platform/OrganizationController.php +++ b/app/Http/Controllers/Platform/OrganizationController.php @@ -92,7 +92,7 @@ public function show(Organization $organization) */ public function edit(Organization $organization) { - $this->authorize('update', $organization); + $this->authorize('act-as-owner', $organization); return view('platform.organizations.edit')->with([ 'organization' => $organization, @@ -109,7 +109,7 @@ public function edit(Organization $organization) */ public function update(Request $request, Organization $organization) { - $this->authorize('update', $organization); + $this->authorize('act-as-owner', $organization); $attributes = $this->validate($request, [ 'name' => 'required|string|min:3|max:50', @@ -130,7 +130,7 @@ public function update(Request $request, Organization $organization) */ public function destroy(Organization $organization) { - $this->authorize('delete', $organization); + $this->authorize('act-as-owner', $organization); if ($organization->urls->isNotEmpty()) { return redirect()->route('platform.organizations.index') diff --git a/app/Http/Controllers/Platform/OrganizationUsersController.php b/app/Http/Controllers/Platform/OrganizationUsersController.php index 6433e95..dbb3be5 100644 --- a/app/Http/Controllers/Platform/OrganizationUsersController.php +++ b/app/Http/Controllers/Platform/OrganizationUsersController.php @@ -34,7 +34,7 @@ public function __construct() */ public function store(Request $request, Organization $organization) { - $this->authorize('update', $organization); + $this->authorize('act-as-owner', $organization); $users = $organization->users->pluck('pivot.user_id'); $attributes = $this->validate($request, [ @@ -48,6 +48,7 @@ public function store(Request $request, Organization $organization) 'integer', Rule::in([ OrganizationUser::ROLE_OWNER, + OrganizationUser::ROLE_MANAGER, OrganizationUser::ROLE_MEMBER, ]), ], @@ -89,7 +90,7 @@ public function store(Request $request, Organization $organization) */ public function destroy(Request $request, Organization $organization, User $user) { - $this->authorize('update', $organization); + $this->authorize('act-as-owner', $organization); if ($request->user()->id == $user->id) { return redirect()->route('platform.organizations.edit', $organization) diff --git a/app/Http/Controllers/Platform/UrlController.php b/app/Http/Controllers/Platform/UrlController.php index ab52068..e40dca9 100644 --- a/app/Http/Controllers/Platform/UrlController.php +++ b/app/Http/Controllers/Platform/UrlController.php @@ -101,7 +101,7 @@ public function store(Request $request) ]); if ($attributes['organization_id']) { - $this->authorize('view', Organization::find($attributes['organization_id'])); + $this->authorize('act-as-member', Organization::find($attributes['organization_id'])); } $url = new Url($attributes); @@ -133,9 +133,12 @@ public function show(Url $url) * @param \Illuminate\Http\Request $request * @param \App\Models\Url $url * @return \Illuminate\Http\Response + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function edit(Request $request, Url $url) { + $this->authorize('update', $url); + return view('platform.urls.edit')->with([ 'domains' => Domain::orderBy('id')->get(), 'organizations' => $request->user()->organizations, @@ -160,8 +163,12 @@ public function update(Request $request, Url $url) 'organization_id' => 'nullable|integer|exists:organizations,id', ]); - if ($attributes['organization_id']) { - $this->authorize('view', Organization::find($attributes['organization_id'])); + if ($attributes['organization_id'] != $url->organization_id) { + $this->authorize('move', $url); + + if ($attributes['organization_id'] != null) { + $this->authorize('act-as-member', Organization::find($attributes['organization_id'])); + } } $url->fill($attributes); diff --git a/app/Models/Organization.php b/app/Models/Organization.php index 1f3ca20..d9f91f5 100644 --- a/app/Models/Organization.php +++ b/app/Models/Organization.php @@ -51,12 +51,28 @@ public function urls() public function owners() { return $this->belongsToMany(User::class) + ->withPivot('role_id') ->withTimestamps() ->using(OrganizationUser::class) ->wherePivot('role_id', OrganizationUser::ROLE_OWNER) ->whereNull('organization_user.deleted_at'); } + /** + * The organization's managers. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + */ + public function managers() + { + return $this->belongsToMany(User::class) + ->withPivot('role_id') + ->withTimestamps() + ->using(OrganizationUser::class) + ->wherePivot('role_id', OrganizationUser::ROLE_MANAGER) + ->whereNull('organization_user.deleted_at'); + } + /** * The organization's members. * @@ -65,6 +81,7 @@ public function owners() public function members() { return $this->belongsToMany(User::class) + ->withPivot('role_id') ->withTimestamps() ->using(OrganizationUser::class) ->wherePivot('role_id', OrganizationUser::ROLE_MEMBER) @@ -79,6 +96,7 @@ public function members() public function users() { return $this->belongsToMany(User::class) + ->withPivot('role_id') ->withTimestamps() ->using(OrganizationUser::class) ->whereNull('organization_user.deleted_at'); diff --git a/app/Models/OrganizationUser.php b/app/Models/OrganizationUser.php index 7024c77..1c75a52 100644 --- a/app/Models/OrganizationUser.php +++ b/app/Models/OrganizationUser.php @@ -13,10 +13,17 @@ class OrganizationUser extends Pivot */ const ROLE_OWNER = 1; + /** + * The manager role ID. + * + * @var int + */ + const ROLE_MANAGER = 2; + /** * The member role ID. * * @var int */ - const ROLE_MEMBER = 2; + const ROLE_MEMBER = 3; } diff --git a/app/Models/User.php b/app/Models/User.php index 062f9cc..fcce452 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -111,6 +111,7 @@ public function emailVerification() public function organizations() { return $this->belongsToMany(Organization::class) + ->withPivot('role_id') ->withTimestamps() ->using(OrganizationUser::class) ->whereNull('organization_user.deleted_at'); diff --git a/app/Policies/OrganizationPolicy.php b/app/Policies/OrganizationPolicy.php index db3718f..27cabe8 100644 --- a/app/Policies/OrganizationPolicy.php +++ b/app/Policies/OrganizationPolicy.php @@ -2,8 +2,9 @@ namespace App\Policies; -use App\Models\User; use App\Models\Organization; +use App\Models\OrganizationUser; +use App\Models\User; use Illuminate\Auth\Access\HandlesAuthorization; class OrganizationPolicy @@ -11,38 +12,45 @@ class OrganizationPolicy use HandlesAuthorization; /** - * Determine whether the user can view the organization. + * Determine whether the user can act as an owner of the organization. * - * @param \App\Models\User $user - * @param \App\Models\Organization $organization + * @param \App\Models\User $user + * @param \App\Models\Organization $organization * @return mixed */ - public function view(User $user, Organization $organization) + public function actAsOwner(User $user, Organization $organization) { - return $user->organizations->contains('id', $organization->id); + $user = $organization->users->where('id', $user->id)->first(); + + return $user && $user->pivot->role_id == OrganizationUser::ROLE_OWNER; } /** - * Determine whether the user can update the organization. + * Determine whether the user can act as a manager of the organization. * - * @param \App\Models\User $user - * @param \App\Models\Organization $organization + * @param \App\Models\User $user + * @param \App\Models\Organization $organization * @return mixed */ - public function update(User $user, Organization $organization) + public function actAsManager(User $user, Organization $organization) { - return $organization->owners->where('id', $user->id)->isNotEmpty(); + $user = $organization->users->where('id', $user->id)->first(); + + return $user && array_search( + $user->pivot->role_id, + [OrganizationUser::ROLE_OWNER, OrganizationUser::ROLE_MANAGER] + ) !== false; } /** - * Determine whether the user can delete the organization. + * Determine whether the user can act as a member of the organization. * - * @param \App\Models\User $user - * @param \App\Models\Organization $organization + * @param \App\Models\User $user + * @param \App\Models\Organization $organization * @return mixed */ - public function delete(User $user, Organization $organization) + public function actAsMember(User $user, Organization $organization) { - return $organization->owners->where('id', $user->id)->isNotEmpty(); + return $organization->users->where('id', $user->id)->isNotEmpty(); } } diff --git a/app/Policies/UrlPolicy.php b/app/Policies/UrlPolicy.php index f849112..ffdd3b6 100644 --- a/app/Policies/UrlPolicy.php +++ b/app/Policies/UrlPolicy.php @@ -20,7 +20,23 @@ class UrlPolicy public function update(User $user, Url $url) { if ($url->organization) { - return $user->can('view', $url->organization); + return $user->can('act-as-member', $url->organization); + } + + return $user->id == $url->user_id; + } + + /** + * Determine whether the user can move the url. + * + * @param \App\Models\User $user + * @param \App\Models\Url $url + * @return mixed + */ + public function move(User $user, Url $url) + { + if ($url->organization) { + return $user->can('act-as-manager', $url->organization); } return $user->id == $url->user_id; @@ -36,7 +52,7 @@ public function update(User $user, Url $url) public function delete(User $user, Url $url) { if ($url->organization) { - return $user->can('view', $url->organization); + return $user->can('act-as-manager', $url->organization); } return $user->id == $url->user_id; diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 50d74ed..243aca8 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -44,6 +44,7 @@ public function boot() /** * Register any application services. * + * @codeCoverageIgnore * @return void */ public function register() diff --git a/app/helpers.php b/app/helpers.php index bc9d153..07eb9e2 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -37,6 +37,9 @@ function array_filter_key(array $array, $callback) function breadcrumbs() { $path = Request::decodedPath(); + if ($path === '/') { + return 'Home'; + } return title_case(str_replace(['/', '-'], [' / ', ' '], $path)); } diff --git a/database/migrations/2018_04_22_111320_update_role_ids_in_organization_user_table.php b/database/migrations/2018_04_22_111320_update_role_ids_in_organization_user_table.php new file mode 100644 index 0000000..934942a --- /dev/null +++ b/database/migrations/2018_04_22_111320_update_role_ids_in_organization_user_table.php @@ -0,0 +1,29 @@ +where('role_id', 2)->update(['role_id' => 3]); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + DB::table('organization_user')->where('role_id', 2)->delete(); + DB::table('organization_user')->where('role_id', 3)->update(['role_id' => 2]); + } +} diff --git a/resources/views/platform/organizations/_table.blade.php b/resources/views/platform/organizations/_table.blade.php index 3f3d23a..65b5a4d 100644 --- a/resources/views/platform/organizations/_table.blade.php +++ b/resources/views/platform/organizations/_table.blade.php @@ -5,6 +5,7 @@