Skip to content

Refactor web route handler #33488

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion routers/web/org/home.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func Home(ctx *context.Context) {
}

ctx.SetPathParam("org", uname)
context.HandleOrgAssignment(ctx)
context.OrgAssignment(context.OrgAssignmentOptions{})(ctx)
if ctx.Written() {
return
}
Expand Down
91 changes: 0 additions & 91 deletions routers/web/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,31 +304,6 @@ func CreatePost(ctx *context.Context) {
handleCreateError(ctx, ctxUser, err, "CreatePost", tplCreate, &form)
}

const (
tplWatchUnwatch templates.TplName = "repo/watch_unwatch"
tplStarUnstar templates.TplName = "repo/star_unstar"
)

func acceptTransfer(ctx *context.Context) {
err := repo_service.AcceptTransferOwnership(ctx, ctx.Repo.Repository, ctx.Doer)
if err == nil {
ctx.Flash.Success(ctx.Tr("repo.settings.transfer.success"))
ctx.Redirect(ctx.Repo.Repository.Link())
return
}
handleActionError(ctx, err)
}

func rejectTransfer(ctx *context.Context) {
err := repo_service.RejectRepositoryTransfer(ctx, ctx.Repo.Repository, ctx.Doer)
if err == nil {
ctx.Flash.Success(ctx.Tr("repo.settings.transfer.rejected"))
ctx.Redirect(ctx.Repo.Repository.Link())
return
}
handleActionError(ctx, err)
}

func handleActionError(ctx *context.Context, err error) {
if errors.Is(err, user_model.ErrBlockedUser) {
ctx.Flash.Error(ctx.Tr("repo.action.blocked_user"))
Expand All @@ -339,72 +314,6 @@ func handleActionError(ctx *context.Context, err error) {
}
}

// Action response for actions to a repository
func Action(ctx *context.Context) {
var err error
switch ctx.PathParam("action") {
case "watch":
err = repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, true)
case "unwatch":
err = repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, false)
case "star":
err = repo_model.StarRepo(ctx, ctx.Doer, ctx.Repo.Repository, true)
case "unstar":
err = repo_model.StarRepo(ctx, ctx.Doer, ctx.Repo.Repository, false)
case "accept_transfer":
acceptTransfer(ctx)
return
case "reject_transfer":
rejectTransfer(ctx)
return
case "desc": // FIXME: this is not used
if !ctx.Repo.IsOwner() {
ctx.Error(http.StatusNotFound)
return
}

ctx.Repo.Repository.Description = ctx.FormString("desc")
ctx.Repo.Repository.Website = ctx.FormString("site")
err = repo_service.UpdateRepository(ctx, ctx.Repo.Repository, false)
}

if err != nil {
handleActionError(ctx, err)
return
}

