Merge branch 'main' into lunny/glob_protected_branch_rule
This commit is contained in:
commit
86b0029fa3
23 changed files with 333 additions and 24 deletions
|
@ -33,6 +33,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers"
|
"code.gitea.io/gitea/routers"
|
||||||
|
markup_service "code.gitea.io/gitea/services/markup"
|
||||||
|
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/config"
|
"github.com/go-git/go-git/v5/config"
|
||||||
|
@ -112,7 +113,7 @@ func runPR() {
|
||||||
log.Printf("[PR] Setting up router\n")
|
log.Printf("[PR] Setting up router\n")
|
||||||
// routers.GlobalInit()
|
// routers.GlobalInit()
|
||||||
external.RegisterRenderers()
|
external.RegisterRenderers()
|
||||||
markup.Init()
|
markup.Init(markup_service.ProcessorHelper())
|
||||||
c := routers.NormalRoutes(graceful.GetManager().HammerContext())
|
c := routers.NormalRoutes(graceful.GetManager().HammerContext())
|
||||||
|
|
||||||
log.Printf("[PR] Ready for testing !\n")
|
log.Printf("[PR] Ready for testing !\n")
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
# type Milestone struct {
|
||||||
|
# ID int64 `xorm:"pk autoincr"`
|
||||||
|
# IsClosed bool
|
||||||
|
# NumIssues int
|
||||||
|
# NumClosedIssues int
|
||||||
|
# Completeness int // Percentage(1-100).
|
||||||
|
# }
|
||||||
|
-
|
||||||
|
id: 1
|
||||||
|
is_closed: false
|
||||||
|
num_issues: 3
|
||||||
|
num_closed_issues: 1
|
||||||
|
completeness: 33
|
||||||
|
-
|
||||||
|
id: 2
|
||||||
|
is_closed: true
|
||||||
|
num_issues: 5
|
||||||
|
num_closed_issues: 5
|
||||||
|
completeness: 100
|
|
@ -0,0 +1,25 @@
|
||||||
|
# type Issue struct {
|
||||||
|
# ID int64 `xorm:"pk autoincr"`
|
||||||
|
# RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"`
|
||||||
|
# Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository.
|
||||||
|
# MilestoneID int64 `xorm:"INDEX"`
|
||||||
|
# IsClosed bool `xorm:"INDEX"`
|
||||||
|
# }
|
||||||
|
-
|
||||||
|
id: 1
|
||||||
|
repo_id: 1
|
||||||
|
index: 1
|
||||||
|
milestone_id: 1
|
||||||
|
is_closed: false
|
||||||
|
-
|
||||||
|
id: 2
|
||||||
|
repo_id: 1
|
||||||
|
index: 2
|
||||||
|
milestone_id: 1
|
||||||
|
is_closed: true
|
||||||
|
-
|
||||||
|
id: 4
|
||||||
|
repo_id: 1
|
||||||
|
index: 3
|
||||||
|
milestone_id: 1
|
||||||
|
is_closed: false
|
|
@ -0,0 +1,19 @@
|
||||||
|
# type Milestone struct {
|
||||||
|
# ID int64 `xorm:"pk autoincr"`
|
||||||
|
# IsClosed bool
|
||||||
|
# NumIssues int
|
||||||
|
# NumClosedIssues int
|
||||||
|
# Completeness int // Percentage(1-100).
|
||||||
|
# }
|
||||||
|
-
|
||||||
|
id: 1
|
||||||
|
is_closed: false
|
||||||
|
num_issues: 4
|
||||||
|
num_closed_issues: 2
|
||||||
|
completeness: 50
|
||||||
|
-
|
||||||
|
id: 2
|
||||||
|
is_closed: true
|
||||||
|
num_issues: 5
|
||||||
|
num_closed_issues: 5
|
||||||
|
completeness: 100
|
|
@ -419,6 +419,8 @@ var migrations = []Migration{
|
||||||
NewMigration("Create key/value table for system settings", createSystemSettingsTable),
|
NewMigration("Create key/value table for system settings", createSystemSettingsTable),
|
||||||
// v228 -> v229
|
// v228 -> v229
|
||||||
NewMigration("Add TeamInvite table", addTeamInviteTable),
|
NewMigration("Add TeamInvite table", addTeamInviteTable),
|
||||||
|
// v229 -> v230
|
||||||
|
NewMigration("Update counts of all open milestones", updateOpenMilestoneCounts),
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentDBVersion returns the current db version
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
|
47
models/migrations/v229.go
Normal file
47
models/migrations/v229.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/issues"
|
||||||
|
|
||||||
|
"xorm.io/builder"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func updateOpenMilestoneCounts(x *xorm.Engine) error {
|
||||||
|
var openMilestoneIDs []int64
|
||||||
|
err := x.Table("milestone").Select("id").Where(builder.Neq{"is_closed": 1}).Find(&openMilestoneIDs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error selecting open milestone IDs: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, id := range openMilestoneIDs {
|
||||||
|
_, err := x.ID(id).
|
||||||
|
SetExpr("num_issues", builder.Select("count(*)").From("issue").Where(
|
||||||
|
builder.Eq{"milestone_id": id},
|
||||||
|
)).
|
||||||
|
SetExpr("num_closed_issues", builder.Select("count(*)").From("issue").Where(
|
||||||
|
builder.Eq{
|
||||||
|
"milestone_id": id,
|
||||||
|
"is_closed": true,
|
||||||
|
},
|
||||||
|
)).
|
||||||
|
Update(&issues.Milestone{})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error updating issue counts in milestone %d: %w", id, err)
|
||||||
|
}
|
||||||
|
_, err = x.Exec("UPDATE `milestone` SET completeness=100*num_closed_issues/(CASE WHEN num_issues > 0 THEN num_issues ELSE 1 END) WHERE id=?",
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error setting completeness on milestone %d: %w", id, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
46
models/migrations/v229_test.go
Normal file
46
models/migrations/v229_test.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/issues"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_updateOpenMilestoneCounts(t *testing.T) {
|
||||||
|
type ExpectedMilestone issues.Milestone
|
||||||
|
|
||||||
|
// Prepare and load the testing database
|
||||||
|
x, deferable := prepareTestEnv(t, 0, new(issues.Milestone), new(ExpectedMilestone), new(issues.Issue))
|
||||||
|
defer deferable()
|
||||||
|
if x == nil || t.Failed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := updateOpenMilestoneCounts(x); err != nil {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []ExpectedMilestone{}
|
||||||
|
if err := x.Table("expected_milestone").Asc("id").Find(&expected); !assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []issues.Milestone{}
|
||||||
|
if err := x.Table("milestone").Asc("id").Find(&got); !assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, e := range expected {
|
||||||
|
got := got[i]
|
||||||
|
assert.Equal(t, e.ID, got.ID)
|
||||||
|
assert.Equal(t, e.NumIssues, got.NumIssues)
|
||||||
|
assert.Equal(t, e.NumClosedIssues, got.NumClosedIssues)
|
||||||
|
}
|
||||||
|
}
|
|
@ -165,6 +165,7 @@ type ImageTagsSearchOptions struct {
|
||||||
PackageID int64
|
PackageID int64
|
||||||
Query string
|
Query string
|
||||||
IsTagged bool
|
IsTagged bool
|
||||||
|
Sort packages.VersionSort
|
||||||
db.Paginator
|
db.Paginator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,12 +196,26 @@ func (opts *ImageTagsSearchOptions) toConds() builder.Cond {
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (opts *ImageTagsSearchOptions) configureOrderBy(e db.Engine) {
|
||||||
|
switch opts.Sort {
|
||||||
|
case packages.SortVersionDesc:
|
||||||
|
e.Desc("package_version.version")
|
||||||
|
case packages.SortVersionAsc:
|
||||||
|
e.Asc("package_version.version")
|
||||||
|
case packages.SortCreatedAsc:
|
||||||
|
e.Asc("package_version.created_unix")
|
||||||
|
default:
|
||||||
|
e.Desc("package_version.created_unix")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SearchImageTags gets a sorted list of the tags of an image
|
// SearchImageTags gets a sorted list of the tags of an image
|
||||||
func SearchImageTags(ctx context.Context, opts *ImageTagsSearchOptions) ([]*packages.PackageVersion, int64, error) {
|
func SearchImageTags(ctx context.Context, opts *ImageTagsSearchOptions) ([]*packages.PackageVersion, int64, error) {
|
||||||
sess := db.GetEngine(ctx).
|
sess := db.GetEngine(ctx).
|
||||||
Join("INNER", "package", "package.id = package_version.package_id").
|
Join("INNER", "package", "package.id = package_version.package_id").
|
||||||
Where(opts.toConds()).
|
Where(opts.toConds())
|
||||||
Desc("package_version.created_unix")
|
|
||||||
|
opts.configureOrderBy(sess)
|
||||||
|
|
||||||
if opts.Paginator != nil {
|
if opts.Paginator != nil {
|
||||||
sess = db.SetSessionPagination(sess, opts)
|
sess = db.SetSessionPagination(sess, opts)
|
||||||
|
|
|
@ -163,6 +163,17 @@ type SearchValue struct {
|
||||||
ExactMatch bool
|
ExactMatch bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VersionSort = string
|
||||||
|
|
||||||
|
const (
|
||||||
|
SortNameAsc VersionSort = "name_asc"
|
||||||
|
SortNameDesc VersionSort = "name_desc"
|
||||||
|
SortVersionAsc VersionSort = "version_asc"
|
||||||
|
SortVersionDesc VersionSort = "version_desc"
|
||||||
|
SortCreatedAsc VersionSort = "created_asc"
|
||||||
|
SortCreatedDesc VersionSort = "created_desc"
|
||||||
|
)
|
||||||
|
|
||||||
// PackageSearchOptions are options for SearchXXX methods
|
// PackageSearchOptions are options for SearchXXX methods
|
||||||
// Besides IsInternal are all fields optional and are not used if they have their default value (nil, "", 0)
|
// Besides IsInternal are all fields optional and are not used if they have their default value (nil, "", 0)
|
||||||
type PackageSearchOptions struct {
|
type PackageSearchOptions struct {
|
||||||
|
@ -176,7 +187,7 @@ type PackageSearchOptions struct {
|
||||||
IsInternal util.OptionalBool
|
IsInternal util.OptionalBool
|
||||||
HasFileWithName string // only results are found which are associated with a file with the specific name
|
HasFileWithName string // only results are found which are associated with a file with the specific name
|
||||||
HasFiles util.OptionalBool // only results are found which have associated files
|
HasFiles util.OptionalBool // only results are found which have associated files
|
||||||
Sort string
|
Sort VersionSort
|
||||||
db.Paginator
|
db.Paginator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,15 +265,15 @@ func (opts *PackageSearchOptions) toConds() builder.Cond {
|
||||||
|
|
||||||
func (opts *PackageSearchOptions) configureOrderBy(e db.Engine) {
|
func (opts *PackageSearchOptions) configureOrderBy(e db.Engine) {
|
||||||
switch opts.Sort {
|
switch opts.Sort {
|
||||||
case "alphabetically":
|
case SortNameAsc:
|
||||||
e.Asc("package.name")
|
e.Asc("package.name")
|
||||||
case "reversealphabetically":
|
case SortNameDesc:
|
||||||
e.Desc("package.name")
|
e.Desc("package.name")
|
||||||
case "highestversion":
|
case SortVersionDesc:
|
||||||
e.Desc("package_version.version")
|
e.Desc("package_version.version")
|
||||||
case "lowestversion":
|
case SortVersionAsc:
|
||||||
e.Asc("package_version.version")
|
e.Asc("package_version.version")
|
||||||
case "oldest":
|
case SortCreatedAsc:
|
||||||
e.Asc("package_version.created_unix")
|
e.Asc("package_version.created_unix")
|
||||||
default:
|
default:
|
||||||
e.Desc("package_version.created_unix")
|
e.Desc("package_version.created_unix")
|
||||||
|
|
|
@ -603,8 +603,14 @@ func mentionProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
start = loc.End
|
start = loc.End
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, mention[1:]), mention, "mention"))
|
mentionedUsername := mention[1:]
|
||||||
|
|
||||||
|
if processorHelper.IsUsernameMentionable != nil && processorHelper.IsUsernameMentionable(ctx.Ctx, mentionedUsername) {
|
||||||
|
replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, mentionedUsername), mention, "mention"))
|
||||||
node = node.NextSibling.NextSibling
|
node = node.NextSibling.NextSibling
|
||||||
|
} else {
|
||||||
|
node = node.NextSibling
|
||||||
|
}
|
||||||
start = 0
|
start = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,11 @@ func TestMain(m *testing.M) {
|
||||||
if err := git.InitSimple(context.Background()); err != nil {
|
if err := git.InitSimple(context.Background()); err != nil {
|
||||||
log.Fatal("git init failed, err: %v", err)
|
log.Fatal("git init failed, err: %v", err)
|
||||||
}
|
}
|
||||||
|
markup.Init(&markup.ProcessorHelper{
|
||||||
|
IsUsernameMentionable: func(ctx context.Context, username string) bool {
|
||||||
|
return username == "r-lyeh"
|
||||||
|
},
|
||||||
|
})
|
||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,18 @@ import (
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ProcessorHelper struct {
|
||||||
|
IsUsernameMentionable func(ctx context.Context, username string) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var processorHelper ProcessorHelper
|
||||||
|
|
||||||
// Init initialize regexps for markdown parsing
|
// Init initialize regexps for markdown parsing
|
||||||
func Init() {
|
func Init(ph *ProcessorHelper) {
|
||||||
|
if ph != nil {
|
||||||
|
processorHelper = *ph
|
||||||
|
}
|
||||||
|
|
||||||
NewSanitizer()
|
NewSanitizer()
|
||||||
if len(setting.Markdown.CustomURLSchemes) > 0 {
|
if len(setting.Markdown.CustomURLSchemes) > 0 {
|
||||||
CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
|
CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
|
||||||
|
|
|
@ -106,6 +106,10 @@ never = Never
|
||||||
|
|
||||||
rss_feed = RSS Feed
|
rss_feed = RSS Feed
|
||||||
|
|
||||||
|
[filter]
|
||||||
|
string.asc = A - Z
|
||||||
|
string.desc = Z - A
|
||||||
|
|
||||||
[error]
|
[error]
|
||||||
occurred = An error occurred
|
occurred = An error occurred
|
||||||
report_message = If you are sure this is a Gitea bug, please search for issues on <a href="https://github.com/go-gitea/gitea/issues" target="_blank">GitHub</a> or open a new issue if necessary.
|
report_message = If you are sure this is a Gitea bug, please search for issues on <a href="https://github.com/go-gitea/gitea/issues" target="_blank">GitHub</a> or open a new issue if necessary.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package misc
|
package misc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
go_context "context"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
@ -13,6 +14,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
"code.gitea.io/gitea/modules/markup"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/templates"
|
"code.gitea.io/gitea/modules/templates"
|
||||||
|
@ -50,6 +52,11 @@ func wrap(ctx *context.Context) *context.APIContext {
|
||||||
|
|
||||||
func TestAPI_RenderGFM(t *testing.T) {
|
func TestAPI_RenderGFM(t *testing.T) {
|
||||||
setting.AppURL = AppURL
|
setting.AppURL = AppURL
|
||||||
|
markup.Init(&markup.ProcessorHelper{
|
||||||
|
IsUsernameMentionable: func(ctx go_context.Context, username string) bool {
|
||||||
|
return username == "r-lyeh"
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
options := api.MarkdownOption{
|
options := api.MarkdownOption{
|
||||||
Mode: "gfm",
|
Mode: "gfm",
|
||||||
|
|
|
@ -41,6 +41,7 @@ import (
|
||||||
"code.gitea.io/gitea/services/automerge"
|
"code.gitea.io/gitea/services/automerge"
|
||||||
"code.gitea.io/gitea/services/cron"
|
"code.gitea.io/gitea/services/cron"
|
||||||
"code.gitea.io/gitea/services/mailer"
|
"code.gitea.io/gitea/services/mailer"
|
||||||
|
markup_service "code.gitea.io/gitea/services/markup"
|
||||||
repo_migrations "code.gitea.io/gitea/services/migrations"
|
repo_migrations "code.gitea.io/gitea/services/migrations"
|
||||||
mirror_service "code.gitea.io/gitea/services/mirror"
|
mirror_service "code.gitea.io/gitea/services/mirror"
|
||||||
pull_service "code.gitea.io/gitea/services/pull"
|
pull_service "code.gitea.io/gitea/services/pull"
|
||||||
|
@ -123,7 +124,7 @@ func GlobalInitInstalled(ctx context.Context) {
|
||||||
|
|
||||||
highlight.NewContext()
|
highlight.NewContext()
|
||||||
external.RegisterRenderers()
|
external.RegisterRenderers()
|
||||||
markup.Init()
|
markup.Init(markup_service.ProcessorHelper())
|
||||||
|
|
||||||
if setting.EnableSQLite3 {
|
if setting.EnableSQLite3 {
|
||||||
log.Info("SQLite3 support is enabled")
|
log.Info("SQLite3 support is enabled")
|
||||||
|
|
|
@ -233,6 +233,7 @@ func ListPackageVersions(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
query := ctx.FormTrim("q")
|
query := ctx.FormTrim("q")
|
||||||
|
sort := ctx.FormTrim("sort")
|
||||||
|
|
||||||
ctx.Data["Title"] = ctx.Tr("packages.title")
|
ctx.Data["Title"] = ctx.Tr("packages.title")
|
||||||
ctx.Data["IsPackagesPage"] = true
|
ctx.Data["IsPackagesPage"] = true
|
||||||
|
@ -243,9 +244,11 @@ func ListPackageVersions(ctx *context.Context) {
|
||||||
Owner: ctx.Package.Owner,
|
Owner: ctx.Package.Owner,
|
||||||
}
|
}
|
||||||
ctx.Data["Query"] = query
|
ctx.Data["Query"] = query
|
||||||
|
ctx.Data["Sort"] = sort
|
||||||
|
|
||||||
pagerParams := map[string]string{
|
pagerParams := map[string]string{
|
||||||
"q": query,
|
"q": query,
|
||||||
|
"sort": sort,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -264,6 +267,7 @@ func ListPackageVersions(ctx *context.Context) {
|
||||||
PackageID: p.ID,
|
PackageID: p.ID,
|
||||||
Query: query,
|
Query: query,
|
||||||
IsTagged: tagged == "" || tagged == "tagged",
|
IsTagged: tagged == "" || tagged == "tagged",
|
||||||
|
Sort: sort,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("SearchImageTags", err)
|
ctx.ServerError("SearchImageTags", err)
|
||||||
|
@ -278,6 +282,7 @@ func ListPackageVersions(ctx *context.Context) {
|
||||||
Value: query,
|
Value: query,
|
||||||
},
|
},
|
||||||
IsInternal: util.OptionalBoolFalse,
|
IsInternal: util.OptionalBoolFalse,
|
||||||
|
Sort: sort,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("SearchVersions", err)
|
ctx.ServerError("SearchVersions", err)
|
||||||
|
|
|
@ -224,6 +224,11 @@ func deleteIssue(issue *issues_model.Issue) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := issues_model.UpdateMilestoneCounters(ctx, issue.MilestoneID); err != nil {
|
||||||
|
return fmt.Errorf("error updating counters for milestone id %d: %w",
|
||||||
|
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); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -438,14 +438,21 @@ func buildObjectResponse(rc *requestContext, pointer lfs_module.Pointer, downloa
|
||||||
}
|
}
|
||||||
|
|
||||||
if download {
|
if download {
|
||||||
rep.Actions["download"] = &lfs_module.Link{Href: rc.DownloadLink(pointer), Header: header}
|
var link *lfs_module.Link
|
||||||
if setting.LFS.ServeDirect {
|
if setting.LFS.ServeDirect {
|
||||||
// If we have a signed url (S3, object storage), redirect to this directly.
|
// If we have a signed url (S3, object storage), redirect to this directly.
|
||||||
u, err := storage.LFS.URL(pointer.RelativePath(), pointer.Oid)
|
u, err := storage.LFS.URL(pointer.RelativePath(), pointer.Oid)
|
||||||
if u != nil && err == nil {
|
if u != nil && err == nil {
|
||||||
rep.Actions["download"] = &lfs_module.Link{Href: u.String(), Header: header}
|
// Presigned url does not need the Authorization header
|
||||||
|
// https://github.com/go-gitea/gitea/issues/21525
|
||||||
|
delete(header, "Authorization")
|
||||||
|
link = &lfs_module.Link{Href: u.String(), Header: header}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if link == nil {
|
||||||
|
link = &lfs_module.Link{Href: rc.DownloadLink(pointer), Header: header}
|
||||||
|
}
|
||||||
|
rep.Actions["download"] = link
|
||||||
}
|
}
|
||||||
if upload {
|
if upload {
|
||||||
rep.Actions["upload"] = &lfs_module.Link{Href: rc.UploadLink(pointer), Header: header}
|
rep.Actions["upload"] = &lfs_module.Link{Href: rc.UploadLink(pointer), Header: header}
|
||||||
|
|
19
services/markup/main_test.go
Normal file
19
services/markup/main_test.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package markup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
unittest.MainTest(m, &unittest.TestOptions{
|
||||||
|
GiteaRootPath: filepath.Join("..", ".."),
|
||||||
|
FixtureFiles: []string{"user.yml"},
|
||||||
|
})
|
||||||
|
}
|
29
services/markup/processorhelper.go
Normal file
29
services/markup/processorhelper.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package markup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/markup"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ProcessorHelper() *markup.ProcessorHelper {
|
||||||
|
return &markup.ProcessorHelper{
|
||||||
|
IsUsernameMentionable: func(ctx context.Context, username string) bool {
|
||||||
|
// TODO: cast ctx to modules/context.Context and use IsUserVisibleToViewer
|
||||||
|
|
||||||
|
// Only link if the user actually exists
|
||||||
|
userExists, err := user.IsUserExist(ctx, 0, username)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to validate user in mention %q exists, assuming it does", username)
|
||||||
|
userExists = true
|
||||||
|
}
|
||||||
|
return userExists
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
20
services/markup/processorhelper_test.go
Normal file
20
services/markup/processorhelper_test.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package markup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProcessorHelper(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
assert.True(t, ProcessorHelper().IsUsernameMentionable(context.Background(), "user10"))
|
||||||
|
assert.False(t, ProcessorHelper().IsUsernameMentionable(context.Background(), "no-such-user"))
|
||||||
|
}
|
|
@ -37,20 +37,20 @@
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
<th>{{.locale.Tr "admin.packages.owner"}}</th>
|
<th>{{.locale.Tr "admin.packages.owner"}}</th>
|
||||||
<th>{{.locale.Tr "admin.packages.type"}}</th>
|
<th>{{.locale.Tr "admin.packages.type"}}</th>
|
||||||
<th data-sortt-asc="alphabetically" data-sortt-desc="reversealphabetically">
|
<th data-sortt-asc="name_asc" data-sortt-desc="name_desc">
|
||||||
{{.locale.Tr "admin.packages.name"}}
|
{{.locale.Tr "admin.packages.name"}}
|
||||||
{{SortArrow "alphabetically" "reversealphabetically" .SortType false}}
|
{{SortArrow "name_asc" "name_desc" .SortType false}}
|
||||||
</th>
|
</th>
|
||||||
<th data-sortt-asc="highestversion" data-sortt-desc="lowestversion">
|
<th data-sortt-asc="version_desc" data-sortt-desc="version_asc">
|
||||||
{{.locale.Tr "admin.packages.version"}}
|
{{.locale.Tr "admin.packages.version"}}
|
||||||
{{SortArrow "highestversion" "lowestversion" .SortType false}}
|
{{SortArrow "version_desc" "version_asc" .SortType false}}
|
||||||
</th>
|
</th>
|
||||||
<th>{{.locale.Tr "admin.packages.creator"}}</th>
|
<th>{{.locale.Tr "admin.packages.creator"}}</th>
|
||||||
<th>{{.locale.Tr "admin.packages.repository"}}</th>
|
<th>{{.locale.Tr "admin.packages.repository"}}</th>
|
||||||
<th>{{.locale.Tr "admin.packages.size"}}</th>
|
<th>{{.locale.Tr "admin.packages.size"}}</th>
|
||||||
<th data-sortt-asc="oldest" data-sortt-desc="newest">
|
<th data-sortt-asc="created_asc" data-sortt-desc="created_desc">
|
||||||
{{.locale.Tr "admin.packages.published"}}
|
{{.locale.Tr "admin.packages.published"}}
|
||||||
{{SortArrow "oldest" "newest" .SortType true}}
|
{{SortArrow "created_asc" "created_desc" .SortType true}}
|
||||||
</th>
|
</th>
|
||||||
<th>{{.locale.Tr "admin.notices.op"}}</th>
|
<th>{{.locale.Tr "admin.notices.op"}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -3,11 +3,17 @@
|
||||||
<form class="ui form ignore-dirty">
|
<form class="ui form ignore-dirty">
|
||||||
<div class="ui fluid action input">
|
<div class="ui fluid action input">
|
||||||
<input name="q" value="{{.Query}}" placeholder="{{.locale.Tr "explore.search"}}..." autofocus>
|
<input name="q" value="{{.Query}}" placeholder="{{.locale.Tr "explore.search"}}..." autofocus>
|
||||||
|
<select class="ui dropdown" name="sort">
|
||||||
|
<option value="version_asc"{{if eq .Sort "version_asc"}} selected="selected"{{end}}>{{.locale.Tr "filter.string.asc"}}</option>
|
||||||
|
<option value="version_desc"{{if eq .Sort "version_desc"}} selected="selected"{{end}}>{{.locale.Tr "filter.string.desc"}}</option>
|
||||||
|
<option value="created_asc"{{if eq .Sort "created_asc"}} selected="selected"{{end}}>{{.locale.Tr "repo.issues.filter_sort.oldest"}}</option>
|
||||||
|
<option value="created_desc"{{if or (eq .Sort "") (eq .Sort "created_desc")}} selected="selected"{{end}}>{{.locale.Tr "repo.issues.filter_sort.latest"}}</option>
|
||||||
|
</select>
|
||||||
{{if eq .PackageDescriptor.Package.Type "container"}}
|
{{if eq .PackageDescriptor.Package.Type "container"}}
|
||||||
<select class="ui dropdown" name="tagged">
|
<select class="ui dropdown" name="tagged">
|
||||||
{{$isTagged := or (eq .Tagged "") (eq .Tagged "tagged")}}
|
{{$isTagged := or (eq .Tagged "") (eq .Tagged "tagged")}}
|
||||||
<option value="tagged" {{if $isTagged}}selected="selected"{{end}}>{{.locale.Tr "packages.filter.container.tagged"}}</option>
|
<option value="tagged"{{if $isTagged}} selected="selected"{{end}}>{{.locale.Tr "packages.filter.container.tagged"}}</option>
|
||||||
<option value="untagged" {{if not $isTagged}}selected="selected"{{end}}>{{.locale.Tr "packages.filter.container.untagged"}}</option>
|
<option value="untagged"{{if not $isTagged}} selected="selected"{{end}}>{{.locale.Tr "packages.filter.container.untagged"}}</option>
|
||||||
</select>
|
</select>
|
||||||
{{end}}
|
{{end}}
|
||||||
<button class="ui primary button">{{.locale.Tr "explore.search"}}</button>
|
<button class="ui primary button">{{.locale.Tr "explore.search"}}</button>
|
||||||
|
|
Loading…
Add table
Reference in a new issue