Skip to content

Commit 2eeb314

Browse files
committed
[permissions] move permissions to database, add GUI permissions editor
1 parent 124f3eb commit 2eeb314

File tree

10 files changed

+585
-79
lines changed

10 files changed

+585
-79
lines changed

core/permissions.php

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ abstract class Permissions
2525

2626
/** enable or disable extensions */
2727
public const MANAGE_EXTENSION_LIST = "manage_extension_list";
28+
public const MANAGE_PERMISSION_LIST = "manage_permission_list";
2829
public const MANAGE_ALIAS_LIST = "manage_alias_list";
2930
public const MANAGE_AUTO_TAG = "manage_auto_tag";
3031
public const MASS_TAG_EDIT = "mass_tag_edit";

core/testcase.php

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ public function setUp(): void
4646
foreach ($database->get_col("SELECT id FROM images") as $image_id) {
4747
send_event(new ImageDeletionEvent(Image::by_id((int)$image_id), true));
4848
}
49+
// Reload users from the database in case they were modified
50+
UserClass::loadClasses();
4951

5052
$_tracer->end(); # setUp
5153
$_tracer->begin("test");

core/tests/UserClassTest.php

-11
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,6 @@
1010

1111
class UserClassTest extends ShimmiePHPUnitTestCase
1212
{
13-
public function test_new_class(): void
14-
{
15-
$cls = new UserClass("user2", "user", [
16-
Permissions::CREATE_COMMENT => true,
17-
Permissions::BIG_SEARCH => false,
18-
]);
19-
$this->assertEquals("user2", $cls->name);
20-
$this->assertTrue($cls->can(Permissions::CREATE_COMMENT));
21-
$this->assertFalse($cls->can(Permissions::BIG_SEARCH));
22-
}
23-
2413
public function test_not_found(): void
2514
{
2615
$cls = UserClass::$known_classes['user'];

core/user.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public function __construct(array $row)
5353
$this->email = $row['email'];
5454
$this->join_date = $row['joindate'];
5555
$this->passhash = $row['pass'];
56-
56+
//var_dump(array_keys(UserClass::$known_classes));
5757
if (array_key_exists($row["class"], UserClass::$known_classes)) {
5858
$this->class = UserClass::$known_classes[$row["class"]];
5959
} else {

core/userclass.php

+40-67
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Shimmie2;
66

7+
use FFSPHP\PDO;
8+
79
use GQLA\Type;
810
use GQLA\Field;
911

@@ -19,21 +21,29 @@ class UserClass
1921
#[Field]
2022
public ?string $name = null;
2123
public ?UserClass $parent = null;
24+
public bool $core = false;
2225

2326
/** @var array<string, bool> */
2427
public array $abilities = [];
2528

26-
/**
27-
* @param array<string, bool> $abilities
28-
*/
29-
public function __construct(string $name, string $parent = null, array $abilities = [])
29+
public function __construct(string $name)
3030
{
31+
global $database;
32+
3133
$this->name = $name;
32-
$this->abilities = $abilities;
34+
$class = $database->execute("SELECT * FROM permissions WHERE class = :class", ["class" => $name])->fetch(PDO::FETCH_ASSOC);
3335

34-
if (!is_null($parent)) {
35-
$this->parent = static::$known_classes[$parent];
36+
if (!is_null($class["parent"])) {
37+
$this->parent = static::$known_classes[$class["parent"]];
3638
}
39+
$this->core = (bool)$class["core"];
40+
41+
unset($class["id"]);
42+
unset($class["class"]);
43+
unset($class["parent"]);
44+
unset($class["core"]);
45+
46+
$this->abilities = $class;
3747

3848
static::$known_classes[$name] = $this;
3949
}
@@ -58,10 +68,16 @@ public function permissions(): array
5868
*/
5969
public function can(string $ability): bool
6070
{
61-
if (array_key_exists($ability, $this->abilities)) {
62-
return $this->abilities[$ability];
71+
// hellbanned is a snowflake, it isn't really a "permission" so much as
72+
// "a special behaviour which applies to one particular user class"
73+
if ($this->name == "admin" && $ability != "hellbanned") {
74+
return true;
75+
} elseif (array_key_exists($ability, $this->abilities) && $this->abilities[$ability]) {
76+
return true;
6377
} elseif (!is_null($this->parent)) {
6478
return $this->parent->can($ability);
79+
} elseif (array_key_exists($ability, $this->abilities)) {
80+
return false;
6581
} else {
6682
$min_dist = 9999;
6783
$min_ability = null;
@@ -75,63 +91,20 @@ public function can(string $ability): bool
7591
throw new ServerError("Unknown ability '$ability'. Did the developer mean '$min_ability'?");
7692
}
7793
}
78-
}
7994

80-
$_all_false = [];
81-
$_all_true = [];
82-
foreach ((new \ReflectionClass(Permissions::class))->getConstants() as $k => $v) {
83-
assert(is_string($v));
84-
$_all_false[$v] = false;
85-
$_all_true[$v] = true;
95+
// clear and load classes from the database.
96+
public static function loadClasses(): void
97+
{
98+
global $database;
99+
100+
// clear any existing classes to avoid complications with parent classes
101+
foreach(static::$known_classes as $k => $v) {
102+
unset(static::$known_classes[$k]);
103+
}
104+
105+
$classes = $database->get_col("SELECT class FROM permissions WHERE 1=1 ORDER BY id");
106+
foreach($classes as $class) {
107+
new UserClass($class);
108+
}
109+
}
86110
}
87-
// hellbanned is a snowflake, it isn't really a "permission" so much as
88-
// "a special behaviour which applies to one particular user class"
89-
$_all_true[Permissions::HELLBANNED] = false;
90-
new UserClass("base", null, $_all_false);
91-
new UserClass("admin", null, $_all_true);
92-
unset($_all_true);
93-
unset($_all_false);
94-
95-
// Ghost users can't do anything
96-
new UserClass("ghost", "base", [
97-
Permissions::READ_PM => true,
98-
]);
99-
100-
// Anonymous users can't do anything by default, but
101-
// the admin might grant them some permissions
102-
new UserClass("anonymous", "base", [
103-
Permissions::CREATE_USER => true,
104-
]);
105-
106-
new UserClass("user", "base", [
107-
Permissions::BIG_SEARCH => true,
108-
Permissions::CREATE_IMAGE => true,
109-
Permissions::CREATE_COMMENT => true,
110-
Permissions::EDIT_IMAGE_TAG => true,
111-
Permissions::EDIT_IMAGE_SOURCE => true,
112-
Permissions::EDIT_IMAGE_TITLE => true,
113-
Permissions::EDIT_IMAGE_RELATIONSHIPS => true,
114-
Permissions::EDIT_IMAGE_ARTIST => true,
115-
Permissions::CREATE_IMAGE_REPORT => true,
116-
Permissions::EDIT_IMAGE_RATING => true,
117-
Permissions::EDIT_FAVOURITES => true,
118-
Permissions::CREATE_VOTE => true,
119-
Permissions::SEND_PM => true,
120-
Permissions::READ_PM => true,
121-
Permissions::SET_PRIVATE_IMAGE => true,
122-
Permissions::PERFORM_BULK_ACTIONS => true,
123-
Permissions::BULK_DOWNLOAD => true,
124-
Permissions::CHANGE_USER_SETTING => true,
125-
Permissions::FORUM_CREATE => true,
126-
Permissions::NOTES_CREATE => true,
127-
Permissions::NOTES_EDIT => true,
128-
Permissions::NOTES_REQUEST => true,
129-
Permissions::POOLS_CREATE => true,
130-
Permissions::POOLS_UPDATE => true,
131-
]);
132-
133-
new UserClass("hellbanned", "user", [
134-
Permissions::HELLBANNED => true,
135-
]);
136-
137-
@include_once "data/config/user-classes.conf.php";

ext/perm_manager/info.php

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shimmie2;
6+
7+
class PermManagerInfo extends ExtensionInfo
8+
{
9+
public const KEY = "perm_manager";
10+
11+
public string $key = self::KEY;
12+
public string $name = "Permission Manager";
13+
public string $url = self::SHIMMIE_URL;
14+
public array $authors = self::SHISH_AUTHOR;
15+
public string $license = self::LICENSE_GPLV2;
16+
public ExtensionVisibility $visibility = ExtensionVisibility::ADMIN;
17+
public ExtensionCategory $category = ExtensionCategory::ADMIN;
18+
public string $description = "Allows the admin to modify user class permissions.";
19+
public bool $core = true;
20+
}

0 commit comments

Comments
 (0)