Mercurial > prosody-hg
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 |
| parents | 85f7cd91dc31 |
| children | 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 |
