Add ContextUser to http request context (#18798)

This PR adds a middleware which sets a ContextUser (like GetUserByParams before) in a single place which can be used by other methods. For routes which represent a repo or org the respective middlewares set the field too.

Also fix a bug in modules/context/org.go during refactoring.
This commit is contained in:
KN4CK3R 2022-03-26 10:04:22 +01:00 committed by GitHub
parent f36701c702
commit 59b867dc2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 247 additions and 323 deletions

View file

@ -15,7 +15,6 @@ import (
"code.gitea.io/gitea/modules/convert"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/user"
"code.gitea.io/gitea/routers/api/v1/utils"
)
@ -45,11 +44,8 @@ func CreateOrg(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateOrgOption)
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
visibility := api.VisibleTypePublic
if form.Visibility != "" {
@ -67,7 +63,7 @@ func CreateOrg(ctx *context.APIContext) {
Visibility: visibility,
}
if err := models.CreateOrganization(org, u); err != nil {
if err := models.CreateOrganization(org, ctx.ContextUser); err != nil {
if user_model.IsErrUserAlreadyExist(err) ||
db.IsErrNameReserved(err) ||
db.IsErrNameCharsNotAllowed(err) ||

View file

@ -9,7 +9,6 @@ import (
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/repo"
"code.gitea.io/gitea/routers/api/v1/user"
)
// CreateRepo api for creating a repository
@ -42,11 +41,8 @@ func CreateRepo(ctx *context.APIContext) {
// "$ref": "#/responses/error"
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateRepoOption)
owner := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
repo.CreateUserRepo(ctx, owner, *form)
form := web.GetForm(ctx).(*api.CreateRepoOption)
repo.CreateUserRepo(ctx, ctx.ContextUser, *form)
}

View file

@ -73,6 +73,7 @@ func CreateUser(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateUserOption)
u := &user_model.User{
@ -163,13 +164,10 @@ func EditUser(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.EditUserOption)
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
parseAuthSource(ctx, u, form.SourceID, form.LoginName)
form := web.GetForm(ctx).(*api.EditUserOption)
parseAuthSource(ctx, ctx.ContextUser, form.SourceID, form.LoginName)
if ctx.Written() {
return
}
@ -193,24 +191,24 @@ func EditUser(ctx *context.APIContext) {
ctx.Error(http.StatusBadRequest, "PasswordPwned", errors.New("PasswordPwned"))
return
}
if u.Salt, err = user_model.GetUserSalt(); err != nil {
if ctx.ContextUser.Salt, err = user_model.GetUserSalt(); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)
return
}
if err = u.SetPassword(form.Password); err != nil {
if err = ctx.ContextUser.SetPassword(form.Password); err != nil {
ctx.InternalServerError(err)
return
}
}
if form.MustChangePassword != nil {
u.MustChangePassword = *form.MustChangePassword
ctx.ContextUser.MustChangePassword = *form.MustChangePassword
}
u.LoginName = form.LoginName
ctx.ContextUser.LoginName = form.LoginName
if form.FullName != nil {
u.FullName = *form.FullName
ctx.ContextUser.FullName = *form.FullName
}
var emailChanged bool
if form.Email != nil {
@ -225,47 +223,47 @@ func EditUser(ctx *context.APIContext) {
return
}
emailChanged = !strings.EqualFold(u.Email, email)
u.Email = email
emailChanged = !strings.EqualFold(ctx.ContextUser.Email, email)
ctx.ContextUser.Email = email
}
if form.Website != nil {
u.Website = *form.Website
ctx.ContextUser.Website = *form.Website
}
if form.Location != nil {
u.Location = *form.Location
ctx.ContextUser.Location = *form.Location
}
if form.Description != nil {
u.Description = *form.Description
ctx.ContextUser.Description = *form.Description
}
if form.Active != nil {
u.IsActive = *form.Active
ctx.ContextUser.IsActive = *form.Active
}
if len(form.Visibility) != 0 {
u.Visibility = api.VisibilityModes[form.Visibility]
ctx.ContextUser.Visibility = api.VisibilityModes[form.Visibility]
}
if form.Admin != nil {
u.IsAdmin = *form.Admin
ctx.ContextUser.IsAdmin = *form.Admin
}
if form.AllowGitHook != nil {
u.AllowGitHook = *form.AllowGitHook
ctx.ContextUser.AllowGitHook = *form.AllowGitHook
}
if form.AllowImportLocal != nil {
u.AllowImportLocal = *form.AllowImportLocal
ctx.ContextUser.AllowImportLocal = *form.AllowImportLocal
}
if form.MaxRepoCreation != nil {
u.MaxRepoCreation = *form.MaxRepoCreation
ctx.ContextUser.MaxRepoCreation = *form.MaxRepoCreation
}
if form.AllowCreateOrganization != nil {
u.AllowCreateOrganization = *form.AllowCreateOrganization
ctx.ContextUser.AllowCreateOrganization = *form.AllowCreateOrganization
}
if form.ProhibitLogin != nil {
u.ProhibitLogin = *form.ProhibitLogin
ctx.ContextUser.ProhibitLogin = *form.ProhibitLogin
}
if form.Restricted != nil {
u.IsRestricted = *form.Restricted
ctx.ContextUser.IsRestricted = *form.Restricted
}
if err := user_model.UpdateUser(u, emailChanged); err != nil {
if err := user_model.UpdateUser(ctx.ContextUser, emailChanged); err != nil {
if user_model.IsErrEmailAlreadyUsed(err) ||
user_model.IsErrEmailCharIsNotSupported(err) ||
user_model.IsErrEmailInvalid(err) {
@ -275,9 +273,9 @@ func EditUser(ctx *context.APIContext) {
}
return
}
log.Trace("Account profile updated by admin (%s): %s", ctx.Doer.Name, u.Name)
log.Trace("Account profile updated by admin (%s): %s", ctx.Doer.Name, ctx.ContextUser.Name)
ctx.JSON(http.StatusOK, convert.ToUser(u, ctx.Doer))
ctx.JSON(http.StatusOK, convert.ToUser(ctx.ContextUser, ctx.Doer))
}
// DeleteUser api for deleting a user
@ -301,17 +299,12 @@ func DeleteUser(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
u := user.GetUserByParams(ctx)
if ctx.Written() {
if ctx.ContextUser.IsOrganization() {
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("%s is an organization not a user", ctx.ContextUser.Name))
return
}
if u.IsOrganization() {
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("%s is an organization not a user", u.Name))
return
}
if err := user_service.DeleteUser(u); err != nil {
if err := user_service.DeleteUser(ctx.ContextUser); err != nil {
if models.IsErrUserOwnRepos(err) ||
models.IsErrUserHasOrgs(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err)
@ -320,7 +313,7 @@ func DeleteUser(ctx *context.APIContext) {
}
return
}
log.Trace("Account deleted by admin(%s): %s", ctx.Doer.Name, u.Name)
log.Trace("Account deleted by admin(%s): %s", ctx.Doer.Name, ctx.ContextUser.Name)
ctx.Status(http.StatusNoContent)
}
@ -351,12 +344,10 @@ func CreatePublicKey(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateKeyOption)
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
user.CreateUserPublicKey(ctx, *form, u.ID)
user.CreateUserPublicKey(ctx, *form, ctx.ContextUser.ID)
}
// DeleteUserPublicKey api for deleting a user's public key
@ -386,12 +377,7 @@ func DeleteUserPublicKey(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
if err := asymkey_service.DeletePublicKey(u, ctx.ParamsInt64(":id")); err != nil {
if err := asymkey_service.DeletePublicKey(ctx.ContextUser, ctx.ParamsInt64(":id")); err != nil {
if asymkey_model.IsErrKeyNotExist(err) {
ctx.NotFound()
} else if asymkey_model.IsErrKeyAccessDenied(err) {
@ -401,7 +387,7 @@ func DeleteUserPublicKey(ctx *context.APIContext) {
}
return
}
log.Trace("Key deleted by admin(%s): %s", ctx.Doer.Name, u.Name)
log.Trace("Key deleted by admin(%s): %s", ctx.Doer.Name, ctx.ContextUser.Name)
ctx.Status(http.StatusNoContent)
}

View file

@ -87,6 +87,7 @@ import (
"code.gitea.io/gitea/routers/api/v1/settings"
"code.gitea.io/gitea/routers/api/v1/user"
"code.gitea.io/gitea/services/auth"
context_service "code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
_ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation
@ -156,6 +157,7 @@ func repoAssignment() func(ctx *context.APIContext) {
}
}
ctx.Repo.Owner = owner
ctx.ContextUser = owner
// Get repository.
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
@ -441,6 +443,7 @@ func orgAssignment(args ...bool) func(ctx *context.APIContext) {
}
return
}
ctx.ContextUser = ctx.Org.Organization.AsUser()
}
if assignTeam {
@ -636,7 +639,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
Post(bind(api.CreateAccessTokenOption{}), user.CreateAccessToken)
m.Combo("/{id}").Delete(user.DeleteAccessToken)
}, reqBasicOrRevProxyAuth())
})
}, context_service.UserAssignmentAPI())
})
m.Group("/users", func() {
@ -653,7 +656,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
m.Get("/starred", user.GetStarredRepos)
m.Get("/subscriptions", user.GetWatchedRepos)
})
}, context_service.UserAssignmentAPI())
}, reqToken())
m.Group("/user", func() {
@ -669,7 +672,11 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
m.Get("/followers", user.ListMyFollowers)
m.Group("/following", func() {
m.Get("", user.ListMyFollowing)
m.Combo("/{username}").Get(user.CheckMyFollowing).Put(user.Follow).Delete(user.Unfollow)
m.Group("/{username}", func() {
m.Get("", user.CheckMyFollowing)
m.Put("", user.Follow)
m.Delete("", user.Unfollow)
}, context_service.UserAssignmentAPI())
})
m.Group("/keys", func() {
@ -1005,7 +1012,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
m.Group("/users/{username}/orgs", func() {
m.Get("", org.ListUserOrgs)
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
})
}, context_service.UserAssignmentAPI())
m.Post("/orgs", reqToken(), bind(api.CreateOrgOption{}), org.Create)
m.Get("/orgs", org.GetAll)
m.Group("/orgs/{org}", func() {
@ -1083,7 +1090,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
m.Get("/orgs", org.ListUserOrgs)
m.Post("/orgs", bind(api.CreateOrgOption{}), admin.CreateOrg)
m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo)
})
}, context_service.UserAssignmentAPI())
})
m.Group("/unadopted", func() {
m.Get("", admin.ListUnadoptedRepositories)

View file

@ -99,11 +99,7 @@ func ListUserOrgs(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/OrganizationList"
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
listUserOrgs(ctx, u)
listUserOrgs(ctx, ctx.ContextUser)
}
// GetUserOrgsPermissions get user permissions in organization
@ -132,11 +128,6 @@ func GetUserOrgsPermissions(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
var u *user_model.User
if u = user.GetUserByParams(ctx); u == nil {
return
}
var o *user_model.User
if o = user.GetUserByParamsName(ctx, ":org"); o == nil {
return
@ -144,13 +135,13 @@ func GetUserOrgsPermissions(ctx *context.APIContext) {
op := api.OrganizationPermissions{}
if !models.HasOrgOrUserVisible(o, u) {
if !models.HasOrgOrUserVisible(o, ctx.ContextUser) {
ctx.NotFound("HasOrgOrUserVisible", nil)
return
}
org := models.OrgFromUser(o)
authorizeLevel, err := org.GetOrgUserMaxAuthorizeLevel(u.ID)
authorizeLevel, err := org.GetOrgUserMaxAuthorizeLevel(ctx.ContextUser.ID)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetOrgUserAuthorizeLevel", err)
return
@ -169,7 +160,7 @@ func GetUserOrgsPermissions(ctx *context.APIContext) {
op.IsOwner = true
}
op.CanCreateRepository, err = org.CanCreateOrgRepo(u.ID)
op.CanCreateRepository, err = org.CanCreateOrgRepo(ctx.ContextUser.ID)
if err != nil {
ctx.Error(http.StatusInternalServerError, "CanCreateOrgRepo", err)
return

View file

@ -82,11 +82,7 @@ func ListFollowers(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/UserList"
u := GetUserByParams(ctx)
if ctx.Written() {
return
}
listUserFollowers(ctx, u)
listUserFollowers(ctx, ctx.ContextUser)
}
func listUserFollowing(ctx *context.APIContext, u *user_model.User) {
@ -148,11 +144,7 @@ func ListFollowing(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/UserList"
u := GetUserByParams(ctx)
if ctx.Written() {
return
}
listUserFollowing(ctx, u)
listUserFollowing(ctx, ctx.ContextUser)
}
func checkUserFollowing(ctx *context.APIContext, u *user_model.User, followID int64) {
@ -180,25 +172,21 @@ func CheckMyFollowing(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
target := GetUserByParams(ctx)
if ctx.Written() {
return
}
checkUserFollowing(ctx, ctx.Doer, target.ID)
checkUserFollowing(ctx, ctx.Doer, ctx.ContextUser.ID)
}
// CheckFollowing check if one user is following another user
func CheckFollowing(ctx *context.APIContext) {
// swagger:operation GET /users/{follower}/following/{followee} user userCheckFollowing
// swagger:operation GET /users/{username}/following/{target} user userCheckFollowing
// ---
// summary: Check if one user is following another user
// parameters:
// - name: follower
// - name: username
// in: path
// description: username of following user
// type: string
// required: true
// - name: followee
// - name: target
// in: path
// description: username of followed user
// type: string
@ -209,15 +197,11 @@ func CheckFollowing(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
u := GetUserByParams(ctx)
if ctx.Written() {
return
}
target := GetUserByParamsName(ctx, ":target")
if ctx.Written() {
return
}
checkUserFollowing(ctx, u, target.ID)
checkUserFollowing(ctx, ctx.ContextUser, target.ID)
}
// Follow follow a user
@ -235,11 +219,7 @@ func Follow(ctx *context.APIContext) {
// "204":
// "$ref": "#/responses/empty"
target := GetUserByParams(ctx)
if ctx.Written() {
return
}
if err := user_model.FollowUser(ctx.Doer.ID, target.ID); err != nil {
if err := user_model.FollowUser(ctx.Doer.ID, ctx.ContextUser.ID); err != nil {
ctx.Error(http.StatusInternalServerError, "FollowUser", err)
return
}
@ -261,11 +241,7 @@ func Unfollow(ctx *context.APIContext) {
// "204":
// "$ref": "#/responses/empty"
target := GetUserByParams(ctx)
if ctx.Written() {
return
}
if err := user_model.UnfollowUser(ctx.Doer.ID, target.ID); err != nil {
if err := user_model.UnfollowUser(ctx.Doer.ID, ctx.ContextUser.ID); err != nil {
ctx.Error(http.StatusInternalServerError, "UnfollowUser", err)
return
}

View file

@ -64,11 +64,7 @@ func ListGPGKeys(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/GPGKeyList"
user := GetUserByParams(ctx)
if ctx.Written() {
return
}
listGPGKeys(ctx, user.ID, utils.GetListOptions(ctx))
listGPGKeys(ctx, ctx.ContextUser.ID, utils.GetListOptions(ctx))
}
// ListMyGPGKeys get the GPG key list of the authenticated user

View file

@ -151,11 +151,7 @@ func ListPublicKeys(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/PublicKeyList"
user := GetUserByParams(ctx)
if ctx.Written() {
return
}
listPublicKeys(ctx, user)
listPublicKeys(ctx, ctx.ContextUser)
}
// GetPublicKey get a public key

View file

@ -78,12 +78,8 @@ func ListUserRepos(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/RepositoryList"
user := GetUserByParams(ctx)
if ctx.Written() {
return
}
private := ctx.IsSigned
listUserRepos(ctx, user, private)
listUserRepos(ctx, ctx.ContextUser, private)
}
// ListMyRepos - list the repositories you own or have access to.

View file

@ -62,15 +62,14 @@ func GetStarredRepos(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/RepositoryList"
user := GetUserByParams(ctx)
private := user.ID == ctx.Doer.ID
repos, err := getStarredRepos(user, private, utils.GetListOptions(ctx))
private := ctx.ContextUser.ID == ctx.Doer.ID
repos, err := getStarredRepos(ctx.ContextUser, private, utils.GetListOptions(ctx))
if err != nil {
ctx.Error(http.StatusInternalServerError, "getStarredRepos", err)
return
}
ctx.SetTotalCountHeader(int64(user.NumStars))
ctx.SetTotalCountHeader(int64(ctx.ContextUser.NumStars))
ctx.JSON(http.StatusOK, &repos)
}

View file

@ -98,18 +98,12 @@ func GetInfo(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
u := GetUserByParams(ctx)
if ctx.Written() {
return
}
if !models.IsUserVisibleToViewer(u, ctx.Doer) {
if !models.IsUserVisibleToViewer(ctx.ContextUser, ctx.Doer) {
// fake ErrUserNotExist error message to not leak information about existence
ctx.NotFound("GetUserByName", user_model.ErrUserNotExist{Name: ctx.Params(":username")})
return
}
ctx.JSON(http.StatusOK, convert.ToUser(u, ctx.Doer))
ctx.JSON(http.StatusOK, convert.ToUser(ctx.ContextUser, ctx.Doer))
}
// GetAuthenticatedUser get current user's information
@ -145,12 +139,7 @@ func GetUserHeatmapData(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
user := GetUserByParams(ctx)
if ctx.Written() {
return
}
heatmap, err := models.GetUserHeatmapDataByUser(user, ctx.Doer)
heatmap, err := models.GetUserHeatmapDataByUser(ctx.ContextUser, ctx.Doer)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserHeatmapDataByUser", err)
return

View file

@ -60,9 +60,8 @@ func GetWatchedRepos(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/RepositoryList"
user := GetUserByParams(ctx)
private := user.ID == ctx.Doer.ID
repos, total, err := getWatchedRepos(user, private, utils.GetListOptions(ctx))
private := ctx.ContextUser.ID == ctx.Doer.ID
repos, total, err := getWatchedRepos(ctx.ContextUser, private, utils.GetListOptions(ctx))
if err != nil {
ctx.Error(http.StatusInternalServerError, "getWatchedRepos", err)
}