1
0
Fork 0
forked from forgejo/forgejo

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

@ -9,19 +9,28 @@ import (
"time"
"code.gitea.io/gitea/models"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"github.com/gorilla/feeds"
)
// ShowUserFeed show user activity as RSS / Atom feed
func ShowUserFeed(ctx *context.Context, ctxUser *user_model.User, formatType string) {
// ShowUserFeedRSS show user activity as RSS feed
func ShowUserFeedRSS(ctx *context.Context) {
showUserFeed(ctx, "rss")
}
// ShowUserFeedAtom show user activity as Atom feed
func ShowUserFeedAtom(ctx *context.Context) {
showUserFeed(ctx, "atom")
}
// showUserFeed show user activity as RSS / Atom feed
func showUserFeed(ctx *context.Context, formatType string) {
actions, err := models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctxUser,
RequestedUser: ctx.ContextUser,
Actor: ctx.Doer,
IncludePrivate: false,
OnlyPerformedBy: !ctxUser.IsOrganization(),
OnlyPerformedBy: !ctx.ContextUser.IsOrganization(),
IncludeDeleted: false,
Date: ctx.FormString("date"),
})
@ -31,9 +40,9 @@ func ShowUserFeed(ctx *context.Context, ctxUser *user_model.User, formatType str
}
feed := &feeds.Feed{
Title: ctx.Tr("home.feed_of", ctxUser.DisplayName()),
Link: &feeds.Link{Href: ctxUser.HTMLURL()},
Description: ctxUser.Description,
Title: ctx.Tr("home.feed_of", ctx.ContextUser.DisplayName()),
Link: &feeds.Link{Href: ctx.ContextUser.HTMLURL()},
Description: ctx.ContextUser.Description,
Created: time.Now(),
}

View file

