admin_users.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. "use strict";
  2. /* eslint-env es2017, browser, jquery */
  3. /* global _post:readable, BASE_URL:readable, reload:readable, jdenticon:readable */
  4. function deleteUser(event) {
  5. event.preventDefault();
  6. event.stopPropagation();
  7. const id = event.target.parentNode.dataset.vwUserUuid;
  8. const email = event.target.parentNode.dataset.vwUserEmail;
  9. if (!id || !email) {
  10. alert("Required parameters not found!");
  11. return false;
  12. }
  13. const input_email = prompt(`To delete user "${email}", please type the email below`);
  14. if (input_email != null) {
  15. if (input_email == email) {
  16. _post(`${BASE_URL}/admin/users/${id}/delete`,
  17. "User deleted correctly",
  18. "Error deleting user"
  19. );
  20. } else {
  21. alert("Wrong email, please try again");
  22. }
  23. }
  24. }
  25. function deleteSSOUser(event) {
  26. event.preventDefault();
  27. event.stopPropagation();
  28. const id = event.target.parentNode.dataset.vwUserUuid;
  29. const email = event.target.parentNode.dataset.vwUserEmail;
  30. if (!id || !email) {
  31. alert("Required parameters not found!");
  32. return false;
  33. }
  34. const input_email = prompt(`To delete user "${email}" SSO association, please type the email below`);
  35. if (input_email != null) {
  36. if (input_email == email) {
  37. _delete(`${BASE_URL}/admin/users/${id}/sso`,
  38. "User SSO association deleted correctly",
  39. "Error deleting user SSO association"
  40. );
  41. } else {
  42. alert("Wrong email, please try again");
  43. }
  44. }
  45. }
  46. function remove2fa(event) {
  47. event.preventDefault();
  48. event.stopPropagation();
  49. const id = event.target.parentNode.dataset.vwUserUuid;
  50. const email = event.target.parentNode.dataset.vwUserEmail;
  51. if (!id || !email) {
  52. alert("Required parameters not found!");
  53. return false;
  54. }
  55. const confirmed = confirm(`Are you sure you want to remove 2FA for "${email}"?`);
  56. if (confirmed) {
  57. _post(`${BASE_URL}/admin/users/${id}/remove-2fa`,
  58. "2FA removed correctly",
  59. "Error removing 2FA"
  60. );
  61. }
  62. }
  63. function deauthUser(event) {
  64. event.preventDefault();
  65. event.stopPropagation();
  66. const id = event.target.parentNode.dataset.vwUserUuid;
  67. const email = event.target.parentNode.dataset.vwUserEmail;
  68. if (!id || !email) {
  69. alert("Required parameters not found!");
  70. return false;
  71. }
  72. const confirmed = confirm(`Are you sure you want to deauthorize sessions for "${email}"?`);
  73. if (confirmed) {
  74. _post(`${BASE_URL}/admin/users/${id}/deauth`,
  75. "Sessions deauthorized correctly",
  76. "Error deauthorizing sessions"
  77. );
  78. }
  79. }
  80. function disableUser(event) {
  81. event.preventDefault();
  82. event.stopPropagation();
  83. const id = event.target.parentNode.dataset.vwUserUuid;
  84. const email = event.target.parentNode.dataset.vwUserEmail;
  85. if (!id || !email) {
  86. alert("Required parameters not found!");
  87. return false;
  88. }
  89. const confirmed = confirm(`Are you sure you want to disable user "${email}"? This will also deauthorize their sessions.`);
  90. if (confirmed) {
  91. _post(`${BASE_URL}/admin/users/${id}/disable`,
  92. "User disabled successfully",
  93. "Error disabling user"
  94. );
  95. }
  96. }
  97. function enableUser(event) {
  98. event.preventDefault();
  99. event.stopPropagation();
  100. const id = event.target.parentNode.dataset.vwUserUuid;
  101. const email = event.target.parentNode.dataset.vwUserEmail;
  102. if (!id || !email) {
  103. alert("Required parameters not found!");
  104. return false;
  105. }
  106. const confirmed = confirm(`Are you sure you want to enable user "${email}"?`);
  107. if (confirmed) {
  108. _post(`${BASE_URL}/admin/users/${id}/enable`,
  109. "User enabled successfully",
  110. "Error enabling user"
  111. );
  112. }
  113. }
  114. function updateRevisions(event) {
  115. event.preventDefault();
  116. event.stopPropagation();
  117. _post(`${BASE_URL}/admin/users/update_revision`,
  118. "Success, clients will sync next time they connect",
  119. "Error forcing clients to sync"
  120. );
  121. }
  122. function inviteUser(event) {
  123. event.preventDefault();
  124. event.stopPropagation();
  125. const email = document.getElementById("inviteEmail");
  126. const data = JSON.stringify({
  127. "email": email.value
  128. });
  129. email.value = "";
  130. _post(`${BASE_URL}/admin/invite`,
  131. "User invited correctly",
  132. "Error inviting user",
  133. data
  134. );
  135. }
  136. function resendUserInvite (event) {
  137. event.preventDefault();
  138. event.stopPropagation();
  139. const id = event.target.parentNode.dataset.vwUserUuid;
  140. const email = event.target.parentNode.dataset.vwUserEmail;
  141. if (!id || !email) {
  142. alert("Required parameters not found!");
  143. return false;
  144. }
  145. const confirmed = confirm(`Are you sure you want to resend invitation for "${email}"?`);
  146. if (confirmed) {
  147. _post(`${BASE_URL}/admin/users/${id}/invite/resend`,
  148. "Invite sent successfully",
  149. "Error resend invite"
  150. );
  151. }
  152. }
  153. const ORG_TYPES = {
  154. "0": {
  155. "name": "Owner",
  156. "bg": "orange",
  157. "font": "black"
  158. },
  159. "1": {
  160. "name": "Admin",
  161. "bg": "blueviolet"
  162. },
  163. "2": {
  164. "name": "User",
  165. "bg": "blue"
  166. },
  167. "4": {
  168. "name": "Manager",
  169. "bg": "green"
  170. },
  171. };
  172. // Special sort function to sort dates in ISO format
  173. jQuery.extend(jQuery.fn.dataTableExt.oSort, {
  174. "date-iso-pre": function(a) {
  175. let x;
  176. const sortDate = a.replace(/(<([^>]+)>)/gi, "").trim();
  177. if (sortDate !== "") {
  178. const dtParts = sortDate.split(" ");
  179. const timeParts = (undefined != dtParts[1]) ? dtParts[1].split(":") : ["00", "00", "00"];
  180. const dateParts = dtParts[0].split("-");
  181. x = (dateParts[0] + dateParts[1] + dateParts[2] + timeParts[0] + timeParts[1] + ((undefined != timeParts[2]) ? timeParts[2] : 0)) * 1;
  182. if (isNaN(x)) {
  183. x = 0;
  184. }
  185. } else {
  186. x = Infinity;
  187. }
  188. return x;
  189. },
  190. "date-iso-asc": function(a, b) {
  191. return a - b;
  192. },
  193. "date-iso-desc": function(a, b) {
  194. return b - a;
  195. }
  196. });
  197. const userOrgTypeDialog = document.getElementById("userOrgTypeDialog");
  198. // Fill the form and title
  199. userOrgTypeDialog.addEventListener("show.bs.modal", function(event) {
  200. // Get shared values
  201. const userEmail = event.relatedTarget.parentNode.dataset.vwUserEmail;
  202. const userUuid = event.relatedTarget.parentNode.dataset.vwUserUuid;
  203. // Get org specific values
  204. const userOrgType = event.relatedTarget.dataset.vwOrgType;
  205. const userOrgTypeName = ORG_TYPES[userOrgType]["name"];
  206. const orgName = event.relatedTarget.dataset.vwOrgName;
  207. const orgUuid = event.relatedTarget.dataset.vwOrgUuid;
  208. document.getElementById("userOrgTypeDialogOrgName").textContent = orgName;
  209. document.getElementById("userOrgTypeDialogUserEmail").textContent = userEmail;
  210. document.getElementById("userOrgTypeUserUuid").value = userUuid;
  211. document.getElementById("userOrgTypeOrgUuid").value = orgUuid;
  212. document.getElementById(`userOrgType${userOrgTypeName}`).checked = true;
  213. }, false);
  214. // Prevent accidental submission of the form with valid elements after the modal has been hidden.
  215. userOrgTypeDialog.addEventListener("hide.bs.modal", function() {
  216. document.getElementById("userOrgTypeDialogOrgName").textContent = "";
  217. document.getElementById("userOrgTypeDialogUserEmail").textContent = "";
  218. document.getElementById("userOrgTypeUserUuid").value = "";
  219. document.getElementById("userOrgTypeOrgUuid").value = "";
  220. }, false);
  221. function updateUserOrgType(event) {
  222. event.preventDefault();
  223. event.stopPropagation();
  224. const data = JSON.stringify(Object.fromEntries(new FormData(event.target).entries()));
  225. _post(`${BASE_URL}/admin/users/org_type`,
  226. "Updated organization type of the user successfully",
  227. "Error updating organization type of the user",
  228. data
  229. );
  230. }
  231. function initUserTable() {
  232. // Color all the org buttons per type
  233. document.querySelectorAll("button[data-vw-org-type]").forEach(function(e) {
  234. const orgType = ORG_TYPES[e.dataset.vwOrgType];
  235. e.style.backgroundColor = orgType.bg;
  236. if (orgType.font !== undefined) {
  237. e.style.color = orgType.font;
  238. }
  239. e.title = orgType.name;
  240. });
  241. document.querySelectorAll("button[vw-remove2fa]").forEach(btn => {
  242. btn.addEventListener("click", remove2fa);
  243. });
  244. document.querySelectorAll("button[vw-deauth-user]").forEach(btn => {
  245. btn.addEventListener("click", deauthUser);
  246. });
  247. document.querySelectorAll("button[vw-delete-user]").forEach(btn => {
  248. btn.addEventListener("click", deleteUser);
  249. });
  250. document.querySelectorAll("button[vw-delete-sso-user]").forEach(btn => {
  251. btn.addEventListener("click", deleteSSOUser);
  252. });
  253. document.querySelectorAll("button[vw-disable-user]").forEach(btn => {
  254. btn.addEventListener("click", disableUser);
  255. });
  256. document.querySelectorAll("button[vw-enable-user]").forEach(btn => {
  257. btn.addEventListener("click", enableUser);
  258. });
  259. document.querySelectorAll("button[vw-resend-user-invite]").forEach(btn => {
  260. btn.addEventListener("click", resendUserInvite);
  261. });
  262. if (jdenticon) {
  263. jdenticon();
  264. }
  265. }
  266. // onLoad events
  267. document.addEventListener("DOMContentLoaded", (/*event*/) => {
  268. const size = jQuery("#users-table > thead th").length;
  269. const ssoOffset = size-7;
  270. jQuery("#users-table").DataTable({
  271. "drawCallback": function() {
  272. initUserTable();
  273. },
  274. "stateSave": true,
  275. "responsive": true,
  276. "lengthMenu": [
  277. [-1, 2, 5, 10, 25, 50],
  278. ["All", 2, 5, 10, 25, 50]
  279. ],
  280. "pageLength": -1, // Default show all
  281. "columnDefs": [{
  282. "targets": [1 + ssoOffset, 2 + ssoOffset],
  283. "type": "date-iso"
  284. }, {
  285. "targets": size-1,
  286. "searchable": false,
  287. "orderable": false
  288. }]
  289. });
  290. // Add click events for user actions
  291. initUserTable();
  292. const btnUpdateRevisions = document.getElementById("updateRevisions");
  293. if (btnUpdateRevisions) {
  294. btnUpdateRevisions.addEventListener("click", updateRevisions);
  295. }
  296. const btnReload = document.getElementById("reload");
  297. if (btnReload) {
  298. btnReload.addEventListener("click", reload);
  299. }
  300. const btnUserOrgTypeForm = document.getElementById("userOrgTypeForm");
  301. if (btnUserOrgTypeForm) {
  302. btnUserOrgTypeForm.addEventListener("submit", updateUserOrgType);
  303. }
  304. const btnInviteUserForm = document.getElementById("inviteUserForm");
  305. if (btnInviteUserForm) {
  306. btnInviteUserForm.addEventListener("submit", inviteUser);
  307. }
  308. });