mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-09 09:33:24 +02:00
Merge remote-tracking branch 'upstream/main' into limit-repo-size
This commit is contained in:
commit
4793882373
477 files changed
+7190
-5990
No files matched your search
@@ -97,7 +97,7 @@ func (s *Service) Register(
|
||||
// FetchTask assigns a task to the runner
|
||||
func (s *Service) FetchTask(
|
||||
ctx context.Context,
|
||||
req *connect.Request[runnerv1.FetchTaskRequest],
|
||||
_ *connect.Request[runnerv1.FetchTaskRequest],
|
||||
) (*connect.Response[runnerv1.FetchTaskResponse], error) {
|
||||
runner := GetRunner(ctx)
|
||||
|
||||
@@ -145,6 +145,31 @@ func (s *Service) UpdateTask(
|
||||
return nil, status.Errorf(codes.Internal, "update task: %v", err)
|
||||
}
|
||||
|
||||
for k, v := range req.Msg.Outputs {
|
||||
if len(k) > 255 {
|
||||
log.Warn("Ignore the output of task %d because the key is too long: %q", task.ID, k)
|
||||
continue
|
||||
}
|
||||
// The value can be a maximum of 1 MB
|
||||
if l := len(v); l > 1024*1024 {
|
||||
log.Warn("Ignore the output %q of task %d because the value is too long: %v", k, task.ID, l)
|
||||
continue
|
||||
}
|
||||
// There's another limitation on GitHub that the total of all outputs in a workflow run can be a maximum of 50 MB.
|
||||
// We don't check the total size here because it's not easy to do, and it doesn't really worth it.
|
||||
// See https://docs.github.com/en/actions/using-jobs/defining-outputs-for-jobs
|
||||
|
||||
if err := actions_model.InsertTaskOutputIfNotExist(ctx, task.ID, k, v); err != nil {
|
||||
log.Warn("Failed to insert the output %q of task %d: %v", k, task.ID, err)
|
||||
// It's ok not to return errors, the runner will resend the outputs.
|
||||
}
|
||||
}
|
||||
sentOutputs, err := actions_model.FindTaskOutputKeyByTaskID(ctx, task.ID)
|
||||
if err != nil {
|
||||
log.Warn("Failed to find the sent outputs of task %d: %v", task.ID, err)
|
||||
// It's not to return errors, it can be handled when the runner resends sent outputs.
|
||||
}
|
||||
|
||||
if err := task.LoadJob(ctx); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "load job: %v", err)
|
||||
}
|
||||
@@ -162,6 +187,7 @@ func (s *Service) UpdateTask(
|
||||
Id: req.Msg.State.Id,
|
||||
Result: task.Status.AsResult(),
|
||||
},
|
||||
SentOutputs: sentOutputs,
|
||||
}), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,17 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
|
||||
Context: generateTaskContext(t),
|
||||
Secrets: getSecretsOfTask(ctx, t),
|
||||
}
|
||||
|
||||
if needs, err := findTaskNeeds(ctx, t); err != nil {
|
||||
log.Error("Cannot find needs for task %v: %v", t.ID, err)
|
||||
// Go on with empty needs.
|
||||
// If return error, the task will be wild, which means the runner will never get it when it has been assigned to the runner.
|
||||
// In contrast, missing needs is less serious.
|
||||
// And the task will fail and the runner will report the error in the logs.
|
||||
} else {
|
||||
task.Needs = needs
|
||||
}
|
||||
|
||||
return task, true, nil
|
||||
}
|
||||
|
||||
@@ -124,3 +135,46 @@ func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
|
||||
|
||||
return taskContext
|
||||
}
|
||||
|
||||
func findTaskNeeds(ctx context.Context, task *actions_model.ActionTask) (map[string]*runnerv1.TaskNeed, error) {
|
||||
if err := task.LoadAttributes(ctx); err != nil {
|
||||
return nil, fmt.Errorf("LoadAttributes: %w", err)
|
||||
}
|
||||
if len(task.Job.Needs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
needs := map[string]struct{}{}
|
||||
for _, v := range task.Job.Needs {
|
||||
needs[v] = struct{}{}
|
||||
}
|
||||
|
||||
jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{RunID: task.Job.RunID})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FindRunJobs: %w", err)
|
||||
}
|
||||
|
||||
ret := make(map[string]*runnerv1.TaskNeed, len(needs))
|
||||
for _, job := range jobs {
|
||||
if _, ok := needs[job.JobID]; !ok {
|
||||
continue
|
||||
}
|
||||
if job.TaskID == 0 || !job.Status.IsDone() {
|
||||
// it shouldn't happen, or the job has been rerun
|
||||
continue
|
||||
}
|
||||
outputs := make(map[string]string)
|
||||
got, err := actions_model.FindTaskOutputByTaskID(ctx, job.TaskID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FindTaskOutputByTaskID: %w", err)
|
||||
}
|
||||
for _, v := range got {
|
||||
outputs[v.OutputKey] = v.OutputValue
|
||||
}
|
||||
ret[job.JobID] = &runnerv1.TaskNeed{
|
||||
Outputs: outputs,
|
||||
Result: runnerv1.Result(job.Status),
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
@@ -480,7 +480,7 @@ func ContainerRoutes(ctx gocontext.Context) *web.Route {
|
||||
)
|
||||
|
||||
// Manual mapping of routes because {image} can contain slashes which chi does not support
|
||||
r.Route("/*", "HEAD,GET,POST,PUT,PATCH,DELETE", func(ctx *context.Context) {
|
||||
r.RouteMethods("/*", "HEAD,GET,POST,PUT,PATCH,DELETE", func(ctx *context.Context) {
|
||||
path := ctx.Params("*")
|
||||
isHead := ctx.Req.Method == "HEAD"
|
||||
isGet := ctx.Req.Method == "GET"
|
||||
|
||||
@@ -142,7 +142,7 @@ func EditHook(ctx *context.APIContext) {
|
||||
|
||||
// DeleteHook delete a system hook
|
||||
func DeleteHook(ctx *context.APIContext) {
|
||||
// swagger:operation DELETE /amdin/hooks/{id} admin adminDeleteHook
|
||||
// swagger:operation DELETE /admin/hooks/{id} admin adminDeleteHook
|
||||
// ---
|
||||
// summary: Delete a hook
|
||||
// produces:
|
||||
|
||||
+10
-10
@@ -634,8 +634,8 @@ func mustEnableAttachments(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
// bind binding an obj to a func(ctx *context.APIContext)
|
||||
func bind[T any](obj T) http.HandlerFunc {
|
||||
return web.Wrap(func(ctx *context.APIContext) {
|
||||
func bind[T any](_ T) any {
|
||||
return func(ctx *context.APIContext) {
|
||||
theObj := new(T) // create a new form obj for every request but not use obj directly
|
||||
errs := binding.Bind(ctx.Req, theObj)
|
||||
if len(errs) > 0 {
|
||||
@@ -643,7 +643,7 @@ func bind[T any](obj T) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
web.SetForm(ctx, theObj)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// The OAuth2 plugin is expected to be executed first, as it must ignore the user id stored
|
||||
@@ -689,7 +689,7 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
// Get user from session if logged in.
|
||||
m.Use(auth.APIAuth(group))
|
||||
|
||||
m.Use(context.ToggleAPI(&context.ToggleOptions{
|
||||
m.Use(auth.VerifyAuthWithOptionsAPI(&auth.VerifyOptions{
|
||||
SignInRequired: setting.Service.RequireSignInView,
|
||||
}))
|
||||
|
||||
@@ -1200,12 +1200,12 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
m.Get("/{org}/permissions", reqToken(auth_model.AccessTokenScopeReadOrg), org.GetUserOrgsPermissions)
|
||||
}, context_service.UserAssignmentAPI())
|
||||
m.Post("/orgs", reqToken(auth_model.AccessTokenScopeWriteOrg), bind(api.CreateOrgOption{}), org.Create)
|
||||
m.Get("/orgs", reqToken(auth_model.AccessTokenScopeReadOrg), org.GetAll)
|
||||
m.Get("/orgs", org.GetAll)
|
||||
m.Group("/orgs/{org}", func() {
|
||||
m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.Get).
|
||||
m.Combo("").Get(org.Get).
|
||||
Patch(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.EditOrgOption{}), org.Edit).
|
||||
Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.Delete)
|
||||
m.Combo("/repos").Get(reqToken(auth_model.AccessTokenScopeReadOrg), user.ListOrgRepos).
|
||||
m.Combo("/repos").Get(user.ListOrgRepos).
|
||||
Post(reqToken(auth_model.AccessTokenScopeWriteOrg), bind(api.CreateRepoOption{}), repo.CreateOrgRepo)
|
||||
m.Group("/members", func() {
|
||||
m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListMembers)
|
||||
@@ -1213,8 +1213,8 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.DeleteMember)
|
||||
})
|
||||
m.Group("/public_members", func() {
|
||||
m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListPublicMembers)
|
||||
m.Combo("/{username}").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.IsPublicMember).
|
||||
m.Get("", org.ListPublicMembers)
|
||||
m.Combo("/{username}").Get(org.IsPublicMember).
|
||||
Put(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgMembership(), org.PublicizeMember).
|
||||
Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgMembership(), org.ConcealMember)
|
||||
})
|
||||
@@ -1224,7 +1224,7 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
m.Get("/search", reqToken(auth_model.AccessTokenScopeReadOrg), org.SearchTeam)
|
||||
}, reqOrgMembership())
|
||||
m.Group("/labels", func() {
|
||||
m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListLabels)
|
||||
m.Get("", org.ListLabels)
|
||||
m.Post("", reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.CreateLabelOption{}), org.CreateLabel)
|
||||
m.Combo("/{id}").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.GetLabel).
|
||||
Patch(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.EditLabelOption{}), org.EditLabel).
|
||||
|
||||
@@ -173,7 +173,7 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) {
|
||||
IssueID: issue.ID,
|
||||
Since: since,
|
||||
Before: before,
|
||||
Type: issues_model.CommentTypeUnknown,
|
||||
Type: issues_model.CommentTypeUndefined,
|
||||
}
|
||||
|
||||
comments, err := issues_model.FindComments(ctx, opts)
|
||||
@@ -549,7 +549,7 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption)
|
||||
return
|
||||
}
|
||||
|
||||
if comment.Type != issues_model.CommentTypeComment && comment.Type != issues_model.CommentTypeReview && comment.Type != issues_model.CommentTypeCode {
|
||||
if !comment.Type.HasContentSupport() {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
+19
-21
@@ -58,10 +58,10 @@ func NewWikiPage(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
wikiName := wiki_service.NormalizeWikiName(form.Title)
|
||||
wikiName := wiki_service.UserTitleToWebPath("", form.Title)
|
||||
|
||||
if len(form.Message) == 0 {
|
||||
form.Message = fmt.Sprintf("Add '%s'", form.Title)
|
||||
form.Message = fmt.Sprintf("Add %q", form.Title)
|
||||
}
|
||||
|
||||
content, err := base64.StdEncoding.DecodeString(form.ContentBase64)
|
||||
@@ -85,7 +85,7 @@ func NewWikiPage(ctx *context.APIContext) {
|
||||
wikiPage := getWikiPage(ctx, wikiName)
|
||||
|
||||
if !ctx.Written() {
|
||||
notification.NotifyNewWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName, form.Message)
|
||||
notification.NotifyNewWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(wikiName), form.Message)
|
||||
ctx.JSON(http.StatusCreated, wikiPage)
|
||||
}
|
||||
}
|
||||
@@ -127,15 +127,15 @@ func EditWikiPage(ctx *context.APIContext) {
|
||||
|
||||
form := web.GetForm(ctx).(*api.CreateWikiPageOptions)
|
||||
|
||||
oldWikiName := wiki_service.NormalizeWikiName(ctx.Params(":pageName"))
|
||||
newWikiName := wiki_service.NormalizeWikiName(form.Title)
|
||||
oldWikiName := wiki_service.WebPathFromRequest(ctx.Params(":pageName"))
|
||||
newWikiName := wiki_service.UserTitleToWebPath("", form.Title)
|
||||
|
||||
if len(newWikiName) == 0 {
|
||||
newWikiName = oldWikiName
|
||||
}
|
||||
|
||||
if len(form.Message) == 0 {
|
||||
form.Message = fmt.Sprintf("Update '%s'", newWikiName)
|
||||
form.Message = fmt.Sprintf("Update %q", newWikiName)
|
||||
}
|
||||
|
||||
content, err := base64.StdEncoding.DecodeString(form.ContentBase64)
|
||||
@@ -153,14 +153,12 @@ func EditWikiPage(ctx *context.APIContext) {
|
||||
wikiPage := getWikiPage(ctx, newWikiName)
|
||||
|
||||
if !ctx.Written() {
|
||||
notification.NotifyEditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, newWikiName, form.Message)
|
||||
notification.NotifyEditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(newWikiName), form.Message)
|
||||
ctx.JSON(http.StatusOK, wikiPage)
|
||||
}
|
||||
}
|
||||
|
||||
func getWikiPage(ctx *context.APIContext, title string) *api.WikiPage {
|
||||
title = wiki_service.NormalizeWikiName(title)
|
||||
|
||||
func getWikiPage(ctx *context.APIContext, wikiName wiki_service.WebPath) *api.WikiPage {
|
||||
wikiRepo, commit := findWikiRepoCommit(ctx)
|
||||
if wikiRepo != nil {
|
||||
defer wikiRepo.Close()
|
||||
@@ -170,7 +168,7 @@ func getWikiPage(ctx *context.APIContext, title string) *api.WikiPage {
|
||||
}
|
||||
|
||||
// lookup filename in wiki - get filecontent, real filename
|
||||
content, pageFilename := wikiContentsByName(ctx, commit, title, false)
|
||||
content, pageFilename := wikiContentsByName(ctx, commit, wikiName, false)
|
||||
if ctx.Written() {
|
||||
return nil
|
||||
}
|
||||
@@ -196,7 +194,7 @@ func getWikiPage(ctx *context.APIContext, title string) *api.WikiPage {
|
||||
}
|
||||
|
||||
return &api.WikiPage{
|
||||
WikiPageMetaData: convert.ToWikiPageMetaData(title, lastCommit, ctx.Repo.Repository),
|
||||
WikiPageMetaData: convert.ToWikiPageMetaData(wikiName, lastCommit, ctx.Repo.Repository),
|
||||
ContentBase64: content,
|
||||
CommitCount: commitsCount,
|
||||
Sidebar: sidebarContent,
|
||||
@@ -233,7 +231,7 @@ func DeleteWikiPage(ctx *context.APIContext) {
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
|
||||
wikiName := wiki_service.NormalizeWikiName(ctx.Params(":pageName"))
|
||||
wikiName := wiki_service.WebPathFromRequest(ctx.Params(":pageName"))
|
||||
|
||||
if err := wiki_service.DeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName); err != nil {
|
||||
if err.Error() == "file does not exist" {
|
||||
@@ -244,7 +242,7 @@ func DeleteWikiPage(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
notification.NotifyDeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName)
|
||||
notification.NotifyDeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(wikiName))
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
@@ -316,7 +314,7 @@ func ListWikiPages(ctx *context.APIContext) {
|
||||
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
|
||||
return
|
||||
}
|
||||
wikiName, err := wiki_service.FilenameToName(entry.Name())
|
||||
wikiName, err := wiki_service.GitPathToWebPath(entry.Name())
|
||||
if err != nil {
|
||||
if repo_model.IsErrWikiInvalidFileName(err) {
|
||||
continue
|
||||
@@ -361,7 +359,7 @@ func GetWikiPage(ctx *context.APIContext) {
|
||||
// "$ref": "#/responses/notFound"
|
||||
|
||||
// get requested pagename
|
||||
pageName := wiki_service.NormalizeWikiName(ctx.Params(":pageName"))
|
||||
pageName := wiki_service.WebPathFromRequest(ctx.Params(":pageName"))
|
||||
|
||||
wikiPage := getWikiPage(ctx, pageName)
|
||||
if !ctx.Written() {
|
||||
@@ -411,7 +409,7 @@ func ListPageRevisions(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
// get requested pagename
|
||||
pageName := wiki_service.NormalizeWikiName(ctx.Params(":pageName"))
|
||||
pageName := wiki_service.WebPathFromRequest(ctx.Params(":pageName"))
|
||||
if len(pageName) == 0 {
|
||||
pageName = "Home"
|
||||
}
|
||||
@@ -502,9 +500,9 @@ func wikiContentsByEntry(ctx *context.APIContext, entry *git.TreeEntry) string {
|
||||
|
||||
// wikiContentsByName returns the contents of a wiki page, along with a boolean
|
||||
// indicating whether the page exists. Writes to ctx if an error occurs.
|
||||
func wikiContentsByName(ctx *context.APIContext, commit *git.Commit, wikiName string, isSidebarOrFooter bool) (string, string) {
|
||||
pageFilename := wiki_service.NameToFilename(wikiName)
|
||||
entry, err := findEntryForFile(commit, pageFilename)
|
||||
func wikiContentsByName(ctx *context.APIContext, commit *git.Commit, wikiName wiki_service.WebPath, isSidebarOrFooter bool) (string, string) {
|
||||
gitFilename := wiki_service.WebPathToGitPath(wikiName)
|
||||
entry, err := findEntryForFile(commit, gitFilename)
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
if !isSidebarOrFooter {
|
||||
@@ -515,5 +513,5 @@ func wikiContentsByName(ctx *context.APIContext, commit *git.Commit, wikiName st
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
return wikiContentsByEntry(ctx, entry), pageFilename
|
||||
return wikiContentsByEntry(ctx, entry), gitFilename
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
// RenderMarkup renders markup text for the /markup and /markdown endpoints
|
||||
func RenderMarkup(ctx *context.Context, mode, text, urlPrefix, filePath string, wiki bool) {
|
||||
markupType := ""
|
||||
var markupType string
|
||||
relativePath := ""
|
||||
|
||||
if len(text) == 0 {
|
||||
|
||||
+1
-1
@@ -108,6 +108,7 @@ func GlobalInitInstalled(ctx context.Context) {
|
||||
}
|
||||
|
||||
mustInitCtx(ctx, git.InitFull)
|
||||
log.Info("Gitea Version: %s%s", setting.AppVer, setting.AppBuiltWith)
|
||||
log.Info("Git Version: %s (home: %s)", git.VersionInfo(), git.HomeDir())
|
||||
log.Info("AppPath: %s", setting.AppPath)
|
||||
log.Info("AppWorkPath: %s", setting.AppWorkPath)
|
||||
@@ -115,7 +116,6 @@ func GlobalInitInstalled(ctx context.Context) {
|
||||
log.Info("Log path: %s", setting.Log.RootPath)
|
||||
log.Info("Configuration file: %s", setting.CustomConf)
|
||||
log.Info("Run Mode: %s", util.ToTitleCase(setting.RunMode))
|
||||
log.Info("Gitea v%s%s", setting.AppVer, setting.AppBuiltWith)
|
||||
|
||||
// Setup i18n
|
||||
translation.InitLocales(ctx)
|
||||
|
||||
@@ -81,14 +81,14 @@ func installRecovery(ctx goctx.Context) func(next http.Handler) http.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
// Routes registers the install routes
|
||||
// Routes registers the installation routes
|
||||
func Routes(ctx goctx.Context) *web.Route {
|
||||
r := web.NewRoute()
|
||||
for _, middle := range common.Middlewares() {
|
||||
r.Use(middle)
|
||||
}
|
||||
|
||||
r.Use(web.WrapWithPrefix("/assets/", public.AssetsHandlerFunc("/assets/"), "AssetsHandler"))
|
||||
r.Use(web.MiddlewareWithPrefix("/assets/", nil, public.AssetsHandlerFunc("/assets/")))
|
||||
|
||||
r.Use(session.Sessioner(session.Options{
|
||||
Provider: setting.SessionConfig.Provider,
|
||||
@@ -109,7 +109,7 @@ func Routes(ctx goctx.Context) *web.Route {
|
||||
r.Get("/post-install", InstallDone)
|
||||
r.Get("/api/healthz", healthcheck.Check)
|
||||
|
||||
r.NotFound(web.Wrap(installNotFound))
|
||||
r.NotFound(installNotFound)
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
@@ -38,12 +38,12 @@ func CheckInternalToken(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
// bind binding an obj to a handler
|
||||
func bind[T any](obj T) http.HandlerFunc {
|
||||
return web.Wrap(func(ctx *context.PrivateContext) {
|
||||
func bind[T any](_ T) any {
|
||||
return func(ctx *context.PrivateContext) {
|
||||
theObj := new(T) // create a new form obj for every request but not use obj directly
|
||||
binding.Bind(ctx.Req, theObj)
|
||||
web.SetForm(ctx, theObj)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Routes registers all internal APIs routes to web application.
|
||||
|
||||
@@ -966,7 +966,7 @@ func SignInOAuthCallback(ctx *context.Context) {
|
||||
}
|
||||
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsActive: util.OptionalBoolOf(!setting.OAuth2Client.RegisterEmailConfirm),
|
||||
IsActive: util.OptionalBoolOf(!setting.OAuth2Client.RegisterEmailConfirm && !setting.Service.RegisterManualConfirm),
|
||||
}
|
||||
|
||||
source := authSource.Cfg.(*oauth2.Source)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package feed
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
|
||||
"github.com/gorilla/feeds"
|
||||
)
|
||||
|
||||
// ShowBranchFeed shows tags and/or releases on the repo as RSS / Atom feed
|
||||
func ShowBranchFeed(ctx *context.Context, repo *repo.Repository, formatType string) {
|
||||
commits, err := ctx.Repo.Commit.CommitsByRange(0, 10)
|
||||
if err != nil {
|
||||
ctx.ServerError("ShowBranchFeed", err)
|
||||
return
|
||||
}
|
||||
|
||||
title := fmt.Sprintf("Latest commits for branch %s", ctx.Repo.BranchName)
|
||||
link := &feeds.Link{Href: repo.HTMLURL() + "/" + ctx.Repo.BranchNameSubURL()}
|
||||
|
||||
feed := &feeds.Feed{
|
||||
Title: title,
|
||||
Link: link,
|
||||
Description: repo.Description,
|
||||
Created: time.Now(),
|
||||
}
|
||||
|
||||
for _, commit := range commits {
|
||||
feed.Items = append(feed.Items, &feeds.Item{
|
||||
Id: commit.ID.String(),
|
||||
Title: strings.TrimSpace(strings.Split(commit.Message(), "\n")[0]),
|
||||
Link: &feeds.Link{Href: repo.HTMLURL() + "/commit/" + commit.ID.String()},
|
||||
Author: &feeds.Author{
|
||||
Name: commit.Author.Name,
|
||||
Email: commit.Author.Email,
|
||||
},
|
||||
Description: commit.Message(),
|
||||
Content: commit.Message(),
|
||||
})
|
||||
}
|
||||
|
||||
writeFeed(ctx, feed, formatType)
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package feed
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/gorilla/feeds"
|
||||
)
|
||||
|
||||
// ShowFileFeed shows tags and/or releases on the repo as RSS / Atom feed
|
||||
func ShowFileFeed(ctx *context.Context, repo *repo.Repository, formatType string) {
|
||||
fileName := ctx.Repo.TreePath
|
||||
if len(fileName) == 0 {
|
||||
return
|
||||
}
|
||||
commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(ctx.Repo.RefName, fileName, 1)
|
||||
if err != nil {
|
||||
ctx.ServerError("ShowBranchFeed", err)
|
||||
return
|
||||
}
|
||||
|
||||
title := fmt.Sprintf("Latest commits for file %s", ctx.Repo.TreePath)
|
||||
|
||||
link := &feeds.Link{Href: repo.HTMLURL() + "/" + ctx.Repo.BranchNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)}
|
||||
|
||||
feed := &feeds.Feed{
|
||||
Title: title,
|
||||
Link: link,
|
||||
Description: repo.Description,
|
||||
Created: time.Now(),
|
||||
}
|
||||
|
||||
for _, commit := range commits {
|
||||
feed.Items = append(feed.Items, &feeds.Item{
|
||||
Id: commit.ID.String(),
|
||||
Title: strings.TrimSpace(strings.Split(commit.Message(), "\n")[0]),
|
||||
Link: &feeds.Link{Href: repo.HTMLURL() + "/commit/" + commit.ID.String()},
|
||||
Author: &feeds.Author{
|
||||
Name: commit.Author.Name,
|
||||
Email: commit.Author.Email,
|
||||
},
|
||||
Description: commit.Message(),
|
||||
Content: commit.Message(),
|
||||
})
|
||||
}
|
||||
|
||||
writeFeed(ctx, feed, formatType)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package feed
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
)
|
||||
|
||||
// RenderBranchFeed render format for branch or file
|
||||
func RenderBranchFeed(ctx *context.Context) {
|
||||
_, _, showFeedType := GetFeedType(ctx.Params(":reponame"), ctx.Req)
|
||||
if ctx.Repo.TreePath == "" {
|
||||
ShowBranchFeed(ctx, ctx.Repo.Repository, showFeedType)
|
||||
} else {
|
||||
ShowFileFeed(ctx, ctx.Repo.Repository, showFeedType)
|
||||
}
|
||||
}
|
||||
@@ -143,7 +143,6 @@ func Home(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Owner"] = org
|
||||
ctx.Data["Repos"] = repos
|
||||
ctx.Data["Total"] = count
|
||||
ctx.Data["MembersTotal"] = membersCount
|
||||
|
||||
@@ -62,6 +62,7 @@ func Members(ctx *context.Context) {
|
||||
}
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.Data["Members"] = members
|
||||
ctx.Data["ContextUser"] = ctx.ContextUser
|
||||
ctx.Data["MembersIsPublicMember"] = membersIsPublic
|
||||
ctx.Data["MembersIsUserOrgOwner"] = organization.IsUserOrgOwner(members, org.ID)
|
||||
ctx.Data["MembersTwoFaStatus"] = members.GetTwoFaStatus()
|
||||
|
||||
@@ -610,6 +610,23 @@ func SetDefaultProjectBoard(ctx *context.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// UnsetDefaultProjectBoard unset default board for uncategorized issues/pulls
|
||||
func UnsetDefaultProjectBoard(ctx *context.Context) {
|
||||
project, _ := CheckProjectBoardChangePermissions(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
if err := project_model.SetDefaultBoard(project.ID, 0); err != nil {
|
||||
ctx.ServerError("SetDefaultBoard", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"ok": true,
|
||||
})
|
||||
}
|
||||
|
||||
// MoveIssues moves or keeps issues in a column and sorts them inside that column
|
||||
func MoveIssues(ctx *context.Context) {
|
||||
if ctx.Doer == nil {
|
||||
|
||||
@@ -43,6 +43,8 @@ func SecretsPost(ctx *context.Context) {
|
||||
func SecretsDelete(ctx *context.Context) {
|
||||
shared.PerformSecretsDelete(
|
||||
ctx,
|
||||
ctx.ContextUser.ID,
|
||||
0,
|
||||
ctx.Org.OrgLink+"/settings/secrets",
|
||||
)
|
||||
}
|
||||
@@ -56,6 +56,7 @@ func Teams(ctx *context.Context) {
|
||||
}
|
||||
}
|
||||
ctx.Data["Teams"] = ctx.Org.Teams
|
||||
ctx.Data["ContextUser"] = ctx.ContextUser
|
||||
|
||||
ctx.HTML(http.StatusOK, tplTeams)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
@@ -11,11 +12,14 @@ import (
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/modules/actions"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/convert"
|
||||
|
||||
"github.com/nektos/act/pkg/model"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -24,9 +28,8 @@ const (
|
||||
)
|
||||
|
||||
type Workflow struct {
|
||||
Entry git.TreeEntry
|
||||
IsInvalid bool
|
||||
ErrMsg string
|
||||
Entry git.TreeEntry
|
||||
ErrMsg string
|
||||
}
|
||||
|
||||
// MustEnableActions check if actions are enabled in settings
|
||||
@@ -73,6 +76,23 @@ func List(ctx *context.Context) {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Get all runner labels
|
||||
opts := actions_model.FindRunnerOptions{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
WithAvailable: true,
|
||||
}
|
||||
runners, err := actions_model.FindRunners(ctx, opts)
|
||||
if err != nil {
|
||||
ctx.ServerError("FindRunners", err)
|
||||
return
|
||||
}
|
||||
allRunnerLabels := make(container.Set[string])
|
||||
for _, r := range runners {
|
||||
allRunnerLabels.AddMultiple(r.AgentLabels...)
|
||||
allRunnerLabels.AddMultiple(r.CustomLabels...)
|
||||
}
|
||||
|
||||
workflows = make([]Workflow, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
workflow := Workflow{Entry: *entry}
|
||||
@@ -81,10 +101,24 @@ func List(ctx *context.Context) {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
_, err = actions.GetEventsFromContent(content)
|
||||
wf, err := model.ReadWorkflow(bytes.NewReader(content))
|
||||
if err != nil {
|
||||
workflow.IsInvalid = true
|
||||
workflow.ErrMsg = err.Error()
|
||||
workflow.ErrMsg = ctx.Locale.Tr("actions.runs.invalid_workflow_helper", err.Error())
|
||||
workflows = append(workflows, workflow)
|
||||
continue
|
||||
}
|
||||
// Check whether have matching runner
|
||||
for _, j := range wf.Jobs {
|
||||
runsOnList := j.RunsOn()
|
||||
for _, ro := range runsOnList {
|
||||
if !allRunnerLabels.Contains(ro) {
|
||||
workflow.ErrMsg = ctx.Locale.Tr("actions.runs.no_matching_runner_helper", ro)
|
||||
break
|
||||
}
|
||||
}
|
||||
if workflow.ErrMsg != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
workflows = append(workflows, workflow)
|
||||
}
|
||||
@@ -128,12 +162,18 @@ func List(ctx *context.Context) {
|
||||
ctx.Data["NumClosedActionRuns"] = numClosedRuns
|
||||
|
||||
opts.IsClosed = util.OptionalBoolNone
|
||||
if ctx.FormString("state") == "closed" {
|
||||
isShowClosed := ctx.FormString("state") == "closed"
|
||||
if len(ctx.FormString("state")) == 0 && numOpenRuns == 0 && numClosedRuns != 0 {
|
||||
isShowClosed = true
|
||||
}
|
||||
|
||||
if isShowClosed {
|
||||
opts.IsClosed = util.OptionalBoolTrue
|
||||
ctx.Data["IsShowClosed"] = true
|
||||
} else {
|
||||
opts.IsClosed = util.OptionalBoolFalse
|
||||
}
|
||||
|
||||
runs, total, err := actions_model.FindRuns(ctx, opts)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
|
||||
@@ -459,7 +459,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
|
||||
rootRepo.ID != ci.HeadRepo.ID &&
|
||||
rootRepo.ID != baseRepo.ID {
|
||||
canRead := access_model.CheckRepoUnitUser(ctx, rootRepo, ctx.Doer, unit.TypeCode)
|
||||
if canRead {
|
||||
if canRead && rootRepo.AllowsPulls() {
|
||||
ctx.Data["RootRepo"] = rootRepo
|
||||
if !fileOnly {
|
||||
branches, tags, err := getBranchesAndTagsForRepo(ctx, rootRepo)
|
||||
|
||||
+26
-18
@@ -82,7 +82,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
|
||||
}
|
||||
|
||||
// Check if the filename (and additional path) is specified in the querystring
|
||||
// (filename is a misnomer, but kept for compatibility with Github)
|
||||
// (filename is a misnomer, but kept for compatibility with GitHub)
|
||||
filePath, fileName := path.Split(ctx.Req.URL.Query().Get("filename"))
|
||||
filePath = strings.Trim(filePath, "/")
|
||||
treeNames, treePaths := getParentTreeFields(path.Join(ctx.Repo.TreePath, filePath))
|
||||
@@ -327,6 +327,10 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
_ = repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, IsEmpty: false}, "is_empty")
|
||||
}
|
||||
|
||||
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
|
||||
} else {
|
||||
@@ -617,25 +621,25 @@ func UploadFilePost(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var newTreePath string
|
||||
for _, part := range treeNames {
|
||||
newTreePath = path.Join(newTreePath, part)
|
||||
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(newTreePath)
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
// Means there is no item with that name, so we're good
|
||||
break
|
||||
if !ctx.Repo.Repository.IsEmpty {
|
||||
var newTreePath string
|
||||
for _, part := range treeNames {
|
||||
newTreePath = path.Join(newTreePath, part)
|
||||
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(newTreePath)
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
break // Means there is no item with that name, so we're good
|
||||
}
|
||||
ctx.ServerError("Repo.Commit.GetTreeEntryByPath", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.ServerError("Repo.Commit.GetTreeEntryByPath", err)
|
||||
return
|
||||
}
|
||||
|
||||
// User can only upload files to a directory.
|
||||
if !entry.IsDir() {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), tplUploadFile, &form)
|
||||
return
|
||||
// User can only upload files to a directory, the directory name shouldn't be an existing file.
|
||||
if !entry.IsDir() {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), tplUploadFile, &form)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -714,6 +718,10 @@ func UploadFilePost(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
_ = repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, IsEmpty: false}, "is_empty")
|
||||
}
|
||||
|
||||
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
|
||||
} else {
|
||||
|
||||
+21
-33
@@ -32,43 +32,31 @@ import (
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
|
||||
"github.com/go-chi/cors"
|
||||
)
|
||||
|
||||
func HTTPGitEnabledHandler(ctx *context.Context) {
|
||||
if setting.Repository.DisableHTTPGit {
|
||||
ctx.Resp.WriteHeader(http.StatusForbidden)
|
||||
_, _ = ctx.Resp.Write([]byte("Interacting with repositories by HTTP protocol is not allowed"))
|
||||
}
|
||||
}
|
||||
|
||||
func CorsHandler() func(next http.Handler) http.Handler {
|
||||
if setting.Repository.AccessControlAllowOrigin != "" {
|
||||
return cors.Handler(cors.Options{
|
||||
AllowedOrigins: []string{setting.Repository.AccessControlAllowOrigin},
|
||||
AllowedHeaders: []string{"Content-Type", "Authorization", "User-Agent"},
|
||||
})
|
||||
}
|
||||
return func(next http.Handler) http.Handler {
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
// httpBase implementation git smart HTTP protocol
|
||||
func httpBase(ctx *context.Context) (h *serviceHandler) {
|
||||
if setting.Repository.DisableHTTPGit {
|
||||
ctx.Resp.WriteHeader(http.StatusForbidden)
|
||||
_, err := ctx.Resp.Write([]byte("Interacting with repositories by HTTP protocol is not allowed"))
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if len(setting.Repository.AccessControlAllowOrigin) > 0 {
|
||||
allowedOrigin := setting.Repository.AccessControlAllowOrigin
|
||||
// Set CORS headers for browser-based git clients
|
||||
ctx.Resp.Header().Set("Access-Control-Allow-Origin", allowedOrigin)
|
||||
ctx.Resp.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, User-Agent")
|
||||
|
||||
// Handle preflight OPTIONS request
|
||||
if ctx.Req.Method == "OPTIONS" {
|
||||
if allowedOrigin == "*" {
|
||||
ctx.Status(http.StatusOK)
|
||||
} else if allowedOrigin == "null" {
|
||||
ctx.Status(http.StatusForbidden)
|
||||
} else {
|
||||
origin := ctx.Req.Header.Get("Origin")
|
||||
if len(origin) > 0 && origin == allowedOrigin {
|
||||
ctx.Status(http.StatusOK)
|
||||
} else {
|
||||
ctx.Status(http.StatusForbidden)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
username := ctx.Params(":username")
|
||||
reponame := strings.TrimSuffix(ctx.Params(":reponame"), ".git")
|
||||
|
||||
|
||||
+20
-14
@@ -1557,7 +1557,7 @@ func ViewIssue(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
} else if comment.Type == issues_model.CommentTypeCode || comment.Type == issues_model.CommentTypeReview || comment.Type == issues_model.CommentTypeDismissReview {
|
||||
} else if comment.Type.HasContentSupport() {
|
||||
comment.RenderedContent, err = markdown.RenderString(&markup.RenderContext{
|
||||
URLPrefix: ctx.Repo.RepoLink,
|
||||
Metas: ctx.Repo.Repository.ComposeMetas(),
|
||||
@@ -1621,8 +1621,10 @@ 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 comment.Type == issues_model.CommentTypeClose || comment.Type == issues_model.CommentTypeMergePull {
|
||||
// record ID of the latest closed/merged comment.
|
||||
// if PR is closed, the comments whose type is CommentTypePullRequestPush(29) after latestCloseCommentID won't be rendered.
|
||||
latestCloseCommentID = comment.ID
|
||||
}
|
||||
@@ -2849,7 +2851,7 @@ func UpdateCommentContent(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if comment.Type != issues_model.CommentTypeComment && comment.Type != issues_model.CommentTypeReview && comment.Type != issues_model.CommentTypeCode {
|
||||
if !comment.Type.HasContentSupport() {
|
||||
ctx.Error(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
@@ -2913,7 +2915,7 @@ func DeleteComment(ctx *context.Context) {
|
||||
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
|
||||
ctx.Error(http.StatusForbidden)
|
||||
return
|
||||
} else if comment.Type != issues_model.CommentTypeComment && comment.Type != issues_model.CommentTypeCode {
|
||||
} else if !comment.Type.HasContentSupport() {
|
||||
ctx.Error(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
@@ -3059,7 +3061,7 @@ func ChangeCommentReaction(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if comment.Type != issues_model.CommentTypeComment && comment.Type != issues_model.CommentTypeCode && comment.Type != issues_model.CommentTypeReview {
|
||||
if !comment.Type.HasContentSupport() {
|
||||
ctx.Error(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
@@ -3175,15 +3177,19 @@ func GetCommentAttachments(ctx *context.Context) {
|
||||
ctx.NotFoundOrServerError("GetCommentByID", issues_model.IsErrCommentNotExist, err)
|
||||
return
|
||||
}
|
||||
|
||||
if !comment.Type.HasAttachmentSupport() {
|
||||
ctx.ServerError("GetCommentAttachments", fmt.Errorf("comment type %v does not support attachments", comment.Type))
|
||||
return
|
||||
}
|
||||
|
||||
attachments := make([]*api.Attachment, 0)
|
||||
if comment.Type == issues_model.CommentTypeComment {
|
||||
if err := comment.LoadAttachments(ctx); err != nil {
|
||||
ctx.ServerError("LoadAttachments", err)
|
||||
return
|
||||
}
|
||||
for i := 0; i < len(comment.Attachments); i++ {
|
||||
attachments = append(attachments, convert.ToAttachment(comment.Attachments[i]))
|
||||
}
|
||||
if err := comment.LoadAttachments(ctx); err != nil {
|
||||
ctx.ServerError("LoadAttachments", err)
|
||||
return
|
||||
}
|
||||
for i := 0; i < len(comment.Attachments); i++ {
|
||||
attachments = append(attachments, convert.ToAttachment(comment.Attachments[i]))
|
||||
}
|
||||
ctx.JSON(http.StatusOK, attachments)
|
||||
}
|
||||
|
||||
@@ -576,6 +576,23 @@ func SetDefaultProjectBoard(ctx *context.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// UnSetDefaultProjectBoard unset default board for uncategorized issues/pulls
|
||||
func UnSetDefaultProjectBoard(ctx *context.Context) {
|
||||
project, _ := checkProjectBoardChangePermissions(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
if err := project_model.SetDefaultBoard(project.ID, 0); err != nil {
|
||||
ctx.ServerError("SetDefaultBoard", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"ok": true,
|
||||
})
|
||||
}
|
||||
|
||||
// MoveIssues moves or keeps issues in a column and sorts them inside that column
|
||||
func MoveIssues(ctx *context.Context) {
|
||||
if ctx.Doer == nil {
|
||||
|
||||
+15
-20
@@ -29,21 +29,17 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
tplReleases base.TplName = "repo/release/list"
|
||||
tplReleaseNew base.TplName = "repo/release/new"
|
||||
tplReleasesList base.TplName = "repo/release/list"
|
||||
tplReleaseNew base.TplName = "repo/release/new"
|
||||
tplTagsList base.TplName = "repo/tag/list"
|
||||
)
|
||||
|
||||
// calReleaseNumCommitsBehind calculates given release has how many commits behind release target.
|
||||
func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model.Release, countCache map[string]int64) error {
|
||||
// Fast return if release target is same as default branch.
|
||||
if repoCtx.BranchName == release.Target {
|
||||
release.NumCommitsBehind = repoCtx.CommitsCount - release.NumCommits
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get count if not exists
|
||||
if _, ok := countCache[release.Target]; !ok {
|
||||
if repoCtx.GitRepo.IsBranchExist(release.Target) {
|
||||
// short-circuit for the default branch
|
||||
if repoCtx.Repository.DefaultBranch == release.Target || repoCtx.GitRepo.IsBranchExist(release.Target) {
|
||||
commit, err := repoCtx.GitRepo.GetBranchCommit(release.Target)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetBranchCommit: %w", err)
|
||||
@@ -63,16 +59,19 @@ func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model
|
||||
|
||||
// Releases render releases list page
|
||||
func Releases(ctx *context.Context) {
|
||||
ctx.Data["PageIsReleaseList"] = true
|
||||
ctx.Data["Title"] = ctx.Tr("repo.release.releases")
|
||||
releasesOrTags(ctx, false)
|
||||
}
|
||||
|
||||
// TagsList render tags list page
|
||||
func TagsList(ctx *context.Context) {
|
||||
ctx.Data["PageIsTagList"] = true
|
||||
ctx.Data["Title"] = ctx.Tr("repo.release.tags")
|
||||
releasesOrTags(ctx, true)
|
||||
}
|
||||
|
||||
func releasesOrTags(ctx *context.Context, isTagList bool) {
|
||||
ctx.Data["PageIsReleaseList"] = true
|
||||
ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
|
||||
ctx.Data["IsViewBranch"] = false
|
||||
ctx.Data["IsViewTag"] = true
|
||||
@@ -80,14 +79,6 @@ func releasesOrTags(ctx *context.Context, isTagList bool) {
|
||||
ctx.Data["CanCreateBranch"] = false
|
||||
ctx.Data["HideBranchesInDropdown"] = true
|
||||
|
||||
if isTagList {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.release.tags")
|
||||
ctx.Data["PageIsTagList"] = true
|
||||
} else {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.release.releases")
|
||||
ctx.Data["PageIsTagList"] = false
|
||||
}
|
||||
|
||||
listOptions := db.ListOptions{
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: ctx.FormInt("limit"),
|
||||
@@ -201,7 +192,11 @@ func releasesOrTags(ctx *context.Context, isTagList bool) {
|
||||
pager.SetDefaultParams(ctx)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplReleases)
|
||||
if isTagList {
|
||||
ctx.HTML(http.StatusOK, tplTagsList)
|
||||
} else {
|
||||
ctx.HTML(http.StatusOK, tplReleasesList)
|
||||
}
|
||||
}
|
||||
|
||||
// ReleasesFeedRSS get feeds for releases in RSS format
|
||||
@@ -287,7 +282,7 @@ func SingleRelease(ctx *context.Context) {
|
||||
}
|
||||
|
||||
ctx.Data["Releases"] = []*repo_model.Release{release}
|
||||
ctx.HTML(http.StatusOK, tplReleases)
|
||||
ctx.HTML(http.StatusOK, tplReleasesList)
|
||||
}
|
||||
|
||||
// LatestRelease redirects to the latest release
|
||||
|
||||
@@ -41,6 +41,8 @@ func SecretsPost(ctx *context.Context) {
|
||||
func DeleteSecret(ctx *context.Context) {
|
||||
shared.PerformSecretsDelete(
|
||||
ctx,
|
||||
0,
|
||||
ctx.Repo.Repository.ID,
|
||||
ctx.Repo.RepoLink+"/settings/secrets",
|
||||
)
|
||||
}
|
||||
+42
-23
@@ -24,6 +24,7 @@ import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/actions"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/charset"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
@@ -39,6 +40,8 @@ import (
|
||||
"code.gitea.io/gitea/modules/typesniffer"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/routers/web/feed"
|
||||
|
||||
"github.com/nektos/act/pkg/model"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -154,16 +157,6 @@ func renderDirectory(ctx *context.Context, treeLink string) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
|
||||
}
|
||||
|
||||
// Check permission to add or upload new file.
|
||||
if ctx.Repo.CanWrite(unit_model.TypeCode) && ctx.Repo.IsViewBranch {
|
||||
ctx.Data["CanAddFile"] = !ctx.Repo.Repository.IsArchived
|
||||
ctx.Data["CanUploadFile"] = setting.Repository.Upload.Enabled && !ctx.Repo.Repository.IsArchived
|
||||
}
|
||||
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
subfolder, readmeFile, err := findReadmeFileInEntries(ctx, entries, true)
|
||||
if err != nil {
|
||||
ctx.ServerError("findReadmeFileInEntries", err)
|
||||
@@ -358,6 +351,15 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
||||
if issueConfigErr != nil {
|
||||
ctx.Data["FileError"] = strings.TrimSpace(issueConfigErr.Error())
|
||||
}
|
||||
} else if actions.IsWorkflow(ctx.Repo.TreePath) {
|
||||
content, err := actions.GetContentFromEntry(entry)
|
||||
if err != nil {
|
||||
log.Error("actions.GetContentFromEntry: %v", err)
|
||||
}
|
||||
_, workFlowErr := model.ReadWorkflow(bytes.NewReader(content))
|
||||
if workFlowErr != nil {
|
||||
ctx.Data["FileError"] = ctx.Locale.Tr("actions.runs.invalid_workflow_helper", workFlowErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
isDisplayingSource := ctx.FormString("display") == "source"
|
||||
@@ -705,10 +707,17 @@ func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) {
|
||||
|
||||
// Home render repository home page
|
||||
func Home(ctx *context.Context) {
|
||||
if setting.EnableFeed {
|
||||
if setting.Other.EnableFeed {
|
||||
isFeed, _, showFeedType := feed.GetFeedType(ctx.Params(":reponame"), ctx.Req)
|
||||
if isFeed {
|
||||
feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType)
|
||||
switch {
|
||||
case ctx.Link == fmt.Sprintf("%s.%s", ctx.Repo.RepoLink, showFeedType):
|
||||
feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType)
|
||||
case ctx.Repo.TreePath == "":
|
||||
feed.ShowBranchFeed(ctx, ctx.Repo.Repository, showFeedType)
|
||||
case ctx.Repo.TreePath != "":
|
||||
feed.ShowFileFeed(ctx, ctx.Repo.Repository, showFeedType)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -868,21 +877,25 @@ func renderRepoTopics(ctx *context.Context) {
|
||||
|
||||
func renderCode(ctx *context.Context) {
|
||||
ctx.Data["PageIsViewCode"] = true
|
||||
ctx.Data["RepositoryUploadEnabled"] = setting.Repository.Upload.Enabled
|
||||
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
reallyEmpty := true
|
||||
if ctx.Repo.Commit == nil || ctx.Repo.Repository.IsEmpty || ctx.Repo.Repository.IsBroken() {
|
||||
showEmpty := true
|
||||
var err error
|
||||
if ctx.Repo.GitRepo != nil {
|
||||
reallyEmpty, err = ctx.Repo.GitRepo.IsEmpty()
|
||||
showEmpty, err = ctx.Repo.GitRepo.IsEmpty()
|
||||
if err != nil {
|
||||
ctx.ServerError("GitRepo.IsEmpty", err)
|
||||
return
|
||||
log.Error("GitRepo.IsEmpty: %v", err)
|
||||
ctx.Repo.Repository.Status = repo_model.RepositoryBroken
|
||||
showEmpty = true
|
||||
ctx.Flash.Error(ctx.Tr("error.occurred"), true)
|
||||
}
|
||||
}
|
||||
if reallyEmpty {
|
||||
if showEmpty {
|
||||
ctx.HTML(http.StatusOK, tplRepoEMPTY)
|
||||
return
|
||||
}
|
||||
|
||||
// the repo is not really empty, so we should update the modal in database
|
||||
// such problem may be caused by:
|
||||
// 1) an error occurs during pushing/receiving. 2) the user replaces an empty git repo manually
|
||||
@@ -898,6 +911,14 @@ func renderCode(ctx *context.Context) {
|
||||
ctx.ServerError("UpdateRepoSize", err)
|
||||
return
|
||||
}
|
||||
|
||||
// the repo's IsEmpty has been updated, redirect to this page to make sure middlewares can get the correct values
|
||||
link := ctx.Link
|
||||
if ctx.Req.URL.RawQuery != "" {
|
||||
link += "?" + ctx.Req.URL.RawQuery
|
||||
}
|
||||
ctx.Redirect(link)
|
||||
return
|
||||
}
|
||||
|
||||
title := ctx.Repo.Repository.Owner.Name + "/" + ctx.Repo.Repository.Name
|
||||
@@ -927,11 +948,9 @@ func renderCode(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !ctx.Repo.Repository.IsEmpty {
|
||||
checkCitationFile(ctx, entry)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
checkCitationFile(ctx, entry)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
renderLanguageStats(ctx)
|
||||
|
||||
+57
-47
@@ -68,9 +68,10 @@ func MustEnableWiki(ctx *context.Context) {
|
||||
|
||||
// PageMeta wiki page meta information
|
||||
type PageMeta struct {
|
||||
Name string
|
||||
SubURL string
|
||||
UpdatedUnix timeutil.TimeStamp
|
||||
Name string
|
||||
SubURL string
|
||||
GitEntryName string
|
||||
UpdatedUnix timeutil.TimeStamp
|
||||
}
|
||||
|
||||
// findEntryForFile finds the tree entry for a target filepath.
|
||||
@@ -83,7 +84,7 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error)
|
||||
return entry, nil
|
||||
}
|
||||
|
||||
// Then the unescaped, shortest alternative
|
||||
// Then the unescaped, the shortest alternative
|
||||
var unescapedTarget string
|
||||
if unescapedTarget, err = url.QueryUnescape(target); err != nil {
|
||||
return nil, err
|
||||
@@ -124,16 +125,16 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte {
|
||||
|
||||
// wikiContentsByName returns the contents of a wiki page, along with a boolean
|
||||
// indicating whether the page exists. Writes to ctx if an error occurs.
|
||||
func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName string) ([]byte, *git.TreeEntry, string, bool) {
|
||||
pageFilename := wiki_service.NameToFilename(wikiName)
|
||||
entry, err := findEntryForFile(commit, pageFilename)
|
||||
func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName wiki_service.WebPath) ([]byte, *git.TreeEntry, string, bool) {
|
||||
gitFilename := wiki_service.WebPathToGitPath(wikiName)
|
||||
entry, err := findEntryForFile(commit, gitFilename)
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
ctx.ServerError("findEntryForFile", err)
|
||||
return nil, nil, "", false
|
||||
} else if entry == nil {
|
||||
return nil, nil, "", true
|
||||
}
|
||||
return wikiContentsByEntry(ctx, entry), entry, pageFilename, false
|
||||
return wikiContentsByEntry(ctx, entry), entry, gitFilename, false
|
||||
}
|
||||
|
||||
func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
|
||||
@@ -162,7 +163,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
|
||||
if !entry.IsRegular() {
|
||||
continue
|
||||
}
|
||||
wikiName, err := wiki_service.FilenameToName(entry.Name())
|
||||
wikiName, err := wiki_service.GitPathToWebPath(entry.Name())
|
||||
if err != nil {
|
||||
if repo_model.IsErrWikiInvalidFileName(err) {
|
||||
continue
|
||||
@@ -175,22 +176,26 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
|
||||
} else if wikiName == "_Sidebar" || wikiName == "_Footer" {
|
||||
continue
|
||||
}
|
||||
_, displayName := wiki_service.WebPathToUserTitle(wikiName)
|
||||
pages = append(pages, PageMeta{
|
||||
Name: wikiName,
|
||||
SubURL: wiki_service.NameToSubURL(wikiName),
|
||||
Name: displayName,
|
||||
SubURL: wiki_service.WebPathToURLPath(wikiName),
|
||||
GitEntryName: entry.Name(),
|
||||
})
|
||||
}
|
||||
ctx.Data["Pages"] = pages
|
||||
|
||||
// get requested pagename
|
||||
pageName := wiki_service.NormalizeWikiName(ctx.Params("*"))
|
||||
// get requested page name
|
||||
pageName := wiki_service.WebPathFromRequest(ctx.Params("*"))
|
||||
if len(pageName) == 0 {
|
||||
pageName = "Home"
|
||||
}
|
||||
ctx.Data["PageURL"] = wiki_service.NameToSubURL(pageName)
|
||||
ctx.Data["old_title"] = pageName
|
||||
ctx.Data["Title"] = pageName
|
||||
ctx.Data["title"] = pageName
|
||||
|
||||
_, displayName := wiki_service.WebPathToUserTitle(pageName)
|
||||
ctx.Data["PageURL"] = wiki_service.WebPathToURLPath(pageName)
|
||||
ctx.Data["old_title"] = displayName
|
||||
ctx.Data["Title"] = displayName
|
||||
ctx.Data["title"] = displayName
|
||||
|
||||
isSideBar := pageName == "_Sidebar"
|
||||
isFooter := pageName == "_Footer"
|
||||
@@ -328,14 +333,17 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
|
||||
}
|
||||
|
||||
// get requested pagename
|
||||
pageName := wiki_service.NormalizeWikiName(ctx.Params("*"))
|
||||
pageName := wiki_service.WebPathFromRequest(ctx.Params("*"))
|
||||
if len(pageName) == 0 {
|
||||
pageName = "Home"
|
||||
}
|
||||
ctx.Data["PageURL"] = wiki_service.NameToSubURL(pageName)
|
||||
ctx.Data["old_title"] = pageName
|
||||
ctx.Data["Title"] = pageName
|
||||
ctx.Data["title"] = pageName
|
||||
|
||||
_, displayName := wiki_service.WebPathToUserTitle(pageName)
|
||||
ctx.Data["PageURL"] = wiki_service.WebPathToURLPath(pageName)
|
||||
ctx.Data["old_title"] = displayName
|
||||
ctx.Data["Title"] = displayName
|
||||
ctx.Data["title"] = displayName
|
||||
|
||||
ctx.Data["Username"] = ctx.Repo.Owner.Name
|
||||
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
|
||||
|
||||
@@ -403,14 +411,16 @@ func renderEditPage(ctx *context.Context) {
|
||||
}()
|
||||
|
||||
// get requested pagename
|
||||
pageName := wiki_service.NormalizeWikiName(ctx.Params("*"))
|
||||
pageName := wiki_service.WebPathFromRequest(ctx.Params("*"))
|
||||
if len(pageName) == 0 {
|
||||
pageName = "Home"
|
||||
}
|
||||
ctx.Data["PageURL"] = wiki_service.NameToSubURL(pageName)
|
||||
ctx.Data["old_title"] = pageName
|
||||
ctx.Data["Title"] = pageName
|
||||
ctx.Data["title"] = pageName
|
||||
|
||||
_, displayName := wiki_service.WebPathToUserTitle(pageName)
|
||||
ctx.Data["PageURL"] = wiki_service.WebPathToURLPath(pageName)
|
||||
ctx.Data["old_title"] = displayName
|
||||
ctx.Data["Title"] = displayName
|
||||
ctx.Data["title"] = displayName
|
||||
|
||||
// lookup filename in wiki - get filecontent, gitTree entry , real filename
|
||||
data, entry, _, noEntry := wikiContentsByName(ctx, commit, pageName)
|
||||
@@ -594,7 +604,7 @@ func WikiPages(ctx *context.Context) {
|
||||
ctx.ServerError("GetCommit", err)
|
||||
return
|
||||
}
|
||||
wikiName, err := wiki_service.FilenameToName(entry.Name())
|
||||
wikiName, err := wiki_service.GitPathToWebPath(entry.Name())
|
||||
if err != nil {
|
||||
if repo_model.IsErrWikiInvalidFileName(err) {
|
||||
continue
|
||||
@@ -602,10 +612,12 @@ func WikiPages(ctx *context.Context) {
|
||||
ctx.ServerError("WikiFilenameToName", err)
|
||||
return
|
||||
}
|
||||
_, displayName := wiki_service.WebPathToUserTitle(wikiName)
|
||||
pages = append(pages, PageMeta{
|
||||
Name: wikiName,
|
||||
SubURL: wiki_service.NameToSubURL(wikiName),
|
||||
UpdatedUnix: timeutil.TimeStamp(c.Author.When.Unix()),
|
||||
Name: displayName,
|
||||
SubURL: wiki_service.WebPathToURLPath(wikiName),
|
||||
GitEntryName: entry.Name(),
|
||||
UpdatedUnix: timeutil.TimeStamp(c.Author.When.Unix()),
|
||||
})
|
||||
}
|
||||
ctx.Data["Pages"] = pages
|
||||
@@ -631,12 +643,12 @@ func WikiRaw(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
providedPath := ctx.Params("*")
|
||||
|
||||
providedWebPath := wiki_service.WebPathFromRequest(ctx.Params("*"))
|
||||
providedGitPath := wiki_service.WebPathToGitPath(providedWebPath)
|
||||
var entry *git.TreeEntry
|
||||
if commit != nil {
|
||||
// Try to find a file with that name
|
||||
entry, err = findEntryForFile(commit, providedPath)
|
||||
entry, err = findEntryForFile(commit, providedGitPath)
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
ctx.ServerError("findFile", err)
|
||||
return
|
||||
@@ -644,10 +656,8 @@ func WikiRaw(ctx *context.Context) {
|
||||
|
||||
if entry == nil {
|
||||
// Try to find a wiki page with that name
|
||||
providedPath = strings.TrimSuffix(providedPath, ".md")
|
||||
|
||||
wikiPath := wiki_service.NameToFilename(providedPath)
|
||||
entry, err = findEntryForFile(commit, wikiPath)
|
||||
providedGitPath = strings.TrimSuffix(providedGitPath, ".md")
|
||||
entry, err = findEntryForFile(commit, providedGitPath)
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
ctx.ServerError("findFile", err)
|
||||
return
|
||||
@@ -694,7 +704,7 @@ func NewWikiPost(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
wikiName := wiki_service.NormalizeWikiName(form.Title)
|
||||
wikiName := wiki_service.UserTitleToWebPath("", form.Title)
|
||||
|
||||
if len(form.Message) == 0 {
|
||||
form.Message = ctx.Tr("repo.editor.add", form.Title)
|
||||
@@ -713,9 +723,9 @@ func NewWikiPost(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
notification.NotifyNewWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName, form.Message)
|
||||
notification.NotifyNewWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(wikiName), form.Message)
|
||||
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + wiki_service.NameToSubURL(wikiName))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + wiki_service.WebPathToURLPath(wikiName))
|
||||
}
|
||||
|
||||
// EditWiki render wiki modify page
|
||||
@@ -745,8 +755,8 @@ func EditWikiPost(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
oldWikiName := wiki_service.NormalizeWikiName(ctx.Params("*"))
|
||||
newWikiName := wiki_service.NormalizeWikiName(form.Title)
|
||||
oldWikiName := wiki_service.WebPathFromRequest(ctx.Params("*"))
|
||||
newWikiName := wiki_service.UserTitleToWebPath("", form.Title)
|
||||
|
||||
if len(form.Message) == 0 {
|
||||
form.Message = ctx.Tr("repo.editor.update", form.Title)
|
||||
@@ -757,14 +767,14 @@ func EditWikiPost(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
notification.NotifyEditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, newWikiName, form.Message)
|
||||
notification.NotifyEditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(newWikiName), form.Message)
|
||||
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + wiki_service.NameToSubURL(newWikiName))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + wiki_service.WebPathToURLPath(newWikiName))
|
||||
}
|
||||
|
||||
// DeleteWikiPagePost delete wiki page
|
||||
func DeleteWikiPagePost(ctx *context.Context) {
|
||||
wikiName := wiki_service.NormalizeWikiName(ctx.Params("*"))
|
||||
wikiName := wiki_service.WebPathFromRequest(ctx.Params("*"))
|
||||
if len(wikiName) == 0 {
|
||||
wikiName = "Home"
|
||||
}
|
||||
@@ -774,7 +784,7 @@ func DeleteWikiPagePost(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
notification.NotifyDeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName)
|
||||
notification.NotifyDeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(wikiName))
|
||||
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"redirect": ctx.Repo.RepoLink + "/wiki/",
|
||||
|
||||
@@ -6,6 +6,7 @@ package repo
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
@@ -24,7 +25,7 @@ const (
|
||||
message = "Wiki commit message for unit tests"
|
||||
)
|
||||
|
||||
func wikiEntry(t *testing.T, repo *repo_model.Repository, wikiName string) *git.TreeEntry {
|
||||
func wikiEntry(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) *git.TreeEntry {
|
||||
wikiRepo, err := git.OpenRepository(git.DefaultContext, repo.WikiPath())
|
||||
assert.NoError(t, err)
|
||||
defer wikiRepo.Close()
|
||||
@@ -33,14 +34,14 @@ func wikiEntry(t *testing.T, repo *repo_model.Repository, wikiName string) *git.
|
||||
entries, err := commit.ListEntries()
|
||||
assert.NoError(t, err)
|
||||
for _, entry := range entries {
|
||||
if entry.Name() == wiki_service.NameToFilename(wikiName) {
|
||||
if entry.Name() == wiki_service.WebPathToGitPath(wikiName) {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func wikiContent(t *testing.T, repo *repo_model.Repository, wikiName string) string {
|
||||
func wikiContent(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) string {
|
||||
entry := wikiEntry(t, repo, wikiName)
|
||||
if !assert.NotNil(t, entry) {
|
||||
return ""
|
||||
@@ -53,11 +54,11 @@ func wikiContent(t *testing.T, repo *repo_model.Repository, wikiName string) str
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
func assertWikiExists(t *testing.T, repo *repo_model.Repository, wikiName string) {
|
||||
func assertWikiExists(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) {
|
||||
assert.NotNil(t, wikiEntry(t, repo, wikiName))
|
||||
}
|
||||
|
||||
func assertWikiNotExists(t *testing.T, repo *repo_model.Repository, wikiName string) {
|
||||
func assertWikiNotExists(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) {
|
||||
assert.Nil(t, wikiEntry(t, repo, wikiName))
|
||||
}
|
||||
|
||||
@@ -124,8 +125,8 @@ func TestNewWikiPost(t *testing.T) {
|
||||
})
|
||||
NewWikiPost(ctx)
|
||||
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
|
||||
assertWikiExists(t, ctx.Repo.Repository, title)
|
||||
assert.Equal(t, wikiContent(t, ctx.Repo.Repository, title), content)
|
||||
assertWikiExists(t, ctx.Repo.Repository, wiki_service.UserTitleToWebPath("", title))
|
||||
assert.Equal(t, wikiContent(t, ctx.Repo.Repository, wiki_service.UserTitleToWebPath("", title)), content)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,8 +177,8 @@ func TestEditWikiPost(t *testing.T) {
|
||||
})
|
||||
EditWikiPost(ctx)
|
||||
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
|
||||
assertWikiExists(t, ctx.Repo.Repository, title)
|
||||
assert.Equal(t, wikiContent(t, ctx.Repo.Repository, title), content)
|
||||
assertWikiExists(t, ctx.Repo.Repository, wiki_service.UserTitleToWebPath("", title))
|
||||
assert.Equal(t, wikiContent(t, ctx.Repo.Repository, wiki_service.UserTitleToWebPath("", title)), content)
|
||||
if title != "Home" {
|
||||
assertWikiNotExists(t, ctx.Repo.Repository, "Home")
|
||||
}
|
||||
@@ -201,17 +202,21 @@ func TestWikiRaw(t *testing.T) {
|
||||
"images/jpeg.jpg": "image/jpeg",
|
||||
"Page With Spaced Name": "text/plain; charset=utf-8",
|
||||
"Page-With-Spaced-Name": "text/plain; charset=utf-8",
|
||||
"Page With Spaced Name.md": "text/plain; charset=utf-8",
|
||||
"Page With Spaced Name.md": "", // there is no "Page With Spaced Name.md" in repo
|
||||
"Page-With-Spaced-Name.md": "text/plain; charset=utf-8",
|
||||
} {
|
||||
unittest.PrepareTestEnv(t)
|
||||
|
||||
ctx := test.MockContext(t, "user2/repo1/wiki/raw/"+filepath)
|
||||
ctx := test.MockContext(t, "user2/repo1/wiki/raw/"+url.PathEscape(filepath))
|
||||
ctx.SetParams("*", filepath)
|
||||
test.LoadUser(t, ctx, 2)
|
||||
test.LoadRepo(t, ctx, 1)
|
||||
WikiRaw(ctx)
|
||||
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
|
||||
assert.EqualValues(t, filetype, ctx.Resp.Header().Get("Content-Type"))
|
||||
if filetype == "" {
|
||||
assert.EqualValues(t, http.StatusNotFound, ctx.Resp.Status(), "filepath: %s", filepath)
|
||||
} else {
|
||||
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status(), "filepath: %s", filepath)
|
||||
assert.EqualValues(t, filetype, ctx.Resp.Header().Get("Content-Type"), "filepath: %s", filepath)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,10 +38,10 @@ func PerformSecretsPost(ctx *context.Context, ownerID, repoID int64, redirectURL
|
||||
ctx.Redirect(redirectURL)
|
||||
}
|
||||
|
||||
func PerformSecretsDelete(ctx *context.Context, redirectURL string) {
|
||||
func PerformSecretsDelete(ctx *context.Context, ownerID, repoID int64, redirectURL string) {
|
||||
id := ctx.FormInt64("id")
|
||||
|
||||
if _, err := db.DeleteByBean(ctx, &secret_model.Secret{ID: id}); err != nil {
|
||||
if _, err := db.DeleteByBean(ctx, &secret_model.Secret{ID: id, OwnerID: ownerID, RepoID: repoID}); err != nil {
|
||||
log.Error("Delete secret %d failed: %v", id, err)
|
||||
ctx.Flash.Error(ctx.Tr("secrets.deletion.failed"))
|
||||
} else {
|
||||
|
||||
@@ -63,7 +63,7 @@ func Profile(ctx *context.Context) {
|
||||
|
||||
ctx.Data["Title"] = ctx.ContextUser.DisplayName()
|
||||
ctx.Data["PageIsUserProfile"] = true
|
||||
ctx.Data["Owner"] = ctx.ContextUser
|
||||
ctx.Data["ContextUser"] = ctx.ContextUser
|
||||
ctx.Data["OpenIDs"] = openIDs
|
||||
ctx.Data["IsFollowing"] = isFollowing
|
||||
|
||||
|
||||
@@ -326,7 +326,7 @@ func Repos(ctx *context.Context) {
|
||||
|
||||
ctx.Data["Repos"] = repos
|
||||
}
|
||||
ctx.Data["Owner"] = ctxUser
|
||||
ctx.Data["ContextUser"] = ctxUser
|
||||
pager := context.NewPagination(count, opts.PageSize, opts.Page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
@@ -40,6 +40,8 @@ func SecretsPost(ctx *context.Context) {
|
||||
func SecretsDelete(ctx *context.Context) {
|
||||
shared.PerformSecretsDelete(
|
||||
ctx,
|
||||
ctx.Doer.ID,
|
||||
0,
|
||||
setting.AppSubURL+"/user/settings/secrets",
|
||||
)
|
||||
}
|
||||
+30
-21
@@ -103,7 +103,7 @@ func buildAuthGroup() *auth_service.Group {
|
||||
func Routes(ctx gocontext.Context) *web.Route {
|
||||
routes := web.NewRoute()
|
||||
|
||||
routes.Use(web.WrapWithPrefix("/assets/", web.Wrap(CorsHandler(), public.AssetsHandlerFunc("/assets/")), "AssetsHandler"))
|
||||
routes.Use(web.MiddlewareWithPrefix("/assets/", CorsHandler(), public.AssetsHandlerFunc("/assets/")))
|
||||
|
||||
sessioner := session.Sessioner(session.Options{
|
||||
Provider: setting.SessionConfig.Provider,
|
||||
@@ -123,8 +123,8 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
routes.Use(Recovery(ctx))
|
||||
|
||||
// We use r.Route here over r.Use because this prevents requests that are not for avatars having to go through this additional handler
|
||||
routes.Route("/avatars/*", "GET, HEAD", storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
|
||||
routes.Route("/repo-avatars/*", "GET, HEAD", storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars))
|
||||
routes.RouteMethods("/avatars/*", "GET, HEAD", storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
|
||||
routes.RouteMethods("/repo-avatars/*", "GET, HEAD", storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars))
|
||||
|
||||
// for health check - doesn't need to be passed through gzip handler
|
||||
routes.Head("/", func(w http.ResponseWriter, req *http.Request) {
|
||||
@@ -153,7 +153,7 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
|
||||
if setting.Service.EnableCaptcha {
|
||||
// The captcha http.Handler should only fire on /captcha/* so we can just mount this on that url
|
||||
routes.Route("/captcha/*", "GET,HEAD", append(common, captcha.Captchaer(context.GetImageCaptcha()))...)
|
||||
routes.RouteMethods("/captcha/*", "GET,HEAD", append(common, captcha.Captchaer(context.GetImageCaptcha()))...)
|
||||
}
|
||||
|
||||
if setting.HasRobotsTxt {
|
||||
@@ -228,11 +228,11 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
|
||||
// RegisterRoutes register routes
|
||||
func RegisterRoutes(m *web.Route) {
|
||||
reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true})
|
||||
ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView})
|
||||
ignExploreSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView})
|
||||
ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true})
|
||||
reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true})
|
||||
reqSignIn := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignInRequired: true})
|
||||
ignSignIn := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignInRequired: setting.Service.RequireSignInView})
|
||||
ignExploreSignIn := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignInRequired: setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView})
|
||||
ignSignInAndCsrf := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{DisableCSRF: true})
|
||||
reqSignOut := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignOutRequired: true})
|
||||
validation.AddBindingRules()
|
||||
|
||||
linkAccountEnabled := func(ctx *context.Context) {
|
||||
@@ -293,7 +293,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
}
|
||||
|
||||
sitemapEnabled := func(ctx *context.Context) {
|
||||
if !setting.EnableSitemap {
|
||||
if !setting.Other.EnableSitemap {
|
||||
ctx.Error(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
@@ -307,7 +307,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
}
|
||||
|
||||
feedEnabled := func(ctx *context.Context) {
|
||||
if !setting.EnableFeed {
|
||||
if !setting.Other.EnableFeed {
|
||||
ctx.Error(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
@@ -551,7 +551,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
|
||||
m.Get("/avatar/{hash}", user.AvatarByEmailHash)
|
||||
|
||||
adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true})
|
||||
adminReq := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignInRequired: true, AdminRequired: true})
|
||||
|
||||
// ***** START: Admin *****
|
||||
m.Group("/admin", func() {
|
||||
@@ -706,7 +706,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
default:
|
||||
context_service.UserAssignmentWeb()(ctx)
|
||||
if !ctx.Written() {
|
||||
ctx.Data["EnableFeed"] = setting.EnableFeed
|
||||
ctx.Data["EnableFeed"] = setting.Other.EnableFeed
|
||||
user.Profile(ctx)
|
||||
}
|
||||
}
|
||||
@@ -856,7 +856,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Post("/delete", org.SecretsDelete)
|
||||
})
|
||||
|
||||
m.Route("/delete", "GET,POST", org.SettingsDelete)
|
||||
m.RouteMethods("/delete", "GET,POST", org.SettingsDelete)
|
||||
|
||||
m.Group("/packages", func() {
|
||||
m.Get("", org.Packages)
|
||||
@@ -936,6 +936,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Put("", web.Bind(forms.EditProjectBoardForm{}), org.EditProjectBoard)
|
||||
m.Delete("", org.DeleteProjectBoard)
|
||||
m.Post("/default", org.SetDefaultProjectBoard)
|
||||
m.Post("/unsetdefault", org.UnsetDefaultProjectBoard)
|
||||
|
||||
m.Post("/move", org.MoveIssues)
|
||||
})
|
||||
@@ -1184,7 +1185,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Post("/upload-file", repo.UploadFileToServer)
|
||||
m.Post("/upload-remove", web.Bind(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
|
||||
}, repo.MustBeEditable, repo.MustBeAbleToUpload)
|
||||
}, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived(), repo.MustBeNotEmpty)
|
||||
}, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived())
|
||||
|
||||
m.Group("/branches", func() {
|
||||
m.Group("/_new", func() {
|
||||
@@ -1197,15 +1198,21 @@ func RegisterRoutes(m *web.Route) {
|
||||
}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
|
||||
}, reqSignIn, context.RepoAssignment, context.UnitTypes())
|
||||
|
||||
// Releases
|
||||
// Tags
|
||||
m.Group("/{username}/{reponame}", func() {
|
||||
m.Group("/tags", func() {
|
||||
m.Get("", repo.TagsList)
|
||||
m.Get(".rss", feedEnabled, repo.TagsListFeedRSS)
|
||||
m.Get(".atom", feedEnabled, repo.TagsListFeedAtom)
|
||||
}, func(ctx *context.Context) {
|
||||
ctx.Data["EnableFeed"] = setting.EnableFeed
|
||||
ctx.Data["EnableFeed"] = setting.Other.EnableFeed
|
||||
}, repo.MustBeNotEmpty, reqRepoCodeReader, context.RepoRefByType(context.RepoRefTag, true))
|
||||
m.Post("/tags/delete", repo.DeleteTag, reqSignIn,
|
||||
repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef())
|
||||
}, reqSignIn, context.RepoAssignment, context.UnitTypes())
|
||||
|
||||
// Releases
|
||||
m.Group("/{username}/{reponame}", func() {
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/", repo.Releases)
|
||||
m.Get("/tag/*", repo.SingleRelease)
|
||||
@@ -1213,7 +1220,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Get(".rss", feedEnabled, repo.ReleasesFeedRSS)
|
||||
m.Get(".atom", feedEnabled, repo.ReleasesFeedAtom)
|
||||
}, func(ctx *context.Context) {
|
||||
ctx.Data["EnableFeed"] = setting.EnableFeed
|
||||
ctx.Data["EnableFeed"] = setting.Other.EnableFeed
|
||||
}, repo.MustBeNotEmpty, reqRepoReleaseReader, context.RepoRefByType(context.RepoRefTag, true))
|
||||
m.Get("/releases/attachments/{uuid}", repo.GetAttachment, repo.MustBeNotEmpty, reqRepoReleaseReader)
|
||||
m.Group("/releases", func() {
|
||||
@@ -1223,8 +1230,6 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Post("/attachments", repo.UploadReleaseAttachment)
|
||||
m.Post("/attachments/remove", repo.DeleteAttachment)
|
||||
}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, context.RepoRef())
|
||||
m.Post("/tags/delete", repo.DeleteTag, reqSignIn,
|
||||
repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef())
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/edit/*", repo.EditRelease)
|
||||
m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost)
|
||||
@@ -1292,6 +1297,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Put("", web.Bind(forms.EditProjectBoardForm{}), repo.EditProjectBoard)
|
||||
m.Delete("", repo.DeleteProjectBoard)
|
||||
m.Post("/default", repo.SetDefaultProjectBoard)
|
||||
m.Post("/unsetdefault", repo.UnSetDefaultProjectBoard)
|
||||
|
||||
m.Post("/move", repo.MoveIssues)
|
||||
})
|
||||
@@ -1448,6 +1454,9 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Get("/cherry-pick/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
|
||||
}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
|
||||
|
||||
m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
|
||||
m.Get("/atom/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
|
||||
|
||||
m.Group("/src", func() {
|
||||
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.Home)
|
||||
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.Home)
|
||||
@@ -1506,7 +1515,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.GetOptions("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
|
||||
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
|
||||
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
|
||||
}, ignSignInAndCsrf, context_service.UserAssignmentWeb())
|
||||
}, ignSignInAndCsrf, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb())
|
||||
})
|
||||
})
|
||||
// ***** END: Repository *****
|
||||
|
||||
Reference in new issue
Block a user