Comparison

util/roles.lua @ 12647:a661292d074a

util.roles: Add new utility module to consolidate role objects and methods
author Matthew Wild <mwild1@gmail.com>
date Tue, 19 Jul 2022 17:44:26 +0100
child 12746:7eabf8d78978
comparison
equal deleted inserted replaced
12646:3f38f4735c7a 12647:a661292d074a
1 local array = require "util.array";
2 local it = require "util.iterators";
3 local new_short_id = require "util.id".short;
4
5 local role_methods = {};
6 local role_mt = {
7 __index = role_methods;
8 __name = "role";
9 __add = nil;
10 };
11
12 local function is_role(o)
13 local mt = getmetatable(o);
14 return mt == role_mt;
15 end
16
17 local function _new_may(permissions, inherited_mays)
18 local n_inherited = inherited_mays and #inherited_mays;
19 return function (role, action, context)
20 -- Note: 'role' may be a descendent role, not only the one we're attached to
21 local policy = permissions[action];
22 if policy ~= nil then
23 return policy;
24 end
25 if n_inherited then
26 for i = 1, n_inherited do
27 policy = inherited_mays[i](role, action, context);
28 if policy ~= nil then
29 return policy;
30 end
31 end
32 end
33 return false;
34 end
35 end
36
37 local permissions_key = {};
38
39 -- {
40 -- Required:
41 -- name = "My fancy role";
42 --
43 -- Optional:
44 -- inherits = { role_obj... }
45 -- default = true
46 -- priority = 100
47 -- permissions = {
48 -- ["foo"] = true; -- allow
49 -- ["bar"] = false; -- deny
50 -- }
51 -- }
52 local function new(base_config, overrides)
53 local config = setmetatable(overrides or {}, { __index = base_config });
54 local permissions = {};
55 local inherited_mays;
56 if config.inherits then
57 inherited_mays = array.pluck(config.inherits, "may");
58 end
59 local new_role = {
60 id = new_short_id();
61 name = config.name;
62 description = config.description;
63 default = config.default;
64 priority = config.priority;
65 may = _new_may(permissions, inherited_mays);
66 inherits = config.inherits;
67 [permissions_key] = permissions;
68 };
69 local desired_permissions = config.permissions or config[permissions_key];
70 for k, v in pairs(desired_permissions or {}) do
71 permissions[k] = v;
72 end
73 return setmetatable(new_role, role_mt);
74 end
75
76 function role_methods:clone(overrides)
77 return new(self, overrides);
78 end
79
80 function role_methods:set_permission(permission_name, policy, overwrite)
81 local permissions = self[permissions_key];
82 if overwrite ~= true and permissions[permission_name] ~= nil and permissions[permission_name] ~= policy then
83 return false, "policy-already-exists";
84 end
85 permissions[permission_name] = policy;
86 return true;
87 end
88
89 function role_mt.__tostring(self)
90 return ("role<[%s] %s>"):format(self.id or "nil", self.name or "[no name]");
91 end
92
93 function role_mt.__pairs(self)
94 return it.filter(permissions_key, next, self);
95 end
96
97 return {
98 is_role = is_role;
99 new = new;
100 };