@ -24,7 +24,6 @@ import (
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
@ -110,19 +109,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
reponame = reponame[:len(reponame)-5]
}
owner, err := user_model.GetUserByName(username)
if err != nil {
if user_model.IsErrUserNotExist(err) {
if redirectUserID, err := user_model.LookupUserRedirect(username); err == nil {
context.RedirectToUser(ctx, username, redirectUserID)
} else {
ctx.NotFound(fmt.Sprintf("User %s does not exist", username), nil)
}
} else {
ctx.ServerError("GetUserByName", err)
}
return
}
owner := ctx.ContextUser
if !owner.IsOrganization() && !owner.IsActive {
ctx.PlainText(http.StatusForbidden, "Repository cannot be accessed. You cannot push or open issues/pull-requests.")
return

View file

@ -756,8 +756,8 @@ func loadRepoByIDs(ctxUser *user_model.User, issueCountByRepo map[int64]int64, u
}
// ShowSSHKeys output all the ssh keys of user by uid
func ShowSSHKeys(ctx *context.Context, uid int64) {
keys, err := asymkey_model.ListPublicKeys(uid, db.ListOptions{})
func ShowSSHKeys(ctx *context.Context) {
keys, err := asymkey_model.ListPublicKeys(ctx.ContextUser.ID, db.ListOptions{})
if err != nil {
ctx.ServerError("ListPublicKeys", err)
return
@ -772,8 +772,8 @@ func ShowSSHKeys(ctx *context.Context, uid int64) {
}
// ShowGPGKeys output all the public GPG keys of user by uid
func ShowGPGKeys(ctx *context.Context, uid int64) {
keys, err := asymkey_model.ListGPGKeys(ctx, uid, db.ListOptions{})
func ShowGPGKeys(ctx *context.Context) {
keys, err := asymkey_model.ListGPGKeys(ctx, ctx.ContextUser.ID, db.ListOptions{})
if err != nil {
ctx.ServerError("ListGPGKeys", err)
return

View file

@ -8,7 +8,6 @@ package user
import (
"fmt"
"net/http"
"path"
"strings"
"code.gitea.io/gitea/models"
@ -24,121 +23,51 @@ import (
"code.gitea.io/gitea/routers/web/org"
)
// GetUserByName get user by name
func GetUserByName(ctx *context.Context, name string) *user_model.User {
user, err := user_model.GetUserByName(name)
if err != nil {
if user_model.IsErrUserNotExist(err) {
if redirectUserID, err := user_model.LookupUserRedirect(name); err == nil {
context.RedirectToUser(ctx, name, redirectUserID)
} else {
ctx.NotFound("GetUserByName", err)
}
} else {
ctx.ServerError("GetUserByName", err)
}
return nil
}
return user
}
// GetUserByParams returns user whose name is presented in URL paramenter.
func GetUserByParams(ctx *context.Context) *user_model.User {
return GetUserByName(ctx, ctx.Params(":username"))
}
// Profile render user's profile page
func Profile(ctx *context.Context) {
uname := ctx.Params(":username")
// Special handle for FireFox requests favicon.ico.
if uname == "favicon.ico" {
ctx.ServeFile(path.Join(setting.StaticRootPath, "public/img/favicon.png"))
if strings.Contains(ctx.Req.Header.Get("Accept"), "application/rss+xml") {
feed.ShowUserFeedRSS(ctx)
return
}
if strings.Contains(ctx.Req.Header.Get("Accept"), "application/atom+xml") {
feed.ShowUserFeedAtom(ctx)
return
}
if strings.HasSuffix(uname, ".png") {
ctx.Error(http.StatusNotFound)
return
}
isShowKeys := false
if strings.HasSuffix(uname, ".keys") {
isShowKeys = true
uname = strings.TrimSuffix(uname, ".keys")
}
isShowGPG := false
if strings.HasSuffix(uname, ".gpg") {
isShowGPG = true
uname = strings.TrimSuffix(uname, ".gpg")
}
isShowFeed, uname, showFeedType := feed.GetFeedType(uname, ctx.Req)
ctxUser := GetUserByName(ctx, uname)
if ctx.Written() {
return
}
if ctxUser.IsOrganization() {
// Show Org RSS feed
if isShowFeed {
feed.ShowUserFeed(ctx, ctxUser, showFeedType)
return
}
if ctx.ContextUser.IsOrganization() {
org.Home(ctx)
return
}
// check view permissions
if !models.IsUserVisibleToViewer(ctxUser, ctx.Doer) {
ctx.NotFound("user", fmt.Errorf(uname))
return
}
// Show SSH keys.
if isShowKeys {
ShowSSHKeys(ctx, ctxUser.ID)
return
}
// Show GPG keys.
if isShowGPG {
ShowGPGKeys(ctx, ctxUser.ID)
return
}
// Show User RSS feed
if isShowFeed {
feed.ShowUserFeed(ctx, ctxUser, showFeedType)
if !models.IsUserVisibleToViewer(ctx.ContextUser, ctx.Doer) {
ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name))
return
}
// advertise feed via meta tag
ctx.Data["FeedURL"] = ctxUser.HTMLURL()
ctx.Data["FeedURL"] = ctx.ContextUser.HTMLURL()
// Show OpenID URIs
openIDs, err := user_model.GetUserOpenIDs(ctxUser.ID)
openIDs, err := user_model.GetUserOpenIDs(ctx.ContextUser.ID)
if err != nil {
ctx.ServerError("GetUserOpenIDs", err)
return
}
var isFollowing bool
if ctx.Doer != nil && ctxUser != nil {
isFollowing = user_model.IsFollowing(ctx.Doer.ID, ctxUser.ID)
if ctx.Doer != nil {
isFollowing = user_model.IsFollowing(ctx.Doer.ID, ctx.ContextUser.ID)
}
ctx.Data["Title"] = ctxUser.DisplayName()
ctx.Data["Title"] = ctx.ContextUser.DisplayName()
ctx.Data["PageIsUserProfile"] = true
ctx.Data["Owner"] = ctxUser
ctx.Data["Owner"] = ctx.ContextUser
ctx.Data["OpenIDs"] = openIDs
ctx.Data["IsFollowing"] = isFollowing
if setting.Service.EnableUserHeatmap {
data, err := models.GetUserHeatmapDataByUser(ctxUser, ctx.Doer)
data, err := models.GetUserHeatmapDataByUser(ctx.ContextUser, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserHeatmapDataByUser", err)
return
@ -146,13 +75,13 @@ func Profile(ctx *context.Context) {
ctx.Data["HeatmapData"] = data
}
if len(ctxUser.Description) != 0 {
if len(ctx.ContextUser.Description) != 0 {
content, err := markdown.RenderString(&markup.RenderContext{
URLPrefix: ctx.Repo.RepoLink,
Metas: map[string]string{"mode": "document"},
GitRepo: ctx.Repo.GitRepo,
Ctx: ctx,
}, ctxUser.Description)
}, ctx.ContextUser.Description)
if err != nil {
ctx.ServerError("RenderString", err)
return
@ -160,10 +89,10 @@ func Profile(ctx *context.Context) {
ctx.Data["RenderedDescription"] = content
}
showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctxUser.ID)
showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
orgs, err := models.FindOrgs(models.FindOrgOptions{
UserID: ctxUser.ID,
UserID: ctx.ContextUser.ID,
IncludePrivate: showPrivate,
})
if err != nil {
@ -226,7 +155,7 @@ func Profile(ctx *context.Context) {
switch tab {
case "followers":
items, err := user_model.GetUserFollowers(ctxUser, db.ListOptions{
items, err := user_model.GetUserFollowers(ctx.ContextUser, db.ListOptions{
PageSize: setting.UI.User.RepoPagingNum,
Page: page,
})
@ -236,9 +165,9 @@ func Profile(ctx *context.Context) {
}
ctx.Data["Cards"] = items
total = ctxUser.NumFollowers
total = ctx.ContextUser.NumFollowers
case "following":
items, err := user_model.GetUserFollowing(ctxUser, db.ListOptions{
items, err := user_model.GetUserFollowing(ctx.ContextUser, db.ListOptions{
PageSize: setting.UI.User.RepoPagingNum,
Page: page,
})
@ -248,10 +177,10 @@ func Profile(ctx *context.Context) {
}
ctx.Data["Cards"] = items
total = ctxUser.NumFollowing
total = ctx.ContextUser.NumFollowing
case "activity":
ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctxUser,
RequestedUser: ctx.ContextUser,
Actor: ctx.Doer,
IncludePrivate: showPrivate,
OnlyPerformedBy: true,
@ -273,7 +202,7 @@ func Profile(ctx *context.Context) {
Keyword: keyword,
OrderBy: orderBy,
Private: ctx.IsSigned,
StarredByID: ctxUser.ID,
StarredByID: ctx.ContextUser.ID,
Collaborate: util.OptionalBoolFalse,
TopicOnly: topicOnly,
Language: language,
@ -305,7 +234,7 @@ func Profile(ctx *context.Context) {
Keyword: keyword,
OrderBy: orderBy,
Private: ctx.IsSigned,
WatchedByID: ctxUser.ID,
WatchedByID: ctx.ContextUser.ID,
Collaborate: util.OptionalBoolFalse,
TopicOnly: topicOnly,
Language: language,
@ -325,7 +254,7 @@ func Profile(ctx *context.Context) {
},
Actor: ctx.Doer,
Keyword: keyword,
OwnerID: ctxUser.ID,
OwnerID: ctx.ContextUser.ID,
OrderBy: orderBy,
Private: ctx.IsSigned,
Collaborate: util.OptionalBoolFalse,
@ -350,24 +279,19 @@ func Profile(ctx *context.Context) {
}
ctx.Data["Page"] = pager
ctx.Data["ShowUserEmail"] = len(ctxUser.Email) > 0 && ctx.IsSigned && (!ctxUser.KeepEmailPrivate || ctxUser.ID == ctx.Doer.ID)
ctx.Data["ShowUserEmail"] = len(ctx.ContextUser.Email) > 0 && ctx.IsSigned && (!ctx.ContextUser.KeepEmailPrivate || ctx.ContextUser.ID == ctx.Doer.ID)
ctx.HTML(http.StatusOK, tplProfile)
}
// Action response for follow/unfollow user request
func Action(ctx *context.Context) {
u := GetUserByParams(ctx)
if ctx.Written() {
return
}
var err error
switch ctx.FormString("action") {
case "follow":
err = user_model.FollowUser(ctx.Doer.ID, u.ID)
err = user_model.FollowUser(ctx.Doer.ID, ctx.ContextUser.ID)
case "unfollow":
err = user_model.UnfollowUser(ctx.Doer.ID, u.ID)
err = user_model.UnfollowUser(ctx.Doer.ID, ctx.ContextUser.ID)
}
if err != nil {
@ -375,5 +299,5 @@ func Action(ctx *context.Context) {
return
}
// FIXME: We should check this URL and make sure that it's a valid Gitea URL
ctx.RedirectToFirst(ctx.FormString("redirect_to"), u.HomeLink())
ctx.RedirectToFirst(ctx.FormString("redirect_to"), ctx.ContextUser.HomeLink())
}

View file

@ -29,12 +29,14 @@ import (
"code.gitea.io/gitea/routers/web/dev"
"code.gitea.io/gitea/routers/web/events"
"code.gitea.io/gitea/routers/web/explore"
"code.gitea.io/gitea/routers/web/feed"
"code.gitea.io/gitea/routers/web/org"
"code.gitea.io/gitea/routers/web/repo"
"code.gitea.io/gitea/routers/web/user"
user_setting "code.gitea.io/gitea/routers/web/user/setting"
"code.gitea.io/gitea/routers/web/user/setting/security"
auth_service "code.gitea.io/gitea/services/auth"
context_service "code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
"code.gitea.io/gitea/services/lfs"
"code.gitea.io/gitea/services/mailer"
@ -496,11 +498,21 @@ func RegisterRoutes(m *web.Route) {
// ***** END: Admin *****
m.Group("", func() {
m.Get("/{username}", user.Profile)
m.Get("/favicon.ico", func(ctx *context.Context) {
ctx.ServeFile(path.Join(setting.StaticRootPath, "public/img/favicon.png"))
})
m.Group("/{username}", func() {
m.Get(".png", func(ctx *context.Context) { ctx.Error(http.StatusNotFound) })
m.Get(".keys", user.ShowSSHKeys)
m.Get(".gpg", user.ShowGPGKeys)
m.Get(".rss", feed.ShowUserFeedRSS)
m.Get(".atom", feed.ShowUserFeedAtom)
m.Get("", user.Profile)
}, context_service.UserAssignmentWeb())
m.Get("/attachments/{uuid}", repo.GetAttachment)
}, ignSignIn)
m.Post("/{username}", reqSignIn, user.Action)
m.Post("/{username}", reqSignIn, context_service.UserAssignmentWeb(), user.Action)
if !setting.IsProd {
m.Get("/template/*", dev.TemplatePreview)
@ -1107,7 +1119,7 @@ func RegisterRoutes(m *web.Route) {
m.GetOptions("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
}, ignSignInAndCsrf)
}, ignSignInAndCsrf, context_service.UserAssignmentWeb())
})
})
// ***** END: Repository *****