Merge branch 'main' into pacman-packages

This commit is contained in:
Danila Fominykh 2023-08-08 16:00:19 +03:00 committed by GitHub
commit 2548414865
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 477 additions and 163 deletions

View File

@ -2,9 +2,38 @@
This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.io).
been added to each release, please refer to the [blog](https://blog.gitea.com).
## [1.20.2](https://github.com/go-gitea/gitea/releases/tag/1.20.2) - 2023-07-29
## [1.20.3](https://github.com/go-gitea/gitea/releases/tag/v1.20.3) - 2023-08-07
* BREAKING
* Fix the wrong derive path (#26271) (#26318)
* SECURITY
* Fix API leaking Usermail if not logged in (#25097) (#26350)
* ENHANCEMENTS
* Display human-readable text instead of cryptic filemodes (#26352) (#26358)
* Hide `last indexed SHA` when a repo could not be indexed yet (#26340) (#26345)
* Fix the topic validation rule and suport dots (#26286) (#26303)
* Fix due date rendering the wrong date in issue (#26268) (#26274)
* Don't autosize textarea in diff view (#26233) (#26244)
* Fix commit compare style (#26209) (#26226)
* Warn instead of reporting an error when a webhook cannot be found (#26039) (#26211)
* BUGFIXES
* Bypass MariaDB performance bug of the "IN" sub-query, fix incorrect IssueIndex (#26279) (#26368)
* Fix incorrect CLI exit code and duplicate error message (#26346) (#26347)
* Prevent newline errors with Debian packages (#26332) (#26342)
* Fix bug with sqlite load read (#26305) (#26339)
* Make git batch operations use parent context timeout instead of default timeout (#26325) (#26330)
* Support getting changed files when commit ID is `EmptySHA` (#26290) (#26316)
* Clarify the logger's MODE config option (#26267) (#26281)
* Use shared template for webhook icons (#26242) (#26246)
* Fix pull request check list is limited (#26179) (#26245)
* Fix attachment clipboard copy on insecure origin (#26224) (#26231)
* Fix access check for org-level project (#26182) (#26223)
* MISC
* Upgrade x/net to 0.13.0 (#26301)
## [1.20.2](https://github.com/go-gitea/gitea/releases/tag/v1.20.2) - 2023-07-29
* ENHANCEMENTS
* Calculate MAX_WORKERS default value by CPU number (#26177) (#26183)
@ -32,7 +61,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Fix wrong workflow status when rerun a job in an already finished workflow (#26119) (#26124)
* Fix duplicated url prefix on issue context menu (#26066) (#26067)
## [1.20.1](https://github.com/go-gitea/gitea/releases/tag/1.20.1) - 2023-07-22
## [1.20.1](https://github.com/go-gitea/gitea/releases/tag/v1.20.1) - 2023-07-22
* SECURITY
* Disallow dangerous URL schemes (#25960) (#25964)

View File

@ -685,18 +685,34 @@ func NotifyWatchersActions(acts []*Action) error {
}
// DeleteIssueActions delete all actions related with issueID
func DeleteIssueActions(ctx context.Context, repoID, issueID int64) error {
func DeleteIssueActions(ctx context.Context, repoID, issueID, issueIndex int64) error {
// delete actions assigned to this issue
subQuery := builder.Select("`id`").
From("`comment`").
Where(builder.Eq{"`issue_id`": issueID})
if _, err := db.GetEngine(ctx).In("comment_id", subQuery).Delete(&Action{}); err != nil {
return err
e := db.GetEngine(ctx)
// MariaDB has a performance bug: https://jira.mariadb.org/browse/MDEV-16289
// so here it uses "DELETE ... WHERE IN" with pre-queried IDs.
var lastCommentID int64
commentIDs := make([]int64, 0, db.DefaultMaxInSize)
for {
commentIDs = commentIDs[:0]
err := e.Select("`id`").Table(&issues_model.Comment{}).
Where(builder.Eq{"issue_id": issueID}).And("`id` > ?", lastCommentID).
OrderBy("`id`").Limit(db.DefaultMaxInSize).
Find(&commentIDs)
if err != nil {
return err
} else if len(commentIDs) == 0 {
break
} else if _, err = db.GetEngine(ctx).In("comment_id", commentIDs).Delete(&Action{}); err != nil {
return err
} else {
lastCommentID = commentIDs[len(commentIDs)-1]
}
}
_, err := db.GetEngine(ctx).Table("action").Where("repo_id = ?", repoID).
_, err := e.Where("repo_id = ?", repoID).
In("op_type", ActionCreateIssue, ActionCreatePullRequest).
Where("content LIKE ?", strconv.FormatInt(issueID, 10)+"|%").
Where("content LIKE ?", strconv.FormatInt(issueIndex, 10)+"|%"). // "IssueIndex|content..."
Delete(&Action{})
return err
}

View File

@ -4,6 +4,7 @@
package activities_test
import (
"fmt"
"path"
"testing"
@ -284,3 +285,36 @@ func TestConsistencyUpdateAction(t *testing.T) {
assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions))
unittest.CheckConsistencyFor(t, &activities_model.Action{})
}
func TestDeleteIssueActions(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
// load an issue
issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4})
assert.NotEqualValues(t, issue.ID, issue.Index) // it needs to use different ID/Index to test the DeleteIssueActions to delete some actions by IssueIndex
// insert a comment
err := db.Insert(db.DefaultContext, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID})
assert.NoError(t, err)
comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID})
// truncate action table and insert some actions
err = db.TruncateBeans(db.DefaultContext, &activities_model.Action{})
assert.NoError(t, err)
err = db.Insert(db.DefaultContext, &activities_model.Action{
OpType: activities_model.ActionCommentIssue,
CommentID: comment.ID,
})
assert.NoError(t, err)
err = db.Insert(db.DefaultContext, &activities_model.Action{
OpType: activities_model.ActionCreateIssue,
RepoID: issue.RepoID,
Content: fmt.Sprintf("%d|content...", issue.Index),
})
assert.NoError(t, err)
// assert that the actions exist, then delete them
unittest.AssertCount(t, &activities_model.Action{}, 2)
assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index))
unittest.AssertCount(t, &activities_model.Action{}, 0)
}

View File

@ -637,3 +637,15 @@
repo_id: 58
type: 5
created_unix: 946684810
-
id: 96
repo_id: 49
type: 1
created_unix: 946684810
-
id: 97
repo_id: 49
type: 2
created_unix: 946684810

View File

@ -854,8 +854,8 @@ func (issue *Issue) MovePin(ctx context.Context, newPosition int) error {
}
// GetPinnedIssues returns the pinned Issues for the given Repo and type
func GetPinnedIssues(ctx context.Context, repoID int64, isPull bool) ([]*Issue, error) {
issues := make([]*Issue, 0)
func GetPinnedIssues(ctx context.Context, repoID int64, isPull bool) (IssueList, error) {
issues := make(IssueList, 0)
err := db.GetEngine(ctx).
Table("issue").
@ -868,7 +868,7 @@ func GetPinnedIssues(ctx context.Context, repoID int64, isPull bool) ([]*Issue,
return nil, err
}
err = IssueList(issues).LoadAttributes(ctx)
err = issues.LoadAttributes(ctx)
if err != nil {
return nil, err
}

View File

@ -53,7 +53,7 @@ func (issue *Issue) projectBoardID(ctx context.Context) int64 {
// LoadIssuesFromBoard load issues assigned to this board
func LoadIssuesFromBoard(ctx context.Context, b *project_model.Board) (IssueList, error) {
issueList := make([]*Issue, 0, 10)
issueList := make(IssueList, 0, 10)
if b.ID != 0 {
issues, err := Issues(ctx, &IssuesOptions{
@ -79,7 +79,7 @@ func LoadIssuesFromBoard(ctx context.Context, b *project_model.Board) (IssueList
issueList = append(issueList, issues...)
}
if err := IssueList(issueList).LoadComments(ctx); err != nil {
if err := issueList.LoadComments(ctx); err != nil {
return nil, err
}

View File

@ -441,7 +441,7 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i
}
// Issues returns a list of issues by given conditions.
func Issues(ctx context.Context, opts *IssuesOptions) ([]*Issue, error) {
func Issues(ctx context.Context, opts *IssuesOptions) (IssueList, error) {
sess := db.GetEngine(ctx).
Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
applyLimit(sess, opts)

View File

@ -5,6 +5,7 @@
package context
import (
"context"
"html"
"html/template"
"io"
@ -31,14 +32,16 @@ import (
// Render represents a template render
type Render interface {
TemplateLookup(tmpl string) (templates.TemplateExecutor, error)
HTML(w io.Writer, status int, name string, data any) error
TemplateLookup(tmpl string, templateCtx context.Context) (templates.TemplateExecutor, error)
HTML(w io.Writer, status int, name string, data any, templateCtx context.Context) error
}
// Context represents context of a request.
type Context struct {
*Base
TemplateContext TemplateContext
Render Render
PageData map[string]any // data used by JavaScript modules in one page, it's `window.config.pageData`
@ -60,6 +63,8 @@ type Context struct {
Package *Package
}
type TemplateContext map[string]any
func init() {
web.RegisterResponseStatusProvider[*Context](func(req *http.Request) web_types.ResponseStatusProvider {
return req.Context().Value(WebContextKey).(*Context)
@ -133,8 +138,12 @@ func Contexter() func(next http.Handler) http.Handler {
}
defer baseCleanUp()
// TODO: "install.go" also shares the same logic, which should be refactored to a general function
ctx.TemplateContext = NewTemplateContext(ctx)
ctx.TemplateContext["Locale"] = ctx.Locale
ctx.Data.MergeFrom(middleware.CommonTemplateContextData())
ctx.Data["Context"] = &ctx
ctx.Data["Context"] = ctx // TODO: use "ctx" in template and remove this
ctx.Data["CurrentURL"] = setting.AppSubURL + req.URL.RequestURI()
ctx.Data["Link"] = ctx.Link
ctx.Data["locale"] = ctx.Locale

View File

@ -75,7 +75,7 @@ func (ctx *Context) HTML(status int, name base.TplName) {
return strconv.FormatInt(time.Since(tmplStartTime).Nanoseconds()/1e6, 10) + "ms"
}
err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data)
err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data, ctx.TemplateContext)
if err == nil {
return
}
@ -93,7 +93,7 @@ func (ctx *Context) HTML(status int, name base.TplName) {
// RenderToString renders the template content to a string
func (ctx *Context) RenderToString(name base.TplName, data map[string]any) (string, error) {
var buf strings.Builder
err := ctx.Render.HTML(&buf, http.StatusOK, string(name), data)
err := ctx.Render.HTML(&buf, http.StatusOK, string(name), data, ctx.TemplateContext)
return buf.String(), err
}

View File

@ -0,0 +1,49 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package context
import (
"context"
"errors"
"time"
"code.gitea.io/gitea/modules/log"
)
var _ context.Context = TemplateContext(nil)
func NewTemplateContext(ctx context.Context) TemplateContext {
return TemplateContext{"_ctx": ctx}
}
func (c TemplateContext) parentContext() context.Context {
return c["_ctx"].(context.Context)
}
func (c TemplateContext) Deadline() (deadline time.Time, ok bool) {
return c.parentContext().Deadline()
}
func (c TemplateContext) Done() <-chan struct{} {
return c.parentContext().Done()
}
func (c TemplateContext) Err() error {
return c.parentContext().Err()
}
func (c TemplateContext) Value(key any) any {
return c.parentContext().Value(key)
}
// DataRaceCheck checks whether the template context function "ctx()" returns the consistent context
// as the current template's rendering context (request context), to help to find data race issues as early as possible.
// When the code is proven to be correct and stable, this function should be removed.
func (c TemplateContext) DataRaceCheck(dataCtx context.Context) (string, error) {
if c.parentContext() != dataCtx {
log.Error("TemplateContext.DataRaceCheck: parent context mismatch\n%s", log.Stack(2))
return "", errors.New("parent context mismatch")
}
return "", nil
}

View File

@ -852,7 +852,7 @@ func fullIssuePatternProcessor(ctx *RenderContext, node *html.Node) {
}
func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
if ctx.Metas == nil {
if ctx.Metas == nil || ctx.Metas["mode"] == "document" {
return
}
var (

View File

@ -262,6 +262,30 @@ func TestRender_IssueIndexPattern5(t *testing.T) {
})
}
func TestRender_IssueIndexPattern_Document(t *testing.T) {
setting.AppURL = TestAppURL
metas := map[string]string{
"format": "https://someurl.com/{user}/{repo}/{index}",
"user": "someUser",
"repo": "someRepo",
"style": IssueNameStyleNumeric,
"mode": "document",
}
testRenderIssueIndexPattern(t, "#1", "#1", &RenderContext{
Ctx: git.DefaultContext,
Metas: metas,
})
testRenderIssueIndexPattern(t, "#1312", "#1312", &RenderContext{
Ctx: git.DefaultContext,
Metas: metas,
})
testRenderIssueIndexPattern(t, "!1", "!1", &RenderContext{
Ctx: git.DefaultContext,
Metas: metas,
})
}
func testRenderIssueIndexPattern(t *testing.T, input, expected string, ctx *RenderContext) {
if ctx.URLPrefix == "" {
ctx.URLPrefix = TestAppURL

View File

@ -529,6 +529,42 @@ func Test_ParseClusterFuzz(t *testing.T) {
assert.NotContains(t, res.String(), "<html")
}
func TestPostProcess_RenderDocument(t *testing.T) {
setting.AppURL = TestAppURL
localMetas := map[string]string{
"user": "go-gitea",
"repo": "gitea",
"mode": "document",
}
test := func(input, expected string) {
var res strings.Builder
err := PostProcess(&RenderContext{
Ctx: git.DefaultContext,
URLPrefix: "https://example.com",
Metas: localMetas,
}, strings.NewReader(input), &res)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res.String()))
}
// Issue index shouldn't be post processing in an document.
test(
"#1",
"#1")
// Test that other post processing still works.
test(
":gitea:",
`<span class="emoji" aria-label="gitea"><img alt=":gitea:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/gitea.png"/></span>`)
test(
"Some text with 😄 in the middle",
`Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span> in the middle`)
test("http://localhost:3000/person/repo/issues/4#issuecomment-1234",
`<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234" class="ref-issue">person/repo#4 (comment)</a>`)
}
func TestIssue16020(t *testing.T) {
setting.AppURL = TestAppURL

View File

@ -5,7 +5,6 @@
package templates
import (
"context"
"fmt"
"html"
"html/template"
@ -13,7 +12,6 @@ import (
"strings"
"time"
system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/emoji"
"code.gitea.io/gitea/modules/markup"
@ -28,6 +26,8 @@ import (
// NewFuncMap returns functions for injecting to templates
func NewFuncMap() template.FuncMap {
return map[string]any{
"ctx": func() any { return nil }, // template context function
"DumpVar": dumpVar,
// -----------------------------------------------------------------
@ -57,7 +57,6 @@ func NewFuncMap() template.FuncMap {
"avatarHTML": AvatarHTML,
"avatarByAction": AvatarByAction,
"avatarByEmail": AvatarByEmail,
"repoAvatar": RepoAvatar,
"EntryIcon": base.EntryIcon,
"MigrationIcon": MigrationIcon,
"ActionIcon": ActionIcon,
@ -103,9 +102,6 @@ func NewFuncMap() template.FuncMap {
"AssetVersion": func() string {
return setting.AssetVersion
},
"DisableGravatar": func(ctx context.Context) bool {
return system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar)
},
"DefaultShowFullName": func() bool {
return setting.UI.DefaultShowFullName
},

View File

@ -6,6 +6,7 @@ package templates
import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
"io"
@ -39,27 +40,28 @@ var (
var ErrTemplateNotInitialized = errors.New("template system is not initialized, check your log for errors")
func (h *HTMLRender) HTML(w io.Writer, status int, name string, data any) error {
func (h *HTMLRender) HTML(w io.Writer, status int, name string, data any, ctx context.Context) error { //nolint:revive
if respWriter, ok := w.(http.ResponseWriter); ok {
if respWriter.Header().Get("Content-Type") == "" {
respWriter.Header().Set("Content-Type", "text/html; charset=utf-8")
}
respWriter.WriteHeader(status)
}
t, err := h.TemplateLookup(name)
t, err := h.TemplateLookup(name, ctx)
if err != nil {
return texttemplate.ExecError{Name: name, Err: err}
}
return t.Execute(w, data)
}
func (h *HTMLRender) TemplateLookup(name string) (TemplateExecutor, error) {
func (h *HTMLRender) TemplateLookup(name string, ctx context.Context) (TemplateExecutor, error) { //nolint:revive
tmpls := h.templates.Load()
if tmpls == nil {
return nil, ErrTemplateNotInitialized
}
return tmpls.Executor(name, NewFuncMap())
m := NewFuncMap()
m["ctx"] = func() any { return ctx }
return tmpls.Executor(name, m)
}
func (h *HTMLRender) CompileTemplates() error {

View File

@ -60,17 +60,6 @@ func AvatarByAction(ctx context.Context, action *activities_model.Action, others
return Avatar(ctx, action.ActUser, others...)
}
// RepoAvatar renders repo avatars. args: repo, size(int), class (string)
func RepoAvatar(repo *repo_model.Repository, others ...any) template.HTML {
size, class := gitea_html.ParseSizeAndClass(avatars.DefaultAvatarPixelSize, avatars.DefaultAvatarClass, others...)
src := repo.RelAvatarLink()
if src != "" {
return AvatarHTML(src, size, class, repo.FullName())
}
return template.HTML("")
}
// AvatarByEmail renders avatars by email address. args: email, name, size (int), class (string)
func AvatarByEmail(ctx context.Context, email, name string, others ...any) template.HTML {
size, class := gitea_html.ParseSizeAndClass(avatars.DefaultAvatarPixelSize, avatars.DefaultAvatarClass, others...)

View File

@ -5,10 +5,10 @@ package templates
import (
"context"
"fmt"
"html/template"
"mime"
"path/filepath"
"strconv"
"strings"
"time"
@ -174,23 +174,12 @@ func FilenameIsImage(filename string) bool {
return strings.HasPrefix(mimeType, "image/")
}
func TabSizeClass(ec any, filename string) string {
var (
value *editorconfig.Editorconfig
ok bool
)
func TabSizeClass(ec *editorconfig.Editorconfig, filename string) string {
if ec != nil {
if value, ok = ec.(*editorconfig.Editorconfig); !ok || value == nil {
return "tab-size-8"
}
def, err := value.GetDefinitionForFilename(filename)
if err != nil {
log.Error("tab size class: getting definition for filename: %v", err)
return "tab-size-8"
}
if def.TabWidth > 0 {
return fmt.Sprintf("tab-size-%d", def.TabWidth)
def, err := ec.GetDefinitionForFilename(filename)
if err == nil && def.TabWidth >= 1 && def.TabWidth <= 16 {
return "tab-size-" + strconv.Itoa(def.TabWidth)
}
}
return "tab-size-8"
return "tab-size-4"
}

View File

@ -150,11 +150,11 @@ func LoadGitRepo(t *testing.T, ctx *context.Context) {
type mockRender struct{}
func (tr *mockRender) TemplateLookup(tmpl string) (templates.TemplateExecutor, error) {
func (tr *mockRender) TemplateLookup(tmpl string, _ gocontext.Context) (templates.TemplateExecutor, error) {
return nil, nil
}
func (tr *mockRender) HTML(w io.Writer, status int, _ string, _ any) error {
func (tr *mockRender) HTML(w io.Writer, status int, _ string, _ any, _ gocontext.Context) error {
if resp, ok := w.(http.ResponseWriter); ok {
resp.WriteHeader(status)
}

16
options/license/HP-1989 Normal file
View File

@ -0,0 +1,16 @@
Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca.
Digital Equipment Corporation, Maynard, Mass.
Copyright (c) 1998 Microsoft.
To anyone who acknowledges that this file is provided "AS IS"
without any express or implied warranty: permission to use, copy,
modify, and distribute this file for any purpose is hereby
granted without fee, provided that the above copyright notices and
this notice appears in all source code copies, and that none of
the names of Open Software Foundation, Inc., Hewlett-Packard
Company, Microsoft, or Digital Equipment Corporation be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission. Neither Open Software
Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
Equipment Corporation makes any representations about the
suitability of this software for any purpose.

7
options/license/Soundex Normal file
View File

@ -0,0 +1,7 @@
# (c) Copyright 1998-2007 by Mark Mielke # # Freedom to use
these sources for whatever you want, as long as credit # is
given where credit is due, is hereby granted. You may make
modifications # where you see fit but leave this copyright
somewhere visible. As well, try # to initial any changes you
make so that if I like the changes I can # incorporate them
into later versions. # # - Mark Mielke <mark@mielke.cc>

View File

@ -0,0 +1,4 @@
As a special exception, when this file is read by TeX when
processing a Texinfo source document, you may use the result without
restriction. This Exception is an additional permission under
section 7 of the GNU General Public License, version 3 ("GPLv3").

View File

@ -2833,6 +2833,7 @@ repos.lfs_size = LFS Size
packages.package_manage_panel = Package Management
packages.total_size = Total Size: %s
packages.unreferenced_size = Unreferenced Size: %s
packages.cleanup = Clean up expired data
packages.owner = Owner
packages.creator = Creator
packages.name = Name
@ -3509,3 +3510,12 @@ variables.update.success = The variable has been edited.
type-1.display_name = Individual Project
type-2.display_name = Repository Project
type-3.display_name = Organization Project
[git.filemode]
changed_filemode = %[1]s → %[2]s
# Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
directory = Directory
normal_file = Normal file
executable_file = Executable file
symbolic_link = Symbolic link
submodule = Submodule

View File

@ -48,7 +48,7 @@ func RenderPanicErrorPage(w http.ResponseWriter, req *http.Request, err any) {
data["ErrorMsg"] = "PANIC: " + combinedErr
}
err = templates.HTMLRenderer().HTML(w, http.StatusInternalServerError, string(tplStatus500), data)
err = templates.HTMLRenderer().HTML(w, http.StatusInternalServerError, string(tplStatus500), data, nil)
if err != nil {
log.Error("Error occurs again when rendering error page: %v", err)
w.WriteHeader(http.StatusInternalServerError)

View File

@ -68,9 +68,13 @@ func Contexter() func(next http.Handler) http.Handler {
}
defer baseCleanUp()
ctx.TemplateContext = context.NewTemplateContext(ctx)
ctx.TemplateContext["Locale"] = ctx.Locale
ctx.AppendContextValue(context.WebContextKey, ctx)
ctx.Data.MergeFrom(middleware.CommonTemplateContextData())
ctx.Data.MergeFrom(middleware.ContextData{
"Context": ctx, // TODO: use "ctx" in template and remove this
"locale": ctx.Locale,
"Title": ctx.Locale.Tr("install.install"),
"PageIsInstall": true,

View File

@ -6,6 +6,7 @@ package admin
import (
"net/http"
"net/url"
"time"
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
@ -14,6 +15,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
packages_service "code.gitea.io/gitea/services/packages"
packages_cleanup_service "code.gitea.io/gitea/services/packages/cleanup"
)
const (
@ -99,3 +101,13 @@ func DeletePackageVersion(ctx *context.Context) {
ctx.Flash.Success(ctx.Tr("packages.settings.delete.success"))
ctx.JSONRedirect(setting.AppSubURL + "/admin/packages?page=" + url.QueryEscape(ctx.FormString("page")) + "&q=" + url.QueryEscape(ctx.FormString("q")) + "&type=" + url.QueryEscape(ctx.FormString("type")))
}
func CleanupExpiredData(ctx *context.Context) {
if err := packages_cleanup_service.CleanupExpiredData(ctx, time.Duration(0)); err != nil {
ctx.ServerError("CleanupExpiredData", err)
return
}
ctx.Flash.Success(ctx.Tr("packages.cleanup.success"))
ctx.Redirect(setting.AppSubURL + "/admin/packages")
}

View File

@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
system_model "code.gitea.io/gitea/models/system"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/auth/password"
"code.gitea.io/gitea/modules/base"
@ -255,6 +256,7 @@ func EditUser(ctx *context.Context) {
ctx.Data["DisableRegularOrgCreation"] = setting.Admin.DisableRegularOrgCreation
ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
ctx.Data["DisableGravatar"] = system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar)
prepareUserInfo(ctx)
if ctx.Written() {
@ -271,6 +273,7 @@ func EditUserPost(ctx *context.Context) {
ctx.Data["PageIsAdminUsers"] = true
ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
ctx.Data["DisableGravatar"] = system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar)
u := prepareUserInfo(ctx)
if ctx.Written() {

View File

@ -578,7 +578,7 @@ func GrantApplicationOAuth(ctx *context.Context) {
// OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities
func OIDCWellKnown(ctx *context.Context) {
t, err := ctx.Render.TemplateLookup("user/auth/oidc_wellknown")
t, err := ctx.Render.TemplateLookup("user/auth/oidc_wellknown", nil)
if err != nil {
ctx.ServerError("unable to find template", err)
return

View File

@ -191,7 +191,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
ctx.Data["last_commit"] = ctx.Repo.CommitID
ctx.Data["PreviewableExtensions"] = strings.Join(markup.PreviewableExtensions(), ",")
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
ctx.Data["Editorconfig"] = GetEditorConfig(ctx, treePath)
ctx.Data["EditorconfigJson"] = GetEditorConfig(ctx, treePath)
ctx.HTML(http.StatusOK, tplEditFile)
}
@ -242,7 +242,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
ctx.Data["last_commit"] = ctx.Repo.CommitID
ctx.Data["PreviewableExtensions"] = strings.Join(markup.PreviewableExtensions(), ",")
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
ctx.Data["Editorconfig"] = GetEditorConfig(ctx, form.TreePath)
ctx.Data["EditorconfigJson"] = GetEditorConfig(ctx, form.TreePath)
if ctx.HasError() {
ctx.HTML(http.StatusOK, tplEditFile)

View File

@ -299,7 +299,7 @@ func ForkPost(ctx *context.Context) {
ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name))
}
func checkPullInfo(ctx *context.Context) *issues_model.Issue {
func getPullInfo(ctx *context.Context) (issue *issues_model.Issue, ok bool) {
issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
if err != nil {
if issues_model.IsErrIssueNotExist(err) {
@ -307,43 +307,43 @@ func checkPullInfo(ctx *context.Context) *issues_model.Issue {
} else {
ctx.ServerError("GetIssueByIndex", err)
}
return nil
return nil, false
}
if err = issue.LoadPoster(ctx); err != nil {
ctx.ServerError("LoadPoster", err)
return nil
return nil, false
}
if err := issue.LoadRepo(ctx); err != nil {
ctx.ServerError("LoadRepo", err)
return nil
return nil, false
}
ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, issue.Title)
ctx.Data["Issue"] = issue
if !issue.IsPull {
ctx.NotFound("ViewPullCommits", nil)
return nil
return nil, false
}
if err = issue.LoadPullRequest(ctx); err != nil {
ctx.ServerError("LoadPullRequest", err)
return nil
return nil, false
}
if err = issue.PullRequest.LoadHeadRepo(ctx); err != nil {
ctx.ServerError("LoadHeadRepo", err)
return nil
return nil, false
}
if ctx.IsSigned {
// Update issue-user.
if err = activities_model.SetIssueReadBy(ctx, issue.ID, ctx.Doer.ID); err != nil {
ctx.ServerError("ReadBy", err)
return nil
return nil, false
}
}
return issue
return issue, true
}
func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) {
@ -361,14 +361,15 @@ func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) {
// GetPullDiffStats get Pull Requests diff stats
func GetPullDiffStats(ctx *context.Context) {
issue := checkPullInfo(ctx)
issue, ok := getPullInfo(ctx)
if !ok {
return
}
pull := issue.PullRequest
mergeBaseCommitID := GetMergedBaseCommitID(ctx, issue)
if ctx.Written() {
return
} else if mergeBaseCommitID == "" {
if mergeBaseCommitID == "" {
ctx.NotFound("PullFiles", nil)
return
}
@ -702,8 +703,8 @@ type pullCommitList struct {
// GetPullCommits get all commits for given pull request
func GetPullCommits(ctx *context.Context) {
issue := checkPullInfo(ctx)
if ctx.Written() {
issue, ok := getPullInfo(ctx)
if !ok {
return
}
resp := &pullCommitList{}
@ -735,8 +736,8 @@ func ViewPullCommits(ctx *context.Context) {
ctx.Data["PageIsPullList"] = true
ctx.Data["PageIsPullCommits"] = true
issue := checkPullInfo(ctx)
if ctx.Written() {
issue, ok := getPullInfo(ctx)
if !ok {
return
}
pull := issue.PullRequest
@ -779,8 +780,8 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
ctx.Data["PageIsPullList"] = true
ctx.Data["PageIsPullFiles"] = true
issue := checkPullInfo(ctx)
if ctx.Written() {
issue, ok := getPullInfo(ctx)
if !ok {
return
}
pull := issue.PullRequest
@ -1016,8 +1017,8 @@ func ViewPullFilesForAllCommitsOfPr(ctx *context.Context) {
// UpdatePullRequest merge PR's baseBranch into headBranch
func UpdatePullRequest(ctx *context.Context) {
issue := checkPullInfo(ctx)
if ctx.Written() {
issue, ok := getPullInfo(ctx)
if !ok {
return
}
if issue.IsClosed {
@ -1101,8 +1102,8 @@ func UpdatePullRequest(ctx *context.Context) {
// MergePullRequest response for merging pull request
func MergePullRequest(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.MergePullRequestForm)
issue := checkPullInfo(ctx)
if ctx.Written() {
issue, ok := getPullInfo(ctx)
if !ok {
return
}
@ -1308,8 +1309,8 @@ func MergePullRequest(ctx *context.Context) {
// CancelAutoMergePullRequest cancels a scheduled pr
func CancelAutoMergePullRequest(ctx *context.Context) {
issue := checkPullInfo(ctx)
if ctx.Written() {
issue, ok := getPullInfo(ctx)
if !ok {
return
}
@ -1447,8 +1448,8 @@ func CompareAndPullRequestPost(ctx *context.Context) {
// CleanUpPullRequest responses for delete merged branch when PR has been merged
func CleanUpPullRequest(ctx *context.Context) {
issue := checkPullInfo(ctx)
if ctx.Written() {
issue, ok := getPullInfo(ctx)
if !ok {
return
}

View File

@ -259,8 +259,8 @@ type viewedFilesUpdate struct {
func UpdateViewedFiles(ctx *context.Context) {
// Find corresponding PR
issue := checkPullInfo(ctx)
if ctx.Written() {
issue, ok := getPullInfo(ctx)
if !ok {
return
}
pull := issue.PullRequest

View File

@ -13,7 +13,7 @@ const tplSwaggerV1Json base.TplName = "swagger/v1_json"
// SwaggerV1Json render swagger v1 json
func SwaggerV1Json(ctx *context.Context) {
t, err := ctx.Render.TemplateLookup(string(tplSwaggerV1Json))
t, err := ctx.Render.TemplateLookup(string(tplSwaggerV1Json), nil)
if err != nil {
ctx.ServerError("unable to find template", err)
return

View File

@ -296,8 +296,7 @@ func NotificationSubscriptions(ctx *context.Context) {
}
ctx.Data["CommitStatus"] = commitStatus
issueList := issues_model.IssueList(issues)
approvalCounts, err := issueList.GetApprovalCounts(ctx)
approvalCounts, err := issues.GetApprovalCounts(ctx)
if err != nil {
ctx.ServerError("ApprovalCounts", err)
return

View File

@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
system_model "code.gitea.io/gitea/models/system"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
@ -43,6 +44,7 @@ func Profile(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings.profile")
ctx.Data["PageIsSettingsProfile"] = true
ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
ctx.Data["DisableGravatar"] = system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar)
ctx.HTML(http.StatusOK, tplSettingsProfile)
}
@ -83,6 +85,8 @@ func ProfilePost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.UpdateProfileForm)
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsProfile"] = true
ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
ctx.Data["DisableGravatar"] = system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar)
if ctx.HasError() {
ctx.HTML(http.StatusOK, tplSettingsProfile)

View File

@ -597,6 +597,7 @@ func registerRoutes(m *web.Route) {
m.Group("/packages", func() {
m.Get("", admin.Packages)
m.Post("/delete", admin.DeletePackageVersion)
m.Post("/cleanup", admin.CleanupExpiredData)
}, packagesEnabled)
m.Group("/hooks", func() {

View File

@ -152,7 +152,7 @@ func registerCleanupPackages() {
OlderThan: 24 * time.Hour,
}, func(ctx context.Context, _ *user_model.User, config Config) error {
realConfig := config.(*OlderThanConfig)
return packages_cleanup_service.Cleanup(ctx, realConfig.OlderThan)
return packages_cleanup_service.CleanupTask(ctx, realConfig.OlderThan)
})
}

View File

@ -427,6 +427,23 @@ func (diffFile *DiffFile) ShouldBeHidden() bool {
return diffFile.IsGenerated || diffFile.IsViewed
}
func (diffFile *DiffFile) ModeTranslationKey(mode string) string {
switch mode {
case "040000":
return "git.filemode.directory"
case "100644":
return "git.filemode.normal_file"
case "100755":
return "git.filemode.executable_file"
case "120000":
return "git.filemode.symbolic_link"
case "160000":
return "git.filemode.submodule"
default:
return mode
}
}
func getCommitFileLineCount(commit *git.Commit, filePath string) int {
blob, err := commit.GetBlobByPath(filePath)
if err != nil {

View File

@ -248,7 +248,7 @@ func deleteIssue(ctx context.Context, issue *issues_model.Issue) error {
issue.MilestoneID, err)
}
if err := activities_model.DeleteIssueActions(ctx, issue.RepoID, issue.ID); err != nil {
if err := activities_model.DeleteIssueActions(ctx, issue.RepoID, issue.ID, issue.Index); err != nil {
return err
}

View File

@ -20,9 +20,17 @@ import (
debian_service "code.gitea.io/gitea/services/packages/debian"
)
// Cleanup removes expired package data
func Cleanup(taskCtx context.Context, olderThan time.Duration) error {
ctx, committer, err := db.TxContext(taskCtx)
// Task method to execute cleanup rules and cleanup expired package data
func CleanupTask(ctx context.Context, olderThan time.Duration) error {
if err := ExecuteCleanupRules(ctx); err != nil {
return err
}
return CleanupExpiredData(ctx, olderThan)
}
func ExecuteCleanupRules(outerCtx context.Context) error {
ctx, committer, err := db.TxContext(outerCtx)
if err != nil {
return err
}
@ -30,7 +38,7 @@ func Cleanup(taskCtx context.Context, olderThan time.Duration) error {
err = packages_model.IterateEnabledCleanupRules(ctx, func(ctx context.Context, pcr *packages_model.PackageCleanupRule) error {
select {
case <-taskCtx.Done():
case <-outerCtx.Done():
return db.ErrCancelledf("While processing package cleanup rules")
default:
}
@ -122,6 +130,16 @@ func Cleanup(taskCtx context.Context, olderThan time.Duration) error {
return err
}
return committer.Commit()
}
func CleanupExpiredData(outerCtx context.Context, olderThan time.Duration) error {
ctx, committer, err := db.TxContext(outerCtx)
if err != nil {
return err
}
defer committer.Close()
if err := container_service.Cleanup(ctx, olderThan); err != nil {
return err
}

View File

@ -4,6 +4,12 @@
{{.locale.Tr "admin.packages.package_manage_panel"}} ({{.locale.Tr "admin.total" .TotalCount}},
{{.locale.Tr "admin.packages.total_size" (FileSize .TotalBlobSize)}},
{{.locale.Tr "admin.packages.unreferenced_size" (FileSize .TotalUnreferencedBlobSize)}})
<div class="ui right">
<form method="post" action="/admin/packages/cleanup">
{{.CsrfTokenHtml}}
<button class="ui primary tiny button">{{.locale.Tr "admin.packages.cleanup"}}</button>
</form>
</div>
</h4>
<div class="ui attached segment">
<form class="ui form ignore-dirty">

View File

@ -159,7 +159,7 @@
<div class="ui attached segment">
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
{{.CsrfTokenHtml}}
{{if not (DisableGravatar $.Context)}}
{{if not .DisableGravatar}}
<div class="inline field">
<div class="ui radio checkbox">
<input name="source" value="lookup" type="radio" {{if not .User.UseCustomAvatar}}checked{{end}}>

View File

@ -26,6 +26,8 @@
{{end}}
{{end}}
<script src="{{AssetUrlPrefix}}/js/index.js?v={{AssetVersion}}" onerror="alert('Failed to load asset files from ' + this.src + '. Please make sure the asset files can be accessed.')"></script>
{{template "custom/footer" .}}
{{template "custom/footer" .}}
{{ctx.DataRaceCheck $.Context}}
</body>
</html>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="{{.locale.Lang}}" class="theme-{{if .SignedUser.Theme}}{{.SignedUser.Theme}}{{else}}{{DefaultTheme}}{{end}}">
<html lang="{{ctx.Locale.Lang}}" class="theme-{{if .SignedUser.Theme}}{{.SignedUser.Theme}}{{else}}{{DefaultTheme}}{{end}}">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}}{{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title>
@ -28,7 +28,7 @@
{{if .PageIsUserProfile}}
<meta property="og:title" content="{{.ContextUser.DisplayName}}">
<meta property="og:type" content="profile">
<meta property="og:image" content="{{.ContextUser.AvatarLink $.Context}}">
<meta property="og:image" content="{{.ContextUser.AvatarLink ctx}}">
<meta property="og:url" content="{{.ContextUser.HTMLURL}}">
{{if .ContextUser.Description}}
<meta property="og:description" content="{{.ContextUser.Description}}">
@ -48,10 +48,10 @@
{{end}}
{{end}}
<meta property="og:type" content="object">
{{if (.Repository.AvatarLink $.Context)}}
<meta property="og:image" content="{{.Repository.AvatarLink $.Context}}">
{{if (.Repository.AvatarLink ctx)}}
<meta property="og:image" content="{{.Repository.AvatarLink ctx}}">
{{else}}
<meta property="og:image" content="{{.Repository.Owner.AvatarLink $.Context}}">
<meta property="og:image" content="{{.Repository.Owner.AvatarLink ctx}}">
{{end}}
{{else}}
<meta property="og:title" content="{{AppName}}">
@ -65,10 +65,11 @@
{{template "custom/header" .}}
</head>
<body>
{{ctx.DataRaceCheck $.Context}}
{{template "custom/body_outer_pre" .}}
<div class="full height">
<noscript>{{.locale.Tr "enable_javascript"}}</noscript>
<noscript>{{ctx.Locale.Tr "enable_javascript"}}</noscript>
{{template "custom/body_inner_pre" .}}

View File

@ -2,12 +2,7 @@
{{range .Repos}}
<div class="flex-item">
<div class="flex-item-leading">
{{$avatar := (repoAvatar . 32)}}
{{if $avatar}}
{{$avatar}}
{{else}}
{{template "repo/icon" .}}
{{end}}
{{template "repo/icon" .}}
</div>
<div class="flex-item-main">
<div class="flex-item-header">

View File

@ -19,18 +19,18 @@
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
<div class="menu">
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=newest&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=oldest&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=alphabetically&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=reversealphabetically&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=recentupdate&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=leastupdate&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
{{if not .DisableStars}}
<a class="{{if eq .SortType "moststars"}}active {{end}}item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.moststars"}}</a>
<a class="{{if eq .SortType "feweststars"}}active {{end}}item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.feweststars"}}</a>
<a class="{{if eq .SortType "moststars"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=moststars&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.moststars"}}</a>
<a class="{{if eq .SortType "feweststars"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=feweststars&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.feweststars"}}</a>
{{end}}
<a class="{{if eq .SortType "mostforks"}}active {{end}}item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.mostforks"}}</a>
<a class="{{if eq .SortType "fewestforks"}}active {{end}}item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.fewestforks"}}</a>
<a class="{{if eq .SortType "mostforks"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=mostforks&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.mostforks"}}</a>
<a class="{{if eq .SortType "fewestforks"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=fewestforks&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.fewestforks"}}</a>
</div>
</div>
</div>

View File

@ -30,12 +30,7 @@
{{range .Team.Repos}}
<div class="flex-item flex-item-center">
<div class="flex-item-leading">
{{$avatar := (repoAvatar . 32)}}
{{if $avatar}}
{{$avatar}}
{{else}}
{{template "repo/icon" .}}
{{end}}
{{template "repo/icon" .}}
</div>
<div class="flex-item-main">
<a class="flex-item-title text primary" href="{{$.Org.HomeLink}}/{{.Name | PathEscape}}">

View File

@ -130,9 +130,11 @@
<span class="ui label">{{$.locale.Tr "repo.diff.vendored"}}</span>
{{end}}
{{if and $file.Mode $file.OldMode}}
<span class="gt-ml-4 gt-mono">{{$file.OldMode}}{{$file.Mode}}</span>
{{$old := $.locale.Tr ($file.ModeTranslationKey $file.OldMode)}}
{{$new := $.locale.Tr ($file.ModeTranslationKey $file.Mode)}}
<span class="gt-ml-4 gt-mono">{{$.locale.Tr "git.filemode.changed_filemode" $old $new}}</span>
{{else if $file.Mode}}
<span class="gt-ml-4 gt-mono">{{$file.Mode}}</span>
<span class="gt-ml-4 gt-mono">{{$.locale.Tr ($file.ModeTranslationKey $file.Mode)}}</span>
{{end}}
</div>
<div class="diff-file-header-actions gt-df gt-ac gt-gap-2 gt-fw">

View File

@ -15,7 +15,7 @@
{{range $i, $v := .TreeNames}}
<div class="divider"> / </div>
{{if eq $i $l}}
<input id="file-name" value="{{$v}}" placeholder="{{$.locale.Tr "repo.editor.name_your_file"}}" data-editorconfig="{{$.Editorconfig}}" required autofocus>
<input id="file-name" value="{{$v}}" placeholder="{{$.locale.Tr "repo.editor.name_your_file"}}" data-editorconfig="{{$.EditorconfigJson}}" required autofocus>
<span data-tooltip-content="{{$.locale.Tr "repo.editor.filename_help"}}">{{svg "octicon-info"}}</span>
{{else}}
<span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span>

View File

@ -4,14 +4,9 @@
<div class="repo-header">
<div class="repo-title-wrap gt-df gt-fc">
<div class="repo-title" role="heading" aria-level="1">
{{$avatar := (repoAvatar . 32 "gt-mr-3")}}
{{if $avatar}}
{{$avatar}}
{{else}}
<div class="gt-mr-3">
{{template "repo/icon" .}}
</div>
{{end}}
<div class="gt-mr-3">
{{template "repo/icon" .}}
</div>
<a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a>
<div class="gt-mx-2">/</div>
<a href="{{$.RepoLink}}">{{.Name}}</a>

View File

@ -1,15 +1,16 @@
<div class="repo-icon">
{{if $.IsTemplate}}
{{$avatarLink := .RelAvatarLink}}
{{if $avatarLink}}
<img class="ui avatar gt-vm" src="{{$avatarLink}}" width="32" height="32" alt="{{.FullName}}">
{{else if $.IsTemplate}}
{{svg "octicon-repo-template" 32}}
{{else if $.IsPrivate}}
{{svg "octicon-lock" 32}}
{{else if $.IsMirror}}
{{svg "octicon-mirror" 32}}
{{else if $.IsFork}}
{{svg "octicon-repo-forked" 32}}
{{else}}
{{if $.IsPrivate}}
{{svg "octicon-lock" 32}}
{{else if $.IsMirror}}
{{svg "octicon-mirror" 32}}
{{else if $.IsFork}}
{{svg "octicon-repo-forked" 32}}
{{else}}
{{svg "octicon-repo" 32}}
{{end}}
{{svg "octicon-repo" 32}}
{{end}}
</div>

View File

@ -116,10 +116,10 @@
</table>
<div class="code-line-menu ui vertical pointing menu tippy-target">
{{if $.Permission.CanRead $.UnitTypeIssues}}
<a class="item ref-in-new-issue" data-url-issue-new="{{.RepoLink}}/issues/new" data-url-param-body-link="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}" rel="nofollow noindex">{{.locale.Tr "repo.issues.context.reference_issue"}}</a>
<a class="item ref-in-new-issue" data-url-issue-new="{{.RepoLink}}/issues/new" data-url-param-body-link="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}" rel="nofollow noindex">{{.locale.Tr "repo.issues.context.reference_issue"}}</a>
{{end}}
<a class="item view_git_blame" href="{{.Repository.Link}}/blame/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.locale.Tr "repo.view_git_blame"}}</a>
<a class="item copy-line-permalink" data-url="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.locale.Tr "repo.file_copy_permalink"}}</a>
<a class="item copy-line-permalink" data-url="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}">{{.locale.Tr "repo.file_copy_permalink"}}</a>
</div>
{{end}}
{{end}}

View File

@ -99,7 +99,7 @@
<div class="ui attached segment">
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
{{.CsrfTokenHtml}}
{{if not (DisableGravatar $.Context)}}
{{if not .DisableGravatar}}
<div class="inline field">
<div class="ui radio checkbox">
<input name="source" value="lookup" type="radio" {{if not .SignedUser.UseCustomAvatar}}checked{{end}}>

View File

@ -475,7 +475,7 @@ func TestPackageCleanup(t *testing.T) {
_, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, "cleanup-test", container_model.UploadVersion)
assert.NoError(t, err)
err = packages_cleanup_service.Cleanup(db.DefaultContext, duration)
err = packages_cleanup_service.CleanupTask(db.DefaultContext, duration)
assert.NoError(t, err)
pbs, err = packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, duration)
@ -610,7 +610,7 @@ func TestPackageCleanup(t *testing.T) {
pcr, err := packages_model.InsertCleanupRule(db.DefaultContext, c.Rule)
assert.NoError(t, err)
err = packages_cleanup_service.Cleanup(db.DefaultContext, duration)
err = packages_cleanup_service.CleanupTask(db.DefaultContext, duration)
assert.NoError(t, err)
for _, v := range c.Versions {

View File

@ -408,3 +408,39 @@ func TestMarkDownReadmeImageSubfolder(t *testing.T) {
assert.True(t, exists, "Image not found in markdown file")
assert.Equal(t, "/user2/repo1/media/branch/sub-home-md-img-check/docs/test-fake-img.jpg", src)
}
func TestGeneratedSourceLink(t *testing.T) {
defer tests.PrepareTestEnv(t)()
t.Run("Rendered file", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/README.md?display=source")
resp := MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
dataURL, exists := doc.doc.Find(".copy-line-permalink").Attr("data-url")
assert.True(t, exists)
assert.Equal(t, "/user2/repo1/src/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d/README.md?display=source", dataURL)
dataURL, exists = doc.doc.Find(".ref-in-new-issue").Attr("data-url-param-body-link")
assert.True(t, exists)
assert.Equal(t, "/user2/repo1/src/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d/README.md?display=source", dataURL)
})
t.Run("Non-Rendered file", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user27")
req := NewRequest(t, "GET", "/user27/repo49/src/branch/master/test/test.txt")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
dataURL, exists := doc.doc.Find(".copy-line-permalink").Attr("data-url")
assert.True(t, exists)
assert.Equal(t, "/user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt", dataURL)
dataURL, exists = doc.doc.Find(".ref-in-new-issue").Attr("data-url-param-body-link")
assert.True(t, exists)
assert.Equal(t, "/user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt", dataURL)
})
}

View File

@ -1218,7 +1218,7 @@ img.ui.avatar,
}
.ui .text.truncate {
overflow: hidden;
overflow-x: clip;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;