aboutsummaryrefslogtreecommitdiff
path: root/routers
diff options
context:
space:
mode:
authorAnthony Wang2023-03-12 23:17:11 +0000
committerAnthony Wang2023-03-12 23:19:57 +0000
commitdbc3eb7fa071307e623fde961bfdff0894856948 (patch)
tree8961dc6a935d9ee89f5adf680a142d36900aaebb /routers
parentb4640101f3c8938ed689743606a79601201141ca (diff)
parente72290fd9aeb77a47311483d1d565e428ce40cd9 (diff)
Merge remote-tracking branch 'origin/main' into forgejo-federation
Diffstat (limited to 'routers')
-rw-r--r--routers/api/actions/runner/runner.go8
-rw-r--r--routers/api/v1/activitypub/create.go2
-rw-r--r--routers/api/v1/admin/adopt.go6
-rw-r--r--routers/api/v1/admin/hooks.go5
-rw-r--r--routers/api/v1/api.go7
-rw-r--r--routers/api/v1/org/hook.go79
-rw-r--r--routers/api/v1/org/label.go33
-rw-r--r--routers/api/v1/repo/branch.go2
-rw-r--r--routers/api/v1/repo/hook.go6
-rw-r--r--routers/api/v1/repo/issue_attachment.go2
-rw-r--r--routers/api/v1/repo/issue_comment_attachment.go2
-rw-r--r--routers/api/v1/repo/label.go52
-rw-r--r--routers/api/v1/repo/notes.go12
-rw-r--r--routers/api/v1/repo/pull.go2
-rw-r--r--routers/api/v1/repo/pull_review.go4
-rw-r--r--routers/api/v1/repo/release_attachment.go2
-rw-r--r--routers/api/v1/repo/repo.go11
-rw-r--r--routers/api/v1/user/hook.go154
-rw-r--r--routers/api/v1/utils/hook.go89
-rw-r--r--routers/common/middleware.go35
-rw-r--r--routers/common/middleware_test.go70
-rw-r--r--routers/init.go2
-rw-r--r--routers/install/install.go54
-rw-r--r--routers/install/routes.go15
-rw-r--r--routers/private/serv.go2
-rw-r--r--routers/web/admin/auths.go23
-rw-r--r--routers/web/admin/repos.go6
-rw-r--r--routers/web/base.go7
-rw-r--r--routers/web/explore/repo.go1
-rw-r--r--routers/web/healthcheck/check.go2
-rw-r--r--routers/web/org/home.go1
-rw-r--r--routers/web/org/org_labels.go5
-rw-r--r--routers/web/org/projects.go30
-rw-r--r--routers/web/org/setting.go10
-rw-r--r--routers/web/repo/actions/view.go24
-rw-r--r--routers/web/repo/attachment.go2
-rw-r--r--routers/web/repo/branch.go2
-rw-r--r--routers/web/repo/editor.go2
-rw-r--r--routers/web/repo/http.go4
-rw-r--r--routers/web/repo/issue.go40
-rw-r--r--routers/web/repo/issue_label.go5
-rw-r--r--routers/web/repo/issue_stopwatch.go14
-rw-r--r--routers/web/repo/lfs.go2
-rw-r--r--routers/web/repo/projects.go7
-rw-r--r--routers/web/repo/pull.go4
-rw-r--r--routers/web/repo/pull_review.go2
-rw-r--r--routers/web/repo/repo.go6
-rw-r--r--routers/web/repo/setting.go16
-rw-r--r--routers/web/repo/setting_protected_branch.go2
-rw-r--r--routers/web/repo/view.go2
-rw-r--r--routers/web/repo/webhook.go67
-rw-r--r--routers/web/shared/user/header.go2
-rw-r--r--routers/web/user/avatar.go2
-rw-r--r--routers/web/user/code.go1
-rw-r--r--routers/web/user/profile.go1
-rw-r--r--routers/web/user/setting/adopt.go4
-rw-r--r--routers/web/user/setting/webhooks.go48
-rw-r--r--routers/web/web.go163
58 files changed, 771 insertions, 392 deletions
diff --git a/routers/api/actions/runner/runner.go b/routers/api/actions/runner/runner.go
index 7dbab9da0..07657c912 100644
--- a/routers/api/actions/runner/runner.go
+++ b/routers/api/actions/runner/runner.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/util"
actions_service "code.gitea.io/gitea/services/actions"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
@@ -51,13 +52,14 @@ func (s *Service) Register(
}
if runnerToken.IsActive {
- return nil, errors.New("runner token has already activated")
+ return nil, errors.New("runner token has already been activated")
}
// create new runner
+ name, _ := util.SplitStringAtByteN(req.Msg.Name, 255)
runner := &actions_model.ActionRunner{
UUID: gouuid.New().String(),
- Name: req.Msg.Name,
+ Name: name,
OwnerID: runnerToken.OwnerID,
RepoID: runnerToken.RepoID,
AgentLabels: req.Msg.AgentLabels,
@@ -148,7 +150,7 @@ func (s *Service) UpdateTask(
}
if err := actions_service.CreateCommitStatus(ctx, task.Job); err != nil {
- log.Error("Update commit status failed: %v", err)
+ log.Error("Update commit status for job %v failed: %v", task.Job.ID, err)
// go on
}
diff --git a/routers/api/v1/activitypub/create.go b/routers/api/v1/activitypub/create.go
index b8f005970..591671c0c 100644
--- a/routers/api/v1/activitypub/create.go
+++ b/routers/api/v1/activitypub/create.go
@@ -142,7 +142,7 @@ func createRepository(ctx context.Context, repository *forgefed.Repository) erro
return err
}
- repo, err := repo_service.CreateRepository(user, user, repo_module.CreateRepoOptions{
+ repo, err := repo_service.CreateRepository(ctx, user, user, repo_module.CreateRepoOptions{
Name: repository.Name.String(),
OriginalURL: repository.GetLink().String(),
})
diff --git a/routers/api/v1/admin/adopt.go b/routers/api/v1/admin/adopt.go
index 0e4e498e9..47fd0ef3c 100644
--- a/routers/api/v1/admin/adopt.go
+++ b/routers/api/v1/admin/adopt.go
@@ -45,7 +45,7 @@ func ListUnadoptedRepositories(ctx *context.APIContext) {
if listOptions.Page == 0 {
listOptions.Page = 1
}
- repoNames, count, err := repo_service.ListUnadoptedRepositories(ctx.FormString("query"), &listOptions)
+ repoNames, count, err := repo_service.ListUnadoptedRepositories(ctx, ctx.FormString("query"), &listOptions)
if err != nil {
ctx.InternalServerError(err)
return
@@ -109,7 +109,7 @@ func AdoptRepository(ctx *context.APIContext) {
ctx.NotFound()
return
}
- if _, err := repo_service.AdoptRepository(ctx.Doer, ctxUser, repo_module.CreateRepoOptions{
+ if _, err := repo_service.AdoptRepository(ctx, ctx.Doer, ctxUser, repo_module.CreateRepoOptions{
Name: repoName,
IsPrivate: true,
}); err != nil {
@@ -172,7 +172,7 @@ func DeleteUnadoptedRepository(ctx *context.APIContext) {
return
}
- if err := repo_service.DeleteUnadoptedRepository(ctx.Doer, ctxUser, repoName); err != nil {
+ if err := repo_service.DeleteUnadoptedRepository(ctx, ctx.Doer, ctxUser, repoName); err != nil {
ctx.InternalServerError(err)
return
}
diff --git a/routers/api/v1/admin/hooks.go b/routers/api/v1/admin/hooks.go
index 2aed4139f..8264503c9 100644
--- a/routers/api/v1/admin/hooks.go
+++ b/routers/api/v1/admin/hooks.go
@@ -105,10 +105,7 @@ func CreateHook(ctx *context.APIContext) {
// "$ref": "#/responses/Hook"
form := web.GetForm(ctx).(*api.CreateHookOption)
- // TODO in body params
- if !utils.CheckCreateHookOption(ctx, form) {
- return
- }
+
utils.AddSystemHook(ctx, form)
}
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 861c17175..e1f34199a 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -848,6 +848,13 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Get("/stopwatches", reqToken(auth_model.AccessTokenScopeRepo), repo.GetStopwatches)
m.Get("/subscriptions", reqToken(auth_model.AccessTokenScopeRepo), user.GetMyWatchedRepos)
m.Get("/teams", reqToken(auth_model.AccessTokenScopeRepo), org.ListUserTeams)
+ m.Group("/hooks", func() {
+ m.Combo("").Get(user.ListHooks).
+ Post(bind(api.CreateHookOption{}), user.CreateHook)
+ m.Combo("/{id}").Get(user.GetHook).
+ Patch(bind(api.EditHookOption{}), user.EditHook).
+ Delete(user.DeleteHook)
+ }, reqToken(auth_model.AccessTokenScopeAdminUserHook), reqWebhooksEnabled())
}, reqToken(""))
// Repositories
diff --git a/routers/api/v1/org/hook.go b/routers/api/v1/org/hook.go
index 4e435c959..a6ea618a7 100644
--- a/routers/api/v1/org/hook.go
+++ b/routers/api/v1/org/hook.go
@@ -6,7 +6,6 @@ package org
import (
"net/http"
- webhook_model "code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
@@ -39,34 +38,10 @@ func ListHooks(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/HookList"
- opts := &webhook_model.ListWebhookOptions{
- ListOptions: utils.GetListOptions(ctx),
- OrgID: ctx.Org.Organization.ID,
- }
-
- count, err := webhook_model.CountWebhooksByOpts(opts)
- if err != nil {
- ctx.InternalServerError(err)
- return
- }
-
- orgHooks, err := webhook_model.ListWebhooksByOpts(ctx, opts)
- if err != nil {
- ctx.InternalServerError(err)
- return
- }
-
- hooks := make([]*api.Hook, len(orgHooks))
- for i, hook := range orgHooks {
- hooks[i], err = webhook_service.ToHook(ctx.Org.Organization.AsUser().HomeLink(), hook)
- if err != nil {
- ctx.InternalServerError(err)
- return
- }
- }
-
- ctx.SetTotalCountHeader(count)
- ctx.JSON(http.StatusOK, hooks)
+ utils.ListOwnerHooks(
+ ctx,
+ ctx.ContextUser,
+ )
}
// GetHook get an organization's hook by id
@@ -92,14 +67,12 @@ func GetHook(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/Hook"
- org := ctx.Org.Organization
- hookID := ctx.ParamsInt64(":id")
- hook, err := utils.GetOrgHook(ctx, org.ID, hookID)
+ hook, err := utils.GetOwnerHook(ctx, ctx.ContextUser.ID, ctx.ParamsInt64("id"))
if err != nil {
return
}
- apiHook, err := webhook_service.ToHook(org.AsUser().HomeLink(), hook)
+ apiHook, err := webhook_service.ToHook(ctx.ContextUser.HomeLink(), hook)
if err != nil {
ctx.InternalServerError(err)
return
@@ -131,15 +104,14 @@ func CreateHook(ctx *context.APIContext) {
// "201":
// "$ref": "#/responses/Hook"
- form := web.GetForm(ctx).(*api.CreateHookOption)
- // TODO in body params
- if !utils.CheckCreateHookOption(ctx, form) {
- return
- }
- utils.AddOrgHook(ctx, form)
+ utils.AddOwnerHook(
+ ctx,
+ ctx.ContextUser,
+ web.GetForm(ctx).(*api.CreateHookOption),
+ )
}
-// EditHook modify a hook of a repository
+// EditHook modify a hook of an organization
func EditHook(ctx *context.APIContext) {
// swagger:operation PATCH /orgs/{org}/hooks/{id} organization orgEditHook
// ---
@@ -168,11 +140,12 @@ func EditHook(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/Hook"
- form := web.GetForm(ctx).(*api.EditHookOption)
-
- // TODO in body params
- hookID := ctx.ParamsInt64(":id")
- utils.EditOrgHook(ctx, form, hookID)
+ utils.EditOwnerHook(
+ ctx,
+ ctx.ContextUser,
+ web.GetForm(ctx).(*api.EditHookOption),
+ ctx.ParamsInt64("id"),
+ )
}
// DeleteHook delete a hook of an organization
@@ -198,15 +171,9 @@ func DeleteHook(ctx *context.APIContext) {
// "204":
// "$ref": "#/responses/empty"
- org := ctx.Org.Organization
- hookID := ctx.ParamsInt64(":id")
- if err := webhook_model.DeleteWebhookByOrgID(org.ID, hookID); err != nil {
- if webhook_model.IsErrWebhookNotExist(err) {
- ctx.NotFound()
- } else {
- ctx.Error(http.StatusInternalServerError, "DeleteWebhookByOrgID", err)
- }
- return
- }
- ctx.Status(http.StatusNoContent)
+ utils.DeleteOwnerHook(
+ ctx,
+ ctx.ContextUser,
+ ctx.ParamsInt64("id"),
+ )
}
diff --git a/routers/api/v1/org/label.go b/routers/api/v1/org/label.go
index 938fe79df..183c1e6cc 100644
--- a/routers/api/v1/org/label.go
+++ b/routers/api/v1/org/label.go
@@ -4,13 +4,13 @@
package org
import (
- "fmt"
"net/http"
"strconv"
"strings"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/label"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
@@ -84,13 +84,12 @@ func CreateLabel(ctx *context.APIContext) {
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateLabelOption)
form.Color = strings.Trim(form.Color, " ")
- if len(form.Color) == 6 {
- form.Color = "#" + form.Color
- }
- if !issues_model.LabelColorPattern.MatchString(form.Color) {
- ctx.Error(http.StatusUnprocessableEntity, "ColorPattern", fmt.Errorf("bad color code: %s", form.Color))
+ color, err := label.NormalizeColor(form.Color)
+ if err != nil {
+ ctx.Error(http.StatusUnprocessableEntity, "Color", err)
return
}
+ form.Color = color
label := &issues_model.Label{
Name: form.Name,
@@ -183,7 +182,7 @@ func EditLabel(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.EditLabelOption)
- label, err := issues_model.GetLabelInOrgByID(ctx, ctx.Org.Organization.ID, ctx.ParamsInt64(":id"))
+ l, err := issues_model.GetLabelInOrgByID(ctx, ctx.Org.Organization.ID, ctx.ParamsInt64(":id"))
if err != nil {
if issues_model.IsErrOrgLabelNotExist(err) {
ctx.NotFound()
@@ -194,30 +193,28 @@ func EditLabel(ctx *context.APIContext) {
}
if form.Name != nil {
- label.Name = *form.Name
+ l.Name = *form.Name
}
if form.Exclusive != nil {
- label.Exclusive = *form.Exclusive
+ l.Exclusive = *form.Exclusive
}
if form.Color != nil {
- label.Color = strings.Trim(*form.Color, " ")
- if len(label.Color) == 6 {
- label.Color = "#" + label.Color
- }
- if !issues_model.LabelColorPattern.MatchString(label.Color) {
- ctx.Error(http.StatusUnprocessableEntity, "ColorPattern", fmt.Errorf("bad color code: %s", label.Color))
+ color, err := label.NormalizeColor(*form.Color)
+ if err != nil {
+ ctx.Error(http.StatusUnprocessableEntity, "Color", err)
return
}
+ l.Color = color
}
if form.Description != nil {
- label.Description = *form.Description
+ l.Description = *form.Description
}
- if err := issues_model.UpdateLabel(label); err != nil {
+ if err := issues_model.UpdateLabel(l); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateLabel", err)
return
}
- ctx.JSON(http.StatusOK, convert.ToLabel(label, nil, ctx.Org.Organization.AsUser()))
+ ctx.JSON(http.StatusOK, convert.ToLabel(l, nil, ctx.Org.Organization.AsUser()))
}
// DeleteLabel delete a label for an organization
diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go
index 8acaeaffb..dff47fbcf 100644
--- a/routers/api/v1/repo/branch.go
+++ b/routers/api/v1/repo/branch.go
@@ -118,7 +118,7 @@ func DeleteBranch(ctx *context.APIContext) {
branchName := ctx.Params("*")
- if err := repo_service.DeleteBranch(ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
+ if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
switch {
case git.IsErrBranchNotExist(err):
ctx.NotFound(err)
diff --git a/routers/api/v1/repo/hook.go b/routers/api/v1/repo/hook.go
index fd54d1f74..39d83912b 100644
--- a/routers/api/v1/repo/hook.go
+++ b/routers/api/v1/repo/hook.go
@@ -223,12 +223,8 @@ func CreateHook(ctx *context.APIContext) {
// responses:
// "201":
// "$ref": "#/responses/Hook"
- form := web.GetForm(ctx).(*api.CreateHookOption)
- if !utils.CheckCreateHookOption(ctx, form) {
- return
- }
- utils.AddRepoHook(ctx, form)
+ utils.AddRepoHook(ctx, web.GetForm(ctx).(*api.CreateHookOption))
}
// EditHook modify a hook of a repository
diff --git a/routers/api/v1/repo/issue_attachment.go b/routers/api/v1/repo/issue_attachment.go
index 8cbd2e11b..92e113868 100644
--- a/routers/api/v1/repo/issue_attachment.go
+++ b/routers/api/v1/repo/issue_attachment.go
@@ -176,7 +176,7 @@ func CreateIssueAttachment(ctx *context.APIContext) {
filename = query
}
- attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, &repo_model.Attachment{
+ attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, header.Size, &repo_model.Attachment{
Name: filename,
UploaderID: ctx.Doer.ID,
RepoID: ctx.Repo.Repository.ID,
diff --git a/routers/api/v1/repo/issue_comment_attachment.go b/routers/api/v1/repo/issue_comment_attachment.go
index 4c8452380..6fe4dbc97 100644
--- a/routers/api/v1/repo/issue_comment_attachment.go
+++ b/routers/api/v1/repo/issue_comment_attachment.go
@@ -180,7 +180,7 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) {
filename = query
}
- attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, &repo_model.Attachment{
+ attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, header.Size, &repo_model.Attachment{
Name: filename,
UploaderID: ctx.Doer.ID,
RepoID: ctx.Repo.Repository.ID,
diff --git a/routers/api/v1/repo/label.go b/routers/api/v1/repo/label.go
index a06d26e83..6cb231f59 100644
--- a/routers/api/v1/repo/label.go
+++ b/routers/api/v1/repo/label.go
@@ -5,13 +5,12 @@
package repo
import (
- "fmt"
"net/http"
"strconv"
- "strings"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/label"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
@@ -93,14 +92,14 @@ func GetLabel(ctx *context.APIContext) {
// "$ref": "#/responses/Label"
var (
- label *issues_model.Label
- err error
+ l *issues_model.Label
+ err error
)
strID := ctx.Params(":id")
if intID, err2 := strconv.ParseInt(strID, 10, 64); err2 != nil {
- label, err = issues_model.GetLabelInRepoByName(ctx, ctx.Repo.Repository.ID, strID)
+ l, err = issues_model.GetLabelInRepoByName(ctx, ctx.Repo.Repository.ID, strID)
} else {
- label, err = issues_model.GetLabelInRepoByID(ctx, ctx.Repo.Repository.ID, intID)
+ l, err = issues_model.GetLabelInRepoByID(ctx, ctx.Repo.Repository.ID, intID)
}
if err != nil {
if issues_model.IsErrRepoLabelNotExist(err) {
@@ -111,7 +110,7 @@ func GetLabel(ctx *context.APIContext) {
return
}
- ctx.JSON(http.StatusOK, convert.ToLabel(label, ctx.Repo.Repository, nil))
+ ctx.JSON(http.StatusOK, convert.ToLabel(l, ctx.Repo.Repository, nil))
}
// CreateLabel create a label for a repository
@@ -145,28 +144,27 @@ func CreateLabel(ctx *context.APIContext) {
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateLabelOption)
- form.Color = strings.Trim(form.Color, " ")
- if len(form.Color) == 6 {
- form.Color = "#" + form.Color
- }
- if !issues_model.LabelColorPattern.MatchString(form.Color) {
- ctx.Error(http.StatusUnprocessableEntity, "ColorPattern", fmt.Errorf("bad color code: %s", form.Color))
+
+ color, err := label.NormalizeColor(form.Color)
+ if err != nil {
+ ctx.Error(http.StatusUnprocessableEntity, "StringToColor", err)
return
}
+ form.Color = color
- label := &issues_model.Label{
+ l := &issues_model.Label{
Name: form.Name,
Exclusive: form.Exclusive,
Color: form.Color,
RepoID: ctx.Repo.Repository.ID,
Description: form.Description,
}
- if err := issues_model.NewLabel(ctx, label); err != nil {
+ if err := issues_model.NewLabel(ctx, l); err != nil {
ctx.Error(http.StatusInternalServerError, "NewLabel", err)
return
}
- ctx.JSON(http.StatusCreated, convert.ToLabel(label, ctx.Repo.Repository, nil))
+ ctx.JSON(http.StatusCreated, convert.ToLabel(l, ctx.Repo.Repository, nil))
}
// EditLabel modify a label for a repository
@@ -206,7 +204,7 @@ func EditLabel(ctx *context.APIContext) {
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.EditLabelOption)
- label, err := issues_model.GetLabelInRepoByID(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
+ l, err := issues_model.GetLabelInRepoByID(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
if err != nil {
if issues_model.IsErrRepoLabelNotExist(err) {
ctx.NotFound()
@@ -217,30 +215,28 @@ func EditLabel(ctx *context.APIContext) {
}
if form.Name != nil {
- label.Name = *form.Name
+ l.Name = *form.Name
}
if form.Exclusive != nil {
- label.Exclusive = *form.Exclusive
+ l.Exclusive = *form.Exclusive
}
if form.Color != nil {
- label.Color = strings.Trim(*form.Color, " ")
- if len(label.Color) == 6 {
- label.Color = "#" + label.Color
- }
- if !issues_model.LabelColorPattern.MatchString(label.Color) {
- ctx.Error(http.StatusUnprocessableEntity, "ColorPattern", fmt.Errorf("bad color code: %s", label.Color))
+ color, err := label.NormalizeColor(*form.Color)
+ if err != nil {
+ ctx.Error(http.StatusUnprocessableEntity, "StringToColor", err)
return
}
+ l.Color = color
}
if form.Description != nil {
- label.Description = *form.Description
+ l.Description = *form.Description
}
- if err := issues_model.UpdateLabel(label); err != nil {
+ if err := issues_model.UpdateLabel(l); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateLabel", err)
return
}
- ctx.JSON(http.StatusOK, convert.ToLabel(label, ctx.Repo.Repository, nil))
+ ctx.JSON(http.StatusOK, convert.ToLabel(l, ctx.Repo.Repository, nil))
}
// DeleteLabel delete a label for a repository
diff --git a/routers/api/v1/repo/notes.go b/routers/api/v1/repo/notes.go
index 2d1f3291f..74969f2ca 100644
--- a/routers/api/v1/repo/notes.go
+++ b/routers/api/v1/repo/notes.go
@@ -58,8 +58,18 @@ func getNote(ctx *context.APIContext, identifier string) {
return
}
+ commitSHA, err := ctx.Repo.GitRepo.ConvertToSHA1(identifier)
+ if err != nil {
+ if git.IsErrNotExist(err) {
+ ctx.NotFound(err)
+ } else {
+ ctx.Error(http.StatusInternalServerError, "ConvertToSHA1", err)
+ }
+ return
+ }
+
var note git.Note
- if err := git.GetNote(ctx, ctx.Repo.GitRepo, identifier, &note); err != nil {
+ if err := git.GetNote(ctx, ctx.Repo.GitRepo, commitSHA.String(), &note); err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound(identifier)
return
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index 84eebeb94..9b5ec0b3f 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -904,7 +904,7 @@ func MergePullRequest(ctx *context.APIContext) {
}
defer headRepo.Close()
}
- if err := repo_service.DeleteBranch(ctx.Doer, pr.HeadRepo, headRepo, pr.HeadBranch); err != nil {
+ if err := repo_service.DeleteBranch(ctx, ctx.Doer, pr.HeadRepo, headRepo, pr.HeadBranch); err != nil {
switch {
case git.IsErrBranchNotExist(err):
ctx.NotFound(err)
diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go
index f6acaa780..8f4b9dafe 100644
--- a/routers/api/v1/repo/pull_review.go
+++ b/routers/api/v1/repo/pull_review.go
@@ -268,7 +268,7 @@ func DeletePullReview(ctx *context.APIContext) {
ctx.Status(http.StatusNoContent)
}
-// CreatePullReview create a review to an pull request
+// CreatePullReview create a review to a pull request
func CreatePullReview(ctx *context.APIContext) {
// swagger:operation POST /repos/{owner}/{repo}/pulls/{index}/reviews repository repoCreatePullReview
// ---
@@ -360,7 +360,7 @@ func CreatePullReview(ctx *context.APIContext) {
line,
c.Body,
c.Path,
- true, // is review
+ true, // pending review
0, // no reply
opts.CommitID,
); err != nil {
diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go
index 597578aac..305b2808d 100644
--- a/routers/api/v1/repo/release_attachment.go
+++ b/routers/api/v1/repo/release_attachment.go
@@ -194,7 +194,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
}
// Create a new attachment and save the file
- attach, err := attachment.UploadAttachment(file, setting.Repository.Release.AllowedTypes, &repo_model.Attachment{
+ attach, err := attachment.UploadAttachment(file, setting.Repository.Release.AllowedTypes, header.Size, &repo_model.Attachment{
Name: filename,
UploaderID: ctx.Doer.ID,
RepoID: release.RepoID,
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index 0395198e2..397600dc5 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -19,6 +19,7 @@ import (
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/label"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
@@ -230,7 +231,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
if opt.AutoInit && opt.Readme == "" {
opt.Readme = "Default"
}
- repo, err := repo_service.CreateRepository(ctx.Doer, owner, repo_module.CreateRepoOptions{
+ repo, err := repo_service.CreateRepository(ctx, ctx.Doer, owner, repo_module.CreateRepoOptions{
Name: opt.Name,
Description: opt.Description,
IssueLabels: opt.IssueLabels,
@@ -248,7 +249,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
} else if db.IsErrNameReserved(err) ||
db.IsErrNamePatternNotAllowed(err) ||
- repo_module.IsErrIssueLabelTemplateLoad(err) {
+ label.IsErrTemplateLoad(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(http.StatusInternalServerError, "CreateRepository", err)
@@ -393,7 +394,7 @@ func Generate(ctx *context.APIContext) {
}
}
- repo, err := repo_service.GenerateRepository(ctx.Doer, ctxUser, ctx.Repo.Repository, opts)
+ repo, err := repo_service.GenerateRepository(ctx, ctx.Doer, ctxUser, ctx.Repo.Repository, opts)
if err != nil {
if repo_model.IsErrRepoAlreadyExist(err) {
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
@@ -637,7 +638,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
}
// Check if repository name has been changed and not just a case change
if repo.LowerName != strings.ToLower(newRepoName) {
- if err := repo_service.ChangeRepositoryName(ctx.Doer, repo, newRepoName); err != nil {
+ if err := repo_service.ChangeRepositoryName(ctx, ctx.Doer, repo, newRepoName); err != nil {
switch {
case repo_model.IsErrRepoAlreadyExist(err):
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name is already taken [name: %s]", newRepoName), err)
@@ -714,7 +715,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
repo.DefaultBranch = *opts.DefaultBranch
}
- if err := repo_service.UpdateRepository(repo, visibilityChanged); err != nil {
+ if err := repo_service.UpdateRepository(ctx, repo, visibilityChanged); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateRepository", err)
return err
}
diff --git a/routers/api/v1/user/hook.go b/routers/api/v1/user/hook.go
new file mode 100644
index 000000000..50be519c8
--- /dev/null
+++ b/routers/api/v1/user/hook.go
@@ -0,0 +1,154 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package user
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/modules/context"
+ api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/web"
+ "code.gitea.io/gitea/routers/api/v1/utils"
+ webhook_service "code.gitea.io/gitea/services/webhook"
+)
+
+// ListHooks list the authenticated user's webhooks
+func ListHooks(ctx *context.APIContext) {
+ // swagger:operation GET /user/hooks user userListHooks
+ // ---
+ // summary: List the authenticated user's webhooks
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: page
+ // in: query
+ // description: page number of results to return (1-based)
+ // type: integer
+ // - name: limit
+ // in: query
+ // description: page size of results
+ // type: integer
+ // responses:
+ // "200":
+ // "$ref": "#/responses/HookList"
+
+ utils.ListOwnerHooks(
+ ctx,
+ ctx.Doer,
+ )
+}
+
+// GetHook get the authenticated user's hook by id
+func GetHook(ctx *context.APIContext) {
+ // swagger:operation GET /user/hooks/{id} user userGetHook
+ // ---
+ // summary: Get a hook
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: id
+ // in: path
+ // description: id of the hook to get
+ // type: integer
+ // format: int64
+ // required: true
+ // responses:
+ // "200":
+ // "$ref": "#/responses/Hook"
+
+ hook, err := utils.GetOwnerHook(ctx, ctx.Doer.ID, ctx.ParamsInt64("id"))
+ if err != nil {
+ return
+ }
+
+ apiHook, err := webhook_service.ToHook(ctx.Doer.HomeLink(), hook)
+ if err != nil {
+ ctx.InternalServerError(err)
+ return
+ }
+ ctx.JSON(http.StatusOK, apiHook)
+}
+
+// CreateHook create a hook for the authenticated user
+func CreateHook(ctx *context.APIContext) {
+ // swagger:operation POST /user/hooks user userCreateHook
+ // ---
+ // summary: Create a hook
+ // consumes:
+ // - application/json
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: body
+ // in: body
+ // required: true
+ // schema:
+ // "$ref": "#/definitions/CreateHookOption"
+ // responses:
+ // "201":
+ // "$ref": "#/responses/Hook"
+
+ utils.AddOwnerHook(
+ ctx,
+ ctx.Doer,
+ web.GetForm(ctx).(*api.CreateHookOption),
+ )
+}
+
+// EditHook modify a hook of the authenticated user
+func EditHook(ctx *context.APIContext) {
+ // swagger:operation PATCH /user/hooks/{id} user userEditHook
+ // ---
+ // summary: Update a hook
+ // consumes:
+ // - application/json
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: id
+ // in: path
+ // description: id of the hook to update
+ // type: integer
+ // format: int64
+ // required: true
+ // - name: body
+ // in: body
+ // schema:
+ // "$ref": "#/definitions/EditHookOption"
+ // responses:
+ // "200":
+ // "$ref": "#/responses/Hook"
+
+ utils.EditOwnerHook(
+ ctx,
+ ctx.Doer,
+ web.GetForm(ctx).(*api.EditHookOption),
+ ctx.ParamsInt64("id"),
+ )
+}
+
+// DeleteHook delete a hook of the authenticated user
+func DeleteHook(ctx *context.APIContext) {
+ // swagger:operation DELETE /user/hooks/{id} user userDeleteHook
+ // ---
+ // summary: Delete a hook
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: id
+ // in: path
+ // description: id of the hook to delete
+ // type: integer
+ // format: int64
+ // required: true
+ // responses:
+ // "204":
+ // "$ref": "#/responses/empty"
+
+ utils.DeleteOwnerHook(
+ ctx,
+ ctx.Doer,
+ ctx.ParamsInt64("id"),
+ )
+}
diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go
index f6aaf74af..44625cc9b 100644
--- a/routers/api/v1/utils/hook.go
+++ b/routers/api/v1/utils/hook.go
@@ -8,6 +8,7 @@ import (
"net/http"
"strings"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/json"
@@ -18,15 +19,46 @@ import (
webhook_service "code.gitea.io/gitea/services/webhook"
)
-// GetOrgHook get an organization's webhook. If there is an error, write to
-// `ctx` accordingly and return the error
-func GetOrgHook(ctx *context.APIContext, orgID, hookID int64) (*webhook.Webhook, error) {
- w, err := webhook.GetWebhookByOrgID(orgID, hookID)
+// ListOwnerHooks lists the webhooks of the provided owner
+func ListOwnerHooks(ctx *context.APIContext, owner *user_model.User) {
+ opts := &webhook.ListWebhookOptions{
+ ListOptions: GetListOptions(ctx),
+ OwnerID: owner.ID,
+ }
+
+ count, err := webhook.CountWebhooksByOpts(opts)
+ if err != nil {
+ ctx.InternalServerError(err)
+ return
+ }
+
+ hooks, err := webhook.ListWebhooksByOpts(ctx, opts)
+ if err != nil {
+ ctx.InternalServerError(err)
+ return
+ }
+
+ apiHooks := make([]*api.Hook, len(hooks))
+ for i, hook := range hooks {
+ apiHooks[i], err = webhook_service.ToHook(owner.HomeLink(), hook)
+ if err != nil {
+ ctx.InternalServerError(err)
+ return
+ }
+ }
+
+ ctx.SetTotalCountHeader(count)
+ ctx.JSON(http.StatusOK, apiHooks)
+}
+
+// GetOwnerHook gets an user or organization webhook. Errors are written to ctx.
+func GetOwnerHook(ctx *context.APIContext, ownerID, hookID int64) (*webhook.Webhook, error) {
+ w, err := webhook.GetWebhookByOwnerID(ownerID, hookID)
if err != nil {
if webhook.IsErrWebhookNotExist(err) {
ctx.NotFound()
} else {
- ctx.Error(http.StatusInternalServerError, "GetWebhookByOrgID", err)
+ ctx.Error(http.StatusInternalServerError, "GetWebhookByOwnerID", err)
}
return nil, err
}
@@ -48,9 +80,9 @@ func GetRepoHook(ctx *context.APIContext, repoID, hookID int64) (*webhook.Webhoo
return w, nil
}
-// CheckCreateHookOption check if a CreateHookOption form is valid. If invalid,
+// checkCreateHookOption check if a CreateHookOption form is valid. If invalid,
// write the appropriate error to `ctx`. Return whether the form is valid
-func CheckCreateHookOption(ctx *context.APIContext, form *api.CreateHookOption) bool {
+func checkCreateHookOption(ctx *context.APIContext, form *api.CreateHookOption) bool {
if !webhook_service.IsValidHookTaskType(form.Type) {
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("Invalid hook type: %s", form.Type))
return false
@@ -81,14 +113,13 @@ func AddSystemHook(ctx *context.APIContext, form *api.CreateHookOption) {
}
}
-// AddOrgHook add a hook to an organization. Writes to `ctx` accordingly
-func AddOrgHook(ctx *context.APIContext, form *api.CreateHookOption) {
- org := ctx.Org.Organization
- hook, ok := addHook(ctx, form, org.ID, 0)
+// AddOwnerHook adds a hook to an user or organization
+func AddOwnerHook(ctx *context.APIContext, owner *user_model.User, form *api.CreateHookOption) {
+ hook, ok := addHook(ctx, form, owner.ID, 0)
if !ok {
return
}
- apiHook, ok := toAPIHook(ctx, org.AsUser().HomeLink(), hook)
+ apiHook, ok := toAPIHook(ctx, owner.HomeLink(), hook)
if !ok {
return
}
@@ -128,14 +159,18 @@ func pullHook(events []string, event string) bool {
return util.SliceContainsString(events, event, true) || util.SliceContainsString(events, string(webhook_module.HookEventPullRequest), true)
}
-// addHook add the hook specified by `form`, `orgID` and `repoID`. If there is
+// addHook add the hook specified by `form`, `ownerID` and `repoID`. If there is
// an error, write to `ctx` accordingly. Return (webhook, ok)
-func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID int64) (*webhook.Webhook, bool) {
+func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoID int64) (*webhook.Webhook, bool) {
+ if !checkCreateHookOption(ctx, form) {
+ return nil, false
+ }
+
if len(form.Events) == 0 {
form.Events = []string{"push"}
}
w := &webhook.Webhook{
- OrgID: orgID,
+ OwnerID: ownerID,
RepoID: repoID,
URL: form.Config["url"],
ContentType: webhook.ToHookContentType(form.Config["content_type"]),
@@ -234,21 +269,20 @@ func EditSystemHook(ctx *context.APIContext, form *api.EditHookOption, hookID in
ctx.JSON(http.StatusOK, h)
}
-// EditOrgHook edit webhook `w` according to `form`. Writes to `ctx` accordingly
-func EditOrgHook(ctx *context.APIContext, form *api.EditHookOption, hookID int64) {
- org := ctx.Org.Organization
- hook, err := GetOrgHook(ctx, org.ID, hookID)
+// EditOwnerHook updates a webhook of an user or organization
+func EditOwnerHook(ctx *context.APIContext, owner *user_model.User, form *api.EditHookOption, hookID int64) {
+ hook, err := GetOwnerHook(ctx, owner.ID, hookID)
if err != nil {
return
}
if !editHook(ctx, form, hook) {
return
}
- updated, err := GetOrgHook(ctx, org.ID, hookID)
+ updated, err := GetOwnerHook(ctx, owner.ID, hookID)
if err != nil {
return
}
- apiHook, ok := toAPIHook(ctx, org.AsUser().HomeLink(), updated)
+ apiHook, ok := toAPIHook(ctx, owner.HomeLink(), updated)
if !ok {
return
}
@@ -362,3 +396,16 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *webhook.Webh
}
return true
}
+
+// DeleteOwnerHook deletes the hook owned by the owner.
+func DeleteOwnerHook(ctx *context.APIContext, owner *user_model.User, hookID int64) {
+ if err := webhook.DeleteWebhookByOwnerID(owner.ID, hookID); err != nil {
+ if webhook.IsErrWebhookNotExist(err) {
+ ctx.NotFound()
+ } else {
+ ctx.Error(http.StatusInternalServerError, "DeleteWebhookByOwnerID", err)
+ }
+ return
+ }
+ ctx.Status(http.StatusNoContent)
+}
diff --git a/routers/common/middleware.go b/routers/common/middleware.go
index 4f9d43c36..2abdcb583 100644
--- a/routers/common/middleware.go
+++ b/routers/common/middleware.go
@@ -16,7 +16,7 @@ import (
"code.gitea.io/gitea/modules/web/routing"
"github.com/chi-middleware/proxy"
- "github.com/go-chi/chi/v5/middleware"
+ chi "github.com/go-chi/chi/v5"
)
// Middlewares returns common middlewares
@@ -48,7 +48,8 @@ func Middlewares() []func(http.Handler) http.Handler {
handlers = append(handlers, proxy.ForwardedHeaders(opt))
}
- handlers = append(handlers, middleware.StripSlashes)
+ // Strip slashes.
+ handlers = append(handlers, stripSlashesMiddleware)
if !setting.Log.DisableRouterLog {
handlers = append(handlers, routing.NewLoggerHandler())
@@ -81,3 +82,33 @@ func Middlewares() []func(http.Handler) http.Handler {
})
return handlers
}
+
+func stripSlashesMiddleware(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
+ var urlPath string
+ rctx := chi.RouteContext(req.Context())
+ if rctx != nil && rctx.RoutePath != "" {
+ urlPath = rctx.RoutePath
+ } else if req.URL.RawPath != "" {
+ urlPath = req.URL.RawPath
+ } else {
+ urlPath = req.URL.Path
+ }
+
+ sanitizedPath := &strings.Builder{}
+ prevWasSlash := false
+ for _, chr := range strings.TrimRight(urlPath, "/") {
+ if chr != '/' || !prevWasSlash {
+ sanitizedPath.WriteRune(chr)
+ }
+ prevWasSlash = chr == '/'
+ }
+
+ if rctx == nil {
+ req.URL.Path = sanitizedPath.String()
+ } else {
+ rctx.RoutePath = sanitizedPath.String()
+ }
+ next.ServeHTTP(resp, req)
+ })
+}
diff --git a/routers/common/middleware_test.go b/routers/common/middleware_test.go
new file mode 100644
index 000000000..f16b9374e
--- /dev/null
+++ b/routers/common/middleware_test.go
@@ -0,0 +1,70 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+package common
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestStripSlashesMiddleware(t *testing.T) {
+ type test struct {
+ name string
+ expectedPath string
+ inputPath string
+ }
+
+ tests := []test{
+ {
+ name: "path with multiple slashes",
+ inputPath: "https://github.com///go-gitea//gitea.git",
+ expectedPath: "/go-gitea/gitea.git",
+ },
+ {
+ name: "path with no slashes",
+ inputPath: "https://github.com/go-gitea/gitea.git",
+ expectedPath: "/go-gitea/gitea.git",
+ },
+ {
+ name: "path with slashes in the middle",
+ inputPath: "https://git.data.coop//halfd/new-website.git",
+ expectedPath: "/halfd/new-website.git",
+ },
+ {
+ name: "path with slashes in the middle",
+ inputPath: "https://git.data.coop//halfd/new-website.git",
+ expectedPath: "/halfd/new-website.git",
+ },
+ {
+ name: "path with slashes in the end",
+ inputPath: "/user2//repo1/",
+ expectedPath: "/user2/repo1",
+ },
+ {
+ name: "path with slashes and query params",
+ inputPath: "/repo//migrate?service_type=3",
+ expectedPath: "/repo/migrate",
+ },
+ {
+ name: "path with encoded slash",
+ inputPath: "/user2/%2F%2Frepo1",
+ expectedPath: "/user2/%2F%2Frepo1",
+ },
+ }
+
+ for _, tt := range tests {
+ testMiddleware := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ assert.Equal(t, tt.expectedPath, r.URL.Path)
+ })
+
+ // pass the test middleware to validate the changes
+ handlerToTest := stripSlashesMiddleware(testMiddleware)
+ // create a mock request to use
+ req := httptest.NewRequest("GET", tt.inputPath, nil)
+ // call the handler using a mock response recorder
+ handlerToTest.ServeHTTP(httptest.NewRecorder(), req)
+ }
+}
diff --git a/routers/init.go b/routers/init.go
index d3f822dc8..8cf53fc10 100644
--- a/routers/init.go
+++ b/routers/init.go
@@ -141,7 +141,7 @@ func GlobalInitInstalled(ctx context.Context) {
if setting.EnableSQLite3 {
log.Info("SQLite3 support is enabled")
- } else if setting.Database.UseSQLite3 {
+ } else if setting.Database.Type.IsSQLite3() {
log.Fatal("SQLite3 support is disabled, but it is used for database setting. Please get or build a Gitea release with SQLite3 support.")
}
diff --git a/routers/install/install.go b/routers/install/install.go
index a3d64e5f7..8e2d19c73 100644
--- a/routers/install/install.go
+++ b/routers/install/install.go
@@ -59,11 +59,6 @@ func Init(ctx goctx.Context) func(next http.Handler) http.Handler {
dbTypeNames := getSupportedDbTypeNames()
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
- if setting.InstallLock {
- resp.Header().Add("Refresh", "1; url="+setting.AppURL+"user/login")
- _ = rnd.HTML(resp, http.StatusOK, string(tplPostInstall), nil)
- return
- }
locale := middleware.Locale(resp, req)
startTime := time.Now()
ctx := context.Context{
@@ -93,6 +88,11 @@ func Init(ctx goctx.Context) func(next http.Handler) http.Handler {
// Install render installation page
func Install(ctx *context.Context) {
+ if setting.InstallLock {
+ InstallDone(ctx)
+ return
+ }
+
form := forms.InstallForm{}
// Database settings
@@ -104,7 +104,7 @@ func Install(ctx *context.Context) {
form.DbSchema = setting.Database.Schema
form.Charset = setting.Database.Charset
- curDBType := setting.Database.Type
+ curDBType := setting.Database.Type.String()
var isCurDBTypeSupported bool
for _, dbType := range setting.SupportedDatabaseTypes {
if dbType == curDBType {
@@ -162,7 +162,7 @@ func Install(ctx *context.Context) {
form.DefaultAllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization
form.DefaultEnableTimetracking = setting.Service.DefaultEnableTimetracking
form.NoReplyAddress = setting.Service.NoReplyAddress
- form.PasswordAlgorithm = setting.PasswordHashAlgo
+ form.PasswordAlgorithm = hash.ConfigHashAlgorithm(setting.PasswordHashAlgo)
middleware.AssignForm(form, ctx.Data)
ctx.HTML(http.StatusOK, tplInstall)
@@ -234,6 +234,11 @@ func checkDatabase(ctx *context.Context, form *forms.InstallForm) bool {
// SubmitInstall response for submit install items
func SubmitInstall(ctx *context.Context) {
+ if setting.InstallLock {
+ InstallDone(ctx)
+ return
+ }
+
var err error
form := *web.GetForm(ctx).(*forms.InstallForm)
@@ -267,7 +272,7 @@ func SubmitInstall(ctx *context.Context) {
// ---- Basic checks are passed, now test configuration.
// Test database setting.
- setting.Database.Type = form.DbType
+ setting.Database.Type = setting.DatabaseType(form.DbType)
setting.Database.Host = form.DbHost
setting.Database.User = form.DbUser
setting.Database.Passwd = form.DbPasswd
@@ -277,7 +282,6 @@ func SubmitInstall(ctx *context.Context) {
setting.Database.Charset = form.Charset
setting.Database.Path = form.DbPath
setting.Database.LogSQL = !setting.IsProd
- setting.PasswordHashAlgo = form.PasswordAlgorithm
if !checkDatabase(ctx, &form) {
return
@@ -388,7 +392,7 @@ func SubmitInstall(ctx *context.Context) {
log.Error("Failed to load custom conf '%s': %v", setting.CustomConf, err)
}
}
- cfg.Section("database").Key("DB_TYPE").SetValue(setting.Database.Type)
+ cfg.Section("database").Key("DB_TYPE").SetValue(setting.Database.Type.String())
cfg.Section("database").Key("HOST").SetValue(setting.Database.Host)
cfg.Section("database").Key("NAME").SetValue(setting.Database.Name)
cfg.Section("database").Key("USER").SetValue(setting.Database.User)
@@ -499,6 +503,12 @@ func SubmitInstall(ctx *context.Context) {
}
if len(form.PasswordAlgorithm) > 0 {
+ var algorithm *hash.PasswordHashAlgorithm
+ setting.PasswordHashAlgo, algorithm = hash.SetDefaultPasswordHashAlgorithm(form.PasswordAlgorithm)
+ if algorithm == nil {
+ ctx.RenderWithErr(ctx.Tr("install.invalid_password_algorithm"), tplInstall, &form)
+ return
+ }
cfg.Section("security").Key("PASSWORD_HASH_ALGO").SetValue(form.PasswordAlgorithm)
}
@@ -571,18 +581,26 @@ func SubmitInstall(ctx *context.Context) {
}
log.Info("First-time run install finished!")
+ InstallDone(ctx)
- ctx.Flash.Success(ctx.Tr("install.install_success"))
-
- ctx.RespHeader().Add("Refresh", "1; url="+setting.AppURL+"user/login")
- ctx.HTML(http.StatusOK, tplPostInstall)
-
- // Now get the http.Server from this request and shut it down
- // NB: This is not our hammerable graceful shutdown this is http.Server.Shutdown
- srv := ctx.Value(http.ServerContextKey).(*http.Server)
go func() {
+ // Sleep for a while to make sure the user's browser has loaded the post-install page and its assets (images, css, js)
+ // What if this duration is not long enough? That's impossible -- if the user can't load the simple page in time, how could they install or use Gitea in the future ....
+ time.Sleep(3 * time.Second)
+
+ // Now get the http.Server from this request and shut it down
+ // NB: This is not our hammerable graceful shutdown this is http.Server.Shutdown
+ srv := ctx.Value(http.ServerContextKey).(*http.Server)
if err := srv.Shutdown(graceful.GetManager().HammerContext()); err != nil {
log.Error("Unable to shutdown the install server! Error: %v", err)
}
+
+ // After the HTTP server for "install" shuts down, the `runWeb()` will continue to run the "normal" server
}()
}
+
+// InstallDone shows the "post-install" page, makes it easier to develop the page.
+// The name is not called as "PostInstall" to avoid misinterpretation as a handler for "POST /install"
+func InstallDone(ctx *context.Context) { //nolint
+ ctx.HTML(http.StatusOK, tplPostInstall)
+}
diff --git a/routers/install/routes.go b/routers/install/routes.go
index 9aa5a88d2..82d9c34b4 100644
--- a/routers/install/routes.go
+++ b/routers/install/routes.go
@@ -6,6 +6,7 @@ package install
import (
goctx "context"
"fmt"
+ "html"
"net/http"
"path"
@@ -37,7 +38,7 @@ func installRecovery(ctx goctx.Context) func(next http.Handler) http.Handler {
// Why we need this? The first recover will try to render a beautiful
// error page for user, but the process can still panic again, then
// we have to just recover twice and send a simple error page that
- // should not panic any more.
+ // should not panic anymore.
defer func() {
if err := recover(); err != nil {
combinedErr := fmt.Sprintf("PANIC: %v\n%s", err, log.Stack(2))
@@ -63,7 +64,7 @@ func installRecovery(ctx goctx.Context) func(next http.Handler) http.Handler {
"SignedUserName": "",
}
- httpcache.AddCacheControlToHeader(w.Header(), 0, "no-transform")
+ httpcache.SetCacheControlInHeader(w.Header(), 0, "no-transform")
w.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
if !setting.IsProd {
@@ -107,8 +108,9 @@ func Routes(ctx goctx.Context) *web.Route {
r.Use(installRecovery(ctx))
r.Use(Init(ctx))
- r.Get("/", Install)
+ r.Get("/", Install) // it must be on the root, because the "install.js" use the window.location to replace the "localhost" AppURL
r.Post("/", web.Bind(forms.InstallForm{}), SubmitInstall)
+ r.Get("/post-install", InstallDone)
r.Get("/api/healthz", healthcheck.Check)
r.NotFound(web.Wrap(installNotFound))
@@ -116,5 +118,10 @@ func Routes(ctx goctx.Context) *web.Route {
}
func installNotFound(w http.ResponseWriter, req *http.Request) {
- http.Redirect(w, req, setting.AppURL, http.StatusFound)
+ w.Header().Add("Content-Type", "text/html; charset=utf-8")
+ w.Header().Add("Refresh", fmt.Sprintf("1; url=%s", setting.AppSubURL+"/"))
+ // do not use 30x status, because the "post-install" page needs to use 404/200 to detect if Gitea has been installed.
+ // the fetch API could follow 30x requests to the page with 200 status.
+ w.WriteHeader(http.StatusNotFound)
+ _, _ = fmt.Fprintf(w, `Not Found. <a href="%s">Go to default page</a>.`, html.EscapeString(setting.AppSubURL+"/"))
}
diff --git a/routers/private/serv.go b/routers/private/serv.go
index 17f966e3e..23ac011cf 100644
--- a/routers/private/serv.go
+++ b/routers/private/serv.go
@@ -368,7 +368,7 @@ func ServCommand(ctx *context.PrivateContext) {
return
}
- repo, err = repo_service.PushCreateRepo(user, owner, results.RepoName)
+ repo, err = repo_service.PushCreateRepo(ctx, user, owner, results.RepoName)
if err != nil {
log.Error("pushCreateRepo: %v", err)
ctx.JSON(http.StatusNotFound, private.ErrServCommand{
diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go
index 8ce45720f..d2953f753 100644
--- a/routers/web/admin/auths.go
+++ b/routers/web/admin/auths.go
@@ -271,6 +271,15 @@ func NewAuthSourcePost(ctx *context.Context) {
}
case auth.OAuth2:
config = parseOAuth2Config(form)
+ oauth2Config := config.(*oauth2.Source)
+ if oauth2Config.Provider == "openidConnect" {
+ discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL)
+ if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
+ ctx.Data["Err_DiscoveryURL"] = true
+ ctx.RenderWithErr(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthNew, form)
+ return
+ }
+ }
case auth.SSPI:
var err error
config, err = parseSSPIConfig(ctx, form)
@@ -305,6 +314,10 @@ func NewAuthSourcePost(ctx *context.Context) {
if auth.IsErrSourceAlreadyExist(err) {
ctx.Data["Err_Name"] = true
ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthNew, form)
+ } else if oauth2.IsErrOpenIDConnectInitialize(err) {
+ ctx.Data["Err_DiscoveryURL"] = true
+ unwrapped := err.(oauth2.ErrOpenIDConnectInitialize).Unwrap()
+ ctx.RenderWithErr(ctx.Tr("admin.auths.unable_to_initialize_openid", unwrapped), tplAuthNew, form)
} else {
ctx.ServerError("auth.CreateSource", err)
}
@@ -389,6 +402,15 @@ func EditAuthSourcePost(ctx *context.Context) {
}
case auth.OAuth2:
config = parseOAuth2Config(form)
+ oauth2Config := config.(*oauth2.Source)
+ if oauth2Config.Provider == "openidConnect" {
+ discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL)
+ if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
+ ctx.Data["Err_DiscoveryURL"] = true
+ ctx.RenderWithErr(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthEdit, form)
+ return
+ }
+ }
case auth.SSPI:
config, err = parseSSPIConfig(ctx, form)
if err != nil {
@@ -408,6 +430,7 @@ func EditAuthSourcePost(ctx *context.Context) {
if err := auth.UpdateSource(source); err != nil {
if oauth2.IsErrOpenIDConnectInitialize(err) {
ctx.Flash.Error(err.Error(), true)
+ ctx.Data["Err_DiscoveryURL"] = true
ctx.HTML(http.StatusOK, tplAuthEdit)
} else {
ctx.ServerError("UpdateSource", err)
diff --git a/routers/web/admin/repos.go b/routers/web/admin/repos.go
index 1c4754f6d..53b609af9 100644
--- a/routers/web/admin/repos.go
+++ b/routers/web/admin/repos.go
@@ -96,7 +96,7 @@ func UnadoptedRepos(ctx *context.Context) {
}
ctx.Data["Keyword"] = q
- repoNames, count, err := repo_service.ListUnadoptedRepositories(q, &opts)
+ repoNames, count, err := repo_service.ListUnadoptedRepositories(ctx, q, &opts)
if err != nil {
ctx.ServerError("ListUnadoptedRepositories", err)
}
@@ -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.Doer, ctxUser, repo_module.CreateRepoOptions{
+ if _, err := repo_service.AdoptRepository(ctx, ctx.Doer, ctxUser, repo_module.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.Doer, ctxUser, dirSplit[1]); err != nil {
+ if err := repo_service.DeleteUnadoptedRepository(ctx, ctx.Doer, ctxUser, dirSplit[1]); err != nil {
ctx.ServerError("repository.AdoptRepository", err)
return
}
diff --git a/routers/web/base.go b/routers/web/base.go
index b0d8a7c3f..2eb0b6f39 100644
--- a/routers/web/base.go
+++ b/routers/web/base.go
@@ -19,6 +19,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/templates"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/modules/web/routing"
"code.gitea.io/gitea/services/auth"
@@ -44,7 +45,7 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
routing.UpdateFuncInfo(req.Context(), funcInfo)
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
- rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
+ rPath = util.CleanPath(strings.ReplaceAll(rPath, "\\", "/"))
u, err := objStore.URL(rPath, path.Base(rPath))
if err != nil {
@@ -80,7 +81,7 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
routing.UpdateFuncInfo(req.Context(), funcInfo)
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
- rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
+ rPath = util.CleanPath(strings.ReplaceAll(rPath, "\\", "/"))
if rPath == "" {
http.Error(w, "file not found", http.StatusNotFound)
return
@@ -158,7 +159,7 @@ func Recovery(ctx goctx.Context) func(next http.Handler) http.Handler {
store["SignedUserName"] = ""
}
- httpcache.AddCacheControlToHeader(w.Header(), 0, "no-transform")
+ httpcache.SetCacheControlInHeader(w.Header(), 0, "no-transform")
w.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
if !setting.IsProd {
diff --git a/routers/web/explore/repo.go b/routers/web/explore/repo.go
index 058971b9b..cc3af8cb2 100644
--- a/routers/web/explore/repo.go
+++ b/routers/web/explore/repo.go
@@ -33,7 +33,6 @@ type RepoSearchOptions struct {
// RenderRepoSearch render repositories search page
// This function is also used to render the Admin Repository Management page.
-// The isAdmin param should be set to true when rendering the Admin page.
func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
// Sitemap index for sitemap paths
page := int(ctx.ParamsInt64("idx"))
diff --git a/routers/web/healthcheck/check.go b/routers/web/healthcheck/check.go
index 1142a0aec..e11dd2aca 100644
--- a/routers/web/healthcheck/check.go
+++ b/routers/web/healthcheck/check.go
@@ -100,7 +100,7 @@ func checkDatabase(checks checks) status {
st.Time = getCheckTime()
}
- if setting.Database.UseSQLite3 && st.Status == pass {
+ if setting.Database.Type.IsSQLite3() && st.Status == pass {
if !setting.EnableSQLite3 {
st.Status = fail
st.Time = getCheckTime()
diff --git a/routers/web/org/home.go b/routers/web/org/home.go
index 4cc364acd..8c9cc8a9d 100644
--- a/routers/web/org/home.go
+++ b/routers/web/org/home.go
@@ -156,6 +156,7 @@ func Home(ctx *context.Context) {
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "language", "Language")
ctx.Data["Page"] = pager
+ ctx.Data["ContextUser"] = ctx.ContextUser
ctx.HTML(http.StatusOK, tplOrgHome)
}
diff --git a/routers/web/org/org_labels.go b/routers/web/org/org_labels.go
index e96627762..9ce05680d 100644
--- a/routers/web/org/org_labels.go
+++ b/routers/web/org/org_labels.go
@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/label"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/forms"
@@ -103,8 +104,8 @@ func InitializeLabels(ctx *context.Context) {
}
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
+ if label.IsErrTemplateLoad(err) {
+ originalErr := err.(label.ErrTemplateLoad).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
diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go
index 6449d12de..c9d63fec5 100644
--- a/routers/web/org/projects.go
+++ b/routers/web/org/projects.go
@@ -103,7 +103,7 @@ func Projects(ctx *context.Context) {
pager.AddParam(ctx, "state", "State")
ctx.Data["Page"] = pager
- ctx.Data["CanWriteProjects"] = canWriteUnit(ctx)
+ ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
ctx.Data["IsShowClosed"] = isShowClosed
ctx.Data["PageIsViewProjects"] = true
ctx.Data["SortType"] = sortType
@@ -111,7 +111,7 @@ func Projects(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplProjects)
}
-func canWriteUnit(ctx *context.Context) bool {
+func canWriteProjects(ctx *context.Context) bool {
if ctx.ContextUser.IsOrganization() {
return ctx.Org.CanWriteUnit(ctx, unit.TypeProjects)
}
@@ -122,7 +122,8 @@ func canWriteUnit(ctx *context.Context) bool {
func NewProject(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.projects.new")
ctx.Data["BoardTypes"] = project_model.GetBoardConfig()
- ctx.Data["CanWriteProjects"] = canWriteUnit(ctx)
+ ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
+ ctx.Data["PageIsViewProjects"] = true
ctx.Data["HomeLink"] = ctx.ContextUser.HomeLink()
shared_user.RenderUserHeader(ctx)
ctx.HTML(http.StatusOK, tplProjectsNew)
@@ -135,7 +136,7 @@ func NewProjectPost(ctx *context.Context) {
shared_user.RenderUserHeader(ctx)
if ctx.HasError() {
- ctx.Data["CanWriteProjects"] = canWriteUnit(ctx)
+ ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
ctx.Data["PageIsViewProjects"] = true
ctx.Data["BoardTypes"] = project_model.GetBoardConfig()
ctx.HTML(http.StatusOK, tplProjectsNew)
@@ -193,7 +194,7 @@ func DeleteProject(ctx *context.Context) {
}
return
}
- if p.RepoID != ctx.Repo.Repository.ID {
+ if p.OwnerID != ctx.ContextUser.ID {
ctx.NotFound("", nil)
return
}
@@ -205,7 +206,7 @@ func DeleteProject(ctx *context.Context) {
}
ctx.JSON(http.StatusOK, map[string]interface{}{
- "redirect": ctx.Repo.RepoLink + "/projects",
+ "redirect": ctx.ContextUser.HomeLink() + "/-/projects",
})
}
@@ -214,7 +215,7 @@ func EditProject(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.projects.edit")
ctx.Data["PageIsEditProjects"] = true
ctx.Data["PageIsViewProjects"] = true
- ctx.Data["CanWriteProjects"] = canWriteUnit(ctx)
+ ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
shared_user.RenderUserHeader(ctx)
p, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id"))
@@ -226,13 +227,14 @@ func EditProject(ctx *context.Context) {
}
return
}
- if p.RepoID != ctx.Repo.Repository.ID {
+ if p.OwnerID != ctx.ContextUser.ID {
ctx.NotFound("", nil)
return
}
ctx.Data["title"] = p.Title
ctx.Data["content"] = p.Description
+ ctx.Data["redirect"] = ctx.FormString("redirect")
ctx.HTML(http.StatusOK, tplProjectsNew)
}
@@ -243,7 +245,7 @@ func EditProjectPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.projects.edit")
ctx.Data["PageIsEditProjects"] = true
ctx.Data["PageIsViewProjects"] = true
- ctx.Data["CanWriteProjects"] = canWriteUnit(ctx)
+ ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
shared_user.RenderUserHeader(ctx)
if ctx.HasError() {
@@ -260,7 +262,7 @@ func EditProjectPost(ctx *context.Context) {
}
return
}
- if p.RepoID != ctx.Repo.Repository.ID {
+ if p.OwnerID != ctx.ContextUser.ID {
ctx.NotFound("", nil)
return
}
@@ -273,7 +275,11 @@ func EditProjectPost(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.projects.edit_success", p.Title))
- ctx.Redirect(ctx.Repo.RepoLink + "/projects")
+ if ctx.FormString("redirect") == "project" {
+ ctx.Redirect(p.Link())
+ } else {
+ ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects")
+ }
}
// ViewProject renders the project board for a project
@@ -332,7 +338,7 @@ func ViewProject(ctx *context.Context) {
project.RenderedContent = project.Description
ctx.Data["LinkedPRs"] = linkedPrsMap
ctx.Data["PageIsViewProjects"] = true
- ctx.Data["CanWriteProjects"] = canWriteUnit(ctx)
+ ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
ctx.Data["Project"] = project
ctx.Data["IssuesMap"] = issuesMap
ctx.Data["Boards"] = boards
diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go
index 5c9b7967c..b57ebfbcd 100644
--- a/routers/web/org/setting.go
+++ b/routers/web/org/setting.go
@@ -137,7 +137,7 @@ func SettingsPost(ctx *context.Context) {
}
for _, repo := range repos {
repo.OwnerName = org.Name
- if err := repo_service.UpdateRepository(repo, true); err != nil {
+ if err := repo_service.UpdateRepository(ctx, repo, true); err != nil {
ctx.ServerError("UpdateRepository", err)
return
}
@@ -218,9 +218,9 @@ func Webhooks(ctx *context.Context) {
ctx.Data["BaseLinkNew"] = ctx.Org.OrgLink + "/settings/hooks"
ctx.Data["Description"] = ctx.Tr("org.settings.hooks_desc")
- ws, err := webhook.ListWebhooksByOpts(ctx, &webhook.ListWebhookOptions{OrgID: ctx.Org.Organization.ID})
+ ws, err := webhook.ListWebhooksByOpts(ctx, &webhook.ListWebhookOptions{OwnerID: ctx.Org.Organization.ID})
if err != nil {
- ctx.ServerError("GetWebhooksByOrgId", err)
+ ctx.ServerError("ListWebhooksByOpts", err)
return
}
@@ -230,8 +230,8 @@ func Webhooks(ctx *context.Context) {
// DeleteWebhook response for delete webhook
func DeleteWebhook(ctx *context.Context) {
- if err := webhook.DeleteWebhookByOrgID(ctx.Org.Organization.ID, ctx.FormInt64("id")); err != nil {
- ctx.Flash.Error("DeleteWebhookByOrgID: " + err.Error())
+ if err := webhook.DeleteWebhookByOwnerID(ctx.Org.Organization.ID, ctx.FormInt64("id")); err != nil {
+ ctx.Flash.Error("DeleteWebhookByOwnerID: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success"))
}
diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go
index dd2750f90..35b99d577 100644
--- a/routers/web/repo/actions/view.go
+++ b/routers/web/repo/actions/view.go
@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/actions"
context_module "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
@@ -51,6 +52,7 @@ type ViewResponse struct {
Run struct {
Link string `json:"link"`
Title string `json:"title"`
+ Status string `json:"status"`
CanCancel bool `json:"canCancel"`
CanApprove bool `json:"canApprove"` // the run needs an approval and the doer has permission to approve
Done bool `json:"done"`
@@ -111,6 +113,7 @@ func ViewPost(ctx *context_module.Context) {
resp.State.Run.CanApprove = run.NeedApproval && ctx.Repo.CanWrite(unit.TypeActions)
resp.State.Run.Done = run.Status.IsDone()
resp.State.Run.Jobs = make([]*ViewJob, 0, len(jobs)) // marshal to '[]' instead fo 'null' in json
+ resp.State.Run.Status = run.Status.String()
for _, v := range jobs {
resp.State.Run.Jobs = append(resp.State.Run.Jobs, &ViewJob{
ID: v.ID,
@@ -212,15 +215,18 @@ func Rerun(ctx *context_module.Context) {
job.Stopped = 0
if err := db.WithTx(ctx, func(ctx context.Context) error {
- if _, err := actions_model.UpdateRunJob(ctx, job, builder.Eq{"status": status}, "task_id", "status", "started", "stopped"); err != nil {
- return err
- }
- return actions_service.CreateCommitStatus(ctx, job)
+ _, err := actions_model.UpdateRunJob(ctx, job, builder.Eq{"status": status}, "task_id", "status", "started", "stopped")
+ return err
}); err != nil {
ctx.Error(http.StatusInternalServerError, err.Error())
return
}
+ if err := actions_service.CreateCommitStatus(ctx, job); err != nil {
+ log.Error("Update commit status for job %v failed: %v", job.ID, err)
+ // go on
+ }
+
ctx.JSON(http.StatusOK, struct{}{})
}
@@ -253,9 +259,6 @@ func Cancel(ctx *context_module.Context) {
if err := actions_model.StopTask(ctx, job.TaskID, actions_model.StatusCancelled); err != nil {
return err
}
- if err := actions_service.CreateCommitStatus(ctx, job); err != nil {
- return err
- }
}
return nil
}); err != nil {
@@ -263,6 +266,13 @@ func Cancel(ctx *context_module.Context) {
return
}
+ for _, job := range jobs {
+ if err := actions_service.CreateCommitStatus(ctx, job); err != nil {
+ log.Error("Update commit status for job %v failed: %v", job.ID, err)
+ // go on
+ }
+ }
+
ctx.JSON(http.StatusOK, struct{}{})
}
diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go
index 589632ad6..c6d8828fa 100644
--- a/routers/web/repo/attachment.go
+++ b/routers/web/repo/attachment.go
@@ -44,7 +44,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) {
}
defer file.Close()
- attach, err := attachment.UploadAttachment(file, allowedTypes, &repo_model.Attachment{
+ attach, err := attachment.UploadAttachment(file, allowedTypes, header.Size, &repo_model.Attachment{
Name: header.Filename,
UploaderID: ctx.Doer.ID,
RepoID: repoID,
diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go
index b34ccf853..d23367e04 100644
--- a/routers/web/repo/branch.go
+++ b/routers/web/repo/branch.go
@@ -91,7 +91,7 @@ func DeleteBranchPost(ctx *context.Context) {
defer redirect(ctx)
branchName := ctx.FormString("name")
- if err := repo_service.DeleteBranch(ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
+ if err := repo_service.DeleteBranch(ctx, 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)
diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go
index e5ba4ad2c..4f208098e 100644
--- a/routers/web/repo/editor.go
+++ b/routers/web/repo/editor.go
@@ -726,7 +726,7 @@ func UploadFilePost(ctx *context.Context) {
func cleanUploadFileName(name string) string {
// Rebase the filename
- name = strings.Trim(path.Clean("/"+name), "/")
+ name = strings.Trim(util.CleanPath(name), "/")
// Git disallows any filenames to have a .git directory in them.
for _, part := range strings.Split(name, "/") {
if strings.ToLower(part) == ".git" {
diff --git a/routers/web/repo/http.go b/routers/web/repo/http.go
index 9d4ffccc6..cd32d9953 100644
--- a/routers/web/repo/http.go
+++ b/routers/web/repo/http.go
@@ -228,7 +228,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
}
if !p.CanAccess(accessMode, unitType) {
- ctx.PlainText(http.StatusForbidden, "User permission denied")
+ ctx.PlainText(http.StatusNotFound, "Repository not found")
return
}
}
@@ -276,7 +276,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
return
}
- repo, err = repo_service.PushCreateRepo(ctx.Doer, owner, reponame)
+ repo, err = repo_service.PushCreateRepo(ctx, ctx.Doer, owner, reponame)
if err != nil {
log.Error("pushCreateRepo: %v", err)
ctx.Status(http.StatusNotFound)
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index f8cc4daeb..f937d93d0 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -589,7 +589,7 @@ func RetrieveRepoReviewers(ctx *context.Context, repo *repo_model.Repository, is
return
}
- teamReviewers, err = repo_service.GetReviewerTeams(repo)
+ teamReviewers, err = repo_service.GetReviewerTeams(ctx, repo)
if err != nil {
ctx.ServerError("GetReviewerTeams", err)
return
@@ -1420,11 +1420,12 @@ func ViewIssue(ctx *context.Context) {
}
var (
- role issues_model.RoleDescriptor
- ok bool
- marked = make(map[int64]issues_model.RoleDescriptor)
- comment *issues_model.Comment
- participants = make([]*user_model.User, 1, 10)
+ role issues_model.RoleDescriptor
+ ok bool
+ marked = make(map[int64]issues_model.RoleDescriptor)
+ comment *issues_model.Comment
+ participants = make([]*user_model.User, 1, 10)
+ latestCloseCommentID int64
)
if ctx.Repo.Repository.IsTimetrackerEnabled(ctx) {
if ctx.IsSigned {
@@ -1432,25 +1433,16 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["IsStopwatchRunning"] = issues_model.StopwatchExists(ctx.Doer.ID, issue.ID)
if !ctx.Data["IsStopwatchRunning"].(bool) {
var exists bool
- var sw *issues_model.Stopwatch
- if exists, sw, err = issues_model.HasUserStopwatch(ctx, ctx.Doer.ID); err != nil {
+ var swIssue *issues_model.Issue
+ if exists, _, swIssue, err = issues_model.HasUserStopwatch(ctx, ctx.Doer.ID); err != nil {
ctx.ServerError("HasUserStopwatch", err)
return
}
ctx.Data["HasUserStopwatch"] = exists
if exists {
// Add warning if the user has already a stopwatch
- var otherIssue *issues_model.Issue
- if otherIssue, err = issues_model.GetIssueByID(ctx, sw.IssueID); err != nil {
- ctx.ServerError("GetIssueByID", err)
- return
- }
- if err = otherIssue.LoadRepo(ctx); err != nil {
- ctx.ServerError("LoadRepo", err)
- return
- }
// Add link to the issue of the already running stopwatch
- ctx.Data["OtherStopwatchURL"] = otherIssue.Link()
+ ctx.Data["OtherStopwatchURL"] = swIssue.Link()
}
}
ctx.Data["CanUseTimetracker"] = ctx.Repo.CanUseTimetracker(issue, ctx.Doer)
@@ -1631,9 +1623,15 @@ func ViewIssue(ctx *context.Context) {
comment.Type == issues_model.CommentTypeStopTracking {
// drop error since times could be pruned from DB..
_ = comment.LoadTime()
+ } else if comment.Type == issues_model.CommentTypeClose {
+ // record ID of latest closed comment.
+ // if PR is closed, the comments whose type is CommentTypePullRequestPush(29) after latestCloseCommentID won't be rendered.
+ latestCloseCommentID = comment.ID
}
}
+ ctx.Data["LatestCloseCommentID"] = latestCloseCommentID
+
// Combine multiple label assignments into a single comment
combineLabelComments(issue)
@@ -2961,7 +2959,7 @@ func ChangeIssueReaction(ctx *context.Context) {
}
html, err := ctx.RenderToString(tplReactions, map[string]interface{}{
- "ctx": ctx.Data,
+ "ctxData": ctx.Data,
"ActionURL": fmt.Sprintf("%s/issues/%d/reactions", ctx.Repo.RepoLink, issue.Index),
"Reactions": issue.Reactions.GroupByType(),
})
@@ -3063,7 +3061,7 @@ func ChangeCommentReaction(ctx *context.Context) {
}
html, err := ctx.RenderToString(tplReactions, map[string]interface{}{
- "ctx": ctx.Data,
+ "ctxData": ctx.Data,
"ActionURL": fmt.Sprintf("%s/comments/%d/reactions", ctx.Repo.RepoLink, comment.ID),
"Reactions": comment.Reactions.GroupByType(),
})
@@ -3185,7 +3183,7 @@ func updateAttachments(ctx *context.Context, item interface{}, files []string) e
func attachmentsHTML(ctx *context.Context, attachments []*repo_model.Attachment, content string) string {
attachHTML, err := ctx.RenderToString(tplAttachment, map[string]interface{}{
- "ctx": ctx.Data,
+ "ctxData": ctx.Data,
"Attachments": attachments,
"Content": content,
})
diff --git a/routers/web/repo/issue_label.go b/routers/web/repo/issue_label.go
index d4fece9f0..31bf85fed 100644
--- a/routers/web/repo/issue_label.go
+++ b/routers/web/repo/issue_label.go
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/label"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/web"
@@ -41,8 +42,8 @@ func InitializeLabels(ctx *context.Context) {
}
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
+ if label.IsErrTemplateLoad(err) {
+ originalErr := err.(label.ErrTemplateLoad).OriginalError
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, originalErr))
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
return
diff --git a/routers/web/repo/issue_stopwatch.go b/routers/web/repo/issue_stopwatch.go
index 3d20b08b4..3e715437e 100644
--- a/routers/web/repo/issue_stopwatch.go
+++ b/routers/web/repo/issue_stopwatch.go
@@ -86,7 +86,7 @@ func GetActiveStopwatch(ctx *context.Context) {
return
}
- _, sw, err := issues_model.HasUserStopwatch(ctx, ctx.Doer.ID)
+ _, sw, issue, err := issues_model.HasUserStopwatch(ctx, ctx.Doer.ID)
if err != nil {
ctx.ServerError("HasUserStopwatch", err)
return
@@ -96,18 +96,6 @@ func GetActiveStopwatch(ctx *context.Context) {
return
}
- issue, err := issues_model.GetIssueByID(ctx, sw.IssueID)
- if err != nil || issue == nil {
- if !issues_model.IsErrIssueNotExist(err) {
- ctx.ServerError("GetIssueByID", err)
- }
- return
- }
- if err = issue.LoadRepo(ctx); err != nil {
- ctx.ServerError("LoadRepo", err)
- return
- }
-
ctx.Data["ActiveStopwatch"] = StopwatchTmplInfo{
issue.Link(),
issue.Repo.FullName(),
diff --git a/routers/web/repo/lfs.go b/routers/web/repo/lfs.go
index 869a69c37..43f552798 100644
--- a/routers/web/repo/lfs.go
+++ b/routers/web/repo/lfs.go
@@ -207,7 +207,7 @@ func LFSLockFile(ctx *context.Context) {
ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks")
return
}
- lockPath = path.Clean("/" + lockPath)[1:]
+ lockPath = util.CleanPath(lockPath)
if len(lockPath) == 0 {
ctx.Flash.Error(ctx.Tr("repo.settings.lfs_invalid_locking_path", originalPath))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks")
diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go
index 967b81c60..29bd59c7a 100644
--- a/routers/web/repo/projects.go
+++ b/routers/web/repo/projects.go
@@ -235,6 +235,7 @@ func EditProject(ctx *context.Context) {
ctx.Data["title"] = p.Title
ctx.Data["content"] = p.Description
ctx.Data["card_type"] = p.CardType
+ ctx.Data["redirect"] = ctx.FormString("redirect")
ctx.HTML(http.StatusOK, tplProjectsNew)
}
@@ -275,7 +276,11 @@ func EditProjectPost(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.projects.edit_success", p.Title))
- ctx.Redirect(ctx.Repo.RepoLink + "/projects")
+ if ctx.FormString("redirect") == "project" {
+ ctx.Redirect(p.Link())
+ } else {
+ ctx.Redirect(ctx.Repo.RepoLink + "/projects")
+ }
}
// ViewProject renders the project board for a project
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index 38b9f22cb..4f9968773 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -587,7 +587,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["HeadBranchCommitID"] = headBranchSha
ctx.Data["PullHeadCommitID"] = sha
- if pull.HeadRepo == nil || !headBranchExist || headBranchSha != sha {
+ if pull.HeadRepo == nil || !headBranchExist || (!pull.Issue.IsClosed && (headBranchSha != sha)) {
ctx.Data["IsPullRequestBroken"] = true
if pull.IsSameRepo() {
ctx.Data["HeadTarget"] = pull.HeadBranch
@@ -1399,7 +1399,7 @@ func CleanUpPullRequest(ctx *context.Context) {
func deleteBranch(ctx *context.Context, pr *issues_model.PullRequest, gitRepo *git.Repository) {
fullBranchName := pr.HeadRepo.FullName() + ":" + pr.HeadBranch
- if err := repo_service.DeleteBranch(ctx.Doer, pr.HeadRepo, gitRepo, pr.HeadBranch); err != nil {
+ if err := repo_service.DeleteBranch(ctx, ctx.Doer, pr.HeadRepo, gitRepo, pr.HeadBranch); err != nil {
switch {
case git.IsErrBranchNotExist(err):
ctx.Flash.Error(ctx.Tr("repo.branch.deletion_failed", fullBranchName))
diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go
index d43a786c5..90cfd5bfc 100644
--- a/routers/web/repo/pull_review.go
+++ b/routers/web/repo/pull_review.go
@@ -77,7 +77,7 @@ func CreateCodeComment(ctx *context.Context) {
signedLine,
form.Content,
form.TreePath,
- form.IsReview,
+ !form.SingleReview,
form.Reply,
form.LatestCommitID,
)
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index aeac7cfa3..d72fd39f9 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -248,14 +248,14 @@ func CreatePost(ctx *context.Context) {
return
}
- repo, err = repo_service.GenerateRepository(ctx.Doer, ctxUser, templateRepo, opts)
+ repo, err = repo_service.GenerateRepository(ctx, 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.Doer, ctxUser, repo_module.CreateRepoOptions{
+ repo, err = repo_service.CreateRepository(ctx, ctx.Doer, ctxUser, repo_module.CreateRepoOptions{
Name: form.RepoName,
Description: form.Description,
Gitignores: form.Gitignores,
@@ -302,7 +302,7 @@ func Action(ctx *context.Context) {
ctx.Repo.Repository.Description = ctx.FormString("desc")
ctx.Repo.Repository.Website = ctx.FormString("site")
- err = repo_service.UpdateRepository(ctx.Repo.Repository, false)
+ err = repo_service.UpdateRepository(ctx, ctx.Repo.Repository, false)
}
if err != nil {
diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go
index 387a91741..0c36503b3 100644
--- a/routers/web/repo/setting.go
+++ b/routers/web/repo/setting.go
@@ -134,7 +134,7 @@ func SettingsPost(ctx *context.Context) {
ctx.Repo.GitRepo.Close()
ctx.Repo.GitRepo = nil
}
- if err := repo_service.ChangeRepositoryName(ctx.Doer, repo, newRepoName); err != nil {
+ if err := repo_service.ChangeRepositoryName(ctx, ctx.Doer, repo, newRepoName); err != nil {
ctx.Data["Err_RepoName"] = true
switch {
case repo_model.IsErrRepoAlreadyExist(err):
@@ -183,7 +183,7 @@ func SettingsPost(ctx *context.Context) {
}
repo.IsPrivate = form.Private
- if err := repo_service.UpdateRepository(repo, visibilityChanged); err != nil {
+ if err := repo_service.UpdateRepository(ctx, repo, visibilityChanged); err != nil {
ctx.ServerError("UpdateRepository", err)
return
}
@@ -541,7 +541,7 @@ func SettingsPost(ctx *context.Context) {
return
}
if repoChanged {
- if err := repo_service.UpdateRepository(repo, false); err != nil {
+ if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
ctx.ServerError("UpdateRepository", err)
return
}
@@ -560,7 +560,7 @@ func SettingsPost(ctx *context.Context) {
}
if changed {
- if err := repo_service.UpdateRepository(repo, false); err != nil {
+ if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
ctx.ServerError("UpdateRepository", err)
return
}
@@ -580,7 +580,7 @@ func SettingsPost(ctx *context.Context) {
repo.IsFsckEnabled = form.EnableHealthCheck
}
- if err := repo_service.UpdateRepository(repo, false); err != nil {
+ if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
ctx.ServerError("UpdateRepository", err)
return
}
@@ -672,7 +672,7 @@ func SettingsPost(ctx *context.Context) {
return
}
- if err := repo_service.ConvertForkToNormalRepository(repo); err != nil {
+ if err := repo_service.ConvertForkToNormalRepository(ctx, repo); err != nil {
log.Error("Unable to convert repository %-v from fork. Error: %v", repo, err)
ctx.ServerError("Convert Fork", err)
return
@@ -1244,7 +1244,7 @@ func UpdateAvatarSetting(ctx *context.Context, form forms.AvatarForm) error {
if !(st.IsImage() && !st.IsSvgImage()) {
return errors.New(ctx.Tr("settings.uploaded_avatar_not_a_image"))
}
- if err = repo_service.UploadAvatar(ctxRepo, data); err != nil {
+ if err = repo_service.UploadAvatar(ctx, ctxRepo, data); err != nil {
return fmt.Errorf("UploadAvatar: %w", err)
}
return nil
@@ -1264,7 +1264,7 @@ func SettingsAvatar(ctx *context.Context) {
// SettingsDeleteAvatar delete repository avatar
func SettingsDeleteAvatar(ctx *context.Context) {
- if err := repo_service.DeleteAvatar(ctx.Repo.Repository); err != nil {
+ if err := repo_service.DeleteAvatar(ctx, ctx.Repo.Repository); err != nil {
ctx.Flash.Error(fmt.Sprintf("DeleteAvatar: %v", err))
}
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
diff --git a/routers/web/repo/setting_protected_branch.go b/routers/web/repo/setting_protected_branch.go
index 0a8c39fef..34e84c465 100644
--- a/routers/web/repo/setting_protected_branch.go
+++ b/routers/web/repo/setting_protected_branch.go
@@ -356,7 +356,7 @@ func RenameBranchPost(ctx *context.Context) {
return
}
- msg, err := repository.RenameBranch(ctx.Repo.Repository, ctx.Doer, ctx.Repo.GitRepo, form.From, form.To)
+ msg, err := repository.RenameBranch(ctx, ctx.Repo.Repository, ctx.Doer, ctx.Repo.GitRepo, form.From, form.To)
if err != nil {
ctx.ServerError("RenameBranch", err)
return
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index e3c61fa40..8663e1138 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -186,7 +186,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
return
}
- renderReadmeFile(ctx, readmeFile, treeLink)
+ renderReadmeFile(ctx, readmeFile, fmt.Sprintf("%s/%s", treeLink, readmeFile.name))
}
// localizedExtensions prepends the provided language code with and without a
diff --git a/routers/web/repo/webhook.go b/routers/web/repo/webhook.go
index d27d0f1bf..f30588967 100644
--- a/routers/web/repo/webhook.go
+++ b/routers/web/repo/webhook.go
@@ -33,6 +33,7 @@ const (
tplHooks base.TplName = "repo/settings/webhook/base"
tplHookNew base.TplName = "repo/settings/webhook/new"
tplOrgHookNew base.TplName = "org/settings/hook_new"
+ tplUserHookNew base.TplName = "user/settings/hook_new"
tplAdminHookNew base.TplName = "admin/hook_new"
)
@@ -54,8 +55,8 @@ func Webhooks(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplHooks)
}
-type orgRepoCtx struct {
- OrgID int64
+type ownerRepoCtx struct {
+ OwnerID int64
RepoID int64
IsAdmin bool
IsSystemWebhook bool
@@ -64,10 +65,10 @@ type orgRepoCtx struct {
NewTemplate base.TplName
}
-// getOrgRepoCtx determines whether this is a repo, organization, or admin (both default and system) context.
-func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) {
- if len(ctx.Repo.RepoLink) > 0 {
- return &orgRepoCtx{
+// getOwnerRepoCtx determines whether this is a repo, owner, or admin (both default and system) context.
+func getOwnerRepoCtx(ctx *context.Context) (*ownerRepoCtx, error) {
+ if is, ok := ctx.Data["IsRepositoryWebhook"]; ok && is.(bool) {
+ return &ownerRepoCtx{
RepoID: ctx.Repo.Repository.ID,
Link: path.Join(ctx.Repo.RepoLink, "settings/hooks"),
LinkNew: path.Join(ctx.Repo.RepoLink, "settings/hooks"),
@@ -75,37 +76,35 @@ func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) {
}, nil
}
- if len(ctx.Org.OrgLink) > 0 {
- return &orgRepoCtx{
- OrgID: ctx.Org.Organization.ID,
+ if is, ok := ctx.Data["IsOrganizationWebhook"]; ok && is.(bool) {
+ return &ownerRepoCtx{
+ OwnerID: ctx.ContextUser.ID,
Link: path.Join(ctx.Org.OrgLink, "settings/hooks"),
LinkNew: path.Join(ctx.Org.OrgLink, "settings/hooks"),
NewTemplate: tplOrgHookNew,
}, nil
}
- if ctx.Doer.IsAdmin {
- // Are we looking at default webhooks?
- if ctx.Params(":configType") == "default-hooks" {
- return &orgRepoCtx{
- IsAdmin: true,
- Link: path.Join(setting.AppSubURL, "/admin/hooks"),
- LinkNew: path.Join(setting.AppSubURL, "/admin/default-hooks"),
- NewTemplate: tplAdminHookNew,
- }, nil
- }
+ if is, ok := ctx.Data["IsUserWebhook"]; ok && is.(bool) {
+ return &ownerRepoCtx{
+ OwnerID: ctx.Doer.ID,
+ Link: path.Join(setting.AppSubURL, "/user/settings/hooks"),
+ LinkNew: path.Join(setting.AppSubURL, "/user/settings/hooks"),
+ NewTemplate: tplUserHookNew,
+ }, nil
+ }
- // Must be system webhooks instead
- return &orgRepoCtx{
+ if ctx.Doer.IsAdmin {
+ return &ownerRepoCtx{
IsAdmin: true,
- IsSystemWebhook: true,
+ IsSystemWebhook: ctx.Params(":configType") == "system-hooks",
Link: path.Join(setting.AppSubURL, "/admin/hooks"),
LinkNew: path.Join(setting.AppSubURL, "/admin/system-hooks"),
NewTemplate: tplAdminHookNew,
}, nil
}
- return nil, errors.New("unable to set OrgRepo context")
+ return nil, errors.New("unable to set OwnerRepo context")
}
func checkHookType(ctx *context.Context) string {
@@ -122,9 +121,9 @@ func WebhooksNew(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook_module.HookEvent{}}
- orCtx, err := getOrgRepoCtx(ctx)
+ orCtx, err := getOwnerRepoCtx(ctx)
if err != nil {
- ctx.ServerError("getOrgRepoCtx", err)
+ ctx.ServerError("getOwnerRepoCtx", err)
return
}
@@ -205,9 +204,9 @@ func createWebhook(ctx *context.Context, params webhookParams) {
ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook_module.HookEvent{}}
ctx.Data["HookType"] = params.Type
- orCtx, err := getOrgRepoCtx(ctx)
+ orCtx, err := getOwnerRepoCtx(ctx)
if err != nil {
- ctx.ServerError("getOrgRepoCtx", err)
+ ctx.ServerError("getOwnerRepoCtx", err)
return
}
ctx.Data["BaseLink"] = orCtx.LinkNew
@@ -236,7 +235,7 @@ func createWebhook(ctx *context.Context, params webhookParams) {
IsActive: params.WebhookForm.Active,
Type: params.Type,
Meta: string(meta),
- OrgID: orCtx.OrgID,
+ OwnerID: orCtx.OwnerID,
IsSystemWebhook: orCtx.IsSystemWebhook,
}
err = w.SetHeaderAuthorization(params.WebhookForm.AuthorizationHeader)
@@ -577,19 +576,19 @@ func packagistHookParams(ctx *context.Context) webhookParams {
}
}
-func checkWebhook(ctx *context.Context) (*orgRepoCtx, *webhook.Webhook) {
- orCtx, err := getOrgRepoCtx(ctx)
+func checkWebhook(ctx *context.Context) (*ownerRepoCtx, *webhook.Webhook) {
+ orCtx, err := getOwnerRepoCtx(ctx)
if err != nil {
- ctx.ServerError("getOrgRepoCtx", err)
+ ctx.ServerError("getOwnerRepoCtx", err)
return nil, nil
}
ctx.Data["BaseLink"] = orCtx.Link
var w *webhook.Webhook
if orCtx.RepoID > 0 {
- w, err = webhook.GetWebhookByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
- } else if orCtx.OrgID > 0 {
- w, err = webhook.GetWebhookByOrgID(ctx.Org.Organization.ID, ctx.ParamsInt64(":id"))
+ w, err = webhook.GetWebhookByRepoID(orCtx.RepoID, ctx.ParamsInt64(":id"))
+ } else if orCtx.OwnerID > 0 {
+ w, err = webhook.GetWebhookByOwnerID(orCtx.OwnerID, ctx.ParamsInt64(":id"))
} else if orCtx.IsAdmin {
w, err = webhook.GetSystemOrDefaultWebhook(ctx, ctx.ParamsInt64(":id"))
}
diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go
index 94e59e2a4..05e45f999 100644
--- a/routers/web/shared/user/header.go
+++ b/routers/web/shared/user/header.go
@@ -9,6 +9,8 @@ import (
)
func RenderUserHeader(ctx *context.Context) {
+ ctx.Data["IsProjectEnabled"] = true
+ ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["ContextUser"] = ctx.ContextUser
}
diff --git a/routers/web/user/avatar.go b/routers/web/user/avatar.go
index 2dba74822..7ad65cd51 100644
--- a/routers/web/user/avatar.go
+++ b/routers/web/user/avatar.go
@@ -17,7 +17,7 @@ func cacheableRedirect(ctx *context.Context, location string) {
// here we should not use `setting.StaticCacheTime`, it is pretty long (default: 6 hours)
// we must make sure the redirection cache time is short enough, otherwise a user won't see the updated avatar in 6 hours
// it's OK to make the cache time short, it is only a redirection, and doesn't cost much to make a new request
- httpcache.AddCacheControlToHeader(ctx.Resp.Header(), 5*time.Minute)
+ httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 5*time.Minute)
ctx.Redirect(location)
}
diff --git a/routers/web/user/code.go b/routers/web/user/code.go
index 81e3e65b4..b3adbcb8d 100644
--- a/routers/web/user/code.go
+++ b/routers/web/user/code.go
@@ -24,6 +24,7 @@ func CodeSearch(ctx *context.Context) {
return
}
+ ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["Title"] = ctx.Tr("explore.code")
diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go
index 5d34df79b..e7f200aa8 100644
--- a/routers/web/user/profile.go
+++ b/routers/web/user/profile.go
@@ -305,6 +305,7 @@ func Profile(ctx *context.Context) {
pager.AddParam(ctx, "date", "Date")
}
ctx.Data["Page"] = pager
+ ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
diff --git a/routers/web/user/setting/adopt.go b/routers/web/user/setting/adopt.go
index 844d6fa16..c9995e727 100644
--- a/routers/web/user/setting/adopt.go
+++ b/routers/web/user/setting/adopt.go
@@ -45,7 +45,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
if has || !isDir {
// Fallthrough to failure mode
} else if action == "adopt" && allowAdopt {
- if _, err := repo_service.AdoptRepository(ctxUser, ctxUser, repo_module.CreateRepoOptions{
+ if _, err := repo_service.AdoptRepository(ctx, ctxUser, ctxUser, repo_module.CreateRepoOptions{
Name: dir,
IsPrivate: true,
}); err != nil {
@@ -54,7 +54,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.adopt_preexisting_success", dir))
} else if action == "delete" && allowDelete {
- if err := repo_service.DeleteUnadoptedRepository(ctxUser, ctxUser, dir); err != nil {
+ if err := repo_service.DeleteUnadoptedRepository(ctx, ctxUser, ctxUser, dir); err != nil {
ctx.ServerError("repository.AdoptRepository", err)
return
}
diff --git a/routers/web/user/setting/webhooks.go b/routers/web/user/setting/webhooks.go
new file mode 100644
index 000000000..9b0b0c961
--- /dev/null
+++ b/routers/web/user/setting/webhooks.go
@@ -0,0 +1,48 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package setting
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/models/webhook"
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/setting"
+)
+
+const (
+ tplSettingsHooks base.TplName = "user/settings/hooks"
+)
+
+// Webhooks render webhook list page
+func Webhooks(ctx *context.Context) {
+ ctx.Data["Title"] = ctx.Tr("settings")
+ ctx.Data["PageIsSettingsHooks"] = true
+ ctx.Data["BaseLink"] = setting.AppSubURL + "/user/settings/hooks"
+ ctx.Data["BaseLinkNew"] = setting.AppSubURL + "/user/settings/hooks"
+ ctx.Data["Description"] = ctx.Tr("settings.hooks.desc")
+
+ ws, err := webhook.ListWebhooksByOpts(ctx, &webhook.ListWebhookOptions{OwnerID: ctx.Doer.ID})
+ if err != nil {
+ ctx.ServerError("ListWebhooksByOpts", err)
+ return
+ }
+
+ ctx.Data["Webhooks"] = ws
+ ctx.HTML(http.StatusOK, tplSettingsHooks)
+}
+
+// DeleteWebhook response for delete webhook
+func DeleteWebhook(ctx *context.Context) {
+ if err := webhook.DeleteWebhookByOwnerID(ctx.Doer.ID, ctx.FormInt64("id")); err != nil {
+ ctx.Flash.Error("DeleteWebhookByOwnerID: " + err.Error())
+ } else {
+ ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success"))
+ }
+
+ ctx.JSON(http.StatusOK, map[string]interface{}{
+ "redirect": setting.AppSubURL + "/user/settings/hooks",
+ })
+}
diff --git a/routers/web/web.go b/routers/web/web.go
index ff312992d..292268dc8 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -315,6 +315,35 @@ func RegisterRoutes(m *web.Route) {
}
}
+ addWebhookAddRoutes := func() {
+ m.Get("/{type}/new", repo.WebhooksNew)
+ m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
+ m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
+ m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
+ m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
+ m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
+ m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
+ m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
+ m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
+ m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
+ m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
+ m.Post("/packagist/new", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost)
+ }
+
+ addWebhookEditRoutes := func() {
+ m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
+ m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
+ m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
+ m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
+ m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
+ m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
+ m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
+ m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
+ m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
+ m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
+ m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost)
+ }
+
// FIXME: not all routes need go through same middleware.
// Especially some AJAX requests, we can reduce middleware number to improve performance.
// Routers.
@@ -482,6 +511,19 @@ func RegisterRoutes(m *web.Route) {
m.Get("/organization", user_setting.Organization)
m.Get("/repos", user_setting.Repos)
m.Post("/repos/unadopted", user_setting.AdoptOrDeleteRepository)
+
+ m.Group("/hooks", func() {
+ m.Get("", user_setting.Webhooks)
+ m.Post("/delete", user_setting.DeleteWebhook)
+ addWebhookAddRoutes()
+ m.Group("/{id}", func() {
+ m.Get("", repo.WebHooksEdit)
+ m.Post("/replay/{uuid}", repo.ReplayWebhook)
+ })
+ addWebhookEditRoutes()
+ }, webhooksEnabled, func(ctx *context.Context) {
+ ctx.Data["IsUserWebhook"] = true
+ })
}, reqSignIn, func(ctx *context.Context) {
ctx.Data["PageIsUserSettings"] = true
ctx.Data["AllThemes"] = setting.UI.Themes
@@ -575,32 +617,11 @@ func RegisterRoutes(m *web.Route) {
m.Get("", repo.WebHooksEdit)
m.Post("/replay/{uuid}", repo.ReplayWebhook)
})
- m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
- m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
- m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
- m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
- m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
- m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
- m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
- m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
- m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
- m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
- m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost)
+ addWebhookEditRoutes()
}, webhooksEnabled)
m.Group("/{configType:default-hooks|system-hooks}", func() {
- m.Get("/{type}/new", repo.WebhooksNew)
- m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
- m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
- m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
- m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
- m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
- m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
- m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
- m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
- m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
- m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
- m.Post("/packagist/new", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost)
+ addWebhookAddRoutes()
})
m.Group("/auths", func() {
@@ -690,6 +711,21 @@ func RegisterRoutes(m *web.Route) {
}
}
+ reqUnitAccess := func(unitType unit.Type, accessMode perm.AccessMode) func(ctx *context.Context) {
+ return func(ctx *context.Context) {
+ if ctx.ContextUser == nil {
+ ctx.NotFound(unitType.String(), nil)
+ return
+ }
+ if ctx.ContextUser.IsOrganization() {
+ if ctx.Org.Organization.UnitPermission(ctx, ctx.Doer, unitType) < accessMode {
+ ctx.NotFound(unitType.String(), nil)
+ return
+ }
+ }
+ }
+ }
+
// ***** START: Organization *****
m.Group("/org", func() {
m.Group("/{org}", func() {
@@ -759,32 +795,15 @@ func RegisterRoutes(m *web.Route) {
m.Group("/hooks", func() {
m.Get("", org.Webhooks)
m.Post("/delete", org.DeleteWebhook)
- m.Get("/{type}/new", repo.WebhooksNew)
- m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
- m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
- m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
- m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
- m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
- m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
- m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
- m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
- m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
- m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
+ addWebhookAddRoutes()
m.Group("/{id}", func() {
m.Get("", repo.WebHooksEdit)
m.Post("/replay/{uuid}", repo.ReplayWebhook)
})
- m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
- m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
- m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
- m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
- m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
- m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
- m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
- m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
- m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
- m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
- }, webhooksEnabled)
+ addWebhookEditRoutes()
+ }, webhooksEnabled, func(ctx *context.Context) {
+ ctx.Data["IsOrganizationWebhook"] = true
+ })
m.Group("/labels", func() {
m.Get("", org.RetrieveLabels, org.Labels)
@@ -869,8 +888,10 @@ func RegisterRoutes(m *web.Route) {
}
m.Group("/projects", func() {
- m.Get("", org.Projects)
- m.Get("/{id}", org.ViewProject)
+ m.Group("", func() {
+ m.Get("", org.Projects)
+ m.Get("/{id}", org.ViewProject)
+ }, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead))
m.Group("", func() { //nolint:dupl
m.Get("/new", org.NewProject)
m.Post("/new", web.Bind(forms.CreateProjectForm{}), org.NewProjectPost)
@@ -890,25 +911,18 @@ func RegisterRoutes(m *web.Route) {
m.Post("/move", org.MoveIssues)
})
})
- }, reqSignIn, func(ctx *context.Context) {
- if ctx.ContextUser == nil {
- ctx.NotFound("NewProject", nil)
- return
- }
- if ctx.ContextUser.IsOrganization() {
- if !ctx.Org.CanWriteUnit(ctx, unit.TypeProjects) {
- ctx.NotFound("NewProject", nil)
- return
- }
- } else if ctx.ContextUser.ID != ctx.Doer.ID {
+ }, reqSignIn, reqUnitAccess(unit.TypeProjects, perm.AccessModeWrite), func(ctx *context.Context) {
+ if ctx.ContextUser.IsIndividual() && ctx.ContextUser.ID != ctx.Doer.ID {
ctx.NotFound("NewProject", nil)
return
}
})
}, repo.MustEnableProjects)
- m.Get("/code", user.CodeSearch)
- }, context_service.UserAssignmentWeb())
+ m.Group("", func() {
+ m.Get("/code", user.CodeSearch)
+ }, reqUnitAccess(unit.TypeCode, perm.AccessModeRead))
+ }, context_service.UserAssignmentWeb(), context.OrgAssignment())
// ***** Release Attachment Download without Signin
m.Get("/{username}/{reponame}/releases/download/{vTag}/{fileName}", ignSignIn, context.RepoAssignment, repo.MustBeNotEmpty, repo.RedirectDownload)
@@ -962,35 +976,16 @@ func RegisterRoutes(m *web.Route) {
m.Group("/hooks", func() {
m.Get("", repo.Webhooks)
m.Post("/delete", repo.DeleteWebhook)
- m.Get("/{type}/new", repo.WebhooksNew)
- m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
- m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
- m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
- m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
- m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
- m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
- m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
- m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
- m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
- m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
- m.Post("/packagist/new", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost)
+ addWebhookAddRoutes()
m.Group("/{id}", func() {
m.Get("", repo.WebHooksEdit)
m.Post("/test", repo.TestWebhook)
m.Post("/replay/{uuid}", repo.ReplayWebhook)
})
- m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
- m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
- m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
- m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
- m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
- m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
- m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
- m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
- m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
- m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
- m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost)
- }, webhooksEnabled)
+ addWebhookEditRoutes()
+ }, webhooksEnabled, func(ctx *context.Context) {
+ ctx.Data["IsRepositoryWebhook"] = true
+ })
m.Group("/keys", func() {
m.Combo("").Get(repo.DeployKeys).