Skip to content
This repository was archived by the owner on Feb 27, 2021. It is now read-only.

Commit 45e7943

Browse files
author
Richard Dern
committed
Per-folder users permissions
1 parent e507f4d commit 45e7943

28 files changed

+487
-91
lines changed

app/Http/Controllers/FolderController.php

+92-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use App\Models\Group;
99
use App\Http\Requests\Folders\SetPermissionsRequest;
1010
use Illuminate\Http\Request;
11+
use App\Models\User;
1112

1213
class FolderController extends Controller
1314
{
@@ -83,10 +84,58 @@ public function details(Request $request, Folder $folder)
8384

8485
$folder->user_permissions = $folder->getUserPermissions($user);
8586
$folder->default_permissions = $folder->getDefaultPermissions();
87+
$folder->group->loadCount('activeUsers');
8688

8789
return $folder;
8890
}
8991

92+
/**
93+
* Load per-user permissions for specified folder
94+
*
95+
* @param \App\Models\Folder $folder
96+
* @return \Illuminate\Http\Response
97+
*/
98+
public function perUserPermissions(Request $request, Folder $folder)
99+
{
100+
if (!$request->user()->can('setPermission', $folder)) {
101+
abort(404);
102+
}
103+
104+
$users = $folder->group->activeUsers()->whereNotIn('users.id', [$request->user()->id])
105+
->whereHas('permissions', function ($query) use ($folder) {
106+
$query->where('folder_id', $folder->id);
107+
})
108+
->with(['permissions'=> function ($query) use ($folder) {
109+
$query->where('folder_id', $folder->id);
110+
}])
111+
->select(['users.id', 'users.name', 'users.email'])
112+
->get();
113+
114+
return $users;
115+
}
116+
117+
/**
118+
* Load list of users with no expicit permissions for specified folder
119+
*
120+
* @param \App\Models\Folder $folder
121+
* @return \Illuminate\Http\Response
122+
*/
123+
public function usersWithoutPermissions(Request $request, Folder $folder)
124+
{
125+
if (!$request->user()->can('setPermission', $folder)) {
126+
abort(404);
127+
}
128+
129+
$users = $folder->group->activeUsers()->whereNotIn('users.id', [$request->user()->id])
130+
->whereDoesntHave('permissions', function ($query) use ($folder) {
131+
$query->where('folder_id', $folder->id);
132+
})
133+
->select(['users.id', 'users.name', 'users.email'])
134+
->get();
135+
136+
return $users;
137+
}
138+
90139
/**
91140
* Update the specified resource in storage.
92141
*
@@ -153,12 +202,53 @@ public function toggleBranch(Request $request, Folder $folder)
153202
return $user->getFlatTree();
154203
}
155204

205+
/**
206+
* Set permissions for specified folder, optionally for specified user
207+
*
208+
* @param App\Http\Requests\Folder\SetPermissionsRequest $request
209+
* @param \App\Models\Folder $folder
210+
* @return \Illuminate\Http\Response
211+
*/
156212
public function setPermission(SetPermissionsRequest $request, Folder $folder)
157213
{
214+
if (!$request->user()->can('setPermission', $folder)) {
215+
abort(404);
216+
}
217+
158218
$validated = $request->validated();
159219

160-
$folder->setDefaultPermission($validated['ability'], $validated['granted']);
220+
$ability = !empty($validated['ability']) ? $validated['ability'] : null;
221+
$granted = !empty($validated['granted']) ? $validated['granted'] : false;
222+
223+
if (empty($validated['user_id'])) {
224+
$folder->setDefaultPermission($ability, $granted);
225+
226+
return $this->details($request, $folder);
227+
} else {
228+
$user = $folder->group->activeUsers()->findOrFail($validated['user_id']);
229+
230+
$user->setFolderPermissions($folder, $ability, $granted);
231+
232+
return $this->perUserPermissions($request, $folder);
233+
}
234+
}
235+
236+
/**
237+
* Remove permissions for specified user in specified folder
238+
*
239+
* @param App\Http\Requests\Folder\SetPermissionsRequest $request
240+
* @param \App\Models\Folder $folder
241+
* @param \App\Models\User $user
242+
* @return \Illuminate\Http\Response
243+
*/
244+
public function removePermissions(Request $request, Folder $folder, User $user)
245+
{
246+
if (!$request->user()->can('setPermission', $folder)) {
247+
abort(404);
248+
}
249+
250+
$user->permissions()->where('folder_id', $folder->id)->delete();
161251

162-
return $this->details($request, $folder);
252+
return $this->perUserPermissions($request, $folder);
163253
}
164254
}

