modtools.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /*global mock, converse, _ */
  2. const $iq = converse.env.$iq;
  3. const $pres = converse.env.$pres;
  4. const sizzle = converse.env.sizzle;
  5. const Strophe = converse.env.Strophe;
  6. const u = converse.env.utils;
  7. async function openModtools (_converse, view) {
  8. const textarea = view.querySelector('.chat-textarea');
  9. textarea.value = '/modtools';
  10. const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
  11. view.onKeyDown(enter);
  12. await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
  13. const modal = _converse.api.modal.get('converse-modtools-modal');
  14. await u.waitUntil(() => u.isVisible(modal.el), 1000);
  15. return modal;
  16. }
  17. describe("The groupchat moderator tool", function () {
  18. it("allows you to set affiliations and roles",
  19. mock.initConverse([], {}, async function (done, _converse) {
  20. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  21. const muc_jid = 'lounge@montague.lit';
  22. let members = [
  23. {'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
  24. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  25. {'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
  26. {'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'owner'},
  27. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
  28. ];
  29. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  30. const view = _converse.chatboxviews.get(muc_jid);
  31. await u.waitUntil(() => (view.model.occupants.length === 5), 1000);
  32. const modal = await openModtools(_converse, view);
  33. let tab = modal.el.querySelector('#affiliations-tab');
  34. // Clear so that we don't match older stanzas
  35. _converse.connection.IQ_stanzas = [];
  36. tab.click();
  37. let select = modal.el.querySelector('.select-affiliation');
  38. expect(select.value).toBe('owner');
  39. select.value = 'admin';
  40. let button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
  41. button.click();
  42. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  43. let user_els = modal.el.querySelectorAll('.list-group--users > li');
  44. expect(user_els.length).toBe(1);
  45. expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: wiccarocks@shakespeare.lit');
  46. expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: wiccan');
  47. expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: admin');
  48. _converse.connection.IQ_stanzas = [];
  49. select.value = 'owner';
  50. button.click();
  51. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  52. user_els = modal.el.querySelectorAll('.list-group--users > li');
  53. expect(user_els.length).toBe(2);
  54. expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: romeo@montague.lit');
  55. expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: romeo');
  56. expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
  57. expect(user_els[1].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: crone1@shakespeare.lit');
  58. expect(user_els[1].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: thirdwitch');
  59. expect(user_els[1].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
  60. const toggle = user_els[1].querySelector('.list-group-item:nth-child(3n) .toggle-form');
  61. const form = user_els[1].querySelector('.list-group-item:nth-child(3n) .affiliation-form');
  62. expect(u.hasClass('hidden', form)).toBeTruthy();
  63. toggle.click();
  64. expect(u.hasClass('hidden', form)).toBeFalsy();
  65. select = form.querySelector('.select-affiliation');
  66. expect(select.value).toBe('owner');
  67. select.value = 'admin';
  68. const input = form.querySelector('input[name="reason"]');
  69. input.value = "You're an admin now";
  70. const submit = form.querySelector('.btn-primary');
  71. submit.click();
  72. spyOn(_converse.ChatRoomOccupants.prototype, 'fetchMembers').and.callThrough();
  73. const sent_IQ = _converse.connection.IQ_stanzas.pop();
  74. expect(Strophe.serialize(sent_IQ)).toBe(
  75. `<iq id="${sent_IQ.getAttribute('id')}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
  76. `<query xmlns="http://jabber.org/protocol/muc#admin">`+
  77. `<item affiliation="admin" jid="crone1@shakespeare.lit">`+
  78. `<reason>You&apos;re an admin now</reason>`+
  79. `</item>`+
  80. `</query>`+
  81. `</iq>`);
  82. _converse.connection.IQ_stanzas = [];
  83. const stanza = $iq({
  84. 'type': 'result',
  85. 'id': sent_IQ.getAttribute('id'),
  86. 'from': view.model.get('jid'),
  87. 'to': _converse.connection.jid
  88. });
  89. _converse.connection._dataRecv(mock.createRequest(stanza));
  90. await u.waitUntil(() => view.model.occupants.fetchMembers.calls.count());
  91. members = [
  92. {'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
  93. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  94. {'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
  95. {'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'admin'},
  96. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
  97. ];
  98. await mock.returnMemberLists(_converse, muc_jid, members);
  99. await u.waitUntil(() => view.model.occupants.pluck('affiliation').filter(o => o === 'owner').length === 1);
  100. const alert = modal.el.querySelector('.alert-primary');
  101. expect(alert.textContent.trim()).toBe('Affiliation changed');
  102. user_els = modal.el.querySelectorAll('.list-group--users > li');
  103. expect(user_els.length).toBe(1);
  104. expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: romeo@montague.lit');
  105. expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: romeo');
  106. expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
  107. tab = modal.el.querySelector('#roles-tab');
  108. tab.click();
  109. select = modal.el.querySelector('.select-role');
  110. expect(u.isVisible(select)).toBe(true);
  111. expect(select.value).toBe('moderator');
  112. button = modal.el.querySelector('.btn-primary[name="users_with_role"]');
  113. button.click();
  114. const roles_panel = modal.el.querySelector('#roles-tabpanel');
  115. await u.waitUntil(() => roles_panel.querySelectorAll('.list-group--users > li').length === 1);
  116. select.value = 'participant';
  117. button.click();
  118. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  119. user_els = roles_panel.querySelectorAll('.list-group--users > li')
  120. expect(user_els.length).toBe(1);
  121. expect(user_els[0].textContent.trim()).toBe('No users with that role found.');
  122. done();
  123. }));
  124. it("allows you to filter affiliation search results",
  125. mock.initConverse([], {}, async function (done, _converse) {
  126. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  127. const muc_jid = 'lounge@montague.lit';
  128. const members = [
  129. {'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
  130. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  131. {'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'member'},
  132. {'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'member'},
  133. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'member'},
  134. {'jid': 'juliet@capulet.lit', 'nick': 'juliet', 'affiliation': 'member'},
  135. ];
  136. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  137. const view = _converse.chatboxviews.get(muc_jid);
  138. await u.waitUntil(() => (view.model.occupants.length === 6), 1000);
  139. // Clear so that we don't match older stanzas
  140. _converse.connection.IQ_stanzas = [];
  141. const modal = await openModtools(_converse, view);
  142. const select = modal.el.querySelector('.select-affiliation');
  143. expect(select.value).toBe('owner');
  144. select.value = 'member';
  145. const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
  146. button.click();
  147. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  148. const user_els = modal.el.querySelectorAll('.list-group--users > li');
  149. expect(user_els.length).toBe(6);
  150. const nicks = Array.from(modal.el.querySelectorAll('.list-group--users > li')).map(el => el.getAttribute('data-nick'));
  151. expect(nicks.join(' ')).toBe('gower juliet romeo thirdwitch wiccan witch');
  152. const filter = modal.el.querySelector('[name="filter"]');
  153. expect(filter).not.toBe(null);
  154. filter.value = 'romeo';
  155. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  156. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
  157. filter.value = 'r';
  158. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  159. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 3));
  160. filter.value = 'gower';
  161. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  162. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
  163. filter.value = 'RoMeO';
  164. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  165. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
  166. done();
  167. }));
  168. it("allows you to filter role search results",
  169. mock.initConverse([], {}, async function (done, _converse) {
  170. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  171. const muc_jid = 'lounge@montague.lit';
  172. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', []);
  173. const view = _converse.chatboxviews.get(muc_jid);
  174. _converse.connection._dataRecv(mock.createRequest(
  175. $pres({to: _converse.jid, from: `${muc_jid}/nomorenicks`})
  176. .c('x', {xmlns: Strophe.NS.MUC_USER})
  177. .c('item', {
  178. 'affiliation': 'none',
  179. 'jid': `nomorenicks@montague.lit`,
  180. 'role': 'participant'
  181. })
  182. ));
  183. _converse.connection._dataRecv(mock.createRequest(
  184. $pres({to: _converse.jid, from: `${muc_jid}/newb`})
  185. .c('x', {xmlns: Strophe.NS.MUC_USER})
  186. .c('item', {
  187. 'affiliation': 'none',
  188. 'jid': `newb@montague.lit`,
  189. 'role': 'participant'
  190. })
  191. ));
  192. _converse.connection._dataRecv(mock.createRequest(
  193. $pres({to: _converse.jid, from: `${muc_jid}/some1`})
  194. .c('x', {xmlns: Strophe.NS.MUC_USER})
  195. .c('item', {
  196. 'affiliation': 'none',
  197. 'jid': `some1@montague.lit`,
  198. 'role': 'participant'
  199. })
  200. ));
  201. _converse.connection._dataRecv(mock.createRequest(
  202. $pres({to: _converse.jid, from: `${muc_jid}/oldhag`})
  203. .c('x', {xmlns: Strophe.NS.MUC_USER})
  204. .c('item', {
  205. 'affiliation': 'none',
  206. 'jid': `oldhag@montague.lit`,
  207. 'role': 'participant'
  208. })
  209. ));
  210. _converse.connection._dataRecv(mock.createRequest(
  211. $pres({to: _converse.jid, from: `${muc_jid}/crone`})
  212. .c('x', {xmlns: Strophe.NS.MUC_USER})
  213. .c('item', {
  214. 'affiliation': 'none',
  215. 'jid': `crone@montague.lit`,
  216. 'role': 'participant'
  217. })
  218. ));
  219. _converse.connection._dataRecv(mock.createRequest(
  220. $pres({to: _converse.jid, from: `${muc_jid}/tux`})
  221. .c('x', {xmlns: Strophe.NS.MUC_USER})
  222. .c('item', {
  223. 'affiliation': 'none',
  224. 'jid': `tux@montague.lit`,
  225. 'role': 'participant'
  226. })
  227. ));
  228. await u.waitUntil(() => (view.model.occupants.length === 7), 1000);
  229. const textarea = view.querySelector('.chat-textarea');
  230. textarea.value = '/modtools';
  231. const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
  232. view.onKeyDown(enter);
  233. await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
  234. const modal = _converse.api.modal.get('converse-modtools-modal');
  235. await u.waitUntil(() => u.isVisible(modal.el), 1000);
  236. const tab = modal.el.querySelector('#roles-tab');
  237. tab.click();
  238. // Clear so that we don't match older stanzas
  239. _converse.connection.IQ_stanzas = [];
  240. const select = modal.el.querySelector('.select-role');
  241. expect(select.value).toBe('moderator');
  242. select.value = 'participant';
  243. const button = modal.el.querySelector('.btn-primary[name="users_with_role"]');
  244. button.click();
  245. await u.waitUntil(() => !modal.loading_users_with_role);
  246. const user_els = modal.el.querySelectorAll('.list-group--users > li');
  247. expect(user_els.length).toBe(6);
  248. const nicks = Array.from(modal.el.querySelectorAll('.list-group--users > li')).map(el => el.getAttribute('data-nick'));
  249. expect(nicks.join(' ')).toBe('crone newb nomorenicks oldhag some1 tux');
  250. const filter = modal.el.querySelector('[name="filter"]');
  251. expect(filter).not.toBe(null);
  252. filter.value = 'tux';
  253. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  254. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
  255. filter.value = 'r';
  256. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  257. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 2));
  258. filter.value = 'crone';
  259. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  260. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
  261. done();
  262. }));
  263. it("shows an error message if a particular affiliation list may not be retrieved",
  264. mock.initConverse([], {}, async function (done, _converse) {
  265. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  266. const muc_jid = 'lounge@montague.lit';
  267. const members = [
  268. {'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
  269. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  270. {'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
  271. {'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'owner'},
  272. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
  273. ];
  274. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  275. const view = _converse.chatboxviews.get(muc_jid);
  276. await u.waitUntil(() => (view.model.occupants.length === 5));
  277. const modal = await openModtools(_converse, view);
  278. const tab = modal.el.querySelector('#affiliations-tab');
  279. // Clear so that we don't match older stanzas
  280. _converse.connection.IQ_stanzas = [];
  281. const IQ_stanzas = _converse.connection.IQ_stanzas;
  282. tab.click();
  283. const select = modal.el.querySelector('.select-affiliation');
  284. select.value = 'outcast';
  285. const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
  286. button.click();
  287. const iq_query = await u.waitUntil(() => _.filter(
  288. IQ_stanzas,
  289. s => sizzle(`iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_ADMIN}"] item[affiliation="outcast"]`, s).length
  290. ).pop());
  291. const error = u.toStanza(
  292. `<iq from="${muc_jid}"
  293. id="${iq_query.getAttribute('id')}"
  294. type="error"
  295. to="${_converse.jid}">
  296. <error type="auth">
  297. <forbidden xmlns="${Strophe.NS.STANZAS}"/>
  298. </error>
  299. </iq>`);
  300. _converse.connection._dataRecv(mock.createRequest(error));
  301. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  302. const user_els = modal.el.querySelectorAll('.list-group--users > li');
  303. expect(user_els.length).toBe(1);
  304. expect(user_els[0].textContent.trim()).toBe('Error: not allowed to fetch outcast list for MUC lounge@montague.lit');
  305. done();
  306. }));
  307. it("shows an error message if a particular affiliation may not be set",
  308. mock.initConverse([], {}, async function (done, _converse) {
  309. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  310. const muc_jid = 'lounge@montague.lit';
  311. const members = [
  312. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  313. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
  314. ];
  315. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  316. const view = _converse.chatboxviews.get(muc_jid);
  317. await u.waitUntil(() => (view.model.occupants.length === 2));
  318. const modal = await openModtools(_converse, view);
  319. // Clear so that we don't match older stanzas
  320. _converse.connection.IQ_stanzas = [];
  321. const tab = modal.el.querySelector('#affiliations-tab');
  322. tab.click();
  323. const select = modal.el.querySelector('.select-affiliation');
  324. select.value = 'member';
  325. const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
  326. button.click();
  327. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  328. const user_els = modal.el.querySelectorAll('.list-group--users > li');
  329. expect(user_els.length).toBe(1);
  330. const toggle = user_els[0].querySelector('.list-group-item:nth-child(3n) .toggle-form');
  331. const form = user_els[0].querySelector('.list-group-item:nth-child(3n) .affiliation-form');
  332. expect(u.hasClass('hidden', form)).toBeTruthy();
  333. toggle.click();
  334. expect(u.hasClass('hidden', form)).toBeFalsy();
  335. const change_affiliation_dropdown = form.querySelector('.select-affiliation');
  336. expect(change_affiliation_dropdown.value).toBe('member');
  337. change_affiliation_dropdown.value = 'admin';
  338. const input = form.querySelector('input[name="reason"]');
  339. input.value = "You're an admin now";
  340. const submit = form.querySelector('.btn-primary');
  341. submit.click();
  342. const sent_IQ = _converse.connection.IQ_stanzas.pop();
  343. expect(Strophe.serialize(sent_IQ)).toBe(
  344. `<iq id="${sent_IQ.getAttribute('id')}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
  345. `<query xmlns="http://jabber.org/protocol/muc#admin">`+
  346. `<item affiliation="admin" jid="gower@shakespeare.lit">`+
  347. `<reason>You&apos;re an admin now</reason>`+
  348. `</item>`+
  349. `</query>`+
  350. `</iq>`);
  351. const error = u.toStanza(
  352. `<iq from="${muc_jid}"
  353. id="${sent_IQ.getAttribute('id')}"
  354. type="error"
  355. to="${_converse.jid}">
  356. <error type="cancel">
  357. <not-allowed xmlns="${Strophe.NS.STANZAS}"/>
  358. </error>
  359. </iq>`);
  360. _converse.connection._dataRecv(mock.createRequest(error));
  361. done();
  362. }));
  363. it("doesn't allow admins to make more admins",
  364. mock.initConverse([], {}, async function (done, _converse) {
  365. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  366. const muc_jid = 'lounge@montague.lit';
  367. const members = [
  368. {'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
  369. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  370. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'admin'},
  371. ];
  372. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  373. const view = _converse.chatboxviews.get(muc_jid);
  374. await u.waitUntil(() => (view.model.occupants.length === 3));
  375. const modal = await openModtools(_converse, view);
  376. const tab = modal.el.querySelector('#affiliations-tab');
  377. // Clear so that we don't match older stanzas
  378. _converse.connection.IQ_stanzas = [];
  379. tab.click();
  380. const show_affiliation_dropdown = modal.el.querySelector('.select-affiliation');
  381. show_affiliation_dropdown.value = 'member';
  382. const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
  383. button.click();
  384. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  385. const user_els = modal.el.querySelectorAll('.list-group--users > li');
  386. expect(user_els.length).toBe(2);
  387. let change_affiliation_dropdown = user_els[0].querySelector('.select-affiliation');
  388. expect(Array.from(change_affiliation_dropdown.options).map(o => o.value)).toEqual(['member', 'outcast', 'none']);
  389. change_affiliation_dropdown = user_els[1].querySelector('.select-affiliation');
  390. expect(Array.from(change_affiliation_dropdown.options).map(o => o.value)).toEqual(['member', 'outcast', 'none']);
  391. done();
  392. }));
  393. it("lets the assignable affiliations and roles be configured via modtools_disable_assign",
  394. mock.initConverse([], {}, async function (done, _converse) {
  395. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  396. const muc_jid = 'lounge@montague.lit';
  397. const members = [{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'}];
  398. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  399. const view = _converse.chatboxviews.get(muc_jid);
  400. const textarea = view.querySelector('.chat-textarea');
  401. textarea.value = '/modtools';
  402. const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
  403. view.onKeyDown(enter);
  404. await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
  405. const modal = _converse.api.modal.get('converse-modtools-modal');
  406. const occupant = view.model.occupants.findWhere({'jid': _converse.bare_jid});
  407. expect(modal.getAssignableAffiliations(occupant)).toEqual(['owner', 'admin', 'member', 'outcast', 'none']);
  408. _converse.api.settings.set('modtools_disable_assign', ['owner']);
  409. expect(modal.getAssignableAffiliations(occupant)).toEqual(['admin', 'member', 'outcast', 'none']);
  410. _converse.api.settings.set('modtools_disable_assign', ['owner', 'admin']);
  411. expect(modal.getAssignableAffiliations(occupant)).toEqual(['member', 'outcast', 'none']);
  412. _converse.api.settings.set('modtools_disable_assign', ['owner', 'admin', 'outcast']);
  413. expect(modal.getAssignableAffiliations(occupant)).toEqual(['member', 'none']);
  414. expect(modal.getAssignableRoles(occupant)).toEqual(['moderator', 'participant', 'visitor']);
  415. _converse.api.settings.set('modtools_disable_assign', ['admin', 'moderator']);
  416. expect(modal.getAssignableRoles(occupant)).toEqual(['participant', 'visitor']);
  417. done();
  418. }));
  419. });