peopleBody.js 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328
  1. import { ReactiveCache } from '/imports/reactiveCache';
  2. import LockoutSettings from '/models/lockoutSettings';
  3. const orgsPerPage = 25;
  4. const teamsPerPage = 25;
  5. const usersPerPage = 25;
  6. let userOrgsTeamsAction = ""; //poosible actions 'addOrg', 'addTeam', 'removeOrg' or 'removeTeam' when adding or modifying a user
  7. let selectedUserChkBoxUserIds = [];
  8. BlazeComponent.extendComponent({
  9. mixins() {
  10. return [Mixins.InfiniteScrolling];
  11. },
  12. onCreated() {
  13. this.error = new ReactiveVar('');
  14. this.loading = new ReactiveVar(false);
  15. this.orgSetting = new ReactiveVar(true);
  16. this.teamSetting = new ReactiveVar(false);
  17. this.peopleSetting = new ReactiveVar(false);
  18. this.lockedUsersSetting = new ReactiveVar(false);
  19. this.findOrgsOptions = new ReactiveVar({});
  20. this.findTeamsOptions = new ReactiveVar({});
  21. this.findUsersOptions = new ReactiveVar({});
  22. this.numberOrgs = new ReactiveVar(0);
  23. this.numberTeams = new ReactiveVar(0);
  24. this.numberPeople = new ReactiveVar(0);
  25. this.userFilterType = new ReactiveVar('all');
  26. this.page = new ReactiveVar(1);
  27. this.loadNextPageLocked = false;
  28. this.callFirstWith(null, 'resetNextPeak');
  29. this.autorun(() => {
  30. const limitOrgs = this.page.get() * orgsPerPage;
  31. const limitTeams = this.page.get() * teamsPerPage;
  32. const limitUsers = this.page.get() * usersPerPage;
  33. this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {
  34. this.loadNextPageLocked = false;
  35. const nextPeakBefore = this.callFirstWith(null, 'getNextPeak');
  36. this.calculateNextPeak();
  37. const nextPeakAfter = this.callFirstWith(null, 'getNextPeak');
  38. if (nextPeakBefore === nextPeakAfter) {
  39. this.callFirstWith(null, 'resetNextPeak');
  40. }
  41. });
  42. this.subscribe('team', this.findTeamsOptions.get(), limitTeams, () => {
  43. this.loadNextPageLocked = false;
  44. const nextPeakBefore = this.callFirstWith(null, 'getNextPeak');
  45. this.calculateNextPeak();
  46. const nextPeakAfter = this.callFirstWith(null, 'getNextPeak');
  47. if (nextPeakBefore === nextPeakAfter) {
  48. this.callFirstWith(null, 'resetNextPeak');
  49. }
  50. });
  51. this.subscribe('people', this.findUsersOptions.get(), limitUsers, () => {
  52. this.loadNextPageLocked = false;
  53. const nextPeakBefore = this.callFirstWith(null, 'getNextPeak');
  54. this.calculateNextPeak();
  55. const nextPeakAfter = this.callFirstWith(null, 'getNextPeak');
  56. if (nextPeakBefore === nextPeakAfter) {
  57. this.callFirstWith(null, 'resetNextPeak');
  58. }
  59. });
  60. });
  61. },
  62. events() {
  63. return [
  64. {
  65. 'click #searchOrgButton'() {
  66. this.filterOrg();
  67. },
  68. 'keydown #searchOrgInput'(event) {
  69. if (event.keyCode === 13 && !event.shiftKey) {
  70. this.filterOrg();
  71. }
  72. },
  73. 'click #searchTeamButton'() {
  74. this.filterTeam();
  75. },
  76. 'keydown #searchTeamInput'(event) {
  77. if (event.keyCode === 13 && !event.shiftKey) {
  78. this.filterTeam();
  79. }
  80. },
  81. 'click #searchButton'() {
  82. this.filterPeople();
  83. },
  84. 'click #addOrRemoveTeam'(){
  85. document.getElementById("divAddOrRemoveTeamContainer").style.display = 'block';
  86. },
  87. 'keydown #searchInput'(event) {
  88. if (event.keyCode === 13 && !event.shiftKey) {
  89. this.filterPeople();
  90. }
  91. },
  92. 'change #userFilterSelect'(event) {
  93. const filterType = $(event.target).val();
  94. this.userFilterType.set(filterType);
  95. this.filterPeople();
  96. },
  97. 'click #unlockAllUsers'(event) {
  98. event.preventDefault();
  99. if (confirm(TAPi18n.__('accounts-lockout-confirm-unlock-all'))) {
  100. Meteor.call('unlockAllUsers', (error) => {
  101. if (error) {
  102. console.error('Error unlocking all users:', error);
  103. } else {
  104. // Show a brief success message
  105. const message = document.createElement('div');
  106. message.className = 'unlock-all-success';
  107. message.textContent = TAPi18n.__('accounts-lockout-all-users-unlocked');
  108. document.body.appendChild(message);
  109. // Remove the message after a short delay
  110. setTimeout(() => {
  111. if (message.parentNode) {
  112. message.parentNode.removeChild(message);
  113. }
  114. }, 3000);
  115. }
  116. });
  117. }
  118. },
  119. 'click #newOrgButton'() {
  120. Popup.open('newOrg');
  121. },
  122. 'click #newTeamButton'() {
  123. Popup.open('newTeam');
  124. },
  125. 'click #newUserButton'() {
  126. Popup.open('newUser');
  127. },
  128. 'click a.js-org-menu': this.switchMenu,
  129. 'click a.js-team-menu': this.switchMenu,
  130. 'click a.js-people-menu': this.switchMenu,
  131. 'click a.js-locked-users-menu': this.switchMenu,
  132. },
  133. ];
  134. },
  135. filterPeople() {
  136. const value = $('#searchInput').first().val();
  137. const filterType = this.userFilterType.get();
  138. const currentTime = Number(new Date());
  139. let query = {};
  140. // Apply text search filter if there's a search value
  141. if (value !== '') {
  142. const regex = new RegExp(value, 'i');
  143. query = {
  144. $or: [
  145. { username: regex },
  146. { 'profile.fullname': regex },
  147. { 'emails.address': regex },
  148. ],
  149. };
  150. }
  151. // Apply filter based on selected option
  152. switch (filterType) {
  153. case 'locked':
  154. // Show only locked users
  155. query['services.accounts-lockout.unlockTime'] = { $gt: currentTime };
  156. break;
  157. case 'active':
  158. // Show only active users (loginDisabled is false or undefined)
  159. query['loginDisabled'] = { $ne: true };
  160. break;
  161. case 'inactive':
  162. // Show only inactive users (loginDisabled is true)
  163. query['loginDisabled'] = true;
  164. break;
  165. case 'all':
  166. default:
  167. // Show all users, no additional filter
  168. break;
  169. }
  170. this.findUsersOptions.set(query);
  171. },
  172. loadNextPage() {
  173. if (this.loadNextPageLocked === false) {
  174. this.page.set(this.page.get() + 1);
  175. this.loadNextPageLocked = true;
  176. }
  177. },
  178. calculateNextPeak() {
  179. const element = this.find('.main-body');
  180. if (element) {
  181. const altitude = element.scrollHeight;
  182. this.callFirstWith(this, 'setNextPeak', altitude);
  183. }
  184. },
  185. reachNextPeak() {
  186. this.loadNextPage();
  187. },
  188. setError(error) {
  189. this.error.set(error);
  190. },
  191. setLoading(w) {
  192. this.loading.set(w);
  193. },
  194. orgList() {
  195. const limitOrgs = this.page.get() * orgsPerPage;
  196. const orgs = ReactiveCache.getOrgs(this.findOrgsOptions.get(), {
  197. sort: { orgDisplayName: 1 },
  198. limit: limitOrgs,
  199. fields: { _id: true },
  200. });
  201. // Count only the items currently loaded to browser, not total from database
  202. this.numberOrgs.set(orgs.length);
  203. return orgs;
  204. },
  205. teamList() {
  206. const limitTeams = this.page.get() * teamsPerPage;
  207. const teams = ReactiveCache.getTeams(this.findTeamsOptions.get(), {
  208. sort: { teamDisplayName: 1 },
  209. limit: limitTeams,
  210. fields: { _id: true },
  211. });
  212. // Count only the items currently loaded to browser, not total from database
  213. this.numberTeams.set(teams.length);
  214. return teams;
  215. },
  216. peopleList() {
  217. const limitUsers = this.page.get() * usersPerPage;
  218. const users = ReactiveCache.getUsers(this.findUsersOptions.get(), {
  219. sort: { username: 1 },
  220. limit: limitUsers,
  221. fields: { _id: true },
  222. });
  223. // Count only the items currently loaded to browser, not total from database
  224. this.numberPeople.set(users.length);
  225. return users;
  226. },
  227. orgNumber() {
  228. return this.numberOrgs.get();
  229. },
  230. teamNumber() {
  231. return this.numberTeams.get();
  232. },
  233. peopleNumber() {
  234. return this.numberPeople.get();
  235. },
  236. switchMenu(event) {
  237. const target = $(event.target);
  238. if (!target.hasClass('active')) {
  239. $('.side-menu li.active').removeClass('active');
  240. target.parent().addClass('active');
  241. const targetID = target.data('id');
  242. this.orgSetting.set('org-setting' === targetID);
  243. this.teamSetting.set('team-setting' === targetID);
  244. this.peopleSetting.set('people-setting' === targetID);
  245. this.lockedUsersSetting.set('locked-users-setting' === targetID);
  246. // When switching to locked users tab, refresh the locked users list
  247. if ('locked-users-setting' === targetID) {
  248. // Find the lockedUsersGeneral component and call refreshLockedUsers
  249. const lockedUsersComponent = Blaze.getView($('.main-body')[0])._templateInstance;
  250. if (lockedUsersComponent && lockedUsersComponent.refreshLockedUsers) {
  251. lockedUsersComponent.refreshLockedUsers();
  252. }
  253. }
  254. }
  255. },
  256. }).register('people');
  257. Template.orgRow.helpers({
  258. orgData() {
  259. return ReactiveCache.getOrg(this.orgId);
  260. },
  261. });
  262. Template.teamRow.helpers({
  263. teamData() {
  264. return ReactiveCache.getTeam(this.teamId);
  265. },
  266. });
  267. Template.peopleRow.helpers({
  268. userData() {
  269. return ReactiveCache.getUser(this.userId);
  270. },
  271. isUserLocked() {
  272. const user = ReactiveCache.getUser(this.userId);
  273. if (!user) return false;
  274. // Check if user has accounts-lockout with unlockTime property
  275. if (user.services &&
  276. user.services['accounts-lockout'] &&
  277. user.services['accounts-lockout'].unlockTime) {
  278. // Check if unlockTime is in the future
  279. const currentTime = Number(new Date());
  280. return user.services['accounts-lockout'].unlockTime > currentTime;
  281. }
  282. return false;
  283. }
  284. });
  285. // Initialize filter dropdown
  286. Template.people.rendered = function() {
  287. const template = this;
  288. // Set the initial value of the dropdown
  289. Tracker.afterFlush(function() {
  290. if (template.findAll('#userFilterSelect').length) {
  291. $('#userFilterSelect').val('all');
  292. }
  293. });
  294. };
  295. Template.editUserPopup.onCreated(function () {
  296. this.authenticationMethods = new ReactiveVar([]);
  297. this.errorMessage = new ReactiveVar('');
  298. Meteor.call('getAuthenticationsEnabled', (_, result) => {
  299. if (result) {
  300. // TODO : add a management of different languages
  301. // (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')})
  302. this.authenticationMethods.set([
  303. { value: 'password' },
  304. // Gets only the authentication methods availables
  305. ...Object.entries(result)
  306. .filter((e) => e[1])
  307. .map((e) => ({ value: e[0] })),
  308. ]);
  309. }
  310. });
  311. });
  312. Template.editOrgPopup.helpers({
  313. org() {
  314. return ReactiveCache.getOrg(this.orgId);
  315. },
  316. errorMessage() {
  317. return Template.instance().errorMessage.get();
  318. },
  319. });
  320. Template.editTeamPopup.helpers({
  321. team() {
  322. return ReactiveCache.getTeam(this.teamId);
  323. },
  324. errorMessage() {
  325. return Template.instance().errorMessage.get();
  326. },
  327. });
  328. Template.editUserPopup.helpers({
  329. user() {
  330. return ReactiveCache.getUser(this.userId);
  331. },
  332. authentications() {
  333. return Template.instance().authenticationMethods.get();
  334. },
  335. orgsDatas() {
  336. const ret = ReactiveCache.getOrgs({}, {sort: { orgDisplayName: 1 }});
  337. return ret;
  338. },
  339. teamsDatas() {
  340. const ret = ReactiveCache.getTeams({}, {sort: { teamDisplayName: 1 }});
  341. return ret;
  342. },
  343. isSelected(match) {
  344. const userId = Template.instance().data.userId;
  345. const selected = ReactiveCache.getUser(userId).authenticationMethod;
  346. return selected === match;
  347. },
  348. isLdap() {
  349. const userId = Template.instance().data.userId;
  350. const selected = ReactiveCache.getUser(userId).authenticationMethod;
  351. return selected === 'ldap';
  352. },
  353. errorMessage() {
  354. return Template.instance().errorMessage.get();
  355. },
  356. });
  357. Template.newOrgPopup.onCreated(function () {
  358. this.errorMessage = new ReactiveVar('');
  359. });
  360. Template.newTeamPopup.onCreated(function () {
  361. this.errorMessage = new ReactiveVar('');
  362. });
  363. Template.newUserPopup.onCreated(function () {
  364. this.authenticationMethods = new ReactiveVar([]);
  365. this.errorMessage = new ReactiveVar('');
  366. Meteor.call('getAuthenticationsEnabled', (_, result) => {
  367. if (result) {
  368. // TODO : add a management of different languages
  369. // (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')})
  370. this.authenticationMethods.set([
  371. { value: 'password' },
  372. // Gets only the authentication methods availables
  373. ...Object.entries(result)
  374. .filter((e) => e[1])
  375. .map((e) => ({ value: e[0] })),
  376. ]);
  377. }
  378. });
  379. });
  380. Template.newOrgPopup.helpers({
  381. org() {
  382. return ReactiveCache.getOrg(this.orgId);
  383. },
  384. errorMessage() {
  385. return Template.instance().errorMessage.get();
  386. },
  387. });
  388. Template.newTeamPopup.helpers({
  389. team() {
  390. return ReactiveCache.getTeam(this.teamId);
  391. },
  392. errorMessage() {
  393. return Template.instance().errorMessage.get();
  394. },
  395. });
  396. Template.newUserPopup.helpers({
  397. user() {
  398. return ReactiveCache.getUser(this.userId);
  399. },
  400. authentications() {
  401. return Template.instance().authenticationMethods.get();
  402. },
  403. orgsDatas() {
  404. const ret = ReactiveCache.getOrgs({}, {sort: { orgDisplayName: 1 }});
  405. return ret;
  406. },
  407. teamsDatas() {
  408. const ret = ReactiveCache.getTeams({}, {sort: { teamDisplayName: 1 }});
  409. return ret;
  410. },
  411. isSelected(match) {
  412. const userId = Template.instance().data.userId;
  413. if(userId){
  414. const selected = ReactiveCache.getUser(userId).authenticationMethod;
  415. return selected === match;
  416. }
  417. else{
  418. false;
  419. }
  420. },
  421. isLdap() {
  422. const userId = Template.instance().data.userId;
  423. const selected = ReactiveCache.getUser(userId).authenticationMethod;
  424. return selected === 'ldap';
  425. },
  426. errorMessage() {
  427. return Template.instance().errorMessage.get();
  428. },
  429. });
  430. BlazeComponent.extendComponent({
  431. onCreated() {},
  432. org() {
  433. return ReactiveCache.getOrg(this.orgId);
  434. },
  435. events() {
  436. return [
  437. {
  438. 'click a.edit-org': Popup.open('editOrg'),
  439. 'click a.more-settings-org': Popup.open('settingsOrg'),
  440. },
  441. ];
  442. },
  443. }).register('orgRow');
  444. BlazeComponent.extendComponent({
  445. onCreated() {},
  446. team() {
  447. return ReactiveCache.getTeam(this.teamId);
  448. },
  449. events() {
  450. return [
  451. {
  452. 'click a.edit-team': Popup.open('editTeam'),
  453. 'click a.more-settings-team': Popup.open('settingsTeam'),
  454. },
  455. ];
  456. },
  457. }).register('teamRow');
  458. BlazeComponent.extendComponent({
  459. onCreated() {},
  460. user() {
  461. return ReactiveCache.getUser(this.userId);
  462. },
  463. events() {
  464. return [
  465. {
  466. 'click a.edit-user': Popup.open('editUser'),
  467. 'click a.more-settings-user': Popup.open('settingsUser'),
  468. 'click .selectUserChkBox': function(ev){
  469. if(ev.currentTarget){
  470. if(ev.currentTarget.checked){
  471. if(!selectedUserChkBoxUserIds.includes(ev.currentTarget.id)){
  472. selectedUserChkBoxUserIds.push(ev.currentTarget.id);
  473. }
  474. }
  475. else{
  476. if(selectedUserChkBoxUserIds.includes(ev.currentTarget.id)){
  477. let index = selectedUserChkBoxUserIds.indexOf(ev.currentTarget.id);
  478. if(index > -1)
  479. selectedUserChkBoxUserIds.splice(index, 1);
  480. }
  481. }
  482. }
  483. if(selectedUserChkBoxUserIds.length > 0)
  484. document.getElementById("divAddOrRemoveTeam").style.display = 'block';
  485. else
  486. document.getElementById("divAddOrRemoveTeam").style.display = 'none';
  487. },
  488. 'click .js-toggle-active-status': function(ev) {
  489. ev.preventDefault();
  490. const userId = this.userId;
  491. const user = ReactiveCache.getUser(userId);
  492. if (!user) return;
  493. // Toggle loginDisabled status
  494. const isActive = !(user.loginDisabled === true);
  495. // Update the user's active status
  496. Users.update(userId, {
  497. $set: {
  498. loginDisabled: isActive
  499. }
  500. });
  501. },
  502. 'click .js-toggle-lock-status': function(ev){
  503. ev.preventDefault();
  504. const userId = this.userId;
  505. const user = ReactiveCache.getUser(userId);
  506. if (!user) return;
  507. // Check if user is currently locked
  508. const isLocked = user.services &&
  509. user.services['accounts-lockout'] &&
  510. user.services['accounts-lockout'].unlockTime &&
  511. user.services['accounts-lockout'].unlockTime > Number(new Date());
  512. if (isLocked) {
  513. // Unlock the user
  514. Meteor.call('unlockUser', userId, (error) => {
  515. if (error) {
  516. console.error('Error unlocking user:', error);
  517. }
  518. });
  519. } else {
  520. // Lock the user - this is optional, you may want to only allow unlocking
  521. // If you want to implement locking too, you would need a server method for it
  522. // For now, we'll leave this as a no-op
  523. }
  524. },
  525. },
  526. ];
  527. },
  528. }).register('peopleRow');
  529. BlazeComponent.extendComponent({
  530. onCreated() {},
  531. teamsDatas() {
  532. const ret = ReactiveCache.getTeams({}, {sort: { teamDisplayName: 1 }});
  533. return ret;
  534. },
  535. events() {
  536. return [
  537. {
  538. 'click #cancelBtn': function(){
  539. let selectedElt = document.getElementById("jsteamsUser");
  540. document.getElementById("divAddOrRemoveTeamContainer").style.display = 'none';
  541. },
  542. 'click #addTeamBtn': function(){
  543. let selectedElt;
  544. let selectedEltValue;
  545. let selectedEltValueId;
  546. let userTms = [];
  547. let currentUser;
  548. let currUserTeamIndex;
  549. selectedElt = document.getElementById("jsteamsUser");
  550. selectedEltValue = selectedElt.options[selectedElt.selectedIndex].text;
  551. selectedEltValueId = selectedElt.options[selectedElt.selectedIndex].value;
  552. if(document.getElementById('addAction').checked){
  553. for(let i = 0; i < selectedUserChkBoxUserIds.length; i++){
  554. currentUser = ReactiveCache.getUser(selectedUserChkBoxUserIds[i]);
  555. userTms = currentUser.teams;
  556. if(userTms == undefined || userTms.length == 0){
  557. userTms = [];
  558. userTms.push({
  559. "teamId": selectedEltValueId,
  560. "teamDisplayName": selectedEltValue,
  561. })
  562. }
  563. else if(userTms.length > 0)
  564. {
  565. currUserTeamIndex = userTms.findIndex(function(t){ return t.teamId == selectedEltValueId});
  566. if(currUserTeamIndex == -1){
  567. userTms.push({
  568. "teamId": selectedEltValueId,
  569. "teamDisplayName": selectedEltValue,
  570. });
  571. }
  572. }
  573. Users.update(selectedUserChkBoxUserIds[i], {
  574. $set:{
  575. teams: userTms
  576. }
  577. });
  578. }
  579. }
  580. else{
  581. for(let i = 0; i < selectedUserChkBoxUserIds.length; i++){
  582. currentUser = ReactiveCache.getUser(selectedUserChkBoxUserIds[i]);
  583. userTms = currentUser.teams;
  584. if(userTms !== undefined || userTms.length > 0)
  585. {
  586. currUserTeamIndex = userTms.findIndex(function(t){ return t.teamId == selectedEltValueId});
  587. if(currUserTeamIndex != -1){
  588. userTms.splice(currUserTeamIndex, 1);
  589. }
  590. }
  591. Users.update(selectedUserChkBoxUserIds[i], {
  592. $set:{
  593. teams: userTms
  594. }
  595. });
  596. }
  597. }
  598. document.getElementById("divAddOrRemoveTeamContainer").style.display = 'none';
  599. },
  600. },
  601. ];
  602. },
  603. }).register('modifyTeamsUsers');
  604. BlazeComponent.extendComponent({
  605. events() {
  606. return [
  607. {
  608. 'click a.new-org': Popup.open('newOrg'),
  609. },
  610. ];
  611. },
  612. }).register('newOrgRow');
  613. BlazeComponent.extendComponent({
  614. events() {
  615. return [
  616. {
  617. 'click a.new-team': Popup.open('newTeam'),
  618. },
  619. ];
  620. },
  621. }).register('newTeamRow');
  622. BlazeComponent.extendComponent({
  623. events() {
  624. return [
  625. {
  626. 'click a.new-user': Popup.open('newUser'),
  627. },
  628. ];
  629. },
  630. }).register('newUserRow');
  631. BlazeComponent.extendComponent({
  632. events() {
  633. return [
  634. {
  635. 'click .allUserChkBox': function(ev){
  636. selectedUserChkBoxUserIds = [];
  637. const checkboxes = document.getElementsByClassName("selectUserChkBox");
  638. if(ev.currentTarget){
  639. if(ev.currentTarget.checked){
  640. for (let i=0; i<checkboxes.length; i++) {
  641. if (!checkboxes[i].disabled) {
  642. selectedUserChkBoxUserIds.push(checkboxes[i].id);
  643. checkboxes[i].checked = true;
  644. }
  645. }
  646. }
  647. else{
  648. for (let i=0; i<checkboxes.length; i++) {
  649. if (!checkboxes[i].disabled) {
  650. checkboxes[i].checked = false;
  651. }
  652. }
  653. }
  654. }
  655. if(selectedUserChkBoxUserIds.length > 0)
  656. document.getElementById("divAddOrRemoveTeam").style.display = 'block';
  657. else
  658. document.getElementById("divAddOrRemoveTeam").style.display = 'none';
  659. },
  660. },
  661. ];
  662. },
  663. }).register('selectAllUser');
  664. Template.editOrgPopup.events({
  665. submit(event, templateInstance) {
  666. event.preventDefault();
  667. const org = ReactiveCache.getOrg(this.orgId);
  668. const orgDisplayName = templateInstance
  669. .find('.js-orgDisplayName')
  670. .value.trim();
  671. const orgDesc = templateInstance.find('.js-orgDesc').value.trim();
  672. const orgShortName = templateInstance.find('.js-orgShortName').value.trim();
  673. const orgAutoAddUsersWithDomainName = templateInstance.find('.js-orgAutoAddUsersWithDomainName').value.trim();
  674. const orgWebsite = templateInstance.find('.js-orgWebsite').value.trim();
  675. const orgIsActive = templateInstance.find('.js-org-isactive').value.trim() == 'true';
  676. const isChangeOrgDisplayName = orgDisplayName !== org.orgDisplayName;
  677. const isChangeOrgDesc = orgDesc !== org.orgDesc;
  678. const isChangeOrgShortName = orgShortName !== org.orgShortName;
  679. const isChangeOrgAutoAddUsersWithDomainName = orgAutoAddUsersWithDomainName !== org.orgAutoAddUsersWithDomainName;
  680. const isChangeOrgWebsite = orgWebsite !== org.orgWebsite;
  681. const isChangeOrgIsActive = orgIsActive !== org.orgIsActive;
  682. if (
  683. isChangeOrgDisplayName ||
  684. isChangeOrgDesc ||
  685. isChangeOrgShortName ||
  686. isChangeOrgAutoAddUsersWithDomainName ||
  687. isChangeOrgWebsite ||
  688. isChangeOrgIsActive
  689. ) {
  690. Meteor.call(
  691. 'setOrgAllFields',
  692. org,
  693. orgDisplayName,
  694. orgDesc,
  695. orgShortName,
  696. orgAutoAddUsersWithDomainName,
  697. orgWebsite,
  698. orgIsActive,
  699. );
  700. }
  701. Popup.back();
  702. },
  703. });
  704. Template.editTeamPopup.events({
  705. submit(event, templateInstance) {
  706. event.preventDefault();
  707. const team = ReactiveCache.getTeam(this.teamId);
  708. const teamDisplayName = templateInstance
  709. .find('.js-teamDisplayName')
  710. .value.trim();
  711. const teamDesc = templateInstance.find('.js-teamDesc').value.trim();
  712. const teamShortName = templateInstance
  713. .find('.js-teamShortName')
  714. .value.trim();
  715. const teamWebsite = templateInstance.find('.js-teamWebsite').value.trim();
  716. const teamIsActive =
  717. templateInstance.find('.js-team-isactive').value.trim() == 'true';
  718. const isChangeTeamDisplayName = teamDisplayName !== team.teamDisplayName;
  719. const isChangeTeamDesc = teamDesc !== team.teamDesc;
  720. const isChangeTeamShortName = teamShortName !== team.teamShortName;
  721. const isChangeTeamWebsite = teamWebsite !== team.teamWebsite;
  722. const isChangeTeamIsActive = teamIsActive !== team.teamIsActive;
  723. if (
  724. isChangeTeamDisplayName ||
  725. isChangeTeamDesc ||
  726. isChangeTeamShortName ||
  727. isChangeTeamWebsite ||
  728. isChangeTeamIsActive
  729. ) {
  730. Meteor.call(
  731. 'setTeamAllFields',
  732. team,
  733. teamDisplayName,
  734. teamDesc,
  735. teamShortName,
  736. teamWebsite,
  737. teamIsActive,
  738. );
  739. }
  740. Popup.back();
  741. },
  742. });
  743. Template.editUserPopup.events({
  744. submit(event, templateInstance) {
  745. event.preventDefault();
  746. const user = ReactiveCache.getUser(this.userId);
  747. const username = templateInstance.find('.js-profile-username').value.trim();
  748. const fullname = templateInstance.find('.js-profile-fullname').value.trim();
  749. const initials = templateInstance.find('.js-profile-initials').value.trim();
  750. const password = templateInstance.find('.js-profile-password').value;
  751. const isAdmin = templateInstance.find('.js-profile-isadmin').value.trim();
  752. const isActive = templateInstance.find('.js-profile-isactive').value.trim();
  753. const email = templateInstance.find('.js-profile-email').value.trim();
  754. const verified = templateInstance.find('.js-profile-email-verified').value.trim();
  755. const authentication = templateInstance.find('.js-authenticationMethod').value.trim();
  756. const importUsernames = templateInstance.find('.js-import-usernames').value.trim();
  757. const userOrgs = templateInstance.find('.js-userOrgs').value.trim();
  758. const userOrgsIds = templateInstance.find('.js-userOrgIds').value.trim();
  759. const userTeams = templateInstance.find('.js-userteams').value.trim();
  760. const userTeamsIds = templateInstance.find('.js-userteamIds').value.trim();
  761. const isChangePassword = password.length > 0;
  762. const isChangeUserName = username !== user.username;
  763. const isChangeInitials = initials.length > 0;
  764. const isChangeEmailVerified = verified !== user.emails[0].verified;
  765. // If previously email address has not been set, it is undefined,
  766. // check for undefined, and allow adding email address.
  767. const isChangeEmail =
  768. email.toLowerCase() !==
  769. (typeof user.emails !== 'undefined'
  770. ? user.emails[0].address.toLowerCase()
  771. : false);
  772. Users.update(this.userId, {
  773. $set: {
  774. 'profile.fullname': fullname,
  775. isAdmin: isAdmin === 'true',
  776. loginDisabled: isActive === 'true',
  777. authenticationMethod: authentication,
  778. importUsernames: Users.parseImportUsernames(importUsernames),
  779. },
  780. });
  781. let userTeamsList = userTeams.split(",");
  782. let userTeamsIdsList = userTeamsIds.split(",");
  783. let userTms = [];
  784. if(userTeams != ''){
  785. for(let i = 0; i < userTeamsList.length; i++){
  786. userTms.push({
  787. "teamId": userTeamsIdsList[i],
  788. "teamDisplayName": userTeamsList[i],
  789. })
  790. }
  791. }
  792. Users.update(this.userId, {
  793. $set:{
  794. teams: userTms
  795. }
  796. });
  797. let userOrgsList = userOrgs.split(",");
  798. let userOrgsIdsList = userOrgsIds.split(",");
  799. let userOrganizations = [];
  800. if(userOrgs != ''){
  801. for(let i = 0; i < userOrgsList.length; i++){
  802. userOrganizations.push({
  803. "orgId": userOrgsIdsList[i],
  804. "orgDisplayName": userOrgsList[i],
  805. })
  806. }
  807. }
  808. Users.update(this.userId, {
  809. $set:{
  810. orgs: userOrganizations
  811. }
  812. });
  813. if (isChangePassword) {
  814. Meteor.call('setPassword', password, this.userId);
  815. }
  816. if (isChangeEmailVerified) {
  817. Meteor.call('setEmailVerified', email, verified === 'true', this.userId);
  818. }
  819. if (isChangeInitials) {
  820. Meteor.call('setInitials', initials, this.userId);
  821. }
  822. if (isChangeUserName && isChangeEmail) {
  823. Meteor.call(
  824. 'setUsernameAndEmail',
  825. username,
  826. email.toLowerCase(),
  827. this.userId,
  828. function (error) {
  829. const usernameMessageElement = templateInstance.$('.username-taken');
  830. const emailMessageElement = templateInstance.$('.email-taken');
  831. if (error) {
  832. const errorElement = error.error;
  833. if (errorElement === 'username-already-taken') {
  834. usernameMessageElement.show();
  835. emailMessageElement.hide();
  836. } else if (errorElement === 'email-already-taken') {
  837. usernameMessageElement.hide();
  838. emailMessageElement.show();
  839. }
  840. } else {
  841. usernameMessageElement.hide();
  842. emailMessageElement.hide();
  843. Popup.back();
  844. }
  845. },
  846. );
  847. } else if (isChangeUserName) {
  848. Meteor.call('setUsername', username, this.userId, function (error) {
  849. const usernameMessageElement = templateInstance.$('.username-taken');
  850. if (error) {
  851. const errorElement = error.error;
  852. if (errorElement === 'username-already-taken') {
  853. usernameMessageElement.show();
  854. }
  855. } else {
  856. usernameMessageElement.hide();
  857. Popup.back();
  858. }
  859. });
  860. } else if (isChangeEmail) {
  861. Meteor.call(
  862. 'setEmail',
  863. email.toLowerCase(),
  864. this.userId,
  865. function (error) {
  866. const emailMessageElement = templateInstance.$('.email-taken');
  867. if (error) {
  868. const errorElement = error.error;
  869. if (errorElement === 'email-already-taken') {
  870. emailMessageElement.show();
  871. }
  872. } else {
  873. emailMessageElement.hide();
  874. Popup.back();
  875. }
  876. },
  877. );
  878. } else Popup.back();
  879. },
  880. 'click #addUserOrg'(event) {
  881. event.preventDefault();
  882. userOrgsTeamsAction = "addOrg";
  883. document.getElementById("jsOrgs").style.display = 'block';
  884. document.getElementById("jsTeams").style.display = 'none';
  885. },
  886. 'click #removeUserOrg'(event) {
  887. event.preventDefault();
  888. userOrgsTeamsAction = "removeOrg";
  889. document.getElementById("jsOrgs").style.display = 'block';
  890. document.getElementById("jsTeams").style.display = 'none';
  891. },
  892. 'click #addUserTeam'(event) {
  893. event.preventDefault();
  894. userOrgsTeamsAction = "addTeam";
  895. document.getElementById("jsTeams").style.display = 'block';
  896. document.getElementById("jsOrgs").style.display = 'none';
  897. },
  898. 'click #removeUserTeam'(event) {
  899. event.preventDefault();
  900. userOrgsTeamsAction = "removeTeam";
  901. document.getElementById("jsTeams").style.display = 'block';
  902. document.getElementById("jsOrgs").style.display = 'none';
  903. },
  904. 'change #jsOrgs'(event) {
  905. event.preventDefault();
  906. UpdateUserOrgsOrTeamsElement();
  907. },
  908. 'change #jsTeams'(event) {
  909. event.preventDefault();
  910. UpdateUserOrgsOrTeamsElement();
  911. },
  912. });
  913. UpdateUserOrgsOrTeamsElement = function(isNewUser = false){
  914. let selectedElt;
  915. let selectedEltValue;
  916. let selectedEltValueId;
  917. let inputElt;
  918. let inputEltId;
  919. let lstInputValues = [];
  920. let lstInputValuesIds = [];
  921. let index;
  922. let indexId;
  923. switch(userOrgsTeamsAction)
  924. {
  925. case "addOrg":
  926. case "removeOrg":
  927. inputElt = !isNewUser ? document.getElementById("jsUserOrgsInPut") : document.getElementById("jsUserOrgsInPutNewUser");
  928. inputEltId = !isNewUser ? document.getElementById("jsUserOrgIdsInPut") : document.getElementById("jsUserOrgIdsInPutNewUser");
  929. selectedElt = !isNewUser ? document.getElementById("jsOrgs") : document.getElementById("jsOrgsNewUser");
  930. break;
  931. case "addTeam":
  932. case "removeTeam":
  933. inputElt = !isNewUser ? document.getElementById("jsUserTeamsInPut") : document.getElementById("jsUserTeamsInPutNewUser");
  934. inputEltId = !isNewUser ? document.getElementById("jsUserTeamIdsInPut") : document.getElementById("jsUserTeamIdsInPutNewUser");
  935. selectedElt = !isNewUser ? document.getElementById("jsTeams") : document.getElementById("jsTeamsNewUser");
  936. break;
  937. default:
  938. break;
  939. }
  940. selectedEltValue = selectedElt.options[selectedElt.selectedIndex].text;
  941. selectedEltValueId = selectedElt.options[selectedElt.selectedIndex].value;
  942. lstInputValues = inputElt.value.trim().split(",");
  943. if(lstInputValues.length == 1 && lstInputValues[0] == ''){
  944. lstInputValues = [];
  945. }
  946. lstInputValuesIds = inputEltId.value.trim().split(",");
  947. if(lstInputValuesIds.length == 1 && lstInputValuesIds[0] == ''){
  948. lstInputValuesIds = [];
  949. }
  950. index = lstInputValues.indexOf(selectedEltValue);
  951. indexId = lstInputValuesIds.indexOf(selectedEltValueId);
  952. if(userOrgsTeamsAction == "addOrg" || userOrgsTeamsAction == "addTeam"){
  953. if(index <= -1 && selectedEltValueId != "-1"){
  954. lstInputValues.push(selectedEltValue);
  955. }
  956. if(indexId <= -1 && selectedEltValueId != "-1"){
  957. lstInputValuesIds.push(selectedEltValueId);
  958. }
  959. }
  960. else{
  961. if(index > -1 && selectedEltValueId != "-1"){
  962. lstInputValues.splice(index, 1);
  963. }
  964. if(indexId > -1 && selectedEltValueId != "-1"){
  965. lstInputValuesIds.splice(indexId, 1);
  966. }
  967. }
  968. if(lstInputValues.length > 0){
  969. inputElt.value = lstInputValues.join(",");
  970. }
  971. else{
  972. inputElt.value = "";
  973. }
  974. if(lstInputValuesIds.length > 0){
  975. inputEltId.value = lstInputValuesIds.join(",");
  976. }
  977. else{
  978. inputEltId.value = "";
  979. }
  980. selectedElt.value = "-1";
  981. selectedElt.style.display = "none";
  982. }
  983. Template.newOrgPopup.events({
  984. submit(event, templateInstance) {
  985. event.preventDefault();
  986. const orgDisplayName = templateInstance
  987. .find('.js-orgDisplayName')
  988. .value.trim();
  989. const orgDesc = templateInstance.find('.js-orgDesc').value.trim();
  990. const orgShortName = templateInstance.find('.js-orgShortName').value.trim();
  991. const orgAutoAddUsersWithDomainName = templateInstance.find('.js-orgAutoAddUsersWithDomainName').value.trim();
  992. const orgWebsite = templateInstance.find('.js-orgWebsite').value.trim();
  993. const orgIsActive =
  994. templateInstance.find('.js-org-isactive').value.trim() == 'true';
  995. Meteor.call(
  996. 'setCreateOrg',
  997. orgDisplayName,
  998. orgDesc,
  999. orgShortName,
  1000. orgAutoAddUsersWithDomainName,
  1001. orgWebsite,
  1002. orgIsActive,
  1003. );
  1004. Popup.back();
  1005. },
  1006. });
  1007. Template.newTeamPopup.events({
  1008. submit(event, templateInstance) {
  1009. event.preventDefault();
  1010. const teamDisplayName = templateInstance
  1011. .find('.js-teamDisplayName')
  1012. .value.trim();
  1013. const teamDesc = templateInstance.find('.js-teamDesc').value.trim();
  1014. const teamShortName = templateInstance
  1015. .find('.js-teamShortName')
  1016. .value.trim();
  1017. const teamWebsite = templateInstance.find('.js-teamWebsite').value.trim();
  1018. const teamIsActive =
  1019. templateInstance.find('.js-team-isactive').value.trim() == 'true';
  1020. Meteor.call(
  1021. 'setCreateTeam',
  1022. teamDisplayName,
  1023. teamDesc,
  1024. teamShortName,
  1025. teamWebsite,
  1026. teamIsActive,
  1027. );
  1028. Popup.back();
  1029. },
  1030. });
  1031. Template.newUserPopup.events({
  1032. submit(event, templateInstance) {
  1033. event.preventDefault();
  1034. const fullname = templateInstance.find('.js-profile-fullname').value.trim();
  1035. const username = templateInstance.find('.js-profile-username').value.trim();
  1036. const initials = templateInstance.find('.js-profile-initials').value.trim();
  1037. const password = templateInstance.find('.js-profile-password').value;
  1038. const isAdmin = templateInstance.find('.js-profile-isadmin').value.trim();
  1039. const isActive = templateInstance.find('.js-profile-isactive').value.trim();
  1040. const email = templateInstance.find('.js-profile-email').value.trim();
  1041. const importUsernames = Users.parseImportUsernames(
  1042. templateInstance.find('.js-import-usernames').value,
  1043. );
  1044. const userOrgs = templateInstance.find('.js-userOrgsNewUser').value.trim();
  1045. const userOrgsIds = templateInstance.find('.js-userOrgIdsNewUser').value.trim();
  1046. const userTeams = templateInstance.find('.js-userteamsNewUser').value.trim();
  1047. const userTeamsIds = templateInstance.find('.js-userteamIdsNewUser').value.trim();
  1048. let userTeamsList = userTeams.split(",");
  1049. let userTeamsIdsList = userTeamsIds.split(",");
  1050. let userTms = [];
  1051. for(let i = 0; i < userTeamsList.length; i++){
  1052. if(!!userTeamsIdsList[i] && !!userTeamsList[i]) {
  1053. userTms.push({
  1054. "teamId": userTeamsIdsList[i],
  1055. "teamDisplayName": userTeamsList[i],
  1056. })
  1057. }
  1058. }
  1059. let userOrgsList = userOrgs.split(",");
  1060. let userOrgsIdsList = userOrgsIds.split(",");
  1061. let userOrganizations = [];
  1062. for(let i = 0; i < userOrgsList.length; i++){
  1063. if(!!userOrgsIdsList[i] && !!userOrgsList[i]) {
  1064. userOrganizations.push({
  1065. "orgId": userOrgsIdsList[i],
  1066. "orgDisplayName": userOrgsList[i],
  1067. })
  1068. }
  1069. }
  1070. Meteor.call(
  1071. 'setCreateUser',
  1072. fullname,
  1073. username,
  1074. initials,
  1075. password,
  1076. isAdmin,
  1077. isActive,
  1078. email.toLowerCase(),
  1079. importUsernames,
  1080. userOrganizations,
  1081. userTms,
  1082. function(error) {
  1083. const usernameMessageElement = templateInstance.$('.username-taken');
  1084. const emailMessageElement = templateInstance.$('.email-taken');
  1085. if (error) {
  1086. const errorElement = error.error;
  1087. if (errorElement === 'username-already-taken') {
  1088. usernameMessageElement.show();
  1089. emailMessageElement.hide();
  1090. } else if (errorElement === 'email-already-taken') {
  1091. usernameMessageElement.hide();
  1092. emailMessageElement.show();
  1093. }
  1094. } else {
  1095. usernameMessageElement.hide();
  1096. emailMessageElement.hide();
  1097. Popup.back();
  1098. }
  1099. },
  1100. );
  1101. Popup.back();
  1102. },
  1103. 'click #addUserOrgNewUser'(event) {
  1104. event.preventDefault();
  1105. userOrgsTeamsAction = "addOrg";
  1106. document.getElementById("jsOrgsNewUser").style.display = 'block';
  1107. document.getElementById("jsTeamsNewUser").style.display = 'none';
  1108. },
  1109. 'click #removeUserOrgNewUser'(event) {
  1110. event.preventDefault();
  1111. userOrgsTeamsAction = "removeOrg";
  1112. document.getElementById("jsOrgsNewUser").style.display = 'block';
  1113. document.getElementById("jsTeamsNewUser").style.display = 'none';
  1114. },
  1115. 'click #addUserTeamNewUser'(event) {
  1116. event.preventDefault();
  1117. userOrgsTeamsAction = "addTeam";
  1118. document.getElementById("jsTeamsNewUser").style.display = 'block';
  1119. document.getElementById("jsOrgsNewUser").style.display = 'none';
  1120. },
  1121. 'click #removeUserTeamNewUser'(event) {
  1122. event.preventDefault();
  1123. userOrgsTeamsAction = "removeTeam";
  1124. document.getElementById("jsTeamsNewUser").style.display = 'block';
  1125. document.getElementById("jsOrgsNewUser").style.display = 'none';
  1126. },
  1127. 'change #jsOrgsNewUser'(event) {
  1128. event.preventDefault();
  1129. UpdateUserOrgsOrTeamsElement(true);
  1130. },
  1131. 'change #jsTeamsNewUser'(event) {
  1132. event.preventDefault();
  1133. UpdateUserOrgsOrTeamsElement(true);
  1134. },
  1135. });
  1136. Template.settingsOrgPopup.events({
  1137. 'click #deleteButton'(event) {
  1138. event.preventDefault();
  1139. if (ReactiveCache.getUsers({"orgs.orgId": this.orgId}).length > 0)
  1140. {
  1141. let orgClassList = document.getElementById("deleteOrgWarningMessage").classList;
  1142. if(orgClassList.contains('hide'))
  1143. {
  1144. orgClassList.remove('hide');
  1145. document.getElementById("deleteOrgWarningMessage").style.color = "red";
  1146. }
  1147. return;
  1148. }
  1149. Org.remove(this.orgId);
  1150. Popup.back();
  1151. }
  1152. });
  1153. Template.settingsTeamPopup.events({
  1154. 'click #deleteButton'(event) {
  1155. event.preventDefault();
  1156. if (ReactiveCache.getUsers({"teams.teamId": this.teamId}).length > 0)
  1157. {
  1158. let teamClassList = document.getElementById("deleteTeamWarningMessage").classList;
  1159. if(teamClassList.contains('hide'))
  1160. {
  1161. teamClassList.remove('hide');
  1162. document.getElementById("deleteTeamWarningMessage").style.color = "red";
  1163. }
  1164. return;
  1165. }
  1166. Team.remove(this.teamId);
  1167. Popup.back();
  1168. }
  1169. });
  1170. Template.settingsUserPopup.events({
  1171. 'click .impersonate-user'(event) {
  1172. event.preventDefault();
  1173. Meteor.call('impersonate', this.userId, (err) => {
  1174. if (!err) {
  1175. FlowRouter.go('/');
  1176. Meteor.connection.setUserId(this.userId);
  1177. }
  1178. });
  1179. },
  1180. 'click #deleteButton'(event) {
  1181. event.preventDefault();
  1182. // Use secure server method instead of direct client-side removal
  1183. Meteor.call('removeUser', this.userId, (error, result) => {
  1184. if (error) {
  1185. if (process.env.DEBUG === 'true') {
  1186. console.error('Error removing user:', error);
  1187. }
  1188. // Show error message to user
  1189. if (error.error === 'not-authorized') {
  1190. alert('You are not authorized to delete this user.');
  1191. } else if (error.error === 'user-not-found') {
  1192. alert('User not found.');
  1193. } else if (error.error === 'not-authorized' && error.reason === 'Cannot delete the last administrator') {
  1194. alert('Cannot delete the last administrator.');
  1195. } else {
  1196. alert('Error deleting user: ' + error.reason);
  1197. }
  1198. } else {
  1199. if (process.env.DEBUG === 'true') {
  1200. console.log('User deleted successfully:', result);
  1201. }
  1202. Popup.back();
  1203. }
  1204. });
  1205. },
  1206. });
  1207. Template.settingsUserPopup.helpers({
  1208. user() {
  1209. return ReactiveCache.getUser(this.userId);
  1210. },
  1211. authentications() {
  1212. return Template.instance().authenticationMethods.get();
  1213. },
  1214. isSelected(match) {
  1215. const userId = Template.instance().data.userId;
  1216. const selected = ReactiveCache.getUser(userId).authenticationMethod;
  1217. return selected === match;
  1218. },
  1219. isLdap() {
  1220. const userId = Template.instance().data.userId;
  1221. const selected = ReactiveCache.getUser(userId).authenticationMethod;
  1222. return selected === 'ldap';
  1223. },
  1224. errorMessage() {
  1225. return Template.instance().errorMessage.get();
  1226. },
  1227. });