switch ctx.PathParam("action") {
case "watch", "unwatch":
ctx.Data["IsWatchingRepo"] = repo_model.IsWatching(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
case "star", "unstar":
ctx.Data["IsStaringRepo"] = repo_model.IsStaring(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
}

// see the `hx-trigger="refreshUserCards ..."` comments in tmpl
ctx.RespHeader().Add("hx-trigger", "refreshUserCards")

switch ctx.PathParam("action") {
case "watch", "unwatch", "star", "unstar":
// we have to reload the repository because NumStars or NumWatching (used in the templates) has just changed
ctx.Data["Repository"], err = repo_model.GetRepositoryByName(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.Name)
if err != nil {
ctx.ServerError(fmt.Sprintf("Action (%s)", ctx.PathParam("action")), err)
return
}
}

switch ctx.PathParam("action") {
case "watch", "unwatch":
ctx.HTML(http.StatusOK, tplWatchUnwatch)
return
case "star", "unstar":
ctx.HTML(http.StatusOK, tplStarUnstar)
return
}

ctx.RedirectToCurrentSite(ctx.FormString("redirect_to"), ctx.Repo.RepoLink)
}

// RedirectDownload return a file based on the following infos:
func RedirectDownload(ctx *context.Context) {
var (
Expand Down
31 changes: 31 additions & 0 deletions routers/web/repo/star.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package repo

import (
"net/http"

repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/services/context"
)

const tplStarUnstar templates.TplName = "repo/star_unstar"

func ActionStar(ctx *context.Context) {
err := repo_model.StarRepo(ctx, ctx.Doer, ctx.Repo.Repository, ctx.PathParam("action") == "star")
if err != nil {
handleActionError(ctx, err)
return
}

ctx.Data["IsStaringRepo"] = repo_model.IsStaring(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
ctx.Data["Repository"], err = repo_model.GetRepositoryByName(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.Name)
if err != nil {
ctx.ServerError("GetRepositoryByName", err)
return
}
ctx.RespHeader().Add("hx-trigger", "refreshUserCards") // see the `hx-trigger="refreshUserCards ..."` comments in tmpl
ctx.HTML(http.StatusOK, tplStarUnstar)
}
38 changes: 38 additions & 0 deletions routers/web/repo/transfer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package repo

import (
"code.gitea.io/gitea/services/context"
repo_service "code.gitea.io/gitea/services/repository"
)

func acceptTransfer(ctx *context.Context) {
err := repo_service.AcceptTransferOwnership(ctx, ctx.Repo.Repository, ctx.Doer)
if err == nil {
ctx.Flash.Success(ctx.Tr("repo.settings.transfer.success"))
ctx.Redirect(ctx.Repo.Repository.Link())
return
}
handleActionError(ctx, err)
}

func rejectTransfer(ctx *context.Context) {
err := repo_service.RejectRepositoryTransfer(ctx, ctx.Repo.Repository, ctx.Doer)
if err == nil {
ctx.Flash.Success(ctx.Tr("repo.settings.transfer.rejected"))
ctx.Redirect(ctx.Repo.Repository.Link())
return
}
handleActionError(ctx, err)
}

func ActionTransfer(ctx *context.Context) {
switch ctx.PathParam("action") {
case "accept_transfer":
acceptTransfer(ctx)
case "reject_transfer":
rejectTransfer(ctx)
}
}
31 changes: 31 additions & 0 deletions routers/web/repo/watch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package repo

import (
"net/http"

repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/services/context"
)

const tplWatchUnwatch templates.TplName = "repo/watch_unwatch"

func ActionWatch(ctx *context.Context) {
err := repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, ctx.PathParam("action") == "watch")
if err != nil {
handleActionError(ctx, err)
return
}

ctx.Data["IsWatchingRepo"] = repo_model.IsWatching(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
ctx.Data["Repository"], err = repo_model.GetRepositoryByName(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.Name)
if err != nil {
ctx.ServerError("GetRepositoryByName", err)
return
}
ctx.RespHeader().Add("hx-trigger", "refreshUserCards") // see the `hx-trigger="refreshUserCards ..."` comments in tmpl
ctx.HTML(http.StatusOK, tplWatchUnwatch)
}
6 changes: 3 additions & 3 deletions routers/web/user/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,8 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb
ctx.Data["Page"] = pager
}

// Action response for follow/unfollow user request
func Action(ctx *context.Context) {
// ActionUserFollow is for follow/unfollow user request
func ActionUserFollow(ctx *context.Context) {
var err error
switch ctx.FormString("action") {
case "follow":
Expand All @@ -339,6 +339,6 @@ func Action(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplFollowUnfollow)
return
}
log.Error("Failed to apply action %q: unsupport context user type: %s", ctx.FormString("action"), ctx.ContextUser.Type)
log.Error("Failed to apply action %q: unsupported context user type: %s", ctx.FormString("action"), ctx.ContextUser.Type)
ctx.Error(http.StatusBadRequest, fmt.Sprintf("Action %q failed", ctx.FormString("action")))
}
25 changes: 13 additions & 12 deletions routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ func registerRoutes(m *web.Router) {
m.Methods("GET, OPTIONS", "/attachments/{uuid}", optionsCorsHandler(), repo.GetAttachment)
}, optSignIn)

m.Post("/{username}", reqSignIn, context.UserAssignmentWeb(), user.Action)
m.Post("/{username}", reqSignIn, context.UserAssignmentWeb(), user.ActionUserFollow)

reqRepoAdmin := context.RequireRepoAdmin()
reqRepoCodeWriter := context.RequireUnitWriter(unit.TypeCode)
Expand Down Expand Up @@ -872,7 +872,7 @@ func registerRoutes(m *web.Router) {
m.Group("/org", func() {
m.Group("/{org}", func() {
m.Get("/members", org.Members)
}, context.OrgAssignment())
}, context.OrgAssignment(context.OrgAssignmentOptions{}))
}, optSignIn)
// end "/org": members

Expand All @@ -898,19 +898,20 @@ func registerRoutes(m *web.Router) {
m.Get("/milestones/{team}", reqMilestonesDashboardPageEnabled, user.Milestones)
m.Post("/members/action/{action}", org.MembersAction)
m.Get("/teams", org.Teams)
}, context.OrgAssignment(true, false, true))
}, context.OrgAssignment(context.OrgAssignmentOptions{RequireMember: true, RequireTeamMember: true}))

