mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-20 19:53:41 +09:00
Adds first-class bot accounts (`UserTypeBot`): local, password-less
users for automation that authenticate only with access tokens.
1. Admin UI: create bots, filter users by type, manage a bot's access
tokens, convert between user and bot
2. API: `POST /admin/users/{username}/convert-type`, and user objects
gain a GitHub-compatible `type` (`User`, `Organization`, `Bot`)
3. CLI: `gitea admin user change-type`, `--user-type` accepts `User` or
`Bot` case-insensitively
4. Converting keeps the password, 2FA, OAuth2 grants and access tokens,
and since sign-in rejects bots, converting back restores the account.
Only local, non-admin accounts can be converted, and conversions are
audited
5. Session, reverse proxy, SSPI, external source and password reset
sign-in reject non-individual users, so a bot never gets an interactive
session
6. Bots receive no notifications or emails
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: joestump <joe@joestump.net>
Co-authored-by: Joe Stump <joe@stu.mp>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
38 lines
1.3 KiB
TypeScript
38 lines
1.3 KiB
TypeScript
export function initAdminUserListSearchForm(): void {
|
|
const searchForm = window.config.pageData.adminUserListSearchForm;
|
|
if (!searchForm) return;
|
|
|
|
const form = document.querySelector<HTMLFormElement>('#user-list-search-form');
|
|
if (!form) return;
|
|
|
|
for (const button of form.querySelectorAll(`button[name=sort][value="${CSS.escape(searchForm.SortType)}"]`)) {
|
|
button.classList.add('active');
|
|
}
|
|
|
|
for (const [k, v] of Object.entries(searchForm.StatusFilterMap || {})) {
|
|
if (!v) continue;
|
|
for (const input of form.querySelectorAll<HTMLInputElement>(`input[name="status_filter[${CSS.escape(k)}]"][value="${CSS.escape(v)}"]`)) {
|
|
input.checked = true;
|
|
}
|
|
}
|
|
|
|
for (const radio of form.querySelectorAll<HTMLInputElement>('input[type=radio]')) {
|
|
radio.addEventListener('click', () => {
|
|
form.submit();
|
|
});
|
|
}
|
|
|
|
const resetButtons = form.querySelectorAll<HTMLAnchorElement>('.js-reset-status-filter');
|
|
for (const button of resetButtons) {
|
|
button.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
for (const input of form.querySelectorAll<HTMLInputElement>('input[type=radio]')) {
|
|
if (input.name.startsWith('status_filter[')) {
|
|
input.checked = false;
|
|
}
|
|
}
|
|
form.submit();
|
|
});
|
|
}
|
|
}
|