app/Http/Requests/Folders/SetPermissionsRequest.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function rules()
2626
{
2727
return [
2828
'ability' => [
29-
'required',
29+
'nullable',
3030
Rule::in([
3131
'can_create_folder',
3232
'can_update_folder',
@@ -36,8 +36,12 @@ public function rules()
3636
])
3737
],
3838
'granted' => [
39-
'required',
39+
'nullable',
4040
'boolean'
41+
],
42+
'user_id' => [
43+
'nullable',
44+
Rule::exists('users', 'id')
4145
]
4246
];
4347
}

app/Models/Folder.php

+15-11
Original file line numberDiff line numberDiff line change
@@ -390,20 +390,24 @@ public function getUserPermissions(User $user = null)
390390
];
391391
}
392392

393-
public function setDefaultPermission($ability, $granted)
393+
public function setDefaultPermission($ability = null, $granted = null)
394394
{
395-
$defaultPermissions = $this->permissions()->whereNull('user_id')->first();
395+
$permissions = $this->permissions()->whereNull('user_id')->first();
396+
397+
if (!$permissions) {
398+
$permissions = new Permission();
396399

397-
if (empty($defaultPermissions)) {
398-
$this->permissions()->save(
399-
new Permission([
400-
$ability => $granted
401-
])
402-
);
403-
} else {
404-
$defaultPermissions->$ability = $granted;
400+
$permissions->folder()->associate($this);
405401

406-
$defaultPermissions->save();
402+
$permissions->can_create_folder = false;
403+
$permissions->can_update_folder = false;
404+
$permissions->can_delete_folder = false;
405+
$permissions->can_create_document = false;
406+
$permissions->can_delete_document = false;
407407
}
408+
409+
$permissions->$ability = $granted;
410+
411+
$permissions->save();
408412
}
409413
}

app/Models/Permission.php

+44-6
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,57 @@ class Permission extends Model
99
{
1010
use HasFactory;
1111

12+
# --------------------------------------------------------------------------
13+
# ----| Properties |--------------------------------------------------------
14+
# --------------------------------------------------------------------------
15+
16+
/**
17+
* The attributes that are mass assignable.
18+
*
19+
* @var array
20+
*/
1221
public $fillable = [
1322
'can_create_folder',
1423
'can_update_folder',
1524
'can_delete_folder',
16-
'can_create_docment',
25+
'can_create_document',
1726
'can_delete_document'
1827
];
1928

29+
/**
30+
* The attributes that should be cast to native types.
31+
*
32+
* @var array
33+
*/
2034
public $casts = [
21-
'can_create_folder' => 'boolean',
22-
'can_update_folder' => 'boolean',
23-
'can_delete_folder' => 'boolean',
24-
'can_create_docment' => 'boolean',
25-
'can_delete_document'=> 'boolean',
35+
'can_create_folder' => 'boolean',
36+
'can_update_folder' => 'boolean',
37+
'can_delete_folder' => 'boolean',
38+
'can_create_document' => 'boolean',
39+
'can_delete_document' => 'boolean',
2640
];
41+
42+
# --------------------------------------------------------------------------
43+
# ----| Relations |---------------------------------------------------------
44+
# --------------------------------------------------------------------------
45+
46+
/**
47+
* Related user
48+
*
49+
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
50+
*/
51+
public function user()
52+
{
53+
return $this->belongsTo(User::class);
54+
}
55+
56+
/**
57+
* Related folder
58+
*
59+
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
60+
*/
61+
public function folder()
62+
{
63+
return $this->belongsTo(Folder::class);
64+
}
2765
}

app/Models/Traits/User/HasFolders.php

+28
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Models\Folder;
66
use App\Models\Group;
7+
use App\Models\Permission;
78

89
trait HasFolders
910
{
@@ -219,4 +220,31 @@ public function ensureAncestorsAreExpanded(Folder $folder = null)
219220
$this->setFolderExpandedState(true, $folder);
220221
}
221222
}
223+
224+
/**
225+
* Define this user permission for specified folder and ability
226+
*/
227+
public function setFolderPermissions(Folder $folder, $ability = null, $grant = false)
228+
{
229+
$permissions = $this->permissions()->where('folder_id', $folder->id)->first();
230+
231+
if (!$permissions) {
232+
$permissions = new Permission();
233+
234+
$permissions->user()->associate($this);
235+
$permissions->folder()->associate($folder);
236+
}
237+
238+
$defaultPermissions = $folder->getDefaultPermissions();
239+
240+
if ($ability !== null) {
241+
$permissions->{$ability} = $grant;
242+
} else {
243+
foreach ($defaultPermissions as $defaultAbility => $defaultGrant) {
244+
$permissions->{$defaultAbility} = $defaultGrant;
245+
}
246+
}
247+
248+
$permissions->save();
249+
}
222250
}

