Software /
code /
prosody
Comparison
plugins/muc/muc.lib.lua @ 6187:c0b4b5d41e55
plugins/muc/muc.lib: Improve set affiliation logic;
- Each affiliation and role is now ranked
- Changes up in affiliation will not downgrade your role
- Now sends a new set of presences if you gained moderator in a semi-anonymous room.
- Better input validation; matches closer with ':set_role'
- Don't short circuit; as if user has non-default role they will not get updated
author | daurnimator <quae@daurnimator.com> |
---|---|
date | Fri, 28 Mar 2014 17:58:25 -0400 |
parent | 6186:85f7cd91dc31 |
child | 6188:f47268c8a8d0 |
comparison
equal
deleted
inserted
replaced
6186:85f7cd91dc31 | 6187:c0b4b5d41e55 |
---|---|
57 end | 57 end |
58 | 58 |
59 function room_mt:get_occupant_jid(real_jid) | 59 function room_mt:get_occupant_jid(real_jid) |
60 return self._jid_nick[real_jid] | 60 return self._jid_nick[real_jid] |
61 end | 61 end |
62 | |
63 local valid_affiliations = { | |
64 outcast = 0; | |
65 none = 1; | |
66 member = 2; | |
67 admin = 3; | |
68 owner = 4; | |
69 }; | |
70 | |
71 local valid_roles = { | |
72 none = 0; | |
73 visitor = 1; | |
74 participant = 2; | |
75 moderator = 3; | |
76 }; | |
62 | 77 |
63 function room_mt:get_default_role(affiliation) | 78 function room_mt:get_default_role(affiliation) |
64 if affiliation == "owner" or affiliation == "admin" then | 79 if affiliation == "owner" or affiliation == "admin" then |
65 return "moderator"; | 80 return "moderator"; |
66 elseif affiliation == "member" then | 81 elseif affiliation == "member" then |
1310 local result = self._affiliations[bare]; -- Affiliations are granted, revoked, and maintained based on the user's bare JID. | 1325 local result = self._affiliations[bare]; -- Affiliations are granted, revoked, and maintained based on the user's bare JID. |
1311 if not result and self._affiliations[host] == "outcast" then result = "outcast"; end -- host banned | 1326 if not result and self._affiliations[host] == "outcast" then result = "outcast"; end -- host banned |
1312 return result; | 1327 return result; |
1313 end | 1328 end |
1314 | 1329 |
1315 local valid_affiliations = { | |
1316 outcast = true; | |
1317 none = true; | |
1318 member = true; | |
1319 admin = true; | |
1320 owner = true; | |
1321 }; | |
1322 function room_mt:set_affiliation(actor, jid, affiliation, reason) | 1330 function room_mt:set_affiliation(actor, jid, affiliation, reason) |
1323 if not actor then return nil, "modify", "not-acceptable"; end; | 1331 if not actor then return nil, "modify", "not-acceptable"; end; |
1324 | 1332 |
1325 jid = jid_bare(jid); | 1333 jid = jid_bare(jid); |
1326 | 1334 |
1327 if valid_affiliations[affiliation or "none"] == nil then | 1335 if valid_affiliations[affiliation or "none"] == nil then |
1328 return nil, "modify", "not-acceptable"; | 1336 return nil, "modify", "not-acceptable"; |
1329 end | 1337 end |
1330 affiliation = affiliation ~= "none" and affiliation or nil; -- coerces `affiliation == false` to `nil` | 1338 affiliation = affiliation ~= "none" and affiliation or nil; -- coerces `affiliation == false` to `nil` |
1331 | 1339 |
1340 local target_affiliation = self._affiliations[jid]; -- Raw; don't want to check against host | |
1341 local is_downgrade = valid_affiliations[target_affiliation or "none"] > valid_affiliations[affiliation or "none"]; | |
1342 | |
1332 if actor ~= true then | 1343 if actor ~= true then |
1333 local actor_affiliation = self:get_affiliation(actor); | 1344 local actor_bare = jid_bare(actor); |
1334 local target_affiliation = self:get_affiliation(jid); | 1345 local actor_affiliation = self._affiliations[actor_bare]; |
1335 if target_affiliation == affiliation then -- no change, shortcut | 1346 if actor_affiliation == "owner" then |
1336 return true; | 1347 if actor_bare == jid then -- self change |
1337 end | 1348 -- need at least one owner |
1338 if actor_affiliation ~= "owner" then | 1349 local is_last = true; |
1339 if affiliation == "owner" or affiliation == "admin" or actor_affiliation ~= "admin" or target_affiliation == "owner" or target_affiliation == "admin" then | 1350 for j, aff in pairs(self._affiliations) do if j ~= jid and aff == "owner" then is_last = false; break; end end |
1340 return nil, "cancel", "not-allowed"; | 1351 if is_last then |
1341 end | 1352 return nil, "cancel", "conflict"; |
1342 elseif target_affiliation == "owner" and jid_bare(actor) == jid then -- self change | 1353 end |
1343 local is_last = true; | 1354 end |
1344 for j, aff in pairs(self._affiliations) do if j ~= jid and aff == "owner" then is_last = false; break; end end | 1355 -- owners can do anything else |
1345 if is_last then | 1356 elseif affiliation == "owner" or affiliation == "admin" |
1346 return nil, "cancel", "conflict"; | 1357 or actor_affiliation ~= "admin" |
1347 end | 1358 or target_affiliation == "owner" or target_affiliation == "admin" then |
1348 end | 1359 -- Can't demote owners or other admins |
1349 end | 1360 return nil, "cancel", "not-allowed"; |
1361 end | |
1362 end | |
1363 | |
1364 -- Set in 'database' | |
1350 self._affiliations[jid] = affiliation; | 1365 self._affiliations[jid] = affiliation; |
1366 | |
1367 -- Update roles | |
1351 local role = self:get_default_role(affiliation); | 1368 local role = self:get_default_role(affiliation); |
1352 local occupants_updated = {}; | 1369 local role_rank = valid_roles[role or "none"]; |
1370 local occupants_updated = {}; -- Filled with old roles | |
1353 for nick, occupant in self:each_occupant() do | 1371 for nick, occupant in self:each_occupant() do |
1354 if occupant.bare_jid == jid then | 1372 if occupant.bare_jid == jid then |
1355 occupant.role = role; | 1373 -- need to publcize in all cases; as affiliation in <item/> has changed. |
1356 self:save_occupant(occupant); | 1374 occupants_updated[occupant] = occupant.role; |
1357 occupants_updated[occupant] = true; | 1375 if occupant.role ~= role and ( |
1358 end | 1376 is_downgrade or |
1359 end | 1377 valid_roles[occupant.role or "none"] < role_rank -- upgrade |
1378 ) then | |
1379 occupant.role = role; | |
1380 self:save_occupant(occupant); | |
1381 end | |
1382 end | |
1383 end | |
1384 | |
1385 -- Tell the room of the new occupant affiliations+roles | |
1360 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}); | 1386 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}); |
1361 if not role then -- getting kicked | 1387 if not role then -- getting kicked |
1362 if affiliation == "outcast" then | 1388 if affiliation == "outcast" then |
1363 x:tag("status", {code="301"}):up(); -- banned | 1389 x:tag("status", {code="301"}):up(); -- banned |
1364 else | 1390 else |
1365 x:tag("status", {code="321"}):up(); -- affiliation change | 1391 x:tag("status", {code="321"}):up(); -- affiliation change |
1366 end | 1392 end |
1367 end | 1393 end |
1368 for occupant in pairs(occupants_updated) do | 1394 local is_semi_anonymous = self:get_whois() == "moderators"; |
1395 for occupant, old_role in pairs(occupants_updated) do | |
1369 self:publicise_occupant_status(occupant, x, actor, reason); | 1396 self:publicise_occupant_status(occupant, x, actor, reason); |
1370 end | 1397 if is_semi_anonymous and |
1398 (old_role == "moderator" and occupant.role ~= "moderator") or | |
1399 (old_role ~= "moderator" and occupant.role == "moderator") then -- Has gained or lost moderator status | |
1400 -- Send everyone else's presences (as jid visibility has changed) | |
1401 for real_jid in occupant:each_session() do | |
1402 self:send_occupant_list(real_jid, function(occupant_jid, occupant) | |
1403 return occupant.bare_jid ~= jid; | |
1404 end); | |
1405 end | |
1406 end | |
1407 end | |
1408 | |
1371 if self.save then self:save(); end | 1409 if self.save then self:save(); end |
1372 return true; | 1410 return true; |
1373 end | 1411 end |
1374 | 1412 |
1375 function room_mt:get_role(nick) | 1413 function room_mt:get_role(nick) |
1376 local occupant = self:get_occupant_by_nick(nick); | 1414 local occupant = self:get_occupant_by_nick(nick); |
1377 return occupant and occupant.role or nil; | 1415 return occupant and occupant.role or nil; |
1378 end | 1416 end |
1379 | 1417 |
1380 local valid_roles = { | |
1381 none = true; | |
1382 visitor = true; | |
1383 participant = true; | |
1384 moderator = true; | |
1385 } | |
1386 function room_mt:set_role(actor, occupant_jid, role, reason) | 1418 function room_mt:set_role(actor, occupant_jid, role, reason) |
1387 if not actor then return nil, "modify", "not-acceptable"; end | 1419 if not actor then return nil, "modify", "not-acceptable"; end |
1388 | 1420 |
1389 local occupant = self:get_occupant_by_nick(occupant_jid); | 1421 local occupant = self:get_occupant_by_nick(occupant_jid); |
1390 if not occupant then return nil, "modify", "not-acceptable"; end | 1422 if not occupant then return nil, "modify", "not-acceptable"; end |