Skip to content

Commit d9e250d

Browse files
Merge pull request #108 from trypostit/fix/role-permissions-audit
fix(permissions): enforce workspace roles across backend and UI
2 parents 0275604 + dc29d4d commit d9e250d

36 files changed

Lines changed: 515 additions & 118 deletions

app/Http/Controllers/App/AnalyticsController.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public function index(Request $request): Response
4242
{
4343
$workspace = $request->user()->currentWorkspace;
4444

45+
$this->authorize('view', $workspace);
46+
4547
$accounts = $workspace->socialAccounts()
4648
->where('is_active', true)
4749
->whereIn('platform', self::SUPPORTED_PLATFORMS)

app/Http/Controllers/App/AutomationController.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ class AutomationController extends Controller
4848
{
4949
public function index(ListAutomations $list): Response
5050
{
51+
$this->authorize('viewAny', Automation::class);
52+
5153
$workspace = request()->user()->currentWorkspace;
5254

5355
$automations = Inertia::scroll(fn () => AutomationResource::collection(
@@ -61,6 +63,8 @@ public function index(ListAutomations $list): Response
6163

6264
public function store(StoreAutomationRequest $request, CreateAutomation $create): RedirectResponse
6365
{
66+
$this->authorize('create', Automation::class);
67+
6468
$automation = $create(
6569
$request->user()->currentWorkspace,
6670
$request->user(),
@@ -71,6 +75,8 @@ public function store(StoreAutomationRequest $request, CreateAutomation $create)
7175

7276
public function show(Automation $automation): RedirectResponse
7377
{
78+
$this->authorize('view', $automation);
79+
7480
return redirect()->route('app.automations.workflow', $automation->id);
7581
}
7682

app/Http/Controllers/App/PostController.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,9 @@ public function store(StorePostRequest $request): RedirectResponse|\Symfony\Comp
180180
session()->flash('flash.banner', __('posts.flash.connect_first'));
181181
session()->flash('flash.bannerStyle', 'danger');
182182

183-
return redirect()->route('app.accounts');
183+
return $request->user()->can('manageAccounts', $workspace)
184+
? redirect()->route('app.accounts')
185+
: redirect()->route('app.calendar');
184186
}
185187

186188
$post = CreatePost::execute($workspace, $request->user(), [
@@ -232,13 +234,15 @@ public function edit(Request $request, Post $post): Response|RedirectResponse
232234
return redirect()->route('app.workspaces.create');
233235
}
234236

235-
$this->authorize('update', $post);
237+
$this->authorize('view', $post);
236238

237239
if (PostStatusRules::blocksEditing($post)) {
238240
return redirect()->route('app.posts.show', $post);
239241
}
240242

241-
SyncPostPlatforms::execute($post);
243+
if ($request->user()->can('update', $post)) {
244+
SyncPostPlatforms::execute($post);
245+
}
242246

243247
$post->load(['postPlatforms.socialAccount', 'labels']);
244248
$socialAccounts = $workspace->socialAccounts()->active()->get();

app/Http/Controllers/Auth/SocialController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function index(Request $request): Response|RedirectResponse
4141
return redirect()->route('app.workspaces.create');
4242
}
4343

44-
$this->authorize('view', $workspace);
44+
$this->authorize('manageAccounts', $workspace);
4545

4646
$platforms = collect(SocialPlatform::enabled())->map(fn ($platform) => [
4747
'value' => $platform->value,

app/Policies/AutomationPolicy.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,20 @@ public function view(User $user, Automation $automation): bool
2121

2222
public function create(User $user): bool
2323
{
24-
return $user->currentWorkspace !== null;
24+
return $user->currentWorkspace !== null
25+
&& $user->can('createPost', $user->currentWorkspace);
2526
}
2627

2728
public function update(User $user, Automation $automation): bool
2829
{
29-
return $automation->workspace_id === $user->current_workspace_id;
30+
return $automation->workspace_id === $user->current_workspace_id
31+
&& $user->can('createPost', $user->currentWorkspace);
3032
}
3133

3234
public function delete(User $user, Automation $automation): bool
3335
{
34-
return $automation->workspace_id === $user->current_workspace_id;
36+
return $automation->workspace_id === $user->current_workspace_id
37+
&& $user->can('createPost', $user->currentWorkspace);
3538
}
3639

3740
public function activate(User $user, Automation $automation): bool

app/Policies/PostPolicy.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,29 @@ public function view(User $user, Post $post): bool|Response
2525
}
2626

2727
/**
28-
* Authorize updating a post. Same workspace-tenancy guard as `view`.
28+
* Authorize updating a post: tenancy guard (404 across tenants) then the
29+
* role gate — viewers are read-only (403).
2930
*/
3031
public function update(User $user, Post $post): bool|Response
3132
{
3233
if ($post->workspace_id !== $user->current_workspace_id) {
3334
return Response::denyAsNotFound();
3435
}
3536

36-
return true;
37+
return $user->can('createPost', $user->currentWorkspace);
3738
}
3839

3940
/**
40-
* Authorize deleting a post. Same workspace-tenancy guard as `view`.
41+
* Authorize deleting a post: tenancy guard (404 across tenants) then the
42+
* same role gate as `update` — viewers are read-only (403).
4143
*/
4244
public function delete(User $user, Post $post): bool|Response
4345
{
4446
if ($post->workspace_id !== $user->current_workspace_id) {
4547
return Response::denyAsNotFound();
4648
}
4749

48-
return true;
50+
return $user->can('createPost', $user->currentWorkspace);
4951
}
5052

5153
/**

lang/en/posts.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@
388388
],
389389

390390
'status' => [
391+
'pending' => 'Pending',
391392
'scheduled' => 'Scheduled',
392393
'published' => 'Published',
393394
'publishing' => 'Publishing...',

lang/en/sidebar.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
'groups' => [
2525
'posts' => 'Posts',
2626
'workspace' => 'Workspace',
27-
'support' => 'Support',
27+
'others' => 'Others',
2828
],
2929

3030
'analytics' => 'Analytics',
@@ -54,9 +54,8 @@
5454
'no_notifications' => 'No notifications',
5555

5656
'support' => [
57-
'discord' => 'Discord',
58-
'share_feedback' => 'Share feedback',
59-
'last_updates' => 'Last Updates',
6057
'docs' => 'Documentation',
58+
'referral' => 'Earn 30% referral',
59+
'stay_updated' => 'Stay updated',
6160
],
6261
];

lang/es/posts.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@
388388
],
389389

390390
'status' => [
391+
'pending' => 'Pendiente',
391392
'scheduled' => 'Programado',
392393
'published' => 'Publicado',
393394
'publishing' => 'Publicando...',

lang/es/sidebar.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
'groups' => [
2525
'posts' => 'Posts',
2626
'workspace' => 'Workspace',
27-
'support' => 'Soporte',
27+
'others' => 'Otros',
2828
],
2929

3030
'analytics' => 'Analytics',
@@ -54,9 +54,8 @@
5454
'no_notifications' => 'Sin notificaciones',
5555

5656
'support' => [
57-
'discord' => 'Discord',
58-
'share_feedback' => 'Dar feedback',
59-
'last_updates' => 'Últimas actualizaciones',
6057
'docs' => 'Documentación',
58+
'referral' => 'Gana 30% de comisión',
59+
'stay_updated' => 'Mantente al día',
6160
],
6261
];

0 commit comments

Comments
 (0)