diff --git a/api/app/Http/Controllers/Forms/FormController.php b/api/app/Http/Controllers/Forms/FormController.php index 1f99c17e4..ac987b1a9 100644 --- a/api/app/Http/Controllers/Forms/FormController.php +++ b/api/app/Http/Controllers/Forms/FormController.php @@ -108,10 +108,9 @@ public function indexAll() public function store(StoreFormRequest $request) { - $this->authorize('create', Form::class); - $workspace = Workspace::findOrFail($request->get('workspace_id')); $this->authorize('view', $workspace); + $this->authorize('create', [Form::class, $workspace]); $formData = $this->formCleaner ->processRequest($request) diff --git a/api/app/Http/Controllers/WorkspaceUserController.php b/api/app/Http/Controllers/WorkspaceUserController.php index 7848d4ccd..f58269bba 100644 --- a/api/app/Http/Controllers/WorkspaceUserController.php +++ b/api/app/Http/Controllers/WorkspaceUserController.php @@ -31,7 +31,7 @@ public function addUser(Request $request, $workspaceId) $this->validate($request, [ 'email' => 'required|email', - 'role' => 'required|in:admin,user', + 'role' => 'required|in:' . implode(',', User::ROLES), ]); $user = User::where('email', $request->email)->first(); @@ -62,10 +62,11 @@ private function inviteUser(Workspace $workspace, string $email, string $role) { if ( UserInvite::where('email', $email) - ->where('workspace_id', $workspace->id) - ->notExpired() - ->pending() - ->exists()) { + ->where('workspace_id', $workspace->id) + ->notExpired() + ->pending() + ->exists() + ) { return $this->success([ 'message' => 'User has already been invited.' ]); @@ -86,7 +87,7 @@ public function updateUserRole(Request $request, $workspaceId, $userId) $this->authorize('adminAction', $workspace); $this->validate($request, [ - 'role' => 'required|in:admin,user', + 'role' => 'required|in:' . implode(',', User::ROLES), ]); $workspace->users()->sync([ diff --git a/api/app/Http/Resources/WorkspaceResource.php b/api/app/Http/Resources/WorkspaceResource.php index a7c4b0e97..a7168796f 100644 --- a/api/app/Http/Resources/WorkspaceResource.php +++ b/api/app/Http/Resources/WorkspaceResource.php @@ -18,6 +18,7 @@ public function toArray($request) { return array_merge(parent::toArray($request), [ 'max_file_size' => $this->max_file_size / 1000000, + 'is_readonly' => $this->isReadonlyUser($request->user()), ]); } } diff --git a/api/app/Models/User.php b/api/app/Models/User.php index 3180c1c10..547337cf3 100644 --- a/api/app/Models/User.php +++ b/api/app/Models/User.php @@ -21,6 +21,13 @@ class User extends Authenticatable implements JWTSubject public const ROLE_ADMIN = 'admin'; public const ROLE_USER = 'user'; + public const ROLE_READONLY = 'readonly'; + + public const ROLES = [ + self::ROLE_ADMIN, + self::ROLE_USER, + self::ROLE_READONLY, + ]; /** * The attributes that are mass assignable. diff --git a/api/app/Models/Workspace.php b/api/app/Models/Workspace.php index 68a0d8115..274f6b33e 100644 --- a/api/app/Models/Workspace.php +++ b/api/app/Models/Workspace.php @@ -203,4 +203,12 @@ public function forms() { return $this->hasMany(Form::class); } + + public function isReadonlyUser(?User $user) + { + return $user ? $this->users() + ->wherePivot('user_id', $user->id) + ->wherePivot('role', User::ROLE_READONLY) + ->exists() : false; + } } diff --git a/api/app/Policies/FormPolicy.php b/api/app/Policies/FormPolicy.php index e35c9f84f..bdf16ca48 100644 --- a/api/app/Policies/FormPolicy.php +++ b/api/app/Policies/FormPolicy.php @@ -4,6 +4,7 @@ use App\Models\Forms\Form; use App\Models\User; +use App\Models\Workspace; use Illuminate\Auth\Access\HandlesAuthorization; class FormPolicy @@ -35,9 +36,17 @@ public function view(User $user, Form $form) * * @return mixed */ - public function create(User $user) + public function create(User $user, Workspace $workspace) { - return true; + return !$workspace->isReadonlyUser($user); + } + + /** + * Determine whether the user can perform write operations on the model. + */ + private function canPerformWriteOperation(User $user, Form $form): bool + { + return $user->ownsForm($form) && !$form->workspace->isReadonlyUser($user); } /** @@ -47,7 +56,7 @@ public function create(User $user) */ public function update(User $user, Form $form) { - return $user->ownsForm($form); + return $this->canPerformWriteOperation($user, $form); } /** @@ -57,7 +66,7 @@ public function update(User $user, Form $form) */ public function delete(User $user, Form $form) { - return $user->ownsForm($form); + return $this->canPerformWriteOperation($user, $form); } /** @@ -67,7 +76,7 @@ public function delete(User $user, Form $form) */ public function restore(User $user, Form $form) { - return $user->ownsForm($form); + return $this->canPerformWriteOperation($user, $form); } /** @@ -77,6 +86,6 @@ public function restore(User $user, Form $form) */ public function forceDelete(User $user, Form $form) { - return $user->ownsForm($form); + return $this->canPerformWriteOperation($user, $form); } } diff --git a/api/app/Policies/TemplatePolicy.php b/api/app/Policies/TemplatePolicy.php index 896f47b81..b2e5ed305 100644 --- a/api/app/Policies/TemplatePolicy.php +++ b/api/app/Policies/TemplatePolicy.php @@ -12,8 +12,6 @@ class TemplatePolicy /** * Determine whether the user can create models. - * - * @return \Illuminate\Auth\Access\Response|bool */ public function create(User $user) { @@ -21,22 +19,20 @@ public function create(User $user) } /** - * Determine whether the user can update the model. - * - * @return mixed + * Determine whether the user can perform write operations on the model. */ - public function update(User $user, Template $template) + private function canPerformWriteOperation(User $user, Template $template): bool { return $user->admin || $user->template_editor || $template->creator_id === $user->id; } - /** - * Determine whether the user can delete the model. - * - * @return mixed - */ + public function update(User $user, Template $template) + { + return $this->canPerformWriteOperation($user, $template); + } + public function delete(User $user, Template $template) { - return $user->admin || $user->template_editor || $template->creator_id === $user->id; + return $this->canPerformWriteOperation($user, $template); } } diff --git a/client/components/open/tables/OpenTable.vue b/client/components/open/tables/OpenTable.vue index d0687c898..301593bf0 100644 --- a/client/components/open/tables/OpenTable.vue +++ b/client/components/open/tables/OpenTable.vue @@ -29,6 +29,7 @@