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