Add support for members and permissions

Fixes #22
master
rubenwardy 2018-11-25 23:19:27 +00:00
parent 8411dfd3ff
commit f300d95b37
9 changed files with 236 additions and 22 deletions

View File

@ -76,7 +76,7 @@ describe("banking", function()
local comp = company.Company:new() local comp = company.Company:new()
comp:set_title_calc_name("Two") comp:set_title_calc_name("Two")
comp.owner = "testuser" comp.ceo = "testuser"
company.add(comp) company.add(comp)
assert.is_false(banking.transfer("a", "c:two", "c:test", 10, nil)) assert.is_false(banking.transfer("a", "c:two", "c:test", 10, nil))

View File

@ -127,6 +127,50 @@ function company.get_companies_for_player(pname)
return comps return comps
end end
function company.set_perms(comp, actor, target, permission, is_grant)
if not comp:check_perm(actor, "MANAGE_MEMBERS",
{ action = "add", name = "username" }) then
return false, "Missing permission: MANAGE_MEMBERS"
end
if target == comp:get_ceo_name() then
if is_grant then
return false, "The CEO already has all permissions"
else
return false, "Permissions cannot be revoked from the CEO"
end
end
permission = permission:upper()
if permission ~= "ALL" and not company.permissions[permission] then
return false, "Unknown permission " .. permission
end
local member = comp.members[target]
if not member then
return false, target .. " is not a member of " .. comp.title
end
if permission == "ALL" then
for key in pairs(company.permissions) do
member.perms[key] = is_grant
end
else
member.perms[permission] = is_grant
end
company.dirty = true
local perms = {}
for key, value in pairs(member.perms) do
if value then
perms[#perms + 1] = key
end
end
return true, "Permissions: " .. table.concat(perms, ", ")
end
company.registered_on_creates = {} company.registered_on_creates = {}
function company.register_on_create(func) function company.register_on_create(func)
assert(type(func) == "function") assert(type(func) == "function")

View File

@ -2,6 +2,7 @@ local adt = audit("company.cmd")
ChatCmdBuilder.types.comp = "(c:[a-z]+)" ChatCmdBuilder.types.comp = "(c:[a-z]+)"
ChatCmdBuilder.types.owner = "(c?:?[a-z]+)" ChatCmdBuilder.types.owner = "(c?:?[a-z]+)"
ChatCmdBuilder.types.alpha = "([A-Za-z_]+)"
ChatCmdBuilder.new("company", function(cmd) ChatCmdBuilder.new("company", function(cmd)
cmd:sub("list", function(name) cmd:sub("list", function(name)
@ -17,7 +18,7 @@ ChatCmdBuilder.new("company", function(cmd)
cmd:sub("register :title:text", function(name, title) cmd:sub("register :title:text", function(name, title)
local comp = company.Company:new() local comp = company.Company:new()
comp:set_title_calc_name(title) comp:set_title_calc_name(title)
comp.owner = name comp.ceo = name
if #title < 3 then if #title < 3 then
return false, "Company names must be at least 3 characters" return false, "Company names must be at least 3 characters"
@ -59,6 +60,87 @@ ChatCmdBuilder.new("company", function(cmd)
return false, "No company by the name '" .. cname .. "' found" return false, "No company by the name '" .. cname .. "' found"
end end
end) end)
cmd:sub("member :username:username", function(name, username)
local comp = company.get_active(name)
if not comp then
return false, "Select a company by doing /company use <NAME>"
end
if comp:get_ceo_name() == username then
return false, username .. " is the CEO of " .. comp.title
end
local member = comp.members[username]
if not member then
return false, username .. " is not a member of " .. comp.title
end
local perms = {}
for key, value in pairs(member.perms) do
if value then
perms[#perms + 1] = key
end
end
return true, username .. " is a member of " .. comp.title ..
"\nPermissions: " .. table.concat(perms, ", ")
end)
cmd:sub("add :username:username", function(name, username)
local comp = company.get_active(name)
if not comp then
return false, "Select a company by doing /company use <NAME>"
end
if not comp:check_perm(name, "MANAGE_MEMBERS",
{ action = "add", name = "username" }) then
return false, "Missing permission: MANAGE_MEMBERS"
end
if comp:get_ceo_name() == username then
return false, username .. " is the CEO of " .. comp.title
end
if comp.members[username] then
return false, username .. " is already a member of " .. comp.title
end
if not minetest.player_exists(username) then
return false, username .. " doesn't exist"
end
local member = comp:add_member(username)
company.dirty = true
local perms = {}
for key, value in pairs(member.perms) do
if value then
perms[#perms + 1] = key
end
end
return true, "Added " .. username .. " to " .. comp.title ..
"\nPermissions: " .. table.concat(perms, ", ")
end)
cmd:sub("grant :username:username :permission:alpha", function(name, username, permission)
local comp = company.get_active(name)
if not comp then
return false, "Select a company by doing /company use <NAME>"
end
return company.set_perms(comp, name, username, permission:upper(), true)
end)
cmd:sub("revoke :username:username :permission:alpha", function(name, username, permission)
local comp = company.get_active(name)
if not comp then
return false, "Select a company by doing /company use <NAME>"
end
return company.set_perms(comp, name, username, permission:upper(), false)
end)
end, { end, {
description = "Company tools" description = "Company tools"
}) })

View File

@ -5,7 +5,8 @@ function Company:new(obj)
obj = obj or {} obj = obj or {}
setmetatable(obj, self) setmetatable(obj, self)
self.__index = self self.__index = self
self.owner = nil self.ceo = nil
self.members = {}
return obj return obj
end end
@ -14,7 +15,8 @@ function Company:to_table()
return { return {
title = self.title, title = self.title,
name = self.name, name = self.name,
owner = self.owner ceo = self.ceo,
members = self.members,
} }
end end
@ -24,8 +26,9 @@ function Company:from_table(t)
if self.name:sub(1, 2) ~= "c:" then if self.name:sub(1, 2) ~= "c:" then
self.name = "c:" .. self.name self.name = "c:" .. self.name
end end
self.owner = t.owner self.ceo = t.ceo or t.owner
return self.name ~= nil and self.owner ~= nil self.members = t.members or {}
return self.name ~= nil and self.ceo ~= nil and type(self.members) == "table"
end end
function Company:set_title_calc_name(title) function Company:set_title_calc_name(title)
@ -36,12 +39,12 @@ function Company:set_title_calc_name(title)
end end
function Company:get_ceo_name() function Company:get_ceo_name()
return self.owner return self.ceo
end end
function Company:get_ownership(username) function Company:get_ownership(username)
-- TODO: ownership -- TODO: ownership
if self.owner == username then if self.ceo == username then
return 1 return 1
else else
return 0 return 0
@ -58,8 +61,26 @@ function Company:check_perm(username, permission, meta)
assert(company.permissions[permission]) assert(company.permissions[permission])
assert(meta == nil or type(meta) == "table") assert(meta == nil or type(meta) == "table")
-- TODO: permissions if self.ceo == username then
return self:get_ownership(username) > 0 return true
end
local member = self.members[username]
return member and member.perms[permission] and true or false
end
function Company:add_member(username)
assert(not self.members[username])
local mem = {
perms = {
SWITCH_TO = true,
INTERACT_AREA = true,
},
}
self.members[username] = mem
return mem
end end
function Company:is_government() function Company:is_government()

View File

@ -21,7 +21,7 @@ company.show_company_select_dialog = lib_quickfs.register("company:set_company",
if comp:get_ceo_name() == pname then if comp:get_ceo_name() == pname then
return minetest.formspec_escape(comp.title) return minetest.formspec_escape(comp.title)
else else
return minetest.formspec_escape(minetest.colorize("#c0c0c0", comp.name)) return minetest.formspec_escape(minetest.colorize("#c0c0c0", comp.title))
end end
end), ","), end), ","),
";1;false]", ";1;false]",
@ -151,10 +151,15 @@ company.register_panel({
}) })
company.register_panel({ company.register_panel({
title = "Employees", title = "Members",
bgcolor = "#396", bgcolor = "#396",
get = function(_, _, _, _) get = function(_, _, comp, _)
return "label[0.2,0.2;0 employees.]" local memcount = 0
for username, props in pairs(comp.members) do
memcount = memcount + 1
end
return "label[0.2,0.2;" .. memcount .. " members]"
end, end,
}) })

View File

@ -10,4 +10,5 @@ company.permissions = {
SHOP_ADMIN = "Can change the settings of a shop, including prices", SHOP_ADMIN = "Can change the settings of a shop, including prices",
SHOP_CHEST = "Can place, modify shop chests", SHOP_CHEST = "Can place, modify shop chests",
BUY_ITEMS = "Can buy from shops", BUY_ITEMS = "Can buy from shops",
MANAGE_MEMBERS = "Can manage company members",
} }

View File

@ -15,7 +15,7 @@ describe("company", function()
it("add", function() it("add", function()
local comp = company.Company:new() local comp = company.Company:new()
comp:set_title_calc_name("Test Company") comp:set_title_calc_name("Test Company")
comp.owner = "testuser" comp.ceo = "testuser"
assert.equals (#company._companies, 0) assert.equals (#company._companies, 0)
assert.is_true(company.add(comp)) assert.is_true(company.add(comp))
assert.equals (#company._companies, 1) assert.equals (#company._companies, 1)
@ -26,7 +26,7 @@ describe("company", function()
local comp = company.get_by_name("c:test_company") local comp = company.get_by_name("c:test_company")
assert.is_not_nil(comp) assert.is_not_nil(comp)
assert.equals("c:test_company", comp.name) assert.equals("c:test_company", comp.name)
assert.equals("testuser", comp.owner) assert.equals("testuser", comp.ceo)
end) end)
it("active_company", function() it("active_company", function()
@ -37,7 +37,7 @@ describe("company", function()
local comp = company.get_active("testuser") local comp = company.get_active("testuser")
assert.is_not_nil(comp) assert.is_not_nil(comp)
assert.equals("c:test_company", comp.name) assert.equals("c:test_company", comp.name)
assert.equals("testuser", comp.owner) assert.equals("testuser", comp.ceo)
end) end)
it("get_companies_for_player", function() it("get_companies_for_player", function()

View File

@ -10,12 +10,12 @@ local Company = company.Company
describe("company.Company", function() describe("company.Company", function()
it("constructs", function() it("constructs", function()
local company = Company:new() local company = Company:new()
assert.is_nil(company.owner) assert.is_nil(company.ceo)
end) end)
it("has ownership", function() it("has ownership", function()
local company = Company:new() local company = Company:new()
company.owner = "foobar" company.ceo = "foobar"
assert.equals(company:get_ownership("foobar"), 1) assert.equals(company:get_ownership("foobar"), 1)
assert.equals(company:get_ownership("foobarasas"), 0) assert.equals(company:get_ownership("foobarasas"), 0)
assert.equals(company:get_ownership("a"), 0) assert.equals(company:get_ownership("a"), 0)
@ -26,21 +26,21 @@ describe("company.Company", function()
it("has ceo", function() it("has ceo", function()
local company = Company:new() local company = Company:new()
company.owner = "foobar" company.ceo = "foobar"
assert.equals(company:get_ceo_name(), "foobar") assert.equals(company:get_ceo_name(), "foobar")
end) end)
it("can become active", function() it("can become active", function()
local company = Company:new() local company = Company:new()
assert.is_false(company:can_become_active("foobar")) assert.is_false(company:can_become_active("foobar"))
company.owner = "foobar" company.ceo = "foobar"
assert.is_true (company:can_become_active("foobar")) assert.is_true (company:can_become_active("foobar"))
assert.is_false(company:can_become_active("sdsddd")) assert.is_false(company:can_become_active("sdsddd"))
end) end)
it("has permissions", function() it("has permissions", function()
local company = Company:new() local company = Company:new()
company.owner = "foobar" company.ceo = "foobar"
assert.is_true (company:check_perm("foobar", "SWITCH_TO")) assert.is_true (company:check_perm("foobar", "SWITCH_TO"))
assert.is_false(company:check_perm("sdsddd", "SWITCH_TO")) assert.is_false(company:check_perm("sdsddd", "SWITCH_TO"))
end) end)

View File

@ -218,6 +218,67 @@ land.show_buy_to = lib_quickfs.register("land:buy", {
}) })
sfinv.register_page("land:places", {
title = "Places",
get = function(self, player, context)
local pname = player:get_player_name()
local comp = company.get_active(pname)
-- Using an array to build a formspec is considerably faster
local formspec = {
company.get_company_header(pname, 8)
}
if comp then
local i = 0
for _, panel in pairs(company.registered_panels) do
if not panel.show_to or panel:show_to(player, comp, context) then
formspec[#formspec + 1] = "container["
formspec[#formspec + 1] = tostring((i % 2) * 4)
formspec[#formspec + 1] = ","
formspec[#formspec + 1] = tostring(math.floor(i / 2) * 2 + 1)
formspec[#formspec + 1] = ".3]"
formspec[#formspec + 1] = "label[1.5,-0.3;"
formspec[#formspec + 1] = panel.title
formspec[#formspec + 1] = "]"
formspec[#formspec + 1] = "box[0,-0.3;3.8,1.8;"
formspec[#formspec + 1] = panel.bgcolor
formspec[#formspec + 1] = "]"
formspec[#formspec + 1] = panel:get(player, comp, context)
formspec[#formspec + 1] = "container_end[]"
i = i + 1
end
end
while i < 2*4 do
formspec[#formspec + 1] = "box["
formspec[#formspec + 1] = tostring((i % 2) * 4)
formspec[#formspec + 1] = ","
formspec[#formspec + 1] = tostring(math.floor(i / 2) * 2 + 1)
formspec[#formspec + 1] = ";3.8,1.8;#111]"
i = i + 1
end
end
-- Wrap the formspec in sfinv's layout (ie: adds the tabs and background)
return sfinv.make_formspec(player, context,
table.concat(formspec, ""), false)
end,
on_player_receive_fields = function(self, player, context, fields)
if fields.switch then
company.show_company_select_dialog(player:get_player_name(), function(player2)
sfinv.set_page_and_show(player2, "company:company")
end)
end
end,
})
company.register_panel({ company.register_panel({
title = "Land", title = "Land",
bgcolor = "#A0522D", bgcolor = "#A0522D",