Allow creation of OAuth2 applications for orgs (#18084)
Adds the settings pages to create OAuth2 apps also to the org settings and allows to create apps for orgs. Refactoring: the oauth2 related templates are shared for instance-wide/org/user, and the backend code uses `OAuth2CommonHandlers` to share code for instance-wide/org/user. Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>tokarchuk/v1.18
parent
97f3f1988b
commit
a813c9d8f3
File diff suppressed because one or more lines are too long
@ -0,0 +1,93 @@ |
|||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package org |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"net/http" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/auth" |
||||||
|
"code.gitea.io/gitea/modules/base" |
||||||
|
"code.gitea.io/gitea/modules/context" |
||||||
|
"code.gitea.io/gitea/modules/setting" |
||||||
|
user_setting "code.gitea.io/gitea/routers/web/user/setting" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
tplSettingsApplications base.TplName = "org/settings/applications" |
||||||
|
tplSettingsOAuthApplicationEdit base.TplName = "org/settings/applications_oauth2_edit" |
||||||
|
) |
||||||
|
|
||||||
|
func newOAuth2CommonHandlers(org *context.Organization) *user_setting.OAuth2CommonHandlers { |
||||||
|
return &user_setting.OAuth2CommonHandlers{ |
||||||
|
OwnerID: org.Organization.ID, |
||||||
|
BasePathList: fmt.Sprintf("%s/org/%s/settings/applications", setting.AppSubURL, org.Organization.Name), |
||||||
|
BasePathEditPrefix: fmt.Sprintf("%s/org/%s/settings/applications/oauth2", setting.AppSubURL, org.Organization.Name), |
||||||
|
TplAppEdit: tplSettingsOAuthApplicationEdit, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Applications render org applications page (for org, at the moment, there are only OAuth2 applications)
|
||||||
|
func Applications(ctx *context.Context) { |
||||||
|
ctx.Data["Title"] = ctx.Tr("settings.applications") |
||||||
|
ctx.Data["PageIsOrgSettings"] = true |
||||||
|
ctx.Data["PageIsSettingsApplications"] = true |
||||||
|
|
||||||
|
apps, err := auth.GetOAuth2ApplicationsByUserID(ctx, ctx.Org.Organization.ID) |
||||||
|
if err != nil { |
||||||
|
ctx.ServerError("GetOAuth2ApplicationsByUserID", err) |
||||||
|
return |
||||||
|
} |
||||||
|
ctx.Data["Applications"] = apps |
||||||
|
|
||||||
|
ctx.HTML(http.StatusOK, tplSettingsApplications) |
||||||
|
} |
||||||
|
|
||||||
|
// OAuthApplicationsPost response for adding an oauth2 application
|
||||||
|
func OAuthApplicationsPost(ctx *context.Context) { |
||||||
|
ctx.Data["Title"] = ctx.Tr("settings.applications") |
||||||
|
ctx.Data["PageIsOrgSettings"] = true |
||||||
|
ctx.Data["PageIsSettingsApplications"] = true |
||||||
|
|
||||||
|
oa := newOAuth2CommonHandlers(ctx.Org) |
||||||
|
oa.AddApp(ctx) |
||||||
|
} |
||||||
|
|
||||||
|
// OAuth2ApplicationShow displays the given application
|
||||||
|
func OAuth2ApplicationShow(ctx *context.Context) { |
||||||
|
ctx.Data["PageIsOrgSettings"] = true |
||||||
|
ctx.Data["PageIsSettingsApplications"] = true |
||||||
|
|
||||||
|
oa := newOAuth2CommonHandlers(ctx.Org) |
||||||
|
oa.EditShow(ctx) |
||||||
|
} |
||||||
|
|
||||||
|
// OAuth2ApplicationEdit response for editing oauth2 application
|
||||||
|
func OAuth2ApplicationEdit(ctx *context.Context) { |
||||||
|
ctx.Data["Title"] = ctx.Tr("settings.applications") |
||||||
|
ctx.Data["PageIsOrgSettings"] = true |
||||||
|
ctx.Data["PageIsSettingsApplications"] = true |
||||||
|
|
||||||
|
oa := newOAuth2CommonHandlers(ctx.Org) |
||||||
|
oa.EditSave(ctx) |
||||||
|
} |
||||||
|
|
||||||
|
// OAuthApplicationsRegenerateSecret handles the post request for regenerating the secret
|
||||||
|
func OAuthApplicationsRegenerateSecret(ctx *context.Context) { |
||||||
|
ctx.Data["Title"] = ctx.Tr("settings") |
||||||
|
ctx.Data["PageIsOrgSettings"] = true |
||||||
|
ctx.Data["PageIsSettingsApplications"] = true |
||||||
|
|
||||||
|
oa := newOAuth2CommonHandlers(ctx.Org) |
||||||
|
oa.RegenerateSecret(ctx) |
||||||
|
} |
||||||
|
|
||||||
|
// DeleteOAuth2Application deletes the given oauth2 application
|
||||||
|
func DeleteOAuth2Application(ctx *context.Context) { |
||||||
|
oa := newOAuth2CommonHandlers(ctx.Org) |
||||||
|
oa.DeleteApp(ctx) |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: revokes the grant with the given id
|
@ -0,0 +1,150 @@ |
|||||||
|
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package setting |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"net/http" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/auth" |
||||||
|
"code.gitea.io/gitea/modules/base" |
||||||
|
"code.gitea.io/gitea/modules/context" |
||||||
|
"code.gitea.io/gitea/modules/web" |
||||||
|
"code.gitea.io/gitea/services/forms" |
||||||
|
) |
||||||
|
|
||||||
|
type OAuth2CommonHandlers struct { |
||||||
|
OwnerID int64 // 0 for instance-wide, otherwise OrgID or UserID
|
||||||
|
BasePathList string // the base URL for the application list page, eg: "/user/setting/applications"
|
||||||
|
BasePathEditPrefix string // the base URL for the application edit page, will be appended with app id, eg: "/user/setting/applications/oauth2"
|
||||||
|
TplAppEdit base.TplName // the template for the application edit page
|
||||||
|
} |
||||||
|
|
||||||
|
func (oa *OAuth2CommonHandlers) renderEditPage(ctx *context.Context) { |
||||||
|
app := ctx.Data["App"].(*auth.OAuth2Application) |
||||||
|
ctx.Data["FormActionPath"] = fmt.Sprintf("%s/%d", oa.BasePathEditPrefix, app.ID) |
||||||
|
ctx.HTML(http.StatusOK, oa.TplAppEdit) |
||||||
|
} |
||||||
|
|
||||||
|
// AddApp adds an oauth2 application
|
||||||
|
func (oa *OAuth2CommonHandlers) AddApp(ctx *context.Context) { |
||||||
|
form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm) |
||||||
|
if ctx.HasError() { |
||||||
|
// go to the application list page
|
||||||
|
ctx.Redirect(oa.BasePathList) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// TODO validate redirect URI
|
||||||
|
app, err := auth.CreateOAuth2Application(ctx, auth.CreateOAuth2ApplicationOptions{ |
||||||
|
Name: form.Name, |
||||||
|
RedirectURIs: []string{form.RedirectURI}, |
||||||
|
UserID: oa.OwnerID, |
||||||
|
}) |
||||||
|
if err != nil { |
||||||
|
ctx.ServerError("CreateOAuth2Application", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// render the edit page with secret
|
||||||
|
ctx.Flash.Success(ctx.Tr("settings.create_oauth2_application_success"), true) |
||||||
|
ctx.Data["App"] = app |
||||||
|
ctx.Data["ClientSecret"], err = app.GenerateClientSecret() |
||||||
|
if err != nil { |
||||||
|
ctx.ServerError("GenerateClientSecret", err) |
||||||
|
return |
||||||
|
} |
||||||
|
oa.renderEditPage(ctx) |
||||||
|
} |
||||||
|
|
||||||
|
// EditShow displays the given application
|
||||||
|
func (oa *OAuth2CommonHandlers) EditShow(ctx *context.Context) { |
||||||
|
app, err := auth.GetOAuth2ApplicationByID(ctx, ctx.ParamsInt64("id")) |
||||||
|
if err != nil { |
||||||
|
if auth.IsErrOAuthApplicationNotFound(err) { |
||||||
|
ctx.NotFound("Application not found", err) |
||||||
|
return |
||||||
|
} |
||||||
|
ctx.ServerError("GetOAuth2ApplicationByID", err) |
||||||
|
return |
||||||
|
} |
||||||
|
if app.UID != oa.OwnerID { |
||||||
|
ctx.NotFound("Application not found", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
ctx.Data["App"] = app |
||||||
|
oa.renderEditPage(ctx) |
||||||
|
} |
||||||
|
|
||||||
|
// EditSave saves the oauth2 application
|
||||||
|
func (oa *OAuth2CommonHandlers) EditSave(ctx *context.Context) { |
||||||
|
form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm) |
||||||
|
|
||||||
|
if ctx.HasError() { |
||||||
|
oa.renderEditPage(ctx) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// TODO validate redirect URI
|
||||||
|
var err error |
||||||
|
if ctx.Data["App"], err = auth.UpdateOAuth2Application(auth.UpdateOAuth2ApplicationOptions{ |
||||||
|
ID: ctx.ParamsInt64("id"), |
||||||
|
Name: form.Name, |
||||||
|
RedirectURIs: []string{form.RedirectURI}, |
||||||
|
UserID: oa.OwnerID, |
||||||
|
}); err != nil { |
||||||
|
ctx.ServerError("UpdateOAuth2Application", err) |
||||||
|
return |
||||||
|
} |
||||||
|
ctx.Flash.Success(ctx.Tr("settings.update_oauth2_application_success")) |
||||||
|
ctx.Redirect(oa.BasePathList) |
||||||
|
} |
||||||
|
|
||||||
|
// RegenerateSecret regenerates the secret
|
||||||
|
func (oa *OAuth2CommonHandlers) RegenerateSecret(ctx *context.Context) { |
||||||
|
app, err := auth.GetOAuth2ApplicationByID(ctx, ctx.ParamsInt64("id")) |
||||||
|
if err != nil { |
||||||
|
if auth.IsErrOAuthApplicationNotFound(err) { |
||||||
|
ctx.NotFound("Application not found", err) |
||||||
|
return |
||||||
|
} |
||||||
|
ctx.ServerError("GetOAuth2ApplicationByID", err) |
||||||
|
return |
||||||
|
} |
||||||
|
if app.UID != oa.OwnerID { |
||||||
|
ctx.NotFound("Application not found", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
ctx.Data["App"] = app |
||||||
|
ctx.Data["ClientSecret"], err = app.GenerateClientSecret() |
||||||
|
if err != nil { |
||||||
|
ctx.ServerError("GenerateClientSecret", err) |
||||||
|
return |
||||||
|
} |
||||||
|
ctx.Flash.Success(ctx.Tr("settings.update_oauth2_application_success"), true) |
||||||
|
oa.renderEditPage(ctx) |
||||||
|
} |
||||||
|
|
||||||
|
// DeleteApp deletes the given oauth2 application
|
||||||
|
func (oa *OAuth2CommonHandlers) DeleteApp(ctx *context.Context) { |
||||||
|
if err := auth.DeleteOAuth2Application(ctx.ParamsInt64("id"), oa.OwnerID); err != nil { |
||||||
|
ctx.ServerError("DeleteOAuth2Application", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
ctx.Flash.Success(ctx.Tr("settings.remove_oauth2_application_success")) |
||||||
|
ctx.JSON(http.StatusOK, map[string]interface{}{"redirect": oa.BasePathList}) |
||||||
|
} |
||||||
|
|
||||||
|
// RevokeGrant revokes the grant
|
||||||
|
func (oa *OAuth2CommonHandlers) RevokeGrant(ctx *context.Context) { |
||||||
|
if err := auth.RevokeOAuth2Grant(ctx, ctx.ParamsInt64("grantId"), oa.OwnerID); err != nil { |
||||||
|
ctx.ServerError("RevokeOAuth2Grant", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
ctx.Flash.Success(ctx.Tr("settings.revoke_oauth2_grant_success")) |
||||||
|
ctx.JSON(http.StatusOK, map[string]interface{}{"redirect": oa.BasePathList}) |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
{{template "base/head" .}} |
||||||
|
<div class="page-content organization settings options"> |
||||||
|
{{template "org/header" .}} |
||||||
|
<div class="ui container"> |
||||||
|
<div class="ui grid"> |
||||||
|
{{template "org/settings/navbar" .}} |
||||||
|
<div class="twelve wide column content"> |
||||||
|
{{template "base/alert" .}} |
||||||
|
<h4 class="ui top attached header"> |
||||||
|
{{.locale.Tr "settings.applications"}} |
||||||
|
</h4> |
||||||
|
|
||||||
|
{{template "user/settings/applications_oauth2_list" .}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{{template "base/footer" .}} |
@ -0,0 +1,7 @@ |
|||||||
|
{{template "base/head" .}} |
||||||
|
<div class="page-content organization settings options"> |
||||||
|
{{template "org/header" .}} |
||||||
|
|
||||||
|
{{template "user/settings/applications_oauth2_edit_form" .}} |
||||||
|
</div> |
||||||
|
{{template "base/footer" .}} |
@ -1,59 +1,6 @@ |
|||||||
<h4 class="ui top attached header"> |
<h4 class="ui top attached header"> |
||||||
{{.locale.Tr "settings.manage_oauth2_applications"}} |
{{.locale.Tr "settings.manage_oauth2_applications"}} |
||||||
</h4> |
</h4> |
||||||
<div class="ui attached segment"> |
|
||||||
<div class="ui key list"> |
|
||||||
<div class="item"> |
|
||||||
{{.locale.Tr "settings.oauth2_application_create_description"}} |
|
||||||
</div> |
|
||||||
{{range $app := .Applications}} |
|
||||||
<div class="item"> |
|
||||||
<div class="right floated content"> |
|
||||||
<a href="{{$.Link}}/oauth2/{{$app.ID}}" class="ui primary tiny button"> |
|
||||||
{{svg "octicon-pencil" 16 "mr-2"}} |
|
||||||
{{$.locale.Tr "settings.oauth2_application_edit"}} |
|
||||||
</a> |
|
||||||
<button class="ui red tiny button delete-button" data-modal-id="remove-gitea-oauth2-application" |
|
||||||
data-url="{{AppSubUrl}}/user/settings/applications/oauth2/delete" |
|
||||||
data-id="{{$app.ID}}"> |
|
||||||
{{svg "octicon-trash" 16 "mr-2"}} |
|
||||||
{{$.locale.Tr "settings.delete_key"}} |
|
||||||
</button> |
|
||||||
</div> |
|
||||||
<div class="content"> |
|
||||||
<strong>{{$app.Name}}</strong> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
{{end}} |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
<div class="ui attached bottom segment"> |
|
||||||
<h5 class="ui top header"> |
|
||||||
{{.locale.Tr "settings.create_oauth2_application"}} |
|
||||||
</h5> |
|
||||||
<form class="ui form ignore-dirty" action="{{.Link}}/oauth2" method="post"> |
|
||||||
{{.CsrfTokenHtml}} |
|
||||||
<div class="field {{if .Err_AppName}}error{{end}}"> |
|
||||||
<label for="application-name">{{.locale.Tr "settings.oauth2_application_name"}}</label> |
|
||||||
<input id="application-name" name="application_name" value="{{.application_name}}" required> |
|
||||||
</div> |
|
||||||
<div class="field {{if .Err_RedirectURI}}error{{end}}"> |
|
||||||
<label for="redirect-uri">{{.locale.Tr "settings.oauth2_redirect_uri"}}</label> |
|
||||||
<input type="url" name="redirect_uri" id="redirect-uri"> |
|
||||||
</div> |
|
||||||
<button class="ui green button"> |
|
||||||
{{.locale.Tr "settings.create_oauth2_application_button"}} |
|
||||||
</button> |
|
||||||
</form> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div class="ui small basic delete modal" id="remove-gitea-oauth2-application"> |
{{template "user/settings/applications_oauth2_list" .}} |
||||||
<div class="ui icon header"> |
|
||||||
{{svg "octicon-trash"}} |
|
||||||
{{.locale.Tr "settings.remove_oauth2_application"}} |
|
||||||
</div> |
|
||||||
<div class="content"> |
|
||||||
<p>{{.locale.Tr "settings.oauth2_application_remove_description"}}</p> |
|
||||||
</div> |
|
||||||
{{template "base/delete_modal_actions" .}} |
|
||||||
</div> |
|
||||||
|
@ -1,68 +1,8 @@ |
|||||||
{{template "base/head" .}} |
{{template "base/head" .}} |
||||||
<div class="page-content user settings applications"> |
<div class="page-content user settings applications"> |
||||||
{{template "user/settings/navbar" .}} |
{{template "user/settings/navbar" .}} |
||||||
<div class="ui container"> |
|
||||||
{{template "base/alert" .}} |
|
||||||
<h4 class="ui top attached header"> |
|
||||||
{{.locale.Tr "settings.edit_oauth2_application"}} |
|
||||||
</h4> |
|
||||||
<div class="ui attached segment"> |
|
||||||
<p>{{.locale.Tr "settings.oauth2_application_create_description"}}</p> |
|
||||||
</div> |
|
||||||
<div class="ui attached segment form ignore-dirty"> |
|
||||||
{{.CsrfTokenHtml}} |
|
||||||
<div class="field"> |
|
||||||
<label for="client-id">{{.locale.Tr "settings.oauth2_client_id"}}</label> |
|
||||||
<input id="client-id" readonly value="{{.App.ClientID}}"> |
|
||||||
</div> |
|
||||||
{{if .ClientSecret}} |
|
||||||
<div class="field"> |
|
||||||
<label for="client-secret">{{.locale.Tr "settings.oauth2_client_secret"}}</label> |
|
||||||
<input id="client-secret" type="text" readonly value="{{.ClientSecret}}"> |
|
||||||
</div> |
|
||||||
{{else}} |
|
||||||
<div class="field"> |
|
||||||
<label for="client-secret">{{.locale.Tr "settings.oauth2_client_secret"}}</label> |
|
||||||
<input id="client-secret" type="password" readonly value="averysecuresecret"> |
|
||||||
</div> |
|
||||||
{{end}} |
|
||||||
<div class="item"> |
|
||||||
<!-- TODO add regenerate secret functionality */ --> |
|
||||||
{{.locale.Tr "settings.oauth2_regenerate_secret_hint"}} |
|
||||||
<form class="ui form ignore-dirty" action="{{AppSubUrl}}/user/settings/applications/oauth2/{{.App.ID}}/regenerate_secret" method="post"> |
|
||||||
{{.CsrfTokenHtml}} |
|
||||||
<a href="#" onclick="event.target.parentNode.submit()">{{.locale.Tr "settings.oauth2_regenerate_secret"}}</a> |
|
||||||
</form> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
<div class="ui attached bottom segment"> |
|
||||||
<form class="ui form ignore-dirty" action="{{AppSubUrl}}/user/settings/applications/oauth2/{{.App.ID}}" method="post"> |
|
||||||
{{.CsrfTokenHtml}} |
|
||||||
<div class="field {{if .Err_AppName}}error{{end}}"> |
|
||||||
<label for="application-name">{{.locale.Tr "settings.oauth2_application_name"}}</label> |
|
||||||
<input id="application-name" value="{{.App.Name}}" name="application_name" required> |
|
||||||
</div> |
|
||||||
<div class="field {{if .Err_RedirectURI}}error{{end}}"> |
|
||||||
<label for="redirect-uri">{{.locale.Tr "settings.oauth2_redirect_uri"}}</label> |
|
||||||
<input type="url" name="redirect_uri" value="{{.App.PrimaryRedirectURI}}" id="redirect-uri"> |
|
||||||
</div> |
|
||||||
<button class="ui green button"> |
|
||||||
{{.locale.Tr "settings.save_application"}} |
|
||||||
</button> |
|
||||||
</form> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div class="ui small basic delete modal" id="delete-oauth2-application"> |
{{template "user/settings/applications_oauth2_edit_form" .}} |
||||||
<div class="ui icon header"> |
|
||||||
{{svg "octicon-trash"}} |
|
||||||
{{.locale.Tr "settings.remove_oauth2_application"}} |
|
||||||
</div> |
|
||||||
<div class="content"> |
|
||||||
<p>{{.locale.Tr "settings.remove_oauth2_application_desc"}}</p> |
|
||||||
</div> |
|
||||||
{{template "base/delete_modal_actions" .}} |
|
||||||
</div> |
</div> |
||||||
|
|
||||||
{{template "base/footer" .}} |
{{template "base/footer" .}} |
||||||
|
@ -0,0 +1,51 @@ |
|||||||
|
<div class="ui container"> |
||||||
|
{{template "base/alert" .}} |
||||||
|
<h4 class="ui top attached header"> |
||||||
|
{{.locale.Tr "settings.edit_oauth2_application"}} |
||||||
|
</h4> |
||||||
|
<div class="ui attached segment"> |
||||||
|
<p>{{.locale.Tr "settings.oauth2_application_create_description"}}</p> |
||||||
|
</div> |
||||||
|
<div class="ui attached segment form ignore-dirty"> |
||||||
|
{{.CsrfTokenHtml}} |
||||||
|
<div class="field"> |
||||||
|
<label for="client-id">{{.locale.Tr "settings.oauth2_client_id"}}</label> |
||||||
|
<input id="client-id" readonly value="{{.App.ClientID}}"> |
||||||
|
</div> |
||||||
|
{{if .ClientSecret}} |
||||||
|
<div class="field"> |
||||||
|
<label for="client-secret">{{.locale.Tr "settings.oauth2_client_secret"}}</label> |
||||||
|
<input id="client-secret" type="text" readonly value="{{.ClientSecret}}"> |
||||||
|
</div> |
||||||
|
{{else}} |
||||||
|
<div class="field"> |
||||||
|
<label for="client-secret">{{.locale.Tr "settings.oauth2_client_secret"}}</label> |
||||||
|
<input id="client-secret" type="password" readonly value="averysecuresecret"> |
||||||
|
</div> |
||||||
|
{{end}} |
||||||
|
<div class="item"> |
||||||
|
<!-- TODO add regenerate secret functionality */ --> |
||||||
|
<form class="ui form ignore-dirty" action="{{.FormActionPath}}/regenerate_secret" method="post"> |
||||||
|
{{.CsrfTokenHtml}} |
||||||
|
{{.locale.Tr "settings.oauth2_regenerate_secret_hint"}} |
||||||
|
<button class="ui tertiary button" type="submit">{{.locale.Tr "settings.oauth2_regenerate_secret"}}</button> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="ui attached bottom segment"> |
||||||
|
<form class="ui form ignore-dirty" action="{{.FormActionPath}}" method="post"> |
||||||
|
{{.CsrfTokenHtml}} |
||||||
|
<div class="field {{if .Err_AppName}}error{{end}}"> |
||||||
|
<label for="application-name">{{.locale.Tr "settings.oauth2_application_name"}}</label> |
||||||
|
<input id="application-name" value="{{.App.Name}}" name="application_name" required> |
||||||
|
</div> |
||||||
|
<div class="field {{if .Err_RedirectURI}}error{{end}}"> |
||||||
|
<label for="redirect-uri">{{.locale.Tr "settings.oauth2_redirect_uri"}}</label> |
||||||
|
<input type="url" name="redirect_uri" value="{{.App.PrimaryRedirectURI}}" id="redirect-uri"> |
||||||
|
</div> |
||||||
|
<button class="ui green button"> |
||||||
|
{{.locale.Tr "settings.save_application"}} |
||||||
|
</button> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
@ -0,0 +1,55 @@ |
|||||||
|
<div class="ui attached segment"> |
||||||
|
<div class="ui key list"> |
||||||
|
<div class="item"> |
||||||
|
{{.locale.Tr "settings.oauth2_application_create_description"}} |
||||||
|
</div> |
||||||
|
{{range $app := .Applications}} |
||||||
|
<div class="item"> |
||||||
|
<div class="right floated content"> |
||||||
|
<a href="{{$.Link}}/oauth2/{{$app.ID}}" class="ui primary tiny button"> |
||||||
|
{{svg "octicon-pencil" 16 "mr-2"}} |
||||||
|
{{$.locale.Tr "settings.oauth2_application_edit"}} |
||||||
|
</a> |
||||||
|
<button class="ui red tiny button delete-button" data-modal-id="remove-gitea-oauth2-application" |
||||||
|
data-url="{{$.Link}}/oauth2/{{$app.ID}}/delete"> |
||||||
|
{{svg "octicon-trash" 16 "mr-2"}} |
||||||
|
{{$.locale.Tr "settings.delete_key"}} |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
<div class="content"> |
||||||
|
<strong>{{$app.Name}}</strong> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{{end}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="ui attached bottom segment"> |
||||||
|
<h5 class="ui top header"> |
||||||
|
{{.locale.Tr "settings.create_oauth2_application"}} |
||||||
|
</h5> |
||||||
|
<form class="ui form ignore-dirty" action="{{.Link}}/oauth2" method="post"> |
||||||
|
{{.CsrfTokenHtml}} |
||||||
|
<div class="field {{if .Err_AppName}}error{{end}}"> |
||||||
|
<label for="application-name">{{.locale.Tr "settings.oauth2_application_name"}}</label> |
||||||
|
<input id="application-name" name="application_name" value="{{.application_name}}" required> |
||||||
|
</div> |
||||||
|
<div class="field {{if .Err_RedirectURI}}error{{end}}"> |
||||||
|
<label for="redirect-uri">{{.locale.Tr "settings.oauth2_redirect_uri"}}</label> |
||||||
|
<input type="url" name="redirect_uri" id="redirect-uri"> |
||||||
|
</div> |
||||||
|
<button class="ui green button"> |
||||||
|
{{.locale.Tr "settings.create_oauth2_application_button"}} |
||||||
|
</button> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="ui small basic delete modal" id="remove-gitea-oauth2-application"> |
||||||
|
<div class="ui icon header"> |
||||||
|
{{svg "octicon-trash"}} |
||||||
|
{{.locale.Tr "settings.remove_oauth2_application"}} |
||||||
|
</div> |
||||||
|
<div class="content"> |
||||||
|
<p>{{.locale.Tr "settings.oauth2_application_remove_description"}}</p> |
||||||
|
</div> |
||||||
|
{{template "base/delete_modal_actions" .}} |
||||||
|
</div> |
Loading…
Reference in new issue