app/Models/User.php

+10
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@ public function userHistoryEntries()
9595
return $this->hasMany(HistoryEntry::class);
9696
}
9797

98+
/**
99+
* Permissions affected to this user
100+
*
101+
* @return \Illuminate\Database\Eloquent\Relations\HasMany
102+
*/
103+
public function permissions()
104+
{
105+
return $this->hasMany(Permission::class);
106+
}
107+
98108
# --------------------------------------------------------------------------
99109
# ----| Methods |-----------------------------------------------------------
100110
# --------------------------------------------------------------------------

config/app.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
|--------------------------------------------------------------------------
113113
*/
114114

115-
'version' => '0.8.10',
115+
'version' => '0.8.11',
116116

117117
/*
118118
|--------------------------------------------------------------------------

config/routes.php

+3
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,14 @@
3434
'folder.destroy',
3535
'folder.details',
3636
'folder.index',
37+
'folder.per_user_permissions',
38+
'folder.remove_permissions',
3739
'folder.set_permission',
3840
'folder.show',
3941
'folder.store',
4042
'folder.toggle_branch',
4143
'folder.update',
44+
'folder.users_without_permissions',
4245
'group.accept_invitation',
4346
'group.destroy',
4447
'group.index',

public/js/app.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/js/groups.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/js/highlights.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/js/history.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/js/import.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/js/themes-browser.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/mix-manifest.json

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{
2-
"/js/app.js": "/js/app.js?id=78811c630a18dc4c3b90",
3-
"/themes/cyca-dark/theme.css": "/themes/cyca-dark/theme.css?id=afb6085e0137be5723c3",
4-
"/themes/cyca-light/theme.css": "/themes/cyca-light/theme.css?id=be5a16cf0e6f85afa3b1",
5-
"/js/groups.js": "/js/groups.js?id=f8ceca1188bafecc6853",
6-
"/js/highlights.js": "/js/highlights.js?id=e22cbaca83e2f10cef32",
7-
"/js/history.js": "/js/history.js?id=04f1837a5d38b6c7385f",
8-
"/js/import.js": "/js/import.js?id=dc4db8077d2231b2ff27",
9-
"/js/themes-browser.js": "/js/themes-browser.js?id=9590890f2ae0200cf94c",
2+
"/js/app.js": "/js/app.js?id=0e811bc45172c7df68bb",
3+
"/themes/cyca-dark/theme.css": "/themes/cyca-dark/theme.css?id=027ec3932a5f8f5f051d",
4+
"/themes/cyca-light/theme.css": "/themes/cyca-light/theme.css?id=f6f2dfe318f709bf0efa",
5+
"/js/groups.js": "/js/groups.js?id=8f3f1acd5f4db7a818b4",
6+
"/js/highlights.js": "/js/highlights.js?id=3402c4cc6939a9c5d3e5",
7+
"/js/history.js": "/js/history.js?id=48c245fddeb9d202f44e",
8+
"/js/import.js": "/js/import.js?id=f61de2d88a9491a69e0f",
9+
"/js/themes-browser.js": "/js/themes-browser.js?id=6f97adf318c4da67d7a2",
1010
"/themes/cyca-dark/theme.json": "/themes/cyca-dark/theme.json?id=e6af9f523b70bc467aa4",
1111
"/themes/cyca-light/theme.json": "/themes/cyca-light/theme.json?id=bb59033be8f29999311e"
1212
}

resources/css/components/badge.css

+5
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@
2828
color: theme("colors.groups-browser.status.joining.bg");
2929
background-color: theme("colors.badge.bg");
3030
}
31+
32+
.badge.danger {
33+
color: theme("colors.groups-browser.status.rejected.bg");
34+
background-color: theme("colors.badge.bg");
35+
}

resources/css/components/components.css

+8
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,11 @@
5454
.inline-document .favicon {
5555
@apply inline-block;
5656
}
57+
58+
.vertical-text {
59+
vertical-align: bottom;
60+
display: inline-block;
61+
width: 1%;
62+
white-space: nowrap;
63+
transform: rotate(-90deg);
64+
}

0 commit comments

Comments
 (0)