m.Group("/{org}", func() {
m.Get("/teams/{team}", org.TeamMembers)
m.Get("/teams/{team}/repositories", org.TeamRepositories)
m.Post("/teams/{team}/action/{action}", org.TeamsAction)
m.Post("/teams/{team}/action/repo/{action}", org.TeamsRepoAction)
}, context.OrgAssignment(true, false, true))
}, context.OrgAssignment(context.OrgAssignmentOptions{RequireMember: true, RequireTeamMember: true}))

// require admin permission
// require member/team-admin permission (old logic is: requireMember=true, requireTeamAdmin=true)
// but it doesn't seem right: requireTeamAdmin does nothing
m.Group("/{org}", func() {
m.Get("/teams/-/search", org.SearchTeam)
}, context.OrgAssignment(true, false, false, true))
}, context.OrgAssignment(context.OrgAssignmentOptions{RequireMember: true, RequireTeamAdmin: true}))

// require owner permission
m.Group("/{org}", func() {
Expand All @@ -920,7 +921,7 @@ func registerRoutes(m *web.Router) {
m.Post("/teams/{team}/edit", web.Bind(forms.CreateTeamForm{}), org.EditTeamPost)
m.Post("/teams/{team}/delete", org.DeleteTeam)

m.Get("/worktime", context.OrgAssignment(false, true), org.Worktime)
m.Get("/worktime", context.OrgAssignment(context.OrgAssignmentOptions{RequireOwner: true}), org.Worktime)

m.Group("/settings", func() {
m.Combo("").Get(org.Settings).
Expand Down Expand Up @@ -989,7 +990,7 @@ func registerRoutes(m *web.Router) {
m.Post("", web.Bind(forms.BlockUserForm{}), org.BlockedUsersPost)
})
}, ctxDataSet("EnableOAuth2", setting.OAuth2.Enabled, "EnablePackages", setting.Packages.Enabled, "PageIsOrgSettings", true))
}, context.OrgAssignment(true, true))
}, context.OrgAssignment(context.OrgAssignmentOptions{RequireOwner: true}))
}, reqSignIn)
// end "/org": most org routes

Expand Down Expand Up @@ -1059,7 +1060,7 @@ func registerRoutes(m *web.Router) {
m.Group("", func() {
m.Get("/code", user.CodeSearch)
}, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false), individualPermsChecker)
}, optSignIn, context.UserAssignmentWeb(), context.OrgAssignment())
}, optSignIn, context.UserAssignmentWeb(), context.OrgAssignment(context.OrgAssignmentOptions{}))
// end "/{username}/-": packages, projects, code

m.Group("/{username}/{reponame}/-", func() {
Expand Down Expand Up @@ -1603,9 +1604,9 @@ func registerRoutes(m *web.Router) {
m.Get("/stars", starsEnabled, repo.Stars)
m.Get("/watchers", repo.Watchers)
m.Get("/search", reqUnitCodeReader, repo.Search)
m.Post("/action/{action:star|unstar}", reqSignIn, starsEnabled, repo.Action)
m.Post("/action/{action:watch|unwatch}", reqSignIn, repo.Action)
m.Post("/action/{action:accept_transfer|reject_transfer}", reqSignIn, repo.Action)
m.Post("/action/{action:star|unstar}", reqSignIn, starsEnabled, repo.ActionStar)
m.Post("/action/{action:watch|unwatch}", reqSignIn, repo.ActionWatch)
m.Post("/action/{action:accept_transfer|reject_transfer}", reqSignIn, repo.ActionTransfer)
}, optSignIn, context.RepoAssignment)

common.AddOwnerRepoGitLFSRoutes(m, optSignInIgnoreCsrf, lfsServerEnabled) // "/{username}/{reponame}/{lfs-paths}": git-lfs support
Expand Down
Loading