Extends the UI introduced in #12558 to have edit capabilities. (not in scope: "Add" for a new Authorized Integration will be the next update to this UI; `create-authorized-integration` CLI is still the only way to create a new record) This PR includes a few refactoring steps. The goal of these steps is to have `services/auth` be a single entrypoint for validating, inserting, or updating an authorized integration. Some logic is moved out of `services/authz` because it is not authorization related, and some is moved out of `services/auth/method` to allow it to be reused during validation without creating a cyclical module dependency. This PR also adds comprehensive validation to the more complex fields in the authorized integration, such as the issuer and claim rules. This validation applies to the `forgejo admin user create-authorized-integration` CLI as well. The visible UI is the same as #12558, but with a "Save" button, and the ability to display errors:  ## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. All work and communication must conform to Forgejo's [AI Agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md). There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests for Go changes - I added test coverage for Go changes... - [x] in their respective `*_test.go` for unit tests. - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I ran... - [x] `make pr-go` before pushing ### Tests for JavaScript changes - I added test coverage for JavaScript changes... - [ ] in `web_src/js/*.test.js` if it can be unit tested. - [x] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)). ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [x] I did not document these changes and I do not expect someone else to do it. - Documentation is on my TODO list and will be completed before release. ### Release notes - [x] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change. - [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12601 Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org>
181 lines
8.6 KiB
Go HTML Template
181 lines
8.6 KiB
Go HTML Template
|
|
<h4 class="ui top attached header">
|
|
{{ctx.Locale.Tr "settings.authorized_integration.perms.title"}}
|
|
</h4>
|
|
<div class="ui attached bottom segment">
|
|
|
|
<div class="field">
|
|
<fieldset>
|
|
<label>{{ctx.Locale.Tr "settings.repo_and_org_access"}}</label>
|
|
<div class="field">
|
|
<div class="field ui radio checkbox">
|
|
<input id="resource-all" class="enable-system" type="radio" name="resource" value="all" {{if eq .Form.Resource "all"}}checked{{end}}>
|
|
<label for="resource-all">{{ctx.Locale.Tr "settings.permissions_access_all"}}</label>
|
|
<p class="help">{{ctx.Locale.Tr "settings.access_token.resource_all_help"}}</p>
|
|
</div>
|
|
</div>
|
|
<div class="field">
|
|
<div class="field ui radio checkbox">
|
|
<input id="resource-public-only" class="enable-system" type="radio" name="resource" value="public-only" {{if eq .Form.Resource "public-only"}}checked{{end}}>
|
|
<label for="resource-public-only">{{ctx.Locale.Tr "settings.permissions_public_only"}}</label>
|
|
<p class="help">
|
|
{{ctx.Locale.Tr "settings.access_token.resource_public_only_help"}}
|
|
{{if $.IsAdmin}}{{ctx.Locale.Tr "settings.access_token.admin_disabled"}}{{end}}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="field">
|
|
<div class="field ui radio checkbox {{if .Err_SelectedRepo}}error{{end}}">
|
|
<input id="resource-repo-specific" class="enable-system" type="radio" name="resource" value="repo-specific" {{if eq .Form.Resource "repo-specific"}}checked{{end}}>
|
|
<label for="resource-repo-specific">{{ctx.Locale.Tr "settings.permissions_access_specific_repositories"}}</label>
|
|
<p class="help">
|
|
{{ctx.Locale.Tr "settings.access_token.resource_specific_repo_help"}}
|
|
{{if $.IsAdmin}}{{ctx.Locale.Tr "settings.access_token.admin_disabled"}}{{end}}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div id="repo-selector-wrapper" role="group" class="field tw-mt-4">
|
|
<div id="repo-selector" class="tw-flex tw-flex-wrap tw-gap-8">
|
|
|
|
<!-- left-hand side: repo list from a search -->
|
|
<div class="ui tab active list tw-flex-1">
|
|
<h5>
|
|
{{ctx.Locale.Tr "settings.access_token.available_repositories"}}
|
|
</h5>
|
|
|
|
<div class="ui small fluid action left icon input tw-mb-3">
|
|
<input type="search" name="repo_search" spellcheck="false" {{if eq .Autofocus "search"}}autofocus{{end}} placeholder="{{ctx.Locale.Tr "search.repo_kind"}}" value="{{.repo_search}}">
|
|
<i class="icon">{{svg "octicon-search" 16}}</i>
|
|
<button class="ui small icon button" aria-label="{{ctx.Locale.Tr "search.search"}}" type="submit" name="set_page" value="1" formnovalidate="true" formmethod="get" formaction="#resource-repo-specific">
|
|
{{svg "octicon-search" 16}}
|
|
</button>
|
|
</div>
|
|
|
|
{{if eq (len .Repos) 0}}
|
|
{{ctx.Locale.Tr "settings.access_token.no_repositories_found"}}
|
|
{{else}}
|
|
<div class="tw-grid tw-items-center" style="grid-template-columns: min-content 1fr min-content;">
|
|
{{range .Repos}}
|
|
{{template "user/settings/repo_icon" .}}
|
|
<div class="text truncate">
|
|
{{.FullName}}
|
|
</div>
|
|
<button class="ui primary button tw-ml-2 tw-my-1 tiny" type="submit" aria-label="{{ctx.Locale.Tr "repo.editor.add" .FullName}}" formnovalidate="true" name="add_selected_repo" value="{{.FullName}}" formmethod="get" formaction="#resource-repo-specific">
|
|
{{ctx.Locale.Tr "add"}}
|
|
</button>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
|
|
{{/* Can't use base/paginate template include here because all the pagination links in
|
|
that template are simple <a href=...> links. Here, we need to turn them into form
|
|
buttons so that we can submit the current form. If a user just changed a value (eg. set
|
|
the token name, changed a selected permission) and then clicked a pagination button, the
|
|
new value that they changed needs to be submitted. base/paginate would allow preserving
|
|
old values from before the change, but not new updates. Implementing here also allows
|
|
the use of smaller styling. */}}
|
|
{{with .Page.Paginater}}
|
|
<input type="hidden" name="page" value="{{.Current}}">
|
|
<div class="center page buttons">
|
|
<div class="ui borderless pagination menu mini">
|
|
<button class="item navigation {{if .IsFirst}}disabled{{end}}" type="submit" formnovalidate="true" name="set_page" value="1" formmethod="get" formaction="#resource-repo-specific">
|
|
{{svg "gitea-double-chevron-left" 16 "tw-mr-1"}}
|
|
<span class="navigation_label">{{ctx.Locale.Tr "admin.first_page"}}</span>
|
|
</button>
|
|
<button class="item navigation {{if not .HasPrevious}}disabled{{end}}" type="submit" formnovalidate="true" name="set_page" value="{{.Previous}}" formmethod="get" formaction="#resource-repo-specific">
|
|
{{svg "octicon-chevron-left" 16 "tw-mr-1"}}
|
|
<span class="navigation_label">{{ctx.Locale.Tr "repo.issues.previous"}}</span>
|
|
</button>
|
|
{{range .Pages}}
|
|
{{if eq .Num -1}}
|
|
<a class="disabled item">...</a>
|
|
{{else}}
|
|
<button class="item navigation {{if .IsCurrent}}active{{end}}" type="submit" formnovalidate="true" name="set_page" value="{{.Num}}" formmethod="get" formaction="#resource-repo-specific">
|
|
{{.Num}}
|
|
</button>
|
|
{{end}}
|
|
{{end}}
|
|
<button class="item navigation {{if not .HasNext}}disabled{{end}}" type="submit" formnovalidate="true" name="set_page" value="{{.Next}}" formmethod="get" formaction="#resource-repo-specific">
|
|
<span class="navigation_label">{{ctx.Locale.Tr "repo.issues.next"}}</span>
|
|
{{svg "octicon-chevron-right" 16 "tw-ml-1"}}
|
|
</button>
|
|
<button class="item navigation {{if .IsLast}}disabled{{end}}" type="submit" formnovalidate="true" name="set_page" value="{{.TotalPages}}" formmethod="get" formaction="#resource-repo-specific">
|
|
<span class="navigation_label">{{ctx.Locale.Tr "admin.last_page"}}</span>
|
|
{{svg "gitea-double-chevron-right" 16 "tw-ml-1"}}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
|
|
<!-- right-hand side: selected repositories -->
|
|
<div class="tw-flex-1">
|
|
<h5>{{ctx.Locale.TrPluralString (len .SelectedRepos) "settings.access_token.selected_repositories" (len .SelectedRepos)}}</h5>
|
|
{{if eq (len .SelectedRepos) 0}}
|
|
<div class="tw-my-2">
|
|
{{ctx.Locale.Tr "settings.access_token.no_repositories_selected"}}
|
|
</div>
|
|
{{else}}
|
|
<div class="tw-grid tw-items-center tw-auto-rows-min" style="grid-template-columns: min-content 1fr min-content;">
|
|
{{range .SelectedRepos}}
|
|
<input type="hidden" name="selected_repo" value="{{.FullName}}">
|
|
{{template "user/settings/repo_icon" .}}
|
|
<div class="text tw-text-nowrap"> <!-- nowrap, !truncate, ensures that this can be fully seen and ensures this side of the control has an appropriate min-width -->
|
|
{{.FullName}}
|
|
</div>
|
|
<button class="ui button tw-ml-2 tw-my-1 tiny" type="submit" aria-label="{{ctx.Locale.Tr "settings.access_token.remove" .FullName}}" formnovalidate="true" name="remove_selected_repo" value="{{.FullName}}" formmethod="get" formaction="#resource-repo-specific">
|
|
{{ctx.Locale.Tr "remove"}}
|
|
</button>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="field {{if .Err_Scope}}error{{end}}">
|
|
<label>
|
|
{{ctx.Locale.Tr "settings.select_permissions"}}
|
|
</label>
|
|
<p class="activity meta">
|
|
<p>{{ctx.Locale.Tr "settings.access_token_desc" (printf "%s/api/swagger" AppSubUrl) "https://forgejo.org/docs/latest/user/token-scope/"}}</p>
|
|
</p>
|
|
|
|
{{range .Categories}}
|
|
<div class="field tw-pl-1 tw-pb-1">
|
|
<label for="scope-{{.}}">
|
|
{{.}}
|
|
</label>
|
|
<div class="gitea-select">
|
|
<select class="ui selection" name="scope" id="scope-{{.}}">
|
|
<option value="">
|
|
{{ctx.Locale.Tr "settings.permission_no_access"}}
|
|
</option>
|
|
<option value="read:{{.}}" {{if (SliceUtils.Contains $.Form.Scope (printf "read:%s" .))}} selected {{end}}>
|
|
{{ctx.Locale.Tr "settings.permission_read"}}
|
|
</option>
|
|
<option value="write:{{.}}" {{if or $.Form.ScopeAll (SliceUtils.Contains $.Form.Scope (printf "write:%s" .))}} selected {{end}}>
|
|
{{ctx.Locale.Tr "settings.permission_write"}}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="ui segment">
|
|
<button class="ui primary button">{{ctx.Locale.Tr "settings.authorized_integration.save"}}</button>
|
|
</div>
|
|
|
|
|
|
</form>
|
|
</div>
|
|
|
|
{{template "user/settings/layout_footer" .}}
|