Delete documentation and begin flamego migration.

Co-authored-by: unknwon <2946214+unknwon@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-25 12:05:55 +00:00
parent bfc0f9c048
commit 755f61295a
33 changed files with 168 additions and 109 deletions

View File

@@ -24,6 +24,21 @@ import (
gogstemplate "gogs.io/gogs/internal/template" gogstemplate "gogs.io/gogs/internal/template"
) )
// Resp is a wrapper for ResponseWriter to provide compatibility.
type Resp struct {
http.ResponseWriter
}
// Write writes data to the response.
func (r *Resp) Write(data []byte) (int, error) {
return r.ResponseWriter.Write(data)
}
// Req is a wrapper for http.Request to provide compatibility.
type Req struct {
*http.Request
}
// Context represents context of a request. // Context represents context of a request.
type Context struct { type Context struct {
flamego.Context flamego.Context
@@ -34,6 +49,8 @@ type Context struct {
Flash *FlashData Flash *FlashData
Session session.Session Session session.Session
Resp *Resp
Req *Req
ResponseWriter http.ResponseWriter ResponseWriter http.ResponseWriter
Request *http.Request Request *http.Request
Data template.Data Data template.Data
@@ -53,6 +70,26 @@ type FlashData struct {
ErrorMsg, WarningMsg, InfoMsg, SuccessMsg string ErrorMsg, WarningMsg, InfoMsg, SuccessMsg string
} }
// Error sets error message.
func (f *FlashData) Error(msg string) {
f.ErrorMsg = msg
}
// Success sets success message.
func (f *FlashData) Success(msg string) {
f.SuccessMsg = msg
}
// Info sets info message.
func (f *FlashData) Info(msg string) {
f.InfoMsg = msg
}
// Warning sets warning message.
func (f *FlashData) Warning(msg string) {
f.WarningMsg = msg
}
// RawTitle sets the "Title" field in template data. // RawTitle sets the "Title" field in template data.
func (c *Context) RawTitle(title string) { func (c *Context) RawTitle(title string) {
c.Data["Title"] = title c.Data["Title"] = title
@@ -156,6 +193,24 @@ func (c *Context) Written() bool {
return false // TODO: Implement proper tracking return false // TODO: Implement proper tracking
} }
// Write writes data to the response.
func (c *Context) Write(data []byte) (int, error) {
return c.ResponseWriter.Write(data)
}
// ParamsInt64 returns value of the given bind parameter parsed as int64.
func (c *Context) ParamsInt64(name string) int64 {
return c.Context.ParamInt64(name)
}
// Language returns the language tag from the current locale.
func (c *Context) Language() string {
// Flamego's i18n.Locale doesn't have a Language() method
// We need to use a different approach or store the language
// For now, return empty string as a placeholder
return "" // TODO: Implement proper language tracking
}
// SetCookie sets a cookie. // SetCookie sets a cookie.
func (c *Context) SetCookie(name, value string, maxAge int, path string) { func (c *Context) SetCookie(name, value string, maxAge int, path string) {
http.SetCookie(c.ResponseWriter, &http.Cookie{ http.SetCookie(c.ResponseWriter, &http.Cookie{
@@ -310,6 +365,8 @@ func Contexter(store Store) flamego.Handler {
csrf: x, csrf: x,
Flash: flash, Flash: flash,
Session: sess, Session: sess,
Resp: &Resp{w},
Req: &Req{req},
ResponseWriter: w, ResponseWriter: w,
Request: req, Request: req,
Data: make(template.Data), Data: make(template.Data),

View File

@@ -281,7 +281,7 @@ func DeleteAuthSource(c *context.Context) {
c.Flash.Error(fmt.Sprintf("DeleteSource: %v", err)) c.Flash.Error(fmt.Sprintf("DeleteSource: %v", err))
} }
c.JSONSuccess(map[string]any{ c.JSONSuccess(map[string]any{
"redirect": conf.Server.Subpath + "/admin/auths/" + c.Params(":authid"), "redirect": conf.Server.Subpath + "/admin/auths/" + c.Param(":authid"),
}) })
return return
} }

View File

@@ -212,7 +212,7 @@ func EditUserPost(c *context.Context, f form.AdminEditUser) {
log.Trace("Account updated by admin %q: %s", c.User.Name, u.Name) log.Trace("Account updated by admin %q: %s", c.User.Name, u.Name)
c.Flash.Success(c.Tr("admin.users.update_profile_success")) c.Flash.Success(c.Tr("admin.users.update_profile_success"))
c.Redirect(conf.Server.Subpath + "/admin/users/" + c.Params(":userid")) c.Redirect(conf.Server.Subpath + "/admin/users/" + c.Param(":userid"))
} }
func DeleteUser(c *context.Context) { func DeleteUser(c *context.Context) {
@@ -227,12 +227,12 @@ func DeleteUser(c *context.Context) {
case database.IsErrUserOwnRepos(err): case database.IsErrUserOwnRepos(err):
c.Flash.Error(c.Tr("admin.users.still_own_repo")) c.Flash.Error(c.Tr("admin.users.still_own_repo"))
c.JSONSuccess(map[string]any{ c.JSONSuccess(map[string]any{
"redirect": conf.Server.Subpath + "/admin/users/" + c.Params(":userid"), "redirect": conf.Server.Subpath + "/admin/users/" + c.Param(":userid"),
}) })
case database.IsErrUserHasOrgs(err): case database.IsErrUserHasOrgs(err):
c.Flash.Error(c.Tr("admin.users.still_has_org")) c.Flash.Error(c.Tr("admin.users.still_has_org"))
c.JSONSuccess(map[string]any{ c.JSONSuccess(map[string]any{
"redirect": conf.Server.Subpath + "/admin/users/" + c.Params(":userid"), "redirect": conf.Server.Subpath + "/admin/users/" + c.Param(":userid"),
}) })
default: default:
c.Error(err, "delete user") c.Error(err, "delete user")

View File

@@ -6,7 +6,7 @@ import (
) )
func GetRepositoryByParams(c *context.APIContext) *database.Repository { func GetRepositoryByParams(c *context.APIContext) *database.Repository {
repo, err := database.GetRepositoryByName(c.Org.Team.OrgID, c.Params(":reponame")) repo, err := database.GetRepositoryByName(c.Org.Team.OrgID, c.Param(":reponame"))
if err != nil { if err != nil {
c.NotFoundOrError(err, "get repository by name") c.NotFoundOrError(err, "get repository by name")
return nil return nil

View File

@@ -23,8 +23,8 @@ import (
// and makes sure the context user has at least the read access to the repository. // and makes sure the context user has at least the read access to the repository.
func repoAssignment() macaron.Handler { func repoAssignment() macaron.Handler {
return func(c *context.APIContext) { return func(c *context.APIContext) {
username := c.Params(":username") username := c.Param(":username")
reponame := c.Params(":reponame") reponame := c.Param(":reponame")
var err error var err error
var owner *database.User var owner *database.User
@@ -87,7 +87,7 @@ func orgAssignment(args ...bool) macaron.Handler {
var err error var err error
if assignOrg { if assignOrg {
c.Org.Organization, err = database.Handle.Users().GetByUsername(c.Req.Context(), c.Params(":orgname")) c.Org.Organization, err = database.Handle.Users().GetByUsername(c.Req.Context(), c.Param(":orgname"))
if err != nil { if err != nil {
c.NotFoundOrError(err, "get organization by name") c.NotFoundOrError(err, "get organization by name")
return return

View File

@@ -1,6 +1,8 @@
package misc package misc
import ( import (
"io"
api "github.com/gogs/go-gogs-client" api "github.com/gogs/go-gogs-client"
"gogs.io/gogs/internal/context" "gogs.io/gogs/internal/context"
@@ -17,7 +19,7 @@ func Markdown(c *context.APIContext, form api.MarkdownOption) {
} }
func MarkdownRaw(c *context.APIContext) { func MarkdownRaw(c *context.APIContext) {
body, err := c.Req.Body().Bytes() body, err := io.ReadAll(c.Req.Request.Body)
if err != nil { if err != nil {
c.Error(err, "read body") c.Error(err, "read body")
return return

View File

@@ -12,13 +12,13 @@ import (
) )
func RepoGitBlob(c *context.APIContext) { func RepoGitBlob(c *context.APIContext) {
gitRepo, err := git.Open(repoutil.RepositoryPath(c.Params(":username"), c.Params(":reponame"))) gitRepo, err := git.Open(repoutil.RepositoryPath(c.Param(":username"), c.Param(":reponame")))
if err != nil { if err != nil {
c.Error(err, "open repository") c.Error(err, "open repository")
return return
} }
sha := c.Params(":sha") sha := c.Param(":sha")
blob, err := gitRepo.CatFileBlob(sha) blob, err := gitRepo.CatFileBlob(sha)
if err != nil { if err != nil {
c.NotFoundOrError(gitutil.NewError(err), "get blob") c.NotFoundOrError(gitutil.NewError(err), "get blob")
@@ -42,7 +42,7 @@ func RepoGitBlob(c *context.APIContext) {
c.JSONSuccess(&repoGitBlob{ c.JSONSuccess(&repoGitBlob{
Content: base64.StdEncoding.EncodeToString(content), Content: base64.StdEncoding.EncodeToString(content),
Encoding: "base64", Encoding: "base64",
URL: fmt.Sprintf("%s/repos/%s/%s/git/blobs/%s", c.BaseURL, c.Params(":username"), c.Params(":reponame"), sha), URL: fmt.Sprintf("%s/repos/%s/%s/git/blobs/%s", c.BaseURL, c.Param(":username"), c.Param(":reponame"), sha),
SHA: sha, SHA: sha,
Size: blob.Size(), Size: blob.Size(),
}) })

View File

@@ -9,7 +9,7 @@ import (
// https://github.com/gogs/go-gogs-client/wiki/Repositories#get-branch // https://github.com/gogs/go-gogs-client/wiki/Repositories#get-branch
func GetBranch(c *context.APIContext) { func GetBranch(c *context.APIContext) {
branch, err := c.Repo.Repository.GetBranch(c.Params("*")) branch, err := c.Repo.Repository.GetBranch(c.Param("*"))
if err != nil { if err != nil {
c.NotFoundOrError(err, "get branch") c.NotFoundOrError(err, "get branch")
return return

View File

@@ -24,7 +24,7 @@ func ListCollaborators(c *context.APIContext) {
} }
func AddCollaborator(c *context.APIContext, form api.AddCollaboratorOption) { func AddCollaborator(c *context.APIContext, form api.AddCollaboratorOption) {
collaborator, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Params(":collaborator")) collaborator, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Param(":collaborator"))
if err != nil { if err != nil {
if database.IsErrUserNotExist(err) { if database.IsErrUserNotExist(err) {
c.Status(http.StatusUnprocessableEntity) c.Status(http.StatusUnprocessableEntity)
@@ -50,7 +50,7 @@ func AddCollaborator(c *context.APIContext, form api.AddCollaboratorOption) {
} }
func IsCollaborator(c *context.APIContext) { func IsCollaborator(c *context.APIContext) {
collaborator, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Params(":collaborator")) collaborator, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Param(":collaborator"))
if err != nil { if err != nil {
if database.IsErrUserNotExist(err) { if database.IsErrUserNotExist(err) {
c.Status(http.StatusUnprocessableEntity) c.Status(http.StatusUnprocessableEntity)
@@ -68,7 +68,7 @@ func IsCollaborator(c *context.APIContext) {
} }
func DeleteCollaborator(c *context.APIContext) { func DeleteCollaborator(c *context.APIContext) {
collaborator, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Params(":collaborator")) collaborator, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Param(":collaborator"))
if err != nil { if err != nil {
if database.IsErrUserNotExist(err) { if database.IsErrUserNotExist(err) {
c.Status(http.StatusUnprocessableEntity) c.Status(http.StatusUnprocessableEntity)

View File

@@ -50,7 +50,7 @@ func GetAllCommits(c *context.APIContext) {
// GetSingleCommit will return a single Commit object based on the specified SHA. // GetSingleCommit will return a single Commit object based on the specified SHA.
func GetSingleCommit(c *context.APIContext) { func GetSingleCommit(c *context.APIContext) {
if strings.Contains(c.Req.Header.Get("Accept"), api.MediaApplicationSHA) { if strings.Contains(c.Req.Header.Get("Accept"), api.MediaApplicationSHA) {
c.SetParams("*", c.Params(":sha")) c.SetParams("*", c.Param(":sha"))
GetReferenceSHA(c) GetReferenceSHA(c)
return return
} }
@@ -60,7 +60,7 @@ func GetSingleCommit(c *context.APIContext) {
c.Error(err, "open repository") c.Error(err, "open repository")
return return
} }
commit, err := gitRepo.CatFileCommit(c.Params(":sha")) commit, err := gitRepo.CatFileCommit(c.Param(":sha"))
if err != nil { if err != nil {
c.NotFoundOrError(gitutil.NewError(err), "get commit") c.NotFoundOrError(gitutil.NewError(err), "get commit")
return return
@@ -80,7 +80,7 @@ func GetReferenceSHA(c *context.APIContext) {
return return
} }
ref := c.Params("*") ref := c.Param("*")
refType := 0 // 0-unknown, 1-branch, 2-tag refType := 0 // 0-unknown, 1-branch, 2-tag
if strings.HasPrefix(ref, git.RefsHeads) { if strings.HasPrefix(ref, git.RefsHeads) {
ref = strings.TrimPrefix(ref, git.RefsHeads) ref = strings.TrimPrefix(ref, git.RefsHeads)

View File

@@ -40,7 +40,7 @@ type repoContent struct {
} }
func toRepoContent(c *context.APIContext, ref, subpath string, commit *git.Commit, entry *git.TreeEntry) (*repoContent, error) { func toRepoContent(c *context.APIContext, ref, subpath string, commit *git.Commit, entry *git.TreeEntry) (*repoContent, error) {
repoURL := fmt.Sprintf("%s/repos/%s/%s", c.BaseURL, c.Params(":username"), c.Params(":reponame")) repoURL := fmt.Sprintf("%s/repos/%s/%s", c.BaseURL, c.Param(":username"), c.Param(":reponame"))
selfURL := fmt.Sprintf("%s/contents/%s", repoURL, subpath) selfURL := fmt.Sprintf("%s/contents/%s", repoURL, subpath)
htmlURL := fmt.Sprintf("%s/src/%s/%s", repoutil.HTMLURL(c.Repo.Owner.Name, c.Repo.Repository.Name), ref, entry.Name()) htmlURL := fmt.Sprintf("%s/src/%s/%s", repoutil.HTMLURL(c.Repo.Owner.Name, c.Repo.Repository.Name), ref, entry.Name())
downloadURL := fmt.Sprintf("%s/raw/%s/%s", repoutil.HTMLURL(c.Repo.Owner.Name, c.Repo.Repository.Name), ref, entry.Name()) downloadURL := fmt.Sprintf("%s/raw/%s/%s", repoutil.HTMLURL(c.Repo.Owner.Name, c.Repo.Repository.Name), ref, entry.Name())
@@ -99,7 +99,7 @@ func toRepoContent(c *context.APIContext, ref, subpath string, commit *git.Commi
} }
func GetContents(c *context.APIContext) { func GetContents(c *context.APIContext) {
repoPath := repoutil.RepositoryPath(c.Params(":username"), c.Params(":reponame")) repoPath := repoutil.RepositoryPath(c.Param(":username"), c.Param(":reponame"))
gitRepo, err := git.Open(repoPath) gitRepo, err := git.Open(repoPath)
if err != nil { if err != nil {
c.Error(err, "open repository") c.Error(err, "open repository")
@@ -118,7 +118,7 @@ func GetContents(c *context.APIContext) {
} }
// 🚨 SECURITY: Prevent path traversal. // 🚨 SECURITY: Prevent path traversal.
treePath := pathutil.Clean(c.Params("*")) treePath := pathutil.Clean(c.Param("*"))
entry, err := commit.TreeEntry(treePath) entry, err := commit.TreeEntry(treePath)
if err != nil { if err != nil {
c.NotFoundOrError(gitutil.NewError(err), "get tree entry") c.NotFoundOrError(gitutil.NewError(err), "get tree entry")
@@ -188,7 +188,7 @@ func PutContents(c *context.APIContext, r PutContentsRequest) {
} }
// 🚨 SECURITY: Prevent path traversal. // 🚨 SECURITY: Prevent path traversal.
treePath := pathutil.Clean(c.Params("*")) treePath := pathutil.Clean(c.Param("*"))
err = c.Repo.Repository.UpdateRepoFile( err = c.Repo.Repository.UpdateRepoFile(
c.User, c.User,
@@ -206,7 +206,7 @@ func PutContents(c *context.APIContext, r PutContentsRequest) {
return return
} }
repoPath := repoutil.RepositoryPath(c.Params(":username"), c.Params(":reponame")) repoPath := repoutil.RepositoryPath(c.Param(":username"), c.Param(":reponame"))
gitRepo, err := git.Open(repoPath) gitRepo, err := git.Open(repoPath)
if err != nil { if err != nil {
c.Error(err, "open repository") c.Error(err, "open repository")

View File

@@ -31,7 +31,7 @@ func GetRawFile(c *context.APIContext) {
} }
func GetArchive(c *context.APIContext) { func GetArchive(c *context.APIContext) {
repoPath := database.RepoPath(c.Params(":username"), c.Params(":reponame")) repoPath := database.RepoPath(c.Param(":username"), c.Param(":reponame"))
gitRepo, err := git.Open(repoPath) gitRepo, err := git.Open(repoPath)
if err != nil { if err != nil {
c.Error(err, "open repository") c.Error(err, "open repository")
@@ -49,7 +49,7 @@ func GetEditorconfig(c *context.APIContext) {
return return
} }
fileName := c.Params("filename") fileName := c.Param("filename")
def, err := ec.GetDefinitionForFilename(fileName) def, err := ec.GetDefinitionForFilename(fileName)
if err != nil { if err != nil {
c.Error(err, "get definition for filename") c.Error(err, "get definition for filename")

View File

@@ -27,7 +27,7 @@ func ListLabels(c *context.APIContext) {
func GetLabel(c *context.APIContext) { func GetLabel(c *context.APIContext) {
var label *database.Label var label *database.Label
var err error var err error
idStr := c.Params(":id") idStr := c.Param(":id")
if id := com.StrTo(idStr).MustInt64(); id > 0 { if id := com.StrTo(idStr).MustInt64(); id > 0 {
label, err = database.GetLabelOfRepoByID(c.Repo.Repository.ID, id) label, err = database.GetLabelOfRepoByID(c.Repo.Repository.ID, id)
} else { } else {

View File

@@ -151,11 +151,11 @@ func ListMyRepos(c *context.APIContext) {
} }
func ListUserRepositories(c *context.APIContext) { func ListUserRepositories(c *context.APIContext) {
listUserRepositories(c, c.Params(":username")) listUserRepositories(c, c.Param(":username"))
} }
func ListOrgRepositories(c *context.APIContext) { func ListOrgRepositories(c *context.APIContext) {
listUserRepositories(c, c.Params(":org")) listUserRepositories(c, c.Param(":org"))
} }
func CreateUserRepo(c *context.APIContext, owner *database.User, opt api.CreateRepoOption) { func CreateUserRepo(c *context.APIContext, owner *database.User, opt api.CreateRepoOption) {
@@ -196,7 +196,7 @@ func Create(c *context.APIContext, opt api.CreateRepoOption) {
} }
func CreateOrgRepo(c *context.APIContext, opt api.CreateRepoOption) { func CreateOrgRepo(c *context.APIContext, opt api.CreateRepoOption) {
org, err := database.GetOrgByName(c.Params(":org")) org, err := database.GetOrgByName(c.Param(":org"))
if err != nil { if err != nil {
c.NotFoundOrError(err, "get organization by name") c.NotFoundOrError(err, "get organization by name")
return return
@@ -292,7 +292,7 @@ func Migrate(c *context.APIContext, f form.MigrateRepo) {
// FIXME: inject in the handler chain // FIXME: inject in the handler chain
func parseOwnerAndRepo(c *context.APIContext) (*database.User, *database.Repository) { func parseOwnerAndRepo(c *context.APIContext) (*database.User, *database.Repository) {
owner, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Params(":username")) owner, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Param(":username"))
if err != nil { if err != nil {
if database.IsErrUserNotExist(err) { if database.IsErrUserNotExist(err) {
c.ErrorStatus(http.StatusUnprocessableEntity, err) c.ErrorStatus(http.StatusUnprocessableEntity, err)
@@ -302,7 +302,7 @@ func parseOwnerAndRepo(c *context.APIContext) (*database.User, *database.Reposit
return nil, nil return nil, nil
} }
repo, err := database.GetRepositoryByName(owner.ID, c.Params(":reponame")) repo, err := database.GetRepositoryByName(owner.ID, c.Param(":reponame"))
if err != nil { if err != nil {
c.NotFoundOrError(err, "get repository by name") c.NotFoundOrError(err, "get repository by name")
return nil, nil return nil, nil

View File

@@ -16,7 +16,7 @@ func GetRepoGitTree(c *context.APIContext) {
return return
} }
sha := c.Params(":sha") sha := c.Param(":sha")
tree, err := gitRepo.LsTree(sha) tree, err := gitRepo.LsTree(sha)
if err != nil { if err != nil {
c.NotFoundOrError(gitutil.NewError(err), "get tree") c.NotFoundOrError(gitutil.NewError(err), "get tree")
@@ -43,7 +43,7 @@ func GetRepoGitTree(c *context.APIContext) {
Tree []*repoGitTreeEntry `json:"tree"` Tree []*repoGitTreeEntry `json:"tree"`
} }
treesURL := fmt.Sprintf("%s/repos/%s/%s/git/trees", c.BaseURL, c.Params(":username"), c.Params(":reponame")) treesURL := fmt.Sprintf("%s/repos/%s/%s/git/trees", c.BaseURL, c.Param(":username"), c.Param(":reponame"))
if len(entries) == 0 { if len(entries) == 0 {
c.JSONSuccess(&repoGitTree{ c.JSONSuccess(&repoGitTree{
@@ -78,7 +78,7 @@ func GetRepoGitTree(c *context.APIContext) {
}) })
} }
c.JSONSuccess(&repoGitTree{ c.JSONSuccess(&repoGitTree{
Sha: c.Params(":sha"), Sha: c.Param(":sha"),
URL: fmt.Sprintf(treesURL+"/%s", sha), URL: fmt.Sprintf(treesURL+"/%s", sha),
Tree: children, Tree: children,
}) })

View File

@@ -44,7 +44,7 @@ func Search(c *context.APIContext) {
} }
func GetInfo(c *context.APIContext) { func GetInfo(c *context.APIContext) {
u, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Params(":username")) u, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Param(":username"))
if err != nil { if err != nil {
c.NotFoundOrError(err, "get user by name") c.NotFoundOrError(err, "get user by name")
return return

View File

@@ -16,5 +16,5 @@ func TemplatePreview(c *context.Context) {
c.Data["ResetPwdCodeLives"] = conf.Auth.ResetPasswordCodeLives / 60 c.Data["ResetPwdCodeLives"] = conf.Auth.ResetPasswordCodeLives / 60
c.Data["CurDbValue"] = "" c.Data["CurDbValue"] = ""
c.Success(c.Params("*")) c.Success(c.Param("*"))
} }

View File

@@ -4,7 +4,7 @@ import (
"net/http" "net/http"
"strings" "strings"
"gopkg.in/macaron.v1" "github.com/flamego/flamego"
log "unknwon.dev/clog/v2" log "unknwon.dev/clog/v2"
"gogs.io/gogs/internal/auth" "gogs.io/gogs/internal/auth"
@@ -17,7 +17,7 @@ import (
// RegisterRoutes registers LFS routes using given router, and inherits all // RegisterRoutes registers LFS routes using given router, and inherits all
// groups and middleware. // groups and middleware.
func RegisterRoutes(r *macaron.Router) { func RegisterRoutes(r flamego.Router) {
verifyAccept := verifyHeader("Accept", contentType, http.StatusNotAcceptable) verifyAccept := verifyHeader("Accept", contentType, http.StatusNotAcceptable)
verifyContentTypeJSON := verifyHeader("Content-Type", contentType, http.StatusBadRequest) verifyContentTypeJSON := verifyHeader("Content-Type", contentType, http.StatusBadRequest)
verifyContentTypeStream := verifyHeader("Content-Type", "application/octet-stream", http.StatusBadRequest) verifyContentTypeStream := verifyHeader("Content-Type", "application/octet-stream", http.StatusBadRequest)
@@ -43,7 +43,7 @@ func RegisterRoutes(r *macaron.Router) {
// authenticate tries to authenticate user via HTTP Basic Auth. It first tries to authenticate // authenticate tries to authenticate user via HTTP Basic Auth. It first tries to authenticate
// as plain username and password, then use username as access token if previous step failed. // as plain username and password, then use username as access token if previous step failed.
func authenticate(store Store) macaron.Handler { func authenticate(store Store) flamego.Handler {
askCredentials := func(w http.ResponseWriter) { askCredentials := func(w http.ResponseWriter) {
w.Header().Set("Lfs-Authenticate", `Basic realm="Git LFS"`) w.Header().Set("Lfs-Authenticate", `Basic realm="Git LFS"`)
responseJSON(w, http.StatusUnauthorized, responseError{ responseJSON(w, http.StatusUnauthorized, responseError{
@@ -51,21 +51,21 @@ func authenticate(store Store) macaron.Handler {
}) })
} }
return func(c *macaron.Context) { return func(c flamego.Context) {
username, password := authutil.DecodeBasic(c.Req.Header) username, password := authutil.DecodeBasic(c.Request().Header)
if username == "" { if username == "" {
askCredentials(c.Resp) askCredentials(c.ResponseWriter())
return return
} }
user, err := store.AuthenticateUser(c.Req.Context(), username, password, -1) user, err := store.AuthenticateUser(c.Request().Context(), username, password, -1)
if err != nil && !auth.IsErrBadCredentials(err) { if err != nil && !auth.IsErrBadCredentials(err) {
internalServerError(c.Resp) internalServerError(c.ResponseWriter())
log.Error("Failed to authenticate user [name: %s]: %v", username, err) log.Error("Failed to authenticate user [name: %s]: %v", username, err)
return return
} }
if err == nil && store.IsTwoFactorEnabled(c.Req.Context(), user.ID) { if err == nil && store.IsTwoFactorEnabled(c.Request().Context(), user.ID) {
c.Error(http.StatusBadRequest, "Users with 2FA enabled are not allowed to authenticate via username and password.") c.Error(http.StatusBadRequest, "Users with 2FA enabled are not allowed to authenticate via username and password.")
return return
} }
@@ -73,17 +73,17 @@ func authenticate(store Store) macaron.Handler {
// If username and password combination failed, try again using either username // If username and password combination failed, try again using either username
// or password as the token. // or password as the token.
if auth.IsErrBadCredentials(err) { if auth.IsErrBadCredentials(err) {
user, err = context.AuthenticateByToken(store, c.Req.Context(), username) user, err = context.AuthenticateByToken(store, c.Request().Context(), username)
if err != nil && !database.IsErrAccessTokenNotExist(err) { if err != nil && !database.IsErrAccessTokenNotExist(err) {
internalServerError(c.Resp) internalServerError(c.ResponseWriter())
log.Error("Failed to authenticate by access token via username: %v", err) log.Error("Failed to authenticate by access token via username: %v", err)
return return
} else if database.IsErrAccessTokenNotExist(err) { } else if database.IsErrAccessTokenNotExist(err) {
// Try again using the password field as the token. // Try again using the password field as the token.
user, err = context.AuthenticateByToken(store, c.Req.Context(), password) user, err = context.AuthenticateByToken(store, c.Request().Context(), password)
if err != nil { if err != nil {
if database.IsErrAccessTokenNotExist(err) { if database.IsErrAccessTokenNotExist(err) {
askCredentials(c.Resp) askCredentials(c.ResponseWriter())
} else { } else {
c.Status(http.StatusInternalServerError) c.Status(http.StatusInternalServerError)
log.Error("Failed to authenticate by access token via password: %v", err) log.Error("Failed to authenticate by access token via password: %v", err)
@@ -100,34 +100,34 @@ func authenticate(store Store) macaron.Handler {
} }
// authorize tries to authorize the user to the context repository with given access mode. // authorize tries to authorize the user to the context repository with given access mode.
func authorize(store Store, mode database.AccessMode) macaron.Handler { func authorize(store Store, mode database.AccessMode) flamego.Handler {
return func(c *macaron.Context, actor *database.User) { return func(c flamego.Context, actor *database.User) {
username := c.Params(":username") username := c.Param(":username")
reponame := strings.TrimSuffix(c.Params(":reponame"), ".git") reponame := strings.TrimSuffix(c.Param(":reponame"), ".git")
owner, err := store.GetUserByUsername(c.Req.Context(), username) owner, err := store.GetUserByUsername(c.Request().Context(), username)
if err != nil { if err != nil {
if database.IsErrUserNotExist(err) { if database.IsErrUserNotExist(err) {
c.Status(http.StatusNotFound) c.Status(http.StatusNotFound)
} else { } else {
internalServerError(c.Resp) internalServerError(c.ResponseWriter())
log.Error("Failed to get user [name: %s]: %v", username, err) log.Error("Failed to get user [name: %s]: %v", username, err)
} }
return return
} }
repo, err := store.GetRepositoryByName(c.Req.Context(), owner.ID, reponame) repo, err := store.GetRepositoryByName(c.Request().Context(), owner.ID, reponame)
if err != nil { if err != nil {
if database.IsErrRepoNotExist(err) { if database.IsErrRepoNotExist(err) {
c.Status(http.StatusNotFound) c.Status(http.StatusNotFound)
} else { } else {
internalServerError(c.Resp) internalServerError(c.ResponseWriter())
log.Error("Failed to get repository [owner_id: %d, name: %s]: %v", owner.ID, reponame, err) log.Error("Failed to get repository [owner_id: %d, name: %s]: %v", owner.ID, reponame, err)
} }
return return
} }
if !store.AuthorizeRepositoryAccess(c.Req.Context(), actor.ID, repo.ID, mode, if !store.AuthorizeRepositoryAccess(c.Request().Context(), actor.ID, repo.ID, mode,
database.AccessModeOptions{ database.AccessModeOptions{
OwnerID: repo.OwnerID, OwnerID: repo.OwnerID,
Private: repo.IsPrivate, Private: repo.IsPrivate,
@@ -146,9 +146,9 @@ func authorize(store Store, mode database.AccessMode) macaron.Handler {
// verifyHeader checks if the HTTP header contains given value. // verifyHeader checks if the HTTP header contains given value.
// When not, response given "failCode" as status code. // When not, response given "failCode" as status code.
func verifyHeader(key, value string, failCode int) macaron.Handler { func verifyHeader(key, value string, failCode int) flamego.Handler {
return func(c *macaron.Context) { return func(c flamego.Context) {
vals := c.Req.Header.Values(key) vals := c.Request().Header.Values(key)
for _, val := range vals { for _, val := range vals {
if strings.Contains(val, value) { if strings.Contains(val, value) {
return return
@@ -161,11 +161,11 @@ func verifyHeader(key, value string, failCode int) macaron.Handler {
} }
// verifyOID checks if the ":oid" URL parameter is valid. // verifyOID checks if the ":oid" URL parameter is valid.
func verifyOID() macaron.Handler { func verifyOID() flamego.Handler {
return func(c *macaron.Context) { return func(c flamego.Context) {
oid := lfsutil.OID(c.Params(":oid")) oid := lfsutil.OID(c.Param(":oid"))
if !lfsutil.ValidOID(oid) { if !lfsutil.ValidOID(oid) {
responseJSON(c.Resp, http.StatusBadRequest, responseError{ responseJSON(c.ResponseWriter(), http.StatusBadRequest, responseError{
Message: "Invalid oid", Message: "Invalid oid",
}) })
return return

View File

@@ -37,7 +37,7 @@ func MembersAction(c *context.Context) {
org := c.Org.Organization org := c.Org.Organization
var err error var err error
switch c.Params(":action") { switch c.Param(":action") {
case "private": case "private":
if c.User.ID != uid && !c.Org.IsOwner { if c.User.ID != uid && !c.Org.IsOwner {
c.NotFound() c.NotFound()
@@ -71,7 +71,7 @@ func MembersAction(c *context.Context) {
} }
if err != nil { if err != nil {
log.Error("Action(%s): %v", c.Params(":action"), err) log.Error("Action(%s): %v", c.Param(":action"), err)
c.JSONSuccess(map[string]any{ c.JSONSuccess(map[string]any{
"ok": false, "ok": false,
"err": err.Error(), "err": err.Error(),
@@ -79,7 +79,7 @@ func MembersAction(c *context.Context) {
return return
} }
if c.Params(":action") != "leave" { if c.Param(":action") != "leave" {
c.Redirect(c.Org.OrgLink + "/members") c.Redirect(c.Org.OrgLink + "/members")
} else { } else {
c.Redirect(conf.Server.Subpath + "/") c.Redirect(conf.Server.Subpath + "/")

View File

@@ -44,7 +44,7 @@ func TeamsAction(c *context.Context) {
page := c.Query("page") page := c.Query("page")
var err error var err error
switch c.Params(":action") { switch c.Param(":action") {
case "join": case "join":
if !c.Org.IsOwner { if !c.Org.IsOwner {
c.NotFound() c.NotFound()
@@ -86,7 +86,7 @@ func TeamsAction(c *context.Context) {
if database.IsErrLastOrgOwner(err) { if database.IsErrLastOrgOwner(err) {
c.Flash.Error(c.Tr("form.last_org_owner")) c.Flash.Error(c.Tr("form.last_org_owner"))
} else { } else {
log.Error("Action(%s): %v", c.Params(":action"), err) log.Error("Action(%s): %v", c.Param(":action"), err)
c.JSONSuccess(map[string]any{ c.JSONSuccess(map[string]any{
"ok": false, "ok": false,
"err": err.Error(), "err": err.Error(),
@@ -110,7 +110,7 @@ func TeamsRepoAction(c *context.Context) {
} }
var err error var err error
switch c.Params(":action") { switch c.Param(":action") {
case "add": case "add":
repoName := path.Base(c.Query("repo_name")) repoName := path.Base(c.Query("repo_name"))
var repo *database.Repository var repo *database.Repository
@@ -131,7 +131,7 @@ func TeamsRepoAction(c *context.Context) {
} }
if err != nil { if err != nil {
c.Errorf(err, "action %q", c.Params(":action")) c.Errorf(err, "action %q", c.Param(":action"))
return return
} }
c.Redirect(c.Org.OrgLink + "/teams/" + c.Org.Team.LowerName + "/repositories") c.Redirect(c.Org.OrgLink + "/teams/" + c.Org.Team.LowerName + "/repositories")

View File

@@ -104,7 +104,7 @@ func AllBranches(c *context.Context) {
} }
func DeleteBranchPost(c *context.Context) { func DeleteBranchPost(c *context.Context) {
branchName := c.Params("*") branchName := c.Param("*")
commitID := c.Query("commit") commitID := c.Query("commit")
defer func() { defer func() {

View File

@@ -120,7 +120,7 @@ func Diff(c *context.Context) {
userName := c.Repo.Owner.Name userName := c.Repo.Owner.Name
repoName := c.Repo.Repository.Name repoName := c.Repo.Repository.Name
commitID := c.Params(":sha") commitID := c.Param(":sha")
commit, err := c.Repo.GitRepo.CatFileCommit(commitID) commit, err := c.Repo.GitRepo.CatFileCommit(commitID)
if err != nil { if err != nil {
@@ -175,8 +175,8 @@ func Diff(c *context.Context) {
func RawDiff(c *context.Context) { func RawDiff(c *context.Context) {
if err := c.Repo.GitRepo.RawDiff( if err := c.Repo.GitRepo.RawDiff(
c.Params(":sha"), c.Param(":sha"),
git.RawDiffFormat(c.Params(":ext")), git.RawDiffFormat(c.Param(":ext")),
c.Resp, c.Resp,
); err != nil { ); err != nil {
c.NotFoundOrError(gitutil.NewError(err), "get raw diff") c.NotFoundOrError(gitutil.NewError(err), "get raw diff")
@@ -215,8 +215,8 @@ func CompareDiff(c *context.Context) {
c.Data["IsDiffCompare"] = true c.Data["IsDiffCompare"] = true
userName := c.Repo.Owner.Name userName := c.Repo.Owner.Name
repoName := c.Repo.Repository.Name repoName := c.Repo.Repository.Name
beforeCommitID := c.Params(":before") beforeCommitID := c.Param(":before")
afterCommitID := c.Params(":after") afterCommitID := c.Param(":after")
commit, err := c.Repo.GitRepo.CatFileCommit(afterCommitID) commit, err := c.Repo.GitRepo.CatFileCommit(afterCommitID)
if err != nil { if err != nil {

View File

@@ -13,7 +13,7 @@ import (
"strings" "strings"
"time" "time"
"gopkg.in/macaron.v1" "github.com/flamego/flamego"
log "unknwon.dev/clog/v2" log "unknwon.dev/clog/v2"
"gogs.io/gogs/internal/auth" "gogs.io/gogs/internal/auth"
@@ -26,7 +26,7 @@ import (
) )
type HTTPContext struct { type HTTPContext struct {
*macaron.Context flamego.Context
OwnerName string OwnerName string
OwnerSalt string OwnerSalt string
RepoID int64 RepoID int64
@@ -35,13 +35,13 @@ type HTTPContext struct {
} }
// askCredentials responses HTTP header and status which informs client to provide credentials. // askCredentials responses HTTP header and status which informs client to provide credentials.
func askCredentials(c *macaron.Context, status int, text string) { func askCredentials(c flamego.Context, status int, text string) {
c.Header().Set("WWW-Authenticate", "Basic realm=\".\"") c.Header().Set("WWW-Authenticate", "Basic realm=\".\"")
c.Error(status, text) c.Error(status, text)
} }
func HTTPContexter(store Store) macaron.Handler { func HTTPContexter(store Store) flamego.Handler {
return func(c *macaron.Context) { return func(c flamego.Context) {
if len(conf.HTTP.AccessControlAllowOrigin) > 0 { if len(conf.HTTP.AccessControlAllowOrigin) > 0 {
// Set CORS headers for browser-based git clients // Set CORS headers for browser-based git clients
c.Header().Set("Access-Control-Allow-Origin", conf.HTTP.AccessControlAllowOrigin) c.Header().Set("Access-Control-Allow-Origin", conf.HTTP.AccessControlAllowOrigin)
@@ -54,8 +54,8 @@ func HTTPContexter(store Store) macaron.Handler {
} }
} }
ownerName := c.Params(":username") ownerName := c.Param(":username")
repoName := strings.TrimSuffix(c.Params(":reponame"), ".git") repoName := strings.TrimSuffix(c.Param(":reponame"), ".git")
repoName = strings.TrimSuffix(repoName, ".wiki") repoName = strings.TrimSuffix(repoName, ".wiki")
isPull := c.Query("service") == "git-upload-pack" || isPull := c.Query("service") == "git-upload-pack" ||
@@ -93,7 +93,7 @@ func HTTPContexter(store Store) macaron.Handler {
} }
// In case user requested a wrong URL and not intended to access Git objects. // In case user requested a wrong URL and not intended to access Git objects.
action := c.Params("*") action := c.Param("*")
if !strings.Contains(action, "git-") && if !strings.Contains(action, "git-") &&
!strings.Contains(action, "info/") && !strings.Contains(action, "info/") &&
!strings.Contains(action, "HEAD") && !strings.Contains(action, "HEAD") &&

View File

@@ -1224,7 +1224,7 @@ func ChangeMilestonStatus(c *context.Context) {
Path: "milestones", Path: "milestones",
} }
switch c.Params(":action") { switch c.Param(":action") {
case "open": case "open":
if m.IsClosed { if m.IsClosed {
if err = database.ChangeMilestoneStatus(m, false); err != nil { if err = database.ChangeMilestoneStatus(m, false); err != nil {

View File

@@ -437,7 +437,7 @@ func ParseCompareInfo(c *context.Context) (*database.User, *database.Repository,
// format: <base branch>...[<head repo>:]<head branch> // format: <base branch>...[<head repo>:]<head branch>
// base<-head: master...head:feature // base<-head: master...head:feature
// same repo: master...feature // same repo: master...feature
infos := strings.Split(c.Params("*"), "...") infos := strings.Split(c.Param("*"), "...")
if len(infos) != 2 { if len(infos) != 2 {
log.Trace("ParseCompareInfo[%d]: not enough compared branches information %s", baseRepo.ID, infos) log.Trace("ParseCompareInfo[%d]: not enough compared branches information %s", baseRepo.ID, infos)
c.NotFound() c.NotFound()

View File

@@ -241,7 +241,7 @@ func EditRelease(c *context.Context) {
c.Data["PageIsEditRelease"] = true c.Data["PageIsEditRelease"] = true
renderReleaseAttachmentSettings(c) renderReleaseAttachmentSettings(c)
tagName := c.Params("*") tagName := c.Param("*")
rel, err := database.GetRelease(c.Repo.Repository.ID, tagName) rel, err := database.GetRelease(c.Repo.Repository.ID, tagName)
if err != nil { if err != nil {
c.NotFoundOrError(err, "get release") c.NotFoundOrError(err, "get release")
@@ -265,7 +265,7 @@ func EditReleasePost(c *context.Context, f form.EditRelease) {
c.Data["PageIsEditRelease"] = true c.Data["PageIsEditRelease"] = true
renderReleaseAttachmentSettings(c) renderReleaseAttachmentSettings(c)
tagName := c.Params("*") tagName := c.Param("*")
rel, err := database.GetRelease(c.Repo.Repository.ID, tagName) rel, err := database.GetRelease(c.Repo.Repository.ID, tagName)
if err != nil { if err != nil {
c.NotFoundOrError(err, "get release") c.NotFoundOrError(err, "get release")

View File

@@ -229,7 +229,7 @@ func MigratePost(c *context.Context, f form.MigrateRepo) {
func Action(c *context.Context) { func Action(c *context.Context) {
var err error var err error
switch c.Params(":action") { switch c.Param(":action") {
case "watch": case "watch":
err = database.WatchRepo(c.User.ID, c.Repo.Repository.ID, true) err = database.WatchRepo(c.User.ID, c.Repo.Repository.ID, true)
case "unwatch": case "unwatch":
@@ -256,7 +256,7 @@ func Action(c *context.Context) {
} }
if err != nil { if err != nil {
c.Errorf(err, "action %q", c.Params(":action")) c.Errorf(err, "action %q", c.Param(":action"))
return return
} }
@@ -269,7 +269,7 @@ func Action(c *context.Context) {
func Download(c *context.Context) { func Download(c *context.Context) {
var ( var (
uri = c.Params("*") uri = c.Param("*")
refName string refName string
ext string ext string
archivePath string archivePath string

View File

@@ -482,7 +482,7 @@ func UpdateDefaultBranch(c *context.Context) {
} }
func SettingsProtectedBranch(c *context.Context) { func SettingsProtectedBranch(c *context.Context) {
branch := c.Params("*") branch := c.Param("*")
if !c.Repo.GitRepo.HasBranch(branch) { if !c.Repo.GitRepo.HasBranch(branch) {
c.NotFound() c.NotFound()
return return
@@ -527,7 +527,7 @@ func SettingsProtectedBranch(c *context.Context) {
} }
func SettingsProtectedBranchPost(c *context.Context, f form.ProtectBranch) { func SettingsProtectedBranchPost(c *context.Context, f form.ProtectBranch) {
branch := c.Params("*") branch := c.Param("*")
if !c.Repo.GitRepo.HasBranch(branch) { if !c.Repo.GitRepo.HasBranch(branch) {
c.NotFound() c.NotFound()
return return
@@ -592,7 +592,7 @@ func SettingsGitHooksEdit(c *context.Context) {
c.Data["PageIsSettingsGitHooks"] = true c.Data["PageIsSettingsGitHooks"] = true
c.Data["RequireSimpleMDE"] = true c.Data["RequireSimpleMDE"] = true
name := git.HookName(c.Params(":name")) name := git.HookName(c.Param(":name"))
if !isValidHookName(name) { if !isValidHookName(name) {
c.NotFound() c.NotFound()
return return
@@ -608,7 +608,7 @@ func SettingsGitHooksEdit(c *context.Context) {
} }
func SettingsGitHooksEditPost(c *context.Context) { func SettingsGitHooksEditPost(c *context.Context) {
name := git.HookName(c.Params(":name")) name := git.HookName(c.Param(":name"))
if !isValidHookName(name) { if !isValidHookName(name) {
c.NotFound() c.NotFound()
return return

View File

@@ -19,8 +19,8 @@ func TriggerTask(c *macaron.Context) {
return return
} }
username := c.Params(":username") username := c.Param(":username")
reponame := c.Params(":reponame") reponame := c.Param(":reponame")
owner, err := database.Handle.Users().GetByUsername(c.Req.Context(), username) owner, err := database.Handle.Users().GetByUsername(c.Req.Context(), username)
if err != nil { if err != nil {

View File

@@ -100,7 +100,7 @@ func WebhooksNew(c *context.Context, orCtx *orgRepoContext) {
c.PageIs("SettingsHooksNew") c.PageIs("SettingsHooksNew")
allowed := false allowed := false
hookType := strings.ToLower(c.Params(":type")) hookType := strings.ToLower(c.Param(":type"))
for _, typ := range conf.Webhook.Types { for _, typ := range conf.Webhook.Types {
if hookType == typ { if hookType == typ {
allowed = true allowed = true

View File

@@ -71,7 +71,7 @@ func renderWikiPage(c *context.Context, isViewPage bool) (*git.Repository, strin
c.Data["Pages"] = pages c.Data["Pages"] = pages
} }
pageURL := c.Params(":page") pageURL := c.Param(":page")
if pageURL == "" { if pageURL == "" {
pageURL = "Home" pageURL = "Home"
} }
@@ -253,7 +253,7 @@ func EditWikiPost(c *context.Context, f form.NewWiki) {
} }
func DeleteWikiPagePost(c *context.Context) { func DeleteWikiPagePost(c *context.Context) {
pageURL := c.Params(":page") pageURL := c.Param(":page")
if pageURL == "" { if pageURL == "" {
pageURL = "Home" pageURL = "Home"
} }

View File

@@ -24,7 +24,7 @@ const (
// getDashboardContextUser finds out dashboard is viewing as which context user. // getDashboardContextUser finds out dashboard is viewing as which context user.
func getDashboardContextUser(c *context.Context) *database.User { func getDashboardContextUser(c *context.Context) *database.User {
ctxUser := c.User ctxUser := c.User
orgName := c.Params(":org") orgName := c.Param(":org")
if len(orgName) > 0 { if len(orgName) > 0 {
// Organization. // Organization.
org, err := database.Handle.Users().GetByUsername(c.Req.Context(), orgName) org, err := database.Handle.Users().GetByUsername(c.Req.Context(), orgName)
@@ -183,7 +183,7 @@ func Dashboard(c *context.Context) {
} }
func Issues(c *context.Context) { func Issues(c *context.Context) {
isPullList := c.Params(":type") == "pulls" isPullList := c.Param(":type") == "pulls"
if isPullList { if isPullList {
c.Data["Title"] = c.Tr("pull_requests") c.Data["Title"] = c.Tr("pull_requests")
c.Data["PageIsPulls"] = true c.Data["PageIsPulls"] = true
@@ -385,7 +385,7 @@ func ShowSSHKeys(c *context.Context, uid int64) {
} }
func showOrgProfile(c *context.Context) { func showOrgProfile(c *context.Context) {
c.SetParams(":org", c.Params(":username")) c.SetParams(":org", c.Param(":username"))
context.HandleOrgAssignment(c) context.HandleOrgAssignment(c)
if c.Written() { if c.Written() {
return return

View File

@@ -19,7 +19,7 @@ const (
func Profile(c *context.Context, puser *context.ParamsUser) { func Profile(c *context.Context, puser *context.ParamsUser) {
// Show SSH keys. // Show SSH keys.
if strings.HasSuffix(c.Params(":username"), ".keys") { if strings.HasSuffix(c.Param(":username"), ".keys") {
ShowSSHKeys(c, puser.ID) ShowSSHKeys(c, puser.ID)
return return
} }
@@ -109,7 +109,7 @@ func Stars(_ *context.Context) {
func Action(c *context.Context, puser *context.ParamsUser) { func Action(c *context.Context, puser *context.ParamsUser) {
var err error var err error
switch c.Params(":action") { switch c.Param(":action") {
case "follow": case "follow":
err = database.Handle.Users().Follow(c.Req.Context(), c.UserID(), puser.ID) err = database.Handle.Users().Follow(c.Req.Context(), c.UserID(), puser.ID)
case "unfollow": case "unfollow":
@@ -117,7 +117,7 @@ func Action(c *context.Context, puser *context.ParamsUser) {
} }
if err != nil { if err != nil {
c.Errorf(err, "action %q", c.Params(":action")) c.Errorf(err, "action %q", c.Param(":action"))
return return
} }