gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. import {checkAppUrl} from '../common-page.ts';
  2. import {hideElem, queryElems, showElem, toggleElem} from '../../utils/dom.ts';
  3. import {POST} from '../../modules/fetch.ts';
  4. import {fomanticQuery} from '../../modules/fomantic/base.ts';
  5. const {appSubUrl} = window.config;
  6. function onSecurityProtocolChange(): void {
  7. if (Number(document.querySelector<HTMLInputElement>('#security_protocol')?.value) > 0) {
  8. showElem('.has-tls');
  9. } else {
  10. hideElem('.has-tls');
  11. }
  12. }
  13. export function initAdminCommon(): void {
  14. if (!document.querySelector('.page-content.admin')) return;
  15. // check whether appUrl(ROOT_URL) is correct, if not, show an error message
  16. checkAppUrl();
  17. initAdminUser();
  18. initAdminAuthentication();
  19. initAdminNotice();
  20. }
  21. function initAdminUser() {
  22. const pageContent = document.querySelector('.page-content.admin.edit.user, .page-content.admin.new.user');
  23. if (!pageContent) return;
  24. document.querySelector<HTMLInputElement>('#login_type')?.addEventListener('change', function () {
  25. if (this.value?.startsWith('0')) {
  26. document.querySelector<HTMLInputElement>('#user_name')?.removeAttribute('disabled');
  27. document.querySelector<HTMLInputElement>('#login_name')?.removeAttribute('required');
  28. hideElem('.non-local');
  29. showElem('.local');
  30. document.querySelector<HTMLInputElement>('#user_name')?.focus();
  31. if (this.getAttribute('data-password') === 'required') {
  32. document.querySelector('#password')?.setAttribute('required', 'required');
  33. }
  34. } else {
  35. if (document.querySelector<HTMLDivElement>('.admin.edit.user')) {
  36. document.querySelector<HTMLInputElement>('#user_name')?.setAttribute('disabled', 'disabled');
  37. }
  38. document.querySelector<HTMLInputElement>('#login_name')?.setAttribute('required', 'required');
  39. showElem('.non-local');
  40. hideElem('.local');
  41. document.querySelector<HTMLInputElement>('#login_name')?.focus();
  42. document.querySelector<HTMLInputElement>('#password')?.removeAttribute('required');
  43. }
  44. });
  45. }
  46. function initAdminAuthentication() {
  47. const pageContent = document.querySelector('.page-content.admin.authentication');
  48. if (!pageContent) return;
  49. const isNewPage = pageContent.classList.contains('new');
  50. const isEditPage = pageContent.classList.contains('edit');
  51. if (!isNewPage && !isEditPage) return;
  52. function onUsePagedSearchChange() {
  53. const searchPageSizeElements = document.querySelectorAll<HTMLDivElement>('.search-page-size');
  54. if (document.querySelector<HTMLInputElement>('#use_paged_search').checked) {
  55. showElem('.search-page-size');
  56. for (const el of searchPageSizeElements) {
  57. el.querySelector('input')?.setAttribute('required', 'required');
  58. }
  59. } else {
  60. hideElem('.search-page-size');
  61. for (const el of searchPageSizeElements) {
  62. el.querySelector('input')?.removeAttribute('required');
  63. }
  64. }
  65. }
  66. function onOAuth2Change(applyDefaultValues: boolean) {
  67. hideElem('.open_id_connect_auto_discovery_url, .oauth2_use_custom_url');
  68. for (const input of document.querySelectorAll<HTMLInputElement>('.open_id_connect_auto_discovery_url input[required]')) {
  69. input.removeAttribute('required');
  70. }
  71. const provider = document.querySelector<HTMLInputElement>('#oauth2_provider').value;
  72. switch (provider) {
  73. case 'openidConnect':
  74. document.querySelector<HTMLInputElement>('.open_id_connect_auto_discovery_url input').setAttribute('required', 'required');
  75. showElem('.open_id_connect_auto_discovery_url');
  76. break;
  77. default: {
  78. const elProviderCustomUrlSettings = document.querySelector<HTMLInputElement>(`#${provider}_customURLSettings`);
  79. if (!elProviderCustomUrlSettings) break; // some providers do not have custom URL settings
  80. const couldChangeCustomURLs = elProviderCustomUrlSettings.getAttribute('data-available') === 'true';
  81. const mustProvideCustomURLs = elProviderCustomUrlSettings.getAttribute('data-required') === 'true';
  82. if (couldChangeCustomURLs) {
  83. showElem('.oauth2_use_custom_url'); // show the checkbox
  84. }
  85. if (mustProvideCustomURLs) {
  86. document.querySelector<HTMLInputElement>('#oauth2_use_custom_url').checked = true; // make the checkbox checked
  87. }
  88. break;
  89. }
  90. }
  91. const supportSshPublicKey = document.querySelector<HTMLInputElement>(`#${provider}_SupportSSHPublicKey`)?.value === 'true';
  92. toggleElem('.field.oauth2_ssh_public_key_claim_name', supportSshPublicKey);
  93. onOAuth2UseCustomURLChange(applyDefaultValues);
  94. }
  95. function onOAuth2UseCustomURLChange(applyDefaultValues: boolean) {
  96. const provider = document.querySelector<HTMLInputElement>('#oauth2_provider').value;
  97. hideElem('.oauth2_use_custom_url_field');
  98. for (const input of document.querySelectorAll<HTMLInputElement>('.oauth2_use_custom_url_field input[required]')) {
  99. input.removeAttribute('required');
  100. }
  101. const elProviderCustomUrlSettings = document.querySelector(`#${provider}_customURLSettings`);
  102. if (elProviderCustomUrlSettings && document.querySelector<HTMLInputElement>('#oauth2_use_custom_url').checked) {
  103. for (const custom of ['token_url', 'auth_url', 'profile_url', 'email_url', 'tenant']) {
  104. if (applyDefaultValues) {
  105. document.querySelector<HTMLInputElement>(`#oauth2_${custom}`).value = document.querySelector<HTMLInputElement>(`#${provider}_${custom}`).value;
  106. }
  107. const customInput = document.querySelector(`#${provider}_${custom}`);
  108. if (customInput && customInput.getAttribute('data-available') === 'true') {
  109. for (const input of document.querySelectorAll(`.oauth2_${custom} input`)) {
  110. input.setAttribute('required', 'required');
  111. }
  112. showElem(`.oauth2_${custom}`);
  113. }
  114. }
  115. }
  116. }
  117. function onEnableLdapGroupsChange() {
  118. const checked = document.querySelector<HTMLInputElement>('.js-ldap-group-toggle')?.checked;
  119. toggleElem(document.querySelector('#ldap-group-options'), checked);
  120. }
  121. const elAuthType = document.querySelector<HTMLInputElement>('#auth_type');
  122. // New authentication
  123. if (isNewPage) {
  124. const onAuthTypeChange = function () {
  125. hideElem('.ldap, .dldap, .smtp, .pam, .oauth2, .has-tls, .search-page-size, .sspi');
  126. for (const input of document.querySelectorAll<HTMLInputElement>('.ldap input[required], .binddnrequired input[required], .dldap input[required], .smtp input[required], .pam input[required], .oauth2 input[required], .has-tls input[required], .sspi input[required]')) {
  127. input.removeAttribute('required');
  128. }
  129. document.querySelector<HTMLDivElement>('.binddnrequired')?.classList.remove('required');
  130. const authType = elAuthType.value;
  131. switch (authType) {
  132. case '2': // LDAP
  133. showElem('.ldap');
  134. for (const input of document.querySelectorAll<HTMLInputElement>('.binddnrequired input, .ldap div.required:not(.dldap) input')) {
  135. input.setAttribute('required', 'required');
  136. }
  137. document.querySelector('.binddnrequired')?.classList.add('required');
  138. break;
  139. case '3': // SMTP
  140. showElem('.smtp');
  141. showElem('.has-tls');
  142. for (const input of document.querySelectorAll<HTMLInputElement>('.smtp div.required input, .has-tls')) {
  143. input.setAttribute('required', 'required');
  144. }
  145. break;
  146. case '4': // PAM
  147. showElem('.pam');
  148. for (const input of document.querySelectorAll<HTMLInputElement>('.pam input')) {
  149. input.setAttribute('required', 'required');
  150. }
  151. break;
  152. case '5': // LDAP
  153. showElem('.dldap');
  154. for (const input of document.querySelectorAll<HTMLInputElement>('.dldap div.required:not(.ldap) input')) {
  155. input.setAttribute('required', 'required');
  156. }
  157. break;
  158. case '6': // OAuth2
  159. showElem('.oauth2');
  160. for (const input of document.querySelectorAll<HTMLInputElement>('.oauth2 div.required:not(.oauth2_use_custom_url,.oauth2_use_custom_url_field,.open_id_connect_auto_discovery_url) input')) {
  161. input.setAttribute('required', 'required');
  162. }
  163. onOAuth2Change(true);
  164. break;
  165. case '7': // SSPI
  166. showElem('.sspi');
  167. for (const input of document.querySelectorAll<HTMLInputElement>('.sspi div.required input')) {
  168. input.setAttribute('required', 'required');
  169. }
  170. break;
  171. }
  172. if (authType === '2' || authType === '5') {
  173. onSecurityProtocolChange();
  174. onEnableLdapGroupsChange();
  175. }
  176. if (authType === '2') {
  177. onUsePagedSearchChange();
  178. }
  179. };
  180. elAuthType.addEventListener('change', onAuthTypeChange);
  181. onAuthTypeChange();
  182. document.querySelector<HTMLInputElement>('#security_protocol')?.addEventListener('change', onSecurityProtocolChange);
  183. document.querySelector<HTMLInputElement>('#use_paged_search')?.addEventListener('change', onUsePagedSearchChange);
  184. document.querySelector<HTMLInputElement>('#oauth2_provider')?.addEventListener('change', () => onOAuth2Change(true));
  185. document.querySelector<HTMLInputElement>('#oauth2_use_custom_url')?.addEventListener('change', () => onOAuth2UseCustomURLChange(true));
  186. document.querySelector('.js-ldap-group-toggle').addEventListener('change', onEnableLdapGroupsChange);
  187. }
  188. // Edit authentication
  189. if (isEditPage) {
  190. const authType = elAuthType.value;
  191. if (authType === '2' || authType === '5') {
  192. document.querySelector<HTMLInputElement>('#security_protocol')?.addEventListener('change', onSecurityProtocolChange);
  193. document.querySelector('.js-ldap-group-toggle').addEventListener('change', onEnableLdapGroupsChange);
  194. onEnableLdapGroupsChange();
  195. if (authType === '2') {
  196. document.querySelector<HTMLInputElement>('#use_paged_search')?.addEventListener('change', onUsePagedSearchChange);
  197. }
  198. } else if (authType === '6') {
  199. document.querySelector<HTMLInputElement>('#oauth2_provider')?.addEventListener('change', () => onOAuth2Change(true));
  200. document.querySelector<HTMLInputElement>('#oauth2_use_custom_url')?.addEventListener('change', () => onOAuth2UseCustomURLChange(false));
  201. onOAuth2Change(false);
  202. }
  203. }
  204. const elAuthName = document.querySelector<HTMLInputElement>('#auth_name');
  205. const onAuthNameChange = function () {
  206. // appSubUrl is either empty or is a path that starts with `/` and doesn't have a trailing slash.
  207. document.querySelector('#oauth2-callback-url').textContent = `${window.location.origin}${appSubUrl}/user/oauth2/${encodeURIComponent(elAuthName.value)}/callback`;
  208. };
  209. elAuthName.addEventListener('input', onAuthNameChange);
  210. onAuthNameChange();
  211. }
  212. function initAdminNotice() {
  213. const pageContent = document.querySelector('.page-content.admin.notice');
  214. if (!pageContent) return;
  215. const detailModal = document.querySelector<HTMLDivElement>('#detail-modal');
  216. // Attach view detail modals
  217. queryElems(pageContent, '.view-detail', (el) => el.addEventListener('click', (e) => {
  218. e.preventDefault();
  219. const elNoticeDesc = el.closest('tr').querySelector('.notice-description');
  220. const elModalDesc = detailModal.querySelector('.content pre');
  221. elModalDesc.textContent = elNoticeDesc.textContent;
  222. fomanticQuery(detailModal).modal('show');
  223. }));
  224. // Select actions
  225. const checkboxes = document.querySelectorAll<HTMLInputElement>('.select.table .ui.checkbox input');
  226. queryElems(pageContent, '.select.action', (el) => el.addEventListener('click', () => {
  227. switch (el.getAttribute('data-action')) {
  228. case 'select-all':
  229. for (const checkbox of checkboxes) {
  230. checkbox.checked = true;
  231. }
  232. break;
  233. case 'deselect-all':
  234. for (const checkbox of checkboxes) {
  235. checkbox.checked = false;
  236. }
  237. break;
  238. case 'inverse':
  239. for (const checkbox of checkboxes) {
  240. checkbox.checked = !checkbox.checked;
  241. }
  242. break;
  243. }
  244. }));
  245. document.querySelector<HTMLButtonElement>('#delete-selection')?.addEventListener('click', async function (e) {
  246. e.preventDefault();
  247. this.classList.add('is-loading', 'disabled');
  248. const data = new FormData();
  249. for (const checkbox of checkboxes) {
  250. if (checkbox.checked) {
  251. data.append('ids[]', checkbox.closest('.ui.checkbox').getAttribute('data-id'));
  252. }
  253. }
  254. await POST(this.getAttribute('data-link'), {data});
  255. window.location.href = this.getAttribute('data-redirect');
  256. });
  257. }