Merge branch 'master' into feature-activitypub

This commit is contained in:
6543
2022-05-09 19:47:40 +02:00
1441 changed files with 45124 additions and 28789 deletions
+33 -11
View File
@@ -35,10 +35,11 @@ import (
)
const (
tplDashboard base.TplName = "admin/dashboard"
tplConfig base.TplName = "admin/config"
tplMonitor base.TplName = "admin/monitor"
tplQueue base.TplName = "admin/queue"
tplDashboard base.TplName = "admin/dashboard"
tplConfig base.TplName = "admin/config"
tplMonitor base.TplName = "admin/monitor"
tplStacktrace base.TplName = "admin/stacktrace"
tplQueue base.TplName = "admin/queue"
)
var sysStatus struct {
@@ -149,7 +150,7 @@ func DashboardPost(ctx *context.Context) {
if form.Op != "" {
task := cron.GetTask(form.Op)
if task != nil {
go task.RunWithUser(ctx.User, nil)
go task.RunWithUser(ctx.Doer, nil)
ctx.Flash.Success(ctx.Tr("admin.dashboard.task.started", ctx.Tr("admin.dashboard."+form.Op)))
} else {
ctx.Flash.Error(ctx.Tr("admin.dashboard.task.unknown", form.Op))
@@ -326,12 +327,33 @@ func Monitor(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("admin.monitor")
ctx.Data["PageIsAdmin"] = true
ctx.Data["PageIsAdminMonitor"] = true
ctx.Data["Processes"] = process.GetManager().Processes(true)
ctx.Data["Processes"], ctx.Data["ProcessCount"] = process.GetManager().Processes(false, true)
ctx.Data["Entries"] = cron.ListTasks()
ctx.Data["Queues"] = queue.GetManager().ManagedQueues()
ctx.HTML(http.StatusOK, tplMonitor)
}
// GoroutineStacktrace show admin monitor goroutines page
func GoroutineStacktrace(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("admin.monitor")
ctx.Data["PageIsAdmin"] = true
ctx.Data["PageIsAdminMonitor"] = true
processStacks, processCount, goroutineCount, err := process.GetManager().ProcessStacktraces(false, false)
if err != nil {
ctx.ServerError("GoroutineStacktrace", err)
return
}
ctx.Data["ProcessStacks"] = processStacks
ctx.Data["GoroutineCount"] = goroutineCount
ctx.Data["ProcessCount"] = processCount
ctx.HTML(http.StatusOK, tplStacktrace)
}
// MonitorCancel cancels a process
func MonitorCancel(ctx *context.Context) {
pid := ctx.Params("pid")
@@ -346,7 +368,7 @@ func Queue(ctx *context.Context) {
qid := ctx.ParamsInt64("qid")
mq := queue.GetManager().GetManagedQueue(qid)
if mq == nil {
ctx.Status(404)
ctx.Status(http.StatusNotFound)
return
}
ctx.Data["Title"] = ctx.Tr("admin.monitor.queue", mq.Name)
@@ -361,7 +383,7 @@ func WorkerCancel(ctx *context.Context) {
qid := ctx.ParamsInt64("qid")
mq := queue.GetManager().GetManagedQueue(qid)
if mq == nil {
ctx.Status(404)
ctx.Status(http.StatusNotFound)
return
}
pid := ctx.ParamsInt64("pid")
@@ -377,7 +399,7 @@ func Flush(ctx *context.Context) {
qid := ctx.ParamsInt64("qid")
mq := queue.GetManager().GetManagedQueue(qid)
if mq == nil {
ctx.Status(404)
ctx.Status(http.StatusNotFound)
return
}
timeout, err := time.ParseDuration(ctx.FormString("timeout"))
@@ -423,7 +445,7 @@ func AddWorkers(ctx *context.Context) {
qid := ctx.ParamsInt64("qid")
mq := queue.GetManager().GetManagedQueue(qid)
if mq == nil {
ctx.Status(404)
ctx.Status(http.StatusNotFound)
return
}
number := ctx.FormInt("number")
@@ -453,7 +475,7 @@ func SetQueueSettings(ctx *context.Context) {
qid := ctx.ParamsInt64("qid")
mq := queue.GetManager().GetManagedQueue(qid)
if mq == nil {
ctx.Status(404)
ctx.Status(http.StatusNotFound)
return
}
if _, ok := mq.Managed.(queue.ManagedPool); !ok {
+5 -8
View File
@@ -93,7 +93,7 @@ func NewAuthSource(ctx *context.Context) {
ctx.Data["PageIsAdmin"] = true
ctx.Data["PageIsAdminAuthentications"] = true
ctx.Data["type"] = auth.LDAP
ctx.Data["type"] = auth.LDAP.Int()
ctx.Data["CurrentTypeName"] = auth.Names[auth.LDAP]
ctx.Data["CurrentSecurityProtocol"] = ldap.SecurityProtocolNames[ldap.SecurityProtocolUnencrypted]
ctx.Data["smtp_auth"] = "PLAIN"
@@ -112,7 +112,7 @@ func NewAuthSource(ctx *context.Context) {
ctx.Data["SSPIDefaultLanguage"] = ""
// only the first as default
ctx.Data["oauth2_provider"] = oauth2providers[0]
ctx.Data["oauth2_provider"] = oauth2providers[0].Name
ctx.HTML(http.StatusOK, tplAuthNew)
}
@@ -253,9 +253,6 @@ func NewAuthSourcePost(ctx *context.Context) {
ctx.Data["SSPISeparatorReplacement"] = "_"
ctx.Data["SSPIDefaultLanguage"] = ""
// FIXME: most error path to render tplAuthNew will fail and result in 500
// * template: admin/auth/new:17:68: executing "admin/auth/new" at <.type.Int>: can't evaluate field Int in type interface {}
// * template: admin/auth/source/oauth:5:93: executing "admin/auth/source/oauth" at <.oauth2_provider.Name>: can't evaluate field Name in type interface {}
hasTLS := false
var config convert.Conversion
switch auth.Type(form.Type) {
@@ -313,7 +310,7 @@ func NewAuthSourcePost(ctx *context.Context) {
return
}
log.Trace("Authentication created by admin(%s): %s", ctx.User.Name, form.Name)
log.Trace("Authentication created by admin(%s): %s", ctx.Doer.Name, form.Name)
ctx.Flash.Success(ctx.Tr("admin.auths.new_success", form.Name))
ctx.Redirect(setting.AppSubURL + "/admin/auths")
@@ -416,7 +413,7 @@ func EditAuthSourcePost(ctx *context.Context) {
}
return
}
log.Trace("Authentication changed by admin(%s): %d", ctx.User.Name, source.ID)
log.Trace("Authentication changed by admin(%s): %d", ctx.Doer.Name, source.ID)
ctx.Flash.Success(ctx.Tr("admin.auths.update_success"))
ctx.Redirect(setting.AppSubURL + "/admin/auths/" + strconv.FormatInt(form.ID, 10))
@@ -441,7 +438,7 @@ func DeleteAuthSource(ctx *context.Context) {
})
return
}
log.Trace("Authentication deleted by admin(%s): %d", ctx.User.Name, source.ID)
log.Trace("Authentication deleted by admin(%s): %d", ctx.Doer.Name, source.ID)
ctx.Flash.Success(ctx.Tr("admin.auths.deletion_success"))
ctx.JSON(http.StatusOK, map[string]interface{}{
+1 -1
View File
@@ -87,7 +87,7 @@ func Emails(ctx *context.Context) {
emails[i].SearchEmailResult = *baseEmails[i]
// Don't let the admin deactivate its own primary email address
// We already know the user is admin
emails[i].CanChange = ctx.User.ID != emails[i].UID || !emails[i].IsPrimary
emails[i].CanChange = ctx.Doer.ID != emails[i].UID || !emails[i].IsPrimary
}
}
ctx.Data["Keyword"] = opts.Keyword
+2 -1
View File
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
)
const (
@@ -34,7 +35,7 @@ func DefaultOrSystemWebhooks(ctx *context.Context) {
sys["Title"] = ctx.Tr("admin.systemhooks")
sys["Description"] = ctx.Tr("admin.systemhooks.desc")
sys["Webhooks"], err = webhook.GetSystemWebhooks()
sys["Webhooks"], err = webhook.GetSystemWebhooks(util.OptionalBoolNone)
sys["BaseLink"] = setting.AppSubURL + "/admin/hooks"
sys["BaseLinkNew"] = setting.AppSubURL + "/admin/system-hooks"
if err != nil {
+3 -1
View File
@@ -12,5 +12,7 @@ import (
)
func TestMain(m *testing.M) {
unittest.MainTest(m, filepath.Join("..", "..", ".."))
unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", "..", ".."),
})
}
+3 -3
View File
@@ -59,10 +59,10 @@ func DeleteNotices(ctx *context.Context) {
if err := admin_model.DeleteNoticesByIDs(ids); err != nil {
ctx.Flash.Error("DeleteNoticesByIDs: " + err.Error())
ctx.Status(500)
ctx.Status(http.StatusInternalServerError)
} else {
ctx.Flash.Success(ctx.Tr("admin.notices.delete_success"))
ctx.Status(200)
ctx.Status(http.StatusOK)
}
}
@@ -73,7 +73,7 @@ func EmptyNotices(ctx *context.Context) {
return
}
log.Trace("System notices deleted by admin (%s): [start: %d]", ctx.User.Name, 0)
log.Trace("System notices deleted by admin (%s): [start: %d]", ctx.Doer.Name, 0)
ctx.Flash.Success(ctx.Tr("admin.notices.delete_success"))
ctx.Redirect(setting.AppSubURL + "/admin/notices")
}
+1 -1
View File
@@ -26,7 +26,7 @@ func Organizations(ctx *context.Context) {
ctx.Data["PageIsAdminOrganizations"] = true
explore.RenderUserSearch(ctx, &user_model.SearchUserOptions{
Actor: ctx.User,
Actor: ctx.Doer,
Type: user_model.UserTypeOrganization,
ListOptions: db.ListOptions{
PageSize: setting.UI.Admin.OrgPagingNum,
+95
View File
@@ -0,0 +1,95 @@
// Copyright 2014 The Gogs 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 admin
import (
"net/http"
"net/url"
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
packages_service "code.gitea.io/gitea/services/packages"
)
const (
tplPackagesList base.TplName = "admin/packages/list"
)
// Packages shows all packages
func Packages(ctx *context.Context) {
page := ctx.FormInt("page")
if page <= 1 {
page = 1
}
query := ctx.FormTrim("q")
packageType := ctx.FormTrim("type")
sort := ctx.FormTrim("sort")
pvs, total, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
Type: packages_model.Type(packageType),
Name: packages_model.SearchValue{Value: query},
Sort: sort,
Paginator: &db.ListOptions{
PageSize: setting.UI.PackagesPagingNum,
Page: page,
},
})
if err != nil {
ctx.ServerError("SearchVersions", err)
return
}
pds, err := packages_model.GetPackageDescriptors(ctx, pvs)
if err != nil {
ctx.ServerError("GetPackageDescriptors", err)
return
}
totalBlobSize, err := packages_model.GetTotalBlobSize()
if err != nil {
ctx.ServerError("GetTotalBlobSize", err)
return
}
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["PageIsAdmin"] = true
ctx.Data["PageIsAdminPackages"] = true
ctx.Data["Query"] = query
ctx.Data["PackageType"] = packageType
ctx.Data["SortType"] = sort
ctx.Data["PackageDescriptors"] = pds
ctx.Data["Total"] = total
ctx.Data["TotalBlobSize"] = totalBlobSize
pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5)
pager.AddParamString("q", query)
pager.AddParamString("type", packageType)
pager.AddParamString("sort", sort)
ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, tplPackagesList)
}
// DeletePackageVersion deletes a package version
func DeletePackageVersion(ctx *context.Context) {
pv, err := packages_model.GetVersionByID(db.DefaultContext, ctx.FormInt64("id"))
if err != nil {
ctx.ServerError("GetRepositoryByID", err)
return
}
if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil {
ctx.ServerError("RemovePackageVersion", err)
return
}
ctx.Flash.Success(ctx.Tr("packages.settings.delete.success"))
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": setting.AppSubURL + "/admin/packages?page=" + url.QueryEscape(ctx.FormString("page")) + "&q=" + url.QueryEscape(ctx.FormString("q")) + "&type=" + url.QueryEscape(ctx.FormString("type")),
})
}
+3 -3
View File
@@ -52,7 +52,7 @@ func DeleteRepo(ctx *context.Context) {
ctx.Repo.GitRepo.Close()
}
if err := repo_service.DeleteRepository(ctx, ctx.User, repo, true); err != nil {
if err := repo_service.DeleteRepository(ctx, ctx.Doer, repo, true); err != nil {
ctx.ServerError("DeleteRepository", err)
return
}
@@ -148,7 +148,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
if has || !isDir {
// Fallthrough to failure mode
} else if action == "adopt" {
if _, err := repo_service.AdoptRepository(ctx.User, ctxUser, models.CreateRepoOptions{
if _, err := repo_service.AdoptRepository(ctx.Doer, ctxUser, models.CreateRepoOptions{
Name: dirSplit[1],
IsPrivate: true,
}); err != nil {
@@ -157,7 +157,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.adopt_preexisting_success", dir))
} else if action == "delete" {
if err := repo_service.DeleteUnadoptedRepository(ctx.User, ctxUser, dirSplit[1]); err != nil {
if err := repo_service.DeleteUnadoptedRepository(ctx.Doer, ctxUser, dirSplit[1]); err != nil {
ctx.ServerError("repository.AdoptRepository", err)
return
}
+30 -8
View File
@@ -63,7 +63,7 @@ func Users(ctx *context.Context) {
}
explore.RenderUserSearch(ctx, &user_model.SearchUserOptions{
Actor: ctx.User,
Actor: ctx.Doer,
Type: user_model.UserTypeIndividual,
ListOptions: db.ListOptions{
PageSize: setting.UI.Admin.UserPagingNum,
@@ -125,10 +125,14 @@ func NewUserPost(ctx *context.Context) {
Name: form.UserName,
Email: form.Email,
Passwd: form.Password,
IsActive: true,
LoginType: auth.Plain,
}
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolTrue,
Visibility: &form.Visibility,
}
if len(form.LoginType) > 0 {
fields := strings.Split(form.LoginType, "-")
if len(fields) == 2 {
@@ -163,7 +167,7 @@ func NewUserPost(ctx *context.Context) {
u.MustChangePassword = form.MustChangePassword
}
if err := user_model.CreateUser(u, &user_model.CreateUserOverwriteOptions{Visibility: form.Visibility}); err != nil {
if err := user_model.CreateUser(u, overwriteDefault); err != nil {
switch {
case user_model.IsErrUserAlreadyExist(err):
ctx.Data["Err_UserName"] = true
@@ -171,6 +175,9 @@ func NewUserPost(ctx *context.Context) {
case user_model.IsErrEmailAlreadyUsed(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserNew, &form)
case user_model.IsErrEmailCharIsNotSupported(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form)
case user_model.IsErrEmailInvalid(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form)
@@ -188,7 +195,7 @@ func NewUserPost(ctx *context.Context) {
}
return
}
log.Trace("Account created by admin (%s): %s", ctx.User.Name, u.Name)
log.Trace("Account created by admin (%s): %s", ctx.Doer.Name, u.Name)
// Send email notification.
if form.SendNotify {
@@ -376,7 +383,7 @@ func EditUserPost(ctx *context.Context) {
u.Visibility = form.Visibility
// skip self Prohibit Login
if ctx.User.ID == u.ID {
if ctx.Doer.ID == u.ID {
u.ProhibitLogin = false
} else {
u.ProhibitLogin = form.ProhibitLogin
@@ -386,7 +393,8 @@ func EditUserPost(ctx *context.Context) {
if user_model.IsErrEmailAlreadyUsed(err) {
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserEdit, &form)
} else if user_model.IsErrEmailInvalid(err) {
} else if user_model.IsErrEmailCharIsNotSupported(err) ||
user_model.IsErrEmailInvalid(err) {
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserEdit, &form)
} else {
@@ -394,7 +402,7 @@ func EditUserPost(ctx *context.Context) {
}
return
}
log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
log.Trace("Account profile updated by admin (%s): %s", ctx.Doer.Name, u.Name)
ctx.Flash.Success(ctx.Tr("admin.users.update_profile_success"))
ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")))
@@ -408,6 +416,15 @@ func DeleteUser(ctx *context.Context) {
return
}
// admin should not delete themself
if u.ID == ctx.Doer.ID {
ctx.Flash.Error(ctx.Tr("admin.users.cannot_delete_self"))
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")),
})
return
}
if err = user_service.DeleteUser(u); err != nil {
switch {
case models.IsErrUserOwnRepos(err):
@@ -420,12 +437,17 @@ func DeleteUser(ctx *context.Context) {
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")),
})
case models.IsErrUserOwnPackages(err):
ctx.Flash.Error(ctx.Tr("admin.users.still_own_packages"))
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": setting.AppSubURL + "/admin/users/" + ctx.Params(":userid"),
})
default:
ctx.ServerError("DeleteUser", err)
}
return
}
log.Trace("Account deleted by admin (%s): %s", ctx.User.Name, u.Name)
log.Trace("Account deleted by admin (%s): %s", ctx.Doer.Name, u.Name)
ctx.Flash.Success(ctx.Tr("admin.users.deletion_success"))
ctx.JSON(http.StatusOK, map[string]interface{}{
+5 -5
View File
@@ -27,7 +27,7 @@ func TestNewUserPost_MustChangePassword(t *testing.T) {
ID: 2,
}).(*user_model.User)
ctx.User = u
ctx.Doer = u
username := "gitea"
email := "gitea@gitea.io"
@@ -64,7 +64,7 @@ func TestNewUserPost_MustChangePasswordFalse(t *testing.T) {
ID: 2,
}).(*user_model.User)
ctx.User = u
ctx.Doer = u
username := "gitea"
email := "gitea@gitea.io"
@@ -101,7 +101,7 @@ func TestNewUserPost_InvalidEmail(t *testing.T) {
ID: 2,
}).(*user_model.User)
ctx.User = u
ctx.Doer = u
username := "gitea"
email := "gitea@gitea.io\r\n"
@@ -131,7 +131,7 @@ func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) {
ID: 2,
}).(*user_model.User)
ctx.User = u
ctx.Doer = u
username := "gitea"
email := "gitea@gitea.io"
@@ -169,7 +169,7 @@ func TestNewUserPost_VisibilityPrivate(t *testing.T) {
ID: 2,
}).(*user_model.User)
ctx.User = u
ctx.Doer = u
username := "gitea"
email := "gitea@gitea.io"
+11
View File
@@ -0,0 +1,11 @@
// 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.
//go:build !windows
package web
import auth_service "code.gitea.io/gitea/services/auth"
func specialAdd(group *auth_service.Group) {}
+31 -24
View File
@@ -107,7 +107,7 @@ func resetLocale(ctx *context.Context, u *user_model.User) error {
// If the user does not have a locale set, we save the current one.
if len(u.Language) == 0 {
u.Language = ctx.Locale.Language()
if err := user_model.UpdateUserCols(db.DefaultContext, u, "language"); err != nil {
if err := user_model.UpdateUserCols(ctx, u, "language"); err != nil {
return err
}
}
@@ -195,7 +195,7 @@ func SignInPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.SignInForm)
u, source, err := auth_service.UserSignIn(form.UserName, form.Password)
if err != nil {
if user_model.IsErrUserNotExist(err) {
if user_model.IsErrUserNotExist(err) || user_model.IsErrEmailAddressNotExist(err) {
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
} else if user_model.IsErrEmailAlreadyUsed(err) {
@@ -333,7 +333,7 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
// If the user does not have a locale set, we save the current one.
if len(u.Language) == 0 {
u.Language = ctx.Locale.Language()
if err := user_model.UpdateUserCols(db.DefaultContext, u, "language"); err != nil {
if err := user_model.UpdateUserCols(ctx, u, "language"); err != nil {
ctx.ServerError("UpdateUserCols Language", fmt.Errorf("Error updating user language [user: %d, locale: %s]", u.ID, u.Language))
return setting.AppSubURL + "/"
}
@@ -345,12 +345,12 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req)
}
// Clear whatever CSRF has right now, force to generate a new one
// Clear whatever CSRF cookie has right now, force to generate a new one
middleware.DeleteCSRFCookie(ctx.Resp)
// Register last login
u.SetLastLogin()
if err := user_model.UpdateUserCols(db.DefaultContext, u, "last_login_unix"); err != nil {
if err := user_model.UpdateUserCols(ctx, u, "last_login_unix"); err != nil {
ctx.ServerError("UpdateUserCols", err)
return setting.AppSubURL + "/"
}
@@ -393,8 +393,8 @@ func HandleSignOut(ctx *context.Context) {
// SignOut sign out from login status
func SignOut(ctx *context.Context) {
if ctx.User != nil {
eventsource.GetManager().SendMessageBlocking(ctx.User.ID, &eventsource.Event{
if ctx.Doer != nil {
eventsource.GetManager().SendMessageBlocking(ctx.Doer.ID, &eventsource.Event{
Name: "logout",
Data: ctx.Session.ID(),
})
@@ -507,14 +507,12 @@ func SignUpPost(ctx *context.Context) {
}
u := &user_model.User{
Name: form.UserName,
Email: form.Email,
Passwd: form.Password,
IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm),
IsRestricted: setting.Service.DefaultUserIsRestricted,
Name: form.UserName,
Email: form.Email,
Passwd: form.Password,
}
if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, false) {
if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, nil, false) {
// error already handled
return
}
@@ -525,8 +523,8 @@ func SignUpPost(ctx *context.Context) {
// createAndHandleCreatedUser calls createUserInContext and
// then handleUserCreated.
func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, gothUser *goth.User, allowLink bool) bool {
if !createUserInContext(ctx, tpl, form, u, gothUser, allowLink) {
func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) bool {
if !createUserInContext(ctx, tpl, form, u, overwrites, gothUser, allowLink) {
return false
}
return handleUserCreated(ctx, u, gothUser)
@@ -534,8 +532,8 @@ func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form int
// createUserInContext creates a user and handles errors within a given context.
// Optionally a template can be specified.
func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, gothUser *goth.User, allowLink bool) (ok bool) {
if err := user_model.CreateUser(u); err != nil {
func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) (ok bool) {
if err := user_model.CreateUser(u, overwrites); err != nil {
if allowLink && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) {
if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingAuto {
var user *user_model.User
@@ -573,6 +571,9 @@ func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{
case user_model.IsErrEmailAlreadyUsed(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tpl, form)
case user_model.IsErrEmailCharIsNotSupported(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form)
case user_model.IsErrEmailInvalid(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form)
@@ -599,11 +600,11 @@ func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{
// sends a confirmation email if required.
func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.User) (ok bool) {
// Auto-set admin for the only user.
if user_model.CountUsers() == 1 {
if user_model.CountUsers(nil) == 1 {
u.IsAdmin = true
u.IsActive = true
u.SetLastLogin()
if err := user_model.UpdateUserCols(db.DefaultContext, u, "is_admin", "is_active", "last_login_unix"); err != nil {
if err := user_model.UpdateUserCols(ctx, u, "is_admin", "is_active", "last_login_unix"); err != nil {
ctx.ServerError("UpdateUser", err)
return
}
@@ -618,6 +619,12 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.
// Send confirmation email
if !u.IsActive && u.ID > 1 {
if setting.Service.RegisterManualConfirm {
ctx.Data["ManualActivationOnly"] = true
ctx.HTML(http.StatusOK, TplActivate)
return
}
mailer.SendActivateAccountMail(ctx.Locale, u)
ctx.Data["IsSendRegisterMail"] = true
@@ -640,19 +647,19 @@ func Activate(ctx *context.Context) {
if len(code) == 0 {
ctx.Data["IsActivatePage"] = true
if ctx.User == nil || ctx.User.IsActive {
if ctx.Doer == nil || ctx.Doer.IsActive {
ctx.NotFound("invalid user", nil)
return
}
// Resend confirmation email.
if setting.Service.RegisterEmailConfirm {
if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) {
if ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName) {
ctx.Data["ResendLimited"] = true
} else {
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
mailer.SendActivateAccountMail(ctx.Locale, ctx.User)
mailer.SendActivateAccountMail(ctx.Locale, ctx.Doer)
if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil {
if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
log.Error("Set cache(MailResendLimit) fail: %v", err)
}
}
@@ -724,7 +731,7 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) {
ctx.ServerError("UpdateUser", err)
return
}
if err := user_model.UpdateUserCols(db.DefaultContext, user, "is_active", "rands"); err != nil {
if err := user_model.UpdateUserCols(ctx, user, "is_active", "rands"); err != nil {
if user_model.IsErrUserNotExist(err) {
ctx.NotFound("UpdateUserCols", err)
} else {
+1 -2
View File
@@ -283,13 +283,12 @@ func LinkAccountPostRegister(ctx *context.Context) {
Name: form.UserName,
Email: form.Email,
Passwd: form.Password,
IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm),
LoginType: auth.OAuth2,
LoginSource: authSource.ID,
LoginName: gothUser.UserID,
}
if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, &gothUser, false) {
if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, nil, &gothUser, false) {
// error already handled
return
}
+3 -1
View File
@@ -12,5 +12,7 @@ import (
)
func TestMain(m *testing.M) {
unittest.MainTest(m, filepath.Join("..", "..", ".."))
unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", "..", ".."),
})
}
+29 -27
View File
@@ -16,7 +16,6 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
@@ -25,6 +24,7 @@ import (
"code.gitea.io/gitea/modules/session"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/modules/web/middleware"
auth_service "code.gitea.io/gitea/services/auth"
@@ -267,21 +267,21 @@ type userInfoResponse struct {
// InfoOAuth manages request for userinfo endpoint
func InfoOAuth(ctx *context.Context) {
if ctx.User == nil || ctx.Data["AuthedMethod"] != (&auth_service.OAuth2{}).Name() {
if ctx.Doer == nil || ctx.Data["AuthedMethod"] != (&auth_service.OAuth2{}).Name() {
ctx.Resp.Header().Set("WWW-Authenticate", `Bearer realm=""`)
ctx.PlainText(http.StatusUnauthorized, "no valid authorization")
return
}
response := &userInfoResponse{
Sub: fmt.Sprint(ctx.User.ID),
Name: ctx.User.FullName,
Username: ctx.User.Name,
Email: ctx.User.Email,
Picture: ctx.User.AvatarLink(),
Sub: fmt.Sprint(ctx.Doer.ID),
Name: ctx.Doer.FullName,
Username: ctx.Doer.Name,
Email: ctx.Doer.Email,
Picture: ctx.Doer.AvatarLink(),
}
groups, err := getOAuthGroupsForUser(ctx.User)
groups, err := getOAuthGroupsForUser(ctx.Doer)
if err != nil {
ctx.ServerError("Oauth groups for user", err)
return
@@ -317,7 +317,7 @@ func getOAuthGroupsForUser(user *user_model.User) ([]string, error) {
// IntrospectOAuth introspects an oauth token
func IntrospectOAuth(ctx *context.Context) {
if ctx.User == nil {
if ctx.Doer == nil {
ctx.Resp.Header().Set("WWW-Authenticate", `Bearer realm=""`)
ctx.PlainText(http.StatusUnauthorized, "no valid authorization")
return
@@ -438,7 +438,7 @@ func AuthorizeOAuth(ctx *context.Context) {
return
}
grant, err := app.GetGrantByUserID(ctx.User.ID)
grant, err := app.GetGrantByUserID(ctx.Doer.ID)
if err != nil {
handleServerError(ctx, form.State, form.RedirectURI)
return
@@ -463,7 +463,7 @@ func AuthorizeOAuth(ctx *context.Context) {
log.Error("Unable to update nonce: %v", err)
}
}
ctx.Redirect(redirect.String(), 302)
ctx.Redirect(redirect.String())
return
}
@@ -515,7 +515,7 @@ func GrantApplicationOAuth(ctx *context.Context) {
ctx.ServerError("GetOAuth2ApplicationByClientID", err)
return
}
grant, err := app.CreateGrant(ctx.User.ID, form.Scope)
grant, err := app.CreateGrant(ctx.Doer.ID, form.Scope)
if err != nil {
handleAuthorizeError(ctx, AuthorizeError{
State: form.State,
@@ -545,7 +545,7 @@ func GrantApplicationOAuth(ctx *context.Context) {
handleServerError(ctx, form.State, form.RedirectURI)
return
}
ctx.Redirect(redirect.String(), 302)
ctx.Redirect(redirect.String(), http.StatusSeeOther)
}
// OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities
@@ -753,7 +753,7 @@ func handleAuthorizeError(ctx *context.Context, authErr AuthorizeError, redirect
if redirectURI == "" {
log.Warn("Authorization failed: %v", authErr.ErrorDescription)
ctx.Data["Error"] = authErr
ctx.HTML(400, tplGrantError)
ctx.HTML(http.StatusBadRequest, tplGrantError)
return
}
redirect, err := url.Parse(redirectURI)
@@ -766,7 +766,7 @@ func handleAuthorizeError(ctx *context.Context, authErr AuthorizeError, redirect
q.Set("error_description", authErr.ErrorDescription)
q.Set("state", authErr.State)
redirect.RawQuery = q.Encode()
ctx.Redirect(redirect.String(), 302)
ctx.Redirect(redirect.String(), http.StatusSeeOther)
}
// SignInOAuth handles the OAuth2 login buttons
@@ -868,19 +868,21 @@ func SignInOAuthCallback(ctx *context.Context) {
return
}
u = &user_model.User{
Name: getUserName(&gothUser),
FullName: gothUser.Name,
Email: gothUser.Email,
IsActive: !setting.OAuth2Client.RegisterEmailConfirm,
LoginType: auth.OAuth2,
LoginSource: authSource.ID,
LoginName: gothUser.UserID,
IsRestricted: setting.Service.DefaultUserIsRestricted,
Name: getUserName(&gothUser),
FullName: gothUser.Name,
Email: gothUser.Email,
LoginType: auth.OAuth2,
LoginSource: authSource.ID,
LoginName: gothUser.UserID,
}
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolOf(!setting.OAuth2Client.RegisterEmailConfirm),
}
setUserGroupClaims(authSource, u, &gothUser)
if !createAndHandleCreatedUser(ctx, base.TplName(""), nil, u, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) {
if !createAndHandleCreatedUser(ctx, base.TplName(""), nil, u, overwriteDefault, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) {
// error already handled
return
}
@@ -1008,7 +1010,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
log.Error("Error storing session: %v", err)
}
// Clear whatever CSRF has right now, force to generate a new one
// Clear whatever CSRF cookie has right now, force to generate a new one
middleware.DeleteCSRFCookie(ctx.Resp)
// Register last login
@@ -1021,7 +1023,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
cols = append(cols, "is_admin", "is_restricted")
}
if err := user_model.UpdateUserCols(db.DefaultContext, u, cols...); err != nil {
if err := user_model.UpdateUserCols(ctx, u, cols...); err != nil {
ctx.ServerError("UpdateUserCols", err)
return
}
@@ -1048,7 +1050,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
changed := setUserGroupClaims(source, u, &gothUser)
if changed {
if err := user_model.UpdateUserCols(db.DefaultContext, u, "is_admin", "is_restricted"); err != nil {
if err := user_model.UpdateUserCols(ctx, u, "is_admin", "is_restricted"); err != nil {
ctx.ServerError("UpdateUserCols", err)
return
}
+4 -5
View File
@@ -423,12 +423,11 @@ func RegisterOpenIDPost(ctx *context.Context) {
}
u := &user_model.User{
Name: form.UserName,
Email: form.Email,
Passwd: password,
IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm),
Name: form.UserName,
Email: form.Email,
Passwd: password,
}
if !createUserInContext(ctx, tplSignUpOID, form, u, nil, false) {
if !createUserInContext(ctx, tplSignUpOID, form, u, nil, nil, false) {
// error already handled
return
}
+6 -7
View File
@@ -9,7 +9,6 @@ import (
"net/http"
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
@@ -103,7 +102,7 @@ func commonResetPassword(ctx *context.Context) (*user_model.User, *auth.TwoFacto
ctx.Data["Title"] = ctx.Tr("auth.reset_password")
ctx.Data["Code"] = code
if nil != ctx.User {
if nil != ctx.Doer {
ctx.Data["user_signed_in"] = true
}
@@ -133,8 +132,8 @@ func commonResetPassword(ctx *context.Context) (*user_model.User, *auth.TwoFacto
// Show the user that they are affecting the account that they intended to
ctx.Data["user_email"] = u.Email
if nil != ctx.User && u.ID != ctx.User.ID {
ctx.Flash.Error(ctx.Tr("auth.reset_password_wrong_user", ctx.User.Email, u.Email))
if nil != ctx.Doer && u.ID != ctx.Doer.ID {
ctx.Flash.Error(ctx.Tr("auth.reset_password_wrong_user", ctx.Doer.Email, u.Email))
return nil, nil
}
@@ -232,7 +231,7 @@ func ResetPasswdPost(ctx *context.Context) {
return
}
u.MustChangePassword = false
if err := user_model.UpdateUserCols(db.DefaultContext, u, "must_change_password", "passwd", "passwd_hash_algo", "rands", "salt"); err != nil {
if err := user_model.UpdateUserCols(ctx, u, "must_change_password", "passwd", "passwd_hash_algo", "rands", "salt"); err != nil {
ctx.ServerError("UpdateUser", err)
return
}
@@ -283,7 +282,7 @@ func MustChangePasswordPost(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplMustChangePassword)
return
}
u := ctx.User
u := ctx.Doer
// Make sure only requests for users who are eligible to change their password via
// this method passes through
if !u.MustChangePassword {
@@ -327,7 +326,7 @@ func MustChangePasswordPost(ctx *context.Context) {
u.MustChangePassword = false
if err := user_model.UpdateUserCols(db.DefaultContext, u, "must_change_password", "passwd", "passwd_hash_algo", "salt"); err != nil {
if err := user_model.UpdateUserCols(ctx, u, "must_change_password", "passwd", "passwd_hash_algo", "salt"); err != nil {
ctx.ServerError("UpdateUser", err)
return
}
+2 -2
View File
@@ -39,7 +39,7 @@ func WebAuthn(ctx *context.Context) {
return
}
ctx.HTML(200, tplWebAuthn)
ctx.HTML(http.StatusOK, tplWebAuthn)
}
// WebAuthnLoginAssertion submits a WebAuthn challenge to the browser
@@ -166,5 +166,5 @@ func WebAuthnLoginAssertionPost(ctx *context.Context) {
}
}
ctx.JSON(200, map[string]string{"redirect": redirect})
ctx.JSON(http.StatusOK, map[string]string{"redirect": redirect})
}
+20
View File
@@ -0,0 +1,20 @@
// 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 web
import (
"code.gitea.io/gitea/models/auth"
auth_service "code.gitea.io/gitea/services/auth"
)
// specialAdd registers the SSPI auth method as the last method in the list.
// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation
// fails (or if negotiation should continue), which would prevent other authentication methods
// to execute at all.
func specialAdd(group *auth_service.Group) {
if auth.IsSSPIEnabled() {
group.Add(&auth_service.SSPI{})
}
}
+17 -18
View File
@@ -11,7 +11,6 @@ import (
"net/http"
"os"
"path"
"path/filepath"
"strings"
"code.gitea.io/gitea/modules/context"
@@ -28,6 +27,7 @@ import (
)
func storageHandler(storageSetting setting.Storage, prefix string, objStore storage.ObjectStorage) func(next http.Handler) http.Handler {
prefix = strings.Trim(prefix, "/")
funcInfo := routing.GetFuncInfo(storageHandler, prefix)
return func(next http.Handler) http.Handler {
if storageSetting.ServeDirect {
@@ -37,29 +37,32 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
return
}
if !strings.HasPrefix(req.URL.RequestURI(), "/"+prefix) {
if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
next.ServeHTTP(w, req)
return
}
routing.UpdateFuncInfo(req.Context(), funcInfo)
rPath := strings.TrimPrefix(req.URL.RequestURI(), "/"+prefix)
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
u, err := objStore.URL(rPath, path.Base(rPath))
if err != nil {
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
log.Warn("Unable to find %s %s", prefix, rPath)
http.Error(w, "file not found", 404)
http.Error(w, "file not found", http.StatusNotFound)
return
}
log.Error("Error whilst getting URL for %s %s. Error: %v", prefix, rPath, err)
http.Error(w, fmt.Sprintf("Error whilst getting URL for %s %s", prefix, rPath), 500)
http.Error(w, fmt.Sprintf("Error whilst getting URL for %s %s", prefix, rPath), http.StatusInternalServerError)
return
}
http.Redirect(
w,
req,
u.String(),
301,
http.StatusPermanentRedirect,
)
})
}
@@ -70,22 +73,18 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
return
}
prefix := strings.Trim(prefix, "/")
if !strings.HasPrefix(req.URL.EscapedPath(), "/"+prefix+"/") {
if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
next.ServeHTTP(w, req)
return
}
routing.UpdateFuncInfo(req.Context(), funcInfo)
rPath := strings.TrimPrefix(req.URL.EscapedPath(), "/"+prefix+"/")
rPath = strings.TrimPrefix(rPath, "/")
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
if rPath == "" {
http.Error(w, "file not found", 404)
http.Error(w, "file not found", http.StatusNotFound)
return
}
rPath = path.Clean("/" + filepath.ToSlash(rPath))
rPath = rPath[1:]
fi, err := objStore.Stat(rPath)
if err == nil && httpcache.HandleTimeCache(req, w, fi) {
@@ -97,11 +96,11 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
if err != nil {
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
log.Warn("Unable to find %s %s", prefix, rPath)
http.Error(w, "file not found", 404)
http.Error(w, "file not found", http.StatusNotFound)
return
}
log.Error("Error whilst opening %s %s. Error: %v", prefix, rPath, err)
http.Error(w, fmt.Sprintf("Error whilst opening %s %s", prefix, rPath), 500)
http.Error(w, fmt.Sprintf("Error whilst opening %s %s", prefix, rPath), http.StatusInternalServerError)
return
}
defer fr.Close()
@@ -109,7 +108,7 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
_, err = io.Copy(w, fr)
if err != nil {
log.Error("Error whilst rendering %s %s. Error: %v", prefix, rPath, err)
http.Error(w, fmt.Sprintf("Error whilst rendering %s %s", prefix, rPath), 500)
http.Error(w, fmt.Sprintf("Error whilst rendering %s %s", prefix, rPath), http.StatusInternalServerError)
return
}
})
@@ -164,7 +163,7 @@ func Recovery() func(next http.Handler) http.Handler {
if !setting.IsProd {
store["ErrorMsg"] = combinedErr
}
err = rnd.HTML(w, 500, "status/500", templates.BaseVars().Merge(store))
err = rnd.HTML(w, http.StatusInternalServerError, "status/500", templates.BaseVars().Merge(store))
if err != nil {
log.Error("%v", err)
}
+3 -36
View File
@@ -8,15 +8,10 @@ import (
"net/http"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/eventsource"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/web/auth"
)
@@ -48,7 +43,7 @@ func Events(ctx *context.Context) {
shutdownCtx := graceful.GetManager().ShutdownContext()
uid := ctx.User.ID
uid := ctx.Doer.ID
messageChan := eventsource.GetManager().Register(uid)
@@ -71,8 +66,6 @@ func Events(ctx *context.Context) {
timer := time.NewTicker(30 * time.Second)
stopwatchTimer := time.NewTicker(setting.UI.Notification.MinTimeout)
loop:
for {
select {
@@ -82,7 +75,7 @@ loop:
}
_, err := event.WriteTo(ctx.Resp)
if err != nil {
log.Error("Unable to write to EventStream for user %s: %v", ctx.User.Name, err)
log.Error("Unable to write to EventStream for user %s: %v", ctx.Doer.Name, err)
go unregister()
break loop
}
@@ -93,32 +86,6 @@ loop:
case <-shutdownCtx.Done():
go unregister()
break loop
case <-stopwatchTimer.C:
sws, err := models.GetUserStopwatches(ctx.User.ID, db.ListOptions{})
if err != nil {
log.Error("Unable to GetUserStopwatches: %v", err)
continue
}
apiSWs, err := convert.ToStopWatches(sws)
if err != nil {
log.Error("Unable to APIFormat stopwatches: %v", err)
continue
}
dataBs, err := json.Marshal(apiSWs)
if err != nil {
log.Error("Unable to marshal stopwatches: %v", err)
continue
}
_, err = (&eventsource.Event{
Name: "stopwatches",
Data: string(dataBs),
}).WriteTo(ctx.Resp)
if err != nil {
log.Error("Unable to write to EventStream for user %s: %v", ctx.User.Name, err)
go unregister()
break loop
}
ctx.Resp.Flush()
case event, ok := <-messageChan:
if !ok {
break loop
@@ -145,7 +112,7 @@ loop:
_, err := event.WriteTo(ctx.Resp)
if err != nil {
log.Error("Unable to write to EventStream for user %s: %v", ctx.User.Name, err)
log.Error("Unable to write to EventStream for user %s: %v", ctx.Doer.Name, err)
go unregister()
break loop
}
+8 -9
View File
@@ -24,7 +24,7 @@ const (
// Code render explore code page
func Code(ctx *context.Context) {
if !setting.Indexer.RepoIndexerEnabled {
ctx.Redirect(setting.AppSubURL+"/explore", 302)
ctx.Redirect(setting.AppSubURL + "/explore")
return
}
@@ -49,13 +49,13 @@ func Code(ctx *context.Context) {
err error
isAdmin bool
)
if ctx.User != nil {
isAdmin = ctx.User.IsAdmin
if ctx.Doer != nil {
isAdmin = ctx.Doer.IsAdmin
}
// guest user or non-admin user
if ctx.User == nil || !isAdmin {
repoIDs, err = models.FindUserAccessibleRepoIDs(ctx.User)
if ctx.Doer == nil || !isAdmin {
repoIDs, err = models.FindUserAccessibleRepoIDs(ctx.Doer)
if err != nil {
ctx.ServerError("SearchResults", err)
return
@@ -69,7 +69,7 @@ func Code(ctx *context.Context) {
)
// if non-admin login user, we need check UnitTypeCode at first
if ctx.User != nil && len(repoIDs) > 0 {
if ctx.Doer != nil && len(repoIDs) > 0 {
repoMaps, err := repo_model.GetRepositoriesMapByIDs(repoIDs)
if err != nil {
ctx.ServerError("SearchResults", err)
@@ -79,7 +79,7 @@ func Code(ctx *context.Context) {
rightRepoMap := make(map[int64]*repo_model.Repository, len(repoMaps))
repoIDs = make([]int64, 0, len(repoMaps))
for id, repo := range repoMaps {
if models.CheckRepoUnitUser(repo, ctx.User, unit.TypeCode) {
if models.CheckRepoUnitUser(repo, ctx.Doer, unit.TypeCode) {
rightRepoMap[id] = repo
repoIDs = append(repoIDs, id)
}
@@ -98,7 +98,7 @@ func Code(ctx *context.Context) {
ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable()
}
// if non-login user or isAdmin, no need to check UnitTypeCode
} else if (ctx.User == nil && len(repoIDs) > 0) || isAdmin {
} else if (ctx.Doer == nil && len(repoIDs) > 0) || isAdmin {
total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(ctx, repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch)
if err != nil {
if code_indexer.IsAvailable() {
@@ -138,7 +138,6 @@ func Code(ctx *context.Context) {
ctx.Data["queryType"] = queryType
ctx.Data["SearchResults"] = searchResults
ctx.Data["SearchResultLanguages"] = searchResultLanguages
ctx.Data["RequireHighlightJS"] = true
ctx.Data["PageIsViewCode"] = true
pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
+2 -2
View File
@@ -27,12 +27,12 @@ func Organizations(ctx *context.Context) {
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
visibleTypes := []structs.VisibleType{structs.VisibleTypePublic}
if ctx.User != nil {
if ctx.Doer != nil {
visibleTypes = append(visibleTypes, structs.VisibleTypeLimited, structs.VisibleTypePrivate)
}
RenderUserSearch(ctx, &user_model.SearchUserOptions{
Actor: ctx.User,
Actor: ctx.Doer,
Type: user_model.UserTypeOrganization,
ListOptions: db.ListOptions{PageSize: setting.UI.ExplorePagingNum},
Visible: visibleTypes,
+4 -4
View File
@@ -86,7 +86,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
Page: page,
PageSize: opts.PageSize,
},
Actor: ctx.User,
Actor: ctx.Doer,
OrderBy: orderBy,
Private: opts.Private,
Keyword: keyword,
@@ -124,14 +124,14 @@ func Repos(ctx *context.Context) {
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
var ownerID int64
if ctx.User != nil && !ctx.User.IsAdmin {
ownerID = ctx.User.ID
if ctx.Doer != nil && !ctx.Doer.IsAdmin {
ownerID = ctx.Doer.ID
}
RenderRepoSearch(ctx, &RepoSearchOptions{
PageSize: setting.UI.ExplorePagingNum,
OwnerID: ownerID,
Private: ctx.User != nil,
Private: ctx.Doer != nil,
TplName: tplExploreRepos,
})
}
+42
View File
@@ -0,0 +1,42 @@
// 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 explore
import (
"net/http"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
api "code.gitea.io/gitea/modules/structs"
)
// TopicSearch search for creating topic
func TopicSearch(ctx *context.Context) {
opts := &repo_model.FindTopicOptions{
Keyword: ctx.FormString("q"),
ListOptions: db.ListOptions{
Page: ctx.FormInt("page"),
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
},
}
topics, total, err := repo_model.FindTopics(opts)
if err != nil {
ctx.Error(http.StatusInternalServerError)
return
}
topicResponses := make([]*api.TopicResponse, len(topics))
for i, topic := range topics {
topicResponses[i] = convert.ToTopicResponse(topic)
}
ctx.SetTotalCountHeader(total)
ctx.JSON(http.StatusOK, map[string]interface{}{
"topics": topicResponses,
})
}
+1 -1
View File
@@ -102,7 +102,7 @@ func Users(ctx *context.Context) {
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
RenderUserSearch(ctx, &user_model.SearchUserOptions{
Actor: ctx.User,
Actor: ctx.Doer,
Type: user_model.UserTypeIndividual,
ListOptions: db.ListOptions{PageSize: setting.UI.ExplorePagingNum},
IsActive: util.OptionalBoolTrue,
+40 -3
View File
@@ -7,12 +7,15 @@ package feed
import (
"fmt"
"html"
"net/http"
"net/url"
"strconv"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/util"
@@ -44,8 +47,27 @@ func toReleaseLink(act *models.Action) string {
return act.GetRepoLink() + "/releases/tag/" + util.PathEscapeSegments(act.GetBranch())
}
// renderMarkdown creates a minimal markdown render context from an action.
// If rendering fails, the original markdown text is returned
func renderMarkdown(ctx *context.Context, act *models.Action, content string) string {
markdownCtx := &markup.RenderContext{
Ctx: ctx,
URLPrefix: act.GetRepoLink(),
Type: markdown.MarkupName,
Metas: map[string]string{
"user": act.GetRepoUserName(),
"repo": act.GetRepoName(),
},
}
markdown, err := markdown.RenderString(markdownCtx, content)
if err != nil {
return content
}
return markdown
}
// feedActionsToFeedItems convert gitea's Action feed to feeds Item
func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (items []*feeds.Item, err error) {
func feedActionsToFeedItems(ctx *context.Context, actions models.ActionList) (items []*feeds.Item, err error) {
for _, act := range actions {
act.LoadActUser()
@@ -192,12 +214,12 @@ func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (ite
case models.ActionCreateIssue, models.ActionCreatePullRequest:
desc = strings.Join(act.GetIssueInfos(), "#")
content = act.GetIssueContent()
content = renderMarkdown(ctx, act, act.GetIssueContent())
case models.ActionCommentIssue, models.ActionApprovePullRequest, models.ActionRejectPullRequest, models.ActionCommentPull:
desc = act.GetIssueTitle()
comment := act.GetIssueInfos()[1]
if len(comment) != 0 {
desc += "\n\n" + comment
desc += "\n\n" + renderMarkdown(ctx, act, comment)
}
case models.ActionMergePullRequest:
desc = act.GetIssueInfos()[1]
@@ -226,3 +248,18 @@ func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (ite
}
return
}
// GetFeedType return if it is a feed request and altered name and feed type.
func GetFeedType(name string, req *http.Request) (bool, string, string) {
if strings.HasSuffix(name, ".rss") ||
strings.Contains(req.Header.Get("Accept"), "application/rss+xml") {
return true, strings.TrimSuffix(name, ".rss"), "rss"
}
if strings.HasSuffix(name, ".atom") ||
strings.Contains(req.Header.Get("Accept"), "application/atom+xml") {
return true, strings.TrimSuffix(name, ".atom"), "atom"
}
return false, name, ""
}
+19 -46
View File
@@ -9,70 +9,43 @@ 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"
)
// RetrieveFeeds loads feeds for the specified user
func RetrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) []*models.Action {
actions, err := models.GetFeeds(options)
if err != nil {
ctx.ServerError("GetFeeds", err)
return nil
}
userCache := map[int64]*user_model.User{options.RequestedUser.ID: options.RequestedUser}
if ctx.User != nil {
userCache[ctx.User.ID] = ctx.User
}
for _, act := range actions {
if act.ActUser != nil {
userCache[act.ActUserID] = act.ActUser
}
}
for _, act := range actions {
repoOwner, ok := userCache[act.Repo.OwnerID]
if !ok {
repoOwner, err = user_model.GetUserByID(act.Repo.OwnerID)
if err != nil {
if user_model.IsErrUserNotExist(err) {
continue
}
ctx.ServerError("GetUserByID", err)
return nil
}
userCache[repoOwner.ID] = repoOwner
}
act.Repo.Owner = repoOwner
}
return actions
// ShowUserFeedRSS show user activity as RSS feed
func ShowUserFeedRSS(ctx *context.Context) {
showUserFeed(ctx, "rss")
}
// ShowUserFeed show user activity as RSS / Atom feed
func ShowUserFeed(ctx *context.Context, ctxUser *user_model.User, formatType string) {
actions := RetrieveFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctxUser,
Actor: ctx.User,
// 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: ctx.ContextUser,
Actor: ctx.Doer,
IncludePrivate: false,
OnlyPerformedBy: true,
OnlyPerformedBy: !ctx.ContextUser.IsOrganization(),
IncludeDeleted: false,
Date: ctx.FormString("date"),
})
if ctx.Written() {
if err != nil {
ctx.ServerError("GetFeeds", err)
return
}
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(),
}
var err error
feed.Items, err = feedActionsToFeedItems(ctx, actions)
if err != nil {
ctx.ServerError("convert feed", err)
+44
View File
@@ -0,0 +1,44 @@
// 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 feed
import (
"time"
"code.gitea.io/gitea/models"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/context"
"github.com/gorilla/feeds"
)
// ShowRepoFeed shows user activity on the repo as RSS / Atom feed
func ShowRepoFeed(ctx *context.Context, repo *repo_model.Repository, formatType string) {
actions, err := models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedRepo: repo,
Actor: ctx.Doer,
IncludePrivate: true,
Date: ctx.FormString("date"),
})
if err != nil {
ctx.ServerError("GetFeeds", err)
return
}
feed := &feeds.Feed{
Title: ctx.Tr("home.feed_of", repo.FullName()),
Link: &feeds.Link{Href: repo.HTMLURL()},
Description: repo.Description,
Created: time.Now(),
}
feed.Items, err = feedActionsToFeedItems(ctx, actions)
if err != nil {
ctx.ServerError("convert feed", err)
return
}
writeFeed(ctx, feed, formatType)
}
+17 -17
View File
@@ -5,6 +5,8 @@
package web
import (
"fmt"
"html"
"net/http"
"net/url"
"path"
@@ -14,8 +16,6 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"github.com/unknwon/com"
)
func goGet(ctx *context.Context) {
@@ -48,7 +48,7 @@ func goGet(ctx *context.Context) {
</body>
</html>
`))
ctx.Status(400)
ctx.Status(http.StatusBadRequest)
return
}
branchName := setting.Repository.DefaultBranch
@@ -65,23 +65,23 @@ func goGet(ctx *context.Context) {
if appURL.Scheme == string(setting.HTTP) {
insecure = "--insecure "
}
ctx.RespHeader().Set("Content-Type", "text/html")
ctx.Status(http.StatusOK)
_, _ = ctx.Write([]byte(com.Expand(`<!doctype html>
goGetImport := context.ComposeGoGetImport(ownerName, trimmedRepoName)
goImportContent := fmt.Sprintf("%s git %s", goGetImport, repo_model.ComposeHTTPSCloneURL(ownerName, repoName) /*CloneLink*/)
goSourceContent := fmt.Sprintf("%s _ %s %s", goGetImport, prefix+"{/dir}" /*GoDocDirectory*/, prefix+"{/dir}/{file}#L{line}" /*GoDocFile*/)
goGetCli := fmt.Sprintf("go get %s%s", insecure, goGetImport)
res := fmt.Sprintf(`<!doctype html>
<html>
<head>
<meta name="go-import" content="{GoGetImport} git {CloneLink}">
<meta name="go-source" content="{GoGetImport} _ {GoDocDirectory} {GoDocFile}">
<meta name="go-import" content="%s">
<meta name="go-source" content="%s">
</head>
<body>
go get {Insecure}{GoGetImport}
%s
</body>
</html>
`, map[string]string{
"GoGetImport": context.ComposeGoGetImport(ownerName, trimmedRepoName),
"CloneLink": repo_model.ComposeHTTPSCloneURL(ownerName, repoName),
"GoDocDirectory": prefix + "{/dir}",
"GoDocFile": prefix + "{/dir}/{file}#L{line}",
"Insecure": insecure,
})))
</html>`, html.EscapeString(goImportContent), html.EscapeString(goSourceContent), html.EscapeString(goGetCli))
ctx.RespHeader().Set("Content-Type", "text/html")
_, _ = ctx.Write([]byte(res))
}
+143
View File
@@ -0,0 +1,143 @@
// 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 healthcheck
import (
"net/http"
"os"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
type status string
const (
// pass healthy (acceptable aliases: "ok" to support Node's Terminus and "up" for Java's SpringBoot)
// fail unhealthy (acceptable aliases: "error" to support Node's Terminus and "down" for Java's SpringBoot), and
// warn healthy, with some concerns.
//
// ref https://datatracker.ietf.org/doc/html/draft-inadarei-api-health-check#section-3.1
// status: (required) indicates whether the service status is acceptable
// or not. API publishers SHOULD use following values for the field:
// The value of the status field is case-insensitive and is tightly
// related with the HTTP response code returned by the health endpoint.
// For "pass" status, HTTP response code in the 2xx-3xx range MUST be
// used. For "fail" status, HTTP response code in the 4xx-5xx range
// MUST be used. In case of the "warn" status, endpoints MUST return
// HTTP status in the 2xx-3xx range, and additional information SHOULD
// be provided, utilizing optional fields of the response.
pass status = "pass"
fail status = "fail"
warn status = "warn"
)
func (s status) ToHTTPStatus() int {
if s == pass || s == warn {
return http.StatusOK
}
return http.StatusFailedDependency
}
type checks map[string][]componentStatus
// response is the data returned by the health endpoint, which will be marshaled to JSON format
type response struct {
Status status `json:"status"`
Description string `json:"description"` // a human-friendly description of the service
Checks checks `json:"checks,omitempty"` // The Checks Object, should be omitted on installation route
}
// componentStatus presents one status of a single check object
// an object that provides detailed health statuses of additional downstream systems and endpoints
// which can affect the overall health of the main API.
type componentStatus struct {
Status status `json:"status"`
Time string `json:"time"` // the date-time, in ISO8601 format
Output string `json:"output,omitempty"` // this field SHOULD be omitted for "pass" state.
}
// Check is the health check API handler
func Check(w http.ResponseWriter, r *http.Request) {
rsp := response{
Status: pass,
Description: setting.AppName,
Checks: make(checks),
}
statuses := make([]status, 0)
if setting.InstallLock {
statuses = append(statuses, checkDatabase(rsp.Checks))
statuses = append(statuses, checkCache(rsp.Checks))
}
for _, s := range statuses {
if s != pass {
rsp.Status = fail
break
}
}
data, _ := json.MarshalIndent(rsp, "", " ")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(rsp.Status.ToHTTPStatus())
_, _ = w.Write(data)
}
// database checks gitea database status
func checkDatabase(checks checks) status {
st := componentStatus{}
if err := db.GetEngine(db.DefaultContext).Ping(); err != nil {
st.Status = fail
st.Time = getCheckTime()
log.Error("database ping failed with error: %v", err)
} else {
st.Status = pass
st.Time = getCheckTime()
}
if setting.Database.UseSQLite3 && st.Status == pass {
if !setting.EnableSQLite3 {
st.Status = fail
st.Time = getCheckTime()
log.Error("SQLite3 health check failed with error: %v", "this Gitea binary is built without SQLite3 enabled")
} else {
if _, err := os.Stat(setting.Database.Path); err != nil {
st.Status = fail
st.Time = getCheckTime()
log.Error("SQLite3 file exists check failed with error: %v", err)
}
}
}
checks["database:ping"] = []componentStatus{st}
return st.Status
}
// cache checks gitea cache status
func checkCache(checks checks) status {
if !setting.CacheService.Enabled {
return pass
}
st := componentStatus{}
if err := cache.Ping(); err != nil {
st.Status = fail
st.Time = getCheckTime()
log.Error("cache ping failed with error: %v", err)
} else {
st.Status = pass
st.Time = getCheckTime()
}
checks["cache:ping"] = []componentStatus{st}
return st.Status
}
func getCheckTime() string {
return time.Now().UTC().Format(time.RFC3339)
}
+4 -4
View File
@@ -25,14 +25,14 @@ const (
// Home render home page
func Home(ctx *context.Context) {
if ctx.IsSigned {
if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm {
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
ctx.HTML(http.StatusOK, auth.TplActivate)
} else if !ctx.User.IsActive || ctx.User.ProhibitLogin {
log.Info("Failed authentication attempt for %s from %s", ctx.User.Name, ctx.RemoteAddr())
} else if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin {
log.Info("Failed authentication attempt for %s from %s", ctx.Doer.Name, ctx.RemoteAddr())
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
} else if ctx.User.MustChangePassword {
} else if ctx.Doer.MustChangePassword {
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI())
+2 -2
View File
@@ -21,13 +21,13 @@ func Metrics(resp http.ResponseWriter, req *http.Request) {
}
header := req.Header.Get("Authorization")
if header == "" {
http.Error(resp, "", 401)
http.Error(resp, "", http.StatusUnauthorized)
return
}
got := []byte(header)
want := []byte("Bearer " + setting.Metrics.Token)
if subtle.ConstantTimeCompare(got, want) != 1 {
http.Error(resp, "", 401)
http.Error(resp, "", http.StatusUnauthorized)
return
}
promhttp.Handler().ServeHTTP(resp, req)
+99
View File
@@ -0,0 +1,99 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// 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 misc
import (
"net/http"
"strings"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"mvdan.cc/xurls/v2"
)
// Markdown render markdown document to HTML
func Markdown(ctx *context.Context) {
// swagger:operation POST /markdown miscellaneous renderMarkdown
// ---
// summary: Render a markdown document as HTML
// parameters:
// - name: body
// in: body
// schema:
// "$ref": "#/definitions/MarkdownOption"
// consumes:
// - application/json
// produces:
// - text/html
// responses:
// "200":
// "$ref": "#/responses/MarkdownRender"
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.MarkdownOption)
if ctx.HasAPIError() {
ctx.Error(http.StatusUnprocessableEntity, "", ctx.GetErrMsg())
return
}
if len(form.Text) == 0 {
_, _ = ctx.Write([]byte(""))
return
}
switch form.Mode {
case "comment":
fallthrough
case "gfm":
urlPrefix := form.Context
meta := map[string]string{}
if !strings.HasPrefix(setting.AppSubURL+"/", urlPrefix) {
// check if urlPrefix is already set to a URL
linkRegex, _ := xurls.StrictMatchingScheme("https?://")
m := linkRegex.FindStringIndex(urlPrefix)
if m == nil {
urlPrefix = util.URLJoin(setting.AppURL, form.Context)
}
}
if ctx.Repo != nil && ctx.Repo.Repository != nil {
// "gfm" = Github Flavored Markdown - set this to render as a document
if form.Mode == "gfm" {
meta = ctx.Repo.Repository.ComposeDocumentMetas()
} else {
meta = ctx.Repo.Repository.ComposeMetas()
}
}
if form.Mode == "gfm" {
meta["mode"] = "document"
}
if err := markdown.Render(&markup.RenderContext{
Ctx: ctx,
URLPrefix: urlPrefix,
Metas: meta,
IsWiki: form.Wiki,
}, strings.NewReader(form.Text), ctx.Resp); err != nil {
ctx.Error(http.StatusInternalServerError, err.Error())
return
}
default:
if err := markdown.RenderRaw(&markup.RenderContext{
Ctx: ctx,
URLPrefix: form.Context,
}, strings.NewReader(form.Text), ctx.Resp); err != nil {
ctx.Error(http.StatusInternalServerError, err.Error())
return
}
}
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2017 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 misc
import (
"net/http"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
)
// tplSwagger swagger page template
const tplSwagger base.TplName = "swagger/ui"
// Swagger render swagger-ui page with v1 json
func Swagger(ctx *context.Context) {
ctx.Data["APIJSONVersion"] = "v1"
ctx.HTML(http.StatusOK, tplSwagger)
}
+9 -8
View File
@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
@@ -39,7 +40,7 @@ func Home(ctx *context.Context) {
org := ctx.Org.Organization
if !models.HasOrgOrUserVisible(org.AsUser(), ctx.User) {
if !organization.HasOrgOrUserVisible(ctx, org.AsUser(), ctx.Doer) {
ctx.NotFound("HasOrgOrUserVisible", nil)
return
}
@@ -113,7 +114,7 @@ func Home(ctx *context.Context) {
OwnerID: org.ID,
OrderBy: orderBy,
Private: ctx.IsSigned,
Actor: ctx.User,
Actor: ctx.Doer,
Language: language,
IncludeDescription: setting.UI.SearchRepoDescription,
})
@@ -122,28 +123,28 @@ func Home(ctx *context.Context) {
return
}
opts := &models.FindOrgMembersOpts{
opts := &organization.FindOrgMembersOpts{
OrgID: org.ID,
PublicOnly: true,
ListOptions: db.ListOptions{Page: 1, PageSize: 25},
}
if ctx.User != nil {
isMember, err := org.IsOrgMember(ctx.User.ID)
if ctx.Doer != nil {
isMember, err := org.IsOrgMember(ctx.Doer.ID)
if err != nil {
ctx.Error(http.StatusInternalServerError, "IsOrgMember")
return
}
opts.PublicOnly = !isMember && !ctx.User.IsAdmin
opts.PublicOnly = !isMember && !ctx.Doer.IsAdmin
}
members, _, err := models.FindOrgMembers(opts)
members, _, err := organization.FindOrgMembers(opts)
if err != nil {
ctx.ServerError("FindOrgMembers", err)
return
}
membersCount, err := models.CountOrgMembers(opts)
membersCount, err := organization.CountOrgMembers(opts)
if err != nil {
ctx.ServerError("CountOrgMembers", err)
return
+15 -14
View File
@@ -9,6 +9,7 @@ import (
"net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
@@ -31,21 +32,21 @@ func Members(ctx *context.Context) {
page = 1
}
opts := &models.FindOrgMembersOpts{
opts := &organization.FindOrgMembersOpts{
OrgID: org.ID,
PublicOnly: true,
}
if ctx.User != nil {
isMember, err := ctx.Org.Organization.IsOrgMember(ctx.User.ID)
if ctx.Doer != nil {
isMember, err := ctx.Org.Organization.IsOrgMember(ctx.Doer.ID)
if err != nil {
ctx.Error(http.StatusInternalServerError, "IsOrgMember")
return
}
opts.PublicOnly = !isMember && !ctx.User.IsAdmin
opts.PublicOnly = !isMember && !ctx.Doer.IsAdmin
}
total, err := models.CountOrgMembers(opts)
total, err := organization.CountOrgMembers(opts)
if err != nil {
ctx.Error(http.StatusInternalServerError, "CountOrgMembers")
return
@@ -54,7 +55,7 @@ func Members(ctx *context.Context) {
pager := context.NewPagination(int(total), setting.UI.MembersPagingNum, page, 5)
opts.ListOptions.Page = page
opts.ListOptions.PageSize = setting.UI.MembersPagingNum
members, membersIsPublic, err := models.FindOrgMembers(opts)
members, membersIsPublic, err := organization.FindOrgMembers(opts)
if err != nil {
ctx.ServerError("GetMembers", err)
return
@@ -80,24 +81,24 @@ func MembersAction(ctx *context.Context) {
var err error
switch ctx.Params(":action") {
case "private":
if ctx.User.ID != uid && !ctx.Org.IsOwner {
if ctx.Doer.ID != uid && !ctx.Org.IsOwner {
ctx.Error(http.StatusNotFound)
return
}
err = models.ChangeOrgUserStatus(org.ID, uid, false)
err = organization.ChangeOrgUserStatus(org.ID, uid, false)
case "public":
if ctx.User.ID != uid && !ctx.Org.IsOwner {
if ctx.Doer.ID != uid && !ctx.Org.IsOwner {
ctx.Error(http.StatusNotFound)
return
}
err = models.ChangeOrgUserStatus(org.ID, uid, true)
err = organization.ChangeOrgUserStatus(org.ID, uid, true)
case "remove":
if !ctx.Org.IsOwner {
ctx.Error(http.StatusNotFound)
return
}
err = org.RemoveMember(uid)
if models.IsErrLastOrgOwner(err) {
err = models.RemoveOrgUser(org.ID, uid)
if organization.IsErrLastOrgOwner(err) {
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": ctx.Org.OrgLink + "/members",
@@ -105,8 +106,8 @@ func MembersAction(ctx *context.Context) {
return
}
case "leave":
err = org.RemoveMember(ctx.User.ID)
if models.IsErrLastOrgOwner(err) {
err = models.RemoveOrgUser(org.ID, ctx.Doer.ID)
if organization.IsErrLastOrgOwner(err) {
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": ctx.Org.OrgLink + "/members",
+6 -6
View File
@@ -9,8 +9,8 @@ import (
"errors"
"net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
@@ -29,7 +29,7 @@ const (
func Create(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("new_org")
ctx.Data["DefaultOrgVisibilityMode"] = setting.Service.DefaultOrgVisibilityMode
if !ctx.User.CanCreateOrganization() {
if !ctx.Doer.CanCreateOrganization() {
ctx.ServerError("Not allowed", errors.New(ctx.Tr("org.form.create_org_not_allowed")))
return
}
@@ -41,7 +41,7 @@ func CreatePost(ctx *context.Context) {
form := *web.GetForm(ctx).(*forms.CreateOrgForm)
ctx.Data["Title"] = ctx.Tr("new_org")
if !ctx.User.CanCreateOrganization() {
if !ctx.Doer.CanCreateOrganization() {
ctx.ServerError("Not allowed", errors.New(ctx.Tr("org.form.create_org_not_allowed")))
return
}
@@ -51,7 +51,7 @@ func CreatePost(ctx *context.Context) {
return
}
org := &models.Organization{
org := &organization.Organization{
Name: form.OrgName,
IsActive: true,
Type: user_model.UserTypeOrganization,
@@ -59,7 +59,7 @@ func CreatePost(ctx *context.Context) {
RepoAdminChangeTeamAccess: form.RepoAdminChangeTeamAccess,
}
if err := models.CreateOrganization(org, ctx.User); err != nil {
if err := organization.CreateOrganization(org, ctx.Doer); err != nil {
ctx.Data["Err_OrgName"] = true
switch {
case user_model.IsErrUserAlreadyExist(err):
@@ -68,7 +68,7 @@ func CreatePost(ctx *context.Context) {
ctx.RenderWithErr(ctx.Tr("org.form.name_reserved", err.(db.ErrNameReserved).Name), tplCreateOrg, &form)
case db.IsErrNamePatternNotAllowed(err):
ctx.RenderWithErr(ctx.Tr("org.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplCreateOrg, &form)
case models.IsErrUserNotAllowedCreateOrg(err):
case organization.IsErrUserNotAllowedCreateOrg(err):
ctx.RenderWithErr(ctx.Tr("org.form.create_org_not_allowed"), tplCreateOrg, &form)
default:
ctx.ServerError("CreateOrganization", err)
+5 -4
View File
@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/context"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/forms"
)
@@ -48,7 +49,7 @@ func NewLabel(ctx *context.Context) {
Description: form.Description,
Color: form.Color,
}
if err := models.NewLabel(l); err != nil {
if err := models.NewLabel(ctx, l); err != nil {
ctx.ServerError("NewLabel", err)
return
}
@@ -100,9 +101,9 @@ func InitializeLabels(ctx *context.Context) {
return
}
if err := models.InitializeLabels(db.DefaultContext, ctx.Org.Organization.ID, form.TemplateName, true); err != nil {
if models.IsErrIssueLabelTemplateLoad(err) {
originalErr := err.(models.ErrIssueLabelTemplateLoad).OriginalError
if err := repo_module.InitializeLabels(ctx, ctx.Org.Organization.ID, form.TemplateName, true); err != nil {
if repo_module.IsErrIssueLabelTemplateLoad(err) {
originalErr := err.(repo_module.ErrIssueLabelTemplateLoad).OriginalError
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, originalErr))
ctx.Redirect(ctx.Org.OrgLink + "/settings/labels")
return
+6 -2
View File
@@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
user_setting "code.gitea.io/gitea/routers/web/user/setting"
@@ -96,7 +97,7 @@ func SettingsPost(ctx *context.Context) {
org.Name = form.Name
org.LowerName = strings.ToLower(form.Name)
if ctx.User.IsAdmin {
if ctx.Doer.IsAdmin {
org.MaxRepoCreation = form.MaxRepoCreation
}
@@ -181,6 +182,9 @@ func SettingsDelete(ctx *context.Context) {
if models.IsErrUserOwnRepos(err) {
ctx.Flash.Error(ctx.Tr("form.org_still_own_repo"))
ctx.Redirect(ctx.Org.OrgLink + "/settings/delete")
} else if models.IsErrUserOwnPackages(err) {
ctx.Flash.Error(ctx.Tr("form.org_still_own_packages"))
ctx.Redirect(ctx.Org.OrgLink + "/settings/delete")
} else {
ctx.ServerError("DeleteOrganization", err)
}
@@ -232,6 +236,6 @@ func Labels(ctx *context.Context) {
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsOrgSettingsLabels"] = true
ctx.Data["RequireTribute"] = true
ctx.Data["LabelTemplates"] = models.LabelTemplates
ctx.Data["LabelTemplates"] = repo_module.LabelTemplates
ctx.HTML(http.StatusOK, tplSettingsLabels)
}
+73 -24
View File
@@ -13,13 +13,17 @@ import (
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/utils"
"code.gitea.io/gitea/services/forms"
@@ -43,7 +47,7 @@ func Teams(ctx *context.Context) {
ctx.Data["PageIsOrgTeams"] = true
for _, t := range ctx.Org.Teams {
if err := t.GetMembers(&models.SearchMembersOptions{}); err != nil {
if err := t.GetMembersCtx(ctx); err != nil {
ctx.ServerError("GetMembers", err)
return
}
@@ -69,11 +73,11 @@ func TeamsAction(ctx *context.Context) {
ctx.Error(http.StatusNotFound)
return
}
err = ctx.Org.Team.AddMember(ctx.User.ID)
err = models.AddTeamMember(ctx.Org.Team, ctx.Doer.ID)
case "leave":
err = ctx.Org.Team.RemoveMember(ctx.User.ID)
err = models.RemoveTeamMember(ctx.Org.Team, ctx.Doer.ID)
if err != nil {
if models.IsErrLastOrgOwner(err) {
if organization.IsErrLastOrgOwner(err) {
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
} else {
log.Error("Action(%s): %v", ctx.Params(":action"), err)
@@ -94,9 +98,9 @@ func TeamsAction(ctx *context.Context) {
ctx.Error(http.StatusNotFound)
return
}
err = ctx.Org.Team.RemoveMember(uid)
err = models.RemoveTeamMember(ctx.Org.Team, uid)
if err != nil {
if models.IsErrLastOrgOwner(err) {
if organization.IsErrLastOrgOwner(err) {
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
} else {
log.Error("Action(%s): %v", ctx.Params(":action"), err)
@@ -139,14 +143,14 @@ func TeamsAction(ctx *context.Context) {
if ctx.Org.Team.IsMember(u.ID) {
ctx.Flash.Error(ctx.Tr("org.teams.add_duplicate_users"))
} else {
err = ctx.Org.Team.AddMember(u.ID)
err = models.AddTeamMember(ctx.Org.Team, u.ID)
}
page = "team"
}
if err != nil {
if models.IsErrLastOrgOwner(err) {
if organization.IsErrLastOrgOwner(err) {
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
} else {
log.Error("Action(%s): %v", ctx.Params(":action"), err)
@@ -191,13 +195,13 @@ func TeamsRepoAction(ctx *context.Context) {
ctx.ServerError("GetRepositoryByName", err)
return
}
err = ctx.Org.Team.AddRepository(repo)
err = models.AddRepository(ctx.Org.Team, repo)
case "remove":
err = ctx.Org.Team.RemoveRepository(ctx.FormInt64("repoid"))
err = models.RemoveRepository(ctx.Org.Team, ctx.FormInt64("repoid"))
case "addall":
err = ctx.Org.Team.AddAllRepositories()
err = models.AddAllRepositories(ctx.Org.Team)
case "removeall":
err = ctx.Org.Team.RemoveAllRepositories()
err = models.RemoveAllRepositories(ctx.Org.Team)
}
if err != nil {
@@ -220,7 +224,7 @@ func NewTeam(ctx *context.Context) {
ctx.Data["Title"] = ctx.Org.Organization.FullName
ctx.Data["PageIsOrgTeams"] = true
ctx.Data["PageIsOrgTeamsNew"] = true
ctx.Data["Team"] = &models.Team{}
ctx.Data["Team"] = &organization.Team{}
ctx.Data["Units"] = unit_model.Units
ctx.HTML(http.StatusOK, tplTeamNew)
}
@@ -251,7 +255,7 @@ func NewTeamPost(ctx *context.Context) {
p = unit_model.MinUnitAccessMode(unitPerms)
}
t := &models.Team{
t := &organization.Team{
OrgID: ctx.Org.Organization.ID,
Name: form.TeamName,
Description: form.Description,
@@ -261,9 +265,9 @@ func NewTeamPost(ctx *context.Context) {
}
if t.AccessMode < perm.AccessModeAdmin {
units := make([]*models.TeamUnit, 0, len(unitPerms))
units := make([]*organization.TeamUnit, 0, len(unitPerms))
for tp, perm := range unitPerms {
units = append(units, &models.TeamUnit{
units = append(units, &organization.TeamUnit{
OrgID: ctx.Org.Organization.ID,
Type: tp,
AccessMode: perm,
@@ -291,7 +295,7 @@ func NewTeamPost(ctx *context.Context) {
if err := models.NewTeam(t); err != nil {
ctx.Data["Err_TeamName"] = true
switch {
case models.IsErrTeamAlreadyExist(err):
case organization.IsErrTeamAlreadyExist(err):
ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
default:
ctx.ServerError("NewTeam", err)
@@ -307,7 +311,7 @@ func TeamMembers(ctx *context.Context) {
ctx.Data["Title"] = ctx.Org.Team.Name
ctx.Data["PageIsOrgTeams"] = true
ctx.Data["PageIsOrgTeamMembers"] = true
if err := ctx.Org.Team.GetMembers(&models.SearchMembersOptions{}); err != nil {
if err := ctx.Org.Team.GetMembersCtx(ctx); err != nil {
ctx.ServerError("GetMembers", err)
return
}
@@ -320,7 +324,7 @@ func TeamRepositories(ctx *context.Context) {
ctx.Data["Title"] = ctx.Org.Team.Name
ctx.Data["PageIsOrgTeams"] = true
ctx.Data["PageIsOrgTeamRepos"] = true
if err := ctx.Org.Team.GetRepositories(&models.SearchOrgTeamOptions{}); err != nil {
if err := ctx.Org.Team.GetRepositoriesCtx(ctx); err != nil {
ctx.ServerError("GetRepositories", err)
return
}
@@ -328,6 +332,51 @@ func TeamRepositories(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplTeamRepositories)
}
// SearchTeam api for searching teams
func SearchTeam(ctx *context.Context) {
listOptions := db.ListOptions{
Page: ctx.FormInt("page"),
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
}
opts := &organization.SearchTeamOptions{
UserID: ctx.Doer.ID,
Keyword: ctx.FormTrim("q"),
OrgID: ctx.Org.Organization.ID,
IncludeDesc: ctx.FormString("include_desc") == "" || ctx.FormBool("include_desc"),
ListOptions: listOptions,
}
teams, maxResults, err := organization.SearchTeam(opts)
if err != nil {
log.Error("SearchTeam failed: %v", err)
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"ok": false,
"error": "SearchTeam internal failure",
})
return
}
apiTeams := make([]*api.Team, len(teams))
for i := range teams {
if err := teams[i].GetUnits(); err != nil {
log.Error("Team GetUnits failed: %v", err)
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"ok": false,
"error": "SearchTeam failed to get units",
})
return
}
apiTeams[i] = convert.ToTeam(teams[i])
}
ctx.SetTotalCountHeader(maxResults)
ctx.JSON(http.StatusOK, map[string]interface{}{
"ok": true,
"data": apiTeams,
})
}
// EditTeam render team edit page
func EditTeam(ctx *context.Context) {
ctx.Data["Title"] = ctx.Org.Organization.FullName
@@ -374,17 +423,17 @@ func EditTeamPost(ctx *context.Context) {
}
t.Description = form.Description
if t.AccessMode < perm.AccessModeAdmin {
units := make([]models.TeamUnit, 0, len(unitPerms))
units := make([]organization.TeamUnit, 0, len(unitPerms))
for tp, perm := range unitPerms {
units = append(units, models.TeamUnit{
units = append(units, organization.TeamUnit{
OrgID: t.OrgID,
TeamID: t.ID,
Type: tp,
AccessMode: perm,
})
}
if err := models.UpdateTeamUnits(t, units); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadIssue", err.Error())
if err := organization.UpdateTeamUnits(t, units); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateTeamUnits", err.Error())
return
}
}
@@ -403,7 +452,7 @@ func EditTeamPost(ctx *context.Context) {
if err := models.UpdateTeam(t, isAuthChanged, isIncludeAllChanged); err != nil {
ctx.Data["Err_TeamName"] = true
switch {
case models.IsErrTeamAlreadyExist(err):
case organization.IsErrTeamAlreadyExist(err):
ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
default:
ctx.ServerError("UpdateTeam", err)
+4 -4
View File
@@ -44,7 +44,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) {
}
defer file.Close()
attach, err := attachment.UploadAttachment(file, ctx.User.ID, repoID, 0, header.Filename, allowedTypes)
attach, err := attachment.UploadAttachment(file, ctx.Doer.ID, repoID, 0, header.Filename, allowedTypes)
if err != nil {
if upload.IsErrFileTypeForbidden(err) {
ctx.Error(http.StatusBadRequest, err.Error())
@@ -68,7 +68,7 @@ func DeleteAttachment(ctx *context.Context) {
ctx.Error(http.StatusBadRequest, err.Error())
return
}
if !ctx.IsSigned || (ctx.User.ID != attach.UploaderID) {
if !ctx.IsSigned || (ctx.Doer.ID != attach.UploaderID) {
ctx.Error(http.StatusForbidden)
return
}
@@ -101,12 +101,12 @@ func GetAttachment(ctx *context.Context) {
}
if repository == nil { // If not linked
if !(ctx.IsSigned && attach.UploaderID == ctx.User.ID) { // We block if not the uploader
if !(ctx.IsSigned && attach.UploaderID == ctx.Doer.ID) { // We block if not the uploader
ctx.Error(http.StatusNotFound)
return
}
} else { // If we have the repository we check access
perm, err := models.GetUserRepoPermission(repository, ctx.User)
perm, err := models.GetUserRepoPermission(ctx, repository, ctx.Doer)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err.Error())
return
+10 -10
View File
@@ -56,7 +56,7 @@ func Branches(ctx *context.Context) {
ctx.Data["IsWriter"] = ctx.Repo.CanWrite(unit.TypeCode)
ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
ctx.Data["CanPull"] = ctx.Repo.CanWrite(unit.TypeCode) ||
(ctx.IsSigned && repo_model.HasForkedRepo(ctx.User.ID, ctx.Repo.Repository.ID))
(ctx.IsSigned && repo_model.HasForkedRepo(ctx.Doer.ID, ctx.Repo.Repository.ID))
ctx.Data["PageIsViewCode"] = true
ctx.Data["PageIsBranches"] = true
@@ -90,7 +90,7 @@ func DeleteBranchPost(ctx *context.Context) {
defer redirect(ctx)
branchName := ctx.FormString("name")
if err := repo_service.DeleteBranch(ctx.User, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
if err := repo_service.DeleteBranch(ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
switch {
case git.IsErrBranchNotExist(err):
log.Debug("DeleteBranch: Can't delete non existing branch '%s'", branchName)
@@ -129,7 +129,7 @@ func RestoreBranchPost(ctx *context.Context) {
if err := git.Push(ctx, ctx.Repo.Repository.RepoPath(), git.PushOptions{
Remote: ctx.Repo.Repository.RepoPath(),
Branch: fmt.Sprintf("%s:%s%s", deletedBranch.Commit, git.BranchPrefix, deletedBranch.Name),
Env: models.PushingEnvironment(ctx.User, ctx.Repo.Repository),
Env: repo_module.PushingEnvironment(ctx.Doer, ctx.Repo.Repository),
}); err != nil {
if strings.Contains(err.Error(), "already exists") {
log.Debug("RestoreBranch: Can't restore branch '%s', since one with same name already exist", deletedBranch.Name)
@@ -147,8 +147,8 @@ func RestoreBranchPost(ctx *context.Context) {
RefFullName: git.BranchPrefix + deletedBranch.Name,
OldCommitID: git.EmptySHA,
NewCommitID: deletedBranch.Commit,
PusherID: ctx.User.ID,
PusherName: ctx.User.Name,
PusherID: ctx.Doer.ID,
PusherName: ctx.Doer.Name,
RepoUserName: ctx.Repo.Owner.Name,
RepoName: ctx.Repo.Repository.Name,
}); err != nil {
@@ -279,7 +279,7 @@ func loadOneBranch(ctx *context.Context, rawBranch, defaultBranch *git.Branch, p
}
if repo, ok := repoIDToRepo[pr.BaseRepoID]; ok {
pr.BaseRepo = repo
} else if err := pr.LoadBaseRepo(); err != nil {
} else if err := pr.LoadBaseRepoCtx(ctx); err != nil {
ctx.ServerError("pr.LoadBaseRepo", err)
return nil
} else {
@@ -290,7 +290,7 @@ func loadOneBranch(ctx *context.Context, rawBranch, defaultBranch *git.Branch, p
if pr.HasMerged {
baseGitRepo, ok := repoIDToGitRepo[pr.BaseRepoID]
if !ok {
baseGitRepo, err = git.OpenRepositoryCtx(ctx, pr.BaseRepo.RepoPath())
baseGitRepo, err = git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
if err != nil {
ctx.ServerError("OpenRepository", err)
return nil
@@ -364,11 +364,11 @@ func CreateBranch(ctx *context.Context) {
if ctx.Repo.IsViewBranch {
target = ctx.Repo.BranchName
}
err = release_service.CreateNewTag(ctx, ctx.User, ctx.Repo.Repository, target, form.NewBranchName, "")
err = release_service.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, target, form.NewBranchName, "")
} else if ctx.Repo.IsViewBranch {
err = repo_service.CreateNewBranch(ctx, ctx.User, ctx.Repo.Repository, ctx.Repo.BranchName, form.NewBranchName)
err = repo_service.CreateNewBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.BranchName, form.NewBranchName)
} else {
err = repo_service.CreateNewBranchFromCommit(ctx, ctx.User, ctx.Repo.Repository, ctx.Repo.CommitID, form.NewBranchName)
err = repo_service.CreateNewBranchFromCommit(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.CommitID, form.NewBranchName)
}
if err != nil {
if models.IsErrTagAlreadyExists(err) {
+3 -6
View File
@@ -47,8 +47,6 @@ func CherryPick(ctx *context.Context) {
ctx.Data["commit_message"] = splits[1]
}
ctx.Data["RequireHighlightJS"] = true
canCommit := renderCommitRights(ctx)
ctx.Data["TreePath"] = ""
@@ -77,7 +75,6 @@ func CherryPickPost(ctx *context.Context) {
ctx.Data["CherryPickType"] = "cherry-pick"
}
ctx.Data["RequireHighlightJS"] = true
canCommit := renderCommitRights(ctx)
branchName := ctx.Repo.BranchName
if form.CommitChoice == frmCommitChoiceNewBranch {
@@ -127,7 +124,7 @@ func CherryPickPost(ctx *context.Context) {
// First lets try the simple plain read-tree -m approach
opts.Content = sha
if _, err := files.CherryPick(ctx, ctx.Repo.Repository, ctx.User, form.Revert, opts); err != nil {
if _, err := files.CherryPick(ctx, ctx.Repo.Repository, ctx.Doer, form.Revert, opts); err != nil {
if models.IsErrBranchAlreadyExists(err) {
// User has specified a branch that already exists
branchErr := err.(models.ErrBranchAlreadyExists)
@@ -151,7 +148,7 @@ func CherryPickPost(ctx *context.Context) {
return
}
} else {
if err := git.GetRawDiff(ctx, ctx.Repo.Repository.RepoPath(), sha, git.RawDiffType("patch"), buf); err != nil {
if err := git.GetRawDiff(ctx.Repo.GitRepo, sha, git.RawDiffType("patch"), buf); err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound("GetRawDiff", errors.New("commit "+ctx.Params(":sha")+" does not exist."))
return
@@ -164,7 +161,7 @@ func CherryPickPost(ctx *context.Context) {
opts.Content = buf.String()
ctx.Data["FileContent"] = opts.Content
if _, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.User, opts); err != nil {
if _, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Doer, opts); err != nil {
if models.IsErrBranchAlreadyExists(err) {
// User has specified a branch that already exists
branchErr := err.(models.ErrBranchAlreadyExists)
+16 -8
View File
@@ -7,13 +7,13 @@ package repo
import (
"errors"
"fmt"
"net/http"
"strings"
"code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/charset"
@@ -253,7 +253,6 @@ func FileHistory(ctx *context.Context) {
// Diff show different from current commit to previous commit
func Diff(ctx *context.Context) {
ctx.Data["PageIsDiff"] = true
ctx.Data["RequireHighlightJS"] = true
ctx.Data["RequireTribute"] = true
userName := ctx.Repo.Owner.Name
@@ -265,7 +264,7 @@ func Diff(ctx *context.Context) {
)
if ctx.Data["PageIsWiki"] != nil {
gitRepo, err = git.OpenRepositoryCtx(ctx, ctx.Repo.Repository.WikiPath())
gitRepo, err = git.OpenRepository(ctx, ctx.Repo.Repository.WikiPath())
if err != nil {
ctx.ServerError("Repo.GitRepo.GetCommit", err)
return
@@ -381,15 +380,24 @@ func Diff(ctx *context.Context) {
// RawDiff dumps diff results of repository in given commit ID to io.Writer
func RawDiff(ctx *context.Context) {
var repoPath string
var gitRepo *git.Repository
if ctx.Data["PageIsWiki"] != nil {
repoPath = ctx.Repo.Repository.WikiPath()
wikiRepo, err := git.OpenRepository(ctx, ctx.Repo.Repository.WikiPath())
if err != nil {
ctx.ServerError("OpenRepository", err)
return
}
defer wikiRepo.Close()
gitRepo = wikiRepo
} else {
repoPath = repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
gitRepo = ctx.Repo.GitRepo
if gitRepo == nil {
ctx.ServerError("GitRepo not open", fmt.Errorf("no open git repo for '%s'", ctx.Repo.Repository.FullName()))
return
}
}
if err := git.GetRawDiff(
ctx,
repoPath,
gitRepo,
ctx.Params(":sha"),
git.RawDiffType(ctx.Params(":ext")),
ctx.Resp,
+37 -20
View File
@@ -18,7 +18,6 @@ import (
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
@@ -144,6 +143,11 @@ func setCsvCompareContext(ctx *context.Context) {
if err == errTooLarge {
return CsvDiffResult{nil, err.Error()}
}
if err != nil {
log.Error("CreateCsvDiff error whilst creating baseReader from file %s in commit %s in %s: %v", diffFile.Name, baseCommit.ID.String(), ctx.Repo.Repository.Name, err)
return CsvDiffResult{nil, "unable to load file from base commit"}
}
headReader, headBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, Filename: diffFile.Name}, headCommit)
if headBlobCloser != nil {
defer headBlobCloser.Close()
@@ -151,13 +155,17 @@ func setCsvCompareContext(ctx *context.Context) {
if err == errTooLarge {
return CsvDiffResult{nil, err.Error()}
}
if err != nil {
log.Error("CreateCsvDiff error whilst creating headReader from file %s in commit %s in %s: %v", diffFile.Name, headCommit.ID.String(), ctx.Repo.Repository.Name, err)
return CsvDiffResult{nil, "unable to load file from head commit"}
}
sections, err := gitdiff.CreateCsvDiff(diffFile, baseReader, headReader)
if err != nil {
errMessage, err := csv_module.FormatError(err, ctx.Locale)
if err != nil {
log.Error("RenderCsvDiff failed: %v", err)
return CsvDiffResult{nil, ""}
log.Error("CreateCsvDiff FormatError failed: %v", err)
return CsvDiffResult{nil, "unknown csv diff error"}
}
return CsvDiffResult{nil, errMessage}
}
@@ -269,7 +277,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
}
return nil
}
if err := ci.HeadRepo.GetOwner(db.DefaultContext); err != nil {
if err := ci.HeadRepo.GetOwner(ctx); err != nil {
if user_model.IsErrUserNotExist(err) {
ctx.NotFound("GetUserByName", nil)
} else {
@@ -299,6 +307,13 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
ci.BaseBranch = baseCommit.ID.String()
ctx.Data["BaseBranch"] = ci.BaseBranch
baseIsCommit = true
} else if ci.BaseBranch == git.EmptySHA {
if isSameRepo {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch))
} else {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadRepo.FullName()) + ":" + util.PathEscapeSegments(ci.HeadBranch))
}
return nil
} else {
ctx.NotFound("IsRefExist", nil)
return nil
@@ -338,8 +353,8 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
// check if they have a fork of the base repo and offer that as
// "OwnForkRepo"
var ownForkRepo *repo_model.Repository
if ctx.User != nil && baseRepo.OwnerID != ctx.User.ID {
repo := repo_model.GetForkedRepo(ctx.User.ID, baseRepo.ID)
if ctx.Doer != nil && baseRepo.OwnerID != ctx.Doer.ID {
repo := repo_model.GetForkedRepo(ctx.Doer.ID, baseRepo.ID)
if repo != nil {
ownForkRepo = repo
ctx.Data["OwnForkRepo"] = ownForkRepo
@@ -354,7 +369,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
has = true
}
// 4. If the ctx.User has their own fork of the baseRepo and the headUser is the ctx.User
// 4. If the ctx.Doer has their own fork of the baseRepo and the headUser is the ctx.Doer
// set the headRepo to the ownFork
if !has && ownForkRepo != nil && ownForkRepo.OwnerID == ci.HeadUser.ID {
ci.HeadRepo = ownForkRepo
@@ -383,7 +398,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
ci.HeadRepo = ctx.Repo.Repository
ci.HeadGitRepo = ctx.Repo.GitRepo
} else if has {
ci.HeadGitRepo, err = git.OpenRepositoryCtx(ctx, ci.HeadRepo.RepoPath())
ci.HeadGitRepo, err = git.OpenRepository(ctx, ci.HeadRepo.RepoPath())
if err != nil {
ctx.ServerError("OpenRepository", err)
return nil
@@ -392,11 +407,12 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
}
ctx.Data["HeadRepo"] = ci.HeadRepo
ctx.Data["BaseCompareRepo"] = ctx.Repo.Repository
// Now we need to assert that the ctx.User has permission to read
// Now we need to assert that the ctx.Doer has permission to read
// the baseRepo's code and pulls
// (NOT headRepo's)
permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User)
permBase, err := models.GetUserRepoPermission(ctx, baseRepo, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return nil
@@ -404,7 +420,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
if !permBase.CanRead(unit.TypeCode) {
if log.IsTrace() {
log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in baseRepo has Permissions: %-+v",
ctx.User,
ctx.Doer,
baseRepo,
permBase)
}
@@ -414,8 +430,8 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
// If we're not merging from the same repo:
if !isSameRepo {
// Assert ctx.User has permission to read headRepo's codes
permHead, err := models.GetUserRepoPermission(ci.HeadRepo, ctx.User)
// Assert ctx.Doer has permission to read headRepo's codes
permHead, err := models.GetUserRepoPermission(ctx, ci.HeadRepo, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return nil
@@ -423,13 +439,14 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
if !permHead.CanRead(unit.TypeCode) {
if log.IsTrace() {
log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v",
ctx.User,
ctx.Doer,
ci.HeadRepo,
permHead)
}
ctx.NotFound("ParseCompareInfo", nil)
return nil
}
ctx.Data["CanWriteToHeadRepo"] = permHead.CanWrite(unit.TypeCode)
}
// If we have a rootRepo and it's different from:
@@ -439,7 +456,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
if rootRepo != nil &&
rootRepo.ID != ci.HeadRepo.ID &&
rootRepo.ID != baseRepo.ID {
canRead := models.CheckRepoUnitUser(rootRepo, ctx.User, unit.TypeCode)
canRead := models.CheckRepoUnitUser(rootRepo, ctx.Doer, unit.TypeCode)
if canRead {
ctx.Data["RootRepo"] = rootRepo
if !fileOnly {
@@ -464,7 +481,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
ownForkRepo.ID != ci.HeadRepo.ID &&
ownForkRepo.ID != baseRepo.ID &&
(rootRepo == nil || ownForkRepo.ID != rootRepo.ID) {
canRead := models.CheckRepoUnitUser(ownForkRepo, ctx.User, unit.TypeCode)
canRead := models.CheckRepoUnitUser(ownForkRepo, ctx.Doer, unit.TypeCode)
if canRead {
ctx.Data["OwnForkRepo"] = ownForkRepo
if !fileOnly {
@@ -506,7 +523,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
if ctx.Data["PageIsComparePull"] == true && !permBase.CanReadIssuesOrPulls(true) {
if log.IsTrace() {
log.Trace("Permission Denied: User: %-v cannot create/read pull requests in Repo: %-v\nUser in baseRepo has Permissions: %-+v",
ctx.User,
ctx.Doer,
baseRepo,
permBase)
}
@@ -655,7 +672,7 @@ func PrepareCompareDiff(
}
func getBranchesAndTagsForRepo(ctx gocontext.Context, repo *repo_model.Repository) (branches, tags []string, err error) {
gitRepo, err := git.OpenRepositoryCtx(ctx, repo.RepoPath())
gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
if err != nil {
return nil, nil, err
}
@@ -789,7 +806,7 @@ func ExcerptBlob(ctx *context.Context) {
gitRepo := ctx.Repo.GitRepo
if ctx.FormBool("wiki") {
var err error
gitRepo, err = git.OpenRepositoryCtx(ctx, ctx.Repo.Repository.WikiPath())
gitRepo, err = git.OpenRepository(ctx, ctx.Repo.Repository.WikiPath())
if err != nil {
ctx.ServerError("OpenRepository", err)
return
@@ -857,7 +874,7 @@ func ExcerptBlob(ctx *context.Context) {
}
}
ctx.Data["section"] = section
ctx.Data["fileName"] = filePath
ctx.Data["FileNameHash"] = base.EncodeSha1(filePath)
ctx.Data["AfterCommitID"] = commitID
ctx.Data["Anchor"] = anchor
ctx.HTML(http.StatusOK, tplBlobExcerpt)
+54 -22
View File
@@ -6,7 +6,11 @@
package repo
import (
"path"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/httpcache"
@@ -18,8 +22,8 @@ import (
)
// ServeBlobOrLFS download a git.Blob redirecting to LFS if necessary
func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error {
if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`) {
func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified time.Time) error {
if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
return nil
}
@@ -45,7 +49,7 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error {
log.Error("ServeBlobOrLFS: Close: %v", err)
}
closed = true
return common.ServeBlob(ctx, blob)
return common.ServeBlob(ctx, blob, lastModified)
}
if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+pointer.Oid+`"`) {
return nil
@@ -76,37 +80,65 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error {
}
closed = true
return common.ServeBlob(ctx, blob)
return common.ServeBlob(ctx, blob, lastModified)
}
func getBlobForEntry(ctx *context.Context) (blob *git.Blob, lastModified time.Time) {
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath)
if err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound("GetTreeEntryByPath", err)
} else {
ctx.ServerError("GetTreeEntryByPath", err)
}
return
}
if entry.IsDir() || entry.IsSubModule() {
ctx.NotFound("getBlobForEntry", nil)
return
}
var c *git.LastCommitCache
if setting.CacheService.LastCommit.Enabled && ctx.Repo.CommitsCount >= setting.CacheService.LastCommit.CommitsCount {
c = git.NewLastCommitCache(ctx.Repo.Repository.FullName(), ctx.Repo.GitRepo, setting.LastCommitCacheTTLSeconds, cache.GetCache())
}
info, _, err := git.Entries([]*git.TreeEntry{entry}).GetCommitsInfo(ctx, ctx.Repo.Commit, path.Dir("/" + ctx.Repo.TreePath)[1:], c)
if err != nil {
ctx.ServerError("GetCommitsInfo", err)
return
}
if len(info) == 1 {
// Not Modified
lastModified = info[0].Commit.Committer.When
}
blob = entry.Blob()
return
}
// SingleDownload download a file by repos path
func SingleDownload(ctx *context.Context) {
blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath)
if err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound("GetBlobByPath", nil)
} else {
ctx.ServerError("GetBlobByPath", err)
}
blob, lastModified := getBlobForEntry(ctx)
if blob == nil {
return
}
if err = common.ServeBlob(ctx, blob); err != nil {
if err := common.ServeBlob(ctx, blob, lastModified); err != nil {
ctx.ServerError("ServeBlob", err)
}
}
// SingleDownloadOrLFS download a file by repos path redirecting to LFS if necessary
func SingleDownloadOrLFS(ctx *context.Context) {
blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath)
if err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound("GetBlobByPath", nil)
} else {
ctx.ServerError("GetBlobByPath", err)
}
blob, lastModified := getBlobForEntry(ctx)
if blob == nil {
return
}
if err = ServeBlobOrLFS(ctx, blob); err != nil {
if err := ServeBlobOrLFS(ctx, blob, lastModified); err != nil {
ctx.ServerError("ServeBlobOrLFS", err)
}
}
@@ -122,7 +154,7 @@ func DownloadByID(ctx *context.Context) {
}
return
}
if err = common.ServeBlob(ctx, blob); err != nil {
if err = common.ServeBlob(ctx, blob, time.Time{}); err != nil {
ctx.ServerError("ServeBlob", err)
}
}
@@ -138,7 +170,7 @@ func DownloadByIDOrLFS(ctx *context.Context) {
}
return
}
if err = ServeBlobOrLFS(ctx, blob); err != nil {
if err = ServeBlobOrLFS(ctx, blob, time.Time{}); err != nil {
ctx.ServerError("ServeBlob", err)
}
}
+7 -9
View File
@@ -40,7 +40,7 @@ const (
)
func renderCommitRights(ctx *context.Context) bool {
canCommitToBranch, err := ctx.Repo.CanCommitToBranch(ctx, ctx.User)
canCommitToBranch, err := ctx.Repo.CanCommitToBranch(ctx, ctx.Doer)
if err != nil {
log.Error("CanCommitToBranch: %v", err)
}
@@ -67,7 +67,6 @@ func getParentTreeFields(treePath string) (treeNames, treePaths []string) {
func editFile(ctx *context.Context, isNewFile bool) {
ctx.Data["PageIsEdit"] = true
ctx.Data["IsNewFile"] = isNewFile
ctx.Data["RequireHighlightJS"] = true
canCommit := renderCommitRights(ctx)
treePath := cleanUploadFileName(ctx.Repo.TreePath)
@@ -197,7 +196,6 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
ctx.Data["PageIsEdit"] = true
ctx.Data["PageHasPosted"] = true
ctx.Data["IsNewFile"] = isNewFile
ctx.Data["RequireHighlightJS"] = true
ctx.Data["TreePath"] = form.TreePath
ctx.Data["TreeNames"] = treeNames
ctx.Data["TreePaths"] = treePaths
@@ -241,7 +239,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
message += "\n\n" + form.CommitMessage
}
if _, err := files_service.CreateOrUpdateRepoFile(ctx, ctx.Repo.Repository, ctx.User, &files_service.UpdateRepoFileOptions{
if _, err := files_service.CreateOrUpdateRepoFile(ctx, ctx.Repo.Repository, ctx.Doer, &files_service.UpdateRepoFileOptions{
LastCommitID: form.LastCommit,
OldBranch: ctx.Repo.BranchName,
NewBranch: branchName,
@@ -447,7 +445,7 @@ func DeleteFilePost(ctx *context.Context) {
message += "\n\n" + form.CommitMessage
}
if _, err := files_service.DeleteRepoFile(ctx, ctx.Repo.Repository, ctx.User, &files_service.DeleteRepoFileOptions{
if _, err := files_service.DeleteRepoFile(ctx, ctx.Repo.Repository, ctx.Doer, &files_service.DeleteRepoFileOptions{
LastCommitID: form.LastCommit,
OldBranch: ctx.Repo.BranchName,
NewBranch: branchName,
@@ -653,7 +651,7 @@ func UploadFilePost(ctx *context.Context) {
message += "\n\n" + form.CommitMessage
}
if err := files_service.UploadRepoFiles(ctx, ctx.Repo.Repository, ctx.User, &files_service.UploadRepoFileOptions{
if err := files_service.UploadRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, &files_service.UploadRepoFileOptions{
LastCommitID: ctx.Repo.CommitID,
OldBranch: oldBranchName,
NewBranch: branchName,
@@ -780,7 +778,7 @@ func UploadFileToServer(ctx *context.Context) {
func RemoveUploadFileFromServer(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.RemoveUploadFileForm)
if len(form.File) == 0 {
ctx.Status(204)
ctx.Status(http.StatusNoContent)
return
}
@@ -790,7 +788,7 @@ func RemoveUploadFileFromServer(ctx *context.Context) {
}
log.Trace("Upload file removed: %s", form.File)
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}
// GetUniquePatchBranchName Gets a unique branch name for a new patch branch
@@ -798,7 +796,7 @@ func RemoveUploadFileFromServer(ctx *context.Context) {
// that doesn't already exist. If we exceed 1000 tries or an error is thrown, we just return "" so the user has to
// type in the branch name themselves (will be an empty field)
func GetUniquePatchBranchName(ctx *context.Context) string {
prefix := ctx.User.LowerName + "-patch-"
prefix := ctx.Doer.LowerName + "-patch-"
for i := 1; i <= 1000; i++ {
branchName := fmt.Sprintf("%s%d", prefix, i)
if _, err := ctx.Repo.GitRepo.GetBranch(branchName); err != nil {
+1 -1
View File
@@ -67,7 +67,7 @@ func TestGetClosestParentWithFiles(t *testing.T) {
repo := ctx.Repo.Repository
branch := repo.DefaultBranch
gitRepo, _ := git.OpenRepository(repo.RepoPath())
gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath())
defer gitRepo.Close()
commit, _ := gitRepo.GetBranchCommit(branch)
expectedTreePath := ""
+27 -42
View File
@@ -21,14 +21,13 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
"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"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
@@ -111,19 +110,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
@@ -159,7 +146,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
// don't allow anonymous pulls if organization is not public
if isPublicPull {
if err := repo.GetOwner(db.DefaultContext); err != nil {
if err := repo.GetOwner(ctx); err != nil {
ctx.ServerError("GetOwner", err)
return
}
@@ -178,7 +165,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
}
if ctx.IsBasicAuth && ctx.Data["IsApiToken"] != true {
_, err = auth.GetTwoFactorByUID(ctx.User.ID)
_, err = auth.GetTwoFactorByUID(ctx.Doer.ID)
if err == nil {
// TODO: This response should be changed to "invalid credentials" for security reasons once the expectation behind it (creating an app token to authenticate) is properly documented
ctx.PlainText(http.StatusUnauthorized, "Users with two-factor authentication enabled cannot perform HTTP/HTTPS operations via plain username and password. Please create and use a personal access token on the user settings page")
@@ -189,13 +176,13 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
}
}
if !ctx.User.IsActive || ctx.User.ProhibitLogin {
if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin {
ctx.PlainText(http.StatusForbidden, "Your account is disabled.")
return
}
if repoExist {
p, err := models.GetUserRepoPermission(repo, ctx.User)
p, err := models.GetUserRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return
@@ -218,22 +205,21 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
}
environ = []string{
models.EnvRepoUsername + "=" + username,
models.EnvRepoName + "=" + reponame,
models.EnvPusherName + "=" + ctx.User.Name,
models.EnvPusherID + fmt.Sprintf("=%d", ctx.User.ID),
models.EnvIsDeployKey + "=false",
models.EnvAppURL + "=" + setting.AppURL,
repo_module.EnvRepoUsername + "=" + username,
repo_module.EnvRepoName + "=" + reponame,
repo_module.EnvPusherName + "=" + ctx.Doer.Name,
repo_module.EnvPusherID + fmt.Sprintf("=%d", ctx.Doer.ID),
repo_module.EnvAppURL + "=" + setting.AppURL,
}
if !ctx.User.KeepEmailPrivate {
environ = append(environ, models.EnvPusherEmail+"="+ctx.User.Email)
if !ctx.Doer.KeepEmailPrivate {
environ = append(environ, repo_module.EnvPusherEmail+"="+ctx.Doer.Email)
}
if isWiki {
environ = append(environ, models.EnvRepoIsWiki+"=true")
environ = append(environ, repo_module.EnvRepoIsWiki+"=true")
} else {
environ = append(environ, models.EnvRepoIsWiki+"=false")
environ = append(environ, repo_module.EnvRepoIsWiki+"=false")
}
}
@@ -263,7 +249,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
return
}
repo, err = repo_service.PushCreateRepo(ctx.User, owner, reponame)
repo, err = repo_service.PushCreateRepo(ctx.Doer, owner, reponame)
if err != nil {
log.Error("pushCreateRepo: %v", err)
ctx.Status(http.StatusNotFound)
@@ -284,7 +270,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
}
}
environ = append(environ, models.EnvRepoID+fmt.Sprintf("=%d", repo.ID))
environ = append(environ, repo_module.EnvRepoID+fmt.Sprintf("=%d", repo.ID))
w := ctx.Resp
r := ctx.Req
@@ -328,7 +314,7 @@ func dummyInfoRefs(ctx *context.Context) {
return
}
refs, err := git.NewCommand(ctx, "receive-pack", "--stateless-rpc", "--advertise-refs", ".").RunInDirBytes(tmpDir)
refs, _, err := git.NewCommand(ctx, "receive-pack", "--stateless-rpc", "--advertise-refs", ".").RunStdBytes(&git.RunOpts{Dir: tmpDir})
if err != nil {
log.Error(fmt.Sprintf("%v - %s", err, string(refs)))
}
@@ -412,7 +398,7 @@ func (h *serviceHandler) sendFile(contentType, file string) {
var safeGitProtocolHeader = regexp.MustCompile(`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$`)
func getGitConfig(ctx gocontext.Context, option, dir string) string {
out, err := git.NewCommand(ctx, "config", option).RunInDir(dir)
out, _, err := git.NewCommand(ctx, "config", option).RunStdString(&git.RunOpts{Dir: dir})
if err != nil {
log.Error("%v - %s", err, out)
}
@@ -487,13 +473,12 @@ func serviceRPC(ctx gocontext.Context, h serviceHandler, service string) {
var stderr bytes.Buffer
cmd := git.NewCommand(h.r.Context(), service, "--stateless-rpc", h.dir)
cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.dir))
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: h.dir,
Env: append(os.Environ(), h.environ...),
Stdout: h.w,
Stdin: reqBody,
Stderr: &stderr,
if err := cmd.Run(&git.RunOpts{
Dir: h.dir,
Env: append(os.Environ(), h.environ...),
Stdout: h.w,
Stdin: reqBody,
Stderr: &stderr,
}); err != nil {
if err.Error() != "signal: killed" {
log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String())
@@ -527,7 +512,7 @@ func getServiceType(r *http.Request) string {
}
func updateServerInfo(ctx gocontext.Context, dir string) []byte {
out, err := git.NewCommand(ctx, "update-server-info").RunInDirBytes(dir)
out, _, err := git.NewCommand(ctx, "update-server-info").RunStdBytes(&git.RunOpts{Dir: dir})
if err != nil {
log.Error(fmt.Sprintf("%v - %s", err, string(out)))
}
@@ -557,7 +542,7 @@ func GetInfoRefs(ctx *context.Context) {
}
h.environ = append(os.Environ(), h.environ...)
refs, err := git.NewCommand(ctx, service, "--stateless-rpc", "--advertise-refs", ".").RunInDirTimeoutEnv(h.environ, -1, h.dir)
refs, _, err := git.NewCommand(ctx, service, "--stateless-rpc", "--advertise-refs", ".").RunStdBytes(&git.RunOpts{Env: h.environ, Dir: h.dir})
if err != nil {
log.Error(fmt.Sprintf("%v - %s", err, string(refs)))
}
+579 -158
View File
File diff suppressed because it is too large Load Diff
+8 -9
View File
@@ -12,16 +12,15 @@ import (
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
issuesModel "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/translation/i18n"
"github.com/sergi/go-diff/diffmatchpatch"
"github.com/unknwon/i18n"
)
// GetContentHistoryOverview get overview
@@ -32,7 +31,7 @@ func GetContentHistoryOverview(ctx *context.Context) {
}
lang := ctx.Locale.Language()
editedHistoryCountMap, _ := issuesModel.QueryIssueContentHistoryEditedCountMap(db.DefaultContext, issue.ID)
editedHistoryCountMap, _ := issuesModel.QueryIssueContentHistoryEditedCountMap(ctx, issue.ID)
ctx.JSON(http.StatusOK, map[string]interface{}{
"i18n": map[string]interface{}{
"textEdited": i18n.Tr(lang, "repo.issues.content_history.edited"),
@@ -52,7 +51,7 @@ func GetContentHistoryList(ctx *context.Context) {
return
}
items, _ := issuesModel.FetchIssueContentHistoryList(db.DefaultContext, issue.ID, commentID)
items, _ := issuesModel.FetchIssueContentHistoryList(ctx, issue.ID, commentID)
// render history list to HTML for frontend dropdown items: (name, value)
// name is HTML of "avatar + userName + userAction + timeSince"
@@ -99,11 +98,11 @@ func canSoftDeleteContentHistory(ctx *context.Context, issue *models.Issue, comm
} else if ctx.Repo.CanWrite(unit.TypeIssues) {
if comment == nil {
// the issue poster or the history poster can soft-delete
canSoftDelete = ctx.User.ID == issue.PosterID || ctx.User.ID == history.PosterID
canSoftDelete = ctx.Doer.ID == issue.PosterID || ctx.Doer.ID == history.PosterID
canSoftDelete = canSoftDelete && (history.IssueID == issue.ID)
} else {
// the comment poster or the history poster can soft-delete
canSoftDelete = ctx.User.ID == comment.PosterID || ctx.User.ID == history.PosterID
canSoftDelete = ctx.Doer.ID == comment.PosterID || ctx.Doer.ID == history.PosterID
canSoftDelete = canSoftDelete && (history.IssueID == issue.ID)
canSoftDelete = canSoftDelete && (history.CommentID == comment.ID)
}
@@ -119,7 +118,7 @@ func GetContentHistoryDetail(ctx *context.Context) {
}
historyID := ctx.FormInt64("history_id")
history, prevHistory, err := issuesModel.GetIssueContentHistoryAndPrev(db.DefaultContext, historyID)
history, prevHistory, err := issuesModel.GetIssueContentHistoryAndPrev(ctx, historyID)
if err != nil {
ctx.JSON(http.StatusNotFound, map[string]interface{}{
"message": "Can not find the content history",
@@ -196,7 +195,7 @@ func SoftDeleteContentHistory(ctx *context.Context) {
return
}
}
if history, err = issuesModel.GetIssueContentHistoryByID(db.DefaultContext, historyID); err != nil {
if history, err = issuesModel.GetIssueContentHistoryByID(ctx, historyID); err != nil {
log.Error("can not get issue content history %v. err=%v", historyID, err)
return
}
@@ -209,7 +208,7 @@ func SoftDeleteContentHistory(ctx *context.Context) {
return
}
err = issuesModel.SoftDeleteIssueContentHistory(db.DefaultContext, historyID)
err = issuesModel.SoftDeleteIssueContentHistory(ctx, historyID)
log.Debug("soft delete issue content history. issue=%d, comment=%d, history=%d", issue.ID, commentID, historyID)
ctx.JSON(http.StatusOK, map[string]interface{}{
"ok": err == nil,
+8 -8
View File
@@ -22,20 +22,20 @@ func AddDependency(ctx *context.Context) {
}
// Check if the Repo is allowed to have dependencies
if !ctx.Repo.CanCreateIssueDependencies(ctx.User, issue.IsPull) {
if !ctx.Repo.CanCreateIssueDependencies(ctx.Doer, issue.IsPull) {
ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
return
}
depID := ctx.FormInt64("newDependency")
if err = issue.LoadRepo(); err != nil {
if err = issue.LoadRepo(ctx); err != nil {
ctx.ServerError("LoadRepo", err)
return
}
// Redirect
defer ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
defer ctx.Redirect(issue.HTMLURL())
// Dependency
dep, err := models.GetIssueByID(depID)
@@ -56,7 +56,7 @@ func AddDependency(ctx *context.Context) {
return
}
err = models.CreateIssueDependency(ctx.User, issue, dep)
err = models.CreateIssueDependency(ctx.Doer, issue, dep)
if err != nil {
if models.IsErrDependencyExists(err) {
ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_dep_exists"))
@@ -81,14 +81,14 @@ func RemoveDependency(ctx *context.Context) {
}
// Check if the Repo is allowed to have dependencies
if !ctx.Repo.CanCreateIssueDependencies(ctx.User, issue.IsPull) {
if !ctx.Repo.CanCreateIssueDependencies(ctx.Doer, issue.IsPull) {
ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
return
}
depID := ctx.FormInt64("removeDependencyID")
if err = issue.LoadRepo(); err != nil {
if err = issue.LoadRepo(ctx); err != nil {
ctx.ServerError("LoadRepo", err)
return
}
@@ -115,7 +115,7 @@ func RemoveDependency(ctx *context.Context) {
return
}
if err = models.RemoveIssueDependency(ctx.User, issue, dep, depType); err != nil {
if err = models.RemoveIssueDependency(ctx.Doer, issue, dep, depType); err != nil {
if models.IsErrDependencyNotExists(err) {
ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_dep_not_exist"))
return
@@ -125,5 +125,5 @@ func RemoveDependency(ctx *context.Context) {
}
// Redirect
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
ctx.Redirect(issue.HTMLURL())
}
+14 -12
View File
@@ -9,9 +9,11 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/forms"
issue_service "code.gitea.io/gitea/services/issue"
@@ -27,7 +29,7 @@ func Labels(ctx *context.Context) {
ctx.Data["PageIsIssueList"] = true
ctx.Data["PageIsLabels"] = true
ctx.Data["RequireTribute"] = true
ctx.Data["LabelTemplates"] = models.LabelTemplates
ctx.Data["LabelTemplates"] = repo_module.LabelTemplates
ctx.HTML(http.StatusOK, tplLabels)
}
@@ -39,9 +41,9 @@ func InitializeLabels(ctx *context.Context) {
return
}
if err := models.InitializeLabels(db.DefaultContext, ctx.Repo.Repository.ID, form.TemplateName, false); err != nil {
if models.IsErrIssueLabelTemplateLoad(err) {
originalErr := err.(models.ErrIssueLabelTemplateLoad).OriginalError
if err := repo_module.InitializeLabels(ctx, ctx.Repo.Repository.ID, form.TemplateName, false); err != nil {
if repo_module.IsErrIssueLabelTemplateLoad(err) {
originalErr := err.(repo_module.ErrIssueLabelTemplateLoad).OriginalError
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, originalErr))
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
return
@@ -77,13 +79,13 @@ func RetrieveLabels(ctx *context.Context) {
}
ctx.Data["OrgLabels"] = orgLabels
org, err := models.GetOrgByName(ctx.Repo.Owner.LowerName)
org, err := organization.GetOrgByName(ctx.Repo.Owner.LowerName)
if err != nil {
ctx.ServerError("GetOrgByName", err)
return
}
if ctx.User != nil {
ctx.Org.IsOwner, err = org.IsOwnedBy(ctx.User.ID)
if ctx.Doer != nil {
ctx.Org.IsOwner, err = org.IsOwnedBy(ctx.Doer.ID)
if err != nil {
ctx.ServerError("org.IsOwnedBy", err)
return
@@ -115,7 +117,7 @@ func NewLabel(ctx *context.Context) {
Description: form.Description,
Color: form.Color,
}
if err := models.NewLabel(l); err != nil {
if err := models.NewLabel(ctx, l); err != nil {
ctx.ServerError("NewLabel", err)
return
}
@@ -169,7 +171,7 @@ func UpdateIssueLabel(ctx *context.Context) {
switch action := ctx.FormString("action"); action {
case "clear":
for _, issue := range issues {
if err := issue_service.ClearLabels(issue, ctx.User); err != nil {
if err := issue_service.ClearLabels(issue, ctx.Doer); err != nil {
ctx.ServerError("ClearLabels", err)
return
}
@@ -189,7 +191,7 @@ func UpdateIssueLabel(ctx *context.Context) {
// detach if any issues already have label, otherwise attach
action = "attach"
for _, issue := range issues {
if issue.HasLabel(label.ID) {
if models.HasIssueLabel(issue.ID, label.ID) {
action = "detach"
break
}
@@ -198,14 +200,14 @@ func UpdateIssueLabel(ctx *context.Context) {
if action == "attach" {
for _, issue := range issues {
if err = issue_service.AddLabel(issue, ctx.User, label); err != nil {
if err = issue_service.AddLabel(issue, ctx.Doer, label); err != nil {
ctx.ServerError("AddLabel", err)
return
}
}
} else {
for _, issue := range issues {
if err = issue_service.RemoveLabel(issue, ctx.User, label); err != nil {
if err = issue_service.RemoveLabel(issue, ctx.Doer, label); err != nil {
ctx.ServerError("RemoveLabel", err)
return
}
+3 -3
View File
@@ -36,7 +36,7 @@ func TestInitializeLabels(t *testing.T) {
test.LoadRepo(t, ctx, 2)
web.SetForm(ctx, &forms.InitializeLabelsForm{TemplateName: "Default"})
InitializeLabels(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
unittest.AssertExistsAndLoadBean(t, &models.Label{
RepoID: 2,
Name: "enhancement",
@@ -82,7 +82,7 @@ func TestNewLabel(t *testing.T) {
Color: "#abcdef",
})
NewLabel(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
unittest.AssertExistsAndLoadBean(t, &models.Label{
Name: "newlabel",
Color: "#abcdef",
@@ -101,7 +101,7 @@ func TestUpdateLabel(t *testing.T) {
Color: "#abcdef",
})
UpdateLabel(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
unittest.AssertExistsAndLoadBean(t, &models.Label{
ID: 2,
Name: "newnameforlabel",
+4 -6
View File
@@ -5,8 +5,6 @@
package repo
import (
"net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/web"
@@ -35,7 +33,7 @@ func LockIssue(ctx *context.Context) {
}
if err := models.LockIssue(&models.IssueLockOptions{
Doer: ctx.User,
Doer: ctx.Doer,
Issue: issue,
Reason: form.Reason,
}); err != nil {
@@ -43,7 +41,7 @@ func LockIssue(ctx *context.Context) {
return
}
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
ctx.Redirect(issue.HTMLURL())
}
// UnlockIssue unlocks a previously locked issue.
@@ -60,12 +58,12 @@ func UnlockIssue(ctx *context.Context) {
}
if err := models.UnlockIssue(&models.IssueLockOptions{
Doer: ctx.User,
Doer: ctx.Doer,
Issue: issue,
}); err != nil {
ctx.ServerError("UnlockIssue", err)
return
}
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
ctx.Redirect(issue.HTMLURL())
}
+28 -14
View File
@@ -9,7 +9,9 @@ import (
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/eventsource"
)
// IssueStopwatch creates or stops a stopwatch for the given issue.
@@ -21,16 +23,16 @@ func IssueStopwatch(c *context.Context) {
var showSuccessMessage bool
if !models.StopwatchExists(c.User.ID, issue.ID) {
if !models.StopwatchExists(c.Doer.ID, issue.ID) {
showSuccessMessage = true
}
if !c.Repo.CanUseTimetracker(issue, c.User) {
if !c.Repo.CanUseTimetracker(issue, c.Doer) {
c.NotFound("CanUseTimetracker", nil)
return
}
if err := models.CreateOrStopIssueStopwatch(c.User, issue); err != nil {
if err := models.CreateOrStopIssueStopwatch(c.Doer, issue); err != nil {
c.ServerError("CreateOrStopIssueStopwatch", err)
return
}
@@ -49,33 +51,45 @@ func CancelStopwatch(c *context.Context) {
if c.Written() {
return
}
if !c.Repo.CanUseTimetracker(issue, c.User) {
if !c.Repo.CanUseTimetracker(issue, c.Doer) {
c.NotFound("CanUseTimetracker", nil)
return
}
if err := models.CancelStopwatch(c.User, issue); err != nil {
if err := models.CancelStopwatch(c.Doer, issue); err != nil {
c.ServerError("CancelStopwatch", err)
return
}
stopwatches, err := models.GetUserStopwatches(c.Doer.ID, db.ListOptions{})
if err != nil {
c.ServerError("GetUserStopwatches", err)
return
}
if len(stopwatches) == 0 {
eventsource.GetManager().SendMessage(c.Doer.ID, &eventsource.Event{
Name: "stopwatches",
Data: "{}",
})
}
url := issue.HTMLURL()
c.Redirect(url, http.StatusSeeOther)
}
// GetActiveStopwatch is the middleware that sets .ActiveStopwatch on context
func GetActiveStopwatch(c *context.Context) {
if strings.HasPrefix(c.Req.URL.Path, "/api") {
func GetActiveStopwatch(ctx *context.Context) {
if strings.HasPrefix(ctx.Req.URL.Path, "/api") {
return
}
if !c.IsSigned {
if !ctx.IsSigned {
return
}
_, sw, err := models.HasUserStopwatch(c.User.ID)
_, sw, err := models.HasUserStopwatch(ctx.Doer.ID)
if err != nil {
c.ServerError("HasUserStopwatch", err)
ctx.ServerError("HasUserStopwatch", err)
return
}
@@ -85,15 +99,15 @@ func GetActiveStopwatch(c *context.Context) {
issue, err := models.GetIssueByID(sw.IssueID)
if err != nil || issue == nil {
c.ServerError("GetIssueByID", err)
ctx.ServerError("GetIssueByID", err)
return
}
if err = issue.LoadRepo(); err != nil {
c.ServerError("LoadRepo", err)
if err = issue.LoadRepo(ctx); err != nil {
ctx.ServerError("LoadRepo", err)
return
}
c.Data["ActiveStopwatch"] = StopwatchTmplInfo{
ctx.Data["ActiveStopwatch"] = StopwatchTmplInfo{
issue.Link(),
issue.Repo.FullName(),
issue.Index,
+6 -5
View File
@@ -9,6 +9,7 @@ import (
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
@@ -22,7 +23,7 @@ func AddTimeManually(c *context.Context) {
if c.Written() {
return
}
if !c.Repo.CanUseTimetracker(issue, c.User) {
if !c.Repo.CanUseTimetracker(issue, c.Doer) {
c.NotFound("CanUseTimetracker", nil)
return
}
@@ -42,7 +43,7 @@ func AddTimeManually(c *context.Context) {
return
}
if _, err := models.AddTime(c.User, issue, int64(total.Seconds()), time.Now()); err != nil {
if _, err := models.AddTime(c.Doer, issue, int64(total.Seconds()), time.Now()); err != nil {
c.ServerError("AddTime", err)
return
}
@@ -56,14 +57,14 @@ func DeleteTime(c *context.Context) {
if c.Written() {
return
}
if !c.Repo.CanUseTimetracker(issue, c.User) {
if !c.Repo.CanUseTimetracker(issue, c.Doer) {
c.NotFound("CanUseTimetracker", nil)
return
}
t, err := models.GetTrackedTimeByID(c.ParamsInt64(":timeid"))
if err != nil {
if models.IsErrNotExist(err) {
if db.IsErrNotExist(err) {
c.NotFound("time not found", err)
return
}
@@ -72,7 +73,7 @@ func DeleteTime(c *context.Context) {
}
// only OP or admin may delete
if !c.IsSigned || (!c.IsUserSiteAdmin() && c.User.ID != t.UserID) {
if !c.IsSigned || (!c.IsUserSiteAdmin() && c.Doer.ID != t.UserID) {
c.Error(http.StatusForbidden, "not allowed")
return
}
+4 -4
View File
@@ -20,7 +20,7 @@ func IssueWatch(ctx *context.Context) {
return
}
if !ctx.IsSigned || (ctx.User.ID != issue.PosterID && !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull)) {
if !ctx.IsSigned || (ctx.Doer.ID != issue.PosterID && !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull)) {
if log.IsTrace() {
if ctx.IsSigned {
issueType := "issues"
@@ -29,7 +29,7 @@ func IssueWatch(ctx *context.Context) {
}
log.Trace("Permission Denied: User %-v not the Poster (ID: %d) and cannot read %s in Repo %-v.\n"+
"User in Repo has Permissions: %-+v",
ctx.User,
ctx.Doer,
log.NewColoredIDValue(issue.PosterID),
issueType,
ctx.Repo.Repository,
@@ -48,10 +48,10 @@ func IssueWatch(ctx *context.Context) {
return
}
if err := models.CreateOrUpdateIssueWatch(ctx.User.ID, issue.ID, watch); err != nil {
if err := models.CreateOrUpdateIssueWatch(ctx.Doer.ID, issue.ID, watch); err != nil {
ctx.ServerError("CreateOrUpdateIssueWatch", err)
return
}
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
ctx.Redirect(issue.HTMLURL())
}
+21 -7
View File
@@ -23,6 +23,7 @@ import (
"code.gitea.io/gitea/modules/git/pipeline"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/typesniffer"
@@ -103,14 +104,14 @@ func LFSLocks(ctx *context.Context) {
}
// Clone base repo.
tmpBasePath, err := models.CreateTemporaryPath("locks")
tmpBasePath, err := repo_module.CreateTemporaryPath("locks")
if err != nil {
log.Error("Failed to create temporary path: %v", err)
ctx.ServerError("LFSLocks", err)
return
}
defer func() {
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
if err := repo_module.RemoveTemporaryPath(tmpBasePath); err != nil {
log.Error("LFSLocks: RemoveTemporaryPath: %v", err)
}
}()
@@ -124,7 +125,7 @@ func LFSLocks(ctx *context.Context) {
return
}
gitRepo, err := git.OpenRepositoryCtx(ctx, tmpBasePath)
gitRepo, err := git.OpenRepository(ctx, tmpBasePath)
if err != nil {
log.Error("Unable to open temporary repository: %s (%v)", tmpBasePath, err)
ctx.ServerError("LFSLocks", fmt.Errorf("failed to open new temporary repository in: %s %v", tmpBasePath, err))
@@ -217,7 +218,7 @@ func LFSLockFile(ctx *context.Context) {
_, err := models.CreateLFSLock(ctx.Repo.Repository, &models.LFSLock{
Path: lockPath,
OwnerID: ctx.User.ID,
OwnerID: ctx.Doer.ID,
})
if err != nil {
if models.IsErrLFSLockAlreadyExist(err) {
@@ -237,7 +238,7 @@ func LFSUnlock(ctx *context.Context) {
ctx.NotFound("LFSUnlock", nil)
return
}
_, err := models.DeleteLFSLockByID(ctx.ParamsInt64("lid"), ctx.Repo.Repository, ctx.User, true)
_, err := models.DeleteLFSLockByID(ctx.ParamsInt64("lid"), ctx.Repo.Repository, ctx.Doer, true)
if err != nil {
ctx.ServerError("LFSUnlock", err)
return
@@ -253,6 +254,13 @@ func LFSFileGet(ctx *context.Context) {
}
ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs"
oid := ctx.Params("oid")
p := lfs.Pointer{Oid: oid}
if !p.IsValid() {
ctx.NotFound("LFSFileGet", nil)
return
}
ctx.Data["Title"] = oid
ctx.Data["PageIsSettingsLFS"] = true
meta, err := models.GetLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid)
@@ -343,6 +351,12 @@ func LFSDelete(ctx *context.Context) {
return
}
oid := ctx.Params("oid")
p := lfs.Pointer{Oid: oid}
if !p.IsValid() {
ctx.NotFound("LFSDelete", nil)
return
}
count, err := models.RemoveLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid)
if err != nil {
ctx.ServerError("LFSDelete", err)
@@ -463,7 +477,7 @@ func LFSPointerFiles(ctx *context.Context) {
// Can we fix?
// OK well that's "simple"
// - we need to check whether current user has access to a repo that has access to the file
result.Associatable, err = models.LFSObjectAccessible(ctx.User, pointerBlob.Oid)
result.Associatable, err = models.LFSObjectAccessible(ctx.Doer, pointerBlob.Oid)
if err != nil {
return err
}
@@ -538,7 +552,7 @@ func LFSAutoAssociate(ctx *context.Context) {
metas[i].Oid = oid[:idx]
// metas[i].RepositoryID = ctx.Repo.Repository.ID
}
if err := models.LFSAutoAssociate(metas, ctx.User, ctx.Repo.Repository.ID); err != nil {
if err := models.LFSAutoAssociate(metas, ctx.Doer, ctx.Repo.Repository.ID); err != nil {
ctx.ServerError("LFSAutoAssociate", err)
return
}
+3 -1
View File
@@ -12,5 +12,7 @@ import (
)
func TestMain(m *testing.M) {
unittest.MainTest(m, filepath.Join("..", "..", ".."))
unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", "..", ".."),
})
}
+4 -4
View File
@@ -43,7 +43,7 @@ func SetDiffViewStyle(ctx *context.Context) {
}
var (
userStyle = ctx.User.DiffViewStyle
userStyle = ctx.Doer.DiffViewStyle
style string
)
@@ -56,7 +56,7 @@ func SetDiffViewStyle(ctx *context.Context) {
}
ctx.Data["IsSplitStyle"] = style == "split"
if err := user_model.UpdateUserDiffViewStyle(ctx.User, style); err != nil {
if err := user_model.UpdateUserDiffViewStyle(ctx.Doer, style); err != nil {
ctx.ServerError("ErrUpdateDiffViewStyle", err)
}
}
@@ -72,12 +72,12 @@ func SetWhitespaceBehavior(ctx *context.Context) {
whitespaceBehavior = defaultWhitespaceBehavior
}
if ctx.IsSigned {
userWhitespaceBehavior, err := user_model.GetUserSetting(ctx.User.ID, user_model.SettingsKeyDiffWhitespaceBehavior, defaultWhitespaceBehavior)
userWhitespaceBehavior, err := user_model.GetUserSetting(ctx.Doer.ID, user_model.SettingsKeyDiffWhitespaceBehavior, defaultWhitespaceBehavior)
if err == nil {
if whitespaceBehavior == "" {
whitespaceBehavior = userWhitespaceBehavior
} else if whitespaceBehavior != userWhitespaceBehavior {
_ = user_model.SetUserSetting(ctx.User.ID, user_model.SettingsKeyDiffWhitespaceBehavior, whitespaceBehavior)
_ = user_model.SetUserSetting(ctx.Doer.ID, user_model.SettingsKeyDiffWhitespaceBehavior, whitespaceBehavior)
}
} // else: we can ignore the error safely
}
+5 -6
View File
@@ -106,8 +106,7 @@ func handleMigrateError(ctx *context.Context, owner *user_model.User, err error,
ctx.Data["Err_RepoName"] = true
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tpl, form)
default:
remoteAddr, _ := forms.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
err = util.NewStringURLSanitizedError(err, remoteAddr, true)
err = util.SanitizeErrorCredentialURLs(err)
if strings.Contains(err.Error(), "Authentication failed") ||
strings.Contains(err.Error(), "Bad credentials") ||
strings.Contains(err.Error(), "could not read Username") {
@@ -178,7 +177,7 @@ func MigratePost(ctx *context.Context) {
remoteAddr, err := forms.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
if err == nil {
err = migrations.IsMigrateURLAllowed(remoteAddr, ctx.User)
err = migrations.IsMigrateURLAllowed(remoteAddr, ctx.Doer)
}
if err != nil {
ctx.Data["Err_CloneAddr"] = true
@@ -195,7 +194,7 @@ func MigratePost(ctx *context.Context) {
ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_lfs_endpoint"), tpl, &form)
return
}
err = migrations.IsMigrateURLAllowed(ep.String(), ctx.User)
err = migrations.IsMigrateURLAllowed(ep.String(), ctx.Doer)
if err != nil {
ctx.Data["Err_LFSEndpoint"] = true
handleMigrateRemoteAddrError(ctx, err, tpl, form)
@@ -233,13 +232,13 @@ func MigratePost(ctx *context.Context) {
opts.Releases = false
}
err = repo_model.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName, false)
err = repo_model.CheckCreateRepository(ctx.Doer, ctxUser, opts.RepoName, false)
if err != nil {
handleMigrateError(ctx, ctxUser, err, "MigratePost", tpl, form)
return
}
err = task.MigrateRepository(ctx.User, ctxUser, opts)
err = task.MigrateRepository(ctx.Doer, ctxUser, opts)
if err == nil {
ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(opts.RepoName))
return
+14 -14
View File
@@ -9,8 +9,8 @@ import (
"net/url"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/markup"
@@ -38,7 +38,7 @@ func Milestones(ctx *context.Context) {
ctx.Data["PageIsMilestones"] = true
isShowClosed := ctx.FormString("state") == "closed"
stats, err := models.GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"id": ctx.Repo.Repository.ID}))
stats, err := issues_model.GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"id": ctx.Repo.Repository.ID}))
if err != nil {
ctx.ServerError("MilestoneStats", err)
return
@@ -60,7 +60,7 @@ func Milestones(ctx *context.Context) {
state = structs.StateClosed
}
miles, total, err := models.GetMilestones(models.GetMilestonesOption{
miles, total, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{
ListOptions: db.ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
@@ -143,7 +143,7 @@ func NewMilestonePost(ctx *context.Context) {
}
deadline = time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 23, 59, 59, 0, deadline.Location())
if err = models.NewMilestone(&models.Milestone{
if err = issues_model.NewMilestone(&issues_model.Milestone{
RepoID: ctx.Repo.Repository.ID,
Name: form.Title,
Content: form.Content,
@@ -163,9 +163,9 @@ func EditMilestone(ctx *context.Context) {
ctx.Data["PageIsMilestones"] = true
ctx.Data["PageIsEditMilestone"] = true
m, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
m, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrMilestoneNotExist(err) {
if issues_model.IsErrMilestoneNotExist(err) {
ctx.NotFound("", nil)
} else {
ctx.ServerError("GetMilestoneByRepoID", err)
@@ -203,9 +203,9 @@ func EditMilestonePost(ctx *context.Context) {
}
deadline = time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 23, 59, 59, 0, deadline.Location())
m, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
m, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrMilestoneNotExist(err) {
if issues_model.IsErrMilestoneNotExist(err) {
ctx.NotFound("", nil)
} else {
ctx.ServerError("GetMilestoneByRepoID", err)
@@ -215,7 +215,7 @@ func EditMilestonePost(ctx *context.Context) {
m.Name = form.Title
m.Content = form.Content
m.DeadlineUnix = timeutil.TimeStamp(deadline.Unix())
if err = models.UpdateMilestone(m, m.IsClosed); err != nil {
if err = issues_model.UpdateMilestone(m, m.IsClosed); err != nil {
ctx.ServerError("UpdateMilestone", err)
return
}
@@ -237,8 +237,8 @@ func ChangeMilestoneStatus(ctx *context.Context) {
}
id := ctx.ParamsInt64(":id")
if err := models.ChangeMilestoneStatusByRepoIDAndID(ctx.Repo.Repository.ID, id, toClose); err != nil {
if models.IsErrMilestoneNotExist(err) {
if err := issues_model.ChangeMilestoneStatusByRepoIDAndID(ctx.Repo.Repository.ID, id, toClose); err != nil {
if issues_model.IsErrMilestoneNotExist(err) {
ctx.NotFound("", err)
} else {
ctx.ServerError("ChangeMilestoneStatusByIDAndRepoID", err)
@@ -250,7 +250,7 @@ func ChangeMilestoneStatus(ctx *context.Context) {
// DeleteMilestone delete a milestone
func DeleteMilestone(ctx *context.Context) {
if err := models.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil {
if err := issues_model.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil {
ctx.Flash.Error("DeleteMilestoneByRepoID: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("repo.milestones.deletion_success"))
@@ -264,9 +264,9 @@ func DeleteMilestone(ctx *context.Context) {
// MilestoneIssuesAndPulls lists all the issues and pull requests of the milestone
func MilestoneIssuesAndPulls(ctx *context.Context) {
milestoneID := ctx.ParamsInt64(":id")
milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, milestoneID)
milestone, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, milestoneID)
if err != nil {
if models.IsErrMilestoneNotExist(err) {
if issues_model.IsErrMilestoneNotExist(err) {
ctx.NotFound("GetMilestoneByID", err)
return
}
+73
View File
@@ -0,0 +1,73 @@
// Copyright 2021 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 repo
import (
"net/http"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
)
const (
tplPackagesList base.TplName = "repo/packages"
)
// Packages displays a list of all packages in the repository
func Packages(ctx *context.Context) {
page := ctx.FormInt("page")
if page <= 1 {
page = 1
}
query := ctx.FormTrim("q")
packageType := ctx.FormTrim("type")
pvs, total, err := packages.SearchLatestVersions(ctx, &packages.PackageSearchOptions{
Paginator: &db.ListOptions{
PageSize: setting.UI.PackagesPagingNum,
Page: page,
},
OwnerID: ctx.ContextUser.ID,
RepoID: ctx.Repo.Repository.ID,
Type: packages.Type(packageType),
Name: packages.SearchValue{Value: query},
})
if err != nil {
ctx.ServerError("SearchLatestVersions", err)
return
}
pds, err := packages.GetPackageDescriptors(ctx, pvs)
if err != nil {
ctx.ServerError("GetPackageDescriptors", err)
return
}
hasPackages, err := packages.HasRepositoryPackages(ctx, ctx.Repo.Repository.ID)
if err != nil {
ctx.ServerError("HasRepositoryPackages", err)
return
}
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["IsPackagesPage"] = true
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["Query"] = query
ctx.Data["PackageType"] = packageType
ctx.Data["HasPackages"] = hasPackages
ctx.Data["PackageDescriptors"] = pds
ctx.Data["Total"] = total
ctx.Data["RepositoryAccessMap"] = map[int64]bool{ctx.Repo.Repository.ID: true} // There is only the current repository
pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5)
pager.AddParam(ctx, "q", "Query")
pager.AddParam(ctx, "type", "PackageType")
ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, tplPackagesList)
}
+1 -4
View File
@@ -24,8 +24,6 @@ const (
// NewDiffPatch render create patch page
func NewDiffPatch(ctx *context.Context) {
ctx.Data["RequireHighlightJS"] = true
canCommit := renderCommitRights(ctx)
ctx.Data["TreePath"] = ""
@@ -54,7 +52,6 @@ func NewDiffPatchPost(ctx *context.Context) {
if form.CommitChoice == frmCommitChoiceNewBranch {
branchName = form.NewBranchName
}
ctx.Data["RequireHighlightJS"] = true
ctx.Data["TreePath"] = ""
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
ctx.Data["FileContent"] = form.Content
@@ -90,7 +87,7 @@ func NewDiffPatchPost(ctx *context.Context) {
message += "\n\n" + form.CommitMessage
}
if _, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.User, &files.ApplyDiffPatchOptions{
if _, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Doer, &files.ApplyDiffPatchOptions{
LastCommitID: form.LastCommit,
OldBranch: ctx.Repo.BranchName,
NewBranch: branchName,
+98 -60
View File
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/perm"
project_model "code.gitea.io/gitea/models/project"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
@@ -69,12 +70,12 @@ func Projects(ctx *context.Context) {
total = repo.NumClosedProjects
}
projects, count, err := models.GetProjects(models.ProjectSearchOptions{
projects, count, err := project_model.GetProjects(project_model.SearchOptions{
RepoID: repo.ID,
Page: page,
IsClosed: util.OptionalBoolOf(isShowClosed),
SortType: sortType,
Type: models.ProjectTypeRepository,
Type: project_model.TypeRepository,
})
if err != nil {
ctx.ServerError("GetProjects", err)
@@ -122,7 +123,7 @@ func Projects(ctx *context.Context) {
// NewProject render creating a project page
func NewProject(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.projects.new")
ctx.Data["ProjectTypes"] = models.GetProjectsConfig()
ctx.Data["ProjectTypes"] = project_model.GetProjectsConfig()
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
ctx.HTML(http.StatusOK, tplProjectsNew)
}
@@ -134,18 +135,18 @@ func NewProjectPost(ctx *context.Context) {
if ctx.HasError() {
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
ctx.Data["ProjectTypes"] = models.GetProjectsConfig()
ctx.Data["ProjectTypes"] = project_model.GetProjectsConfig()
ctx.HTML(http.StatusOK, tplProjectsNew)
return
}
if err := models.NewProject(&models.Project{
if err := project_model.NewProject(&project_model.Project{
RepoID: ctx.Repo.Repository.ID,
Title: form.Title,
Description: form.Content,
CreatorID: ctx.User.ID,
CreatorID: ctx.Doer.ID,
BoardType: form.BoardType,
Type: models.ProjectTypeRepository,
Type: project_model.TypeRepository,
}); err != nil {
ctx.ServerError("NewProject", err)
return
@@ -168,8 +169,8 @@ func ChangeProjectStatus(ctx *context.Context) {
}
id := ctx.ParamsInt64(":id")
if err := models.ChangeProjectStatusByRepoIDAndID(ctx.Repo.Repository.ID, id, toClose); err != nil {
if models.IsErrProjectNotExist(err) {
if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx.Repo.Repository.ID, id, toClose); err != nil {
if project_model.IsErrProjectNotExist(err) {
ctx.NotFound("", err)
} else {
ctx.ServerError("ChangeProjectStatusByIDAndRepoID", err)
@@ -181,9 +182,9 @@ func ChangeProjectStatus(ctx *context.Context) {
// DeleteProject delete a project
func DeleteProject(ctx *context.Context) {
p, err := models.GetProjectByID(ctx.ParamsInt64(":id"))
p, err := project_model.GetProjectByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrProjectNotExist(err) {
if project_model.IsErrProjectNotExist(err) {
ctx.NotFound("", nil)
} else {
ctx.ServerError("GetProjectByID", err)
@@ -195,7 +196,7 @@ func DeleteProject(ctx *context.Context) {
return
}
if err := models.DeleteProjectByID(p.ID); err != nil {
if err := project_model.DeleteProjectByID(p.ID); err != nil {
ctx.Flash.Error("DeleteProjectByID: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("repo.projects.deletion_success"))
@@ -212,9 +213,9 @@ func EditProject(ctx *context.Context) {
ctx.Data["PageIsEditProjects"] = true
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
p, err := models.GetProjectByID(ctx.ParamsInt64(":id"))
p, err := project_model.GetProjectByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrProjectNotExist(err) {
if project_model.IsErrProjectNotExist(err) {
ctx.NotFound("", nil)
} else {
ctx.ServerError("GetProjectByID", err)
@@ -244,9 +245,9 @@ func EditProjectPost(ctx *context.Context) {
return
}
p, err := models.GetProjectByID(ctx.ParamsInt64(":id"))
p, err := project_model.GetProjectByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrProjectNotExist(err) {
if project_model.IsErrProjectNotExist(err) {
ctx.NotFound("", nil)
} else {
ctx.ServerError("GetProjectByID", err)
@@ -260,7 +261,7 @@ func EditProjectPost(ctx *context.Context) {
p.Title = form.Title
p.Description = form.Content
if err = models.UpdateProject(p); err != nil {
if err = project_model.UpdateProject(p); err != nil {
ctx.ServerError("UpdateProjects", err)
return
}
@@ -271,9 +272,9 @@ func EditProjectPost(ctx *context.Context) {
// ViewProject renders the project board for a project
func ViewProject(ctx *context.Context) {
project, err := models.GetProjectByID(ctx.ParamsInt64(":id"))
project, err := project_model.GetProjectByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrProjectNotExist(err) {
if project_model.IsErrProjectNotExist(err) {
ctx.NotFound("", nil)
} else {
ctx.ServerError("GetProjectByID", err)
@@ -285,7 +286,7 @@ func ViewProject(ctx *context.Context) {
return
}
boards, err := models.GetProjectBoards(project.ID)
boards, err := project_model.GetBoards(project.ID)
if err != nil {
ctx.ServerError("GetProjectBoards", err)
return
@@ -295,27 +296,29 @@ func ViewProject(ctx *context.Context) {
boards[0].Title = ctx.Tr("repo.projects.type.uncategorized")
}
issueList, err := boards.LoadIssues()
issuesMap, err := models.LoadIssuesFromBoardList(boards)
if err != nil {
ctx.ServerError("LoadIssuesOfBoards", err)
return
}
linkedPrsMap := make(map[int64][]*models.Issue)
for _, issue := range issueList {
var referencedIds []int64
for _, comment := range issue.Comments {
if comment.RefIssueID != 0 && comment.RefIsPull {
referencedIds = append(referencedIds, comment.RefIssueID)
for _, issuesList := range issuesMap {
for _, issue := range issuesList {
var referencedIds []int64
for _, comment := range issue.Comments {
if comment.RefIssueID != 0 && comment.RefIsPull {
referencedIds = append(referencedIds, comment.RefIssueID)
}
}
}
if len(referencedIds) > 0 {
if linkedPrs, err := models.Issues(&models.IssuesOptions{
IssueIDs: referencedIds,
IsPull: util.OptionalBoolTrue,
}); err == nil {
linkedPrsMap[issue.ID] = linkedPrs
if len(referencedIds) > 0 {
if linkedPrs, err := models.Issues(&models.IssuesOptions{
IssueIDs: referencedIds,
IsPull: util.OptionalBoolTrue,
}); err == nil {
linkedPrsMap[issue.ID] = linkedPrs
}
}
}
}
@@ -335,6 +338,7 @@ func ViewProject(ctx *context.Context) {
ctx.Data["IsProjectsPage"] = true
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
ctx.Data["Project"] = project
ctx.Data["IssuesMap"] = issuesMap
ctx.Data["Boards"] = boards
ctx.HTML(http.StatusOK, tplProjectsView)
@@ -354,7 +358,7 @@ func UpdateIssueProject(ctx *context.Context) {
continue
}
if err := models.ChangeProjectAssign(issue, ctx.User, projectID); err != nil {
if err := models.ChangeProjectAssign(issue, ctx.Doer, projectID); err != nil {
ctx.ServerError("ChangeProjectAssign", err)
return
}
@@ -367,7 +371,7 @@ func UpdateIssueProject(ctx *context.Context) {
// DeleteProjectBoard allows for the deletion of a project board
func DeleteProjectBoard(ctx *context.Context) {
if ctx.User == nil {
if ctx.Doer == nil {
ctx.JSON(http.StatusForbidden, map[string]string{
"message": "Only signed in users are allowed to perform this action.",
})
@@ -381,9 +385,9 @@ func DeleteProjectBoard(ctx *context.Context) {
return
}
project, err := models.GetProjectByID(ctx.ParamsInt64(":id"))
project, err := project_model.GetProjectByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrProjectNotExist(err) {
if project_model.IsErrProjectNotExist(err) {
ctx.NotFound("", nil)
} else {
ctx.ServerError("GetProjectByID", err)
@@ -391,7 +395,7 @@ func DeleteProjectBoard(ctx *context.Context) {
return
}
pb, err := models.GetProjectBoard(ctx.ParamsInt64(":boardID"))
pb, err := project_model.GetBoard(ctx.ParamsInt64(":boardID"))
if err != nil {
ctx.ServerError("GetProjectBoard", err)
return
@@ -410,7 +414,7 @@ func DeleteProjectBoard(ctx *context.Context) {
return
}
if err := models.DeleteProjectBoardByID(ctx.ParamsInt64(":boardID")); err != nil {
if err := project_model.DeleteBoardByID(ctx.ParamsInt64(":boardID")); err != nil {
ctx.ServerError("DeleteProjectBoardByID", err)
return
}
@@ -430,9 +434,9 @@ func AddBoardToProjectPost(ctx *context.Context) {
return
}
project, err := models.GetProjectByID(ctx.ParamsInt64(":id"))
project, err := project_model.GetProjectByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrProjectNotExist(err) {
if project_model.IsErrProjectNotExist(err) {
ctx.NotFound("", nil)
} else {
ctx.ServerError("GetProjectByID", err)
@@ -440,11 +444,11 @@ func AddBoardToProjectPost(ctx *context.Context) {
return
}
if err := models.NewProjectBoard(&models.ProjectBoard{
if err := project_model.NewBoard(&project_model.Board{
ProjectID: project.ID,
Title: form.Title,
Color: form.Color,
CreatorID: ctx.User.ID,
CreatorID: ctx.Doer.ID,
}); err != nil {
ctx.ServerError("NewProjectBoard", err)
return
@@ -455,8 +459,8 @@ func AddBoardToProjectPost(ctx *context.Context) {
})
}
func checkProjectBoardChangePermissions(ctx *context.Context) (*models.Project, *models.ProjectBoard) {
if ctx.User == nil {
func checkProjectBoardChangePermissions(ctx *context.Context) (*project_model.Project, *project_model.Board) {
if ctx.Doer == nil {
ctx.JSON(http.StatusForbidden, map[string]string{
"message": "Only signed in users are allowed to perform this action.",
})
@@ -470,9 +474,9 @@ func checkProjectBoardChangePermissions(ctx *context.Context) (*models.Project,
return nil, nil
}
project, err := models.GetProjectByID(ctx.ParamsInt64(":id"))
project, err := project_model.GetProjectByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrProjectNotExist(err) {
if project_model.IsErrProjectNotExist(err) {
ctx.NotFound("", nil)
} else {
ctx.ServerError("GetProjectByID", err)
@@ -480,7 +484,7 @@ func checkProjectBoardChangePermissions(ctx *context.Context) (*models.Project,
return nil, nil
}
board, err := models.GetProjectBoard(ctx.ParamsInt64(":boardID"))
board, err := project_model.GetBoard(ctx.ParamsInt64(":boardID"))
if err != nil {
ctx.ServerError("GetProjectBoard", err)
return nil, nil
@@ -519,7 +523,7 @@ func EditProjectBoard(ctx *context.Context) {
board.Sorting = form.Sorting
}
if err := models.UpdateProjectBoard(board); err != nil {
if err := project_model.UpdateBoard(board); err != nil {
ctx.ServerError("UpdateProjectBoard", err)
return
}
@@ -536,7 +540,7 @@ func SetDefaultProjectBoard(ctx *context.Context) {
return
}
if err := models.SetDefaultBoard(project.ID, board.ID); err != nil {
if err := project_model.SetDefaultBoard(project.ID, board.ID); err != nil {
ctx.ServerError("SetDefaultBoard", err)
return
}
@@ -548,7 +552,7 @@ func SetDefaultProjectBoard(ctx *context.Context) {
// MoveIssues moves or keeps issues in a column and sorts them inside that column
func MoveIssues(ctx *context.Context) {
if ctx.User == nil {
if ctx.Doer == nil {
ctx.JSON(http.StatusForbidden, map[string]string{
"message": "Only signed in users are allowed to perform this action.",
})
@@ -562,9 +566,9 @@ func MoveIssues(ctx *context.Context) {
return
}
project, err := models.GetProjectByID(ctx.ParamsInt64(":id"))
project, err := project_model.GetProjectByID(ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrProjectNotExist(err) {
if project_model.IsErrProjectNotExist(err) {
ctx.NotFound("ProjectNotExist", nil)
} else {
ctx.ServerError("GetProjectByID", err)
@@ -576,19 +580,18 @@ func MoveIssues(ctx *context.Context) {
return
}
var board *models.ProjectBoard
var board *project_model.Board
if ctx.ParamsInt64(":boardID") == 0 {
board = &models.ProjectBoard{
board = &project_model.Board{
ID: 0,
ProjectID: project.ID,
Title: ctx.Tr("repo.projects.type.uncategorized"),
}
} else {
// column
board, err = models.GetProjectBoard(ctx.ParamsInt64(":boardID"))
board, err = project_model.GetBoard(ctx.ParamsInt64(":boardID"))
if err != nil {
if models.IsErrProjectBoardNotExist(err) {
if project_model.IsErrProjectBoardNotExist(err) {
ctx.NotFound("ProjectBoardNotExist", nil)
} else {
ctx.ServerError("GetProjectBoard", err)
@@ -634,7 +637,7 @@ func MoveIssues(ctx *context.Context) {
return
}
if err = models.MoveIssuesOnProjectBoard(board, sortedIssueIDs); err != nil {
if err = project_model.MoveIssuesOnProjectBoard(board, sortedIssueIDs); err != nil {
ctx.ServerError("MoveIssuesOnProjectBoard", err)
return
}
@@ -647,8 +650,43 @@ func MoveIssues(ctx *context.Context) {
// CreateProject renders the generic project creation page
func CreateProject(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.projects.new")
ctx.Data["ProjectTypes"] = models.GetProjectsConfig()
ctx.Data["ProjectTypes"] = project_model.GetProjectsConfig()
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
ctx.HTML(http.StatusOK, tplGenericProjectsNew)
}
// CreateProjectPost creates an individual and/or organization project
func CreateProjectPost(ctx *context.Context, form forms.UserCreateProjectForm) {
user := checkContextUser(ctx, form.UID)
if ctx.Written() {
return
}
ctx.Data["ContextUser"] = user
if ctx.HasError() {
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
ctx.HTML(http.StatusOK, tplGenericProjectsNew)
return
}
projectType := project_model.TypeIndividual
if user.IsOrganization() {
projectType = project_model.TypeOrganization
}
if err := project_model.NewProject(&project_model.Project{
Title: form.Title,
Description: form.Content,
CreatorID: user.ID,
BoardType: form.BoardType,
Type: projectType,
}); err != nil {
ctx.ServerError("NewProject", err)
return
}
ctx.Flash.Success(ctx.Tr("repo.projects.create_success", form.Title))
ctx.Redirect(setting.AppSubURL + "/")
}
+175 -160
View File
@@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
@@ -33,6 +34,7 @@ import (
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/routers/utils"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/forms"
"code.gitea.io/gitea/services/gitdiff"
pull_service "code.gitea.io/gitea/services/pull"
@@ -68,7 +70,7 @@ func getRepository(ctx *context.Context, repoID int64) *repo_model.Repository {
return nil
}
perm, err := models.GetUserRepoPermission(repo, ctx.User)
perm, err := models.GetUserRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return nil
@@ -77,7 +79,7 @@ func getRepository(ctx *context.Context, repoID int64) *repo_model.Repository {
if !perm.CanRead(unit.TypeCode) {
log.Trace("Permission Denied: User %-v cannot read %-v of repo %-v\n"+
"User in repo has Permissions: %-+v",
ctx.User,
ctx.Doer,
unit.TypeCode,
ctx.Repo,
perm)
@@ -99,7 +101,7 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
return nil
}
if err := forkRepo.GetOwner(db.DefaultContext); err != nil {
if err := forkRepo.GetOwner(ctx); err != nil {
ctx.ServerError("GetOwner", err)
return nil
}
@@ -107,16 +109,16 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
ctx.Data["repo_name"] = forkRepo.Name
ctx.Data["description"] = forkRepo.Description
ctx.Data["IsPrivate"] = forkRepo.IsPrivate || forkRepo.Owner.Visibility == structs.VisibleTypePrivate
canForkToUser := forkRepo.OwnerID != ctx.User.ID && !repo_model.HasForkedRepo(ctx.User.ID, forkRepo.ID)
canForkToUser := forkRepo.OwnerID != ctx.Doer.ID && !repo_model.HasForkedRepo(ctx.Doer.ID, forkRepo.ID)
ctx.Data["ForkRepo"] = forkRepo
ownedOrgs, err := models.GetOrgsCanCreateRepoByUserID(ctx.User.ID)
ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(ctx.Doer.ID)
if err != nil {
ctx.ServerError("GetOrgsCanCreateRepoByUserID", err)
return nil
}
var orgs []*models.Organization
var orgs []*organization.Organization
for _, org := range ownedOrgs {
if forkRepo.OwnerID != org.ID && !repo_model.HasForkedRepo(org.ID, forkRepo.ID) {
orgs = append(orgs, org)
@@ -125,7 +127,7 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
traverseParentRepo := forkRepo
for {
if ctx.User.ID == traverseParentRepo.OwnerID {
if ctx.Doer.ID == traverseParentRepo.OwnerID {
canForkToUser = false
} else {
for i, org := range orgs {
@@ -150,7 +152,7 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
ctx.Data["Orgs"] = orgs
if canForkToUser {
ctx.Data["ContextUser"] = ctx.User
ctx.Data["ContextUser"] = ctx.Doer
} else if len(orgs) > 0 {
ctx.Data["ContextUser"] = orgs[0]
}
@@ -216,7 +218,7 @@ func ForkPost(ctx *context.Context) {
// Check if user is allowed to create repo's on the organization.
if ctxUser.IsOrganization() {
isAllowedToFork, err := models.OrgFromUser(ctxUser).CanCreateOrgRepo(ctx.User.ID)
isAllowedToFork, err := organization.OrgFromUser(ctxUser).CanCreateOrgRepo(ctx.Doer.ID)
if err != nil {
ctx.ServerError("CanCreateOrgRepo", err)
return
@@ -226,7 +228,7 @@ func ForkPost(ctx *context.Context) {
}
}
repo, err := repo_service.ForkRepository(ctx.User, ctxUser, repo_service.ForkRepoOptions{
repo, err := repo_service.ForkRepository(ctx, ctx.Doer, ctxUser, repo_service.ForkRepoOptions{
BaseRepo: forkRepo,
Name: form.RepoName,
Description: form.Description,
@@ -264,7 +266,7 @@ func checkPullInfo(ctx *context.Context) *models.Issue {
ctx.ServerError("LoadPoster", err)
return nil
}
if err := issue.LoadRepo(); err != nil {
if err := issue.LoadRepo(ctx); err != nil {
ctx.ServerError("LoadRepo", err)
return nil
}
@@ -281,14 +283,14 @@ func checkPullInfo(ctx *context.Context) *models.Issue {
return nil
}
if err = issue.PullRequest.LoadHeadRepo(); err != nil {
if err = issue.PullRequest.LoadHeadRepoCtx(ctx); err != nil {
ctx.ServerError("LoadHeadRepo", err)
return nil
}
if ctx.IsSigned {
// Update issue-user.
if err = issue.ReadBy(ctx.User.ID); err != nil {
if err = issue.ReadBy(ctx, ctx.Doer.ID); err != nil {
ctx.ServerError("ReadBy", err)
return nil
}
@@ -338,7 +340,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C
}
if commitSHA != "" {
// Get immediate parent of the first commit in the patch, grab history back
parentCommit, err = git.NewCommand(ctx, "rev-list", "-1", "--skip=1", commitSHA).RunInDir(ctx.Repo.GitRepo.Path)
parentCommit, _, err = git.NewCommand(ctx, "rev-list", "-1", "--skip=1", commitSHA).RunStdString(&git.RunOpts{Dir: ctx.Repo.GitRepo.Path})
if err == nil {
parentCommit = strings.TrimSpace(parentCommit)
}
@@ -395,12 +397,12 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
repo := ctx.Repo.Repository
pull := issue.PullRequest
if err := pull.LoadHeadRepo(); err != nil {
if err := pull.LoadHeadRepoCtx(ctx); err != nil {
ctx.ServerError("LoadHeadRepo", err)
return nil
}
if err := pull.LoadBaseRepo(); err != nil {
if err := pull.LoadBaseRepoCtx(ctx); err != nil {
ctx.ServerError("LoadBaseRepo", err)
return nil
}
@@ -417,7 +419,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
if pull.BaseRepoID == ctx.Repo.Repository.ID && ctx.Repo.GitRepo != nil {
baseGitRepo = ctx.Repo.GitRepo
} else {
baseGitRepo, err := git.OpenRepositoryCtx(ctx, pull.BaseRepo.RepoPath())
baseGitRepo, err := git.OpenRepository(ctx, pull.BaseRepo.RepoPath())
if err != nil {
ctx.ServerError("OpenRepository", err)
return nil
@@ -469,7 +471,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
var headBranchSha string
// HeadRepo may be missing
if pull.HeadRepo != nil {
headGitRepo, err := git.OpenRepositoryCtx(ctx, pull.HeadRepo.RepoPath())
headGitRepo, err := git.OpenRepository(ctx, pull.HeadRepo.RepoPath())
if err != nil {
ctx.ServerError("OpenRepository", err)
return nil
@@ -497,7 +499,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
if headBranchExist {
var err error
ctx.Data["UpdateAllowed"], ctx.Data["UpdateByRebaseAllowed"], err = pull_service.IsUserAllowedToUpdate(pull, ctx.User)
ctx.Data["UpdateAllowed"], ctx.Data["UpdateByRebaseAllowed"], err = pull_service.IsUserAllowedToUpdate(ctx, pull, ctx.Doer)
if err != nil {
ctx.ServerError("IsUserAllowedToUpdate", err)
return nil
@@ -683,23 +685,36 @@ func ViewPullFiles(ctx *context.Context) {
if fileOnly && (len(files) == 2 || len(files) == 1) {
maxLines, maxFiles = -1, -1
}
diffOptions := &gitdiff.DiffOptions{
BeforeCommitID: startCommitID,
AfterCommitID: endCommitID,
SkipTo: ctx.FormString("skip-to"),
MaxLines: maxLines,
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
MaxFiles: maxFiles,
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)),
}
diff, err := gitdiff.GetDiff(gitRepo,
&gitdiff.DiffOptions{
BeforeCommitID: startCommitID,
AfterCommitID: endCommitID,
SkipTo: ctx.FormString("skip-to"),
MaxLines: maxLines,
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
MaxFiles: maxFiles,
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)),
}, ctx.FormStrings("files")...)
var methodWithError string
var diff *gitdiff.Diff
if !ctx.IsSigned {
diff, err = gitdiff.GetDiff(gitRepo, diffOptions, files...)
methodWithError = "GetDiff"
} else {
diff, err = gitdiff.SyncAndGetUserSpecificDiff(ctx, ctx.Doer.ID, pull, gitRepo, diffOptions, files...)
methodWithError = "SyncAndGetUserSpecificDiff"
}
if err != nil {
ctx.ServerError("GetDiffRangeWithWhitespaceBehavior", err)
ctx.ServerError(methodWithError, err)
return
}
if err = diff.LoadComments(ctx, issue, ctx.User); err != nil {
ctx.PageData["prReview"] = map[string]interface{}{
"numberOfFiles": diff.NumFiles,
"numberOfViewedFiles": diff.NumViewedFiles,
}
if err = diff.LoadComments(ctx, issue, ctx.Doer); err != nil {
ctx.ServerError("LoadComments", err)
return
}
@@ -732,8 +747,8 @@ func ViewPullFiles(ctx *context.Context) {
return
}
if ctx.IsSigned && ctx.User != nil {
if ctx.Data["CanMarkConversation"], err = models.CanMarkConversation(issue, ctx.User); err != nil {
if ctx.IsSigned && ctx.Doer != nil {
if ctx.Data["CanMarkConversation"], err = models.CanMarkConversation(issue, ctx.Doer); err != nil {
ctx.ServerError("CanMarkConversation", err)
return
}
@@ -741,7 +756,6 @@ func ViewPullFiles(ctx *context.Context) {
setCompareContext(ctx, baseCommit, commit, ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
ctx.Data["RequireHighlightJS"] = true
ctx.Data["RequireTribute"] = true
if ctx.Data["Assignees"], err = models.GetRepoAssignees(ctx.Repo.Repository); err != nil {
ctx.ServerError("GetAssignees", err)
@@ -751,13 +765,29 @@ func ViewPullFiles(ctx *context.Context) {
if ctx.Written() {
return
}
ctx.Data["CurrentReview"], err = models.GetCurrentReview(ctx.User, issue)
currentReview, err := models.GetCurrentReview(ctx.Doer, issue)
if err != nil && !models.IsErrReviewNotExist(err) {
ctx.ServerError("GetCurrentReview", err)
return
}
numPendingCodeComments := int64(0)
if currentReview != nil {
numPendingCodeComments, err = models.CountComments(&models.FindCommentsOptions{
Type: models.CommentTypeCode,
ReviewID: currentReview.ID,
IssueID: issue.ID,
})
if err != nil {
ctx.ServerError("CountComments", err)
return
}
}
ctx.Data["CurrentReview"] = currentReview
ctx.Data["PendingCodeCommentNumber"] = numPendingCodeComments
getBranchData(ctx, issue)
ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.Doer.ID)
ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
@@ -783,16 +813,16 @@ func UpdatePullRequest(ctx *context.Context) {
rebase := ctx.FormString("style") == "rebase"
if err := issue.PullRequest.LoadBaseRepo(); err != nil {
if err := issue.PullRequest.LoadBaseRepoCtx(ctx); err != nil {
ctx.ServerError("LoadBaseRepo", err)
return
}
if err := issue.PullRequest.LoadHeadRepo(); err != nil {
if err := issue.PullRequest.LoadHeadRepoCtx(ctx); err != nil {
ctx.ServerError("LoadHeadRepo", err)
return
}
allowedUpdateByMerge, allowedUpdateByRebase, err := pull_service.IsUserAllowedToUpdate(issue.PullRequest, ctx.User)
allowedUpdateByMerge, allowedUpdateByRebase, err := pull_service.IsUserAllowedToUpdate(ctx, issue.PullRequest, ctx.Doer)
if err != nil {
ctx.ServerError("IsUserAllowedToMerge", err)
return
@@ -808,7 +838,7 @@ func UpdatePullRequest(ctx *context.Context) {
// default merge commit message
message := fmt.Sprintf("Merge branch '%s' into %s", issue.PullRequest.BaseBranch, issue.PullRequest.HeadBranch)
if err = pull_service.Update(ctx, issue.PullRequest, ctx.User, message, rebase); err != nil {
if err = pull_service.Update(ctx, issue.PullRequest, ctx.Doer, message, rebase); err != nil {
if models.IsErrMergeConflicts(err) {
conflictError := err.(models.ErrMergeConflicts)
flashError, err := ctx.RenderToString(tplAlertDetails, map[string]interface{}{
@@ -857,50 +887,62 @@ func MergePullRequest(ctx *context.Context) {
if ctx.Written() {
return
}
if issue.IsClosed {
if issue.IsPull {
ctx.Flash.Error(ctx.Tr("repo.pulls.is_closed"))
ctx.Redirect(issue.Link())
return
}
ctx.Flash.Error(ctx.Tr("repo.issues.closed_title"))
ctx.Redirect(issue.Link())
return
}
pr := issue.PullRequest
pr.Issue = issue
pr.Issue.Repo = ctx.Repo.Repository
manuallMerge := repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged
forceMerge := form.ForceMerge != nil && *form.ForceMerge
allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.Repo.Permission, ctx.User)
if err != nil {
ctx.ServerError("IsUserAllowedToMerge", err)
return
}
if !allowedMerge {
ctx.Flash.Error(ctx.Tr("repo.pulls.update_not_allowed"))
ctx.Redirect(issue.Link())
return
}
if pr.HasMerged {
ctx.Flash.Error(ctx.Tr("repo.pulls.has_merged"))
ctx.Redirect(issue.Link())
// start with merging by checking
if err := pull_service.CheckPullMergable(ctx, ctx.Doer, &ctx.Repo.Permission, pr, manuallMerge, forceMerge); err != nil {
if errors.Is(err, pull_service.ErrIsClosed) {
if issue.IsPull {
ctx.Flash.Error(ctx.Tr("repo.pulls.is_closed"))
ctx.Redirect(issue.Link())
} else {
ctx.Flash.Error(ctx.Tr("repo.issues.closed_title"))
ctx.Redirect(issue.Link())
}
} else if errors.Is(err, pull_service.ErrUserNotAllowedToMerge) {
ctx.Flash.Error(ctx.Tr("repo.pulls.update_not_allowed"))
ctx.Redirect(issue.Link())
} else if errors.Is(err, pull_service.ErrHasMerged) {
ctx.Flash.Error(ctx.Tr("repo.pulls.has_merged"))
ctx.Redirect(issue.Link())
} else if errors.Is(err, pull_service.ErrIsWorkInProgress) {
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_wip"))
ctx.Redirect(issue.Link())
} else if errors.Is(err, pull_service.ErrNotMergableState) {
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
ctx.Redirect(issue.Link())
} else if models.IsErrDisallowedToMerge(err) {
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
ctx.Redirect(issue.Link())
} else if asymkey_service.IsErrWontSign(err) {
ctx.Flash.Error(err.Error()) // has not translation ...
ctx.Redirect(issue.Link())
} else if errors.Is(err, pull_service.ErrDependenciesLeft) {
ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
ctx.Redirect(issue.Link())
} else {
ctx.ServerError("WebCheck", err)
}
return
}
// handle manually-merged mark
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged {
if err = pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
if manuallMerge {
if err := pull_service.MergedManually(pr, ctx.Doer, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
if models.IsErrInvalidMergeStyle(err) {
ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
ctx.Redirect(issue.Link())
return
} else if strings.Contains(err.Error(), "Wrong commit ID") {
ctx.Flash.Error(ctx.Tr("repo.pulls.wrong_commit_id"))
ctx.Redirect(issue.Link())
return
} else {
ctx.ServerError("MergedManually", err)
}
ctx.ServerError("MergedManually", err)
return
}
@@ -908,49 +950,13 @@ func MergePullRequest(ctx *context.Context) {
return
}
if !pr.CanAutoMerge() {
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
ctx.Redirect(issue.Link())
return
}
if pr.IsWorkInProgress() {
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_wip"))
ctx.Redirect(issue.Link())
return
}
if err := pull_service.CheckPRReadyToMerge(ctx, pr, false); err != nil {
if !models.IsErrNotAllowedToMerge(err) {
ctx.ServerError("Merge PR status", err)
return
}
if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, ctx.User); err != nil {
ctx.ServerError("IsUserRepoAdmin", err)
return
} else if !isRepoAdmin {
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
ctx.Redirect(issue.Link())
return
}
}
if ctx.HasError() {
ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
ctx.Redirect(issue.Link())
return
}
message := strings.TrimSpace(form.MergeTitleField)
if len(message) == 0 {
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleMerge {
message = pr.GetDefaultMergeMessage()
}
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleRebaseMerge {
message = pr.GetDefaultMergeMessage()
}
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleSquash {
message = pr.GetDefaultSquashMessage()
var err error
message, err = pull_service.GetDefaultMergeMessage(ctx.Repo.GitRepo, pr, repo_model.MergeStyle(form.Do))
if err != nil {
ctx.ServerError("GetDefaultMergeMessage", err)
return
}
}
@@ -959,25 +965,10 @@ func MergePullRequest(ctx *context.Context) {
message += "\n\n" + form.MergeMessageField
}
pr.Issue = issue
pr.Issue.Repo = ctx.Repo.Repository
noDeps, err := models.IssueNoDependenciesLeft(issue)
if err != nil {
return
}
if !noDeps {
ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
ctx.Redirect(issue.Link())
return
}
if err = pull_service.Merge(ctx, pr, ctx.User, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message); err != nil {
if err := pull_service.Merge(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message); err != nil {
if models.IsErrInvalidMergeStyle(err) {
ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
ctx.Redirect(issue.Link())
return
} else if models.IsErrMergeConflicts(err) {
conflictError := err.(models.ErrMergeConflicts)
flashError, err := ctx.RenderToString(tplAlertDetails, map[string]interface{}{
@@ -991,7 +982,6 @@ func MergePullRequest(ctx *context.Context) {
}
ctx.Flash.Error(flashError)
ctx.Redirect(issue.Link())
return
} else if models.IsErrRebaseConflicts(err) {
conflictError := err.(models.ErrRebaseConflicts)
flashError, err := ctx.RenderToString(tplAlertDetails, map[string]interface{}{
@@ -1005,22 +995,18 @@ func MergePullRequest(ctx *context.Context) {
}
ctx.Flash.Error(flashError)
ctx.Redirect(issue.Link())
return
} else if models.IsErrMergeUnrelatedHistories(err) {
log.Debug("MergeUnrelatedHistories error: %v", err)
ctx.Flash.Error(ctx.Tr("repo.pulls.unrelated_histories"))
ctx.Redirect(issue.Link())
return
} else if git.IsErrPushOutOfDate(err) {
log.Debug("MergePushOutOfDate error: %v", err)
ctx.Flash.Error(ctx.Tr("repo.pulls.merge_out_of_date"))
ctx.Redirect(issue.Link())
return
} else if models.IsErrSHADoesNotMatch(err) {
log.Debug("MergeHeadOutOfDate error: %v", err)
ctx.Flash.Error(ctx.Tr("repo.pulls.head_out_of_date"))
ctx.Redirect(issue.Link())
return
} else if git.IsErrPushRejected(err) {
log.Debug("MergePushRejected error: %v", err)
pushrejErr := err.(*git.ErrPushRejected)
@@ -1040,13 +1026,14 @@ func MergePullRequest(ctx *context.Context) {
ctx.Flash.Error(flashError)
}
ctx.Redirect(issue.Link())
return
} else {
ctx.ServerError("Merge", err)
}
ctx.ServerError("Merge", err)
return
}
log.Trace("Pull request merged: %d", pr.ID)
if err := stopTimerIfAvailable(ctx.User, issue); err != nil {
if err := stopTimerIfAvailable(ctx.Doer, issue); err != nil {
ctx.ServerError("CreateOrStopIssueStopwatch", err)
return
}
@@ -1055,7 +1042,7 @@ func MergePullRequest(ctx *context.Context) {
if form.DeleteBranchAfterMerge {
// Don't cleanup when other pr use this branch as head branch
exist, err := models.HasUnmergedPullRequestsByHeadInfo(pr.HeadRepoID, pr.HeadBranch)
exist, err := models.HasUnmergedPullRequestsByHeadInfo(ctx, pr.HeadRepoID, pr.HeadBranch)
if err != nil {
ctx.ServerError("HasUnmergedPullRequestsByHeadInfo", err)
return
@@ -1069,7 +1056,7 @@ func MergePullRequest(ctx *context.Context) {
if ctx.Repo != nil && ctx.Repo.Repository != nil && pr.HeadRepoID == ctx.Repo.Repository.ID && ctx.Repo.GitRepo != nil {
headRepo = ctx.Repo.GitRepo
} else {
headRepo, err = git.OpenRepositoryCtx(ctx, pr.HeadRepo.RepoPath())
headRepo, err = git.OpenRepository(ctx, pr.HeadRepo.RepoPath())
if err != nil {
ctx.ServerError(fmt.Sprintf("OpenRepository[%s]", pr.HeadRepo.RepoPath()), err)
return
@@ -1100,7 +1087,6 @@ func CompareAndPullRequestPost(ctx *context.Context) {
ctx.Data["IsDiffCompare"] = true
ctx.Data["IsRepoToolbarCommits"] = true
ctx.Data["RequireTribute"] = true
ctx.Data["RequireHighlightJS"] = true
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
upload.AddUploadContext(ctx, "comment")
@@ -1168,21 +1154,22 @@ func CompareAndPullRequestPost(ctx *context.Context) {
RepoID: repo.ID,
Repo: repo,
Title: form.Title,
PosterID: ctx.User.ID,
Poster: ctx.User,
PosterID: ctx.Doer.ID,
Poster: ctx.Doer,
MilestoneID: milestoneID,
IsPull: true,
Content: form.Content,
}
pullRequest := &models.PullRequest{
HeadRepoID: ci.HeadRepo.ID,
BaseRepoID: repo.ID,
HeadBranch: ci.HeadBranch,
BaseBranch: ci.BaseBranch,
HeadRepo: ci.HeadRepo,
BaseRepo: repo,
MergeBase: ci.CompareInfo.MergeBase,
Type: models.PullRequestGitea,
HeadRepoID: ci.HeadRepo.ID,
BaseRepoID: repo.ID,
HeadBranch: ci.HeadBranch,
BaseBranch: ci.BaseBranch,
HeadRepo: ci.HeadRepo,
BaseRepo: repo,
MergeBase: ci.CompareInfo.MergeBase,
Type: models.PullRequestGitea,
AllowMaintainerEdit: form.AllowMaintainerEdit,
}
// FIXME: check error in the case two people send pull request at almost same time, give nice error prompt
// instead of 500.
@@ -1235,7 +1222,7 @@ func CleanUpPullRequest(ctx *context.Context) {
}
// Don't cleanup when there are other PR's that use this branch as head branch.
exist, err := models.HasUnmergedPullRequestsByHeadInfo(pr.HeadRepoID, pr.HeadBranch)
exist, err := models.HasUnmergedPullRequestsByHeadInfo(ctx, pr.HeadRepoID, pr.HeadBranch)
if err != nil {
ctx.ServerError("HasUnmergedPullRequestsByHeadInfo", err)
return
@@ -1245,22 +1232,22 @@ func CleanUpPullRequest(ctx *context.Context) {
return
}
if err := pr.LoadHeadRepo(); err != nil {
if err := pr.LoadHeadRepoCtx(ctx); err != nil {
ctx.ServerError("LoadHeadRepo", err)
return
} else if pr.HeadRepo == nil {
// Forked repository has already been deleted
ctx.NotFound("CleanUpPullRequest", nil)
return
} else if err = pr.LoadBaseRepo(); err != nil {
} else if err = pr.LoadBaseRepoCtx(ctx); err != nil {
ctx.ServerError("LoadBaseRepo", err)
return
} else if err = pr.HeadRepo.GetOwner(db.DefaultContext); err != nil {
} else if err = pr.HeadRepo.GetOwner(ctx); err != nil {
ctx.ServerError("HeadRepo.GetOwner", err)
return
}
perm, err := models.GetUserRepoPermission(pr.HeadRepo, ctx.User)
perm, err := models.GetUserRepoPermission(ctx, pr.HeadRepo, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return
@@ -1279,7 +1266,7 @@ func CleanUpPullRequest(ctx *context.Context) {
gitBaseRepo = ctx.Repo.GitRepo
} else {
// If not just open it
gitBaseRepo, err = git.OpenRepositoryCtx(ctx, pr.BaseRepo.RepoPath())
gitBaseRepo, err = git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
if err != nil {
ctx.ServerError(fmt.Sprintf("OpenRepository[%s]", pr.BaseRepo.RepoPath()), err)
return
@@ -1294,7 +1281,7 @@ func CleanUpPullRequest(ctx *context.Context) {
gitRepo = ctx.Repo.GitRepo
} else if pr.BaseRepoID != pr.HeadRepoID {
// Otherwise just load it up
gitRepo, err = git.OpenRepositoryCtx(ctx, pr.HeadRepo.RepoPath())
gitRepo, err = git.OpenRepository(ctx, pr.HeadRepo.RepoPath())
if err != nil {
ctx.ServerError(fmt.Sprintf("OpenRepository[%s]", pr.HeadRepo.RepoPath()), err)
return
@@ -1331,7 +1318,7 @@ func CleanUpPullRequest(ctx *context.Context) {
func deleteBranch(ctx *context.Context, pr *models.PullRequest, gitRepo *git.Repository) {
fullBranchName := pr.HeadRepo.Owner.Name + "/" + pr.HeadBranch
if err := repo_service.DeleteBranch(ctx.User, pr.HeadRepo, gitRepo, pr.HeadBranch); err != nil {
if err := repo_service.DeleteBranch(ctx.Doer, pr.HeadRepo, gitRepo, pr.HeadBranch); err != nil {
switch {
case git.IsErrBranchNotExist(err):
ctx.Flash.Error(ctx.Tr("repo.branch.deletion_failed", fullBranchName))
@@ -1346,7 +1333,7 @@ func deleteBranch(ctx *context.Context, pr *models.PullRequest, gitRepo *git.Rep
return
}
if err := models.AddDeletePRBranchComment(ctx.User, pr.BaseRepo, pr.IssueID, pr.HeadBranch); err != nil {
if err := models.AddDeletePRBranchComment(ctx, ctx.Doer, pr.BaseRepo, pr.IssueID, pr.HeadBranch); err != nil {
// Do not fail here as branch has already been deleted
log.Error("DeleteBranch: %v", err)
}
@@ -1396,7 +1383,7 @@ func UpdatePullRequestTarget(ctx *context.Context) {
return
}
if !ctx.IsSigned || (!issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)) {
if !ctx.IsSigned || (!issue.IsPoster(ctx.Doer.ID) && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)) {
ctx.Error(http.StatusForbidden)
return
}
@@ -1407,7 +1394,7 @@ func UpdatePullRequestTarget(ctx *context.Context) {
return
}
if err := pull_service.ChangeTargetBranch(ctx, pr, ctx.User, targetBranch); err != nil {
if err := pull_service.ChangeTargetBranch(ctx, pr, ctx.Doer, targetBranch); err != nil {
if models.IsErrPullRequestAlreadyExists(err) {
err := err.(models.ErrPullRequestAlreadyExists)
@@ -1448,9 +1435,37 @@ func UpdatePullRequestTarget(ctx *context.Context) {
}
return
}
notification.NotifyPullRequestChangeTargetBranch(ctx.User, pr, targetBranch)
notification.NotifyPullRequestChangeTargetBranch(ctx.Doer, pr, targetBranch)
ctx.JSON(http.StatusOK, map[string]interface{}{
"base_branch": pr.BaseBranch,
})
}
// SetAllowEdits allow edits from maintainers to PRs
func SetAllowEdits(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.UpdateAllowEditsForm)
pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
if err != nil {
if models.IsErrPullRequestNotExist(err) {
ctx.NotFound("GetPullRequestByIndex", err)
} else {
ctx.ServerError("GetPullRequestByIndex", err)
}
return
}
if err := pull_service.SetAllowEdits(ctx, ctx.Doer, pr, form.AllowMaintainerEdit); err != nil {
if errors.Is(pull_service.ErrUserHasNoPermissionForAction, err) {
ctx.Error(http.StatusForbidden)
return
}
ctx.ServerError("SetAllowEdits", err)
return
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"allow_maintainer_edit": pr.AllowMaintainerEdit,
})
}
+54 -8
View File
@@ -9,8 +9,10 @@ import (
"net/http"
"code.gitea.io/gitea/models"
pull_model "code.gitea.io/gitea/models/pull"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
@@ -29,7 +31,7 @@ func RenderNewCodeCommentForm(ctx *context.Context) {
if !issue.IsPull {
return
}
currentReview, err := models.GetCurrentReview(ctx.User, issue)
currentReview, err := models.GetCurrentReview(ctx.Doer, issue)
if err != nil && !models.IsErrReviewNotExist(err) {
ctx.ServerError("GetCurrentReview", err)
return
@@ -69,7 +71,7 @@ func CreateCodeComment(ctx *context.Context) {
}
comment, err := pull_service.CreateCodeComment(ctx,
ctx.User,
ctx.Doer,
ctx.Repo.GitRepo,
issue,
signedLine,
@@ -117,7 +119,7 @@ func UpdateResolveConversation(ctx *context.Context) {
}
var permResult bool
if permResult, err = models.CanMarkConversation(comment.Issue, ctx.User); err != nil {
if permResult, err = models.CanMarkConversation(comment.Issue, ctx.Doer); err != nil {
ctx.ServerError("CanMarkConversation", err)
return
}
@@ -132,7 +134,7 @@ func UpdateResolveConversation(ctx *context.Context) {
}
if action == "Resolve" || action == "UnResolve" {
err = models.MarkConversation(comment, ctx.User, action == "Resolve")
err = models.MarkConversation(comment, ctx.Doer, action == "Resolve")
if err != nil {
ctx.ServerError("MarkConversation", err)
return
@@ -152,7 +154,7 @@ func UpdateResolveConversation(ctx *context.Context) {
}
func renderConversation(ctx *context.Context, comment *models.Comment) {
comments, err := models.FetchCodeCommentsByLine(ctx, comment.Issue, ctx.User, comment.TreePath, comment.Line)
comments, err := models.FetchCodeCommentsByLine(ctx, comment.Issue, ctx.Doer, comment.TreePath, comment.Line)
if err != nil {
ctx.ServerError("FetchCodeCommentsByLine", err)
return
@@ -198,7 +200,7 @@ func SubmitReview(ctx *context.Context) {
// can not approve/reject your own PR
case models.ReviewTypeApprove, models.ReviewTypeReject:
if issue.IsPoster(ctx.User.ID) {
if issue.IsPoster(ctx.Doer.ID) {
var translated string
if reviewType == models.ReviewTypeApprove {
translated = ctx.Tr("repo.issues.review.self.approval")
@@ -217,7 +219,7 @@ func SubmitReview(ctx *context.Context) {
attachments = form.Files
}
_, comm, err := pull_service.SubmitReview(ctx, ctx.User, ctx.Repo.GitRepo, issue, reviewType, form.Content, form.CommitID, attachments)
_, comm, err := pull_service.SubmitReview(ctx, ctx.Doer, ctx.Repo.GitRepo, issue, reviewType, form.Content, form.CommitID, attachments)
if err != nil {
if models.IsContentEmptyErr(err) {
ctx.Flash.Error(ctx.Tr("repo.issues.review.content.empty"))
@@ -234,7 +236,7 @@ func SubmitReview(ctx *context.Context) {
// DismissReview dismissing stale review by repo admin
func DismissReview(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.DismissReviewForm)
comm, err := pull_service.DismissReview(ctx, form.ReviewID, form.Message, ctx.User, true)
comm, err := pull_service.DismissReview(ctx, form.ReviewID, form.Message, ctx.Doer, true)
if err != nil {
ctx.ServerError("pull_service.DismissReview", err)
return
@@ -242,3 +244,47 @@ func DismissReview(ctx *context.Context) {
ctx.Redirect(fmt.Sprintf("%s/pulls/%d#%s", ctx.Repo.RepoLink, comm.Issue.Index, comm.HashTag()))
}
// viewedFilesUpdate Struct to parse the body of a request to update the reviewed files of a PR
// If you want to implement an API to update the review, simply move this struct into modules.
type viewedFilesUpdate struct {
Files map[string]bool `json:"files"`
HeadCommitSHA string `json:"headCommitSHA"`
}
func UpdateViewedFiles(ctx *context.Context) {
// Find corresponding PR
issue := checkPullInfo(ctx)
if ctx.Written() {
return
}
pull := issue.PullRequest
var data *viewedFilesUpdate
err := json.NewDecoder(ctx.Req.Body).Decode(&data)
if err != nil {
log.Warn("Attempted to update a review but could not parse request body: %v", err)
ctx.Resp.WriteHeader(http.StatusBadRequest)
return
}
// Expect the review to have been now if no head commit was supplied
if data.HeadCommitSHA == "" {
data.HeadCommitSHA = pull.HeadCommitID
}
updatedFiles := make(map[string]pull_model.ViewedState, len(data.Files))
for file, viewed := range data.Files {
// Only unviewed and viewed are possible, has-changed can not be set from the outside
state := pull_model.Unviewed
if viewed {
state = pull_model.Viewed
}
updatedFiles[file] = state
}
if err := pull_model.UpdateReviewState(ctx, ctx.Doer.ID, pull.ID, data.HeadCommitSHA, updatedFiles); err != nil {
ctx.ServerError("UpdateReview", err)
}
}
+10 -10
View File
@@ -134,8 +134,8 @@ func releasesOrTags(ctx *context.Context, isTagList bool) {
// Temporary cache commits count of used branches to speed up.
countCache := make(map[string]int64)
cacheUsers := make(map[int64]*user_model.User)
if ctx.User != nil {
cacheUsers[ctx.User.ID] = ctx.User
if ctx.Doer != nil {
cacheUsers[ctx.Doer.ID] = ctx.Doer
}
var ok bool
@@ -325,7 +325,7 @@ func NewReleasePost(ctx *context.Context) {
}
if len(form.TagOnly) > 0 {
if err = releaseservice.CreateNewTag(ctx, ctx.User, ctx.Repo.Repository, form.Target, form.TagName, msg); err != nil {
if err = releaseservice.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, form.Target, form.TagName, msg); err != nil {
if models.IsErrTagAlreadyExists(err) {
e := err.(models.ErrTagAlreadyExists)
ctx.Flash.Error(ctx.Tr("repo.branch.tag_collision", e.TagName))
@@ -357,8 +357,8 @@ func NewReleasePost(ctx *context.Context) {
rel = &models.Release{
RepoID: ctx.Repo.Repository.ID,
Repo: ctx.Repo.Repository,
PublisherID: ctx.User.ID,
Publisher: ctx.User,
PublisherID: ctx.Doer.ID,
Publisher: ctx.Doer,
Title: form.Title,
TagName: form.TagName,
Target: form.Target,
@@ -394,16 +394,16 @@ func NewReleasePost(ctx *context.Context) {
rel.Target = form.Target
rel.IsDraft = len(form.Draft) > 0
rel.IsPrerelease = form.Prerelease
rel.PublisherID = ctx.User.ID
rel.PublisherID = ctx.Doer.ID
rel.IsTag = false
if err = releaseservice.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, attachmentUUIDs, nil, nil); err != nil {
if err = releaseservice.UpdateRelease(ctx.Doer, ctx.Repo.GitRepo, rel, attachmentUUIDs, nil, nil); err != nil {
ctx.Data["Err_TagName"] = true
ctx.ServerError("UpdateRelease", err)
return
}
}
log.Trace("Release created: %s/%s:%s", ctx.User.LowerName, ctx.Repo.Repository.Name, form.TagName)
log.Trace("Release created: %s/%s:%s", ctx.Doer.LowerName, ctx.Repo.Repository.Name, form.TagName)
ctx.Redirect(ctx.Repo.RepoLink + "/releases")
}
@@ -497,7 +497,7 @@ func EditReleasePost(ctx *context.Context) {
rel.Note = form.Content
rel.IsDraft = len(form.Draft) > 0
rel.IsPrerelease = form.Prerelease
if err = releaseservice.UpdateRelease(ctx.User, ctx.Repo.GitRepo,
if err = releaseservice.UpdateRelease(ctx.Doer, ctx.Repo.GitRepo,
rel, addAttachmentUUIDs, delAttachmentUUIDs, editAttachments); err != nil {
ctx.ServerError("UpdateRelease", err)
return
@@ -516,7 +516,7 @@ func DeleteTag(ctx *context.Context) {
}
func deleteReleaseOrTag(ctx *context.Context, isDelTag bool) {
if err := releaseservice.DeleteReleaseByID(ctx, ctx.FormInt64("id"), ctx.User, isDelTag); err != nil {
if err := releaseservice.DeleteReleaseByID(ctx, ctx.FormInt64("id"), ctx.Doer, isDelTag); err != nil {
ctx.Flash.Error("DeleteReleaseByID: " + err.Error())
} else {
if isDelTag {
+149 -33
View File
@@ -14,15 +14,20 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
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/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/forms"
repo_service "code.gitea.io/gitea/services/repository"
@@ -57,14 +62,14 @@ func MustBeAbleToUpload(ctx *context.Context) {
}
func checkContextUser(ctx *context.Context, uid int64) *user_model.User {
orgs, err := models.GetOrgsCanCreateRepoByUserID(ctx.User.ID)
orgs, err := organization.GetOrgsCanCreateRepoByUserID(ctx.Doer.ID)
if err != nil {
ctx.ServerError("GetOrgsCanCreateRepoByUserID", err)
return nil
}
if !ctx.User.IsAdmin {
orgsAvailable := []*models.Organization{}
if !ctx.Doer.IsAdmin {
orgsAvailable := []*organization.Organization{}
for i := 0; i < len(orgs); i++ {
if orgs[i].CanCreateRepo() {
orgsAvailable = append(orgsAvailable, orgs[i])
@@ -76,13 +81,13 @@ func checkContextUser(ctx *context.Context, uid int64) *user_model.User {
}
// Not equal means current user is an organization.
if uid == ctx.User.ID || uid == 0 {
return ctx.User
if uid == ctx.Doer.ID || uid == 0 {
return ctx.Doer
}
org, err := user_model.GetUserByID(uid)
if user_model.IsErrUserNotExist(err) {
return ctx.User
return ctx.Doer
}
if err != nil {
@@ -95,8 +100,8 @@ func checkContextUser(ctx *context.Context, uid int64) *user_model.User {
ctx.Error(http.StatusForbidden)
return nil
}
if !ctx.User.IsAdmin {
canCreate, err := models.OrgFromUser(org).CanCreateOrgRepo(ctx.User.ID)
if !ctx.Doer.IsAdmin {
canCreate, err := organization.OrgFromUser(org).CanCreateOrgRepo(ctx.Doer.ID)
if err != nil {
ctx.ServerError("CanCreateOrgRepo", err)
return nil
@@ -113,13 +118,13 @@ func checkContextUser(ctx *context.Context, uid int64) *user_model.User {
func getRepoPrivate(ctx *context.Context) bool {
switch strings.ToLower(setting.Repository.DefaultPrivate) {
case setting.RepoCreatingLastUserVisibility:
return ctx.User.LastRepoVisibility
return ctx.Doer.LastRepoVisibility
case setting.RepoCreatingPrivate:
return true
case setting.RepoCreatingPublic:
return false
default:
return ctx.User.LastRepoVisibility
return ctx.Doer.LastRepoVisibility
}
}
@@ -128,10 +133,10 @@ func Create(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("new_repo")
// Give default value for template to render.
ctx.Data["Gitignores"] = models.Gitignores
ctx.Data["LabelTemplates"] = models.LabelTemplates
ctx.Data["Licenses"] = models.Licenses
ctx.Data["Readmes"] = models.Readmes
ctx.Data["Gitignores"] = repo_module.Gitignores
ctx.Data["LabelTemplates"] = repo_module.LabelTemplates
ctx.Data["Licenses"] = repo_module.Licenses
ctx.Data["Readmes"] = repo_module.Readmes
ctx.Data["readme"] = "Default"
ctx.Data["private"] = getRepoPrivate(ctx)
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
@@ -153,8 +158,8 @@ func Create(ctx *context.Context) {
}
}
ctx.Data["CanCreateRepo"] = ctx.User.CanCreateRepo()
ctx.Data["MaxCreationLimit"] = ctx.User.MaxCreationLimit()
ctx.Data["CanCreateRepo"] = ctx.Doer.CanCreateRepo()
ctx.Data["MaxCreationLimit"] = ctx.Doer.MaxCreationLimit()
ctx.HTML(http.StatusOK, tplCreate)
}
@@ -196,13 +201,13 @@ func CreatePost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.CreateRepoForm)
ctx.Data["Title"] = ctx.Tr("new_repo")
ctx.Data["Gitignores"] = models.Gitignores
ctx.Data["LabelTemplates"] = models.LabelTemplates
ctx.Data["Licenses"] = models.Licenses
ctx.Data["Readmes"] = models.Readmes
ctx.Data["Gitignores"] = repo_module.Gitignores
ctx.Data["LabelTemplates"] = repo_module.LabelTemplates
ctx.Data["Licenses"] = repo_module.Licenses
ctx.Data["Readmes"] = repo_module.Readmes
ctx.Data["CanCreateRepo"] = ctx.User.CanCreateRepo()
ctx.Data["MaxCreationLimit"] = ctx.User.MaxCreationLimit()
ctx.Data["CanCreateRepo"] = ctx.Doer.CanCreateRepo()
ctx.Data["MaxCreationLimit"] = ctx.Doer.MaxCreationLimit()
ctxUser := checkContextUser(ctx, form.UID)
if ctx.Written() {
@@ -245,14 +250,14 @@ func CreatePost(ctx *context.Context) {
return
}
repo, err = repo_service.GenerateRepository(ctx.User, ctxUser, templateRepo, opts)
repo, err = repo_service.GenerateRepository(ctx.Doer, ctxUser, templateRepo, opts)
if err == nil {
log.Trace("Repository generated [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
ctx.Redirect(repo.Link())
return
}
} else {
repo, err = repo_service.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{
repo, err = repo_service.CreateRepository(ctx.Doer, ctxUser, models.CreateRepoOptions{
Name: form.RepoName,
Description: form.Description,
Gitignores: form.Gitignores,
@@ -280,13 +285,13 @@ func Action(ctx *context.Context) {
var err error
switch ctx.Params(":action") {
case "watch":
err = repo_model.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
err = repo_model.WatchRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, true)
case "unwatch":
err = repo_model.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
err = repo_model.WatchRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, false)
case "star":
err = repo_model.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
err = repo_model.StarRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, true)
case "unstar":
err = repo_model.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
err = repo_model.StarRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, false)
case "accept_transfer":
err = acceptOrRejectRepoTransfer(ctx, true)
case "reject_transfer":
@@ -320,7 +325,7 @@ func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error {
return err
}
if !repoTransfer.CanUserAcceptTransfer(ctx.User) {
if !repoTransfer.CanUserAcceptTransfer(ctx.Doer) {
return errors.New("user does not have enough permissions")
}
@@ -353,7 +358,7 @@ func RedirectDownload(ctx *context.Context) {
)
tagNames := []string{vTag}
curRepo := ctx.Repo.Repository
releases, err := models.GetReleasesByRepoIDAndNames(db.DefaultContext, curRepo.ID, tagNames)
releases, err := models.GetReleasesByRepoIDAndNames(ctx, curRepo.ID, tagNames)
if err != nil {
if repo_model.IsErrAttachmentNotExist(err) {
ctx.Error(http.StatusNotFound)
@@ -394,7 +399,7 @@ func Download(ctx *context.Context) {
return
}
archiver, err := repo_model.GetRepoArchiver(db.DefaultContext, aReq.RepoID, aReq.Type, aReq.CommitID)
archiver, err := repo_model.GetRepoArchiver(ctx, aReq.RepoID, aReq.Type, aReq.CommitID)
if err != nil {
ctx.ServerError("models.GetRepoArchiver", err)
return
@@ -424,7 +429,7 @@ func Download(ctx *context.Context) {
return
}
times++
archiver, err = repo_model.GetRepoArchiver(db.DefaultContext, aReq.RepoID, aReq.Type, aReq.CommitID)
archiver, err = repo_model.GetRepoArchiver(ctx, aReq.RepoID, aReq.Type, aReq.CommitID)
if err != nil {
ctx.ServerError("archiver_service.StartArchive", err)
return
@@ -480,7 +485,7 @@ func InitiateDownload(ctx *context.Context) {
return
}
archiver, err := repo_model.GetRepoArchiver(db.DefaultContext, aReq.RepoID, aReq.Type, aReq.CommitID)
archiver, err := repo_model.GetRepoArchiver(ctx, aReq.RepoID, aReq.Type, aReq.CommitID)
if err != nil {
ctx.ServerError("archiver_service.StartArchive", err)
return
@@ -501,3 +506,114 @@ func InitiateDownload(ctx *context.Context) {
"complete": completed,
})
}
// SearchRepo repositories via options
func SearchRepo(ctx *context.Context) {
opts := &models.SearchRepoOptions{
ListOptions: db.ListOptions{
Page: ctx.FormInt("page"),
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
},
Actor: ctx.Doer,
Keyword: ctx.FormTrim("q"),
OwnerID: ctx.FormInt64("uid"),
PriorityOwnerID: ctx.FormInt64("priority_owner_id"),
TeamID: ctx.FormInt64("team_id"),
TopicOnly: ctx.FormBool("topic"),
Collaborate: util.OptionalBoolNone,
Private: ctx.IsSigned && (ctx.FormString("private") == "" || ctx.FormBool("private")),
Template: util.OptionalBoolNone,
StarredByID: ctx.FormInt64("starredBy"),
IncludeDescription: ctx.FormBool("includeDesc"),
}
if ctx.FormString("template") != "" {
opts.Template = util.OptionalBoolOf(ctx.FormBool("template"))
}
if ctx.FormBool("exclusive") {
opts.Collaborate = util.OptionalBoolFalse
}
mode := ctx.FormString("mode")
switch mode {
case "source":
opts.Fork = util.OptionalBoolFalse
opts.Mirror = util.OptionalBoolFalse
case "fork":
opts.Fork = util.OptionalBoolTrue
case "mirror":
opts.Mirror = util.OptionalBoolTrue
case "collaborative":
opts.Mirror = util.OptionalBoolFalse
opts.Collaborate = util.OptionalBoolTrue
case "":
default:
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid search mode: \"%s\"", mode))
return
}
if ctx.FormString("archived") != "" {
opts.Archived = util.OptionalBoolOf(ctx.FormBool("archived"))
}
if ctx.FormString("is_private") != "" {
opts.IsPrivate = util.OptionalBoolOf(ctx.FormBool("is_private"))
}
sortMode := ctx.FormString("sort")
if len(sortMode) > 0 {
sortOrder := ctx.FormString("order")
if len(sortOrder) == 0 {
sortOrder = "asc"
}
if searchModeMap, ok := context.SearchOrderByMap[sortOrder]; ok {
if orderBy, ok := searchModeMap[sortMode]; ok {
opts.OrderBy = orderBy
} else {
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid sort mode: \"%s\"", sortMode))
return
}
} else {
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid sort order: \"%s\"", sortOrder))
return
}
}
var err error
repos, count, err := models.SearchRepository(opts)
if err != nil {
ctx.JSON(http.StatusInternalServerError, api.SearchError{
OK: false,
Error: err.Error(),
})
return
}
ctx.SetTotalCountHeader(count)
// To improve performance when only the count is requested
if ctx.FormBool("count_only") {
return
}
results := make([]*api.Repository, len(repos))
for i, repo := range repos {
results[i] = &api.Repository{
ID: repo.ID,
FullName: repo.FullName(),
Fork: repo.IsFork,
Private: repo.IsPrivate,
Template: repo.IsTemplate,
Mirror: repo.IsMirror,
Stars: repo.NumStars,
HTMLURL: repo.HTMLURL(),
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
}
}
ctx.JSON(http.StatusOK, api.SearchResults{
OK: true,
Data: results,
})
}
+1 -2
View File
@@ -18,7 +18,7 @@ const tplSearch base.TplName = "repo/search"
// Search render repository search page
func Search(ctx *context.Context) {
if !setting.Indexer.RepoIndexerEnabled {
ctx.Redirect(ctx.Repo.RepoLink, 302)
ctx.Redirect(ctx.Repo.RepoLink)
return
}
language := ctx.FormTrim("l")
@@ -47,7 +47,6 @@ func Search(ctx *context.Context) {
ctx.Data["SourcePath"] = ctx.Repo.Repository.HTMLURL()
ctx.Data["SearchResults"] = searchResults
ctx.Data["SearchResultLanguages"] = searchResultLanguages
ctx.Data["RequireHighlightJS"] = true
ctx.Data["PageIsViewCode"] = true
pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
+35 -29
View File
@@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
@@ -31,7 +32,6 @@ import (
"code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/validation"
@@ -70,7 +70,7 @@ func Settings(ctx *context.Context) {
ctx.Data["SigningKeyAvailable"] = len(signing) > 0
ctx.Data["SigningSettings"] = setting.Repository.Signing
ctx.Data["CodeIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
if ctx.User.IsAdmin {
if ctx.Doer.IsAdmin {
if setting.Indexer.RepoIndexerEnabled {
status, err := repo_model.GetIndexerStatus(ctx.Repo.Repository, repo_model.RepoIndexerTypeCode)
if err != nil {
@@ -119,7 +119,7 @@ func SettingsPost(ctx *context.Context) {
ctx.Repo.GitRepo.Close()
ctx.Repo.GitRepo = nil
}
if err := repo_service.ChangeRepositoryName(ctx.User, repo, newRepoName); err != nil {
if err := repo_service.ChangeRepositoryName(ctx.Doer, repo, newRepoName); err != nil {
ctx.Data["Err_RepoName"] = true
switch {
case repo_model.IsErrRepoAlreadyExist(err):
@@ -162,7 +162,7 @@ func SettingsPost(ctx *context.Context) {
visibilityChanged := repo.IsPrivate != form.Private
// when ForcePrivate enabled, you could change public repo to private, but only admin users can change private to public
if visibilityChanged && setting.Repository.ForcePrivate && !form.Private && !ctx.User.IsAdmin {
if visibilityChanged && setting.Repository.ForcePrivate && !form.Private && !ctx.Doer.IsAdmin {
ctx.RenderWithErr(ctx.Tr("form.repository_force_private"), tplSettingsOptions, form)
return
}
@@ -194,11 +194,7 @@ func SettingsPost(ctx *context.Context) {
} else {
ctx.Repo.Mirror.EnablePrune = form.EnablePrune
ctx.Repo.Mirror.Interval = interval
if interval != 0 {
ctx.Repo.Mirror.NextUpdateUnix = timeutil.TimeStampNow().AddDuration(interval)
} else {
ctx.Repo.Mirror.NextUpdateUnix = 0
}
ctx.Repo.Mirror.ScheduleNextUpdate()
if err := repo_model.UpdateMirror(ctx.Repo.Mirror); err != nil {
ctx.Data["Err_Interval"] = true
ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
@@ -213,7 +209,7 @@ func SettingsPost(ctx *context.Context) {
address, err := forms.ParseRemoteAddr(form.MirrorAddress, form.MirrorUsername, form.MirrorPassword)
if err == nil {
err = migrations.IsMigrateURLAllowed(address, ctx.User)
err = migrations.IsMigrateURLAllowed(address, ctx.Doer)
}
if err != nil {
ctx.Data["Err_MirrorAddress"] = true
@@ -235,7 +231,7 @@ func SettingsPost(ctx *context.Context) {
ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_lfs_endpoint"), tplSettingsOptions, &form)
return
}
err = migrations.IsMigrateURLAllowed(ep.String(), ctx.User)
err = migrations.IsMigrateURLAllowed(ep.String(), ctx.Doer)
if err != nil {
ctx.Data["Err_LFSEndpoint"] = true
handleSettingRemoteAddrError(ctx, err, form)
@@ -329,7 +325,7 @@ func SettingsPost(ctx *context.Context) {
address, err := forms.ParseRemoteAddr(form.PushMirrorAddress, form.PushMirrorUsername, form.PushMirrorPassword)
if err == nil {
err = migrations.IsMigrateURLAllowed(address, ctx.User)
err = migrations.IsMigrateURLAllowed(address, ctx.Doer)
}
if err != nil {
ctx.Data["Err_PushMirrorAddress"] = true
@@ -460,6 +456,15 @@ func SettingsPost(ctx *context.Context) {
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeProjects)
}
if form.EnablePackages && !unit_model.TypeProjects.UnitGlobalDisabled() {
units = append(units, repo_model.RepoUnit{
RepoID: repo.ID,
Type: unit_model.TypePackages,
})
} else if !unit_model.TypePackages.UnitGlobalDisabled() {
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePackages)
}
if form.EnablePulls && !unit_model.TypePullRequests.UnitGlobalDisabled() {
units = append(units, repo_model.RepoUnit{
RepoID: repo.ID,
@@ -516,7 +521,7 @@ func SettingsPost(ctx *context.Context) {
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
case "admin":
if !ctx.User.IsAdmin {
if !ctx.Doer.IsAdmin {
ctx.Error(http.StatusForbidden)
return
}
@@ -536,7 +541,7 @@ func SettingsPost(ctx *context.Context) {
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
case "admin_index":
if !ctx.User.IsAdmin {
if !ctx.Doer.IsAdmin {
ctx.Error(http.StatusForbidden)
return
}
@@ -595,7 +600,7 @@ func SettingsPost(ctx *context.Context) {
ctx.Error(http.StatusNotFound)
return
}
if err := repo.GetOwner(db.DefaultContext); err != nil {
if err := repo.GetOwner(ctx); err != nil {
ctx.ServerError("Convert Fork", err)
return
}
@@ -648,7 +653,7 @@ func SettingsPost(ctx *context.Context) {
}
if newOwner.Type == user_model.UserTypeOrganization {
if !ctx.User.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !models.OrgFromUser(newOwner).HasMemberWithUserID(ctx.User.ID) {
if !ctx.Doer.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx.Doer.ID) {
// The user shouldn't know about this organization
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
return
@@ -661,7 +666,7 @@ func SettingsPost(ctx *context.Context) {
ctx.Repo.GitRepo = nil
}
if err := repo_service.StartRepositoryTransfer(ctx.User, newOwner, repo, nil); err != nil {
if err := repo_service.StartRepositoryTransfer(ctx.Doer, newOwner, repo, nil); err != nil {
if repo_model.IsErrRepoAlreadyExist(err) {
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
} else if models.IsErrRepoTransferInProgress(err) {
@@ -724,7 +729,7 @@ func SettingsPost(ctx *context.Context) {
ctx.Repo.GitRepo.Close()
}
if err := repo_service.DeleteRepository(ctx, ctx.User, ctx.Repo.Repository, true); err != nil {
if err := repo_service.DeleteRepository(ctx, ctx.Doer, ctx.Repo.Repository, true); err != nil {
ctx.ServerError("DeleteRepository", err)
return
}
@@ -835,7 +840,7 @@ func Collaboration(ctx *context.Context) {
}
ctx.Data["Collaborators"] = users
teams, err := models.GetRepoTeams(ctx.Repo.Repository)
teams, err := organization.GetRepoTeams(ctx.Repo.Repository)
if err != nil {
ctx.ServerError("GetRepoTeams", err)
return
@@ -894,7 +899,7 @@ func CollaborationPost(ctx *context.Context) {
}
if setting.Service.EnableNotifyMail {
mailer.SendCollaboratorMail(u, ctx.User, ctx.Repo.Repository)
mailer.SendCollaboratorMail(u, ctx.Doer, ctx.Repo.Repository)
}
ctx.Flash.Success(ctx.Tr("repo.settings.add_collaborator_success"))
@@ -938,9 +943,9 @@ func AddTeamPost(ctx *context.Context) {
return
}
team, err := models.OrgFromUser(ctx.Repo.Owner).GetTeam(name)
team, err := organization.OrgFromUser(ctx.Repo.Owner).GetTeam(name)
if err != nil {
if models.IsErrTeamNotExist(err) {
if organization.IsErrTeamNotExist(err) {
ctx.Flash.Error(ctx.Tr("form.team_not_exist"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
} else {
@@ -955,13 +960,13 @@ func AddTeamPost(ctx *context.Context) {
return
}
if models.HasTeamRepo(ctx.Repo.Repository.OwnerID, team.ID, ctx.Repo.Repository.ID) {
if organization.HasTeamRepo(ctx, ctx.Repo.Repository.OwnerID, team.ID, ctx.Repo.Repository.ID) {
ctx.Flash.Error(ctx.Tr("repo.settings.add_team_duplicate"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
return
}
if err = team.AddRepository(ctx.Repo.Repository); err != nil {
if err = models.AddRepository(team, ctx.Repo.Repository); err != nil {
ctx.ServerError("team.AddRepository", err)
return
}
@@ -978,13 +983,13 @@ func DeleteTeam(ctx *context.Context) {
return
}
team, err := models.GetTeamByID(ctx.FormInt64("id"))
team, err := organization.GetTeamByID(ctx.FormInt64("id"))
if err != nil {
ctx.ServerError("GetTeamByID", err)
return
}
if err = team.RemoveRepository(ctx.Repo.Repository.ID); err != nil {
if err = models.RemoveRepository(team, ctx.Repo.Repository.ID); err != nil {
ctx.ServerError("team.RemoveRepositorys", err)
return
}
@@ -1055,7 +1060,7 @@ func DeployKeys(ctx *context.Context) {
ctx.Data["PageIsSettingsKeys"] = true
ctx.Data["DisableSSH"] = setting.SSH.Disabled
keys, err := asymkey_model.ListDeployKeys(db.DefaultContext, &asymkey_model.ListDeployKeysOptions{RepoID: ctx.Repo.Repository.ID})
keys, err := asymkey_model.ListDeployKeys(ctx, &asymkey_model.ListDeployKeysOptions{RepoID: ctx.Repo.Repository.ID})
if err != nil {
ctx.ServerError("ListDeployKeys", err)
return
@@ -1070,8 +1075,9 @@ func DeployKeysPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.AddKeyForm)
ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys")
ctx.Data["PageIsSettingsKeys"] = true
ctx.Data["DisableSSH"] = setting.SSH.Disabled
keys, err := asymkey_model.ListDeployKeys(db.DefaultContext, &asymkey_model.ListDeployKeysOptions{RepoID: ctx.Repo.Repository.ID})
keys, err := asymkey_model.ListDeployKeys(ctx, &asymkey_model.ListDeployKeysOptions{RepoID: ctx.Repo.Repository.ID})
if err != nil {
ctx.ServerError("ListDeployKeys", err)
return
@@ -1127,7 +1133,7 @@ func DeployKeysPost(ctx *context.Context) {
// DeleteDeployKey response for deleting a deploy key
func DeleteDeployKey(ctx *context.Context) {
if err := asymkey_service.DeleteDeployKey(ctx.User, ctx.FormInt64("id")); err != nil {
if err := asymkey_service.DeleteDeployKey(ctx.Doer, ctx.FormInt64("id")); err != nil {
ctx.Flash.Error("DeleteDeployKey: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("repo.settings.deploy_key_deletion_success"))
+5 -4
View File
@@ -11,6 +11,7 @@ import (
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/base"
@@ -73,7 +74,7 @@ func ProtectedBranchPost(ctx *context.Context) {
branch := ctx.FormString("branch")
if !ctx.Repo.GitRepo.IsBranchExist(branch) {
ctx.Status(404)
ctx.Status(http.StatusNotFound)
return
} else if repo.DefaultBranch != branch {
repo.DefaultBranch = branch
@@ -158,7 +159,7 @@ func SettingsProtectedBranch(c *context.Context) {
}
if c.Repo.Owner.IsOrganization() {
teams, err := models.OrgFromUser(c.Repo.Owner).TeamsWithAccessToRepo(c.Repo.Repository.ID, perm.AccessModeRead)
teams, err := organization.OrgFromUser(c.Repo.Owner).TeamsWithAccessToRepo(c.Repo.Repository.ID, perm.AccessModeRead)
if err != nil {
c.ServerError("Repo.Owner.TeamsWithAccessToRepo", err)
return
@@ -260,7 +261,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
protectBranch.UnprotectedFilePatterns = f.UnprotectedFilePatterns
protectBranch.BlockOnOutdatedBranch = f.BlockOnOutdatedBranch
err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, models.WhitelistOptions{
err = models.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, models.WhitelistOptions{
UserIDs: whitelistUsers,
TeamIDs: whitelistTeams,
MergeUserIDs: mergeWhitelistUsers,
@@ -305,7 +306,7 @@ func RenameBranchPost(ctx *context.Context) {
return
}
msg, err := repository.RenameBranch(ctx.Repo.Repository, ctx.User, ctx.Repo.GitRepo, form.From, form.To)
msg, err := repository.RenameBranch(ctx.Repo.Repository, ctx.Doer, ctx.Repo.GitRepo, form.From, form.To)
if err != nil {
ctx.ServerError("RenameBranch", err)
return
+20 -19
View File
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
@@ -60,7 +61,7 @@ func TestAddReadOnlyDeployKey(t *testing.T) {
}
web.SetForm(ctx, &addKeyForm)
DeployKeysPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
Name: addKeyForm.Title,
@@ -90,7 +91,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) {
}
web.SetForm(ctx, &addKeyForm)
DeployKeysPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
Name: addKeyForm.Title,
@@ -127,7 +128,7 @@ func TestCollaborationPost(t *testing.T) {
CollaborationPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
exists, err := models.IsCollaborator(re.ID, 4)
assert.NoError(t, err)
@@ -153,7 +154,7 @@ func TestCollaborationPost_InactiveUser(t *testing.T) {
CollaborationPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -185,7 +186,7 @@ func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) {
CollaborationPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
exists, err := models.IsCollaborator(re.ID, 4)
assert.NoError(t, err)
@@ -194,7 +195,7 @@ func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) {
// Try adding the same collaborator again
CollaborationPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -216,7 +217,7 @@ func TestCollaborationPost_NonExistentUser(t *testing.T) {
CollaborationPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -231,7 +232,7 @@ func TestAddTeamPost(t *testing.T) {
Type: user_model.UserTypeOrganization,
}
team := &models.Team{
team := &organization.Team{
ID: 11,
OrgID: 26,
}
@@ -255,8 +256,8 @@ func TestAddTeamPost(t *testing.T) {
AddTeamPost(ctx)
assert.True(t, team.HasRepository(re.ID))
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.True(t, models.HasRepository(team, re.ID))
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assert.Empty(t, ctx.Flash.ErrorMsg)
}
@@ -271,7 +272,7 @@ func TestAddTeamPost_NotAllowed(t *testing.T) {
Type: user_model.UserTypeOrganization,
}
team := &models.Team{
team := &organization.Team{
ID: 11,
OrgID: 26,
}
@@ -295,8 +296,8 @@ func TestAddTeamPost_NotAllowed(t *testing.T) {
AddTeamPost(ctx)
assert.False(t, team.HasRepository(re.ID))
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.False(t, models.HasRepository(team, re.ID))
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -311,7 +312,7 @@ func TestAddTeamPost_AddTeamTwice(t *testing.T) {
Type: user_model.UserTypeOrganization,
}
team := &models.Team{
team := &organization.Team{
ID: 11,
OrgID: 26,
}
@@ -336,8 +337,8 @@ func TestAddTeamPost_AddTeamTwice(t *testing.T) {
AddTeamPost(ctx)
AddTeamPost(ctx)
assert.True(t, team.HasRepository(re.ID))
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.True(t, models.HasRepository(team, re.ID))
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -370,7 +371,7 @@ func TestAddTeamPost_NonExistentTeam(t *testing.T) {
ctx.Repo = repo
AddTeamPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -385,7 +386,7 @@ func TestDeleteTeam(t *testing.T) {
Type: user_model.UserTypeOrganization,
}
team := &models.Team{
team := &organization.Team{
ID: 2,
OrgID: 3,
}
@@ -409,5 +410,5 @@ func TestDeleteTeam(t *testing.T) {
DeleteTeam(ctx)
assert.False(t, team.HasRepository(re.ID))
assert.False(t, models.HasRepository(team, re.ID))
}
+2 -1
View File
@@ -10,6 +10,7 @@ import (
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
@@ -150,7 +151,7 @@ func setTagsContext(ctx *context.Context) error {
ctx.Data["Users"] = users
if ctx.Repo.Owner.IsOrganization() {
teams, err := models.OrgFromUser(ctx.Repo.Owner).TeamsWithAccessToRepo(ctx.Repo.Repository.ID, perm.AccessModeRead)
teams, err := organization.OrgFromUser(ctx.Repo.Owner).TeamsWithAccessToRepo(ctx.Repo.Repository.ID, perm.AccessModeRead)
if err != nil {
ctx.ServerError("Repo.Owner.TeamsWithAccessToRepo", err)
return err
+1 -1
View File
@@ -15,7 +15,7 @@ import (
// TopicsPost response for creating repository
func TopicsPost(ctx *context.Context) {
if ctx.User == nil {
if ctx.Doer == nil {
ctx.JSON(http.StatusForbidden, map[string]interface{}{
"message": "Only owners could change the topics.",
})
+151 -121
View File
@@ -38,6 +38,7 @@ import (
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/web/feed"
)
const (
@@ -145,6 +146,21 @@ func renderDirectory(ctx *context.Context, treeLink string) {
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
}
// Check permission to add or upload new file.
if ctx.Repo.CanWrite(unit_model.TypeCode) && ctx.Repo.IsViewBranch {
ctx.Data["CanAddFile"] = !ctx.Repo.Repository.IsArchived
ctx.Data["CanUploadFile"] = setting.Repository.Upload.Enabled && !ctx.Repo.Repository.IsArchived
}
readmeFile, readmeTreelink := findReadmeFile(ctx, entries, treeLink)
if ctx.Written() || readmeFile == nil {
return
}
renderReadmeFile(ctx, readmeFile, readmeTreelink)
}
func findReadmeFile(ctx *context.Context, entries git.Entries, treeLink string) (*namedBlob, string) {
// 3 for the extensions in exts[] in order
// the last one is for a readme that doesn't
// strictly match an extension
@@ -182,7 +198,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
target, err = entry.FollowLinks()
if err != nil && !git.IsErrBadLink(err) {
ctx.ServerError("FollowLinks", err)
return
return nil, ""
}
}
log.Debug("%t", target == nil)
@@ -204,7 +220,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
entry, err = entry.FollowLinks()
if err != nil && !git.IsErrBadLink(err) {
ctx.ServerError("FollowLinks", err)
return
return nil, ""
}
}
if entry != nil && (entry.IsExecutable() || entry.IsRegular()) {
@@ -235,7 +251,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
readmeFile, err = getReadmeFileFromPath(ctx.Repo.Commit, entry.GetSubJumpablePathName())
if err != nil {
ctx.ServerError("getReadmeFileFromPath", err)
return
return nil, ""
}
if readmeFile != nil {
readmeFile.name = entry.Name() + "/" + readmeFile.name
@@ -244,129 +260,127 @@ func renderDirectory(ctx *context.Context, treeLink string) {
}
}
}
return readmeFile, readmeTreelink
}
if readmeFile != nil {
ctx.Data["RawFileLink"] = ""
ctx.Data["ReadmeInList"] = true
ctx.Data["ReadmeExist"] = true
ctx.Data["FileIsSymlink"] = readmeFile.isSymlink
func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelink string) {
ctx.Data["RawFileLink"] = ""
ctx.Data["ReadmeInList"] = true
ctx.Data["ReadmeExist"] = true
ctx.Data["FileIsSymlink"] = readmeFile.isSymlink
dataRc, err := readmeFile.blob.DataAsync()
if err != nil {
ctx.ServerError("Data", err)
return
}
defer dataRc.Close()
dataRc, err := readmeFile.blob.DataAsync()
if err != nil {
ctx.ServerError("Data", err)
return
}
defer dataRc.Close()
buf := make([]byte, 1024)
n, _ := util.ReadAtMost(dataRc, buf)
buf = buf[:n]
buf := make([]byte, 1024)
n, _ := util.ReadAtMost(dataRc, buf)
buf = buf[:n]
st := typesniffer.DetectContentType(buf)
isTextFile := st.IsText()
st := typesniffer.DetectContentType(buf)
isTextFile := st.IsText()
ctx.Data["FileIsText"] = isTextFile
ctx.Data["FileName"] = readmeFile.name
fileSize := int64(0)
isLFSFile := false
ctx.Data["IsLFSFile"] = false
ctx.Data["FileIsText"] = isTextFile
ctx.Data["FileName"] = readmeFile.name
fileSize := int64(0)
isLFSFile := false
ctx.Data["IsLFSFile"] = false
// FIXME: what happens when README file is an image?
if isTextFile && setting.LFS.StartServer {
pointer, _ := lfs.ReadPointerFromBuffer(buf)
if pointer.IsValid() {
meta, err := models.GetLFSMetaObjectByOid(ctx.Repo.Repository.ID, pointer.Oid)
if err != nil && err != models.ErrLFSObjectNotExist {
ctx.ServerError("GetLFSMetaObject", err)
// FIXME: what happens when README file is an image?
if isTextFile && setting.LFS.StartServer {
pointer, _ := lfs.ReadPointerFromBuffer(buf)
if pointer.IsValid() {
meta, err := models.GetLFSMetaObjectByOid(ctx.Repo.Repository.ID, pointer.Oid)
if err != nil && err != models.ErrLFSObjectNotExist {
ctx.ServerError("GetLFSMetaObject", err)
return
}
if meta != nil {
ctx.Data["IsLFSFile"] = true
isLFSFile = true
// OK read the lfs object
var err error
dataRc, err = lfs.ReadMetaObject(pointer)
if err != nil {
ctx.ServerError("ReadMetaObject", err)
return
}
if meta != nil {
ctx.Data["IsLFSFile"] = true
isLFSFile = true
defer dataRc.Close()
// OK read the lfs object
var err error
dataRc, err = lfs.ReadMetaObject(pointer)
if err != nil {
ctx.ServerError("ReadMetaObject", err)
return
}
defer dataRc.Close()
buf = make([]byte, 1024)
n, err = util.ReadAtMost(dataRc, buf)
if err != nil {
ctx.ServerError("Data", err)
return
}
buf = buf[:n]
st = typesniffer.DetectContentType(buf)
isTextFile = st.IsText()
ctx.Data["IsTextFile"] = isTextFile
fileSize = meta.Size
ctx.Data["FileSize"] = meta.Size
filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(readmeFile.name))
ctx.Data["RawFileLink"] = fmt.Sprintf("%s.git/info/lfs/objects/%s/%s", ctx.Repo.Repository.HTMLURL(), url.PathEscape(meta.Oid), url.PathEscape(filenameBase64))
buf = make([]byte, 1024)
n, err = util.ReadAtMost(dataRc, buf)
if err != nil {
ctx.ServerError("Data", err)
return
}
}
}
buf = buf[:n]
if !isLFSFile {
fileSize = readmeFile.blob.Size()
}
st = typesniffer.DetectContentType(buf)
isTextFile = st.IsText()
ctx.Data["IsTextFile"] = isTextFile
if isTextFile {
if fileSize >= setting.UI.MaxDisplayFileSize {
// Pretend that this is a normal text file to display 'This file is too large to be shown'
ctx.Data["IsFileTooLarge"] = true
ctx.Data["IsTextFile"] = true
ctx.Data["FileSize"] = fileSize
} else {
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
if markupType := markup.Type(readmeFile.name); markupType != "" {
ctx.Data["IsMarkup"] = true
ctx.Data["MarkupType"] = string(markupType)
var result strings.Builder
err := markup.Render(&markup.RenderContext{
Ctx: ctx,
Filename: readmeFile.name,
URLPrefix: readmeTreelink,
Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
GitRepo: ctx.Repo.GitRepo,
}, rd, &result)
if err != nil {
log.Error("Render failed: %v then fallback", err)
buf := &bytes.Buffer{}
ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf)
ctx.Data["FileContent"] = strings.ReplaceAll(
gotemplate.HTMLEscapeString(buf.String()), "\n", `<br>`,
)
} else {
ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlString(result.String())
}
} else {
ctx.Data["IsRenderedHTML"] = true
buf := &bytes.Buffer{}
ctx.Data["EscapeStatus"], err = charset.EscapeControlReader(rd, buf)
if err != nil {
log.Error("Read failed: %v", err)
}
ctx.Data["FileContent"] = strings.ReplaceAll(
gotemplate.HTMLEscapeString(buf.String()), "\n", `<br>`,
)
}
fileSize = meta.Size
ctx.Data["FileSize"] = meta.Size
filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(readmeFile.name))
ctx.Data["RawFileLink"] = fmt.Sprintf("%s.git/info/lfs/objects/%s/%s", ctx.Repo.Repository.HTMLURL(), url.PathEscape(meta.Oid), url.PathEscape(filenameBase64))
}
}
}
// Check permission to add or upload new file.
if ctx.Repo.CanWrite(unit_model.TypeCode) && ctx.Repo.IsViewBranch {
ctx.Data["CanAddFile"] = !ctx.Repo.Repository.IsArchived
ctx.Data["CanUploadFile"] = setting.Repository.Upload.Enabled && !ctx.Repo.Repository.IsArchived
if !isTextFile {
return
}
if !isLFSFile {
fileSize = readmeFile.blob.Size()
}
if fileSize >= setting.UI.MaxDisplayFileSize {
// Pretend that this is a normal text file to display 'This file is too large to be shown'
ctx.Data["IsFileTooLarge"] = true
ctx.Data["IsTextFile"] = true
ctx.Data["FileSize"] = fileSize
return
}
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
if markupType := markup.Type(readmeFile.name); markupType != "" {
ctx.Data["IsMarkup"] = true
ctx.Data["MarkupType"] = string(markupType)
var result strings.Builder
err := markup.Render(&markup.RenderContext{
Ctx: ctx,
Filename: readmeFile.name,
URLPrefix: readmeTreelink,
Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
GitRepo: ctx.Repo.GitRepo,
}, rd, &result)
if err != nil {
log.Error("Render failed: %v then fallback", err)
buf := &bytes.Buffer{}
ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf)
ctx.Data["FileContent"] = strings.ReplaceAll(
gotemplate.HTMLEscapeString(buf.String()), "\n", `<br>`,
)
} else {
ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlString(result.String())
}
} else {
ctx.Data["IsRenderedHTML"] = true
buf := &bytes.Buffer{}
ctx.Data["EscapeStatus"], err = charset.EscapeControlReader(rd, buf)
if err != nil {
log.Error("Read failed: %v", err)
}
ctx.Data["FileContent"] = strings.ReplaceAll(
gotemplate.HTMLEscapeString(buf.String()), "\n", `<br>`,
)
}
}
@@ -488,9 +502,17 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
}
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
shouldRenderSource := ctx.FormString("display") == "source"
readmeExist := markup.IsReadmeFile(blob.Name())
ctx.Data["ReadmeExist"] = readmeExist
if markupType := markup.Type(blob.Name()); markupType != "" {
markupType := markup.Type(blob.Name())
if markupType != "" {
ctx.Data["HasSourceRenderedToggle"] = true
}
if markupType != "" && !shouldRenderSource {
ctx.Data["IsMarkup"] = true
ctx.Data["MarkupType"] = markupType
var result strings.Builder
@@ -506,7 +528,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
return
}
ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlString(result.String())
} else if readmeExist {
} else if readmeExist && !shouldRenderSource {
buf := &bytes.Buffer{}
ctx.Data["IsRenderedHTML"] = true
@@ -557,8 +579,8 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
ctx.Data["LineEscapeStatus"] = statuses
}
if !isLFSFile {
if ctx.Repo.CanEnableEditor() {
if lfsLock != nil && lfsLock.OwnerID != ctx.User.ID {
if ctx.Repo.CanEnableEditor(ctx.Doer) {
if lfsLock != nil && lfsLock.OwnerID != ctx.Doer.ID {
ctx.Data["CanEditFile"] = false
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.this_file_locked")
} else {
@@ -567,7 +589,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
}
} else if !ctx.Repo.IsViewBranch {
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.must_be_on_a_branch")
} else if !ctx.Repo.CanWrite(unit_model.TypeCode) {
} else if !ctx.Repo.CanWriteToBranch(ctx.Doer, ctx.Repo.BranchName) {
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.fork_before_edit")
}
}
@@ -607,8 +629,8 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
}
}
if ctx.Repo.CanEnableEditor() {
if lfsLock != nil && lfsLock.OwnerID != ctx.User.ID {
if ctx.Repo.CanEnableEditor(ctx.Doer) {
if lfsLock != nil && lfsLock.OwnerID != ctx.Doer.ID {
ctx.Data["CanDeleteFile"] = false
ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.this_file_locked")
} else {
@@ -617,7 +639,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
}
} else if !ctx.Repo.IsViewBranch {
ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.must_be_on_a_branch")
} else if !ctx.Repo.CanWrite(unit_model.TypeCode) {
} else if !ctx.Repo.CanWriteToBranch(ctx.Doer, ctx.Repo.BranchName) {
ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.must_have_write_access")
}
}
@@ -662,7 +684,7 @@ func checkHomeCodeViewable(ctx *context.Context) {
if ctx.IsSigned {
// Set repo notification-status read if unread
if err := models.SetRepoReadBy(ctx.Repo.Repository.ID, ctx.User.ID); err != nil {
if err := models.SetRepoReadBy(ctx.Repo.Repository.ID, ctx.Doer.ID); err != nil {
ctx.ServerError("ReadBy", err)
return
}
@@ -691,6 +713,14 @@ func checkHomeCodeViewable(ctx *context.Context) {
// Home render repository home page
func Home(ctx *context.Context) {
isFeed, _, showFeedType := feed.GetFeedType(ctx.Params(":reponame"), ctx.Req)
if isFeed {
feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType)
return
}
ctx.Data["FeedURL"] = ctx.Repo.Repository.HTMLURL()
checkHomeCodeViewable(ctx)
if ctx.Written() {
return
@@ -875,7 +905,7 @@ func renderCode(ctx *context.Context) {
ctx.ServerError("UpdateRepositoryCols", err)
return
}
if err = models.UpdateRepoSize(db.DefaultContext, ctx.Repo.Repository); err != nil {
if err = models.UpdateRepoSize(ctx, ctx.Repo.Repository); err != nil {
ctx.ServerError("UpdateRepoSize", err)
return
}
@@ -1008,7 +1038,7 @@ func Forks(ctx *context.Context) {
}
for _, fork := range forks {
if err = fork.GetOwner(db.DefaultContext); err != nil {
if err = fork.GetOwner(ctx); err != nil {
ctx.ServerError("GetOwner", err)
return
}
+17 -20
View File
@@ -13,7 +13,6 @@ import (
"path"
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
@@ -85,7 +84,7 @@ func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) {
}, nil
}
if ctx.User.IsAdmin {
if ctx.Doer.IsAdmin {
// Are we looking at default webhooks?
if ctx.Params(":configType") == "default-hooks" {
return &orgRepoCtx{
@@ -148,7 +147,6 @@ func WebhooksNew(ctx *context.Context) {
if hookType == "discord" {
ctx.Data["DiscordHook"] = map[string]interface{}{
"Username": "Gitea",
"IconURL": setting.AppURL + "img/favicon.png",
}
}
ctx.Data["BaseLink"] = orCtx.LinkNew
@@ -181,6 +179,7 @@ func ParseHookEvent(form forms.WebhookForm) *webhook.HookEvent {
PullRequestReview: form.PullRequestReview,
PullRequestSync: form.PullRequestSync,
Repository: form.Repository,
Package: form.Package,
},
BranchFilter: form.BranchFilter,
}
@@ -227,7 +226,7 @@ func GiteaHooksNewPost(ctx *context.Context) {
if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err)
return
} else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil {
} else if err := webhook.CreateWebhook(ctx, w); err != nil {
ctx.ServerError("CreateWebhook", err)
return
}
@@ -281,7 +280,7 @@ func newGogsWebhookPost(ctx *context.Context, form forms.NewGogshookForm, kind w
if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err)
return
} else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil {
} else if err := webhook.CreateWebhook(ctx, w); err != nil {
ctx.ServerError("CreateWebhook", err)
return
}
@@ -333,7 +332,7 @@ func DiscordHooksNewPost(ctx *context.Context) {
if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err)
return
} else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil {
} else if err := webhook.CreateWebhook(ctx, w); err != nil {
ctx.ServerError("CreateWebhook", err)
return
}
@@ -376,7 +375,7 @@ func DingtalkHooksNewPost(ctx *context.Context) {
if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err)
return
} else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil {
} else if err := webhook.CreateWebhook(ctx, w); err != nil {
ctx.ServerError("CreateWebhook", err)
return
}
@@ -428,7 +427,7 @@ func TelegramHooksNewPost(ctx *context.Context) {
if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err)
return
} else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil {
} else if err := webhook.CreateWebhook(ctx, w); err != nil {
ctx.ServerError("CreateWebhook", err)
return
}
@@ -483,7 +482,7 @@ func MatrixHooksNewPost(ctx *context.Context) {
if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err)
return
} else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil {
} else if err := webhook.CreateWebhook(ctx, w); err != nil {
ctx.ServerError("CreateWebhook", err)
return
}
@@ -526,7 +525,7 @@ func MSTeamsHooksNewPost(ctx *context.Context) {
if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err)
return
} else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil {
} else if err := webhook.CreateWebhook(ctx, w); err != nil {
ctx.ServerError("CreateWebhook", err)
return
}
@@ -586,7 +585,7 @@ func SlackHooksNewPost(ctx *context.Context) {
if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err)
return
} else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil {
} else if err := webhook.CreateWebhook(ctx, w); err != nil {
ctx.ServerError("CreateWebhook", err)
return
}
@@ -629,7 +628,7 @@ func FeishuHooksNewPost(ctx *context.Context) {
if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err)
return
} else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil {
} else if err := webhook.CreateWebhook(ctx, w); err != nil {
ctx.ServerError("CreateWebhook", err)
return
}
@@ -673,7 +672,7 @@ func WechatworkHooksNewPost(ctx *context.Context) {
if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err)
return
} else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil {
} else if err := webhook.CreateWebhook(ctx, w); err != nil {
ctx.ServerError("CreateWebhook", err)
return
}
@@ -726,7 +725,7 @@ func PackagistHooksNewPost(ctx *context.Context) {
if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err)
return
} else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil {
} else if err := webhook.CreateWebhook(ctx, w); err != nil {
ctx.ServerError("CreateWebhook", err)
return
}
@@ -736,8 +735,6 @@ func PackagistHooksNewPost(ctx *context.Context) {
}
func checkWebhook(ctx *context.Context) (*orgRepoCtx, *webhook.Webhook) {
ctx.Data["RequireHighlightJS"] = true
orCtx, err := getOrgRepoCtx(ctx)
if err != nil {
ctx.ServerError("getOrgRepoCtx", err)
@@ -1242,7 +1239,7 @@ func TestWebhook(ctx *context.Context) {
w, err := webhook.GetWebhookByRepoID(ctx.Repo.Repository.ID, hookID)
if err != nil {
ctx.Flash.Error("GetWebhookByID: " + err.Error())
ctx.Status(500)
ctx.Status(http.StatusInternalServerError)
return
}
@@ -1258,7 +1255,7 @@ func TestWebhook(ctx *context.Context) {
}
}
apiUser := convert.ToUserWithAccessMode(ctx.User, perm.AccessModeNone)
apiUser := convert.ToUserWithAccessMode(ctx.Doer, perm.AccessModeNone)
apiCommit := &api.PayloadCommit{
ID: commit.ID.String(),
@@ -1286,10 +1283,10 @@ func TestWebhook(ctx *context.Context) {
}
if err := webhook_service.PrepareWebhook(w, ctx.Repo.Repository, webhook.HookEventPush, p); err != nil {
ctx.Flash.Error("PrepareWebhook: " + err.Error())
ctx.Status(500)
ctx.Status(http.StatusInternalServerError)
} else {
ctx.Flash.Info(ctx.Tr("repo.settings.webhook.delivery.success"))
ctx.Status(200)
ctx.Status(http.StatusOK)
}
}
+54 -42
View File
@@ -13,6 +13,7 @@ import (
"net/url"
"path/filepath"
"strings"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/unit"
@@ -47,7 +48,7 @@ func MustEnableWiki(ctx *context.Context) {
if log.IsTrace() {
log.Trace("Permission Denied: User %-v cannot read %-v or %-v of repo %-v\n"+
"User in repo has Permissions: %-+v",
ctx.User,
ctx.Doer,
unit.TypeWiki,
unit.TypeExternalWiki,
ctx.Repo.Repository,
@@ -90,7 +91,7 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error)
}
func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) {
wikiRepo, err := git.OpenRepositoryCtx(ctx, ctx.Repo.Repository.WikiPath())
wikiRepo, err := git.OpenRepository(ctx, ctx.Repo.Repository.WikiPath())
if err != nil {
ctx.ServerError("OpenRepository", err)
return nil, nil, err
@@ -189,7 +190,9 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
ctx.Data["old_title"] = pageName
ctx.Data["Title"] = pageName
ctx.Data["title"] = pageName
ctx.Data["RequireHighlightJS"] = true
isSideBar := pageName == "_Sidebar"
isFooter := pageName == "_Footer"
// lookup filename in wiki - get filecontent, gitTree entry , real filename
data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName)
@@ -203,20 +206,30 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
return nil, nil
}
sidebarContent, _, _, _ := wikiContentsByName(ctx, commit, "_Sidebar")
if ctx.Written() {
if wikiRepo != nil {
wikiRepo.Close()
var sidebarContent []byte
if !isSideBar {
sidebarContent, _, _, _ = wikiContentsByName(ctx, commit, "_Sidebar")
if ctx.Written() {
if wikiRepo != nil {
wikiRepo.Close()
}
return nil, nil
}
return nil, nil
} else {
sidebarContent = data
}
footerContent, _, _, _ := wikiContentsByName(ctx, commit, "_Footer")
if ctx.Written() {
if wikiRepo != nil {
wikiRepo.Close()
var footerContent []byte
if !isFooter {
footerContent, _, _, _ = wikiContentsByName(ctx, commit, "_Footer")
if ctx.Written() {
if wikiRepo != nil {
wikiRepo.Close()
}
return nil, nil
}
return nil, nil
} else {
footerContent = data
}
rctx := &markup.RenderContext{
@@ -237,27 +250,35 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
ctx.Data["EscapeStatus"], ctx.Data["content"] = charset.EscapeControlString(buf.String())
buf.Reset()
if err := markdown.Render(rctx, bytes.NewReader(sidebarContent), &buf); err != nil {
if wikiRepo != nil {
wikiRepo.Close()
if !isSideBar {
buf.Reset()
if err := markdown.Render(rctx, bytes.NewReader(sidebarContent), &buf); err != nil {
if wikiRepo != nil {
wikiRepo.Close()
}
ctx.ServerError("Render", err)
return nil, nil
}
ctx.ServerError("Render", err)
return nil, nil
ctx.Data["sidebarPresent"] = sidebarContent != nil
ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"] = charset.EscapeControlString(buf.String())
} else {
ctx.Data["sidebarPresent"] = false
}
ctx.Data["sidebarPresent"] = sidebarContent != nil
ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"] = charset.EscapeControlString(buf.String())
buf.Reset()
if err := markdown.Render(rctx, bytes.NewReader(footerContent), &buf); err != nil {
if wikiRepo != nil {
wikiRepo.Close()
if !isFooter {
buf.Reset()
if err := markdown.Render(rctx, bytes.NewReader(footerContent), &buf); err != nil {
if wikiRepo != nil {
wikiRepo.Close()
}
ctx.ServerError("Render", err)
return nil, nil
}
ctx.ServerError("Render", err)
return nil, nil
ctx.Data["footerPresent"] = footerContent != nil
ctx.Data["footerEscapeStatus"], ctx.Data["footerContent"] = charset.EscapeControlString(buf.String())
} else {
ctx.Data["footerPresent"] = false
}
ctx.Data["footerPresent"] = footerContent != nil
ctx.Data["footerEscapeStatus"], ctx.Data["footerContent"] = charset.EscapeControlString(buf.String())
// get commit count - wiki revisions
commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename)
@@ -287,7 +308,6 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
ctx.Data["old_title"] = pageName
ctx.Data["Title"] = pageName
ctx.Data["title"] = pageName
ctx.Data["RequireHighlightJS"] = true
ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
@@ -363,7 +383,6 @@ func renderEditPage(ctx *context.Context) {
ctx.Data["old_title"] = pageName
ctx.Data["Title"] = pageName
ctx.Data["title"] = pageName
ctx.Data["RequireHighlightJS"] = true
// lookup filename in wiki - get filecontent, gitTree entry , real filename
data, entry, _, noEntry := wikiContentsByName(ctx, commit, pageName)
@@ -409,7 +428,6 @@ func WikiPost(ctx *context.Context) {
// Wiki renders single wiki page
func Wiki(ctx *context.Context) {
ctx.Data["PageIsWiki"] = true
ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived
switch ctx.FormString("action") {
@@ -474,7 +492,6 @@ func Wiki(ctx *context.Context) {
// WikiRevision renders file revision list of wiki page
func WikiRevision(ctx *context.Context) {
ctx.Data["PageIsWiki"] = true
ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived
if !ctx.Repo.Repository.HasWiki() {
@@ -519,7 +536,6 @@ func WikiPages(ctx *context.Context) {
}
ctx.Data["Title"] = ctx.Tr("repo.wiki.pages")
ctx.Data["PageIsWiki"] = true
ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived
wikiRepo, commit, err := findWikiRepoCommit(ctx)
@@ -612,7 +628,7 @@ func WikiRaw(ctx *context.Context) {
}
if entry != nil {
if err = common.ServeBlob(ctx, entry.Blob()); err != nil {
if err = common.ServeBlob(ctx, entry.Blob(), time.Time{}); err != nil {
ctx.ServerError("ServeBlob", err)
}
return
@@ -624,7 +640,6 @@ func WikiRaw(ctx *context.Context) {
// NewWiki render wiki create page
func NewWiki(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
ctx.Data["PageIsWiki"] = true
if !ctx.Repo.Repository.HasWiki() {
ctx.Data["title"] = "Home"
@@ -640,7 +655,6 @@ func NewWiki(ctx *context.Context) {
func NewWikiPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.NewWikiForm)
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
ctx.Data["PageIsWiki"] = true
if ctx.HasError() {
ctx.HTML(http.StatusOK, tplWikiNew)
@@ -658,7 +672,7 @@ func NewWikiPost(ctx *context.Context) {
form.Message = ctx.Tr("repo.editor.add", form.Title)
}
if err := wiki_service.AddWikiPage(ctx, ctx.User, ctx.Repo.Repository, wikiName, form.Content, form.Message); err != nil {
if err := wiki_service.AddWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName, form.Content, form.Message); err != nil {
if models.IsErrWikiReservedName(err) {
ctx.Data["Err_Title"] = true
ctx.RenderWithErr(ctx.Tr("repo.wiki.reserved_page", wikiName), tplWikiNew, &form)
@@ -676,7 +690,6 @@ func NewWikiPost(ctx *context.Context) {
// EditWiki render wiki modify page
func EditWiki(ctx *context.Context) {
ctx.Data["PageIsWiki"] = true
ctx.Data["PageIsWikiEdit"] = true
if !ctx.Repo.Repository.HasWiki() {
@@ -696,7 +709,6 @@ func EditWiki(ctx *context.Context) {
func EditWikiPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.NewWikiForm)
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
ctx.Data["PageIsWiki"] = true
if ctx.HasError() {
ctx.HTML(http.StatusOK, tplWikiNew)
@@ -710,7 +722,7 @@ func EditWikiPost(ctx *context.Context) {
form.Message = ctx.Tr("repo.editor.update", form.Title)
}
if err := wiki_service.EditWikiPage(ctx, ctx.User, ctx.Repo.Repository, oldWikiName, newWikiName, form.Content, form.Message); err != nil {
if err := wiki_service.EditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, oldWikiName, newWikiName, form.Content, form.Message); err != nil {
ctx.ServerError("EditWikiPage", err)
return
}
@@ -725,7 +737,7 @@ func DeleteWikiPagePost(ctx *context.Context) {
wikiName = "Home"
}
if err := wiki_service.DeleteWikiPage(ctx, ctx.User, ctx.Repo.Repository, wikiName); err != nil {
if err := wiki_service.DeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName); err != nil {
ctx.ServerError("DeleteWikiPage", err)
return
}
+3 -3
View File
@@ -26,7 +26,7 @@ const (
)
func wikiEntry(t *testing.T, repo *repo_model.Repository, wikiName string) *git.TreeEntry {
wikiRepo, err := git.OpenRepository(repo.WikiPath())
wikiRepo, err := git.OpenRepository(git.DefaultContext, repo.WikiPath())
assert.NoError(t, err)
defer wikiRepo.Close()
commit, err := wikiRepo.GetBranchCommit("master")
@@ -124,7 +124,7 @@ func TestNewWikiPost(t *testing.T) {
Message: message,
})
NewWikiPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assertWikiExists(t, ctx.Repo.Repository, title)
assert.Equal(t, wikiContent(t, ctx.Repo.Repository, title), content)
}
@@ -176,7 +176,7 @@ func TestEditWikiPost(t *testing.T) {
Message: message,
})
EditWikiPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assertWikiExists(t, ctx.Repo.Repository, title)
assert.Equal(t, wikiContent(t, ctx.Repo.Repository, title), content)
if title != "Home" {
+78 -39
View File
@@ -17,6 +17,8 @@ import (
"code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
@@ -29,7 +31,6 @@ import (
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/web/feed"
issue_service "code.gitea.io/gitea/services/issue"
pull_service "code.gitea.io/gitea/services/pull"
@@ -47,7 +48,7 @@ const (
// getDashboardContextUser finds out which context user dashboard is being viewed as .
func getDashboardContextUser(ctx *context.Context) *user_model.User {
ctxUser := ctx.User
ctxUser := ctx.Doer
orgName := ctx.Params(":org")
if len(orgName) > 0 {
ctxUser = ctx.Org.Organization.AsUser()
@@ -55,7 +56,7 @@ func getDashboardContextUser(ctx *context.Context) *user_model.User {
}
ctx.Data["ContextUser"] = ctxUser
orgs, err := models.GetUserOrgsList(ctx.User)
orgs, err := models.GetUserOrgsList(ctx.Doer)
if err != nil {
ctx.ServerError("GetUserOrgsList", err)
return nil
@@ -75,7 +76,7 @@ func Dashboard(ctx *context.Context) {
ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Tr("dashboard")
ctx.Data["PageIsDashboard"] = true
ctx.Data["PageIsNews"] = true
cnt, _ := models.GetOrganizationCount(db.DefaultContext, ctxUser)
cnt, _ := organization.GetOrganizationCount(ctx, ctxUser)
ctx.Data["UserOrgsCount"] = cnt
var uid int64
@@ -89,7 +90,7 @@ func Dashboard(ctx *context.Context) {
}
if setting.Service.EnableUserHeatmap {
data, err := models.GetUserHeatmapDataByUserTeam(ctxUser, ctx.Org.Team, ctx.User)
data, err := models.GetUserHeatmapDataByUserTeam(ctxUser, ctx.Org.Team, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserHeatmapDataByUserTeam", err)
return
@@ -100,11 +101,11 @@ func Dashboard(ctx *context.Context) {
var err error
var mirrors []*repo_model.Repository
if ctxUser.IsOrganization() {
var env models.AccessibleReposEnvironment
var env organization.AccessibleReposEnvironment
if ctx.Org.Team != nil {
env = models.OrgFromUser(ctxUser).AccessibleTeamReposEnv(ctx.Org.Team)
env = organization.OrgFromUser(ctxUser).AccessibleTeamReposEnv(ctx.Org.Team)
} else {
env, err = models.OrgFromUser(ctxUser).AccessibleReposEnv(ctx.User.ID)
env, err = organization.AccessibleReposEnv(ctx, organization.OrgFromUser(ctxUser), ctx.Doer.ID)
if err != nil {
ctx.ServerError("AccessibleReposEnv", err)
return
@@ -131,17 +132,17 @@ func Dashboard(ctx *context.Context) {
ctx.Data["MirrorCount"] = len(mirrors)
ctx.Data["Mirrors"] = mirrors
ctx.Data["Feeds"] = feed.RetrieveFeeds(ctx, models.GetFeedsOptions{
ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctxUser,
RequestedTeam: ctx.Org.Team,
Actor: ctx.User,
Actor: ctx.Doer,
IncludePrivate: true,
OnlyPerformedBy: false,
IncludeDeleted: false,
Date: ctx.FormString("date"),
})
if ctx.Written() {
if err != nil {
ctx.ServerError("GetFeeds", err)
return
}
@@ -152,7 +153,7 @@ func Dashboard(ctx *context.Context) {
func Milestones(ctx *context.Context) {
if unit.TypeIssues.UnitGlobalDisabled() && unit.TypePullRequests.UnitGlobalDisabled() {
log.Debug("Milestones overview page not available as both issues and pull requests are globally disabled")
ctx.Status(404)
ctx.Status(http.StatusNotFound)
return
}
@@ -219,13 +220,13 @@ func Milestones(ctx *context.Context) {
}
}
counts, err := models.CountMilestonesByRepoCondAndKw(userRepoCond, keyword, isShowClosed)
counts, err := issues_model.CountMilestonesByRepoCondAndKw(userRepoCond, keyword, isShowClosed)
if err != nil {
ctx.ServerError("CountMilestonesByRepoIDs", err)
return
}
milestones, err := models.SearchMilestones(repoCond, page, isShowClosed, sortType, keyword)
milestones, err := issues_model.SearchMilestones(repoCond, page, isShowClosed, sortType, keyword)
if err != nil {
ctx.ServerError("SearchMilestones", err)
return
@@ -271,17 +272,17 @@ func Milestones(ctx *context.Context) {
i++
}
milestoneStats, err := models.GetMilestonesStatsByRepoCondAndKw(repoCond, keyword)
milestoneStats, err := issues_model.GetMilestonesStatsByRepoCondAndKw(repoCond, keyword)
if err != nil {
ctx.ServerError("GetMilestoneStats", err)
return
}
var totalMilestoneStats *models.MilestonesStats
var totalMilestoneStats *issues_model.MilestonesStats
if len(repoIDs) == 0 {
totalMilestoneStats = milestoneStats
} else {
totalMilestoneStats, err = models.GetMilestonesStatsByRepoCondAndKw(userRepoCond, keyword)
totalMilestoneStats, err = issues_model.GetMilestonesStatsByRepoCondAndKw(userRepoCond, keyword)
if err != nil {
ctx.ServerError("GetMilestoneStats", err)
return
@@ -324,7 +325,7 @@ func Milestones(ctx *context.Context) {
func Pulls(ctx *context.Context) {
if unit.TypePullRequests.UnitGlobalDisabled() {
log.Debug("Pull request overview page not available as it is globally disabled.")
ctx.Status(404)
ctx.Status(http.StatusNotFound)
return
}
@@ -337,7 +338,7 @@ func Pulls(ctx *context.Context) {
func Issues(ctx *context.Context) {
if unit.TypeIssues.UnitGlobalDisabled() {
log.Debug("Issues overview page not available as it is globally disabled.")
ctx.Status(404)
ctx.Status(http.StatusNotFound)
return
}
@@ -363,7 +364,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
var (
viewType string
sortType = ctx.FormString("sort")
filterMode = models.FilterModeAll
filterMode int
)
// --------------------------------------------------------------------------------
@@ -389,8 +390,10 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
filterMode = models.FilterModeMention
case "review_requested":
filterMode = models.FilterModeReviewRequested
case "your_repositories": // filterMode already set to All
case "your_repositories":
fallthrough
default:
filterMode = models.FilterModeYourRepositories
viewType = "your_repositories"
}
@@ -403,8 +406,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
// --------------------------------------------------------------------------
// Get repository IDs where User/Org/Team has access.
var team *models.Team
var org *models.Organization
var team *organization.Team
var org *organization.Organization
if ctx.Org != nil {
org = ctx.Org.Organization
team = ctx.Org.Team
@@ -417,19 +420,50 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
IsArchived: util.OptionalBoolFalse,
Org: org,
Team: team,
User: ctx.User,
User: ctx.Doer,
}
// Search all repositories which
//
// As user:
// - Owns the repository.
// - Have collaborator permissions in repository.
//
// As org:
// - Owns the repository.
//
// As team:
// - Team org's owns the repository.
// - Team has read permission to repository.
repoOpts := &models.SearchRepoOptions{
Actor: ctx.Doer,
OwnerID: ctx.Doer.ID,
Private: true,
AllPublic: false,
AllLimited: false,
}
if ctxUser.IsOrganization() && ctx.Org.Team != nil {
repoOpts.TeamID = ctx.Org.Team.ID
}
switch filterMode {
case models.FilterModeAll:
case models.FilterModeAssign:
opts.AssigneeID = ctx.User.ID
opts.AssigneeID = ctx.Doer.ID
case models.FilterModeCreate:
opts.PosterID = ctx.User.ID
opts.PosterID = ctx.Doer.ID
case models.FilterModeMention:
opts.MentionedID = ctx.User.ID
opts.MentionedID = ctx.Doer.ID
case models.FilterModeReviewRequested:
opts.ReviewRequestedID = ctx.User.ID
opts.ReviewRequestedID = ctx.Doer.ID
case models.FilterModeYourRepositories:
if ctxUser.IsOrganization() && ctx.Org.Team != nil {
// Fixes a issue whereby the user's ID would be used
// to check if it's in the team(which possible isn't the case).
opts.User = nil
}
opts.RepoCond = models.SearchRepositoryCondition(repoOpts)
}
// keyword holds the search term entered into the search field.
@@ -493,7 +527,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
// Gets set when clicking filters on the issues overview page.
repoIDs := getRepoIDs(ctx.FormString("repos"))
if len(repoIDs) > 0 {
opts.RepoIDs = repoIDs
opts.RepoCond = builder.In("issue.repo_id", repoIDs)
}
// ------------------------------
@@ -539,7 +573,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
}
}
commitStatus, err := pull_service.GetIssuesLastCommitStatus(ctx, issues)
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues)
if err != nil {
ctx.ServerError("GetIssuesLastCommitStatus", err)
return
@@ -551,7 +585,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
var issueStats *models.IssueStats
if !forceEmpty {
statsOpts := models.UserIssueStatsOptions{
UserID: ctx.User.ID,
UserID: ctx.Doer.ID,
FilterMode: filterMode,
IsPull: isPullList,
IsClosed: isShowClosed,
@@ -561,8 +595,12 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
Org: org,
Team: team,
}
if len(repoIDs) > 0 {
statsOpts.RepoIDs = repoIDs
if filterMode == models.FilterModeYourRepositories {
statsOpts.RepoCond = models.SearchRepositoryCondition(repoOpts)
}
// Detect when we only should search by team.
if opts.User == nil {
statsOpts.UserID = 0
}
issueStats, err = models.GetUserIssueStats(statsOpts)
if err != nil {
@@ -612,7 +650,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
}
return 0
}
ctx.Data["CommitStatus"] = commitStatus
ctx.Data["CommitLastStatus"] = lastStatus
ctx.Data["CommitStatuses"] = commitStatuses
ctx.Data["Repos"] = showRepos
ctx.Data["Counts"] = issueCountByRepo
ctx.Data["IssueStats"] = issueStats
@@ -714,8 +753,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
@@ -730,8 +769,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(db.DefaultContext, 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
+1 -1
View File
@@ -26,7 +26,7 @@ func TestArchivedIssues(t *testing.T) {
ctx.Req.Form.Set("state", "open")
// Assume: User 30 has access to two Repos with Issues, one of the Repos being archived.
repos, _, _ := models.GetUserRepositories(&models.SearchRepoOptions{Actor: ctx.User})
repos, _, _ := models.GetUserRepositories(&models.SearchRepoOptions{Actor: ctx.Doer})
assert.Len(t, repos, 2)
IsArchived := make(map[int64]bool)
NumIssues := make(map[int64]int)
+3 -1
View File
@@ -12,5 +12,7 @@ import (
)
func TestMain(m *testing.M) {
unittest.MainTest(m, filepath.Join("..", "..", ".."))
unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", "..", ".."),
})
}
+11 -5
View File
@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
)
const (
@@ -33,7 +34,7 @@ func GetNotificationCount(c *context.Context) {
}
c.Data["NotificationUnreadCount"] = func() int64 {
count, err := models.GetNotificationCount(c.User, models.NotificationStatusUnread)
count, err := models.GetNotificationCount(c.Doer, models.NotificationStatusUnread)
if err != nil {
c.ServerError("GetNotificationCount", err)
return -1
@@ -78,7 +79,7 @@ func getNotifications(c *context.Context) {
status = models.NotificationStatusUnread
}
total, err := models.GetNotificationCount(c.User, status)
total, err := models.GetNotificationCount(c.Doer, status)
if err != nil {
c.ServerError("ErrGetNotificationCount", err)
return
@@ -92,7 +93,7 @@ func getNotifications(c *context.Context) {
}
statuses := []models.NotificationStatus{status, models.NotificationStatusPinned}
notifications, err := models.NotificationsForUser(c.User, statuses, page, perPage)
notifications, err := models.NotificationsForUser(c.Doer, statuses, page, perPage)
if err != nil {
c.ServerError("ErrNotificationsForUser", err)
return
@@ -161,7 +162,7 @@ func NotificationStatusPost(c *context.Context) {
return
}
if _, err := models.SetNotificationStatus(notificationID, c.User, status); err != nil {
if _, err := models.SetNotificationStatus(notificationID, c.Doer, status); err != nil {
c.ServerError("SetNotificationStatus", err)
return
}
@@ -183,7 +184,7 @@ func NotificationStatusPost(c *context.Context) {
// NotificationPurgePost is a route for 'purging' the list of notifications - marking all unread as read
func NotificationPurgePost(c *context.Context) {
err := models.UpdateNotificationStatuses(c.User, models.NotificationStatusUnread, models.NotificationStatusRead)
err := models.UpdateNotificationStatuses(c.Doer, models.NotificationStatusUnread, models.NotificationStatusRead)
if err != nil {
c.ServerError("ErrUpdateNotificationStatuses", err)
return
@@ -191,3 +192,8 @@ func NotificationPurgePost(c *context.Context) {
c.Redirect(setting.AppSubURL+"/notifications", http.StatusSeeOther)
}
// NewAvailable returns the notification counts
func NewAvailable(ctx *context.Context) {
ctx.JSON(http.StatusOK, structs.NotificationCount{New: models.CountUnread(ctx.Doer)})
}
+376
View File
@@ -0,0 +1,376 @@
// Copyright 2021 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 user
import (
"net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
container_model "code.gitea.io/gitea/models/packages/container"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"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"
packages_service "code.gitea.io/gitea/services/packages"
)
const (
tplPackagesList base.TplName = "user/overview/packages"
tplPackagesView base.TplName = "package/view"
tplPackageVersionList base.TplName = "user/overview/package_versions"
tplPackagesSettings base.TplName = "package/settings"
)
// ListPackages displays a list of all packages of the context user
func ListPackages(ctx *context.Context) {
page := ctx.FormInt("page")
if page <= 1 {
page = 1
}
query := ctx.FormTrim("q")
packageType := ctx.FormTrim("type")
pvs, total, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{
Paginator: &db.ListOptions{
PageSize: setting.UI.PackagesPagingNum,
Page: page,
},
OwnerID: ctx.ContextUser.ID,
Type: packages_model.Type(packageType),
Name: packages_model.SearchValue{Value: query},
})
if err != nil {
ctx.ServerError("SearchLatestVersions", err)
return
}
pds, err := packages_model.GetPackageDescriptors(ctx, pvs)
if err != nil {
ctx.ServerError("GetPackageDescriptors", err)
return
}
repositoryAccessMap := make(map[int64]bool)
for _, pd := range pds {
if pd.Repository == nil {
continue
}
if _, has := repositoryAccessMap[pd.Repository.ID]; has {
continue
}
permission, err := models.GetUserRepoPermission(ctx, pd.Repository, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return
}
repositoryAccessMap[pd.Repository.ID] = permission.HasAccess()
}
hasPackages, err := packages_model.HasOwnerPackages(ctx, ctx.ContextUser.ID)
if err != nil {
ctx.ServerError("HasOwnerPackages", err)
return
}
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["IsPackagesPage"] = true
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["Query"] = query
ctx.Data["PackageType"] = packageType
ctx.Data["HasPackages"] = hasPackages
ctx.Data["PackageDescriptors"] = pds
ctx.Data["Total"] = total
ctx.Data["RepositoryAccessMap"] = repositoryAccessMap
pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5)
pager.AddParam(ctx, "q", "Query")
pager.AddParam(ctx, "type", "PackageType")
ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, tplPackagesList)
}
// RedirectToLastVersion redirects to the latest package version
func RedirectToLastVersion(ctx *context.Context) {
p, err := packages_model.GetPackageByName(ctx, ctx.Package.Owner.ID, packages_model.Type(ctx.Params("type")), ctx.Params("name"))
if err != nil {
if err == packages_model.ErrPackageNotExist {
ctx.NotFound("GetPackageByName", err)
} else {
ctx.ServerError("GetPackageByName", err)
}
return
}
pvs, _, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{
PackageID: p.ID,
})
if err != nil {
ctx.ServerError("GetPackageByName", err)
return
}
if len(pvs) == 0 {
ctx.NotFound("", err)
return
}
pd, err := packages_model.GetPackageDescriptor(ctx, pvs[0])
if err != nil {
ctx.ServerError("GetPackageDescriptor", err)
return
}
ctx.Redirect(pd.FullWebLink())
}
// ViewPackageVersion displays a single package version
func ViewPackageVersion(ctx *context.Context) {
pd := ctx.Package.Descriptor
ctx.Data["Title"] = pd.Package.Name
ctx.Data["IsPackagesPage"] = true
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["PackageDescriptor"] = pd
var (
total int64
pvs []*packages_model.PackageVersion
err error
)
switch pd.Package.Type {
case packages_model.TypeContainer:
ctx.Data["RegistryHost"] = setting.Packages.RegistryHost
pvs, total, err = container_model.SearchImageTags(ctx, &container_model.ImageTagsSearchOptions{
Paginator: db.NewAbsoluteListOptions(0, 5),
PackageID: pd.Package.ID,
IsTagged: true,
})
default:
pvs, total, err = packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
Paginator: db.NewAbsoluteListOptions(0, 5),
PackageID: pd.Package.ID,
})
if err != nil {
ctx.ServerError("SearchVersions", err)
return
}
}
if err != nil {
ctx.ServerError("", err)
return
}
ctx.Data["LatestVersions"] = pvs
ctx.Data["TotalVersionCount"] = total
ctx.Data["CanWritePackages"] = ctx.Package.AccessMode >= perm.AccessModeWrite || ctx.IsUserSiteAdmin()
hasRepositoryAccess := false
if pd.Repository != nil {
permission, err := models.GetUserRepoPermission(ctx, pd.Repository, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return
}
hasRepositoryAccess = permission.HasAccess()
}
ctx.Data["HasRepositoryAccess"] = hasRepositoryAccess
ctx.HTML(http.StatusOK, tplPackagesView)
}
// ListPackageVersions lists all versions of a package
func ListPackageVersions(ctx *context.Context) {
p, err := packages_model.GetPackageByName(ctx, ctx.Package.Owner.ID, packages_model.Type(ctx.Params("type")), ctx.Params("name"))
if err != nil {
if err == packages_model.ErrPackageNotExist {
ctx.NotFound("GetPackageByName", err)
} else {
ctx.ServerError("GetPackageByName", err)
}
return
}
page := ctx.FormInt("page")
if page <= 1 {
page = 1
}
pagination := &db.ListOptions{
PageSize: setting.UI.PackagesPagingNum,
Page: page,
}
query := ctx.FormTrim("q")
ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["IsPackagesPage"] = true
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["PackageDescriptor"] = &packages_model.PackageDescriptor{
Package: p,
Owner: ctx.Package.Owner,
}
ctx.Data["Query"] = query
pagerParams := map[string]string{
"q": query,
}
var (
total int64
pvs []*packages_model.PackageVersion
)
switch p.Type {
case packages_model.TypeContainer:
tagged := ctx.FormTrim("tagged")
pagerParams["tagged"] = tagged
ctx.Data["Tagged"] = tagged
pvs, total, err = container_model.SearchImageTags(ctx, &container_model.ImageTagsSearchOptions{
Paginator: pagination,
PackageID: p.ID,
Query: query,
IsTagged: tagged == "" || tagged == "tagged",
})
if err != nil {
ctx.ServerError("SearchImageTags", err)
return
}
default:
pvs, total, err = packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
Paginator: pagination,
PackageID: p.ID,
Version: packages_model.SearchValue{
ExactMatch: false,
Value: query,
},
})
if err != nil {
ctx.ServerError("SearchVersions", err)
return
}
}
ctx.Data["PackageDescriptors"], err = packages_model.GetPackageDescriptors(ctx, pvs)
if err != nil {
ctx.ServerError("GetPackageDescriptors", err)
return
}
ctx.Data["Total"] = total
pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5)
for k, v := range pagerParams {
pager.AddParamString(k, v)
}
ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, tplPackageVersionList)
}
// PackageSettings displays the package settings page
func PackageSettings(ctx *context.Context) {
pd := ctx.Package.Descriptor
ctx.Data["Title"] = pd.Package.Name
ctx.Data["IsPackagesPage"] = true
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["PackageDescriptor"] = pd
repos, _, _ := models.GetUserRepositories(&models.SearchRepoOptions{
Actor: pd.Owner,
Private: true,
})
ctx.Data["Repos"] = repos
ctx.Data["CanWritePackages"] = ctx.Package.AccessMode >= perm.AccessModeWrite || ctx.IsUserSiteAdmin()
ctx.HTML(http.StatusOK, tplPackagesSettings)
}
// PackageSettingsPost updates the package settings
func PackageSettingsPost(ctx *context.Context) {
pd := ctx.Package.Descriptor
form := web.GetForm(ctx).(*forms.PackageSettingForm)
switch form.Action {
case "link":
success := func() bool {
repoID := int64(0)
if form.RepoID != 0 {
repo, err := repo_model.GetRepositoryByID(form.RepoID)
if err != nil {
log.Error("Error getting repository: %v", err)
return false
}
if repo.OwnerID != pd.Owner.ID {
return false
}
repoID = repo.ID
}
if err := packages_model.SetRepositoryLink(ctx, pd.Package.ID, repoID); err != nil {
log.Error("Error updating package: %v", err)
return false
}
return true
}()
if success {
ctx.Flash.Success(ctx.Tr("packages.settings.link.success"))
} else {
ctx.Flash.Error(ctx.Tr("packages.settings.link.error"))
}
ctx.Redirect(ctx.Link)
return
case "delete":
err := packages_service.RemovePackageVersion(ctx.Doer, ctx.Package.Descriptor.Version)
if err != nil {
log.Error("Error deleting package: %v", err)
ctx.Flash.Error(ctx.Tr("packages.settings.delete.error"))
} else {
ctx.Flash.Success(ctx.Tr("packages.settings.delete.success"))
}
ctx.Redirect(ctx.Package.Owner.HTMLURL() + "/-/packages")
return
}
}
// DownloadPackageFile serves the content of a package file
func DownloadPackageFile(ctx *context.Context) {
pf, err := packages_model.GetFileForVersionByID(ctx, ctx.Package.Descriptor.Version.ID, ctx.ParamsInt64(":fileid"))
if err != nil {
if err == packages_model.ErrPackageFileNotExist {
ctx.NotFound("", err)
} else {
ctx.ServerError("GetFileForVersionByID", err)
}
return
}
s, _, err := packages_service.GetPackageFileStream(
ctx,
pf,
)
if err != nil {
ctx.ServerError("GetPackageFileStream", err)
return
}
defer s.Close()
ctx.ServeStream(s, pf.Name)
}
+47 -131
View File
@@ -8,11 +8,12 @@ package user
import (
"fmt"
"net/http"
"path"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
project_model "code.gitea.io/gitea/models/project"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
@@ -24,133 +25,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")
}
showFeedType := ""
if strings.HasSuffix(uname, ".rss") {
showFeedType = "rss"
uname = strings.TrimSuffix(uname, ".rss")
} else if strings.Contains(ctx.Req.Header.Get("Accept"), "application/rss+xml") {
showFeedType = "rss"
}
if strings.HasSuffix(uname, ".atom") {
showFeedType = "atom"
uname = strings.TrimSuffix(uname, ".atom")
} else if strings.Contains(ctx.Req.Header.Get("Accept"), "application/atom+xml") {
showFeedType = "atom"
}
ctxUser := GetUserByName(ctx, uname)
if ctx.Written() {
return
}
if ctxUser.IsOrganization() {
/*
// TODO: enable after rss.RetrieveFeeds() do handle org correctly
// Show Org RSS feed
if len(showFeedType) != 0 {
rss.ShowUserFeed(ctx, ctxUser, showFeedType)
return
}
*/
if ctx.ContextUser.IsOrganization() {
org.Home(ctx)
return
}
// check view permissions
if !models.IsUserVisibleToViewer(ctxUser, ctx.User) {
ctx.NotFound("user", fmt.Errorf(uname))
if !user_model.IsUserVisibleToViewer(ctx.ContextUser, ctx.Doer) {
ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name))
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 len(showFeedType) != 0 {
feed.ShowUserFeed(ctx, ctxUser, showFeedType)
return
}
// advertise feed via meta tag
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.User != nil && ctxUser != nil {
isFollowing = user_model.IsFollowing(ctx.User.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.User)
data, err := models.GetUserHeatmapDataByUser(ctx.ContextUser, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserHeatmapDataByUser", err)
return
@@ -158,13 +77,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
@@ -172,10 +91,10 @@ func Profile(ctx *context.Context) {
ctx.Data["RenderedDescription"] = content
}
showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == ctxUser.ID)
showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
orgs, err := models.FindOrgs(models.FindOrgOptions{
UserID: ctxUser.ID,
orgs, err := organization.FindOrgs(organization.FindOrgOptions{
UserID: ctx.ContextUser.ID,
IncludePrivate: showPrivate,
})
if err != nil {
@@ -184,7 +103,7 @@ func Profile(ctx *context.Context) {
}
ctx.Data["Orgs"] = orgs
ctx.Data["HasOrgsVisible"] = models.HasOrgsVisible(orgs, ctx.User)
ctx.Data["HasOrgsVisible"] = organization.HasOrgsVisible(orgs, ctx.Doer)
tab := ctx.FormString("tab")
ctx.Data["TabName"] = tab
@@ -238,7 +157,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,
})
@@ -248,9 +167,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,
})
@@ -260,17 +179,18 @@ func Profile(ctx *context.Context) {
}
ctx.Data["Cards"] = items
total = ctxUser.NumFollowing
total = ctx.ContextUser.NumFollowing
case "activity":
ctx.Data["Feeds"] = feed.RetrieveFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctxUser,
Actor: ctx.User,
ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctx.ContextUser,
Actor: ctx.Doer,
IncludePrivate: showPrivate,
OnlyPerformedBy: true,
IncludeDeleted: false,
Date: ctx.FormString("date"),
})
if ctx.Written() {
if err != nil {
ctx.ServerError("GetFeeds", err)
return
}
case "stars":
@@ -280,11 +200,11 @@ func Profile(ctx *context.Context) {
PageSize: setting.UI.User.RepoPagingNum,
Page: page,
},
Actor: ctx.User,
Actor: ctx.Doer,
Keyword: keyword,
OrderBy: orderBy,
Private: ctx.IsSigned,
StarredByID: ctxUser.ID,
StarredByID: ctx.ContextUser.ID,
Collaborate: util.OptionalBoolFalse,
TopicOnly: topicOnly,
Language: language,
@@ -297,10 +217,10 @@ func Profile(ctx *context.Context) {
total = int(count)
case "projects":
ctx.Data["OpenProjects"], _, err = models.GetProjects(models.ProjectSearchOptions{
ctx.Data["OpenProjects"], _, err = project_model.GetProjects(project_model.SearchOptions{
Page: -1,
IsClosed: util.OptionalBoolFalse,
Type: models.ProjectTypeIndividual,
Type: project_model.TypeIndividual,
})
if err != nil {
ctx.ServerError("GetProjects", err)
@@ -312,11 +232,11 @@ func Profile(ctx *context.Context) {
PageSize: setting.UI.User.RepoPagingNum,
Page: page,
},
Actor: ctx.User,
Actor: ctx.Doer,
Keyword: keyword,
OrderBy: orderBy,
Private: ctx.IsSigned,
WatchedByID: ctxUser.ID,
WatchedByID: ctx.ContextUser.ID,
Collaborate: util.OptionalBoolFalse,
TopicOnly: topicOnly,
Language: language,
@@ -334,9 +254,9 @@ func Profile(ctx *context.Context) {
PageSize: setting.UI.User.RepoPagingNum,
Page: page,
},
Actor: ctx.User,
Actor: ctx.Doer,
Keyword: keyword,
OwnerID: ctxUser.ID,
OwnerID: ctx.ContextUser.ID,
OrderBy: orderBy,
Private: ctx.IsSigned,
Collaborate: util.OptionalBoolFalse,
@@ -360,25 +280,21 @@ func Profile(ctx *context.Context) {
pager.AddParam(ctx, "language", "Language")
}
ctx.Data["Page"] = pager
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["ShowUserEmail"] = len(ctxUser.Email) > 0 && ctx.IsSigned && (!ctxUser.KeepEmailPrivate || ctxUser.ID == ctx.User.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.User.ID, u.ID)
err = user_model.FollowUser(ctx.Doer.ID, ctx.ContextUser.ID)
case "unfollow":
err = user_model.UnfollowUser(ctx.User.ID, u.ID)
err = user_model.UnfollowUser(ctx.Doer.ID, ctx.ContextUser.ID)
}
if err != nil {
@@ -386,5 +302,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())
}
+44
View File
@@ -0,0 +1,44 @@
// 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 user
import (
"net/http"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
)
// Search search users
func Search(ctx *context.Context) {
listOptions := db.ListOptions{
Page: ctx.FormInt("page"),
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
}
users, maxResults, err := user_model.SearchUsers(&user_model.SearchUserOptions{
Actor: ctx.Doer,
Keyword: ctx.FormTrim("q"),
UID: ctx.FormInt64("uid"),
Type: user_model.UserTypeIndividual,
ListOptions: listOptions,
})
if err != nil {
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"ok": false,
"error": err.Error(),
})
return
}
ctx.SetTotalCountHeader(maxResults)
ctx.JSON(http.StatusOK, map[string]interface{}{
"ok": true,
"data": convert.ToUsers(ctx.Doer, users),
})
}
+36 -33
View File
@@ -11,7 +11,6 @@ import (
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
@@ -34,7 +33,7 @@ const (
func Account(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsAccount"] = true
ctx.Data["Email"] = ctx.User.Email
ctx.Data["Email"] = ctx.Doer.Email
loadAccountData(ctx)
@@ -56,7 +55,7 @@ func AccountPost(ctx *context.Context) {
if len(form.Password) < setting.MinPasswordLength {
ctx.Flash.Error(ctx.Tr("auth.password_too_short", setting.MinPasswordLength))
} else if ctx.User.IsPasswordSet() && !ctx.User.ValidatePassword(form.OldPassword) {
} else if ctx.Doer.IsPasswordSet() && !ctx.Doer.ValidatePassword(form.OldPassword) {
ctx.Flash.Error(ctx.Tr("settings.password_incorrect"))
} else if form.Password != form.Retype {
ctx.Flash.Error(ctx.Tr("form.password_not_match"))
@@ -71,15 +70,15 @@ func AccountPost(ctx *context.Context) {
ctx.Flash.Error(errMsg)
} else {
var err error
if err = ctx.User.SetPassword(form.Password); err != nil {
if err = ctx.Doer.SetPassword(form.Password); err != nil {
ctx.ServerError("UpdateUser", err)
return
}
if err := user_model.UpdateUserCols(db.DefaultContext, ctx.User, "salt", "passwd_hash_algo", "passwd"); err != nil {
if err := user_model.UpdateUserCols(ctx, ctx.Doer, "salt", "passwd_hash_algo", "passwd"); err != nil {
ctx.ServerError("UpdateUser", err)
return
}
log.Trace("User password updated: %s", ctx.User.Name)
log.Trace("User password updated: %s", ctx.Doer.Name)
ctx.Flash.Success(ctx.Tr("settings.change_password_success"))
}
@@ -99,50 +98,50 @@ func EmailPost(ctx *context.Context) {
return
}
log.Trace("Email made primary: %s", ctx.User.Name)
log.Trace("Email made primary: %s", ctx.Doer.Name)
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
// Send activation Email
if ctx.FormString("_method") == "SENDACTIVATION" {
var address string
if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) {
if ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName) {
log.Error("Send activation: activation still pending")
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
id := ctx.FormInt64("id")
email, err := user_model.GetEmailAddressByID(ctx.User.ID, id)
email, err := user_model.GetEmailAddressByID(ctx.Doer.ID, id)
if err != nil {
log.Error("GetEmailAddressByID(%d,%d) error: %v", ctx.User.ID, id, err)
log.Error("GetEmailAddressByID(%d,%d) error: %v", ctx.Doer.ID, id, err)
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
if email == nil {
log.Warn("Send activation failed: EmailAddress[%d] not found for user: %-v", id, ctx.User)
log.Warn("Send activation failed: EmailAddress[%d] not found for user: %-v", id, ctx.Doer)
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
if email.IsActivated {
log.Debug("Send activation failed: email %s is already activated for user: %-v", email.Email, ctx.User)
log.Debug("Send activation failed: email %s is already activated for user: %-v", email.Email, ctx.Doer)
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
if email.IsPrimary {
if ctx.User.IsActive && !setting.Service.RegisterEmailConfirm {
log.Debug("Send activation failed: email %s is already activated for user: %-v", email.Email, ctx.User)
if ctx.Doer.IsActive && !setting.Service.RegisterEmailConfirm {
log.Debug("Send activation failed: email %s is already activated for user: %-v", email.Email, ctx.Doer)
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
// Only fired when the primary email is inactive (Wrong state)
mailer.SendActivateAccountMail(ctx.Locale, ctx.User)
mailer.SendActivateAccountMail(ctx.Locale, ctx.Doer)
} else {
mailer.SendActivateEmailMail(ctx.User, email)
mailer.SendActivateEmailMail(ctx.Doer, email)
}
address = email.Email
if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil {
if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
log.Error("Set cache(MailResendLimit) fail: %v", err)
}
ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", address, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())))
@@ -155,16 +154,16 @@ func EmailPost(ctx *context.Context) {
if !(preference == user_model.EmailNotificationsEnabled ||
preference == user_model.EmailNotificationsOnMention ||
preference == user_model.EmailNotificationsDisabled) {
log.Error("Email notifications preference change returned unrecognized option %s: %s", preference, ctx.User.Name)
log.Error("Email notifications preference change returned unrecognized option %s: %s", preference, ctx.Doer.Name)
ctx.ServerError("SetEmailPreference", errors.New("option unrecognized"))
return
}
if err := user_model.SetEmailNotifications(ctx.User, preference); err != nil {
if err := user_model.SetEmailNotifications(ctx.Doer, preference); err != nil {
log.Error("Set Email Notifications failed: %v", err)
ctx.ServerError("SetEmailNotifications", err)
return
}
log.Trace("Email notifications preference made %s: %s", preference, ctx.User.Name)
log.Trace("Email notifications preference made %s: %s", preference, ctx.Doer.Name)
ctx.Flash.Success(ctx.Tr("settings.email_preference_set_success"))
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
@@ -178,7 +177,7 @@ func EmailPost(ctx *context.Context) {
}
email := &user_model.EmailAddress{
UID: ctx.User.ID,
UID: ctx.Doer.ID,
Email: form.Email,
IsActivated: !setting.Service.RegisterEmailConfirm,
}
@@ -188,7 +187,8 @@ func EmailPost(ctx *context.Context) {
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsAccount, &form)
return
} else if user_model.IsErrEmailInvalid(err) {
} else if user_model.IsErrEmailCharIsNotSupported(err) ||
user_model.IsErrEmailInvalid(err) {
loadAccountData(ctx)
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSettingsAccount, &form)
@@ -200,8 +200,8 @@ func EmailPost(ctx *context.Context) {
// Send confirmation email
if setting.Service.RegisterEmailConfirm {
mailer.SendActivateEmailMail(ctx.User, email)
if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil {
mailer.SendActivateEmailMail(ctx.Doer, email)
if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
log.Error("Set cache(MailResendLimit) fail: %v", err)
}
ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())))
@@ -215,11 +215,11 @@ func EmailPost(ctx *context.Context) {
// DeleteEmail response for delete user's email
func DeleteEmail(ctx *context.Context) {
if err := user_model.DeleteEmailAddress(&user_model.EmailAddress{ID: ctx.FormInt64("id"), UID: ctx.User.ID}); err != nil {
if err := user_model.DeleteEmailAddress(&user_model.EmailAddress{ID: ctx.FormInt64("id"), UID: ctx.Doer.ID}); err != nil {
ctx.ServerError("DeleteEmail", err)
return
}
log.Trace("Email address deleted: %s", ctx.User.Name)
log.Trace("Email address deleted: %s", ctx.Doer.Name)
ctx.Flash.Success(ctx.Tr("settings.email_deletion_success"))
ctx.JSON(http.StatusOK, map[string]interface{}{
@@ -232,7 +232,7 @@ func DeleteAccount(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsAccount"] = true
if _, _, err := auth.UserSignIn(ctx.User.Name, ctx.FormString("password")); err != nil {
if _, _, err := auth.UserSignIn(ctx.Doer.Name, ctx.FormString("password")); err != nil {
if user_model.IsErrUserNotExist(err) {
loadAccountData(ctx)
@@ -243,7 +243,7 @@ func DeleteAccount(ctx *context.Context) {
return
}
if err := user.DeleteUser(ctx.User); err != nil {
if err := user.DeleteUser(ctx.Doer); err != nil {
switch {
case models.IsErrUserOwnRepos(err):
ctx.Flash.Error(ctx.Tr("form.still_own_repo"))
@@ -251,17 +251,20 @@ func DeleteAccount(ctx *context.Context) {
case models.IsErrUserHasOrgs(err):
ctx.Flash.Error(ctx.Tr("form.still_has_org"))
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
case models.IsErrUserOwnPackages(err):
ctx.Flash.Error(ctx.Tr("form.still_own_packages"))
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
default:
ctx.ServerError("DeleteUser", err)
}
} else {
log.Trace("Account deleted: %s", ctx.User.Name)
log.Trace("Account deleted: %s", ctx.Doer.Name)
ctx.Redirect(setting.AppSubURL + "/")
}
}
func loadAccountData(ctx *context.Context) {
emlist, err := user_model.GetEmailAddresses(ctx.User.ID)
emlist, err := user_model.GetEmailAddresses(ctx.Doer.ID)
if err != nil {
ctx.ServerError("GetEmailAddresses", err)
return
@@ -270,7 +273,7 @@ func loadAccountData(ctx *context.Context) {
user_model.EmailAddress
CanBePrimary bool
}
pendingActivation := ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName)
pendingActivation := ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName)
emails := make([]*UserEmail, len(emlist))
for i, em := range emlist {
var email UserEmail
@@ -279,12 +282,12 @@ func loadAccountData(ctx *context.Context) {
emails[i] = &email
}
ctx.Data["Emails"] = emails
ctx.Data["EmailNotificationsPreference"] = ctx.User.EmailNotifications()
ctx.Data["EmailNotificationsPreference"] = ctx.Doer.EmailNotifications()
ctx.Data["ActivationsPending"] = pendingActivation
ctx.Data["CanAddEmails"] = !pendingActivation || !setting.Service.RegisterEmailConfirm
if setting.Service.UserDeleteWithCommentsMaxTime != 0 {
ctx.Data["UserDeleteWithCommentsMaxTime"] = setting.Service.UserDeleteWithCommentsMaxTime.String()
ctx.Data["UserDeleteWithComments"] = ctx.User.CreatedUnix.AsTime().Add(setting.Service.UserDeleteWithCommentsMaxTime).After(time.Now())
ctx.Data["UserDeleteWithComments"] = ctx.Doer.CreatedUnix.AsTime().Add(setting.Service.UserDeleteWithCommentsMaxTime).After(time.Now())
}
}
+1 -1
View File
@@ -94,6 +94,6 @@ func TestChangePassword(t *testing.T) {
AccountPost(ctx)
assert.Contains(t, ctx.Flash.ErrorMsg, req.Message)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
}
}
+1 -1
View File
@@ -28,7 +28,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
dir := ctx.FormString("id")
action := ctx.FormString("action")
ctxUser := ctx.User
ctxUser := ctx.Doer
root := user_model.UserPath(ctxUser.LowerName)
// check not a repo
+5 -5
View File
@@ -45,7 +45,7 @@ func ApplicationsPost(ctx *context.Context) {
}
t := &models.AccessToken{
UID: ctx.User.ID,
UID: ctx.Doer.ID,
Name: form.Name,
}
@@ -73,7 +73,7 @@ func ApplicationsPost(ctx *context.Context) {
// DeleteApplication response for delete user access token
func DeleteApplication(ctx *context.Context) {
if err := models.DeleteAccessTokenByID(ctx.FormInt64("id"), ctx.User.ID); err != nil {
if err := models.DeleteAccessTokenByID(ctx.FormInt64("id"), ctx.Doer.ID); err != nil {
ctx.Flash.Error("DeleteAccessTokenByID: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("settings.delete_token_success"))
@@ -85,7 +85,7 @@ func DeleteApplication(ctx *context.Context) {
}
func loadApplicationsData(ctx *context.Context) {
tokens, err := models.ListAccessTokens(models.ListAccessTokensOptions{UserID: ctx.User.ID})
tokens, err := models.ListAccessTokens(models.ListAccessTokensOptions{UserID: ctx.Doer.ID})
if err != nil {
ctx.ServerError("ListAccessTokens", err)
return
@@ -93,12 +93,12 @@ func loadApplicationsData(ctx *context.Context) {
ctx.Data["Tokens"] = tokens
ctx.Data["EnableOAuth2"] = setting.OAuth2.Enable
if setting.OAuth2.Enable {
ctx.Data["Applications"], err = auth.GetOAuth2ApplicationsByUserID(ctx.User.ID)
ctx.Data["Applications"], err = auth.GetOAuth2ApplicationsByUserID(ctx.Doer.ID)
if err != nil {
ctx.ServerError("GetOAuth2ApplicationsByUserID", err)
return
}
ctx.Data["Grants"], err = auth.GetOAuth2GrantsByUserID(ctx.User.ID)
ctx.Data["Grants"], err = auth.GetOAuth2GrantsByUserID(ctx.Doer.ID)
if err != nil {
ctx.ServerError("GetOAuth2GrantsByUserID", err)
return
+22 -22
View File
@@ -52,7 +52,7 @@ func KeysPost(ctx *context.Context) {
}
switch form.Type {
case "principal":
content, err := asymkey_model.CheckPrincipalKeyString(ctx.User, form.Content)
content, err := asymkey_model.CheckPrincipalKeyString(ctx.Doer, form.Content)
if err != nil {
if db.IsErrSSHDisabled(err) {
ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
@@ -62,7 +62,7 @@ func KeysPost(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
return
}
if _, err = asymkey_model.AddPrincipalKey(ctx.User.ID, content, 0); err != nil {
if _, err = asymkey_model.AddPrincipalKey(ctx.Doer.ID, content, 0); err != nil {
ctx.Data["HasPrincipalError"] = true
switch {
case asymkey_model.IsErrKeyAlreadyExist(err), asymkey_model.IsErrKeyNameAlreadyUsed(err):
@@ -78,12 +78,12 @@ func KeysPost(ctx *context.Context) {
ctx.Flash.Success(ctx.Tr("settings.add_principal_success", form.Content))
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "gpg":
token := asymkey_model.VerificationToken(ctx.User, 1)
lastToken := asymkey_model.VerificationToken(ctx.User, 0)
token := asymkey_model.VerificationToken(ctx.Doer, 1)
lastToken := asymkey_model.VerificationToken(ctx.Doer, 0)
keys, err := asymkey_model.AddGPGKey(ctx.User.ID, form.Content, token, form.Signature)
keys, err := asymkey_model.AddGPGKey(ctx.Doer.ID, form.Content, token, form.Signature)
if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) {
keys, err = asymkey_model.AddGPGKey(ctx.User.ID, form.Content, lastToken, form.Signature)
keys, err = asymkey_model.AddGPGKey(ctx.Doer.ID, form.Content, lastToken, form.Signature)
}
if err != nil {
ctx.Data["HasGPGError"] = true
@@ -125,12 +125,12 @@ func KeysPost(ctx *context.Context) {
ctx.Flash.Success(ctx.Tr("settings.add_gpg_key_success", keyIDs))
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "verify_gpg":
token := asymkey_model.VerificationToken(ctx.User, 1)
lastToken := asymkey_model.VerificationToken(ctx.User, 0)
token := asymkey_model.VerificationToken(ctx.Doer, 1)
lastToken := asymkey_model.VerificationToken(ctx.Doer, 0)
keyID, err := asymkey_model.VerifyGPGKey(ctx.User.ID, form.KeyID, token, form.Signature)
keyID, err := asymkey_model.VerifyGPGKey(ctx.Doer.ID, form.KeyID, token, form.Signature)
if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) {
keyID, err = asymkey_model.VerifyGPGKey(ctx.User.ID, form.KeyID, lastToken, form.Signature)
keyID, err = asymkey_model.VerifyGPGKey(ctx.Doer.ID, form.KeyID, lastToken, form.Signature)
}
if err != nil {
ctx.Data["HasGPGVerifyError"] = true
@@ -161,7 +161,7 @@ func KeysPost(ctx *context.Context) {
return
}
if _, err = asymkey_model.AddPublicKey(ctx.User.ID, form.Title, content, 0); err != nil {
if _, err = asymkey_model.AddPublicKey(ctx.Doer.ID, form.Title, content, 0); err != nil {
ctx.Data["HasSSHError"] = true
switch {
case asymkey_model.IsErrKeyAlreadyExist(err):
@@ -185,12 +185,12 @@ func KeysPost(ctx *context.Context) {
ctx.Flash.Success(ctx.Tr("settings.add_key_success", form.Title))
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "verify_ssh":
token := asymkey_model.VerificationToken(ctx.User, 1)
lastToken := asymkey_model.VerificationToken(ctx.User, 0)
token := asymkey_model.VerificationToken(ctx.Doer, 1)
lastToken := asymkey_model.VerificationToken(ctx.Doer, 0)
fingerprint, err := asymkey_model.VerifySSHKey(ctx.User.ID, form.Fingerprint, token, form.Signature)
fingerprint, err := asymkey_model.VerifySSHKey(ctx.Doer.ID, form.Fingerprint, token, form.Signature)
if err != nil && asymkey_model.IsErrSSHInvalidTokenSignature(err) {
fingerprint, err = asymkey_model.VerifySSHKey(ctx.User.ID, form.Fingerprint, lastToken, form.Signature)
fingerprint, err = asymkey_model.VerifySSHKey(ctx.Doer.ID, form.Fingerprint, lastToken, form.Signature)
}
if err != nil {
ctx.Data["HasSSHVerifyError"] = true
@@ -217,7 +217,7 @@ func KeysPost(ctx *context.Context) {
func DeleteKey(ctx *context.Context) {
switch ctx.FormString("type") {
case "gpg":
if err := asymkey_model.DeleteGPGKey(ctx.User, ctx.FormInt64("id")); err != nil {
if err := asymkey_model.DeleteGPGKey(ctx.Doer, ctx.FormInt64("id")); err != nil {
ctx.Flash.Error("DeleteGPGKey: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("settings.gpg_key_deletion_success"))
@@ -234,13 +234,13 @@ func DeleteKey(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
return
}
if err := asymkey_service.DeletePublicKey(ctx.User, keyID); err != nil {
if err := asymkey_service.DeletePublicKey(ctx.Doer, keyID); err != nil {
ctx.Flash.Error("DeletePublicKey: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("settings.ssh_key_deletion_success"))
}
case "principal":
if err := asymkey_service.DeletePublicKey(ctx.User, ctx.FormInt64("id")); err != nil {
if err := asymkey_service.DeletePublicKey(ctx.Doer, ctx.FormInt64("id")); err != nil {
ctx.Flash.Error("DeletePublicKey: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("settings.ssh_principal_deletion_success"))
@@ -255,7 +255,7 @@ func DeleteKey(ctx *context.Context) {
}
func loadKeysData(ctx *context.Context) {
keys, err := asymkey_model.ListPublicKeys(ctx.User.ID, db.ListOptions{})
keys, err := asymkey_model.ListPublicKeys(ctx.Doer.ID, db.ListOptions{})
if err != nil {
ctx.ServerError("ListPublicKeys", err)
return
@@ -269,18 +269,18 @@ func loadKeysData(ctx *context.Context) {
}
ctx.Data["ExternalKeys"] = externalKeys
gpgkeys, err := asymkey_model.ListGPGKeys(db.DefaultContext, ctx.User.ID, db.ListOptions{})
gpgkeys, err := asymkey_model.ListGPGKeys(ctx, ctx.Doer.ID, db.ListOptions{})
if err != nil {
ctx.ServerError("ListGPGKeys", err)
return
}
ctx.Data["GPGKeys"] = gpgkeys
tokenToSign := asymkey_model.VerificationToken(ctx.User, 1)
tokenToSign := asymkey_model.VerificationToken(ctx.Doer, 1)
// generate a new aes cipher using the csrfToken
ctx.Data["TokenToSign"] = tokenToSign
principals, err := asymkey_model.ListPrincipalKeys(ctx.User.ID, db.ListOptions{})
principals, err := asymkey_model.ListPrincipalKeys(ctx.Doer.ID, db.ListOptions{})
if err != nil {
ctx.ServerError("ListPrincipalKeys", err)
return
+3 -1
View File
@@ -12,5 +12,7 @@ import (
)
func TestMain(m *testing.M) {
unittest.MainTest(m, filepath.Join("..", "..", "..", ".."))
unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", "..", "..", ".."),
})
}
+8 -8
View File
@@ -37,7 +37,7 @@ func OAuthApplicationsPost(ctx *context.Context) {
app, err := auth.CreateOAuth2Application(auth.CreateOAuth2ApplicationOptions{
Name: form.Name,
RedirectURIs: []string{form.RedirectURI},
UserID: ctx.User.ID,
UserID: ctx.Doer.ID,
})
if err != nil {
ctx.ServerError("CreateOAuth2Application", err)
@@ -71,7 +71,7 @@ func OAuthApplicationsEdit(ctx *context.Context) {
ID: ctx.ParamsInt64("id"),
Name: form.Name,
RedirectURIs: []string{form.RedirectURI},
UserID: ctx.User.ID,
UserID: ctx.Doer.ID,
}); err != nil {
ctx.ServerError("UpdateOAuth2Application", err)
return
@@ -94,7 +94,7 @@ func OAuthApplicationsRegenerateSecret(ctx *context.Context) {
ctx.ServerError("GetOAuth2ApplicationByID", err)
return
}
if app.UID != ctx.User.ID {
if app.UID != ctx.Doer.ID {
ctx.NotFound("Application not found", nil)
return
}
@@ -119,7 +119,7 @@ func OAuth2ApplicationShow(ctx *context.Context) {
ctx.ServerError("GetOAuth2ApplicationByID", err)
return
}
if app.UID != ctx.User.ID {
if app.UID != ctx.Doer.ID {
ctx.NotFound("Application not found", nil)
return
}
@@ -129,11 +129,11 @@ func OAuth2ApplicationShow(ctx *context.Context) {
// DeleteOAuth2Application deletes the given oauth2 application
func DeleteOAuth2Application(ctx *context.Context) {
if err := auth.DeleteOAuth2Application(ctx.FormInt64("id"), ctx.User.ID); err != nil {
if err := auth.DeleteOAuth2Application(ctx.FormInt64("id"), ctx.Doer.ID); err != nil {
ctx.ServerError("DeleteOAuth2Application", err)
return
}
log.Trace("OAuth2 Application deleted: %s", ctx.User.Name)
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{}{
@@ -143,11 +143,11 @@ func DeleteOAuth2Application(ctx *context.Context) {
// RevokeOAuth2Grant revokes the grant with the given id
func RevokeOAuth2Grant(ctx *context.Context) {
if ctx.User.ID == 0 || ctx.FormInt64("id") == 0 {
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.FormInt64("id"), ctx.User.ID); err != nil {
if err := auth.RevokeOAuth2Grant(ctx.FormInt64("id"), ctx.Doer.ID); err != nil {
ctx.ServerError("RevokeOAuth2Grant", err)
return
}
+36 -36
View File
@@ -17,12 +17,14 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"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/translation/i18n"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
@@ -30,8 +32,6 @@ import (
"code.gitea.io/gitea/services/agit"
"code.gitea.io/gitea/services/forms"
user_service "code.gitea.io/gitea/services/user"
"github.com/unknwon/i18n"
)
const (
@@ -106,24 +106,24 @@ func ProfilePost(ctx *context.Context) {
return
}
if len(form.Name) != 0 && ctx.User.Name != form.Name {
log.Debug("Changing name for %s to %s", ctx.User.Name, form.Name)
if err := HandleUsernameChange(ctx, ctx.User, form.Name); err != nil {
if len(form.Name) != 0 && ctx.Doer.Name != form.Name {
log.Debug("Changing name for %s to %s", ctx.Doer.Name, form.Name)
if err := HandleUsernameChange(ctx, ctx.Doer, form.Name); err != nil {
ctx.Redirect(setting.AppSubURL + "/user/settings")
return
}
ctx.User.Name = form.Name
ctx.User.LowerName = strings.ToLower(form.Name)
ctx.Doer.Name = form.Name
ctx.Doer.LowerName = strings.ToLower(form.Name)
}
ctx.User.FullName = form.FullName
ctx.User.KeepEmailPrivate = form.KeepEmailPrivate
ctx.User.Website = form.Website
ctx.User.Location = form.Location
ctx.User.Description = form.Description
ctx.User.KeepActivityPrivate = form.KeepActivityPrivate
ctx.User.Visibility = form.Visibility
if err := user_model.UpdateUserSetting(ctx.User); err != nil {
ctx.Doer.FullName = form.FullName
ctx.Doer.KeepEmailPrivate = form.KeepEmailPrivate
ctx.Doer.Website = form.Website
ctx.Doer.Location = form.Location
ctx.Doer.Description = form.Description
ctx.Doer.KeepActivityPrivate = form.KeepActivityPrivate
ctx.Doer.Visibility = form.Visibility
if err := user_model.UpdateUserSetting(ctx.Doer); err != nil {
if _, ok := err.(user_model.ErrEmailAlreadyUsed); ok {
ctx.Flash.Error(ctx.Tr("form.email_been_used"))
ctx.Redirect(setting.AppSubURL + "/user/settings")
@@ -134,10 +134,10 @@ func ProfilePost(ctx *context.Context) {
}
// Update the language to the one we just set
middleware.SetLocaleCookie(ctx.Resp, ctx.User.Language, 0)
middleware.SetLocaleCookie(ctx.Resp, ctx.Doer.Language, 0)
log.Trace("User settings updated: %s", ctx.User.Name)
ctx.Flash.Success(i18n.Tr(ctx.User.Language, "settings.update_profile_success"))
log.Trace("User settings updated: %s", ctx.Doer.Name)
ctx.Flash.Success(i18n.Tr(ctx.Doer.Language, "settings.update_profile_success"))
ctx.Redirect(setting.AppSubURL + "/user/settings")
}
@@ -185,7 +185,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser *
}
}
if err := user_model.UpdateUserCols(db.DefaultContext, ctxUser, "avatar", "avatar_email", "use_custom_avatar"); err != nil {
if err := user_model.UpdateUserCols(ctx, ctxUser, "avatar", "avatar_email", "use_custom_avatar"); err != nil {
return fmt.Errorf("UpdateUser: %v", err)
}
@@ -195,7 +195,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser *
// AvatarPost response for change user's avatar request
func AvatarPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.AvatarForm)
if err := UpdateAvatarSetting(ctx, form, ctx.User); err != nil {
if err := UpdateAvatarSetting(ctx, form, ctx.Doer); err != nil {
ctx.Flash.Error(err.Error())
} else {
ctx.Flash.Success(ctx.Tr("settings.update_avatar_success"))
@@ -206,7 +206,7 @@ func AvatarPost(ctx *context.Context) {
// DeleteAvatar render delete avatar page
func DeleteAvatar(ctx *context.Context) {
if err := user_service.DeleteAvatar(ctx.User); err != nil {
if err := user_service.DeleteAvatar(ctx.Doer); err != nil {
ctx.Flash.Error(err.Error())
}
@@ -218,12 +218,12 @@ func Organization(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsOrganization"] = true
opts := models.FindOrgOptions{
opts := organization.FindOrgOptions{
ListOptions: db.ListOptions{
PageSize: setting.UI.Admin.UserPagingNum,
Page: ctx.FormInt("page"),
},
UserID: ctx.User.ID,
UserID: ctx.Doer.ID,
IncludePrivate: ctx.IsSigned,
}
@@ -231,12 +231,12 @@ func Organization(ctx *context.Context) {
opts.Page = 1
}
orgs, err := models.FindOrgs(opts)
orgs, err := organization.FindOrgs(opts)
if err != nil {
ctx.ServerError("FindOrgs", err)
return
}
total, err := models.CountOrgs(opts)
total, err := organization.CountOrgs(opts)
if err != nil {
ctx.ServerError("CountOrgs", err)
return
@@ -268,7 +268,7 @@ func Repos(ctx *context.Context) {
adoptOrDelete := ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories)
ctxUser := ctx.User
ctxUser := ctx.Doer
count := 0
if adoptOrDelete {
@@ -360,7 +360,7 @@ func Appearance(ctx *context.Context) {
ctx.Data["PageIsSettingsAppearance"] = true
var hiddenCommentTypes *big.Int
val, err := user_model.GetUserSetting(ctx.User.ID, user_model.SettingsKeyHiddenCommentTypes)
val, err := user_model.GetUserSetting(ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes)
if err != nil {
ctx.ServerError("GetUserSetting", err)
return
@@ -391,13 +391,13 @@ func UpdateUIThemePost(ctx *context.Context) {
return
}
if err := user_model.UpdateUserTheme(ctx.User, form.Theme); err != nil {
if err := user_model.UpdateUserTheme(ctx.Doer, form.Theme); err != nil {
ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
return
}
log.Trace("Update user theme: %s", ctx.User.Name)
log.Trace("Update user theme: %s", ctx.Doer.Name)
ctx.Flash.Success(ctx.Tr("settings.theme_update_success"))
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
}
@@ -414,31 +414,31 @@ func UpdateUserLang(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
return
}
ctx.User.Language = form.Language
ctx.Doer.Language = form.Language
}
if err := user_model.UpdateUserSetting(ctx.User); err != nil {
if err := user_model.UpdateUserSetting(ctx.Doer); err != nil {
ctx.ServerError("UpdateUserSetting", err)
return
}
// Update the language to the one we just set
middleware.SetLocaleCookie(ctx.Resp, ctx.User.Language, 0)
middleware.SetLocaleCookie(ctx.Resp, ctx.Doer.Language, 0)
log.Trace("User settings updated: %s", ctx.User.Name)
ctx.Flash.Success(i18n.Tr(ctx.User.Language, "settings.update_language_success"))
log.Trace("User settings updated: %s", ctx.Doer.Name)
ctx.Flash.Success(i18n.Tr(ctx.Doer.Language, "settings.update_language_success"))
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
}
// UpdateUserHiddenComments update a user's shown comment types
func UpdateUserHiddenComments(ctx *context.Context) {
err := user_model.SetUserSetting(ctx.User.ID, user_model.SettingsKeyHiddenCommentTypes, forms.UserHiddenCommentTypesFromRequest(ctx).String())
err := user_model.SetUserSetting(ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes, forms.UserHiddenCommentTypesFromRequest(ctx).String())
if err != nil {
ctx.ServerError("SetUserSetting", err)
return
}
log.Trace("User settings updated: %s", ctx.User.Name)
log.Trace("User settings updated: %s", ctx.Doer.Name)
ctx.Flash.Success(ctx.Tr("settings.saved_successfully"))
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
}
+8 -8
View File
@@ -29,7 +29,7 @@ func RegenerateScratchTwoFactor(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsSecurity"] = true
t, err := auth.GetTwoFactorByUID(ctx.User.ID)
t, err := auth.GetTwoFactorByUID(ctx.Doer.ID)
if err != nil {
if auth.IsErrTwoFactorNotEnrolled(err) {
ctx.Flash.Error(ctx.Tr("settings.twofa_not_enrolled"))
@@ -59,7 +59,7 @@ func DisableTwoFactor(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsSecurity"] = true
t, err := auth.GetTwoFactorByUID(ctx.User.ID)
t, err := auth.GetTwoFactorByUID(ctx.Doer.ID)
if err != nil {
if auth.IsErrTwoFactorNotEnrolled(err) {
ctx.Flash.Error(ctx.Tr("settings.twofa_not_enrolled"))
@@ -69,7 +69,7 @@ func DisableTwoFactor(ctx *context.Context) {
return
}
if err = auth.DeleteTwoFactorByID(t.ID, ctx.User.ID); err != nil {
if err = auth.DeleteTwoFactorByID(t.ID, ctx.Doer.ID); err != nil {
if auth.IsErrTwoFactorNotEnrolled(err) {
// There is a potential DB race here - we must have been disabled by another request in the intervening period
ctx.Flash.Success(ctx.Tr("settings.twofa_disabled"))
@@ -100,7 +100,7 @@ func twofaGenerateSecretAndQr(ctx *context.Context) bool {
otpKey, err = totp.Generate(totp.GenerateOpts{
SecretSize: 40,
Issuer: issuer,
AccountName: ctx.User.Name,
AccountName: ctx.Doer.Name,
})
if err != nil {
ctx.ServerError("SettingsTwoFactor: totpGenerate Failed", err)
@@ -146,10 +146,10 @@ func EnrollTwoFactor(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsSecurity"] = true
t, err := auth.GetTwoFactorByUID(ctx.User.ID)
t, err := auth.GetTwoFactorByUID(ctx.Doer.ID)
if t != nil {
// already enrolled - we should redirect back!
log.Warn("Trying to re-enroll %-v in twofa when already enrolled", ctx.User)
log.Warn("Trying to re-enroll %-v in twofa when already enrolled", ctx.Doer)
ctx.Flash.Error(ctx.Tr("settings.twofa_is_enrolled"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
return
@@ -172,7 +172,7 @@ func EnrollTwoFactorPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsSecurity"] = true
t, err := auth.GetTwoFactorByUID(ctx.User.ID)
t, err := auth.GetTwoFactorByUID(ctx.Doer.ID)
if t != nil {
// already enrolled
ctx.Flash.Error(ctx.Tr("settings.twofa_is_enrolled"))
@@ -210,7 +210,7 @@ func EnrollTwoFactorPost(ctx *context.Context) {
}
t = &auth.TwoFactor{
UID: ctx.User.ID,
UID: ctx.Doer.ID,
}
err = t.SetSecret(secret)
if err != nil {
+5 -5
View File
@@ -45,7 +45,7 @@ func OpenIDPost(ctx *context.Context) {
form.Openid = id
log.Trace("Normalized id: " + id)
oids, err := user_model.GetUserOpenIDs(ctx.User.ID)
oids, err := user_model.GetUserOpenIDs(ctx.Doer.ID)
if err != nil {
ctx.ServerError("GetUserOpenIDs", err)
return
@@ -89,7 +89,7 @@ func settingsOpenIDVerify(ctx *context.Context) {
log.Trace("Verified ID: " + id)
oid := &user_model.UserOpenID{UID: ctx.User.ID, URI: id}
oid := &user_model.UserOpenID{UID: ctx.Doer.ID, URI: id}
if err = user_model.AddUserOpenID(oid); err != nil {
if user_model.IsErrOpenIDAlreadyUsed(err) {
ctx.RenderWithErr(ctx.Tr("form.openid_been_used", id), tplSettingsSecurity, &forms.AddOpenIDForm{Openid: id})
@@ -98,7 +98,7 @@ func settingsOpenIDVerify(ctx *context.Context) {
ctx.ServerError("AddUserOpenID", err)
return
}
log.Trace("Associated OpenID %s to user %s", id, ctx.User.Name)
log.Trace("Associated OpenID %s to user %s", id, ctx.Doer.Name)
ctx.Flash.Success(ctx.Tr("settings.add_openid_success"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
@@ -106,11 +106,11 @@ func settingsOpenIDVerify(ctx *context.Context) {
// DeleteOpenID response for delete user's openid
func DeleteOpenID(ctx *context.Context) {
if err := user_model.DeleteUserOpenID(&user_model.UserOpenID{ID: ctx.FormInt64("id"), UID: ctx.User.ID}); err != nil {
if err := user_model.DeleteUserOpenID(&user_model.UserOpenID{ID: ctx.FormInt64("id"), UID: ctx.Doer.ID}); err != nil {
ctx.ServerError("DeleteUserOpenID", err)
return
}
log.Trace("OpenID address deleted: %s", ctx.User.Name)
log.Trace("OpenID address deleted: %s", ctx.Doer.Name)
ctx.Flash.Success(ctx.Tr("settings.openid_deletion_success"))
ctx.JSON(http.StatusOK, map[string]interface{}{
@@ -43,7 +43,7 @@ func DeleteAccountLink(ctx *context.Context) {
if id <= 0 {
ctx.Flash.Error("Account link id is not given")
} else {
if _, err := user_model.RemoveAccountLink(ctx.User, id); err != nil {
if _, err := user_model.RemoveAccountLink(ctx.Doer, id); err != nil {
ctx.Flash.Error("RemoveAccountLink: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("settings.remove_account_link_success"))
@@ -56,28 +56,28 @@ func DeleteAccountLink(ctx *context.Context) {
}
func loadSecurityData(ctx *context.Context) {
enrolled, err := auth.HasTwoFactorByUID(ctx.User.ID)
enrolled, err := auth.HasTwoFactorByUID(ctx.Doer.ID)
if err != nil {
ctx.ServerError("SettingsTwoFactor", err)
return
}
ctx.Data["TOTPEnrolled"] = enrolled
credentials, err := auth.GetWebAuthnCredentialsByUID(ctx.User.ID)
credentials, err := auth.GetWebAuthnCredentialsByUID(ctx.Doer.ID)
if err != nil {
ctx.ServerError("GetWebAuthnCredentialsByUID", err)
return
}
ctx.Data["WebAuthnCredentials"] = credentials
tokens, err := models.ListAccessTokens(models.ListAccessTokensOptions{UserID: ctx.User.ID})
tokens, err := models.ListAccessTokens(models.ListAccessTokensOptions{UserID: ctx.Doer.ID})
if err != nil {
ctx.ServerError("ListAccessTokens", err)
return
}
ctx.Data["Tokens"] = tokens
accountLinks, err := user_model.ListAccountLinks(ctx.User)
accountLinks, err := user_model.ListAccountLinks(ctx.Doer)
if err != nil {
ctx.ServerError("ListAccountLinks", err)
return
@@ -109,7 +109,7 @@ func loadSecurityData(ctx *context.Context) {
}
ctx.Data["AccountLinks"] = sources
openid, err := user_model.GetUserOpenIDs(ctx.User.ID)
openid, err := user_model.GetUserOpenIDs(ctx.Doer.ID)
if err != nil {
ctx.ServerError("GetUserOpenIDs", err)
return

Some files were not shown because too many files have changed in this diff Show More