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>
This commit is contained in:
		
							parent
							
								
									97f3f1988b
								
							
						
					
					
						commit
						a813c9d8f3
					
				
					 15 changed files with 439 additions and 235 deletions
				
			
		
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -225,7 +225,8 @@ func updateOAuth2Application(ctx context.Context, app *OAuth2Application) error
 | 
			
		|||
 | 
			
		||||
func deleteOAuth2Application(ctx context.Context, id, userid int64) error {
 | 
			
		||||
	sess := db.GetEngine(ctx)
 | 
			
		||||
	if deleted, err := sess.Delete(&OAuth2Application{ID: id, UID: userid}); err != nil {
 | 
			
		||||
	// the userid could be 0 if the app is instance-wide
 | 
			
		||||
	if deleted, err := sess.Where(builder.Eq{"id": id, "uid": userid}).Delete(&OAuth2Application{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if deleted == 0 {
 | 
			
		||||
		return ErrOAuthApplicationNotFound{ID: id}
 | 
			
		||||
| 
						 | 
				
			
			@ -476,7 +477,7 @@ func GetOAuth2GrantsByUserID(ctx context.Context, uid int64) ([]*OAuth2Grant, er
 | 
			
		|||
 | 
			
		||||
// RevokeOAuth2Grant deletes the grant with grantID and userID
 | 
			
		||||
func RevokeOAuth2Grant(ctx context.Context, grantID, userID int64) error {
 | 
			
		||||
	_, err := db.DeleteByBean(ctx, &OAuth2Grant{ID: grantID, UserID: userID})
 | 
			
		||||
	_, err := db.GetEngine(ctx).Where(builder.Eq{"id": grantID, "user_id": userID}).Delete(&OAuth2Grant{})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										93
									
								
								routers/web/org/setting_oauth2.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								routers/web/org/setting_oauth2.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -5,79 +5,40 @@
 | 
			
		|||
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/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/web"
 | 
			
		||||
	"code.gitea.io/gitea/services/forms"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	tplSettingsOAuthApplications base.TplName = "user/settings/applications_oauth2_edit"
 | 
			
		||||
	tplSettingsOAuthApplicationEdit base.TplName = "user/settings/applications_oauth2_edit"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func newOAuth2CommonHandlers(userID int64) *OAuth2CommonHandlers {
 | 
			
		||||
	return &OAuth2CommonHandlers{
 | 
			
		||||
		OwnerID:            userID,
 | 
			
		||||
		BasePathList:       setting.AppSubURL + "/user/settings/applications",
 | 
			
		||||
		BasePathEditPrefix: setting.AppSubURL + "/user/settings/applications/oauth2",
 | 
			
		||||
		TplAppEdit:         tplSettingsOAuthApplicationEdit,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OAuthApplicationsPost response for adding a oauth2 application
 | 
			
		||||
func OAuthApplicationsPost(ctx *context.Context) {
 | 
			
		||||
	form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm)
 | 
			
		||||
	ctx.Data["Title"] = ctx.Tr("settings")
 | 
			
		||||
	ctx.Data["PageIsSettingsApplications"] = true
 | 
			
		||||
 | 
			
		||||
	if ctx.HasError() {
 | 
			
		||||
		loadApplicationsData(ctx)
 | 
			
		||||
 | 
			
		||||
		ctx.HTML(http.StatusOK, tplSettingsApplications)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// TODO validate redirect URI
 | 
			
		||||
	app, err := auth.CreateOAuth2Application(ctx, auth.CreateOAuth2ApplicationOptions{
 | 
			
		||||
		Name:         form.Name,
 | 
			
		||||
		RedirectURIs: []string{form.RedirectURI},
 | 
			
		||||
		UserID:       ctx.Doer.ID,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.ServerError("CreateOAuth2Application", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Flash.Success(ctx.Tr("settings.create_oauth2_application_success"))
 | 
			
		||||
	ctx.Data["App"] = app
 | 
			
		||||
	ctx.Data["ClientSecret"], err = app.GenerateClientSecret()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.ServerError("GenerateClientSecret", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
 | 
			
		||||
	oa := newOAuth2CommonHandlers(ctx.Doer.ID)
 | 
			
		||||
	oa.AddApp(ctx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OAuthApplicationsEdit response for editing oauth2 application
 | 
			
		||||
func OAuthApplicationsEdit(ctx *context.Context) {
 | 
			
		||||
	form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm)
 | 
			
		||||
	ctx.Data["Title"] = ctx.Tr("settings")
 | 
			
		||||
	ctx.Data["PageIsSettingsApplications"] = true
 | 
			
		||||
 | 
			
		||||
	if ctx.HasError() {
 | 
			
		||||
		loadApplicationsData(ctx)
 | 
			
		||||
 | 
			
		||||
		ctx.HTML(http.StatusOK, tplSettingsApplications)
 | 
			
		||||
		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:       ctx.Doer.ID,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		ctx.ServerError("UpdateOAuth2Application", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Flash.Success(ctx.Tr("settings.update_oauth2_application_success"))
 | 
			
		||||
	ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
 | 
			
		||||
	oa := newOAuth2CommonHandlers(ctx.Doer.ID)
 | 
			
		||||
	oa.EditSave(ctx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OAuthApplicationsRegenerateSecret handles the post request for regenerating the secret
 | 
			
		||||
| 
						 | 
				
			
			@ -85,75 +46,24 @@ func OAuthApplicationsRegenerateSecret(ctx *context.Context) {
 | 
			
		|||
	ctx.Data["Title"] = ctx.Tr("settings")
 | 
			
		||||
	ctx.Data["PageIsSettingsApplications"] = true
 | 
			
		||||
 | 
			
		||||
	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 != ctx.Doer.ID {
 | 
			
		||||
		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"))
 | 
			
		||||
	ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
 | 
			
		||||
	oa := newOAuth2CommonHandlers(ctx.Doer.ID)
 | 
			
		||||
	oa.RegenerateSecret(ctx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OAuth2ApplicationShow displays the given application
 | 
			
		||||
func OAuth2ApplicationShow(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 != ctx.Doer.ID {
 | 
			
		||||
		ctx.NotFound("Application not found", nil)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["App"] = app
 | 
			
		||||
	ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
 | 
			
		||||
	oa := newOAuth2CommonHandlers(ctx.Doer.ID)
 | 
			
		||||
	oa.EditShow(ctx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteOAuth2Application deletes the given oauth2 application
 | 
			
		||||
func DeleteOAuth2Application(ctx *context.Context) {
 | 
			
		||||
	if err := auth.DeleteOAuth2Application(ctx.FormInt64("id"), ctx.Doer.ID); err != nil {
 | 
			
		||||
		ctx.ServerError("DeleteOAuth2Application", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	log.Trace("OAuth2 Application deleted: %s", ctx.Doer.Name)
 | 
			
		||||
 | 
			
		||||
	ctx.Flash.Success(ctx.Tr("settings.remove_oauth2_application_success"))
 | 
			
		||||
	ctx.JSON(http.StatusOK, map[string]interface{}{
 | 
			
		||||
		"redirect": setting.AppSubURL + "/user/settings/applications",
 | 
			
		||||
	})
 | 
			
		||||
	oa := newOAuth2CommonHandlers(ctx.Doer.ID)
 | 
			
		||||
	oa.DeleteApp(ctx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RevokeOAuth2Grant revokes the grant with the given id
 | 
			
		||||
func RevokeOAuth2Grant(ctx *context.Context) {
 | 
			
		||||
	if ctx.Doer.ID == 0 || ctx.FormInt64("id") == 0 {
 | 
			
		||||
		ctx.ServerError("RevokeOAuth2Grant", fmt.Errorf("user id or grant id is zero"))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err := auth.RevokeOAuth2Grant(ctx, ctx.FormInt64("id"), ctx.Doer.ID); 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": setting.AppSubURL + "/user/settings/applications",
 | 
			
		||||
	})
 | 
			
		||||
	oa := newOAuth2CommonHandlers(ctx.Doer.ID)
 | 
			
		||||
	oa.RevokeGrant(ctx)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										150
									
								
								routers/web/user/setting/oauth2_common.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								routers/web/user/setting/oauth2_common.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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})
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -427,8 +427,8 @@ func RegisterRoutes(m *web.Route) {
 | 
			
		|||
			m.Post("/{id}", bindIgnErr(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsEdit)
 | 
			
		||||
			m.Post("/{id}/regenerate_secret", user_setting.OAuthApplicationsRegenerateSecret)
 | 
			
		||||
			m.Post("", bindIgnErr(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsPost)
 | 
			
		||||
			m.Post("/delete", user_setting.DeleteOAuth2Application)
 | 
			
		||||
			m.Post("/revoke", user_setting.RevokeOAuth2Grant)
 | 
			
		||||
			m.Post("/{id}/delete", user_setting.DeleteOAuth2Application)
 | 
			
		||||
			m.Post("/{id}/revoke/{grantId}", user_setting.RevokeOAuth2Grant)
 | 
			
		||||
		})
 | 
			
		||||
		m.Combo("/applications").Get(user_setting.Applications).
 | 
			
		||||
			Post(bindIgnErr(forms.NewAccessTokenForm{}), user_setting.ApplicationsPost)
 | 
			
		||||
| 
						 | 
				
			
			@ -662,6 +662,20 @@ func RegisterRoutes(m *web.Route) {
 | 
			
		|||
					Post(bindIgnErr(forms.UpdateOrgSettingForm{}), org.SettingsPost)
 | 
			
		||||
				m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), org.SettingsAvatar)
 | 
			
		||||
				m.Post("/avatar/delete", org.SettingsDeleteAvatar)
 | 
			
		||||
				m.Group("/applications", func() {
 | 
			
		||||
					m.Get("", org.Applications)
 | 
			
		||||
					m.Post("/oauth2", bindIgnErr(forms.EditOAuth2ApplicationForm{}), org.OAuthApplicationsPost)
 | 
			
		||||
					m.Group("/oauth2/{id}", func() {
 | 
			
		||||
						m.Combo("").Get(org.OAuth2ApplicationShow).Post(bindIgnErr(forms.EditOAuth2ApplicationForm{}), org.OAuth2ApplicationEdit)
 | 
			
		||||
						m.Post("/regenerate_secret", org.OAuthApplicationsRegenerateSecret)
 | 
			
		||||
						m.Post("/delete", org.DeleteOAuth2Application)
 | 
			
		||||
					})
 | 
			
		||||
				}, func(ctx *context.Context) {
 | 
			
		||||
					if !setting.OAuth2.Enable {
 | 
			
		||||
						ctx.Error(http.StatusForbidden)
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
				})
 | 
			
		||||
 | 
			
		||||
				m.Group("/hooks", func() {
 | 
			
		||||
					m.Get("", org.Webhooks)
 | 
			
		||||
| 
						 | 
				
			
			@ -702,6 +716,8 @@ func RegisterRoutes(m *web.Route) {
 | 
			
		|||
				})
 | 
			
		||||
 | 
			
		||||
				m.Route("/delete", "GET,POST", org.SettingsDelete)
 | 
			
		||||
			}, func(ctx *context.Context) {
 | 
			
		||||
				ctx.Data["EnableOAuth2"] = setting.OAuth2.Enable
 | 
			
		||||
			})
 | 
			
		||||
		}, context.OrgAssignment(true, true))
 | 
			
		||||
	}, reqSignIn)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								templates/org/settings/applications.tmpl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								templates/org/settings/applications.tmpl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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" .}}
 | 
			
		||||
							
								
								
									
										7
									
								
								templates/org/settings/applications_oauth2_edit.tmpl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								templates/org/settings/applications_oauth2_edit.tmpl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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" .}}
 | 
			
		||||
| 
						 | 
				
			
			@ -12,6 +12,11 @@
 | 
			
		|||
		<a class="{{if .PageIsOrgSettingsLabels}}active{{end}} item" href="{{.OrgLink}}/settings/labels">
 | 
			
		||||
			{{.locale.Tr "repo.labels"}}
 | 
			
		||||
		</a>
 | 
			
		||||
		{{if .EnableOAuth2}}
 | 
			
		||||
		<a class="{{if .PageIsSettingsApplications}}active{{end}} item" href="{{.OrgLink}}/settings/applications">
 | 
			
		||||
			{{.locale.Tr "settings.applications"}}
 | 
			
		||||
		</a>
 | 
			
		||||
		{{end}}
 | 
			
		||||
		<a class="{{if .PageIsSettingsDelete}}active{{end}} item" href="{{.OrgLink}}/settings/delete">
 | 
			
		||||
			{{.locale.Tr "org.settings.delete"}}
 | 
			
		||||
		</a>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,59 +1,6 @@
 | 
			
		|||
<h4 class="ui top attached header">
 | 
			
		||||
	{{.locale.Tr "settings.manage_oauth2_applications"}}
 | 
			
		||||
</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">
 | 
			
		||||
	<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>
 | 
			
		||||
{{template "user/settings/applications_oauth2_list" .}}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,68 +1,8 @@
 | 
			
		|||
{{template "base/head" .}}
 | 
			
		||||
<div class="page-content user settings applications">
 | 
			
		||||
	{{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">
 | 
			
		||||
	<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" .}}
 | 
			
		||||
	{{template "user/settings/applications_oauth2_edit_form" .}}
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{{template "base/footer" .}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										51
									
								
								templates/user/settings/applications_oauth2_edit_form.tmpl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								templates/user/settings/applications_oauth2_edit_form.tmpl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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>
 | 
			
		||||
							
								
								
									
										55
									
								
								templates/user/settings/applications_oauth2_list.tmpl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								templates/user/settings/applications_oauth2_list.tmpl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			@ -10,8 +10,7 @@
 | 
			
		|||
			<div class="item">
 | 
			
		||||
				<div class="right floated content">
 | 
			
		||||
					<button class="ui red tiny button delete-button" data-modal-id="revoke-gitea-oauth2-grant"
 | 
			
		||||
							data-url="{{AppSubUrl}}/user/settings/applications/oauth2/revoke"
 | 
			
		||||
							data-id="{{$grant.ID}}">
 | 
			
		||||
							data-url="{{AppSubUrl}}/user/settings/applications/oauth2/{{$grant.ApplicationID}}/revoke/{{$grant.ID}}">
 | 
			
		||||
						{{$.locale.Tr "settings.revoke_key"}}
 | 
			
		||||
					</button>
 | 
			
		||||
				</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1804,7 +1804,9 @@ a.ui.label:hover {
 | 
			
		|||
  border: 1px solid var(--color-light-border);
 | 
			
		||||
  color: var(--color-text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ui.tertiary.button {
 | 
			
		||||
  border: none;
 | 
			
		||||
}
 | 
			
		||||
.page-content .ui.button {
 | 
			
		||||
  box-shadow: none !important;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue