From 8c1d9885e5360111400bd4fb729f743065037d69 Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Mon, 7 Nov 2022 19:41:39 -0600 Subject: [PATCH 001/149] Remove semver compatible flag and change pypi to an array of test cases (#21708) This addresses #21707 and adds a second package test case for a non-semver compatible version (this might be overkill though since you could also edit the old package version to have an epoch in front and see the error, this just seemed more flexible for the future). Co-authored-by: KN4CK3R --- routers/api/packages/pypi/pypi.go | 12 ++++--- routers/api/packages/pypi/pypi_test.go | 39 +++++++++++++++++++++ tests/integration/api_packages_pypi_test.go | 6 ++-- 3 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 routers/api/packages/pypi/pypi_test.go diff --git a/routers/api/packages/pypi/pypi.go b/routers/api/packages/pypi/pypi.go index 66380d832c..4c8041c30c 100644 --- a/routers/api/packages/pypi/pypi.go +++ b/routers/api/packages/pypi/pypi.go @@ -21,9 +21,9 @@ import ( packages_service "code.gitea.io/gitea/services/packages" ) -// https://www.python.org/dev/peps/pep-0503/#normalized-names +// https://peps.python.org/pep-0426/#name var normalizer = strings.NewReplacer(".", "-", "_", "-") -var nameMatcher = regexp.MustCompile(`\A[a-zA-Z0-9\.\-_]+\z`) +var nameMatcher = regexp.MustCompile(`\A(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\.\-_]*[a-zA-Z0-9])\z`) // https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions var versionMatcher = regexp.MustCompile(`\Av?` + @@ -128,7 +128,7 @@ func UploadPackageFile(ctx *context.Context) { packageName := normalizer.Replace(ctx.Req.FormValue("name")) packageVersion := ctx.Req.FormValue("version") - if !nameMatcher.MatchString(packageName) || !versionMatcher.MatchString(packageVersion) { + if !isValidNameAndVersion(packageName, packageVersion) { apiError(ctx, http.StatusBadRequest, "invalid name or version") return } @@ -146,7 +146,7 @@ func UploadPackageFile(ctx *context.Context) { Name: packageName, Version: packageVersion, }, - SemverCompatible: true, + SemverCompatible: false, Creator: ctx.Doer, Metadata: &pypi_module.Metadata{ Author: ctx.Req.FormValue("author"), @@ -177,3 +177,7 @@ func UploadPackageFile(ctx *context.Context) { ctx.Status(http.StatusCreated) } + +func isValidNameAndVersion(packageName, packageVersion string) bool { + return nameMatcher.MatchString(packageName) && versionMatcher.MatchString(packageVersion) +} diff --git a/routers/api/packages/pypi/pypi_test.go b/routers/api/packages/pypi/pypi_test.go new file mode 100644 index 0000000000..56e327a347 --- /dev/null +++ b/routers/api/packages/pypi/pypi_test.go @@ -0,0 +1,39 @@ +// 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 pypi + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIsValidNameAndVersion(t *testing.T) { + // The test cases below were created from the following Python PEPs: + // https://peps.python.org/pep-0426/#name + // https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions + + // Valid Cases + assert.True(t, isValidNameAndVersion("A", "1.0.1")) + assert.True(t, isValidNameAndVersion("Test.Name.1234", "1.0.1")) + assert.True(t, isValidNameAndVersion("test_name", "1.0.1")) + assert.True(t, isValidNameAndVersion("test-name", "1.0.1")) + assert.True(t, isValidNameAndVersion("test-name", "v1.0.1")) + assert.True(t, isValidNameAndVersion("test-name", "2012.4")) + assert.True(t, isValidNameAndVersion("test-name", "1.0.1-alpha")) + assert.True(t, isValidNameAndVersion("test-name", "1.0.1a1")) + assert.True(t, isValidNameAndVersion("test-name", "1.0b2.r345.dev456")) + assert.True(t, isValidNameAndVersion("test-name", "1!1.0.1")) + assert.True(t, isValidNameAndVersion("test-name", "1.0.1+local.1")) + + // Invalid Cases + assert.False(t, isValidNameAndVersion(".test-name", "1.0.1")) + assert.False(t, isValidNameAndVersion("test!name", "1.0.1")) + assert.False(t, isValidNameAndVersion("-test-name", "1.0.1")) + assert.False(t, isValidNameAndVersion("test-name-", "1.0.1")) + assert.False(t, isValidNameAndVersion("test-name", "a1.0.1")) + assert.False(t, isValidNameAndVersion("test-name", "1.0.1aa")) + assert.False(t, isValidNameAndVersion("test-name", "1.0.0-alpha.beta")) +} diff --git a/tests/integration/api_packages_pypi_test.go b/tests/integration/api_packages_pypi_test.go index 0cd6ff7d13..83719dcca0 100644 --- a/tests/integration/api_packages_pypi_test.go +++ b/tests/integration/api_packages_pypi_test.go @@ -29,7 +29,7 @@ func TestPackagePyPI(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) packageName := "test-package" - packageVersion := "1.0.1+r1234" + packageVersion := "1!1.0.1+r1234" packageAuthor := "KN4CK3R" packageDescription := "Test Description" @@ -72,7 +72,7 @@ func TestPackagePyPI(t *testing.T) { pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0]) assert.NoError(t, err) - assert.NotNil(t, pd.SemVer) + assert.Nil(t, pd.SemVer) assert.IsType(t, &pypi.Metadata{}, pd.Metadata) assert.Equal(t, packageName, pd.Package.Name) assert.Equal(t, packageVersion, pd.Version.Version) @@ -100,7 +100,7 @@ func TestPackagePyPI(t *testing.T) { pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0]) assert.NoError(t, err) - assert.NotNil(t, pd.SemVer) + assert.Nil(t, pd.SemVer) assert.IsType(t, &pypi.Metadata{}, pd.Metadata) assert.Equal(t, packageName, pd.Package.Name) assert.Equal(t, packageVersion, pd.Version.Version) From 91c7a3e66f16f42816784817017408b6b35fb585 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 8 Nov 2022 12:07:46 +0800 Subject: [PATCH 002/149] Fix tests on migrations (#21705) --- models/migrations/v1_19/main_test.go | 15 +++++++++++++++ models/migrations/v1_19/v233_test.go | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 models/migrations/v1_19/main_test.go diff --git a/models/migrations/v1_19/main_test.go b/models/migrations/v1_19/main_test.go new file mode 100644 index 0000000000..8ba7fcaf10 --- /dev/null +++ b/models/migrations/v1_19/main_test.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package v1_19 // nolint + +import ( + "testing" + + "code.gitea.io/gitea/models/migrations/base" +) + +func TestMain(m *testing.M) { + base.MainTest(m) +} diff --git a/models/migrations/v1_19/v233_test.go b/models/migrations/v1_19/v233_test.go index f0a44df8cb..dd810feef2 100644 --- a/models/migrations/v1_19/v233_test.go +++ b/models/migrations/v1_19/v233_test.go @@ -16,7 +16,7 @@ import ( "github.com/stretchr/testify/assert" ) -func Test_addHeaderAuthorizationEncryptedColWebhook(t *testing.T) { +func Test_AddHeaderAuthorizationEncryptedColWebhook(t *testing.T) { // Create Webhook table type Webhook struct { ID int64 `xorm:"pk autoincr"` From 2ebab429347f04330dab9de5a730e0296ba6524b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 8 Nov 2022 23:13:58 +0800 Subject: [PATCH 003/149] Move svg html render to modules/svg (#21716) Also added more checks for the render function. Co-authored-by: silverwind --- modules/html/html.go | 34 +++++++++++++++++++++++ modules/svg/svg.go | 37 +++++++++++++++++++++++-- modules/templates/helper.go | 55 ++++++------------------------------- 3 files changed, 77 insertions(+), 49 deletions(-) create mode 100644 modules/html/html.go diff --git a/modules/html/html.go b/modules/html/html.go new file mode 100644 index 0000000000..dafdb503b6 --- /dev/null +++ b/modules/html/html.go @@ -0,0 +1,34 @@ +// 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 html + +// ParseSizeAndClass get size and class from string with default values +// If present, "others" expects the new size first and then the classes to use +func ParseSizeAndClass(defaultSize int, defaultClass string, others ...interface{}) (int, string) { + if len(others) == 0 { + return defaultSize, defaultClass + } + + size := defaultSize + _size, ok := others[0].(int) + if ok && _size != 0 { + size = _size + } + + if len(others) == 1 { + return size, defaultClass + } + + class := defaultClass + if _class, ok := others[1].(string); ok && _class != "" { + if defaultClass == "" { + class = _class + } else { + class = defaultClass + " " + _class + } + } + + return size, class +} diff --git a/modules/svg/svg.go b/modules/svg/svg.go index 1d1f8a90eb..4e13d92d41 100644 --- a/modules/svg/svg.go +++ b/modules/svg/svg.go @@ -4,10 +4,43 @@ package svg -// SVGs contains discovered SVGs -var SVGs map[string]string +import ( + "fmt" + "html/template" + "regexp" + "strings" + + "code.gitea.io/gitea/modules/html" +) + +var ( + // SVGs contains discovered SVGs + SVGs map[string]string + + widthRe = regexp.MustCompile(`width="[0-9]+?"`) + heightRe = regexp.MustCompile(`height="[0-9]+?"`) +) + +const defaultSize = 16 // Init discovers SVGs and populates the `SVGs` variable func Init() { SVGs = Discover() } + +// Render render icons - arguments icon name (string), size (int), class (string) +func RenderHTML(icon string, others ...interface{}) template.HTML { + size, class := html.ParseSizeAndClass(defaultSize, "", others...) + + if svgStr, ok := SVGs[icon]; ok { + if size != defaultSize { + svgStr = widthRe.ReplaceAllString(svgStr, fmt.Sprintf(`width="%d"`, size)) + svgStr = heightRe.ReplaceAllString(svgStr, fmt.Sprintf(`height="%d"`, size)) + } + if class != "" { + svgStr = strings.Replace(svgStr, `class="`, fmt.Sprintf(`class="%s `, class), 1) + } + return template.HTML(svgStr) + } + return template.HTML("") +} diff --git a/modules/templates/helper.go b/modules/templates/helper.go index a127b98dc2..c5434b7c63 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -35,6 +35,7 @@ import ( "code.gitea.io/gitea/modules/emoji" "code.gitea.io/gitea/modules/git" giturl "code.gitea.io/gitea/modules/git/url" + gitea_html "code.gitea.io/gitea/modules/html" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" @@ -348,7 +349,7 @@ func NewFuncMap() []template.FuncMap { } return false }, - "svg": SVG, + "svg": svg.RenderHTML, "avatar": Avatar, "avatarHTML": AvatarHTML, "avatarByAction": AvatarByAction, @@ -363,17 +364,17 @@ func NewFuncMap() []template.FuncMap { if len(urlSort) == 0 && isDefault { // if sort is sorted as default add arrow tho this table header if isDefault { - return SVG("octicon-triangle-down", 16) + return svg.RenderHTML("octicon-triangle-down", 16) } } else { // if sort arg is in url test if it correlates with column header sort arguments // the direction of the arrow should indicate the "current sort order", up means ASC(normal), down means DESC(rev) if urlSort == normSort { // the table is sorted with this header normal - return SVG("octicon-triangle-up", 16) + return svg.RenderHTML("octicon-triangle-up", 16) } else if urlSort == revSort { // the table is sorted with this header reverse - return SVG("octicon-triangle-down", 16) + return svg.RenderHTML("octicon-triangle-down", 16) } } // the table is NOT sorted with this header @@ -594,29 +595,6 @@ func NewTextFuncMap() []texttmpl.FuncMap { }} } -var ( - widthRe = regexp.MustCompile(`width="[0-9]+?"`) - heightRe = regexp.MustCompile(`height="[0-9]+?"`) -) - -func parseOthers(defaultSize int, defaultClass string, others ...interface{}) (int, string) { - size := defaultSize - if len(others) > 0 && others[0].(int) != 0 { - size = others[0].(int) - } - - class := defaultClass - if len(others) > 1 && others[1].(string) != "" { - if defaultClass == "" { - class = others[1].(string) - } else { - class = defaultClass + " " + others[1].(string) - } - } - - return size, class -} - // AvatarHTML creates the HTML for an avatar func AvatarHTML(src string, size int, class, name string) template.HTML { sizeStr := fmt.Sprintf(`%d`, size) @@ -628,26 +606,9 @@ func AvatarHTML(src string, size int, class, name string) template.HTML { return template.HTML(``) } -// SVG render icons - arguments icon name (string), size (int), class (string) -func SVG(icon string, others ...interface{}) template.HTML { - size, class := parseOthers(16, "", others...) - - if svgStr, ok := svg.SVGs[icon]; ok { - if size != 16 { - svgStr = widthRe.ReplaceAllString(svgStr, fmt.Sprintf(`width="%d"`, size)) - svgStr = heightRe.ReplaceAllString(svgStr, fmt.Sprintf(`height="%d"`, size)) - } - if class != "" { - svgStr = strings.Replace(svgStr, `class="`, fmt.Sprintf(`class="%s `, class), 1) - } - return template.HTML(svgStr) - } - return template.HTML("") -} - // Avatar renders user avatars. args: user, size (int), class (string) func Avatar(item interface{}, others ...interface{}) template.HTML { - size, class := parseOthers(avatars.DefaultAvatarPixelSize, "ui avatar vm", others...) + size, class := gitea_html.ParseSizeAndClass(avatars.DefaultAvatarPixelSize, "ui avatar vm", others...) switch t := item.(type) { case *user_model.User: @@ -678,7 +639,7 @@ func AvatarByAction(action *activities_model.Action, others ...interface{}) temp // RepoAvatar renders repo avatars. args: repo, size(int), class (string) func RepoAvatar(repo *repo_model.Repository, others ...interface{}) template.HTML { - size, class := parseOthers(avatars.DefaultAvatarPixelSize, "ui avatar", others...) + size, class := gitea_html.ParseSizeAndClass(avatars.DefaultAvatarPixelSize, "ui avatar", others...) src := repo.RelAvatarLink() if src != "" { @@ -689,7 +650,7 @@ func RepoAvatar(repo *repo_model.Repository, others ...interface{}) template.HTM // AvatarByEmail renders avatars by email address. args: email, name, size (int), class (string) func AvatarByEmail(email, name string, others ...interface{}) template.HTML { - size, class := parseOthers(avatars.DefaultAvatarPixelSize, "ui avatar", others...) + size, class := gitea_html.ParseSizeAndClass(avatars.DefaultAvatarPixelSize, "ui avatar", others...) src := avatars.GenerateEmailAvatarFastLink(email, size*setting.Avatar.RenderedSizeFactor) if src != "" { From cb83288530b1860677b07d72bc4ce8349e3c0d67 Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Wed, 9 Nov 2022 02:11:26 +0200 Subject: [PATCH 004/149] Add attention blocks within quote blocks for `Note` and `Warning` (#21711) For each quote block, the first `**Note**` or `**Warning**` gets an icon prepended to it and its text is colored accordingly. GitHub does this (community/community#16925). [Initially requested on Discord.](https://discord.com/channels/322538954119184384/322538954119184384/1038816475638661181) ### Before ![image](https://user-images.githubusercontent.com/20454870/200408558-bd318302-6ff9-4d56-996f-9190e89013ec.png) ### After ![image](https://user-images.githubusercontent.com/20454870/200658863-1bac6461-dae7-4bf2-abd2-672d209574e4.png) Signed-off-by: Yarden Shoham Co-authored-by: delvh Co-authored-by: silverwind --- modules/markup/markdown/ast.go | 34 ++++++++++++++++++++++++++ modules/markup/markdown/goldmark.go | 37 +++++++++++++++++++++++++++++ modules/markup/sanitizer.go | 7 ++++++ web_src/less/_base.less | 14 +++++++++++ 4 files changed, 92 insertions(+) diff --git a/modules/markup/markdown/ast.go b/modules/markup/markdown/ast.go index c82d5e5e73..3d49620253 100644 --- a/modules/markup/markdown/ast.go +++ b/modules/markup/markdown/ast.go @@ -180,3 +180,37 @@ func IsColorPreview(node ast.Node) bool { _, ok := node.(*ColorPreview) return ok } + +const ( + AttentionNote string = "Note" + AttentionWarning string = "Warning" +) + +// Attention is an inline for a color preview +type Attention struct { + ast.BaseInline + AttentionType string +} + +// Dump implements Node.Dump. +func (n *Attention) Dump(source []byte, level int) { + m := map[string]string{} + m["AttentionType"] = n.AttentionType + ast.DumpHelper(n, source, level, m, nil) +} + +// KindAttention is the NodeKind for Attention +var KindAttention = ast.NewNodeKind("Attention") + +// Kind implements Node.Kind. +func (n *Attention) Kind() ast.NodeKind { + return KindAttention +} + +// NewAttention returns a new Attention node. +func NewAttention(attentionType string) *Attention { + return &Attention{ + BaseInline: ast.BaseInline{}, + AttentionType: attentionType, + } +} diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 1a36681366..84a02bfbbb 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/common" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/svg" giteautil "code.gitea.io/gitea/modules/util" "github.com/microcosm-cc/bluemonday/css" @@ -46,6 +47,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa ctx.TableOfContents = make([]markup.Header, 0, 100) } + attentionMarkedBlockquotes := make(container.Set[*ast.Blockquote]) _ = ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) { if !entering { return ast.WalkContinue, nil @@ -184,6 +186,18 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa if css.ColorHandler(strings.ToLower(string(colorContent))) { v.AppendChild(v, NewColorPreview(colorContent)) } + case *ast.Emphasis: + // check if inside blockquote for attention, expected hierarchy is + // Emphasis < Paragraph < Blockquote + blockquote, isInBlockquote := n.Parent().Parent().(*ast.Blockquote) + if isInBlockquote && !attentionMarkedBlockquotes.Contains(blockquote) { + fullText := string(n.Text(reader.Source())) + if fullText == AttentionNote || fullText == AttentionWarning { + v.SetAttributeString("class", []byte("attention-"+strings.ToLower(fullText))) + v.Parent().InsertBefore(v.Parent(), v, NewAttention(fullText)) + attentionMarkedBlockquotes.Add(blockquote) + } + } } return ast.WalkContinue, nil }) @@ -273,6 +287,7 @@ func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { reg.Register(KindSummary, r.renderSummary) reg.Register(KindIcon, r.renderIcon) reg.Register(ast.KindCodeSpan, r.renderCodeSpan) + reg.Register(KindAttention, r.renderAttention) reg.Register(KindTaskCheckBoxListItem, r.renderTaskCheckBoxListItem) reg.Register(east.KindTaskCheckBox, r.renderTaskCheckBox) } @@ -309,6 +324,28 @@ func (r *HTMLRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Nod return ast.WalkContinue, nil } +// renderAttention renders a quote marked with i.e. "> **Note**" or "> **Warning**" with a corresponding svg +func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + _, _ = w.WriteString(``) + + var octiconType string + switch n.AttentionType { + case AttentionNote: + octiconType = "info" + case AttentionWarning: + octiconType = "alert" + } + _, _ = w.WriteString(string(svg.RenderHTML("octicon-" + octiconType))) + } else { + _, _ = w.WriteString("\n") + } + return ast.WalkContinue, nil +} + func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { n := node.(*ast.Document) diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go index ff7165c131..c2a6c4a38f 100644 --- a/modules/markup/sanitizer.go +++ b/modules/markup/sanitizer.go @@ -58,6 +58,13 @@ func createDefaultPolicy() *bluemonday.Policy { // For color preview policy.AllowAttrs("class").Matching(regexp.MustCompile(`^color-preview$`)).OnElements("span") + // For attention + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^attention-\w+$`)).OnElements("strong") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^attention-icon attention-\w+$`)).OnElements("span", "strong") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^svg octicon-\w+$`)).OnElements("svg") + policy.AllowAttrs("viewBox", "width", "height", "aria-hidden").OnElements("svg") + policy.AllowAttrs("fill-rule", "d").OnElements("path") + // For Chroma markdown plugin policy.AllowAttrs("class").Matching(regexp.MustCompile(`^(chroma )?language-[\w-]+( display)?( is-loading)?$`)).OnElements("code") diff --git a/web_src/less/_base.less b/web_src/less/_base.less index f1691d8156..43d8d711aa 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -1732,6 +1732,20 @@ a.ui.card:hover, border-radius: .15em; } +.attention-icon { + vertical-align: text-top; +} + +.attention-note { + font-weight: unset; + color: var(--color-info-text); +} + +.attention-warning { + font-weight: unset; + color: var(--color-warning-text); +} + footer { background-color: var(--color-footer); border-top: 1px solid var(--color-secondary); From 20674dd05da909b42cbdd07a6682fdf1d980f011 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Wed, 9 Nov 2022 07:34:27 +0100 Subject: [PATCH 005/149] Add package registry quota limits (#21584) Related #20471 This PR adds global quota limits for the package registry. Settings for individual users/orgs can be added in a seperate PR using the settings table. Co-authored-by: Lauris BH Co-authored-by: Lunny Xiao --- cmd/migrate_storage_test.go | 5 +- custom/conf/app.example.ini | 29 ++++++ .../doc/advanced/config-cheat-sheet.en-us.md | 14 +++ models/packages/package_file.go | 10 ++ models/packages/package_version.go | 9 ++ modules/setting/packages.go | 50 +++++++++- modules/setting/packages_test.go | 31 ++++++ routers/api/packages/composer/composer.go | 14 ++- routers/api/packages/conan/conan.go | 14 ++- routers/api/packages/generic/generic.go | 14 ++- routers/api/packages/helm/helm.go | 10 +- routers/api/packages/maven/maven.go | 10 +- routers/api/packages/npm/npm.go | 14 ++- routers/api/packages/nuget/nuget.go | 28 ++++-- routers/api/packages/pub/pub.go | 14 ++- routers/api/packages/pypi/pypi.go | 14 ++- routers/api/packages/rubygems/rubygems.go | 14 ++- routers/api/packages/vagrant/vagrant.go | 14 ++- services/packages/packages.go | 97 ++++++++++++++++++- tests/integration/api_packages_test.go | 34 +++++++ 20 files changed, 378 insertions(+), 61 deletions(-) create mode 100644 modules/setting/packages_test.go diff --git a/cmd/migrate_storage_test.go b/cmd/migrate_storage_test.go index 0d264ef5a1..7051591ad6 100644 --- a/cmd/migrate_storage_test.go +++ b/cmd/migrate_storage_test.go @@ -44,8 +44,9 @@ func TestMigratePackages(t *testing.T) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: "a.go", }, - Data: buf, - IsLead: true, + Creator: creator, + Data: buf, + IsLead: true, }) assert.NoError(t, err) assert.NotNil(t, v) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index b59ceee4f1..b46dfc20a9 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2335,6 +2335,35 @@ ROUTER = console ;; ;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload` ;CHUNKED_UPLOAD_PATH = tmp/package-upload +;; +;; Maxmimum count of package versions a single owner can have (`-1` means no limits) +;LIMIT_TOTAL_OWNER_COUNT = -1 +;; Maxmimum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_TOTAL_OWNER_SIZE = -1 +;; Maxmimum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_COMPOSER = -1 +;; Maxmimum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_CONAN = -1 +;; Maxmimum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_CONTAINER = -1 +;; Maxmimum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_GENERIC = -1 +;; Maxmimum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_HELM = -1 +;; Maxmimum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_MAVEN = -1 +;; Maxmimum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_NPM = -1 +;; Maxmimum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_NUGET = -1 +;; Maxmimum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_PUB = -1 +;; Maxmimum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_PYPI = -1 +;; Maxmimum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_RUBYGEMS = -1 +;; Maxmimum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_VAGRANT = -1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index df1911934c..28bcaf29af 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -1138,6 +1138,20 @@ Task queue configuration has been moved to `queue.task`. However, the below conf - `ENABLED`: **true**: Enable/Disable package registry capabilities - `CHUNKED_UPLOAD_PATH`: **tmp/package-upload**: Path for chunked uploads. Defaults to `APP_DATA_PATH` + `tmp/package-upload` +- `LIMIT_TOTAL_OWNER_COUNT`: **-1**: Maxmimum count of package versions a single owner can have (`-1` means no limits) +- `LIMIT_TOTAL_OWNER_SIZE`: **-1**: Maxmimum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_COMPOSER`: **-1**: Maxmimum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_CONAN`: **-1**: Maxmimum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_CONTAINER`: **-1**: Maxmimum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_GENERIC`: **-1**: Maxmimum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_HELM`: **-1**: Maxmimum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_MAVEN`: **-1**: Maxmimum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_NPM`: **-1**: Maxmimum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_NUGET`: **-1**: Maxmimum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_PUB`: **-1**: Maxmimum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_PYPI`: **-1**: Maxmimum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_RUBYGEMS`: **-1**: Maxmimum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_VAGRANT`: **-1**: Maxmimum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ## Mirror (`mirror`) diff --git a/models/packages/package_file.go b/models/packages/package_file.go index 8f304ce8ac..9f6284af07 100644 --- a/models/packages/package_file.go +++ b/models/packages/package_file.go @@ -199,3 +199,13 @@ func SearchFiles(ctx context.Context, opts *PackageFileSearchOptions) ([]*Packag count, err := sess.FindAndCount(&pfs) return pfs, count, err } + +// CalculateBlobSize sums up all blob sizes matching the search options. +// It does NOT respect the deduplication of blobs. +func CalculateBlobSize(ctx context.Context, opts *PackageFileSearchOptions) (int64, error) { + return db.GetEngine(ctx). + Table("package_file"). + Where(opts.toConds()). + Join("INNER", "package_blob", "package_blob.id = package_file.blob_id"). + SumInt(new(PackageBlob), "size") +} diff --git a/models/packages/package_version.go b/models/packages/package_version.go index 782261c575..48c6aa7d60 100644 --- a/models/packages/package_version.go +++ b/models/packages/package_version.go @@ -319,3 +319,12 @@ func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*P count, err := sess.FindAndCount(&pvs) return pvs, count, err } + +// CountVersions counts all versions of packages matching the search options +func CountVersions(ctx context.Context, opts *PackageSearchOptions) (int64, error) { + return db.GetEngine(ctx). + Where(opts.toConds()). + Table("package_version"). + Join("INNER", "package", "package.id = package_version.package_id"). + Count(new(PackageVersion)) +} diff --git a/modules/setting/packages.go b/modules/setting/packages.go index 5e0f2a3b03..62201032c7 100644 --- a/modules/setting/packages.go +++ b/modules/setting/packages.go @@ -5,11 +5,15 @@ package setting import ( + "math" "net/url" "os" "path/filepath" "code.gitea.io/gitea/modules/log" + + "github.com/dustin/go-humanize" + ini "gopkg.in/ini.v1" ) // Package registry settings @@ -19,8 +23,24 @@ var ( Enabled bool ChunkedUploadPath string RegistryHost string + + LimitTotalOwnerCount int64 + LimitTotalOwnerSize int64 + LimitSizeComposer int64 + LimitSizeConan int64 + LimitSizeContainer int64 + LimitSizeGeneric int64 + LimitSizeHelm int64 + LimitSizeMaven int64 + LimitSizeNpm int64 + LimitSizeNuGet int64 + LimitSizePub int64 + LimitSizePyPI int64 + LimitSizeRubyGems int64 + LimitSizeVagrant int64 }{ - Enabled: true, + Enabled: true, + LimitTotalOwnerCount: -1, } ) @@ -43,4 +63,32 @@ func newPackages() { if err := os.MkdirAll(Packages.ChunkedUploadPath, os.ModePerm); err != nil { log.Error("Unable to create chunked upload directory: %s (%v)", Packages.ChunkedUploadPath, err) } + + Packages.LimitTotalOwnerSize = mustBytes(sec, "LIMIT_TOTAL_OWNER_SIZE") + Packages.LimitSizeComposer = mustBytes(sec, "LIMIT_SIZE_COMPOSER") + Packages.LimitSizeConan = mustBytes(sec, "LIMIT_SIZE_CONAN") + Packages.LimitSizeContainer = mustBytes(sec, "LIMIT_SIZE_CONTAINER") + Packages.LimitSizeGeneric = mustBytes(sec, "LIMIT_SIZE_GENERIC") + Packages.LimitSizeHelm = mustBytes(sec, "LIMIT_SIZE_HELM") + Packages.LimitSizeMaven = mustBytes(sec, "LIMIT_SIZE_MAVEN") + Packages.LimitSizeNpm = mustBytes(sec, "LIMIT_SIZE_NPM") + Packages.LimitSizeNuGet = mustBytes(sec, "LIMIT_SIZE_NUGET") + Packages.LimitSizePub = mustBytes(sec, "LIMIT_SIZE_PUB") + Packages.LimitSizePyPI = mustBytes(sec, "LIMIT_SIZE_PYPI") + Packages.LimitSizeRubyGems = mustBytes(sec, "LIMIT_SIZE_RUBYGEMS") + Packages.LimitSizeVagrant = mustBytes(sec, "LIMIT_SIZE_VAGRANT") +} + +func mustBytes(section *ini.Section, key string) int64 { + const noLimit = "-1" + + value := section.Key(key).MustString(noLimit) + if value == noLimit { + return -1 + } + bytes, err := humanize.ParseBytes(value) + if err != nil || bytes > math.MaxInt64 { + return -1 + } + return int64(bytes) } diff --git a/modules/setting/packages_test.go b/modules/setting/packages_test.go new file mode 100644 index 0000000000..059273dce4 --- /dev/null +++ b/modules/setting/packages_test.go @@ -0,0 +1,31 @@ +// 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 setting + +import ( + "testing" + + "github.com/stretchr/testify/assert" + ini "gopkg.in/ini.v1" +) + +func TestMustBytes(t *testing.T) { + test := func(value string) int64 { + sec, _ := ini.Empty().NewSection("test") + sec.NewKey("VALUE", value) + + return mustBytes(sec, "VALUE") + } + + assert.EqualValues(t, -1, test("")) + assert.EqualValues(t, -1, test("-1")) + assert.EqualValues(t, 0, test("0")) + assert.EqualValues(t, 1, test("1")) + assert.EqualValues(t, 10000, test("10000")) + assert.EqualValues(t, 1000000, test("1 mb")) + assert.EqualValues(t, 1048576, test("1mib")) + assert.EqualValues(t, 1782579, test("1.7mib")) + assert.EqualValues(t, -1, test("1 yib")) // too large +} diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go index 86ef7cbd9a..92e83dbe79 100644 --- a/routers/api/packages/composer/composer.go +++ b/routers/api/packages/composer/composer.go @@ -235,16 +235,20 @@ func UploadPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: strings.ToLower(fmt.Sprintf("%s.%s.zip", strings.ReplaceAll(cp.Name, "/", "-"), cp.Version)), }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/conan/conan.go b/routers/api/packages/conan/conan.go index dd078d6ad3..c8c9dc3e38 100644 --- a/routers/api/packages/conan/conan.go +++ b/routers/api/packages/conan/conan.go @@ -348,8 +348,9 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey Filename: strings.ToLower(filename), CompositeKey: fileKey, }, - Data: buf, - IsLead: isConanfileFile, + Creator: ctx.Doer, + Data: buf, + IsLead: isConanfileFile, Properties: map[string]string{ conan_module.PropertyRecipeUser: rref.User, conan_module.PropertyRecipeChannel: rref.Channel, @@ -416,11 +417,14 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey pfci, ) if err != nil { - if err == packages_model.ErrDuplicatePackageFile { + switch err { + case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go index 81891bec26..1bccc6764c 100644 --- a/routers/api/packages/generic/generic.go +++ b/routers/api/packages/generic/generic.go @@ -104,16 +104,20 @@ func UploadPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: filename, }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageFile { + switch err { + case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusConflict, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/helm/helm.go b/routers/api/packages/helm/helm.go index 9c85e0874f..662d9a5dda 100644 --- a/routers/api/packages/helm/helm.go +++ b/routers/api/packages/helm/helm.go @@ -186,17 +186,21 @@ func UploadPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: createFilename(metadata), }, + Creator: ctx.Doer, Data: buf, IsLead: true, OverwriteExisting: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusConflict, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go index bf00c199f5..de274b2046 100644 --- a/routers/api/packages/maven/maven.go +++ b/routers/api/packages/maven/maven.go @@ -266,6 +266,7 @@ func UploadPackageFile(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: params.Filename, }, + Creator: ctx.Doer, Data: buf, IsLead: false, OverwriteExisting: params.IsMeta, @@ -312,11 +313,14 @@ func UploadPackageFile(ctx *context.Context) { pfci, ) if err != nil { - if err == packages_model.ErrDuplicatePackageFile { + switch err { + case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go index 82dae0cf43..6d589bde3a 100644 --- a/routers/api/packages/npm/npm.go +++ b/routers/api/packages/npm/npm.go @@ -180,16 +180,20 @@ func UploadPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: npmPackage.Filename, }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go index e84aef3160..442d94243b 100644 --- a/routers/api/packages/nuget/nuget.go +++ b/routers/api/packages/nuget/nuget.go @@ -374,16 +374,20 @@ func UploadPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: strings.ToLower(fmt.Sprintf("%s.%s.nupkg", np.ID, np.Version)), }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusConflict, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } @@ -428,8 +432,9 @@ func UploadSymbolPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: strings.ToLower(fmt.Sprintf("%s.%s.snupkg", np.ID, np.Version)), }, - Data: buf, - IsLead: false, + Creator: ctx.Doer, + Data: buf, + IsLead: false, }, ) if err != nil { @@ -438,6 +443,8 @@ func UploadSymbolPackage(ctx *context.Context) { apiError(ctx, http.StatusNotFound, err) case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusConflict, err) + case packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) default: apiError(ctx, http.StatusInternalServerError, err) } @@ -452,8 +459,9 @@ func UploadSymbolPackage(ctx *context.Context) { Filename: strings.ToLower(pdb.Name), CompositeKey: strings.ToLower(pdb.ID), }, - Data: pdb.Content, - IsLead: false, + Creator: ctx.Doer, + Data: pdb.Content, + IsLead: false, Properties: map[string]string{ nuget_module.PropertySymbolID: strings.ToLower(pdb.ID), }, @@ -463,6 +471,8 @@ func UploadSymbolPackage(ctx *context.Context) { switch err { case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusConflict, err) + case packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) default: apiError(ctx, http.StatusInternalServerError, err) } diff --git a/routers/api/packages/pub/pub.go b/routers/api/packages/pub/pub.go index 9af0ceeb0e..635147b6d0 100644 --- a/routers/api/packages/pub/pub.go +++ b/routers/api/packages/pub/pub.go @@ -199,16 +199,20 @@ func UploadPackageFile(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: strings.ToLower(pck.Version + ".tar.gz"), }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/pypi/pypi.go b/routers/api/packages/pypi/pypi.go index 4c8041c30c..4853e6658b 100644 --- a/routers/api/packages/pypi/pypi.go +++ b/routers/api/packages/pypi/pypi.go @@ -162,16 +162,20 @@ func UploadPackageFile(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: fileHeader.Filename, }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageFile { + switch err { + case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go index 319c94b91f..eeae21146c 100644 --- a/routers/api/packages/rubygems/rubygems.go +++ b/routers/api/packages/rubygems/rubygems.go @@ -242,16 +242,20 @@ func UploadPackageFile(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: filename, }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/vagrant/vagrant.go b/routers/api/packages/vagrant/vagrant.go index 7750e5dc4b..31ac56a532 100644 --- a/routers/api/packages/vagrant/vagrant.go +++ b/routers/api/packages/vagrant/vagrant.go @@ -193,19 +193,23 @@ func UploadPackageFile(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: strings.ToLower(boxProvider), }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, Properties: map[string]string{ vagrant_module.PropertyProvider: strings.TrimSuffix(boxProvider, ".box"), }, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageFile { + switch err { + case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusConflict, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/services/packages/packages.go b/services/packages/packages.go index 96132eac09..443976e174 100644 --- a/services/packages/packages.go +++ b/services/packages/packages.go @@ -6,6 +6,7 @@ package packages import ( "context" + "errors" "fmt" "io" "strings" @@ -19,10 +20,17 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification" packages_module "code.gitea.io/gitea/modules/packages" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" container_service "code.gitea.io/gitea/services/packages/container" ) +var ( + ErrQuotaTypeSize = errors.New("maximum allowed package type size exceeded") + ErrQuotaTotalSize = errors.New("maximum allowed package storage quota exceeded") + ErrQuotaTotalCount = errors.New("maximum allowed package count exceeded") +) + // PackageInfo describes a package type PackageInfo struct { Owner *user_model.User @@ -50,6 +58,7 @@ type PackageFileInfo struct { // PackageFileCreationInfo describes a package file to create type PackageFileCreationInfo struct { PackageFileInfo + Creator *user_model.User Data packages_module.HashedSizeReader IsLead bool Properties map[string]string @@ -78,7 +87,7 @@ func createPackageAndAddFile(pvci *PackageCreationInfo, pfci *PackageFileCreatio return nil, nil, err } - pf, pb, blobCreated, err := addFileToPackageVersion(ctx, pv, pfci) + pf, pb, blobCreated, err := addFileToPackageVersion(ctx, pv, &pvci.PackageInfo, pfci) removeBlob := false defer func() { if blobCreated && removeBlob { @@ -164,6 +173,10 @@ func createPackageAndVersion(ctx context.Context, pvci *PackageCreationInfo, all } if versionCreated { + if err := checkCountQuotaExceeded(ctx, pvci.Creator, pvci.Owner); err != nil { + return nil, false, err + } + for name, value := range pvci.VersionProperties { if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypeVersion, pv.ID, name, value); err != nil { log.Error("Error setting package version property: %v", err) @@ -188,7 +201,7 @@ func AddFileToExistingPackage(pvi *PackageInfo, pfci *PackageFileCreationInfo) ( return nil, nil, err } - pf, pb, blobCreated, err := addFileToPackageVersion(ctx, pv, pfci) + pf, pb, blobCreated, err := addFileToPackageVersion(ctx, pv, pvi, pfci) removeBlob := false defer func() { if removeBlob { @@ -224,9 +237,13 @@ func NewPackageBlob(hsr packages_module.HashedSizeReader) *packages_model.Packag } } -func addFileToPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) { +func addFileToPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pvi *PackageInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) { log.Trace("Adding package file: %v, %s", pv.ID, pfci.Filename) + if err := checkSizeQuotaExceeded(ctx, pfci.Creator, pvi.Owner, pvi.PackageType, pfci.Data.Size()); err != nil { + return nil, nil, false, err + } + pb, exists, err := packages_model.GetOrInsertBlob(ctx, NewPackageBlob(pfci.Data)) if err != nil { log.Error("Error inserting package blob: %v", err) @@ -285,6 +302,80 @@ func addFileToPackageVersion(ctx context.Context, pv *packages_model.PackageVers return pf, pb, !exists, nil } +func checkCountQuotaExceeded(ctx context.Context, doer, owner *user_model.User) error { + if doer.IsAdmin { + return nil + } + + if setting.Packages.LimitTotalOwnerCount > -1 { + totalCount, err := packages_model.CountVersions(ctx, &packages_model.PackageSearchOptions{ + OwnerID: owner.ID, + IsInternal: util.OptionalBoolFalse, + }) + if err != nil { + log.Error("CountVersions failed: %v", err) + return err + } + if totalCount > setting.Packages.LimitTotalOwnerCount { + return ErrQuotaTotalCount + } + } + + return nil +} + +func checkSizeQuotaExceeded(ctx context.Context, doer, owner *user_model.User, packageType packages_model.Type, uploadSize int64) error { + if doer.IsAdmin { + return nil + } + + var typeSpecificSize int64 + switch packageType { + case packages_model.TypeComposer: + typeSpecificSize = setting.Packages.LimitSizeComposer + case packages_model.TypeConan: + typeSpecificSize = setting.Packages.LimitSizeConan + case packages_model.TypeContainer: + typeSpecificSize = setting.Packages.LimitSizeContainer + case packages_model.TypeGeneric: + typeSpecificSize = setting.Packages.LimitSizeGeneric + case packages_model.TypeHelm: + typeSpecificSize = setting.Packages.LimitSizeHelm + case packages_model.TypeMaven: + typeSpecificSize = setting.Packages.LimitSizeMaven + case packages_model.TypeNpm: + typeSpecificSize = setting.Packages.LimitSizeNpm + case packages_model.TypeNuGet: + typeSpecificSize = setting.Packages.LimitSizeNuGet + case packages_model.TypePub: + typeSpecificSize = setting.Packages.LimitSizePub + case packages_model.TypePyPI: + typeSpecificSize = setting.Packages.LimitSizePyPI + case packages_model.TypeRubyGems: + typeSpecificSize = setting.Packages.LimitSizeRubyGems + case packages_model.TypeVagrant: + typeSpecificSize = setting.Packages.LimitSizeVagrant + } + if typeSpecificSize > -1 && typeSpecificSize < uploadSize { + return ErrQuotaTypeSize + } + + if setting.Packages.LimitTotalOwnerSize > -1 { + totalSize, err := packages_model.CalculateBlobSize(ctx, &packages_model.PackageFileSearchOptions{ + OwnerID: owner.ID, + }) + if err != nil { + log.Error("CalculateBlobSize failed: %v", err) + return err + } + if totalSize+uploadSize > setting.Packages.LimitTotalOwnerSize { + return ErrQuotaTotalSize + } + } + + return nil +} + // RemovePackageVersionByNameAndVersion deletes a package version and all associated files func RemovePackageVersionByNameAndVersion(doer *user_model.User, pvi *PackageInfo) error { pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version) diff --git a/tests/integration/api_packages_test.go b/tests/integration/api_packages_test.go index 25f5b3f2a1..815685ea79 100644 --- a/tests/integration/api_packages_test.go +++ b/tests/integration/api_packages_test.go @@ -16,6 +16,7 @@ import ( container_model "code.gitea.io/gitea/models/packages/container" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" packages_service "code.gitea.io/gitea/services/packages" "code.gitea.io/gitea/tests" @@ -166,6 +167,39 @@ func TestPackageAccess(t *testing.T) { uploadPackage(admin, user, http.StatusCreated) } +func TestPackageQuota(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + limitTotalOwnerCount, limitTotalOwnerSize, limitSizeGeneric := setting.Packages.LimitTotalOwnerCount, setting.Packages.LimitTotalOwnerSize, setting.Packages.LimitSizeGeneric + + admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10}) + + uploadPackage := func(doer *user_model.User, version string, expectedStatus int) { + url := fmt.Sprintf("/api/packages/%s/generic/test-package/%s/file.bin", user.Name, version) + req := NewRequestWithBody(t, "PUT", url, bytes.NewReader([]byte{1})) + AddBasicAuthHeader(req, doer.Name) + MakeRequest(t, req, expectedStatus) + } + + // Exceeded quota result in StatusForbidden for normal users but admins are always allowed to upload. + + setting.Packages.LimitTotalOwnerCount = 0 + uploadPackage(user, "1.0", http.StatusForbidden) + uploadPackage(admin, "1.0", http.StatusCreated) + setting.Packages.LimitTotalOwnerCount = limitTotalOwnerCount + + setting.Packages.LimitTotalOwnerSize = 0 + uploadPackage(user, "1.1", http.StatusForbidden) + uploadPackage(admin, "1.1", http.StatusCreated) + setting.Packages.LimitTotalOwnerSize = limitTotalOwnerSize + + setting.Packages.LimitSizeGeneric = 0 + uploadPackage(user, "1.2", http.StatusForbidden) + uploadPackage(admin, "1.2", http.StatusCreated) + setting.Packages.LimitSizeGeneric = limitSizeGeneric +} + func TestPackageCleanup(t *testing.T) { defer tests.PrepareTestEnv(t)() From 7e40ceee9e90bd2cab0339f4301c476040d7121b Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 9 Nov 2022 15:40:26 +0800 Subject: [PATCH 006/149] Fix UI language switching bug (#21597) Related: * https://github.com/go-gitea/gitea/pull/21596#issuecomment-1291450224 There was a bug when switching language by AJAX: the irrelevant POST requests were processed by the target page's handler. Now, use GET instead of POST. The GET requests should be harmless. Co-authored-by: delvh Co-authored-by: Jason Song Co-authored-by: Lunny Xiao --- web_src/js/features/common-global.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index a3aebc0246..b00b4aea9c 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -37,7 +37,7 @@ export function initHeadNavbarContentToggle() { export function initFootLanguageMenu() { function linkLanguageAction() { const $this = $(this); - $.post($this.data('url')).always(() => { + $.get($this.data('url')).always(() => { window.location.reload(); }); } From dd7f1c0334dff5fb5eb93765dff3b951a9f6b3fc Mon Sep 17 00:00:00 2001 From: Xinyu Zhou Date: Wed, 9 Nov 2022 18:02:19 +0800 Subject: [PATCH 007/149] Quick fixes monaco-editor error: "vs.editor.nullLanguage" (#21734) fixes: https://github.com/go-gitea/gitea/issues/21733 Uncaught Error: Language id "vs.editor.nullLanguage" is not configured nor known Note that this monaco-editor worked fine on 0.33.0 and broke on 0.34.0. If upstream fixed, remove this code. Signed-off-by: Xinyu Zhou Co-authored-by: Lunny Xiao --- web_src/js/bootstrap.js | 3 --- web_src/js/features/codeeditor.js | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index b5db398545..54b7c62887 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -26,9 +26,6 @@ function processWindowErrorEvent(e) { return; // ignore such nonsense error event } - // Wait for upstream fix: https://github.com/microsoft/monaco-editor/issues/2962 - if (e.message.includes('Language id "vs.editor.nullLanguage" is not configured nor known')) return; - showGlobalErrorMessage(`JavaScript error: ${e.message} (${e.filename} @ ${e.lineno}:${e.colno}). Open browser console to see more details.`); } diff --git a/web_src/js/features/codeeditor.js b/web_src/js/features/codeeditor.js index 0366afc2c0..23a26ba2b0 100644 --- a/web_src/js/features/codeeditor.js +++ b/web_src/js/features/codeeditor.js @@ -99,6 +99,10 @@ export async function createMonaco(textarea, filename, editorOpts) { } }); + // Quick fix: https://github.com/microsoft/monaco-editor/issues/2962 + monaco.languages.register({id: 'vs.editor.nullLanguage'}); + monaco.languages.setLanguageConfiguration('vs.editor.nullLanguage', {}); + const editor = monaco.editor.create(container, { value: textarea.value, theme: 'gitea', From 5a6cba4cf43f9e5be3ca4a3ffd8bfa351c92acbd Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 10 Nov 2022 00:42:06 +0800 Subject: [PATCH 008/149] Set last login when activating account (#21731) Fix #21698. Set the last login time to the current time when activating the user successfully. Co-authored-by: Lunny Xiao --- routers/web/auth/auth.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 25d70d7c47..0f8128946c 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -783,6 +783,13 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) { return } + // Register last login + user.SetLastLogin() + if err := user_model.UpdateUserCols(ctx, user, "last_login_unix"); err != nil { + ctx.ServerError("UpdateUserCols", err) + return + } + ctx.Flash.Success(ctx.Tr("auth.account_activated")) ctx.Redirect(setting.AppSubURL + "/") } From 99688ef994af34724a7120e97d09464297a673fe Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 10 Nov 2022 01:22:31 +0000 Subject: [PATCH 009/149] Attempt clarify AppWorkPath etc. (#21656) Attempt clarify the AppWorkPath in the documentation by using different notation and adding a section to the start of the cheat sheet. Fix #21523 Signed-off-by: Andrew Thornton Signed-off-by: Andrew Thornton --- custom/conf/app.example.ini | 62 +++++++++++++---- .../doc/advanced/config-cheat-sheet.en-us.md | 68 ++++++++++++++----- docs/content/doc/help/faq.en-us.md | 30 ++++---- .../doc/installation/from-source.en-us.md | 16 ++--- modules/setting/setting.go | 4 +- 5 files changed, 126 insertions(+), 54 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index b46dfc20a9..9f41fdb080 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -7,6 +7,38 @@ ;; see https://docs.gitea.io/en-us/config-cheat-sheet/ for additional documentation. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Default Configuration (non-`app.ini` configuration) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; These values are environment-dependent but form the basis of a lot of values. They will be +;; reported as part of the default configuration when running `gitea --help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up. +;; +;; - _`AppPath`_: This is the absolute path of the running gitea binary. +;; - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy: +;; - The `--work-path` flag passed to the binary +;; - The environment variable `$GITEA_WORK_DIR` +;; - A built-in value set at build time (see building from source) +;; - Otherwise it defaults to the directory of the _`AppPath`_ +;; - If any of the above are relative paths then they are made absolute against the +;; the directory of the _`AppPath`_ +;; - _`CustomPath`_: This is the base directory for custom templates and other options. +;; It is determined by using the first set thing in the following hierarchy: +;; - The `--custom-path` flag passed to the binary +;; - The environment variable `$GITEA_CUSTOM` +;; - A built-in value set at build time (see building from source) +;; - Otherwise it defaults to _`AppWorkPath`_`/custom` +;; - If any of the above are relative paths then they are made absolute against the +;; the directory of the _`AppWorkPath`_ +;; - _`CustomConf`_: This is the path to the `app.ini` file. +;; - The `--config` flag passed to the binary +;; - A built-in value set at build time (see building from source) +;; - Otherwise it defaults to _`CustomPath`_`/conf/app.ini` +;; - If any of the above are relative paths then they are made absolute against the +;; the directory of the _`CustomPath`_ +;; +;; In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_ + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; General Settings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -26,7 +58,7 @@ RUN_MODE = ; prod ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; The protocol the server listens on. One of 'http', 'https', 'unix' or 'fcgi'. Defaults to 'http' +;; The protocol the server listens on. One of 'http', 'https', 'http+unix', 'fcgi' or 'fcgi+unix'. Defaults to 'http' ;PROTOCOL = http ;; ;; Expect PROXY protocol headers on connections @@ -51,6 +83,8 @@ RUN_MODE = ; prod ;STATIC_URL_PREFIX = ;; ;; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket. +;; If PROTOCOL is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use. +;; Relative paths will be made absolute against the _`AppWorkPath`_. ;HTTP_ADDR = 0.0.0.0 ;; ;; The port to listen on. Leave empty when using a unix socket. @@ -64,7 +98,7 @@ RUN_MODE = ; prod ;PORT_TO_REDIRECT = 80 ;; ;; expect PROXY protocol header on connections to https redirector. -;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL) +;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s ;; Minimum and maximum supported TLS versions ;SSL_MIN_VERSION=TLSv1.2 ;SSL_MAX_VERSION= @@ -91,7 +125,7 @@ RUN_MODE = ; prod ;LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/ ;; ;; When making local connections pass the PROXY protocol header. -;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL) +;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s ;; ;; Disable SSH feature when not available ;DISABLE_SSH = false @@ -145,7 +179,7 @@ RUN_MODE = ; prod ;; ;; For the built-in SSH server, choose the keypair to offer as the host key ;; The private key should be at SSH_SERVER_HOST_KEY and the public SSH_SERVER_HOST_KEY.pub -;; relative paths are made absolute relative to the APP_DATA_PATH +;; relative paths are made absolute relative to the %(APP_DATA_PATH)s ;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa ;; ;; Directory to create temporary files in when testing public keys using ssh-keygen, @@ -241,10 +275,10 @@ RUN_MODE = ; prod ;; ;; Root directory containing templates and static files. ;; default is the path where Gitea is executed -;STATIC_ROOT_PATH = +;STATIC_ROOT_PATH = ; Will default to the built-in value _`StaticRootPath`_ ;; ;; Default path for App data -;APP_DATA_PATH = data +;APP_DATA_PATH = data ; relative paths will be made absolute with _`AppWorkPath`_ ;; ;; Enable gzip compression for runtime-generated content, static resources excluded ;ENABLE_GZIP = false @@ -255,7 +289,7 @@ RUN_MODE = ; prod ;ENABLE_PPROF = false ;; ;; PPROF_DATA_PATH, use an absolute path when you start gitea as service -;PPROF_DATA_PATH = data/tmp/pprof +;PPROF_DATA_PATH = data/tmp/pprof ; Path is relative to _`AppWorkPath`_ ;; ;; Landing page, can be "home", "explore", "organizations", "login", or any URL such as "/org/repo" or even "https://anotherwebsite.com" ;; The "login" choice is not a security measure but just a UI flow change, use REQUIRE_SIGNIN_VIEW to force users to log in. @@ -633,7 +667,7 @@ ROUTER = console ;PATH = ;; ;; The HOME directory for Git -;HOME_PATH = %(APP_DATA_PATH)/home +;HOME_PATH = %(APP_DATA_PATH)s/home ;; ;; Disables highlight of added and removed changes ;DISABLE_DIFF_HIGHLIGHT = false @@ -838,8 +872,8 @@ ROUTER = console ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[repository] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)/gitea-repositories. -;; A relative path is interpreted as %(GITEA_WORK_DIR)/%(ROOT) +;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)s/gitea-repositories. +;; A relative path is interpreted as _`AppWorkPath`_/%(ROOT)s ;ROOT = ;; ;; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. @@ -1296,7 +1330,7 @@ ROUTER = console ;ISSUE_INDEXER_TYPE = bleve ;; ;; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve -;ISSUE_INDEXER_PATH = indexers/issues.bleve +;ISSUE_INDEXER_PATH = indexers/issues.bleve ; Relative paths will be made absolute against _`AppWorkPath`_. ;; ;; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch ;ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200 @@ -1314,7 +1348,7 @@ ROUTER = console ;; When ISSUE_INDEXER_QUEUE_TYPE is levelqueue, this will be the path where the queue will be saved. ;; This can be overridden by `ISSUE_INDEXER_QUEUE_CONN_STR`. ;; default is queues/common -;ISSUE_INDEXER_QUEUE_DIR = queues/common; **DEPRECATED** use settings in `[queue.issue_indexer]`. +;ISSUE_INDEXER_QUEUE_DIR = queues/common; **DEPRECATED** use settings in `[queue.issue_indexer]`. Relative paths will be made absolute against `%(APP_DATA_PATH)s`. ;; ;; When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string. ;; When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this is a directory or additional options of @@ -1370,7 +1404,7 @@ ROUTER = console ;TYPE = persistable-channel ;; ;; data-dir for storing persistable queues and level queues, individual queues will default to `queues/common` meaning the queue is shared. -;DATADIR = queues/ +;DATADIR = queues/ ; Relative paths will be made absolute against `%(APP_DATA_PATH)s`. ;; ;; Default queue length before a channel queue will block ;LENGTH = 20 @@ -1672,7 +1706,7 @@ ROUTER = console ;; file: session file path, e.g. `data/sessions` ;; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180 ;; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table` -;PROVIDER_CONFIG = data/sessions +;PROVIDER_CONFIG = data/sessions ; Relative paths will be made absolute against _`AppWorkPath`_. ;; ;; Session cookie name ;COOKIE_NAME = i_like_gitea diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 28bcaf29af..b0060e9afa 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -27,23 +27,56 @@ accurately recorded in [app.example.ini](https://github.com/go-gitea/gitea/blob/ (s/main/\). Any string in the format `%(X)s` is a feature powered by [ini](https://github.com/go-ini/ini/#recursive-values), for reading values recursively. +In the default values below, a value in the form `$XYZ` refers to an environment variable. (However, see `environment-to-ini`.) Values in the form _`XxYyZz`_ refer to values listed as part of the default configuration. These notation forms will not work in your own `app.ini` file and are only listed here as documentation. + Values containing `#` or `;` must be quoted using `` ` `` or `"""`. **Note:** A full restart is required for Gitea configuration changes to take effect. {{< toc >}} +## Default Configuration (non-`app.ini` configuration) + +These values are environment-dependent but form the basis of a lot of values. They will be +reported as part of the default configuration when running `gitea --help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up. + +- _`AppPath`_: This is the absolute path of the running gitea binary. +- _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy: + - The `--work-path` flag passed to the binary + - The environment variable `$GITEA_WORK_DIR` + - A built-in value set at build time (see building from source) + - Otherwise it defaults to the directory of the _`AppPath`_ + - If any of the above are relative paths then they are made absolute against the +the directory of the _`AppPath`_ +- _`CustomPath`_: This is the base directory for custom templates and other options. +It is determined by using the first set thing in the following hierarchy: + - The `--custom-path` flag passed to the binary + - The environment variable `$GITEA_CUSTOM` + - A built-in value set at build time (see building from source) + - Otherwise it defaults to _`AppWorkPath`_`/custom` + - If any of the above are relative paths then they are made absolute against the +the directory of the _`AppWorkPath`_ +- _`CustomConf`_: This is the path to the `app.ini` file. + - The `--config` flag passed to the binary + - A built-in value set at build time (see building from source) + - Otherwise it defaults to _`CustomPath`_`/conf/app.ini` + - If any of the above are relative paths then they are made absolute against the +the directory of the _`CustomPath`_ + +In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_ + ## Overall (`DEFAULT`) - `APP_NAME`: **Gitea: Git with a cup of tea**: Application name, used in the page title. -- `RUN_USER`: **git**: The user Gitea will run as. This should be a dedicated system - (non-user) account. Setting this incorrectly will cause Gitea to not start. +- `RUN_USER`: **_current OS username_/`$USER`/`$USERNAME` e.g. git**: The user Gitea will run as. + This should be a dedicated system (non-user) account. Setting this incorrectly will cause Gitea + to not start. - `RUN_MODE`: **prod**: Application run mode, affects performance and debugging. Either "dev", "prod" or "test". ## Repository (`repository`) -- `ROOT`: **%(APP_DATA_PATH)/gitea-repositories**: Root path for storing all repository data. - A relative path is interpreted as **%(GITEA_WORK_DIR)/%(ROOT)**. +- `ROOT`: **%(APP_DATA_PATH)s/gitea-repositories**: Root path for storing all repository data. + A relative path is interpreted as **_`AppWorkPath`_/%(ROOT)s**. - `SCRIPT_TYPE`: **bash**: The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. - `DETECTED_CHARSETS_ORDER`: **UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE, ISO-8859, windows-1252, ISO-8859, windows-1250, ISO-8859, ISO-8859, ISO-8859, windows-1253, ISO-8859, windows-1255, ISO-8859, windows-1251, windows-1256, KOI8-R, ISO-8859, windows-1254, Shift_JIS, GB18030, EUC-JP, EUC-KR, Big5, ISO-2022, ISO-2022, ISO-2022, IBM424_rtl, IBM424_ltr, IBM420_rtl, IBM420_ltr**: Tie-break order of detected charsets - if the detected charsets have equal confidence, charsets earlier in the list will be chosen in preference to those later. Adding `defaults` will place the unnamed charsets at that point. @@ -240,6 +273,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a ## Server (`server`) +- `APP_DATA_PATH`: **_`AppWorkPath`_/data**: This is the default root path for storing data. - `PROTOCOL`: **http**: \[http, https, fcgi, http+unix, fcgi+unix\] - `USE_PROXY_PROTOCOL`: **false**: Expect PROXY protocol headers on connections - `PROXY_PROTOCOL_TLS_BRIDGING`: **false**: When protocol is https, expect PROXY protocol headers after TLS negotiation. @@ -259,7 +293,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `HTTP_ADDR`: **0.0.0.0**: HTTP listen address. - If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings. - - If `PROTOCOL` is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use. Relative paths will be made absolute against the AppWorkPath. + - If `PROTOCOL` is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use. Relative paths will be made absolute against the _`AppWorkPath`_. - `HTTP_PORT`: **3000**: HTTP listen port. - If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings. @@ -269,7 +303,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a most cases you do not need to change the default value. Alter it only if your SSH server node is not the same as HTTP node. Do not set this variable if `PROTOCOL` is set to `http+unix`. -- `LOCAL_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)**: When making local connections pass the PROXY protocol header. +- `LOCAL_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)s**: When making local connections pass the PROXY protocol header. This should be set to false if the local connection will go through the proxy. - `PER_WRITE_TIMEOUT`: **30s**: Timeout for any write to the connection. (Set to -1 to disable all timeouts.) @@ -279,7 +313,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `START_SSH_SERVER`: **false**: When enabled, use the built-in SSH server. - `SSH_SERVER_USE_PROXY_PROTOCOL`: **false**: Expect PROXY protocol header on connections to the built-in SSH Server. - `BUILTIN_SSH_SERVER_USER`: **%(RUN_USER)s**: Username to use for the built-in SSH Server. -- `SSH_USER`: **%(BUILTIN_SSH_SERVER_USER)**: SSH username displayed in clone URLs. This is only for people who configure the SSH server themselves; in most cases, you want to leave this blank and modify the `BUILTIN_SSH_SERVER_USER`. +- `SSH_USER`: **%(BUILTIN_SSH_SERVER_USER)s**: SSH username displayed in clone URLs. This is only for people who configure the SSH server themselves; in most cases, you want to leave this blank and modify the `BUILTIN_SSH_SERVER_USER`. - `SSH_DOMAIN`: **%(DOMAIN)s**: Domain name of this server, used for displayed clone URL. - `SSH_PORT`: **22**: SSH port displayed in clone URL. - `SSH_LISTEN_HOST`: **0.0.0.0**: Listen address for the built-in SSH server. @@ -308,22 +342,22 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures. - `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`. - `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`. -- `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path. -- `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data. +- `STATIC_ROOT_PATH`: **_`StaticRootPath`_**: Upper level of template and static files path. +- `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data. Relative paths will be made absolute against _`AppWorkPath`_. - `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. Note that this cache is disabled when `RUN_MODE` is "dev". - `ENABLE_GZIP`: **false**: Enable gzip compression for runtime-generated content, static resources excluded. - `ENABLE_PPROF`: **false**: Application profiling (memory and cpu). For "web" command it listens on `localhost:6060`. For "serv" command it dumps to disk at `PPROF_DATA_PATH` as `(cpuprofile|memprofile)__` -- `PPROF_DATA_PATH`: **data/tmp/pprof**: `PPROF_DATA_PATH`, use an absolute path when you start Gitea as service +- `PPROF_DATA_PATH`: **_`AppWorkPath`_/data/tmp/pprof**: `PPROF_DATA_PATH`, use an absolute path when you start Gitea as service - `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login, **custom**\]. Where custom would instead be any URL such as "/org/repo" or even `https://anotherwebsite.com` - `LFS_START_SERVER`: **false**: Enables Git LFS support. -- `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)/lfs**: Default LFS content path. (if it is on local storage.) **DEPRECATED** use settings in `[lfs]`. +- `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)s/lfs**: Default LFS content path. (if it is on local storage.) **DEPRECATED** use settings in `[lfs]`. - `LFS_JWT_SECRET`: **\**: LFS authentication secret, change this a unique string. - `LFS_HTTP_AUTH_EXPIRY`: **20m**: LFS authentication validity period in time.Duration, pushes taking longer than this may fail. - `LFS_MAX_FILE_SIZE`: **0**: Maximum allowed LFS file size in bytes (Set to 0 for no limit). - `LFS_LOCKS_PAGING_NUM`: **50**: Maximum number of LFS Locks returned per page. - `REDIRECT_OTHER_PORT`: **false**: If true and `PROTOCOL` is https, allows redirecting http requests on `PORT_TO_REDIRECT` to the https port Gitea listens on. -- `REDIRECTOR_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)**: expect PROXY protocol header on connections to https redirector. +- `REDIRECTOR_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)s**: expect PROXY protocol header on connections to https redirector. - `PORT_TO_REDIRECT`: **80**: Port for the http redirection service to listen on. Used when `REDIRECT_OTHER_PORT` is true. - `SSL_MIN_VERSION`: **TLSv1.2**: Set the minimum version of ssl support. - `SSL_MAX_VERSION`: **\**: Set the maximum version of ssl support. @@ -413,10 +447,10 @@ relation to port exhaustion. - `ISSUE_INDEXER_TYPE`: **bleve**: Issue indexer type, currently supported: `bleve`, `db` or `elasticsearch`. - `ISSUE_INDEXER_CONN_STR`: ****: Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch. i.e. http://elastic:changeme@localhost:9200 - `ISSUE_INDEXER_NAME`: **gitea_issues**: Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch -- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search; available when ISSUE_INDEXER_TYPE is bleve and elasticsearch. +- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search; available when ISSUE_INDEXER_TYPE is bleve and elasticsearch. Relative paths will be made absolute against _`AppWorkPath`_. - The next 4 configuration values are deprecated and should be set in `queue.issue_indexer` however are kept for backwards compatibility: - `ISSUE_INDEXER_QUEUE_TYPE`: **levelqueue**: Issue indexer queue, currently supports:`channel`, `levelqueue`, `redis`. **DEPRECATED** use settings in `[queue.issue_indexer]`. -- `ISSUE_INDEXER_QUEUE_DIR`: **queues/common**: When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this will be the path where the queue will be saved. **DEPRECATED** use settings in `[queue.issue_indexer]`. +- `ISSUE_INDEXER_QUEUE_DIR`: **queues/common**: When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this will be the path where the queue will be saved. **DEPRECATED** use settings in `[queue.issue_indexer]`. Relative paths will be made absolute against `%(APP_DATA_PATH)s`. - `ISSUE_INDEXER_QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string. When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this is a directory or additional options of the form `leveldb://path/to/db?option=value&....`, and overrides `ISSUE_INDEXER_QUEUE_DIR`. **DEPRECATED** use settings in `[queue.issue_indexer]`. - `ISSUE_INDEXER_QUEUE_BATCH_NUMBER`: **20**: Batch queue number. **DEPRECATED** use settings in `[queue.issue_indexer]`. @@ -438,7 +472,7 @@ relation to port exhaustion. Configuration at `[queue]` will set defaults for queues with overrides for individual queues at `[queue.*]`. (However see below.) - `TYPE`: **persistable-channel**: General queue type, currently support: `persistable-channel` (uses a LevelDB internally), `channel`, `level`, `redis`, `dummy` -- `DATADIR`: **queues/**: Base DataDir for storing persistent and level queues. `DATADIR` for individual queues can be set in `queue.name` sections but will default to `DATADIR/`**`common`**. (Previously each queue would default to `DATADIR/`**`name`**.) +- `DATADIR`: **queues/**: Base DataDir for storing persistent and level queues. `DATADIR` for individual queues can be set in `queue.name` sections but will default to `DATADIR/`**`common`**. (Previously each queue would default to `DATADIR/`**`name`**.) Relative paths will be made absolute against `%(APP_DATA_PATH)s`. - `LENGTH`: **20**: Maximal queue size before channel queues block - `BATCH_LENGTH`: **20**: Batch data before passing to the handler - `CONN_STR`: **redis://127.0.0.1:6379/0**: Connection string for the redis queue type. Options can be set using query params. Similarly LevelDB options can also be set using: **leveldb://relative/path?option=value** or **leveldb:///absolute/path?option=value**, and will override `DATADIR` @@ -722,7 +756,7 @@ and ## Session (`session`) - `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, db, mysql, couchbase, memcache, postgres\]. Setting `db` will reuse the configuration in `[database]` -- `PROVIDER_CONFIG`: **data/sessions**: For file, the root path; for db, empty (database config will be used); for others, the connection string. +- `PROVIDER_CONFIG`: **data/sessions**: For file, the root path; for db, empty (database config will be used); for others, the connection string. Relative paths will be made absolute against _`AppWorkPath`_. - `COOKIE_SECURE`: **false**: Enable this to force using HTTPS for all session access. - `COOKIE_NAME`: **i\_like\_gitea**: The name of the cookie used for the session ID. - `GC_INTERVAL_TIME`: **86400**: GC interval in seconds. @@ -980,7 +1014,7 @@ Default templates for project boards: ## Git (`git`) - `PATH`: **""**: The path of Git executable. If empty, Gitea searches through the PATH environment. -- `HOME_PATH`: **%(APP_DATA_PATH)/home**: The HOME directory for Git. +- `HOME_PATH`: **%(APP_DATA_PATH)s/home**: The HOME directory for Git. This directory will be used to contain the `.gitconfig` and possible `.gnupg` directories that Gitea's git calls will use. If you can confirm Gitea is the only application running in this environment, you can set it to the normal home directory for Gitea user. - `DISABLE_DIFF_HIGHLIGHT`: **false**: Disables highlight of added and removed changes. - `MAX_GIT_DIFF_LINES`: **1000**: Max number of lines allowed of a single file in diff view. diff --git a/docs/content/doc/help/faq.en-us.md b/docs/content/doc/help/faq.en-us.md index a59abe8335..a92186334f 100644 --- a/docs/content/doc/help/faq.en-us.md +++ b/docs/content/doc/help/faq.en-us.md @@ -58,29 +58,33 @@ https://github.com/loganinak/MigrateGitlabToGogs ## Where does Gitea store what file -- WorkPath - - Environment variable `GITEA_WORK_DIR` - - Else `--work-path` flag +- _`AppWorkPath`_ + - The `--work-path` flag + - Else Environment variable `GITEA_WORK_DIR` + - Else a built-in value set at build time - Else the directory that contains the Gitea binary -- AppDataPath (default for database, indexers, etc.) +- `%(APP_DATA_PATH)` (default for database, indexers, etc.) - `APP_DATA_PATH` from `app.ini` - - Else `%(WorkPath)/data` -- CustomPath (custom templates) - - Environment variable `GITEA_CUSTOM` - - Else `%(WorkPath)/custom` + - Else _`AppWorkPath`_`/data` +- _`CustomPath`_ (custom templates) + - The `--custom-path` flag + - Else Environment variable `GITEA_CUSTOM` + - Else a built-in value set at build time + - Else _`AppWorkPath`_`/custom` - HomeDir - Unix: Environment variable `HOME` - Windows: Environment variable `USERPROFILE`, else environment variables `HOMEDRIVE`+`HOMEPATH` - RepoRootPath - `ROOT` in the \[repository] section of `app.ini` if absolute - - Else `%(AppWorkPath)/ROOT` if `ROOT` in the \[repository] section of `app.ini` if relative - - Default `%(AppDataPath)/gitea-repositories` + - Else _`AppWorkPath`_`/ROOT` if `ROOT` in the \[repository] section of `app.ini` if relative + - Default `%(APP_DATA_PATH)/gitea-repositories` - INI (config file) - - `-c` flag - - Else `%(CustomPath)/conf/app.ini` + - `--config` flag + - A possible built-in value set a build time + - Else _`CustomPath`_`/conf/app.ini` - SQLite Database - `PATH` in `database` section of `app.ini` - - Else `%(AppDataPath)/gitea.db` + - Else `%(APP_DATA_PATH)/gitea.db` ## Not seeing a clone URL or the clone URL being incorrect diff --git a/docs/content/doc/installation/from-source.en-us.md b/docs/content/doc/installation/from-source.en-us.md index 0be5673be4..a6493598be 100644 --- a/docs/content/doc/installation/from-source.en-us.md +++ b/docs/content/doc/installation/from-source.en-us.md @@ -144,11 +144,11 @@ launched manually from command line, it can be killed by pressing `Ctrl + C`. ## Changing default paths -Gitea will search for a number of things from the `CustomPath`. By default this is +Gitea will search for a number of things from the _`CustomPath`_. By default this is the `custom/` directory in the current working directory when running Gitea. It will also -look for its configuration file `CustomConf` in `$CustomPath/conf/app.ini`, and will use the -current working directory as the relative base path `AppWorkPath` for a number configurable -values. Finally the static files will be served from `StaticRootPath` which defaults to the `AppWorkPath`. +look for its configuration file _`CustomConf`_ in _`CustomPath`_/conf/app.ini`, and will use the +current working directory as the relative base path _`AppWorkPath`_ for a number configurable +values. Finally the static files will be served from _`StaticRootPath`_ which defaults to the _`AppWorkPath`_. These values, although useful when developing, may conflict with downstream users preferences. @@ -156,10 +156,10 @@ One option is to use a script file to shadow the `gitea` binary and create an ap environment before running Gitea. However, when building you can change these defaults using the `LDFLAGS` environment variable for `make`. The appropriate settings are as follows -- To set the `CustomPath` use `LDFLAGS="-X \"code.gitea.io/gitea/modules/setting.CustomPath=custom-path\""` -- For `CustomConf` you should use `-X \"code.gitea.io/gitea/modules/setting.CustomConf=conf.ini\"` -- For `AppWorkPath` you should use `-X \"code.gitea.io/gitea/modules/setting.AppWorkPath=working-path\"` -- For `StaticRootPath` you should use `-X \"code.gitea.io/gitea/modules/setting.StaticRootPath=static-root-path\"` +- To set the _`CustomPath`_ use `LDFLAGS="-X \"code.gitea.io/gitea/modules/setting.CustomPath=custom-path\""` +- For _`CustomConf`_ you should use `-X \"code.gitea.io/gitea/modules/setting.CustomConf=conf.ini\"` +- For _`AppWorkPath`_ you should use `-X \"code.gitea.io/gitea/modules/setting.AppWorkPath=working-path\"` +- For _`StaticRootPath`_ you should use `-X \"code.gitea.io/gitea/modules/setting.StaticRootPath=static-root-path\"` - To change the default PID file location use `-X \"code.gitea.io/gitea/modules/setting.PIDFile=/run/gitea.pid\"` Add as many of the strings with their preceding `-X` to the `LDFLAGS` variable and run `make build` diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 2e5bb17b6a..12558da494 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -88,10 +88,10 @@ var ( // AppWorkPath is used as the base path for several other paths. AppWorkPath string // AppDataPath is the default path for storing data. - // It maps to ini:"APP_DATA_PATH" and defaults to AppWorkPath + "/data" + // It maps to ini:"APP_DATA_PATH" in [server] and defaults to AppWorkPath + "/data" AppDataPath string // LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix - // It maps to ini:"LOCAL_ROOT_URL" + // It maps to ini:"LOCAL_ROOT_URL" in [server] LocalURL string // AssetVersion holds a opaque value that is used for cache-busting assets AssetVersion string From ce5aafbc698de72d8acf03851dc5db057b3cc01f Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 10 Nov 2022 11:04:09 +0800 Subject: [PATCH 010/149] Add .dockerignore (#21753) There's a lot of work that has been done on `.dockerignore`: - #329 - #2927 - #8338 And finally, it has been deleted by #2927. This is a copy of the `.gitignore`. Creating a soft link is more elegant, but it may cause trouble to the Windows users. --- .dockerignore | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..1ce2a87611 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,114 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# IntelliJ +.idea +# Goland's output filename can not be set manually +/go_build_* + +# MS VSCode +.vscode +__debug_bin + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +*coverage.out +coverage.all +cpu.out + +/modules/migration/bindata.go +/modules/migration/bindata.go.hash +/modules/options/bindata.go +/modules/options/bindata.go.hash +/modules/public/bindata.go +/modules/public/bindata.go.hash +/modules/templates/bindata.go +/modules/templates/bindata.go.hash + +*.db +*.log + +/gitea +/gitea-vet +/debug +/integrations.test + +/bin +/dist +/custom/* +!/custom/conf +/custom/conf/* +!/custom/conf/app.example.ini +/data +/indexers +/log +/public/img/avatar +/tests/integration/gitea-integration-* +/tests/integration/indexers-* +/tests/e2e/gitea-e2e-* +/tests/e2e/indexers-* +/tests/e2e/reports +/tests/e2e/test-artifacts +/tests/e2e/test-snapshots +/tests/*.ini +/node_modules +/yarn.lock +/yarn-error.log +/npm-debug.log* +/public/js +/public/serviceworker.js +/public/css +/public/fonts +/public/img/webpack +/vendor +/web_src/fomantic/node_modules +/web_src/fomantic/build/* +!/web_src/fomantic/build/semantic.js +!/web_src/fomantic/build/semantic.css +!/web_src/fomantic/build/themes +/web_src/fomantic/build/themes/* +!/web_src/fomantic/build/themes/default +/web_src/fomantic/build/themes/default/assets/* +!/web_src/fomantic/build/themes/default/assets/fonts +/web_src/fomantic/build/themes/default/assets/fonts/* +!/web_src/fomantic/build/themes/default/assets/fonts/icons.woff2 +!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2 +/VERSION +/.air +/.go-licenses + +# Snapcraft +snap/.snapcraft/ +parts/ +stage/ +prime/ +*.snap +*.snap-build +*_source.tar.bz2 +.DS_Store + +# Make evidence files +/.make_evidence + +# Manpage +/man From 385462d36c75e809ee082d3432941f938cbdffc9 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 10 Nov 2022 14:43:53 +0800 Subject: [PATCH 011/149] Fix dashboard ignored system setting cache (#21621) This is a performance regression from #18058 Signed-off-by: Andrew Thornton Co-authored-by: Andrew Thornton --- models/avatars/avatar.go | 11 ++- models/system/setting.go | 40 ++++++-- models/system/setting_key.go | 5 + models/user/avatar.go | 6 +- models/user/setting.go | 36 +++++++- models/user/setting_test.go | 2 +- modules/activitypub/user_settings.go | 2 +- modules/cache/cache.go | 131 +++++++++++++++++---------- modules/system/setting.go | 46 ---------- modules/system/user_setting.go | 34 ------- modules/templates/helper.go | 3 +- routers/web/admin/config.go | 7 +- 12 files changed, 172 insertions(+), 151 deletions(-) delete mode 100644 modules/system/setting.go delete mode 100644 modules/system/user_setting.go diff --git a/models/avatars/avatar.go b/models/avatars/avatar.go index 418e9b9ccc..ec3b611312 100644 --- a/models/avatars/avatar.go +++ b/models/avatars/avatar.go @@ -150,10 +150,11 @@ func generateEmailAvatarLink(email string, size int, final bool) string { return DefaultAvatarLink() } - enableFederatedAvatar, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar) + enableFederatedAvatarSetting, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar) + enableFederatedAvatar := enableFederatedAvatarSetting.GetValueBool() var err error - if enableFederatedAvatar != nil && enableFederatedAvatar.GetValueBool() && system_model.LibravatarService != nil { + if enableFederatedAvatar && system_model.LibravatarService != nil { emailHash := saveEmailHash(email) if final { // for final link, we can spend more time on slow external query @@ -171,8 +172,10 @@ func generateEmailAvatarLink(email string, size int, final bool) string { return urlStr } - disableGravatar, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar) - if disableGravatar != nil && !disableGravatar.GetValueBool() { + disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar) + + disableGravatar := disableGravatarSetting.GetValueBool() + if !disableGravatar { // copy GravatarSourceURL, because we will modify its Path. avatarURLCopy := *system_model.GravatarSourceURL avatarURLCopy.Path = path.Join(avatarURLCopy.Path, HashEmail(email)) diff --git a/models/system/setting.go b/models/system/setting.go index 9711d38f3b..b4011b1b3e 100644 --- a/models/system/setting.go +++ b/models/system/setting.go @@ -12,6 +12,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" @@ -35,6 +36,10 @@ func (s *Setting) TableName() string { } func (s *Setting) GetValueBool() bool { + if s == nil { + return false + } + b, _ := strconv.ParseBool(s.SettingValue) return b } @@ -75,8 +80,8 @@ func IsErrDataExpired(err error) bool { return ok } -// GetSetting returns specific setting -func GetSetting(key string) (*Setting, error) { +// GetSettingNoCache returns specific setting without using the cache +func GetSettingNoCache(key string) (*Setting, error) { v, err := GetSettings([]string{key}) if err != nil { return nil, err @@ -87,6 +92,24 @@ func GetSetting(key string) (*Setting, error) { return v[key], nil } +// GetSetting returns the setting value via the key +func GetSetting(key string) (*Setting, error) { + return cache.Get(genSettingCacheKey(key), func() (*Setting, error) { + res, err := GetSettingNoCache(key) + if err != nil { + return nil, err + } + return res, nil + }) +} + +// GetSettingBool return bool value of setting, +// none existing keys and errors are ignored and result in false +func GetSettingBool(key string) bool { + s, _ := GetSetting(key) + return s.GetValueBool() +} + // GetSettings returns specific settings func GetSettings(keys []string) (map[string]*Setting, error) { for i := 0; i < len(keys); i++ { @@ -139,12 +162,13 @@ func GetAllSettings() (AllSettings, error) { // DeleteSetting deletes a specific setting for a user func DeleteSetting(setting *Setting) error { + cache.Remove(genSettingCacheKey(setting.SettingKey)) _, err := db.GetEngine(db.DefaultContext).Delete(setting) return err } func SetSettingNoVersion(key, value string) error { - s, err := GetSetting(key) + s, err := GetSettingNoCache(key) if IsErrSettingIsNotExist(err) { return SetSetting(&Setting{ SettingKey: key, @@ -160,9 +184,13 @@ func SetSettingNoVersion(key, value string) error { // SetSetting updates a users' setting for a specific key func SetSetting(setting *Setting) error { - if err := upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version); err != nil { + _, err := cache.Set(genSettingCacheKey(setting.SettingKey), func() (*Setting, error) { + return setting, upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version) + }) + if err != nil { return err } + setting.Version++ return nil } @@ -213,7 +241,7 @@ var ( func Init() error { var disableGravatar bool - disableGravatarSetting, err := GetSetting(KeyPictureDisableGravatar) + disableGravatarSetting, err := GetSettingNoCache(KeyPictureDisableGravatar) if IsErrSettingIsNotExist(err) { disableGravatar = setting.GetDefaultDisableGravatar() disableGravatarSetting = &Setting{SettingValue: strconv.FormatBool(disableGravatar)} @@ -224,7 +252,7 @@ func Init() error { } var enableFederatedAvatar bool - enableFederatedAvatarSetting, err := GetSetting(KeyPictureEnableFederatedAvatar) + enableFederatedAvatarSetting, err := GetSettingNoCache(KeyPictureEnableFederatedAvatar) if IsErrSettingIsNotExist(err) { enableFederatedAvatar = setting.GetDefaultEnableFederatedAvatar(disableGravatar) enableFederatedAvatarSetting = &Setting{SettingValue: strconv.FormatBool(enableFederatedAvatar)} diff --git a/models/system/setting_key.go b/models/system/setting_key.go index 5a6ea6ed72..14105b89d0 100644 --- a/models/system/setting_key.go +++ b/models/system/setting_key.go @@ -9,3 +9,8 @@ const ( KeyPictureDisableGravatar = "picture.disable_gravatar" KeyPictureEnableFederatedAvatar = "picture.enable_federated_avatar" ) + +// genSettingCacheKey returns the cache key for some configuration +func genSettingCacheKey(key string) string { + return "system.setting." + key +} diff --git a/models/user/avatar.go b/models/user/avatar.go index f73ac56c5e..102206f3a2 100644 --- a/models/user/avatar.go +++ b/models/user/avatar.go @@ -68,11 +68,9 @@ func (u *User) AvatarLinkWithSize(size int) string { useLocalAvatar := false autoGenerateAvatar := false - var disableGravatar bool disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar) - if disableGravatarSetting != nil { - disableGravatar = disableGravatarSetting.GetValueBool() - } + + disableGravatar := disableGravatarSetting.GetValueBool() switch { case u.UseCustomAvatar: diff --git a/models/user/setting.go b/models/user/setting.go index 5fe7c2ec23..896f3c8da1 100644 --- a/models/user/setting.go +++ b/models/user/setting.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/cache" "xorm.io/builder" ) @@ -47,9 +48,25 @@ func IsErrUserSettingIsNotExist(err error) bool { return ok } -// GetSetting returns specific setting +// genSettingCacheKey returns the cache key for some configuration +func genSettingCacheKey(userID int64, key string) string { + return fmt.Sprintf("user_%d.setting.%s", userID, key) +} + +// GetSetting returns the setting value via the key func GetSetting(uid int64, key string) (*Setting, error) { - v, err := GetUserSettings(uid, []string{key}) + return cache.Get(genSettingCacheKey(uid, key), func() (*Setting, error) { + res, err := GetSettingNoCache(uid, key) + if err != nil { + return nil, err + } + return res, nil + }) +} + +// GetSettingNoCache returns specific setting without using the cache +func GetSettingNoCache(uid int64, key string) (*Setting, error) { + v, err := GetSettings(uid, []string{key}) if err != nil { return nil, err } @@ -59,8 +76,8 @@ func GetSetting(uid int64, key string) (*Setting, error) { return v[key], nil } -// GetUserSettings returns specific settings from user -func GetUserSettings(uid int64, keys []string) (map[string]*Setting, error) { +// GetSettings returns specific settings from user +func GetSettings(uid int64, keys []string) (map[string]*Setting, error) { settings := make([]*Setting, 0, len(keys)) if err := db.GetEngine(db.DefaultContext). Where("user_id=?", uid). @@ -105,6 +122,7 @@ func GetUserSetting(userID int64, key string, def ...string) (string, error) { if err := validateUserSettingKey(key); err != nil { return "", err } + setting := &Setting{UserID: userID, SettingKey: key} has, err := db.GetEngine(db.DefaultContext).Get(setting) if err != nil { @@ -124,7 +142,10 @@ func DeleteUserSetting(userID int64, key string) error { if err := validateUserSettingKey(key); err != nil { return err } + + cache.Remove(genSettingCacheKey(userID, key)) _, err := db.GetEngine(db.DefaultContext).Delete(&Setting{UserID: userID, SettingKey: key}) + return err } @@ -133,7 +154,12 @@ func SetUserSetting(userID int64, key, value string) error { if err := validateUserSettingKey(key); err != nil { return err } - return upsertUserSettingValue(userID, key, value) + + _, err := cache.Set(genSettingCacheKey(userID, key), func() (string, error) { + return value, upsertUserSettingValue(userID, key, value) + }) + + return err } func upsertUserSettingValue(userID int64, key, value string) error { diff --git a/models/user/setting_test.go b/models/user/setting_test.go index f0083038df..5a772a8ce7 100644 --- a/models/user/setting_test.go +++ b/models/user/setting_test.go @@ -27,7 +27,7 @@ func TestSettings(t *testing.T) { assert.NoError(t, err) // get specific setting - settings, err := user_model.GetUserSettings(99, []string{keyName}) + settings, err := user_model.GetSettings(99, []string{keyName}) assert.NoError(t, err) assert.Len(t, settings, 1) assert.EqualValues(t, newSetting.SettingValue, settings[keyName].SettingValue) diff --git a/modules/activitypub/user_settings.go b/modules/activitypub/user_settings.go index fc9775b0f0..d192b9cdb2 100644 --- a/modules/activitypub/user_settings.go +++ b/modules/activitypub/user_settings.go @@ -11,7 +11,7 @@ import ( // GetKeyPair function returns a user's private and public keys func GetKeyPair(user *user_model.User) (pub, priv string, err error) { var settings map[string]*user_model.Setting - settings, err = user_model.GetUserSettings(user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem}) + settings, err = user_model.GetSettings(user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem}) if err != nil { return } else if len(settings) == 0 { diff --git a/modules/cache/cache.go b/modules/cache/cache.go index 21d0cd0a04..d98b0a0cec 100644 --- a/modules/cache/cache.go +++ b/modules/cache/cache.go @@ -46,32 +46,64 @@ func GetCache() mc.Cache { return conn } +// Get returns the key value from cache with callback when no key exists in cache +func Get[V interface{}](key string, getFunc func() (V, error)) (V, error) { + if conn == nil || setting.CacheService.TTL == 0 { + return getFunc() + } + + cached := conn.Get(key) + if value, ok := cached.(V); ok { + return value, nil + } + + value, err := getFunc() + if err != nil { + return value, err + } + + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) +} + +// Set updates and returns the key value in the cache with callback. The old value is only removed if the updateFunc() is successful +func Set[V interface{}](key string, valueFunc func() (V, error)) (V, error) { + if conn == nil || setting.CacheService.TTL == 0 { + return valueFunc() + } + + value, err := valueFunc() + if err != nil { + return value, err + } + + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) +} + // GetString returns the key value from cache with callback when no key exists in cache func GetString(key string, getFunc func() (string, error)) (string, error) { if conn == nil || setting.CacheService.TTL == 0 { return getFunc() } - if !conn.IsExist(key) { - var ( - value string - err error - ) - if value, err = getFunc(); err != nil { + + cached := conn.Get(key) + + if cached == nil { + value, err := getFunc() + if err != nil { return value, err } - err = conn.Put(key, value, setting.CacheService.TTLSeconds()) - if err != nil { - return "", err - } + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) } - value := conn.Get(key) - if v, ok := value.(string); ok { - return v, nil + + if value, ok := cached.(string); ok { + return value, nil } - if v, ok := value.(fmt.Stringer); ok { - return v.String(), nil + + if stringer, ok := cached.(fmt.Stringer); ok { + return stringer.String(), nil } - return fmt.Sprintf("%s", conn.Get(key)), nil + + return fmt.Sprintf("%s", cached), nil } // GetInt returns key value from cache with callback when no key exists in cache @@ -79,30 +111,33 @@ func GetInt(key string, getFunc func() (int, error)) (int, error) { if conn == nil || setting.CacheService.TTL == 0 { return getFunc() } - if !conn.IsExist(key) { - var ( - value int - err error - ) - if value, err = getFunc(); err != nil { + + cached := conn.Get(key) + + if cached == nil { + value, err := getFunc() + if err != nil { return value, err } - err = conn.Put(key, value, setting.CacheService.TTLSeconds()) - if err != nil { - return 0, err - } + + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) } - switch value := conn.Get(key).(type) { + + switch v := cached.(type) { case int: - return value, nil + return v, nil case string: - v, err := strconv.Atoi(value) + value, err := strconv.Atoi(v) if err != nil { return 0, err } - return v, nil + return value, nil default: - return 0, fmt.Errorf("Unsupported cached value type: %v", value) + value, err := getFunc() + if err != nil { + return value, err + } + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) } } @@ -111,30 +146,34 @@ func GetInt64(key string, getFunc func() (int64, error)) (int64, error) { if conn == nil || setting.CacheService.TTL == 0 { return getFunc() } - if !conn.IsExist(key) { - var ( - value int64 - err error - ) - if value, err = getFunc(); err != nil { + + cached := conn.Get(key) + + if cached == nil { + value, err := getFunc() + if err != nil { return value, err } - err = conn.Put(key, value, setting.CacheService.TTLSeconds()) - if err != nil { - return 0, err - } + + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) } - switch value := conn.Get(key).(type) { + + switch v := conn.Get(key).(type) { case int64: - return value, nil + return v, nil case string: - v, err := strconv.ParseInt(value, 10, 64) + value, err := strconv.ParseInt(v, 10, 64) if err != nil { return 0, err } - return v, nil + return value, nil default: - return 0, fmt.Errorf("Unsupported cached value type: %v", value) + value, err := getFunc() + if err != nil { + return value, err + } + + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) } } diff --git a/modules/system/setting.go b/modules/system/setting.go deleted file mode 100644 index aebf24a501..0000000000 --- a/modules/system/setting.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2021 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package system - -import ( - "strconv" - - "code.gitea.io/gitea/models/system" - "code.gitea.io/gitea/modules/cache" -) - -func genKey(key string) string { - return "system.setting." + key -} - -// GetSetting returns the setting value via the key -func GetSetting(key string) (string, error) { - return cache.GetString(genKey(key), func() (string, error) { - res, err := system.GetSetting(key) - if err != nil { - return "", err - } - return res.SettingValue, nil - }) -} - -// GetSettingBool return bool value of setting, -// none existing keys and errors are ignored and result in false -func GetSettingBool(key string) bool { - s, _ := GetSetting(key) - b, _ := strconv.ParseBool(s) - return b -} - -// SetSetting sets the setting value -func SetSetting(key, value string, version int) error { - cache.Remove(genKey(key)) - - return system.SetSetting(&system.Setting{ - SettingKey: key, - SettingValue: value, - Version: version, - }) -} diff --git a/modules/system/user_setting.go b/modules/system/user_setting.go deleted file mode 100644 index eaf146c08d..0000000000 --- a/modules/system/user_setting.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2021 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package system - -import ( - "fmt" - - "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/cache" -) - -func genUserKey(userID int64, key string) string { - return fmt.Sprintf("user_%d.setting.%s", userID, key) -} - -// GetUserSetting returns the user setting value via the key -func GetUserSetting(userID int64, key string) (string, error) { - return cache.GetString(genUserKey(userID, key), func() (string, error) { - res, err := user.GetSetting(userID, key) - if err != nil { - return "", err - } - return res.SettingValue, nil - }) -} - -// SetUserSetting sets the user setting value -func SetUserSetting(userID int64, key, value string) error { - cache.Remove(genUserKey(userID, key)) - - return user.SetUserSetting(userID, key, value) -} diff --git a/modules/templates/helper.go b/modules/templates/helper.go index c5434b7c63..d0866d3e2c 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -43,7 +43,6 @@ import ( "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/svg" - system_module "code.gitea.io/gitea/modules/system" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/gitdiff" @@ -88,7 +87,7 @@ func NewFuncMap() []template.FuncMap { return setting.AssetVersion }, "DisableGravatar": func() bool { - return system_module.GetSettingBool(system_model.KeyPictureDisableGravatar) + return system_model.GetSettingBool(system_model.KeyPictureDisableGravatar) }, "DefaultShowFullName": func() bool { return setting.UI.DefaultShowFullName diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index 614d3d4f66..792eec8d56 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - system_module "code.gitea.io/gitea/modules/system" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/mailer" @@ -203,7 +202,11 @@ func ChangeConfig(ctx *context.Context) { value := ctx.FormString("value") version := ctx.FormInt("version") - if err := system_module.SetSetting(key, value, version); err != nil { + if err := system_model.SetSetting(&system_model.Setting{ + SettingKey: key, + SettingValue: value, + Version: version, + }); err != nil { log.Error("set setting failed: %v", err) ctx.JSON(http.StatusOK, map[string]string{ "err": ctx.Tr("admin.config.set_setting_failed", key), From 1d22911cfe08db93b4be5a99c2a67bcb132c7035 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 10 Nov 2022 19:43:06 +0800 Subject: [PATCH 012/149] Extract updateSession function to reduce repetition (#21735) A simple refactor to reduce duplicate codes. Co-authored-by: Lunny Xiao Co-authored-by: zeripath Co-authored-by: delvh --- routers/web/auth/auth.go | 117 ++++++++++++++------------------ routers/web/auth/linkaccount.go | 22 ++---- routers/web/auth/oauth.go | 50 ++++---------- routers/web/auth/openid.go | 26 ++----- 4 files changed, 80 insertions(+), 135 deletions(-) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 0f8128946c..2919fd3513 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -82,19 +82,12 @@ func AutoSignIn(ctx *context.Context) (bool, error) { isSucceed = true - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - return false, fmt.Errorf("unable to RegenerateSession: Error: %w", err) - } - - // Set session IDs - if err := ctx.Session.Set("uid", u.ID); err != nil { - return false, err - } - if err := ctx.Session.Set("uname", u.Name); err != nil { - return false, err - } - if err := ctx.Session.Release(); err != nil { - return false, err + if err := updateSession(ctx, nil, map[string]interface{}{ + // Set session IDs + "uid": u.ID, + "uname": u.Name, + }); err != nil { + return false, fmt.Errorf("unable to updateSession: %w", err) } if err := resetLocale(ctx, u); err != nil { @@ -252,32 +245,17 @@ func SignInPost(ctx *context.Context) { return } - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - ctx.ServerError("UserSignIn: Unable to set regenerate session", err) - return + updates := map[string]interface{}{ + // User will need to use 2FA TOTP or WebAuthn, save data + "twofaUid": u.ID, + "twofaRemember": form.Remember, } - - // User will need to use 2FA TOTP or WebAuthn, save data - if err := ctx.Session.Set("twofaUid", u.ID); err != nil { - ctx.ServerError("UserSignIn: Unable to set twofaUid in session", err) - return - } - - if err := ctx.Session.Set("twofaRemember", form.Remember); err != nil { - ctx.ServerError("UserSignIn: Unable to set twofaRemember in session", err) - return - } - if hasTOTPtwofa { // User will need to use WebAuthn, save data - if err := ctx.Session.Set("totpEnrolled", u.ID); err != nil { - ctx.ServerError("UserSignIn: Unable to set WebAuthn Enrolled in session", err) - return - } + updates["totpEnrolled"] = u.ID } - - if err := ctx.Session.Release(); err != nil { - ctx.ServerError("UserSignIn: Unable to save session", err) + if err := updateSession(ctx, nil, updates); err != nil { + ctx.ServerError("UserSignIn: Unable to update session", err) return } @@ -308,29 +286,23 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe setting.CookieRememberName, u.Name, days) } - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { + if err := updateSession(ctx, []string{ + // Delete the openid, 2fa and linkaccount data + "openid_verified_uri", + "openid_signin_remember", + "openid_determined_email", + "openid_determined_username", + "twofaUid", + "twofaRemember", + "linkAccount", + }, map[string]interface{}{ + "uid": u.ID, + "uname": u.Name, + }); err != nil { ctx.ServerError("RegenerateSession", err) return setting.AppSubURL + "/" } - // Delete the openid, 2fa and linkaccount data - _ = ctx.Session.Delete("openid_verified_uri") - _ = ctx.Session.Delete("openid_signin_remember") - _ = ctx.Session.Delete("openid_determined_email") - _ = ctx.Session.Delete("openid_determined_username") - _ = ctx.Session.Delete("twofaUid") - _ = ctx.Session.Delete("twofaRemember") - _ = ctx.Session.Delete("linkAccount") - if err := ctx.Session.Set("uid", u.ID); err != nil { - log.Error("Error setting uid %d in session: %v", u.ID, err) - } - if err := ctx.Session.Set("uname", u.Name); err != nil { - log.Error("Error setting uname %s session: %v", u.Name, err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Unable to store session: %v", err) - } - // Language setting of the user overwrites the one previously set // If the user does not have a locale set, we save the current one. if len(u.Language) == 0 { @@ -762,22 +734,15 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) { log.Trace("User activated: %s", user.Name) - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { + if err := updateSession(ctx, nil, map[string]interface{}{ + "uid": user.ID, + "uname": user.Name, + }); err != nil { log.Error("Unable to regenerate session for user: %-v with email: %s: %v", user, user.Email, err) ctx.ServerError("ActivateUserEmail", err) return } - if err := ctx.Session.Set("uid", user.ID); err != nil { - log.Error("Error setting uid in session[%s]: %v", ctx.Session.ID(), err) - } - if err := ctx.Session.Set("uname", user.Name); err != nil { - log.Error("Error setting uname in session[%s]: %v", ctx.Session.ID(), err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Error storing session[%s]: %v", ctx.Session.ID(), err) - } - if err := resetLocale(ctx, user); err != nil { ctx.ServerError("resetLocale", err) return @@ -821,3 +786,25 @@ func ActivateEmail(ctx *context.Context) { // Should users be logged in automatically here? (consider 2FA requirements, etc.) ctx.Redirect(setting.AppSubURL + "/user/settings/account") } + +func updateSession(ctx *context.Context, deletes []string, updates map[string]interface{}) error { + if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { + return fmt.Errorf("regenerate session: %w", err) + } + sess := ctx.Session + sessID := sess.ID() + for _, k := range deletes { + if err := sess.Delete(k); err != nil { + return fmt.Errorf("delete %v in session[%s]: %w", k, sessID, err) + } + } + for k, v := range updates { + if err := sess.Set(k, v); err != nil { + return fmt.Errorf("set %v in session[%s]: %w", k, sessID, err) + } + } + if err := sess.Release(); err != nil { + return fmt.Errorf("store session[%s]: %w", sessID, err) + } + return nil +} diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index 4f3f2062b6..d3211eaa5c 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/mcaptcha" "code.gitea.io/gitea/modules/recaptcha" - "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" auth_service "code.gitea.io/gitea/services/auth" @@ -156,25 +155,16 @@ func linkAccount(ctx *context.Context, u *user_model.User, gothUser goth.User, r return } - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { + if err := updateSession(ctx, nil, map[string]interface{}{ + // User needs to use 2FA, save data and redirect to 2FA page. + "twofaUid": u.ID, + "twofaRemember": remember, + "linkAccount": true, + }); err != nil { ctx.ServerError("RegenerateSession", err) return } - // User needs to use 2FA, save data and redirect to 2FA page. - if err := ctx.Session.Set("twofaUid", u.ID); err != nil { - log.Error("Error setting twofaUid in session: %v", err) - } - if err := ctx.Session.Set("twofaRemember", remember); err != nil { - log.Error("Error setting twofaRemember in session: %v", err) - } - if err := ctx.Session.Set("linkAccount", true); err != nil { - log.Error("Error setting linkAccount in session: %v", err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Error storing session: %v", err) - } - // If WebAuthn is enrolled -> Redirect to WebAuthn instead regs, err := auth.GetWebAuthnCredentialsByUID(u.ID) if err == nil && len(regs) > 0 { diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 4fba8d8e8c..d845f21a33 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -22,7 +22,6 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -1027,17 +1026,12 @@ func setUserGroupClaims(loginSource *auth.Source, u *user_model.User, gothUser * } func showLinkingLogin(ctx *context.Context, gothUser goth.User) { - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - ctx.ServerError("RegenerateSession", err) + if err := updateSession(ctx, nil, map[string]interface{}{ + "linkAccountGothUser": gothUser, + }); err != nil { + ctx.ServerError("updateSession", err) return } - - if err := ctx.Session.Set("linkAccountGothUser", gothUser); err != nil { - log.Error("Error setting linkAccountGothUser in session: %v", err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Error storing session: %v", err) - } ctx.Redirect(setting.AppSubURL + "/user/link_account") } @@ -1075,21 +1069,14 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model // If this user is enrolled in 2FA and this source doesn't override it, // we can't sign the user in just yet. Instead, redirect them to the 2FA authentication page. if !needs2FA { - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - ctx.ServerError("RegenerateSession", err) + if err := updateSession(ctx, nil, map[string]interface{}{ + "uid": u.ID, + "uname": u.Name, + }); err != nil { + ctx.ServerError("updateSession", err) return } - if err := ctx.Session.Set("uid", u.ID); err != nil { - log.Error("Error setting uid in session: %v", err) - } - if err := ctx.Session.Set("uname", u.Name); err != nil { - log.Error("Error setting uname in session: %v", err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Error storing session: %v", err) - } - // Clear whatever CSRF cookie has right now, force to generate a new one middleware.DeleteCSRFCookie(ctx.Resp) @@ -1138,22 +1125,15 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model } } - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - ctx.ServerError("RegenerateSession", err) + if err := updateSession(ctx, nil, map[string]interface{}{ + // User needs to use 2FA, save data and redirect to 2FA page. + "twofaUid": u.ID, + "twofaRemember": false, + }); err != nil { + ctx.ServerError("updateSession", err) return } - // User needs to use 2FA, save data and redirect to 2FA page. - if err := ctx.Session.Set("twofaUid", u.ID); err != nil { - log.Error("Error setting twofaUid in session: %v", err) - } - if err := ctx.Session.Set("twofaRemember", false); err != nil { - log.Error("Error setting twofaRemember in session: %v", err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Error storing session: %v", err) - } - // If WebAuthn is enrolled -> Redirect to WebAuthn instead regs, err := auth.GetWebAuthnCredentialsByUID(u.ID) if err == nil && len(regs) > 0 { diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index 3b1065189d..d34f4db7c0 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -17,7 +17,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/mcaptcha" "code.gitea.io/gitea/modules/recaptcha" - "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -232,27 +231,16 @@ func signInOpenIDVerify(ctx *context.Context) { } } - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - ctx.ServerError("RegenerateSession", err) - return - } - - if err := ctx.Session.Set("openid_verified_uri", id); err != nil { - log.Error("signInOpenIDVerify: Could not set openid_verified_uri in session: %v", err) - } - if err := ctx.Session.Set("openid_determined_email", email); err != nil { - log.Error("signInOpenIDVerify: Could not set openid_determined_email in session: %v", err) - } - if u != nil { nickname = u.LowerName } - - if err := ctx.Session.Set("openid_determined_username", nickname); err != nil { - log.Error("signInOpenIDVerify: Could not set openid_determined_username in session: %v", err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("signInOpenIDVerify: Unable to save changes to the session: %v", err) + if err := updateSession(ctx, nil, map[string]interface{}{ + "openid_verified_uri": id, + "openid_determined_email": email, + "openid_determined_username": nickname, + }); err != nil { + ctx.ServerError("updateSession", err) + return } if u != nil || !setting.Service.EnableOpenIDSignUp || setting.Service.AllowOnlyInternalRegistration { From 92525ddffd8256a2cd9d10c55eca753073ffce8e Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Thu, 10 Nov 2022 22:22:39 +0800 Subject: [PATCH 013/149] Init git module before database migration (#21764) Close #21761 Some database migrations depend on the git module. --- models/migrations/migrations.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 5f5ec8fdd7..6ef4ef5617 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -6,6 +6,7 @@ package migrations import ( + "context" "fmt" "os" @@ -23,6 +24,7 @@ import ( "code.gitea.io/gitea/models/migrations/v1_7" "code.gitea.io/gitea/models/migrations/v1_8" "code.gitea.io/gitea/models/migrations/v1_9" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -527,6 +529,13 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t return nil } + // Some migration tasks depend on the git command + if git.DefaultContext == nil { + if err = git.InitSimple(context.Background()); err != nil { + return err + } + } + // Migrate for i, m := range migrations[v-minDBVersion:] { log.Info("Migration[%d]: %s", v+int64(i), m.Description()) From fb704f6c7248a13b29300e161bd28c52115aeb22 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 11 Nov 2022 05:12:23 +0800 Subject: [PATCH 014/149] Revert unrelated changes for SMTP auth (#21767) The purpose of #18982 is to improve the SMTP mailer, but there were some unrelated changes made to the SMTP auth in https://github.com/go-gitea/gitea/pull/18982/commits/d60c43869420f5fc43ad19b454c9ae50dad65964 This PR reverts these unrelated changes, fix #21744 --- cmd/admin.go | 8 ++++---- routers/web/admin/auths.go | 2 +- services/auth/source/smtp/auth.go | 6 +++--- services/auth/source/smtp/source.go | 2 +- services/auth/source/smtp/source_authenticate.go | 2 +- services/forms/auth_form.go | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/admin.go b/cmd/admin.go index 525bc2cfcd..d33d17a53d 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -413,9 +413,9 @@ var ( Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN", }, cli.StringFlag{ - Name: "addr", + Name: "host", Value: "", - Usage: "SMTP Addr", + Usage: "SMTP Host", }, cli.IntFlag{ Name: "port", @@ -955,8 +955,8 @@ func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error { } conf.Auth = c.String("auth-type") } - if c.IsSet("addr") { - conf.Addr = c.String("addr") + if c.IsSet("host") { + conf.Host = c.String("host") } if c.IsSet("port") { conf.Port = c.Int("port") diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index b79b317555..7ea8a52809 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -159,7 +159,7 @@ func parseLDAPConfig(form forms.AuthenticationForm) *ldap.Source { func parseSMTPConfig(form forms.AuthenticationForm) *smtp.Source { return &smtp.Source{ Auth: form.SMTPAuth, - Addr: form.SMTPAddr, + Host: form.SMTPHost, Port: form.SMTPPort, AllowedDomains: form.AllowedDomains, ForceSMTPS: form.ForceSMTPS, diff --git a/services/auth/source/smtp/auth.go b/services/auth/source/smtp/auth.go index 487c049722..e8453fde69 100644 --- a/services/auth/source/smtp/auth.go +++ b/services/auth/source/smtp/auth.go @@ -58,10 +58,10 @@ var ErrUnsupportedLoginType = errors.New("Login source is unknown") func Authenticate(a smtp.Auth, source *Source) error { tlsConfig := &tls.Config{ InsecureSkipVerify: source.SkipVerify, - ServerName: source.Addr, + ServerName: source.Host, } - conn, err := net.Dial("tcp", net.JoinHostPort(source.Addr, strconv.Itoa(source.Port))) + conn, err := net.Dial("tcp", net.JoinHostPort(source.Host, strconv.Itoa(source.Port))) if err != nil { return err } @@ -71,7 +71,7 @@ func Authenticate(a smtp.Auth, source *Source) error { conn = tls.Client(conn, tlsConfig) } - client, err := smtp.NewClient(conn, source.Addr) + client, err := smtp.NewClient(conn, source.Host) if err != nil { return fmt.Errorf("failed to create NewClient: %w", err) } diff --git a/services/auth/source/smtp/source.go b/services/auth/source/smtp/source.go index b2286d42a0..5e69f912da 100644 --- a/services/auth/source/smtp/source.go +++ b/services/auth/source/smtp/source.go @@ -19,7 +19,7 @@ import ( // Source holds configuration for the SMTP login source. type Source struct { Auth string - Addr string + Host string Port int AllowedDomains string `xorm:"TEXT"` ForceSMTPS bool diff --git a/services/auth/source/smtp/source_authenticate.go b/services/auth/source/smtp/source_authenticate.go index 63fd3e5511..dff24d494e 100644 --- a/services/auth/source/smtp/source_authenticate.go +++ b/services/auth/source/smtp/source_authenticate.go @@ -32,7 +32,7 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str var auth smtp.Auth switch source.Auth { case PlainAuthentication: - auth = smtp.PlainAuth("", userName, password, source.Addr) + auth = smtp.PlainAuth("", userName, password, source.Host) case LoginAuthentication: auth = &loginAuthenticator{userName, password} case CRAMMD5Authentication: diff --git a/services/forms/auth_form.go b/services/forms/auth_form.go index 9064be2cca..7e7c756752 100644 --- a/services/forms/auth_form.go +++ b/services/forms/auth_form.go @@ -45,7 +45,7 @@ type AuthenticationForm struct { IsActive bool IsSyncEnabled bool SMTPAuth string - SMTPAddr string + SMTPHost string SMTPPort int AllowedDomains string SecurityProtocol int `binding:"Range(0,2)"` From 2cbea23d700df9a45899e5de40e93e1a73354ce1 Mon Sep 17 00:00:00 2001 From: Drew Noel Date: Fri, 11 Nov 2022 01:39:27 -0500 Subject: [PATCH 015/149] Add configuration for CORS allowed headers (#21747) This PR enhances the CORS middleware usage by allowing for the headers to be configured in `app.ini`. Fixes #21746 Co-authored-by: KN4CK3R Co-authored-by: John Olheiser Co-authored-by: Lunny Xiao --- custom/conf/app.example.ini | 3 +++ docs/content/doc/advanced/config-cheat-sheet.en-us.md | 1 + modules/setting/cors.go | 2 ++ routers/api/v1/api.go | 2 +- routers/web/web.go | 1 + 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 9f41fdb080..8e85394d34 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1138,6 +1138,9 @@ ROUTER = console ;; allow request with credentials ;ALLOW_CREDENTIALS = false ;; +;; headers to permit +;HEADERS = Content-Type,User-Agent +;; ;; set X-FRAME-OPTIONS header ;X_FRAME_OPTIONS = SAMEORIGIN diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index b0060e9afa..aece6afc08 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -200,6 +200,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: list of methods allowed to request - `MAX_AGE`: **10m**: max time to cache response - `ALLOW_CREDENTIALS`: **false**: allow request with credentials +- `HEADERS`: **Content-Type,User-Agent**: additional headers that are permitted in requests - `X_FRAME_OPTIONS`: **SAMEORIGIN**: Set the `X-Frame-Options` header value. ## UI (`ui`) diff --git a/modules/setting/cors.go b/modules/setting/cors.go index a843194ff9..74ec6618a5 100644 --- a/modules/setting/cors.go +++ b/modules/setting/cors.go @@ -19,10 +19,12 @@ var CORSConfig = struct { Methods []string MaxAge time.Duration AllowCredentials bool + Headers []string XFrameOptions string }{ Enabled: false, MaxAge: 10 * time.Minute, + Headers: []string{"Content-Type", "User-Agent"}, XFrameOptions: "SAMEORIGIN", } diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 0d11674aa9..4b27270840 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -617,7 +617,7 @@ func Routes(ctx gocontext.Context) *web.Route { // setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option AllowedMethods: setting.CORSConfig.Methods, AllowCredentials: setting.CORSConfig.AllowCredentials, - AllowedHeaders: []string{"Authorization", "X-Gitea-OTP"}, + AllowedHeaders: append([]string{"Authorization", "X-Gitea-OTP"}, setting.CORSConfig.Headers...), MaxAge: int(setting.CORSConfig.MaxAge.Seconds()), })) } diff --git a/routers/web/web.go b/routers/web/web.go index 48b33813c9..d0ee9c5eac 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -67,6 +67,7 @@ func CorsHandler() func(next http.Handler) http.Handler { // setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option AllowedMethods: setting.CORSConfig.Methods, AllowCredentials: setting.CORSConfig.AllowCredentials, + AllowedHeaders: setting.CORSConfig.Headers, MaxAge: int(setting.CORSConfig.MaxAge.Seconds()), }) } From 50dd32ede4e776b083ee2c81192c21925294eff5 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Fri, 11 Nov 2022 17:19:12 +0800 Subject: [PATCH 016/149] Update message of reach_limit_of_creation (#21757) When I'm trying to use a user which has no repo numbers limit to create a repo for a org which has reached the limit, it says "You have already reached your limit of 5 repositories." That's confusing. "I" haven't reached the limit, the owner has. xnip_2022-11-10_11-57-45 Co-authored-by: Lauris BH Co-authored-by: techknowlogick --- options/locale/locale_en-US.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index e610bc6b28..1d7086ed1d 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -944,8 +944,8 @@ archive.title = This repo is archived. You can view files and clone it, but cann archive.issue.nocomment = This repo is archived. You cannot comment on issues. archive.pull.nocomment = This repo is archived. You cannot comment on pull requests. -form.reach_limit_of_creation_1 = You have already reached your limit of %d repository. -form.reach_limit_of_creation_n = You have already reached your limit of %d repositories. +form.reach_limit_of_creation_1 = The owner has already reached the limit of %d repository. +form.reach_limit_of_creation_n = The owner has already reached the limit of %d repositories. form.name_reserved = The repository name '%s' is reserved. form.name_pattern_not_allowed = The pattern '%s' is not allowed in a repository name. From 9db221780f28e161c02c4106f63d0b6f185933d4 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 11 Nov 2022 11:22:36 +0100 Subject: [PATCH 017/149] Ignore line anchor links with leading zeroes (#21728) Fixes: https://github.com/go-gitea/gitea/issues/21722 Co-authored-by: Lunny Xiao --- web_src/js/features/repo-code.js | 36 ++++++++++++++++----------- web_src/js/features/repo-code.test.js | 18 ++++++++++++++ 2 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 web_src/js/features/repo-code.test.js diff --git a/web_src/js/features/repo-code.js b/web_src/js/features/repo-code.js index ad27036372..ef6b61196b 100644 --- a/web_src/js/features/repo-code.js +++ b/web_src/js/features/repo-code.js @@ -5,6 +5,8 @@ import {createTippy, showTemporaryTooltip} from '../modules/tippy.js'; import {copyToClipboard} from './clipboard.js'; const {i18n} = window.config; +export const singleAnchorRegex = /^#(L|n)([1-9][0-9]*)$/; +export const rangeAnchorRegex = /^#(L[1-9][0-9]*)-(L[1-9][0-9]*)$/; function changeHash(hash) { if (window.history.pushState) { @@ -149,7 +151,7 @@ export function initRepoCodeView() { }); $(window).on('hashchange', () => { - let m = window.location.hash.match(/^#(L\d+)-(L\d+)$/); + let m = window.location.hash.match(rangeAnchorRegex); let $list; if ($('div.blame').length) { $list = $('.code-view td.lines-code.blame-code'); @@ -159,27 +161,31 @@ export function initRepoCodeView() { let $first; if (m) { $first = $list.filter(`[rel=${m[1]}]`); - selectRange($list, $first, $list.filter(`[rel=${m[2]}]`)); + if ($first.length) { + selectRange($list, $first, $list.filter(`[rel=${m[2]}]`)); - // show code view menu marker (don't show in blame page) - if ($('div.blame').length === 0) { - showLineButton(); + // show code view menu marker (don't show in blame page) + if ($('div.blame').length === 0) { + showLineButton(); + } + + $('html, body').scrollTop($first.offset().top - 200); + return; } - - $('html, body').scrollTop($first.offset().top - 200); - return; } - m = window.location.hash.match(/^#(L|n)(\d+)$/); + m = window.location.hash.match(singleAnchorRegex); if (m) { $first = $list.filter(`[rel=L${m[2]}]`); - selectRange($list, $first); + if ($first.length) { + selectRange($list, $first); - // show code view menu marker (don't show in blame page) - if ($('div.blame').length === 0) { - showLineButton(); + // show code view menu marker (don't show in blame page) + if ($('div.blame').length === 0) { + showLineButton(); + } + + $('html, body').scrollTop($first.offset().top - 200); } - - $('html, body').scrollTop($first.offset().top - 200); } }).trigger('hashchange'); } diff --git a/web_src/js/features/repo-code.test.js b/web_src/js/features/repo-code.test.js new file mode 100644 index 0000000000..3bd1973c1f --- /dev/null +++ b/web_src/js/features/repo-code.test.js @@ -0,0 +1,18 @@ +import {test, expect} from 'vitest'; +import {singleAnchorRegex, rangeAnchorRegex} from './repo-code.js'; + +test('singleAnchorRegex', () => { + expect(singleAnchorRegex.test('#L0')).toEqual(false); + expect(singleAnchorRegex.test('#L1')).toEqual(true); + expect(singleAnchorRegex.test('#L01')).toEqual(false); + expect(singleAnchorRegex.test('#n0')).toEqual(false); + expect(singleAnchorRegex.test('#n1')).toEqual(true); + expect(singleAnchorRegex.test('#n01')).toEqual(false); +}); + +test('rangeAnchorRegex', () => { + expect(rangeAnchorRegex.test('#L0-L10')).toEqual(false); + expect(rangeAnchorRegex.test('#L1-L10')).toEqual(true); + expect(rangeAnchorRegex.test('#L01-L10')).toEqual(false); + expect(rangeAnchorRegex.test('#L1-L01')).toEqual(false); +}); From 9f8e7789187013ab6752c2635b24c9dd1d70cd90 Mon Sep 17 00:00:00 2001 From: Nolann <62215577+Nolann71@users.noreply.github.com> Date: Fri, 11 Nov 2022 18:02:50 +0100 Subject: [PATCH 018/149] Copy citation file content, in APA and BibTex format, on repo home page (#19999) Add feature to easily copy CITATION.cff content in APA and BibTex format. --- options/locale/locale_en-US.ini | 2 + package-lock.json | 289 ++++++++++++++++++++++++-- package.json | 4 + routers/web/repo/view.go | 45 ++++ templates/repo/cite/cite_buttons.tmpl | 11 + templates/repo/cite/cite_modal.tmpl | 22 ++ templates/repo/home.tmpl | 8 +- web_src/js/features/citation.js | 60 ++++++ web_src/js/features/repo-legacy.js | 2 + web_src/less/_repository.less | 52 ++++- 10 files changed, 474 insertions(+), 21 deletions(-) create mode 100644 templates/repo/cite/cite_buttons.tmpl create mode 100644 templates/repo/cite/cite_modal.tmpl create mode 100644 web_src/js/features/citation.js diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 1d7086ed1d..eb2a1c86db 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1013,10 +1013,12 @@ unstar = Unstar star = Star fork = Fork download_archive = Download Repository +more_actions = More Actions no_desc = No Description quick_guide = Quick Guide clone_this_repo = Clone this repository +cite_this_repo = Cite this repository create_new_repo_command = Creating a new repository on the command line push_exist_repo = Pushing an existing repository from the command line empty_message = This repository does not contain any content. diff --git a/package-lock.json b/package-lock.json index cd11a43e4f..bf8d4b05e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,10 @@ "name": "gitea", "license": "MIT", "dependencies": { + "@citation-js/core": "0.6.1", + "@citation-js/plugin-bibtex": "0.6.1", + "@citation-js/plugin-csl": "0.6.3", + "@citation-js/plugin-software-formats": "0.6.0", "@claviska/jquery-minicolors": "2.3.6", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "17.7.0", @@ -197,6 +201,80 @@ "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.1.tgz", "integrity": "sha512-zr9Qs9KFQiEvMWdZesjcmRJlUck5NR+eKGS1uyKk+oYTWwlYrsoPEi6VmG6/TzBD1hKCGEimrhTgGS6hvn/xIQ==" }, + "node_modules/@citation-js/core": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.6.1.tgz", + "integrity": "sha512-zvVxsAP4ciVHiZ60TmKTfjui4m6xeISSp/rtIhOcvZxZ70bBfkt83+kGnuI4xRlhB/oUrZN2fC9BSRKdivSobQ==", + "dependencies": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "fetch-ponyfill": "^7.1.0", + "sync-fetch": "^0.4.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@citation-js/date": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@citation-js/date/-/date-0.5.1.tgz", + "integrity": "sha512-1iDKAZ4ie48PVhovsOXQ+C6o55dWJloXqtznnnKy6CltJBQLIuLLuUqa8zlIvma0ZigjVjgDUhnVaNU1MErtZw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@citation-js/name": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@citation-js/name/-/name-0.4.2.tgz", + "integrity": "sha512-brSPsjs2fOVzSnARLKu0qncn6suWjHVQtrqSUrnqyaRH95r/Ad4wPF5EsoWr+Dx8HzkCGb/ogmoAzfCsqlTwTQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@citation-js/plugin-bibtex": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.6.1.tgz", + "integrity": "sha512-JMw9h9MUXH7YWvgN0j+A5xI4Fw3cHYcDMzpweeAcXBfjfnC6q30Dyvs2YxfUxNEKvWDgRQjAiNNIzgWXs9uK1Q==", + "dependencies": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "moo": "^0.5.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@citation-js/core": "^0.6.0" + } + }, + "node_modules/@citation-js/plugin-csl": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.3.tgz", + "integrity": "sha512-SP1/QyHfhcNufQ6VTJUM04Ti0XEWSWYMUhkDGG2lQtnDJU7pSDeAwtsE1kYUIJ9Np0Gm8IEZAfJ3CslMfsbimg==", + "dependencies": { + "@citation-js/date": "^0.5.0", + "citeproc": "^2.4.6" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@citation-js/core": "^0.6.0" + } + }, + "node_modules/@citation-js/plugin-software-formats": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-software-formats/-/plugin-software-formats-0.6.0.tgz", + "integrity": "sha512-l0Vp2h9UNlqsGMgrJulA92csgu8l3WhhBC0F2nFl76aTMOrMzC9/DX1G2Ob5tUQvPfuy4B5ZZsYPJNTJdtPVhw==", + "dependencies": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "js-yaml": "^4.0.0" + }, + "peerDependencies": { + "@citation-js/core": "^0.6.0" + } + }, "node_modules/@claviska/jquery-minicolors": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/@claviska/jquery-minicolors/-/jquery-minicolors-2.3.6.tgz", @@ -1783,8 +1861,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-find-index": { "version": "1.0.2", @@ -1908,6 +1985,25 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -1975,6 +2071,29 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2126,6 +2245,11 @@ "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", "dev": true }, + "node_modules/citeproc": { + "version": "2.4.62", + "resolved": "https://registry.npmjs.org/citeproc/-/citeproc-2.4.62.tgz", + "integrity": "sha512-l3uFfSEwNZp/jlz/TpgyBs85kOww6VlQHbAth0cpbgOn6iulZd+QlFY43LrRelzcYt3FZHTZ3soDyd8lNmkqdw==" + }, "node_modules/clean-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", @@ -4616,6 +4740,14 @@ "reusify": "^1.0.4" } }, + "node_modules/fetch-ponyfill": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-7.1.0.tgz", + "integrity": "sha512-FhbbL55dj/qdVO3YNK7ZEkshvj3eQ7EuIGV2I6ic/2YiocvyWv+7jg2s4AyS0wdRU75s3tA8ZxI/xPigb0v5Aw==", + "dependencies": { + "node-fetch": "~2.6.1" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -5221,6 +5353,25 @@ "postcss": "^8.1.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -5724,7 +5875,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -6575,6 +6725,11 @@ "webpack": "^4.5.0 || 5.x" } }, + "node_modules/moo": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", + "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -6671,7 +6826,6 @@ "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -6690,20 +6844,17 @@ "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -8498,6 +8649,18 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "node_modules/sync-fetch": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.4.2.tgz", + "integrity": "sha512-vilDD6yTGwyUjm7/W5WUUOCw1GH1aV591zC21XhbV6MJNZqfZcNMs9DVPHzy1UAmQ2GAg6S03F5TQ3paegKSdg==", + "dependencies": { + "buffer": "^5.7.1", + "node-fetch": "^2.6.1" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/table": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", @@ -9845,6 +10008,56 @@ "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.1.tgz", "integrity": "sha512-zr9Qs9KFQiEvMWdZesjcmRJlUck5NR+eKGS1uyKk+oYTWwlYrsoPEi6VmG6/TzBD1hKCGEimrhTgGS6hvn/xIQ==" }, + "@citation-js/core": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.6.1.tgz", + "integrity": "sha512-zvVxsAP4ciVHiZ60TmKTfjui4m6xeISSp/rtIhOcvZxZ70bBfkt83+kGnuI4xRlhB/oUrZN2fC9BSRKdivSobQ==", + "requires": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "fetch-ponyfill": "^7.1.0", + "sync-fetch": "^0.4.1" + } + }, + "@citation-js/date": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@citation-js/date/-/date-0.5.1.tgz", + "integrity": "sha512-1iDKAZ4ie48PVhovsOXQ+C6o55dWJloXqtznnnKy6CltJBQLIuLLuUqa8zlIvma0ZigjVjgDUhnVaNU1MErtZw==" + }, + "@citation-js/name": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@citation-js/name/-/name-0.4.2.tgz", + "integrity": "sha512-brSPsjs2fOVzSnARLKu0qncn6suWjHVQtrqSUrnqyaRH95r/Ad4wPF5EsoWr+Dx8HzkCGb/ogmoAzfCsqlTwTQ==" + }, + "@citation-js/plugin-bibtex": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.6.1.tgz", + "integrity": "sha512-JMw9h9MUXH7YWvgN0j+A5xI4Fw3cHYcDMzpweeAcXBfjfnC6q30Dyvs2YxfUxNEKvWDgRQjAiNNIzgWXs9uK1Q==", + "requires": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "moo": "^0.5.1" + } + }, + "@citation-js/plugin-csl": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.3.tgz", + "integrity": "sha512-SP1/QyHfhcNufQ6VTJUM04Ti0XEWSWYMUhkDGG2lQtnDJU7pSDeAwtsE1kYUIJ9Np0Gm8IEZAfJ3CslMfsbimg==", + "requires": { + "@citation-js/date": "^0.5.0", + "citeproc": "^2.4.6" + } + }, + "@citation-js/plugin-software-formats": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-software-formats/-/plugin-software-formats-0.6.0.tgz", + "integrity": "sha512-l0Vp2h9UNlqsGMgrJulA92csgu8l3WhhBC0F2nFl76aTMOrMzC9/DX1G2Ob5tUQvPfuy4B5ZZsYPJNTJdtPVhw==", + "requires": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "js-yaml": "^4.0.0" + } + }, "@claviska/jquery-minicolors": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/@claviska/jquery-minicolors/-/jquery-minicolors-2.3.6.tgz", @@ -11114,8 +11327,7 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "array-find-index": { "version": "1.0.2", @@ -11206,6 +11418,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -11251,6 +11468,15 @@ "update-browserslist-db": "^1.0.9" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -11353,6 +11579,11 @@ "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", "dev": true }, + "citeproc": { + "version": "2.4.62", + "resolved": "https://registry.npmjs.org/citeproc/-/citeproc-2.4.62.tgz", + "integrity": "sha512-l3uFfSEwNZp/jlz/TpgyBs85kOww6VlQHbAth0cpbgOn6iulZd+QlFY43LrRelzcYt3FZHTZ3soDyd8lNmkqdw==" + }, "clean-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", @@ -13191,6 +13422,14 @@ "reusify": "^1.0.4" } }, + "fetch-ponyfill": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-7.1.0.tgz", + "integrity": "sha512-FhbbL55dj/qdVO3YNK7ZEkshvj3eQ7EuIGV2I6ic/2YiocvyWv+7jg2s4AyS0wdRU75s3tA8ZxI/xPigb0v5Aw==", + "requires": { + "node-fetch": "~2.6.1" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -13640,6 +13879,11 @@ "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "requires": {} }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -13991,7 +14235,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "requires": { "argparse": "^2.0.1" } @@ -14642,6 +14885,11 @@ "loader-utils": "^2.0.2" } }, + "moo": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", + "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -14719,7 +14967,6 @@ "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, "requires": { "whatwg-url": "^5.0.0" }, @@ -14727,20 +14974,17 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -16067,6 +16311,15 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "sync-fetch": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.4.2.tgz", + "integrity": "sha512-vilDD6yTGwyUjm7/W5WUUOCw1GH1aV591zC21XhbV6MJNZqfZcNMs9DVPHzy1UAmQ2GAg6S03F5TQ3paegKSdg==", + "requires": { + "buffer": "^5.7.1", + "node-fetch": "^2.6.1" + } + }, "table": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", diff --git a/package.json b/package.json index 035f3fd0b0..d221a1379a 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,10 @@ "node": ">= 14.0.0" }, "dependencies": { + "@citation-js/core": "0.6.1", + "@citation-js/plugin-bibtex": "0.6.1", + "@citation-js/plugin-csl": "0.6.3", + "@citation-js/plugin-software-formats": "0.6.0", "@claviska/jquery-minicolors": "2.3.6", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "17.7.0", diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index d35ec48df0..e7aca04819 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -730,6 +730,44 @@ func checkHomeCodeViewable(ctx *context.Context) { ctx.NotFound("Home", fmt.Errorf(ctx.Tr("units.error.no_unit_allowed_repo"))) } +func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) { + if entry.Name() != "" { + return + } + tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) + if err != nil { + ctx.NotFoundOrServerError("Repo.Commit.SubTree", git.IsErrNotExist, err) + return + } + allEntries, err := tree.ListEntries() + if err != nil { + ctx.ServerError("ListEntries", err) + return + } + for _, entry := range allEntries { + if entry.Name() == "CITATION.cff" || entry.Name() == "CITATION.bib" { + ctx.Data["CitiationExist"] = true + // Read Citation file contents + blob := entry.Blob() + dataRc, err := blob.DataAsync() + if err != nil { + ctx.ServerError("DataAsync", err) + return + } + defer dataRc.Close() + buf := make([]byte, 1024) + n, err := util.ReadAtMost(dataRc, buf) + if err != nil { + ctx.ServerError("ReadAtMost", err) + return + } + buf = buf[:n] + ctx.PageData["citationFileContent"] = string(buf) + break + } + } +} + // Home render repository home page func Home(ctx *context.Context) { isFeed, _, showFeedType := feed.GetFeedType(ctx.Params(":reponame"), ctx.Req) @@ -954,6 +992,13 @@ func renderCode(ctx *context.Context) { return } + if !ctx.Repo.Repository.IsEmpty { + checkCitationFile(ctx, entry) + if ctx.Written() { + return + } + } + renderLanguageStats(ctx) if ctx.Written() { return diff --git a/templates/repo/cite/cite_buttons.tmpl b/templates/repo/cite/cite_buttons.tmpl new file mode 100644 index 0000000000..0f4fb43484 --- /dev/null +++ b/templates/repo/cite/cite_buttons.tmpl @@ -0,0 +1,11 @@ + + + + + diff --git a/templates/repo/cite/cite_modal.tmpl b/templates/repo/cite/cite_modal.tmpl new file mode 100644 index 0000000000..185b34173d --- /dev/null +++ b/templates/repo/cite/cite_modal.tmpl @@ -0,0 +1,22 @@ + diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 69eaf17429..6b4a0008d6 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -117,19 +117,23 @@ {{if eq $n 0}}
{{template "repo/clone_buttons" .}} - {{template "repo/clone_script" .}}{{/* the script will update `.js-clone-url` and related elements */}}
+ {{template "repo/cite/cite_modal" .}} {{end}} {{if and (ne $n 0) (not .IsViewFile) (not .IsBlame)}} diff --git a/web_src/js/features/citation.js b/web_src/js/features/citation.js new file mode 100644 index 0000000000..01fcd95a1c --- /dev/null +++ b/web_src/js/features/citation.js @@ -0,0 +1,60 @@ +import $ from 'jquery'; + +const {pageData} = window.config; + +const initInputCitationValue = async ($citationCopyBibtex, $citationCopyApa) => { + const [{Cite, plugins}] = await Promise.all([ + import(/* webpackChunkName: "citation-js-core" */'@citation-js/core'), + import(/* webpackChunkName: "citation-js-formats" */'@citation-js/plugin-software-formats'), + import(/* webpackChunkName: "citation-js-bibtex" */'@citation-js/plugin-bibtex'), + import(/* webpackChunkName: "citation-js-bibtex" */'@citation-js/plugin-csl'), + ]); + const {citationFileContent} = pageData; + const config = plugins.config.get('@bibtex'); + config.constants.fieldTypes.doi = ['field', 'literal']; + config.constants.fieldTypes.version = ['field', 'literal']; + const citationFormatter = new Cite(citationFileContent); + const lang = document.documentElement.lang || 'en-US'; + const apaOutput = citationFormatter.format('bibliography', {template: 'apa', lang}); + const bibtexOutput = citationFormatter.format('bibtex', {lang}); + $citationCopyBibtex.attr('data-text', bibtexOutput); + $citationCopyApa.attr('data-text', apaOutput); +}; + +export function initCitationFileCopyContent() { + const defaultCitationFormat = 'apa'; // apa or bibtex + + if (!pageData.citationFileContent) return; + + const $citationCopyApa = $('#citation-copy-apa'); + const $citationCopyBibtex = $('#citation-copy-bibtex'); + const $inputContent = $('#citation-copy-content'); + + if ((!$citationCopyApa.length && !$citationCopyBibtex.length) || !$inputContent.length) return; + const updateUi = () => { + const isBibtex = (localStorage.getItem('citation-copy-format') || defaultCitationFormat) === 'bibtex'; + const copyContent = (isBibtex ? $citationCopyBibtex : $citationCopyApa).attr('data-text'); + + $inputContent.val(copyContent); + $citationCopyBibtex.toggleClass('primary', isBibtex); + $citationCopyApa.toggleClass('primary', !isBibtex); + }; + initInputCitationValue($citationCopyApa, $citationCopyBibtex).then(updateUi); + + $citationCopyApa.on('click', () => { + localStorage.setItem('citation-copy-format', 'apa'); + updateUi(); + }); + $citationCopyBibtex.on('click', () => { + localStorage.setItem('citation-copy-format', 'bibtex'); + updateUi(); + }); + + $inputContent.on('click', () => { + $inputContent.select(); + }); + + $('#cite-repo-button').on('click', () => { + $('#cite-repo-modal').modal('show'); + }); +} diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 2c93ca0342..e6a7c6dcd1 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -21,6 +21,7 @@ import { initRepoCommonFilterSearchDropdown, initRepoCommonLanguageStats, } from './repo-common.js'; +import {initCitationFileCopyContent} from './citation.js'; import {initCompLabelEdit} from './comp/LabelEdit.js'; import {initRepoDiffConversationNav} from './repo-diff.js'; import attachTribute from './tribute.js'; @@ -505,6 +506,7 @@ export function initRepository() { } initRepoCloneLink(); + initCitationFileCopyContent(); initRepoCommonLanguageStats(); initRepoSettingBranches(); diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less index 193a73c706..bf1fb53e2b 100644 --- a/web_src/less/_repository.less +++ b/web_src/less/_repository.less @@ -227,7 +227,7 @@ border-right: none; } - #download-btn { + #more-btn { border-left: none; } @@ -2468,6 +2468,56 @@ // End of .repository +#cite-repo-modal { + #citation-panel { + width: 500px; + + @media @mediaSm { + width: 100%; + } + + input { + border-radius: 0; + padding: 5px 10px; + width: 50%; + line-height: 1.4; + } + + .citation.button { + font-size: 13px; + padding: 7.5px 5px; + } + + #citation-copy-content { + border-radius: 0; + padding: 5px 10px; + font-size: 1.2em; + line-height: 1.4; + } + + #citation-copy-apa, + #citation-copy-bibtex { + border-right: none; + } + + #goto-citation-btn { + border-left: none; + } + + >:first-child { + border-radius: var(--border-radius) 0 0 var(--border-radius) !important; + } + + >:last-child { + border-radius: 0 var(--border-radius) var(--border-radius) 0 !important; + } + + .icon.button { + padding: 0 10px; + } + } +} + &.user-cards { .list { padding: 0; From bf2078640f98094ae63cb53f6a71964b315a34ce Mon Sep 17 00:00:00 2001 From: Jason Song Date: Sat, 12 Nov 2022 08:32:04 +0800 Subject: [PATCH 019/149] Load GitRepo in API before deleting issue (#21720) Fix #20921. The `ctx.Repo.GitRepo` has been used in deleting issues when the issue is a PR. Co-authored-by: Lunny Xiao Co-authored-by: Lauris BH --- routers/api/v1/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 4b27270840..ee1804daa7 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -898,7 +898,7 @@ func Routes(ctx gocontext.Context) *web.Route { m.Group("/{index}", func() { m.Combo("").Get(repo.GetIssue). Patch(reqToken(), bind(api.EditIssueOption{}), repo.EditIssue). - Delete(reqToken(), reqAdmin(), repo.DeleteIssue) + Delete(reqToken(), reqAdmin(), context.ReferencesGitRepo(), repo.DeleteIssue) m.Group("/comments", func() { m.Combo("").Get(repo.ListIssueComments). Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueCommentOption{}), repo.CreateIssueComment) From aed1622766843a093ac586c8d8a77ba85646d1ff Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 12 Nov 2022 15:30:52 +0100 Subject: [PATCH 020/149] Simplify text color selectors and tweak arc-green colors (#21784) Move the text color rules out of the unneeded `.ui` block, add missing colors, tweak colors on arc-green to be more readable (red was particulary bad to read). Also, this removes the previous inheritance of link colors. I think links should always be in primary color and if they are to be discolored, the color should be set on them explicitely. Screenshot 2022-11-12 at 13 28 30 Screenshot 2022-11-12 at 13 18 48 HTML to test with: ```html
some text with a link.
some text with a link.
some text with a link.
some text with a link.
some text with a link.
some text with a link.
some text with a link.
some text with a link.
some text with a link.
some text with a link.
some text with a link.
--- web_src/less/_base.less | 84 +++++------------------- web_src/less/themes/theme-arc-green.less | 38 +++++------ 2 files changed, 35 insertions(+), 87 deletions(-) diff --git a/web_src/less/_base.less b/web_src/less/_base.less index 43d8d711aa..dc0e69c6d1 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -1301,6 +1301,22 @@ a.ui.card:hover, visibility: hidden; } +.text.red { color: var(--color-red) !important; } +.text.orange { color: var(--color-orange) !important; } +.text.yellow { color: var(--color-yellow) !important; } +.text.olive { color: var(--color-olive) !important; } +.text.green { color: var(--color-green) !important; } +.text.teal { color: var(--color-teal) !important; } +.text.blue { color: var(--color-blue) !important; } +.text.violet { color: var(--color-violet) !important; } +.text.purple { color: var(--color-purple) !important; } +.text.pink { color: var(--color-pink) !important; } +.text.brown { color: var(--color-brown) !important; } +.text.black { color: var(--color-text) !important; } +.text.grey { color: var(--color-text-light) !important; } +.text.light.grey { color: var(--color-grey-light) !important; } +.text.gold { color: var(--color-gold) !important; } + .ui { &.left:not(.action) { float: left; @@ -1370,74 +1386,6 @@ a.ui.card:hover, } .text { - &.red { - color: var(--color-red) !important; - - a { - color: inherit !important; - - &:hover { - color: var(--color-red-light) !important; - } - } - } - - &.blue { - color: var(--color-blue) !important; - - a { - color: inherit !important; - - &:hover { - color: var(--color-blue-light) !important; - } - } - } - - &.black { - color: var(--color-text); - - &:hover { - color: var(--color-text-dark); - } - } - - &.grey { - color: var(--color-text-light) !important; - - a { - color: var(--color-text) !important; - - &:hover { - color: var(--color-primary) !important; - } - } - } - - &.light.grey { - color: var(--color-text-light-2) !important; - } - - &.green { - color: var(--color-green) !important; - } - - &.purple { - color: var(--color-purple) !important; - } - - &.yellow { - color: var(--color-yellow) !important; - } - - &.orange { - color: var(--color-orange) !important; - } - - &.gold { - color: var(--color-gold) !important; - } - &.left { text-align: left !important; } diff --git a/web_src/less/themes/theme-arc-green.less b/web_src/less/themes/theme-arc-green.less index 229ffd8937..370a866abb 100644 --- a/web_src/less/themes/theme-arc-green.less +++ b/web_src/less/themes/theme-arc-green.less @@ -56,34 +56,34 @@ --color-secondary-alpha-80: #454a57cc; --color-secondary-alpha-90: #454a57e1; /* colors */ - --color-red: #7d3434; + --color-red: #cc4848; --color-orange: #cc580c; --color-yellow: #cc9903; --color-olive: #91a313; --color-green: #87ab63; --color-teal: #00918a; - --color-blue: #1a6aa6; - --color-violet: #502aa1; - --color-purple: #8229a0; - --color-pink: #c21e7b; - --color-brown: #845232; + --color-blue: #3a8ac6; + --color-violet: #906ae1; + --color-purple: #b259d0; + --color-pink: #d22e8b; + --color-brown: #a47252; --color-grey: #5e626a; /* light variants */ - --color-red-light: #984646; - --color-orange-light: #e6630d; - --color-yellow-light: #e5ac04; - --color-olive-light: #a3b816; - --color-green-light: #9fbc82; - --color-teal-light: #00a39c; - --color-blue-light: #1e78bb; - --color-violet-light: #5a30b5; - --color-purple-light: #932eb4; - --color-pink-light: #db228a; - --color-brown-light: #955d39; - --color-grey-light: #6a6e78; + --color-red-light: #c23636; + --color-orange-light: #b84f0b; + --color-yellow-light: #b88a03; + --color-olive-light: #839311; + --color-green-light: #7a9e55; + --color-teal-light: #00837c; + --color-blue-light: #347cb3; + --color-violet-light: #7b4edb; + --color-purple-light: #a742c9; + --color-pink-light: #be297d; + --color-brown-light: #94674a; + --color-grey-light: #55585f; /* other colors */ --color-black: #1e222e; - --color-gold: #a1882b; + --color-gold: #b1983b; --color-white: #ffffff; --color-diff-removed-word-bg: #6f3333; --color-diff-added-word-bg: #3c653c; From 158b088ec3eb39e2129c2244179006b030eba947 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 12 Nov 2022 18:58:26 +0000 Subject: [PATCH 021/149] Adjust clone timeout error to suggest increasing timeout (#21769) There are far too many error reports regarding timeouts from migrations. We should adjust error report to suggest increasing this timeout. Ref #20680 Signed-off-by: Andrew Thornton --- modules/repository/repo.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/repository/repo.go b/modules/repository/repo.go index de6de3bda4..51e1699821 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -6,6 +6,7 @@ package repository import ( "context" + "errors" "fmt" "io" "net/http" @@ -79,6 +80,9 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, Timeout: migrateTimeout, SkipTLSVerify: setting.Migrations.SkipTLSVerify, }); err != nil { + if errors.Is(err, context.DeadlineExceeded) { + return repo, fmt.Errorf("Clone timed out. Consider increasing [git.timeout] MIGRATE in app.ini. Underlying Error: %w", err) + } return repo, fmt.Errorf("Clone: %w", err) } From a0a425a13ba587829a831aaecd8469d39d372111 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 12 Nov 2022 18:59:15 +0000 Subject: [PATCH 022/149] Add some documentation to packages (#21648) In #21637 it was mentioned that the purpose of the API routes for the packages is unclear. This PR adds some documentation. Fix #21637 Signed-off-by: Andrew Thornton Co-authored-by: KN4CK3R --- routers/api/packages/api.go | 7 ++++++- routers/api/v1/api.go | 1 + routers/init.go | 8 +++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 6f53bc4ae0..11e7e5d6a6 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -40,7 +40,9 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) { } } -func Routes(ctx gocontext.Context) *web.Route { +// CommonRoutes provide endpoints for most package managers (except containers - see below) +// These are mounted on `/api/packages` (not `/api/v1/packages`) +func CommonRoutes(ctx gocontext.Context) *web.Route { r := web.NewRoute() r.Use(context.PackageContexter(ctx)) @@ -301,6 +303,9 @@ func Routes(ctx gocontext.Context) *web.Route { return r } +// ContainerRoutes provides endpoints that implement the OCI API to serve containers +// These have to be mounted on `/v2/...` to comply with the OCI spec: +// https://github.com/opencontainers/distribution-spec/blob/main/spec.md func ContainerRoutes(ctx gocontext.Context) *web.Route { r := web.NewRoute() diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index ee1804daa7..e41fccb635 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1073,6 +1073,7 @@ func Routes(ctx gocontext.Context) *web.Route { }, repoAssignment()) }) + // NOTE: these are Gitea package management API - see packages.CommonRoutes and packages.DockerContainerRoutes for endpoints that implement package manager APIs m.Group("/packages/{username}", func() { m.Group("/{type}/{name}/{version}", func() { m.Get("", packages.GetPackage) diff --git a/routers/init.go b/routers/init.go index 53b33f468f..fecc5c439c 100644 --- a/routers/init.go +++ b/routers/init.go @@ -185,8 +185,14 @@ func NormalRoutes(ctx context.Context) *web.Route { r.Mount("/", web_routers.Routes(ctx)) r.Mount("/api/v1", apiv1.Routes(ctx)) r.Mount("/api/internal", private.Routes()) + if setting.Packages.Enabled { - r.Mount("/api/packages", packages_router.Routes(ctx)) + // Add endpoints to match common package manager APIs + + // This implements package support for most package managers + r.Mount("/api/packages", packages_router.CommonRoutes(ctx)) + + // This implements the OCI API (Note this is not preceded by /api but is instead /v2) r.Mount("/v2", packages_router.ContainerRoutes(ctx)) } return r From 34283a74e85278fed2c9b70d6f8749dc6a4001ca Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 13 Nov 2022 04:18:50 +0800 Subject: [PATCH 023/149] Allow detect whether it's in a database transaction for a context.Context (#21756) Fix #19513 This PR introduce a new db method `InTransaction(context.Context)`, and also builtin check on `db.TxContext` and `db.WithTx`. There is also a new method `db.AutoTx` has been introduced but could be used by other PRs. `WithTx` will always open a new transaction, if a transaction exist in context, return an error. `AutoTx` will try to open a new transaction if no transaction exist in context. That means it will always enter a transaction if there is no error. Co-authored-by: delvh Co-authored-by: 6543 <6543@obermui.de> --- models/activities/action.go | 2 +- models/activities/notification.go | 4 +- models/asymkey/gpg_key.go | 2 +- models/asymkey/gpg_key_add.go | 2 +- models/asymkey/gpg_key_verify.go | 2 +- models/asymkey/ssh_key.go | 4 +- models/asymkey/ssh_key_deploy.go | 2 +- models/asymkey/ssh_key_principals.go | 2 +- models/asymkey/ssh_key_verify.go | 2 +- models/auth/oauth2.go | 4 +- models/auth/session.go | 4 +- models/avatars/avatar.go | 2 +- models/db/context.go | 54 +++++++++++++++++++--- models/db/context_test.go | 33 +++++++++++++ models/db/error.go | 3 ++ models/db/index_test.go | 8 ++-- models/git/branches.go | 2 +- models/git/branches_test.go | 2 +- models/git/commit_status.go | 4 +- models/git/lfs.go | 6 +-- models/git/lfs_lock.go | 4 +- models/issues/assignees.go | 2 +- models/issues/comment.go | 6 +-- models/issues/dependency.go | 4 +- models/issues/issue.go | 20 ++++---- models/issues/issue_index.go | 2 +- models/issues/issue_lock.go | 2 +- models/issues/issue_project.go | 4 +- models/issues/issue_xref_test.go | 4 +- models/issues/label.go | 8 ++-- models/issues/label_test.go | 2 +- models/issues/milestone.go | 10 ++-- models/issues/pull.go | 4 +- models/issues/reaction.go | 2 +- models/issues/review.go | 14 +++--- models/issues/stopwatch.go | 2 +- models/issues/tracked_time.go | 6 +-- models/migrate.go | 10 ++-- models/org.go | 2 +- models/org_team.go | 16 +++---- models/organization/org.go | 4 +- models/organization/team_unit.go | 2 +- models/project/board.go | 2 +- models/project/issue.go | 2 +- models/project/project.go | 8 ++-- models/repo.go | 4 +- models/repo/collaboration.go | 2 +- models/repo/language_stats.go | 4 +- models/repo/repo_unit.go | 2 +- models/repo/star.go | 2 +- models/repo/topic.go | 4 +- models/repo/update.go | 4 +- models/repo/upload.go | 2 +- models/repo_collaboration.go | 2 +- models/repo_transfer.go | 6 +-- models/system/appstate.go | 2 +- models/system/setting.go | 2 +- models/user/email_address.go | 6 +-- models/user/follow.go | 4 +- models/user/setting.go | 2 +- models/user/user.go | 6 +-- models/webhook/webhook.go | 4 +- modules/repository/collaborator.go | 2 +- modules/repository/create.go | 2 +- modules/repository/repo.go | 4 +- routers/api/packages/conan/conan.go | 2 +- routers/api/packages/container/blob.go | 4 +- routers/api/packages/container/manifest.go | 4 +- routers/api/packages/npm/npm.go | 2 +- services/asymkey/deploy_key.go | 2 +- services/asymkey/ssh_key.go | 2 +- services/attachment/attachment.go | 2 +- services/automerge/automerge.go | 8 ++-- services/comments/comments.go | 2 +- services/issue/issue.go | 2 +- services/issue/label.go | 2 +- services/issue/milestone.go | 2 +- services/org/org.go | 2 +- services/org/repo.go | 2 +- services/packages/packages.go | 8 ++-- services/pull/check.go | 4 +- services/pull/merge.go | 2 +- services/release/release.go | 2 +- services/repository/adopt.go | 2 +- services/repository/archiver/archiver.go | 2 +- services/repository/avatar.go | 4 +- services/repository/fork.go | 4 +- services/repository/push.go | 2 +- services/repository/repository.go | 2 +- services/repository/template.go | 2 +- services/user/user.go | 4 +- 91 files changed, 252 insertions(+), 176 deletions(-) create mode 100644 models/db/context_test.go diff --git a/models/activities/action.go b/models/activities/action.go index cad3263c2d..5c3419c5ec 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -572,7 +572,7 @@ func NotifyWatchers(actions ...*Action) error { // NotifyWatchersActions creates batch of actions for every watcher. func NotifyWatchersActions(acts []*Action) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/activities/notification.go b/models/activities/notification.go index 5748b807a0..28adc8cc4e 100644 --- a/models/activities/notification.go +++ b/models/activities/notification.go @@ -142,7 +142,7 @@ func CountNotifications(opts *FindNotificationOptions) (int64, error) { // CreateRepoTransferNotification creates notification for the user a repository was transferred to func CreateRepoTransferNotification(doer, newOwner *user_model.User, repo *repo_model.Repository) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -185,7 +185,7 @@ func CreateRepoTransferNotification(doer, newOwner *user_model.User, repo *repo_ // for each watcher, or updates it if already exists // receiverID > 0 just send to receiver, else send to all watcher func CreateOrUpdateIssueNotifications(issueID, commentID, notificationAuthorID, receiverID int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/asymkey/gpg_key.go b/models/asymkey/gpg_key.go index 83774533aa..30f5ecc949 100644 --- a/models/asymkey/gpg_key.go +++ b/models/asymkey/gpg_key.go @@ -234,7 +234,7 @@ func DeleteGPGKey(doer *user_model.User, id int64) (err error) { return ErrGPGKeyAccessDenied{doer.ID, key.ID} } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/asymkey/gpg_key_add.go b/models/asymkey/gpg_key_add.go index d01f2deb03..e7be19073a 100644 --- a/models/asymkey/gpg_key_add.go +++ b/models/asymkey/gpg_key_add.go @@ -73,7 +73,7 @@ func AddGPGKey(ownerID int64, content, token, signature string) ([]*GPGKey, erro return nil, err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } diff --git a/models/asymkey/gpg_key_verify.go b/models/asymkey/gpg_key_verify.go index 152765cc3a..4e9d04f576 100644 --- a/models/asymkey/gpg_key_verify.go +++ b/models/asymkey/gpg_key_verify.go @@ -31,7 +31,7 @@ import ( // VerifyGPGKey marks a GPG key as verified func VerifyGPGKey(ownerID int64, keyID, token, signature string) (string, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return "", err } diff --git a/models/asymkey/ssh_key.go b/models/asymkey/ssh_key.go index 7ed4ad6b3f..811f563c8d 100644 --- a/models/asymkey/ssh_key.go +++ b/models/asymkey/ssh_key.go @@ -100,7 +100,7 @@ func AddPublicKey(ownerID int64, name, content string, authSourceID int64) (*Pub return nil, err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -321,7 +321,7 @@ func PublicKeyIsExternallyManaged(id int64) (bool, error) { // deleteKeysMarkedForDeletion returns true if ssh keys needs update func deleteKeysMarkedForDeletion(keys []string) (bool, error) { // Start session - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return false, err } diff --git a/models/asymkey/ssh_key_deploy.go b/models/asymkey/ssh_key_deploy.go index d5c981da47..601e5c32e5 100644 --- a/models/asymkey/ssh_key_deploy.go +++ b/models/asymkey/ssh_key_deploy.go @@ -126,7 +126,7 @@ func AddDeployKey(repoID int64, name, content string, readOnly bool) (*DeployKey accessMode = perm.AccessModeWrite } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } diff --git a/models/asymkey/ssh_key_principals.go b/models/asymkey/ssh_key_principals.go index e0d407af35..7a769fd84d 100644 --- a/models/asymkey/ssh_key_principals.go +++ b/models/asymkey/ssh_key_principals.go @@ -26,7 +26,7 @@ import ( // AddPrincipalKey adds new principal to database and authorized_principals file. func AddPrincipalKey(ownerID int64, content string, authSourceID int64) (*PublicKey, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } diff --git a/models/asymkey/ssh_key_verify.go b/models/asymkey/ssh_key_verify.go index 710cb3af00..6931df9e88 100644 --- a/models/asymkey/ssh_key_verify.go +++ b/models/asymkey/ssh_key_verify.go @@ -15,7 +15,7 @@ import ( // VerifySSHKey marks a SSH key as verified func VerifySSHKey(ownerID int64, fingerprint, token, signature string) (string, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return "", err } diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go index ccd9336f65..2ff1066288 100644 --- a/models/auth/oauth2.go +++ b/models/auth/oauth2.go @@ -201,7 +201,7 @@ type UpdateOAuth2ApplicationOptions struct { // UpdateOAuth2Application updates an oauth2 application func UpdateOAuth2Application(opts UpdateOAuth2ApplicationOptions) (*OAuth2Application, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -265,7 +265,7 @@ func deleteOAuth2Application(ctx context.Context, id, userid int64) error { // DeleteOAuth2Application deletes the application with the given id and the grants and auth codes related to it. It checks if the userid was the creator of the app. func DeleteOAuth2Application(id, userid int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/auth/session.go b/models/auth/session.go index 5b130c64b6..b5e4712bde 100644 --- a/models/auth/session.go +++ b/models/auth/session.go @@ -37,7 +37,7 @@ func ReadSession(key string) (*Session, error) { Key: key, } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -73,7 +73,7 @@ func DestroySession(key string) error { // RegenerateSession regenerates a session from the old id func RegenerateSession(oldKey, newKey string) (*Session, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } diff --git a/models/avatars/avatar.go b/models/avatars/avatar.go index ec3b611312..61f0ac19c3 100644 --- a/models/avatars/avatar.go +++ b/models/avatars/avatar.go @@ -97,7 +97,7 @@ func saveEmailHash(email string) string { Hash: emailHash, } // OK we're going to open a session just because I think that that might hide away any problems with postgres reporting errors - if err := db.WithTx(func(ctx context.Context) error { + if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { has, err := db.GetEngine(ctx).Where("email = ? AND hash = ?", emailHash.Email, emailHash.Hash).Get(new(EmailHash)) if has || err != nil { // Seriously we don't care about any DB problems just return the lowerEmail - we expect the transaction to fail most of the time diff --git a/models/db/context.go b/models/db/context.go index e90780e4e9..8c81469ebc 100644 --- a/models/db/context.go +++ b/models/db/context.go @@ -8,6 +8,7 @@ import ( "context" "database/sql" + "xorm.io/xorm" "xorm.io/xorm/schemas" ) @@ -86,7 +87,11 @@ type Committer interface { } // TxContext represents a transaction Context -func TxContext() (*Context, Committer, error) { +func TxContext(parentCtx context.Context) (*Context, Committer, error) { + if InTransaction(parentCtx) { + return nil, nil, ErrAlreadyInTransaction + } + sess := x.NewSession() if err := sess.Begin(); err != nil { sess.Close() @@ -97,14 +102,24 @@ func TxContext() (*Context, Committer, error) { } // WithTx represents executing database operations on a transaction -// you can optionally change the context to a parent one -func WithTx(f func(ctx context.Context) error, stdCtx ...context.Context) error { - parentCtx := DefaultContext - if len(stdCtx) != 0 && stdCtx[0] != nil { - // TODO: make sure parent context has no open session - parentCtx = stdCtx[0] +// This function will always open a new transaction, if a transaction exist in parentCtx return an error. +func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error { + if InTransaction(parentCtx) { + return ErrAlreadyInTransaction } + return txWithNoCheck(parentCtx, f) +} +// AutoTx represents executing database operations on a transaction, if the transaction exist, +// this function will reuse it otherwise will create a new one and close it when finished. +func AutoTx(parentCtx context.Context, f func(ctx context.Context) error) error { + if InTransaction(parentCtx) { + return f(newContext(parentCtx, GetEngine(parentCtx), true)) + } + return txWithNoCheck(parentCtx, f) +} + +func txWithNoCheck(parentCtx context.Context, f func(ctx context.Context) error) error { sess := x.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { @@ -180,3 +195,28 @@ func EstimateCount(ctx context.Context, bean interface{}) (int64, error) { } return rows, err } + +// InTransaction returns true if the engine is in a transaction otherwise return false +func InTransaction(ctx context.Context) bool { + var e Engine + if engined, ok := ctx.(Engined); ok { + e = engined.Engine() + } else { + enginedInterface := ctx.Value(enginedContextKey) + if enginedInterface != nil { + e = enginedInterface.(Engined).Engine() + } + } + if e == nil { + return false + } + + switch t := e.(type) { + case *xorm.Engine: + return false + case *xorm.Session: + return t.IsInTx() + default: + return false + } +} diff --git a/models/db/context_test.go b/models/db/context_test.go new file mode 100644 index 0000000000..f00e7834ed --- /dev/null +++ b/models/db/context_test.go @@ -0,0 +1,33 @@ +// 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 db_test + +import ( + "context" + "testing" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func TestInTransaction(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + assert.False(t, db.InTransaction(db.DefaultContext)) + assert.NoError(t, db.WithTx(db.DefaultContext, func(ctx context.Context) error { + assert.True(t, db.InTransaction(ctx)) + return nil + })) + + ctx, committer, err := db.TxContext(db.DefaultContext) + assert.NoError(t, err) + defer committer.Close() + assert.True(t, db.InTransaction(ctx)) + assert.Error(t, db.WithTx(ctx, func(ctx context.Context) error { + assert.True(t, db.InTransaction(ctx)) + return nil + })) +} diff --git a/models/db/error.go b/models/db/error.go index 9577fa55db..85cba5c4e9 100644 --- a/models/db/error.go +++ b/models/db/error.go @@ -5,11 +5,14 @@ package db import ( + "errors" "fmt" "code.gitea.io/gitea/modules/util" ) +var ErrAlreadyInTransaction = errors.New("database connection has already been in a transaction") + // ErrCancelled represents an error due to context cancellation type ErrCancelled struct { Message string diff --git a/models/db/index_test.go b/models/db/index_test.go index 1ea30e2b60..cf777b9d38 100644 --- a/models/db/index_test.go +++ b/models/db/index_test.go @@ -59,7 +59,7 @@ func TestSyncMaxResourceIndex(t *testing.T) { assert.EqualValues(t, 62, maxIndex) // commit transaction - err = db.WithTx(func(ctx context.Context) error { + err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { err = db.SyncMaxResourceIndex(ctx, "test_index", 10, 73) assert.NoError(t, err) maxIndex, err = getCurrentResourceIndex(ctx, "test_index", 10) @@ -73,7 +73,7 @@ func TestSyncMaxResourceIndex(t *testing.T) { assert.EqualValues(t, 73, maxIndex) // rollback transaction - err = db.WithTx(func(ctx context.Context) error { + err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { err = db.SyncMaxResourceIndex(ctx, "test_index", 10, 84) maxIndex, err = getCurrentResourceIndex(ctx, "test_index", 10) assert.NoError(t, err) @@ -102,7 +102,7 @@ func TestGetNextResourceIndex(t *testing.T) { assert.EqualValues(t, 2, maxIndex) // commit transaction - err = db.WithTx(func(ctx context.Context) error { + err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { maxIndex, err = db.GetNextResourceIndex(ctx, "test_index", 20) assert.NoError(t, err) assert.EqualValues(t, 3, maxIndex) @@ -114,7 +114,7 @@ func TestGetNextResourceIndex(t *testing.T) { assert.EqualValues(t, 3, maxIndex) // rollback transaction - err = db.WithTx(func(ctx context.Context) error { + err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { maxIndex, err = db.GetNextResourceIndex(ctx, "test_index", 20) assert.NoError(t, err) assert.EqualValues(t, 4, maxIndex) diff --git a/models/git/branches.go b/models/git/branches.go index b17d762dbe..328f6f0f0d 100644 --- a/models/git/branches.go +++ b/models/git/branches.go @@ -544,7 +544,7 @@ func FindRenamedBranch(repoID int64, from string) (branch *RenamedBranch, exist // RenameBranch rename a branch func RenameBranch(repo *repo_model.Repository, from, to string, gitAction func(isDefault bool) error) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/git/branches_test.go b/models/git/branches_test.go index 58c4ad027b..754c5a4e66 100644 --- a/models/git/branches_test.go +++ b/models/git/branches_test.go @@ -102,7 +102,7 @@ func TestRenameBranch(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) _isDefault := false - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) defer committer.Close() assert.NoError(t, err) assert.NoError(t, git_model.UpdateProtectBranch(ctx, repo1, &git_model.ProtectedBranch{ diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 620baa036c..df6f5ae7ea 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -94,7 +94,7 @@ func GetNextCommitStatusIndex(repoID int64, sha string) (int64, error) { // getNextCommitStatusIndex return the next index func getNextCommitStatusIndex(repoID int64, sha string) (int64, error) { - ctx, commiter, err := db.TxContext() + ctx, commiter, err := db.TxContext(db.DefaultContext) if err != nil { return 0, err } @@ -297,7 +297,7 @@ func NewCommitStatus(opts NewCommitStatusOptions) error { return fmt.Errorf("generate commit status index failed: %w", err) } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", opts.Repo.ID, opts.Creator.ID, opts.SHA, err) } diff --git a/models/git/lfs.go b/models/git/lfs.go index 58042edfdb..74721dabb1 100644 --- a/models/git/lfs.go +++ b/models/git/lfs.go @@ -137,7 +137,7 @@ var ErrLFSObjectNotExist = db.ErrNotExist{Resource: "LFS Meta object"} func NewLFSMetaObject(m *LFSMetaObject) (*LFSMetaObject, error) { var err error - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -185,7 +185,7 @@ func RemoveLFSMetaObjectByOid(repoID int64, oid string) (int64, error) { return 0, ErrLFSObjectNotExist } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return 0, err } @@ -242,7 +242,7 @@ func LFSObjectIsAssociated(oid string) (bool, error) { // LFSAutoAssociate auto associates accessible LFSMetaObjects func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/git/lfs_lock.go b/models/git/lfs_lock.go index 016db899a9..c5a8cc245e 100644 --- a/models/git/lfs_lock.go +++ b/models/git/lfs_lock.go @@ -44,7 +44,7 @@ func cleanPath(p string) string { // CreateLFSLock creates a new lock. func CreateLFSLock(repo *repo_model.Repository, lock *LFSLock) (*LFSLock, error) { - dbCtx, committer, err := db.TxContext() + dbCtx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -137,7 +137,7 @@ func CountLFSLockByRepoID(repoID int64) (int64, error) { // DeleteLFSLockByID deletes a lock by given ID. func DeleteLFSLockByID(id int64, repo *repo_model.Repository, u *user_model.User, force bool) (*LFSLock, error) { - dbCtx, committer, err := db.TxContext() + dbCtx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } diff --git a/models/issues/assignees.go b/models/issues/assignees.go index d960d5ebaf..ce497b116d 100644 --- a/models/issues/assignees.go +++ b/models/issues/assignees.go @@ -64,7 +64,7 @@ func IsUserAssignedToIssue(ctx context.Context, issue *Issue, user *user_model.U // ToggleIssueAssignee changes a user between assigned and not assigned for this issue, and make issue comment for it. func ToggleIssueAssignee(issue *Issue, doer *user_model.User, assigneeID int64) (removed bool, comment *Comment, err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return false, nil, err } diff --git a/models/issues/comment.go b/models/issues/comment.go index 6877991a93..d71c675d23 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -565,7 +565,7 @@ func (c *Comment) LoadAttachments() error { // UpdateAttachments update attachments by UUIDs for the comment func (c *Comment) UpdateAttachments(uuids []string) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -1003,7 +1003,7 @@ type CreateCommentOptions struct { // CreateComment creates comment of issue or commit. func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -1135,7 +1135,7 @@ func CountComments(opts *FindCommentsOptions) (int64, error) { // UpdateComment updates information of comment. func UpdateComment(c *Comment, doer *user_model.User) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/issues/dependency.go b/models/issues/dependency.go index 4754ed0f5f..a02280d8a6 100644 --- a/models/issues/dependency.go +++ b/models/issues/dependency.go @@ -129,7 +129,7 @@ const ( // CreateIssueDependency creates a new dependency for an issue func CreateIssueDependency(user *user_model.User, issue, dep *Issue) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -170,7 +170,7 @@ func CreateIssueDependency(user *user_model.User, issue, dep *Issue) error { // RemoveIssueDependency removes a dependency from an issue func RemoveIssueDependency(user *user_model.User, issue, dep *Issue, depType DependencyType) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/issues/issue.go b/models/issues/issue.go index ca48f425f2..c2f7cb6578 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -540,7 +540,7 @@ func clearIssueLabels(ctx context.Context, issue *Issue, doer *user_model.User) // ClearIssueLabels removes all issue labels as the given user. // Triggers appropriate WebHooks, if any. func ClearIssueLabels(issue *Issue, doer *user_model.User) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -588,7 +588,7 @@ func (ts labelSorter) Swap(i, j int) { // ReplaceIssueLabels removes all current labels and add new labels to the issue. // Triggers appropriate WebHooks, if any. func ReplaceIssueLabels(issue *Issue, labels []*Label, doer *user_model.User) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -760,7 +760,7 @@ func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, // ChangeIssueTitle changes the title of this issue, as the given user. func ChangeIssueTitle(issue *Issue, doer *user_model.User, oldTitle string) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -794,7 +794,7 @@ func ChangeIssueTitle(issue *Issue, doer *user_model.User, oldTitle string) (err // ChangeIssueRef changes the branch of this issue, as the given user. func ChangeIssueRef(issue *Issue, doer *user_model.User, oldRef string) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -844,7 +844,7 @@ func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo * // UpdateIssueAttachments update attachments by UUIDs for the issue func UpdateIssueAttachments(issueID int64, uuids []string) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -864,7 +864,7 @@ func UpdateIssueAttachments(issueID int64, uuids []string) (err error) { // ChangeIssueContent changes issue content, as the given user. func ChangeIssueContent(issue *Issue, doer *user_model.User, content string) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -1069,7 +1069,7 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue // NewIssue creates new issue with labels for repository. func NewIssue(repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -1986,7 +1986,7 @@ func SearchIssueIDsByKeyword(ctx context.Context, kw string, repoIDs []int64, li // If the issue status is changed a statusChangeComment is returned // similarly if the title is changed the titleChanged bool is set to true func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment *Comment, titleChanged bool, err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, false, err } @@ -2044,7 +2044,7 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *us if issue.DeadlineUnix == deadlineUnix { return nil } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -2436,7 +2436,7 @@ func CountOrphanedIssues() (int64, error) { // DeleteOrphanedIssues delete issues without a repo func DeleteOrphanedIssues() error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/issues/issue_index.go b/models/issues/issue_index.go index f4acc5aa1b..1fa79f494a 100644 --- a/models/issues/issue_index.go +++ b/models/issues/issue_index.go @@ -9,7 +9,7 @@ import "code.gitea.io/gitea/models/db" // RecalculateIssueIndexForRepo create issue_index for repo if not exist and // update it based on highest index of existing issues assigned to a repo func RecalculateIssueIndexForRepo(repoID int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/issues/issue_lock.go b/models/issues/issue_lock.go index 7b52429ef7..608b5fd140 100644 --- a/models/issues/issue_lock.go +++ b/models/issues/issue_lock.go @@ -40,7 +40,7 @@ func updateIssueLock(opts *IssueLockOptions, lock bool) error { commentType = CommentTypeUnlock } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go index 8299087c5b..0c59f4e82b 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -110,7 +110,7 @@ func LoadIssuesFromBoardList(bs project_model.BoardList) (map[int64]IssueList, e // ChangeProjectAssign changes the project associated with an issue func ChangeProjectAssign(issue *Issue, doer *user_model.User, newProjectID int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -166,7 +166,7 @@ func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.U // MoveIssueAcrossProjectBoards move a card from one board to another func MoveIssueAcrossProjectBoards(issue *Issue, board *project_model.Board) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/issues/issue_xref_test.go b/models/issues/issue_xref_test.go index 0f72fc7ca6..d6d88db894 100644 --- a/models/issues/issue_xref_test.go +++ b/models/issues/issue_xref_test.go @@ -131,7 +131,7 @@ func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispu r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo}) d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}) - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) assert.NoError(t, err) defer committer.Close() @@ -174,7 +174,7 @@ func testCreateComment(t *testing.T, repo, doer, issue int64, content string) *i i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue}) c := &issues_model.Comment{Type: issues_model.CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content} - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) assert.NoError(t, err) defer committer.Close() err = db.Insert(ctx, c) diff --git a/models/issues/label.go b/models/issues/label.go index bbdc99e265..0b0d1419b1 100644 --- a/models/issues/label.go +++ b/models/issues/label.go @@ -232,7 +232,7 @@ func NewLabel(ctx context.Context, label *Label) error { // NewLabels creates new labels func NewLabels(labels ...*Label) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -267,7 +267,7 @@ func DeleteLabel(id, labelID int64) error { return err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -627,7 +627,7 @@ func NewIssueLabel(issue *Issue, label *Label, doer *user_model.User) (err error return nil } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -676,7 +676,7 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us // NewIssueLabels creates a list of issue-label relations. func NewIssueLabels(issue *Issue, labels []*Label, doer *user_model.User) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/issues/label_test.go b/models/issues/label_test.go index 9ad6fd427b..5e6cc9a2a0 100644 --- a/models/issues/label_test.go +++ b/models/issues/label_test.go @@ -370,7 +370,7 @@ func TestDeleteIssueLabel(t *testing.T) { } } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) defer committer.Close() assert.NoError(t, err) assert.NoError(t, issues_model.DeleteIssueLabel(ctx, issue, label, doer)) diff --git a/models/issues/milestone.go b/models/issues/milestone.go index 3ccade7411..9d1778f732 100644 --- a/models/issues/milestone.go +++ b/models/issues/milestone.go @@ -111,7 +111,7 @@ func (m *Milestone) State() api.StateType { // NewMilestone creates new milestone of repository. func NewMilestone(m *Milestone) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -161,7 +161,7 @@ func GetMilestoneByRepoIDANDName(repoID int64, name string) (*Milestone, error) // UpdateMilestone updates information of given milestone. func UpdateMilestone(m *Milestone, oldIsClosed bool) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -219,7 +219,7 @@ func UpdateMilestoneCounters(ctx context.Context, id int64) error { // ChangeMilestoneStatusByRepoIDAndID changes a milestone open/closed status if the milestone ID is in the repo. func ChangeMilestoneStatusByRepoIDAndID(repoID, milestoneID int64, isClosed bool) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -246,7 +246,7 @@ func ChangeMilestoneStatusByRepoIDAndID(repoID, milestoneID int64, isClosed bool // ChangeMilestoneStatus changes the milestone open/closed status. func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -290,7 +290,7 @@ func DeleteMilestoneByRepoID(repoID, id int64) error { return err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/issues/pull.go b/models/issues/pull.go index f03cabc3c8..e906407d31 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -368,7 +368,7 @@ func (pr *PullRequest) getReviewedByLines(writer io.Writer) error { return nil } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -498,7 +498,7 @@ func (pr *PullRequest) SetMerged(ctx context.Context) (bool, error) { // NewPullRequest creates new pull request with labels for repository. func NewPullRequest(outerCtx context.Context, repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string, pr *PullRequest) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(outerCtx) if err != nil { return err } diff --git a/models/issues/reaction.go b/models/issues/reaction.go index c7503c23a2..5cb63795d1 100644 --- a/models/issues/reaction.go +++ b/models/issues/reaction.go @@ -224,7 +224,7 @@ func CreateReaction(opts *ReactionOptions) (*Reaction, error) { return nil, ErrForbiddenIssueReaction{opts.Type} } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } diff --git a/models/issues/review.go b/models/issues/review.go index 3d2fceda2d..f66c70c1fc 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -374,7 +374,7 @@ func IsContentEmptyErr(err error) bool { // SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, content, commitID string, stale bool, attachmentUUIDs []string) (*Review, *Comment, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, nil, err } @@ -622,7 +622,7 @@ func DismissReview(review *Review, isDismiss bool) (err error) { // InsertReviews inserts review and review comments func InsertReviews(reviews []*Review) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -664,7 +664,7 @@ func InsertReviews(reviews []*Review) error { // AddReviewRequest add a review request from one reviewer func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -719,7 +719,7 @@ func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, // RemoveReviewRequest remove a review request from one reviewer func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -772,7 +772,7 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Commen // AddTeamReviewRequest add a review request from one team func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_model.User) (*Comment, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -831,7 +831,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_ // RemoveTeamReviewRequest remove a review request from one team func RemoveTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_model.User) (*Comment, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -949,7 +949,7 @@ func CanMarkConversation(issue *Issue, doer *user_model.User) (permResult bool, // DeleteReview delete a review and it's code comments func DeleteReview(r *Review) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/issues/stopwatch.go b/models/issues/stopwatch.go index a87fbfafa2..d1d985b746 100644 --- a/models/issues/stopwatch.go +++ b/models/issues/stopwatch.go @@ -261,7 +261,7 @@ func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss // CancelStopwatch removes the given stopwatch and logs it into issue's timeline. func CancelStopwatch(user *user_model.User, issue *Issue) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/issues/tracked_time.go b/models/issues/tracked_time.go index ca21eb5149..e1da0f32b0 100644 --- a/models/issues/tracked_time.go +++ b/models/issues/tracked_time.go @@ -149,7 +149,7 @@ func GetTrackedSeconds(ctx context.Context, opts FindTrackedTimesOptions) (track // AddTime will add the given time (in seconds) to the issue func AddTime(user *user_model.User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -220,7 +220,7 @@ func TotalTimes(options *FindTrackedTimesOptions) (map[*user_model.User]string, // DeleteIssueUserTimes deletes times for issue func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -257,7 +257,7 @@ func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error { // DeleteTime delete a specific Time func DeleteTime(t *TrackedTime) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/migrate.go b/models/migrate.go index d842fb967b..2a79640b07 100644 --- a/models/migrate.go +++ b/models/migrate.go @@ -20,7 +20,7 @@ func InsertMilestones(ms ...*issues_model.Milestone) (err error) { return nil } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -42,7 +42,7 @@ func InsertMilestones(ms ...*issues_model.Milestone) (err error) { // InsertIssues insert issues to database func InsertIssues(issues ...*issues_model.Issue) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -105,7 +105,7 @@ func InsertIssueComments(comments []*issues_model.Comment) error { issueIDs.Add(comment.IssueID) } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -137,7 +137,7 @@ func InsertIssueComments(comments []*issues_model.Comment) error { // InsertPullRequests inserted pull requests func InsertPullRequests(prs ...*issues_model.PullRequest) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -157,7 +157,7 @@ func InsertPullRequests(prs ...*issues_model.PullRequest) error { // InsertReleases migrates release func InsertReleases(rels ...*repo_model.Release) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/org.go b/models/org.go index 150c41f55d..b56c80522b 100644 --- a/models/org.go +++ b/models/org.go @@ -99,7 +99,7 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error { // RemoveOrgUser removes user from given organization. func RemoveOrgUser(orgID, userID int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/org_team.go b/models/org_team.go index 290b1c8b6a..792829563a 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -76,7 +76,7 @@ func addAllRepositories(ctx context.Context, t *organization.Team) error { // AddAllRepositories adds all repositories to the team func AddAllRepositories(t *organization.Team) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -95,7 +95,7 @@ func RemoveAllRepositories(t *organization.Team) (err error) { return nil } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -219,7 +219,7 @@ func RemoveRepository(t *organization.Team, repoID int64) error { return err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -263,7 +263,7 @@ func NewTeam(t *organization.Team) (err error) { return organization.ErrTeamAlreadyExist{OrgID: t.OrgID, Name: t.LowerName} } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -308,7 +308,7 @@ func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err t.Description = t.Description[:255] } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -375,7 +375,7 @@ func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err // DeleteTeam deletes given team. // It's caller's responsibility to assign organization ID. func DeleteTeam(t *organization.Team) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -460,7 +460,7 @@ func AddTeamMember(team *organization.Team, userID int64) error { return err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -598,7 +598,7 @@ func removeTeamMember(ctx context.Context, team *organization.Team, userID int64 // RemoveTeamMember removes member from given team of given organization. func RemoveTeamMember(team *organization.Team, userID int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/organization/org.go b/models/organization/org.go index 993ca3f10d..af9c1f307c 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -277,7 +277,7 @@ func CreateOrganization(org *Organization, owner *user_model.User) (err error) { org.NumMembers = 1 org.Type = user_model.UserTypeOrganization - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -564,7 +564,7 @@ func AddOrgUser(orgID, uid int64) error { return err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/organization/team_unit.go b/models/organization/team_unit.go index a712ddb2eb..4ad1ae95dc 100644 --- a/models/organization/team_unit.go +++ b/models/organization/team_unit.go @@ -32,7 +32,7 @@ func getUnitsByTeamID(ctx context.Context, teamID int64) (units []*TeamUnit, err // UpdateTeamUnits updates a teams's units func UpdateTeamUnits(team *Team, units []TeamUnit) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/project/board.go b/models/project/board.go index be7119ee4d..8428fca722 100644 --- a/models/project/board.go +++ b/models/project/board.go @@ -133,7 +133,7 @@ func NewBoard(board *Board) error { // DeleteBoardByID removes all issues references to the project board. func DeleteBoardByID(boardID int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/project/issue.go b/models/project/issue.go index 59af7063a5..da48d4731e 100644 --- a/models/project/issue.go +++ b/models/project/issue.go @@ -78,7 +78,7 @@ func (p *Project) NumOpenIssues() int { // MoveIssuesOnProjectBoard moves or keeps issues in a column and sorts them inside that column func MoveIssuesOnProjectBoard(board *Board, sortedIssueIDs map[int64]int64) error { - return db.WithTx(func(ctx context.Context) error { + return db.WithTx(db.DefaultContext, func(ctx context.Context) error { sess := db.GetEngine(ctx) issueIDs := make([]int64, 0, len(sortedIssueIDs)) diff --git a/models/project/project.go b/models/project/project.go index ccdf5342d4..5dee241dcf 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -180,7 +180,7 @@ func NewProject(p *Project) error { return errors.New("project type is not valid") } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -248,7 +248,7 @@ func updateRepositoryProjectCount(ctx context.Context, repoID int64) error { // ChangeProjectStatusByRepoIDAndID toggles a project between opened and closed func ChangeProjectStatusByRepoIDAndID(repoID, projectID int64, isClosed bool) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -272,7 +272,7 @@ func ChangeProjectStatusByRepoIDAndID(repoID, projectID int64, isClosed bool) er // ChangeProjectStatus toggle a project between opened and closed func ChangeProjectStatus(p *Project, isClosed bool) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -301,7 +301,7 @@ func changeProjectStatus(ctx context.Context, p *Project, isClosed bool) error { // DeleteProjectByID deletes a project from a repository. func DeleteProjectByID(id int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/repo.go b/models/repo.go index 569dafee5f..2510f0e6bc 100644 --- a/models/repo.go +++ b/models/repo.go @@ -45,7 +45,7 @@ func Init() error { // DeleteRepository deletes a repository for a user or organization. // make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock) func DeleteRepository(doer *user_model.User, uid, repoID int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -569,7 +569,7 @@ func UpdateRepoStats(ctx context.Context, id int64) error { } func updateUserStarNumbers(users []user_model.User) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/repo/collaboration.go b/models/repo/collaboration.go index 0aaa749210..c558259e46 100644 --- a/models/repo/collaboration.go +++ b/models/repo/collaboration.go @@ -138,7 +138,7 @@ func ChangeCollaborationAccessModeCtx(ctx context.Context, repo *Repository, uid // ChangeCollaborationAccessMode sets new access mode for the collaboration. func ChangeCollaborationAccessMode(repo *Repository, uid int64, mode perm.AccessMode) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/repo/language_stats.go b/models/repo/language_stats.go index b047046aeb..5c4cecdca1 100644 --- a/models/repo/language_stats.go +++ b/models/repo/language_stats.go @@ -110,7 +110,7 @@ func GetTopLanguageStats(repo *Repository, limit int) (LanguageStatList, error) // UpdateLanguageStats updates the language statistics for repository func UpdateLanguageStats(repo *Repository, commitID string, stats map[string]int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -182,7 +182,7 @@ func UpdateLanguageStats(repo *Repository, commitID string, stats map[string]int // CopyLanguageStat Copy originalRepo language stat information to destRepo (use for forked repo) func CopyLanguageStat(originalRepo, destRepo *Repository) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go index dd85ca9186..c21c1e7a79 100644 --- a/models/repo/repo_unit.go +++ b/models/repo/repo_unit.go @@ -241,7 +241,7 @@ func UpdateRepoUnit(unit *RepoUnit) error { // UpdateRepositoryUnits updates a repository's units func UpdateRepositoryUnits(repo *Repository, units []RepoUnit, deleteUnitTypes []unit.Type) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/repo/star.go b/models/repo/star.go index 113b56f595..c7459b3655 100644 --- a/models/repo/star.go +++ b/models/repo/star.go @@ -26,7 +26,7 @@ func init() { // StarRepo or unstar repository. func StarRepo(userID, repoID int64, star bool) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/repo/topic.go b/models/repo/topic.go index 33bbb05af9..db41c85a33 100644 --- a/models/repo/topic.go +++ b/models/repo/topic.go @@ -231,7 +231,7 @@ func GetRepoTopicByName(ctx context.Context, repoID int64, topicName string) (*T // AddTopic adds a topic name to a repository (if it does not already have it) func AddTopic(repoID int64, topicName string) (*Topic, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -293,7 +293,7 @@ func SaveTopics(repoID int64, topicNames ...string) error { return err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/repo/update.go b/models/repo/update.go index cc21deb0bc..39c89a7c7c 100644 --- a/models/repo/update.go +++ b/models/repo/update.go @@ -21,7 +21,7 @@ func UpdateRepositoryOwnerNames(ownerID int64, ownerName string) error { if ownerID == 0 { return nil } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -172,7 +172,7 @@ func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName s } } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/repo/upload.go b/models/repo/upload.go index e115c8e50e..13b6055701 100644 --- a/models/repo/upload.go +++ b/models/repo/upload.go @@ -121,7 +121,7 @@ func DeleteUploads(uploads ...*Upload) (err error) { return nil } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go index 58d6b0f488..684d0e63a0 100644 --- a/models/repo_collaboration.go +++ b/models/repo_collaboration.go @@ -25,7 +25,7 @@ func DeleteCollaboration(repo *repo_model.Repository, uid int64) (err error) { UserID: uid, } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/repo_transfer.go b/models/repo_transfer.go index d6a3985fe5..067ab4122f 100644 --- a/models/repo_transfer.go +++ b/models/repo_transfer.go @@ -124,7 +124,7 @@ func deleteRepositoryTransfer(ctx context.Context, repoID int64) error { // CancelRepositoryTransfer marks the repository as ready and remove pending transfer entry, // thus cancel the transfer process. func CancelRepositoryTransfer(repo *repo_model.Repository) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -156,7 +156,7 @@ func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error { // CreatePendingRepositoryTransfer transfer a repo from one owner to a new one. // it marks the repository transfer as "pending" func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -243,7 +243,7 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo } }() - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/system/appstate.go b/models/system/appstate.go index c11a2512ab..bc18c5181d 100644 --- a/models/system/appstate.go +++ b/models/system/appstate.go @@ -25,7 +25,7 @@ func init() { // SaveAppStateContent saves the app state item to database func SaveAppStateContent(key, content string) error { - return db.WithTx(func(ctx context.Context) error { + return db.WithTx(db.DefaultContext, func(ctx context.Context) error { eng := db.GetEngine(ctx) // try to update existing row res, err := eng.Exec("UPDATE app_state SET revision=revision+1, content=? WHERE id=?", content, key) diff --git a/models/system/setting.go b/models/system/setting.go index b4011b1b3e..22119ee5e6 100644 --- a/models/system/setting.go +++ b/models/system/setting.go @@ -196,7 +196,7 @@ func SetSetting(setting *Setting) error { } func upsertSettingValue(key, value string, version int) error { - return db.WithTx(func(ctx context.Context) error { + return db.WithTx(db.DefaultContext, func(ctx context.Context) error { e := db.GetEngine(ctx) // here we use a general method to do a safe upsert for different databases (and most transaction levels) diff --git a/models/user/email_address.go b/models/user/email_address.go index d6279b6639..b6d372f04d 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -321,7 +321,7 @@ func DeleteInactiveEmailAddresses(ctx context.Context) error { // ActivateEmail activates the email address to given user. func ActivateEmail(email *EmailAddress) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -372,7 +372,7 @@ func MakeEmailPrimary(email *EmailAddress) error { } } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -510,7 +510,7 @@ func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error) // ActivateUserEmail will change the activated state of an email address, // either primary or secondary (all in the email_address table) func ActivateUserEmail(userID int64, email string, activate bool) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/user/follow.go b/models/user/follow.go index 5f24f706d1..a02ebdb8c2 100644 --- a/models/user/follow.go +++ b/models/user/follow.go @@ -33,7 +33,7 @@ func FollowUser(userID, followID int64) (err error) { return nil } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -59,7 +59,7 @@ func UnfollowUser(userID, followID int64) (err error) { return nil } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/user/setting.go b/models/user/setting.go index 896f3c8da1..41de499de9 100644 --- a/models/user/setting.go +++ b/models/user/setting.go @@ -163,7 +163,7 @@ func SetUserSetting(userID int64, key, value string) error { } func upsertUserSettingValue(userID int64, key, value string) error { - return db.WithTx(func(ctx context.Context) error { + return db.WithTx(db.DefaultContext, func(ctx context.Context) error { e := db.GetEngine(ctx) // here we use a general method to do a safe upsert for different databases (and most transaction levels) diff --git a/models/user/user.go b/models/user/user.go index 84e2c4a9cc..c36fc21c77 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -695,7 +695,7 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e return err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -814,7 +814,7 @@ func ChangeUserName(u *User, newUserName string) (err error) { return err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -957,7 +957,7 @@ func UpdateUserCols(ctx context.Context, u *User, cols ...string) error { // UpdateUserSetting updates user's settings. func UpdateUserSetting(u *User) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index 6426b95202..1daf806c4e 100644 --- a/models/webhook/webhook.go +++ b/models/webhook/webhook.go @@ -575,7 +575,7 @@ func UpdateWebhookLastStatus(w *Webhook) error { // deleteWebhook uses argument bean as query condition, // ID must be specified and do not assign unnecessary fields. func deleteWebhook(bean *Webhook) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -610,7 +610,7 @@ func DeleteWebhookByOrgID(orgID, id int64) error { // DeleteDefaultSystemWebhook deletes an admin-configured default or system webhook (where Org and Repo ID both 0) func DeleteDefaultSystemWebhook(id int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/modules/repository/collaborator.go b/modules/repository/collaborator.go index 9d20a25890..b83d8199b9 100644 --- a/modules/repository/collaborator.go +++ b/modules/repository/collaborator.go @@ -37,7 +37,7 @@ func addCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_m // AddCollaborator adds new collaboration to a repository with default access mode. func AddCollaborator(repo *repo_model.Repository, u *user_model.User) error { - return db.WithTx(func(ctx context.Context) error { + return db.WithTx(db.DefaultContext, func(ctx context.Context) error { return addCollaborator(ctx, repo, u) }) } diff --git a/modules/repository/create.go b/modules/repository/create.go index 1fec0335a2..c43f1e0989 100644 --- a/modules/repository/create.go +++ b/modules/repository/create.go @@ -211,7 +211,7 @@ func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_m var rollbackRepo *repo_model.Repository - if err := db.WithTx(func(ctx context.Context) error { + if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { if err := CreateRepositoryByExample(ctx, doer, u, repo, false); err != nil { return err } diff --git a/modules/repository/repo.go b/modules/repository/repo.go index 51e1699821..1d3a4658c2 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -173,7 +173,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } @@ -489,7 +489,7 @@ func pullMirrorReleaseSync(repo *repo_model.Repository, gitRepo *git.Repository) if err != nil { return fmt.Errorf("unable to GetTagInfos in pull-mirror Repo[%d:%s/%s]: %w", repo.ID, repo.OwnerName, repo.Name, err) } - err = db.WithTx(func(ctx context.Context) error { + err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { // // clear out existing releases // diff --git a/routers/api/packages/conan/conan.go b/routers/api/packages/conan/conan.go index c8c9dc3e38..b69a674106 100644 --- a/routers/api/packages/conan/conan.go +++ b/routers/api/packages/conan/conan.go @@ -604,7 +604,7 @@ func DeletePackageV2(ctx *context.Context) { } func deleteRecipeOrPackage(apictx *context.Context, rref *conan_module.RecipeReference, ignoreRecipeRevision bool, pref *conan_module.PackageReference, ignorePackageRevision bool) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/routers/api/packages/container/blob.go b/routers/api/packages/container/blob.go index 8a9cbd4a15..df6b7aed92 100644 --- a/routers/api/packages/container/blob.go +++ b/routers/api/packages/container/blob.go @@ -28,7 +28,7 @@ func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pi *packages_servic contentStore := packages_module.NewContentStore() - err := db.WithTx(func(ctx context.Context) error { + err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { created := true p := &packages_model.Package{ OwnerID: pi.Owner.ID, @@ -117,7 +117,7 @@ func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pi *packages_servic } func deleteBlob(ownerID int64, image, digest string) error { - return db.WithTx(func(ctx context.Context) error { + return db.WithTx(db.DefaultContext, func(ctx context.Context) error { pfds, err := container_model.GetContainerBlobs(ctx, &container_model.BlobSearchOptions{ OwnerID: ownerID, Image: image, diff --git a/routers/api/packages/container/manifest.go b/routers/api/packages/container/manifest.go index 8beed3dbb7..a48b1de3b2 100644 --- a/routers/api/packages/container/manifest.go +++ b/routers/api/packages/container/manifest.go @@ -77,7 +77,7 @@ func processImageManifest(mci *manifestCreationInfo, buf *packages_module.Hashed return err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -190,7 +190,7 @@ func processImageManifestIndex(mci *manifestCreationInfo, buf *packages_module.H return err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go index 6d589bde3a..af0e9be56e 100644 --- a/routers/api/packages/npm/npm.go +++ b/routers/api/packages/npm/npm.go @@ -355,7 +355,7 @@ func setPackageTag(tag string, pv *packages_model.PackageVersion, deleteOnly boo return errInvalidTagName } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/asymkey/deploy_key.go b/services/asymkey/deploy_key.go index aa0925ab13..4feeadd952 100644 --- a/services/asymkey/deploy_key.go +++ b/services/asymkey/deploy_key.go @@ -13,7 +13,7 @@ import ( // DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed. func DeleteDeployKey(doer *user_model.User, id int64) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/asymkey/ssh_key.go b/services/asymkey/ssh_key.go index 143c807a10..06b20001fd 100644 --- a/services/asymkey/ssh_key.go +++ b/services/asymkey/ssh_key.go @@ -26,7 +26,7 @@ func DeletePublicKey(doer *user_model.User, id int64) (err error) { } } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/attachment/attachment.go b/services/attachment/attachment.go index 557cc808a3..cc329f568b 100644 --- a/services/attachment/attachment.go +++ b/services/attachment/attachment.go @@ -25,7 +25,7 @@ func NewAttachment(attach *repo_model.Attachment, file io.Reader) (*repo_model.A return nil, fmt.Errorf("attachment %s should belong to a repository", attach.Name) } - err := db.WithTx(func(ctx context.Context) error { + err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { attach.UUID = uuid.New().String() size, err := storage.Attachments.Save(attach.RelativePath(), file, -1) if err != nil { diff --git a/services/automerge/automerge.go b/services/automerge/automerge.go index 3ee8af2344..5c38367e3b 100644 --- a/services/automerge/automerge.go +++ b/services/automerge/automerge.go @@ -63,7 +63,7 @@ func addToQueue(pr *issues_model.PullRequest, sha string) { // ScheduleAutoMerge if schedule is false and no error, pull can be merged directly func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pull *issues_model.PullRequest, style repo_model.MergeStyle, message string) (scheduled bool, err error) { - err = db.WithTx(func(ctx context.Context) error { + err = db.WithTx(ctx, func(ctx context.Context) error { lastCommitStatus, err := pull_service.GetPullRequestCommitStatusState(ctx, pull) if err != nil { return err @@ -81,20 +81,20 @@ func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pull *issues_ _, err = issues_model.CreateAutoMergeComment(ctx, issues_model.CommentTypePRScheduledToAutoMerge, pull, doer) return err - }, ctx) + }) return scheduled, err } // RemoveScheduledAutoMerge cancels a previously scheduled pull request func RemoveScheduledAutoMerge(ctx context.Context, doer *user_model.User, pull *issues_model.PullRequest) error { - return db.WithTx(func(ctx context.Context) error { + return db.WithTx(ctx, func(ctx context.Context) error { if err := pull_model.DeleteScheduledAutoMerge(ctx, pull.ID); err != nil { return err } _, err := issues_model.CreateAutoMergeComment(ctx, issues_model.CommentTypePRUnScheduledToAutoMerge, pull, doer) return err - }, ctx) + }) } // MergeScheduledPullRequest merges a previously scheduled pull request when all checks succeeded diff --git a/services/comments/comments.go b/services/comments/comments.go index c40631359b..7167219c20 100644 --- a/services/comments/comments.go +++ b/services/comments/comments.go @@ -72,7 +72,7 @@ func UpdateComment(c *issues_model.Comment, doer *user_model.User, oldContent st // DeleteComment deletes the comment func DeleteComment(doer *user_model.User, comment *issues_model.Comment) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/issue/issue.go b/services/issue/issue.go index 47782e50d3..8342d7f5d2 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -209,7 +209,7 @@ func GetRefEndNamesAndURLs(issues []*issues_model.Issue, repoLink string) (map[i // deleteIssue deletes the issue func deleteIssue(issue *issues_model.Issue) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/issue/label.go b/services/issue/label.go index bc5f9b910e..a9a0c20b01 100644 --- a/services/issue/label.go +++ b/services/issue/label.go @@ -45,7 +45,7 @@ func AddLabels(issue *issues_model.Issue, doer *user_model.User, labels []*issue // RemoveLabel removes a label from issue by given ID. func RemoveLabel(issue *issues_model.Issue, doer *user_model.User, label *issues_model.Label) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/issue/milestone.go b/services/issue/milestone.go index 756a8625de..965b07556d 100644 --- a/services/issue/milestone.go +++ b/services/issue/milestone.go @@ -65,7 +65,7 @@ func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *is // ChangeMilestoneAssign changes assignment of milestone for issue. func ChangeMilestoneAssign(issue *issues_model.Issue, doer *user_model.User, oldMilestoneID int64) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/org/org.go b/services/org/org.go index 39845610d2..d993f82bbf 100644 --- a/services/org/org.go +++ b/services/org/org.go @@ -19,7 +19,7 @@ import ( // DeleteOrganization completely and permanently deletes everything of organization. func DeleteOrganization(org *organization.Organization) error { - ctx, commiter, err := db.TxContext() + ctx, commiter, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/org/repo.go b/services/org/repo.go index 769419d45b..88520c819f 100644 --- a/services/org/repo.go +++ b/services/org/repo.go @@ -22,7 +22,7 @@ func TeamAddRepository(t *organization.Team, repo *repo_model.Repository) (err e return nil } - return db.WithTx(func(ctx context.Context) error { + return db.WithTx(db.DefaultContext, func(ctx context.Context) error { return models.AddRepository(ctx, t, repo) }) } diff --git a/services/packages/packages.go b/services/packages/packages.go index 443976e174..4513215ae1 100644 --- a/services/packages/packages.go +++ b/services/packages/packages.go @@ -76,7 +76,7 @@ func CreatePackageOrAddFileToExisting(pvci *PackageCreationInfo, pfci *PackageFi } func createPackageAndAddFile(pvci *PackageCreationInfo, pfci *PackageFileCreationInfo, allowDuplicate bool) (*packages_model.PackageVersion, *packages_model.PackageFile, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, nil, err } @@ -190,7 +190,7 @@ func createPackageAndVersion(ctx context.Context, pvci *PackageCreationInfo, all // AddFileToExistingPackage adds a file to an existing package. If the package does not exist, ErrPackageNotExist is returned func AddFileToExistingPackage(pvi *PackageInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, nil, err } @@ -388,7 +388,7 @@ func RemovePackageVersionByNameAndVersion(doer *user_model.User, pvi *PackageInf // RemovePackageVersion deletes the package version and all associated files func RemovePackageVersion(doer *user_model.User, pv *packages_model.PackageVersion) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -444,7 +444,7 @@ func DeletePackageFile(ctx context.Context, pf *packages_model.PackageFile) erro // Cleanup removes expired package data func Cleanup(unused context.Context, olderThan time.Duration) error { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/pull/check.go b/services/pull/check.go index 830ff640b5..6e91c22f3e 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -63,7 +63,7 @@ func AddToTaskQueue(pr *issues_model.PullRequest) { // CheckPullMergable check if the pull mergable based on all conditions (branch protection, merge options, ...) func CheckPullMergable(stdCtx context.Context, doer *user_model.User, perm *access_model.Permission, pr *issues_model.PullRequest, manuallMerge, force bool) error { - return db.WithTx(func(ctx context.Context) error { + return db.WithTx(stdCtx, func(ctx context.Context) error { if pr.HasMerged { return ErrHasMerged } @@ -122,7 +122,7 @@ func CheckPullMergable(stdCtx context.Context, doer *user_model.User, perm *acce } return nil - }, stdCtx) + }) } // isSignedIfRequired check if merge will be signed if required diff --git a/services/pull/merge.go b/services/pull/merge.go index 56ee9c9a73..6f37a887db 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -828,7 +828,7 @@ func MergedManually(pr *issues_model.PullRequest, doer *user_model.User, baseGit pullWorkingPool.CheckIn(fmt.Sprint(pr.ID)) defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID)) - if err := db.WithTx(func(ctx context.Context) error { + if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { prUnit, err := pr.BaseRepo.GetUnitCtx(ctx, unit.TypePullRequests) if err != nil { return err diff --git a/services/release/release.go b/services/release/release.go index 8ccc222fb2..cf398debbb 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -196,7 +196,7 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod } rel.LowerTagName = strings.ToLower(rel.TagName) - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/repository/adopt.go b/services/repository/adopt.go index a9a0639548..57a21f500c 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -54,7 +54,7 @@ func AdoptRepository(doer, u *user_model.User, opts repo_module.CreateRepoOption IsEmpty: !opts.AutoInit, } - if err := db.WithTx(func(ctx context.Context) error { + if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { repoPath := repo_model.RepoPath(u.Name, repo.Name) isExist, err := util.IsExist(repoPath) if err != nil { diff --git a/services/repository/archiver/archiver.go b/services/repository/archiver/archiver.go index 79537ea051..f1c2693aeb 100644 --- a/services/repository/archiver/archiver.go +++ b/services/repository/archiver/archiver.go @@ -174,7 +174,7 @@ func (aReq *ArchiveRequest) Await(ctx context.Context) (*repo_model.RepoArchiver } func doArchive(r *ArchiveRequest) (*repo_model.RepoArchiver, error) { - txCtx, committer, err := db.TxContext() + txCtx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil, err } diff --git a/services/repository/avatar.go b/services/repository/avatar.go index 1cf9e869c0..e4c8da3ba2 100644 --- a/services/repository/avatar.go +++ b/services/repository/avatar.go @@ -33,7 +33,7 @@ func UploadAvatar(repo *repo_model.Repository, data []byte) error { return nil } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -76,7 +76,7 @@ func DeleteAvatar(repo *repo_model.Repository) error { avatarPath := repo.CustomAvatarRelativePath() log.Trace("DeleteAvatar[%d]: %s", repo.ID, avatarPath) - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/repository/fork.go b/services/repository/fork.go index 136d7ccab6..e597bfa449 100644 --- a/services/repository/fork.go +++ b/services/repository/fork.go @@ -112,7 +112,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork panic(panicErr) }() - err = db.WithTx(func(txCtx context.Context) error { + err = db.WithTx(ctx, func(txCtx context.Context) error { if err = repo_module.CreateRepositoryByExample(txCtx, doer, owner, repo, false); err != nil { return err } @@ -184,7 +184,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork // ConvertForkToNormalRepository convert the provided repo from a forked repo to normal repo func ConvertForkToNormalRepository(repo *repo_model.Repository) error { - err := db.WithTx(func(ctx context.Context) error { + err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { repo, err := repo_model.GetRepositoryByIDCtx(ctx, repo.ID) if err != nil { return err diff --git a/services/repository/push.go b/services/repository/push.go index 3a7205d18b..6776ff9f74 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -290,7 +290,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { // PushUpdateAddDeleteTags updates a number of added and delete tags func PushUpdateAddDeleteTags(repo *repo_model.Repository, gitRepo *git.Repository, addTags, delTags []string) error { - return db.WithTx(func(ctx context.Context) error { + return db.WithTx(db.DefaultContext, func(ctx context.Context) error { if err := repo_model.PushUpdateDeleteTagsContext(ctx, repo, delTags); err != nil { return err } diff --git a/services/repository/repository.go b/services/repository/repository.go index 763ef74927..2f2c27ff20 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -90,7 +90,7 @@ func Init() error { // UpdateRepository updates a repository func UpdateRepository(repo *repo_model.Repository, visibilityChanged bool) (err error) { - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } diff --git a/services/repository/template.go b/services/repository/template.go index b73abdce58..bb5e3f4668 100644 --- a/services/repository/template.go +++ b/services/repository/template.go @@ -48,7 +48,7 @@ func GenerateRepository(doer, owner *user_model.User, templateRepo *repo_model.R } var generateRepo *repo_model.Repository - if err = db.WithTx(func(ctx context.Context) error { + if err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { generateRepo, err = repo_module.GenerateRepository(ctx, doer, owner, templateRepo, opts) if err != nil { return err diff --git a/services/user/user.go b/services/user/user.go index c8b497a5c4..4186efe682 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -132,7 +132,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { } } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } @@ -235,7 +235,7 @@ func UploadAvatar(u *user_model.User, data []byte) error { return err } - ctx, committer, err := db.TxContext() + ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return err } From bea25d77ce1084a2dd065a9d8a31e73743b35eb9 Mon Sep 17 00:00:00 2001 From: Gusted Date: Sun, 13 Nov 2022 05:14:35 +0100 Subject: [PATCH 024/149] Upgrade golang.org/x/crypto (#21792) - Update the crypto dependency to include https://github.com/golang/crypto/commit/6fad3dfc18918c2ac9c112e46b32473bd2e5e2f9 - Resolves #17798 Executed: `go get golang.org/x/crypto@6fad3dfc18918c2ac9c112e46b32473bd2e5e2f9 && rm go.sum && go mod tidy` --- go.mod | 8 ++++---- go.sum | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 408249880c..cf1397c468 100644 --- a/go.mod +++ b/go.mod @@ -94,11 +94,11 @@ require ( github.com/yuin/goldmark-meta v1.1.0 go.jolheiser.com/hcaptcha v0.0.4 go.jolheiser.com/pwn v0.0.3 - golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be - golang.org/x/net v0.0.0-20220927171203-f486391704dc + golang.org/x/crypto v0.2.1-0.20221112162523-6fad3dfc1891 + golang.org/x/net v0.2.0 golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 - golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec - golang.org/x/text v0.3.8 + golang.org/x/sys v0.2.0 + golang.org/x/text v0.4.0 golang.org/x/tools v0.1.12 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.67.0 diff --git a/go.sum b/go.sum index 65841b8ec3..d6748eae34 100644 --- a/go.sum +++ b/go.sum @@ -1608,8 +1608,8 @@ golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A= -golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.2.1-0.20221112162523-6fad3dfc1891 h1:WhEPFM1Ck5gaKybeSWvzI7Y/cd8K9K5tJGRxXMACOBA= +golang.org/x/crypto v0.2.1-0.20221112162523-6fad3dfc1891/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1721,8 +1721,8 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ= -golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1876,13 +1876,13 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI= -golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1892,8 +1892,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 6f3efdfe117b46978d449f9223394326e39067ce Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Sun, 13 Nov 2022 07:55:19 +0200 Subject: [PATCH 025/149] Render number of commits in repo page in a user friendly way (#21786) Use `JsPrettyNumber` to render the number of commits * Closes #12637 ### Before ![1094](https://user-images.githubusercontent.com/20454870/201484428-eaa80d27-eeed-444e-9dc5-ae046424de2f.png) ### After ![1,094](https://user-images.githubusercontent.com/20454870/201484385-b5bdc290-86fd-493b-a87c-c987012b18ad.png) Signed-off-by: Yarden Shoham Co-authored-by: 6543 <6543@obermui.de> --- templates/repo/sub_menu.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index fac8e5ac99..e74823e36d 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -4,7 +4,7 @@ From c772934ff623b3a76efbe306f597695330a71287 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 15 Nov 2022 08:08:59 +0000 Subject: [PATCH 032/149] Adjust gitea doctor --run storages to check all storage types (#21785) The doctor check `storages` currently only checks the attachment storage. This PR adds some basic garbage collection functionality for the other types of storage. Signed-off-by: Andrew Thornton Co-authored-by: Lunny Xiao --- models/git/lfs.go | 6 +- models/packages/package_blob.go | 7 + models/repo/archiver.go | 36 +++++ models/repo/attachment.go | 6 +- models/repo/avatar.go | 7 + models/user/avatar.go | 7 + modules/doctor/storage.go | 232 ++++++++++++++++++++++++++---- modules/git/repo_archive.go | 12 ++ modules/packages/content_store.go | 12 ++ routers/web/repo/lfs.go | 2 +- 10 files changed, 296 insertions(+), 31 deletions(-) diff --git a/models/git/lfs.go b/models/git/lfs.go index 74721dabb1..87e07d7a5e 100644 --- a/models/git/lfs.go +++ b/models/git/lfs.go @@ -235,9 +235,9 @@ func LFSObjectAccessible(user *user_model.User, oid string) (bool, error) { return count > 0, err } -// LFSObjectIsAssociated checks if a provided Oid is associated -func LFSObjectIsAssociated(oid string) (bool, error) { - return db.GetEngine(db.DefaultContext).Exist(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}}) +// ExistsLFSObject checks if a provided Oid exists within the DB +func ExistsLFSObject(ctx context.Context, oid string) (bool, error) { + return db.GetEngine(ctx).Exist(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}}) } // LFSAutoAssociate auto associates accessible LFSMetaObjects diff --git a/models/packages/package_blob.go b/models/packages/package_blob.go index 8c701d4285..fcb71a96ec 100644 --- a/models/packages/package_blob.go +++ b/models/packages/package_blob.go @@ -62,6 +62,13 @@ func GetBlobByID(ctx context.Context, blobID int64) (*PackageBlob, error) { return pb, nil } +// ExistPackageBlobWithSHA returns if a package blob exists with the provided sha +func ExistPackageBlobWithSHA(ctx context.Context, blobSha256 string) (bool, error) { + return db.GetEngine(ctx).Exist(&PackageBlob{ + HashSHA256: blobSha256, + }) +} + // FindExpiredUnreferencedBlobs gets all blobs without associated files older than the specific duration func FindExpiredUnreferencedBlobs(ctx context.Context, olderThan time.Duration) ([]*PackageBlob, error) { pbs := make([]*PackageBlob, 0, 10) diff --git a/models/repo/archiver.go b/models/repo/archiver.go index 003911943f..84358ce0dc 100644 --- a/models/repo/archiver.go +++ b/models/repo/archiver.go @@ -7,11 +7,14 @@ package repo import ( "context" "fmt" + "strconv" + "strings" "time" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -44,6 +47,28 @@ func (archiver *RepoArchiver) RelativePath() string { return fmt.Sprintf("%d/%s/%s.%s", archiver.RepoID, archiver.CommitID[:2], archiver.CommitID, archiver.Type.String()) } +// repoArchiverForRelativePath takes a relativePath created from (archiver *RepoArchiver) RelativePath() and creates a shell repoArchiver struct representing it +func repoArchiverForRelativePath(relativePath string) (*RepoArchiver, error) { + parts := strings.SplitN(relativePath, "/", 3) + if len(parts) != 3 { + return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument} + } + repoID, err := strconv.ParseInt(parts[0], 10, 64) + if err != nil { + return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument} + } + nameExts := strings.SplitN(parts[2], ".", 2) + if len(nameExts) != 2 { + return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument} + } + + return &RepoArchiver{ + RepoID: repoID, + CommitID: parts[1] + nameExts[0], + Type: git.ToArchiveType(nameExts[1]), + }, nil +} + var delRepoArchiver = new(RepoArchiver) // DeleteRepoArchiver delete archiver @@ -65,6 +90,17 @@ func GetRepoArchiver(ctx context.Context, repoID int64, tp git.ArchiveType, comm return nil, nil } +// ExistsRepoArchiverWithStoragePath checks if there is a RepoArchiver for a given storage path +func ExistsRepoArchiverWithStoragePath(ctx context.Context, storagePath string) (bool, error) { + // We need to invert the path provided func (archiver *RepoArchiver) RelativePath() above + archiver, err := repoArchiverForRelativePath(storagePath) + if err != nil { + return false, err + } + + return db.GetEngine(ctx).Exist(archiver) +} + // AddRepoArchiver adds an archiver func AddRepoArchiver(ctx context.Context, archiver *RepoArchiver) error { _, err := db.GetEngine(ctx).Insert(archiver) diff --git a/models/repo/attachment.go b/models/repo/attachment.go index 180d7730ba..df7528df09 100644 --- a/models/repo/attachment.go +++ b/models/repo/attachment.go @@ -122,9 +122,9 @@ func GetAttachmentsByUUIDs(ctx context.Context, uuids []string) ([]*Attachment, return attachments, db.GetEngine(ctx).In("uuid", uuids).Find(&attachments) } -// ExistAttachmentsByUUID returns true if attachment is exist by given UUID -func ExistAttachmentsByUUID(uuid string) (bool, error) { - return db.GetEngine(db.DefaultContext).Where("`uuid`=?", uuid).Exist(new(Attachment)) +// ExistAttachmentsByUUID returns true if attachment exists with the given UUID +func ExistAttachmentsByUUID(ctx context.Context, uuid string) (bool, error) { + return db.GetEngine(ctx).Where("`uuid`=?", uuid).Exist(new(Attachment)) } // GetAttachmentsByIssueID returns all attachments of an issue. diff --git a/models/repo/avatar.go b/models/repo/avatar.go index 1bc37598fe..84b9f5ac21 100644 --- a/models/repo/avatar.go +++ b/models/repo/avatar.go @@ -24,6 +24,13 @@ func (repo *Repository) CustomAvatarRelativePath() string { return repo.Avatar } +// ExistsWithAvatarAtStoragePath returns true if there is a user with this Avatar +func ExistsWithAvatarAtStoragePath(ctx context.Context, storagePath string) (bool, error) { + // See func (repo *Repository) CustomAvatarRelativePath() + // repo.Avatar is used directly as the storage path - therefore we can check for existence directly using the path + return db.GetEngine(ctx).Where("`avatar`=?", storagePath).Exist(new(Repository)) +} + // RelAvatarLink returns a relative link to the repository's avatar. func (repo *Repository) RelAvatarLink() string { return repo.relAvatarLink(db.DefaultContext) diff --git a/models/user/avatar.go b/models/user/avatar.go index 102206f3a2..f523766746 100644 --- a/models/user/avatar.go +++ b/models/user/avatar.go @@ -111,3 +111,10 @@ func (u *User) IsUploadAvatarChanged(data []byte) bool { avatarID := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", u.ID, md5.Sum(data))))) return u.Avatar != avatarID } + +// ExistsWithAvatarAtStoragePath returns true if there is a user with this Avatar +func ExistsWithAvatarAtStoragePath(ctx context.Context, storagePath string) (bool, error) { + // See func (u *User) CustomAvatarRelativePath() + // u.Avatar is used directly as the storage path - therefore we can check for existence directly using the path + return db.GetEngine(ctx).Where("`avatar`=?", storagePath).Exist(new(User)) +} diff --git a/modules/doctor/storage.go b/modules/doctor/storage.go index dafd989cf0..8ae9168ea6 100644 --- a/modules/doctor/storage.go +++ b/modules/doctor/storage.go @@ -6,71 +6,255 @@ package doctor import ( "context" + "errors" + "io/fs" + "strings" - repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/git" + "code.gitea.io/gitea/models/packages" + "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" + packages_module "code.gitea.io/gitea/modules/packages" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/util" ) -func checkAttachmentStorageFiles(logger log.Logger, autofix bool) error { - var total, garbageNum int - var deletePaths []string - if err := storage.Attachments.IterateObjects(func(p string, obj storage.Object) error { +type commonStorageCheckOptions struct { + storer storage.ObjectStorage + isOrphaned func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) + name string +} + +func commonCheckStorage(ctx context.Context, logger log.Logger, autofix bool, opts *commonStorageCheckOptions) error { + totalCount, orphanedCount := 0, 0 + totalSize, orphanedSize := int64(0), int64(0) + + var pathsToDelete []string + if err := opts.storer.IterateObjects(func(p string, obj storage.Object) error { defer obj.Close() - total++ + totalCount++ stat, err := obj.Stat() if err != nil { return err } - exist, err := repo_model.ExistAttachmentsByUUID(stat.Name()) + totalSize += stat.Size() + + orphaned, err := opts.isOrphaned(p, obj, stat) if err != nil { return err } - if !exist { - garbageNum++ + if orphaned { + orphanedCount++ + orphanedSize += stat.Size() if autofix { - deletePaths = append(deletePaths, p) + pathsToDelete = append(pathsToDelete, p) } } return nil }); err != nil { - logger.Error("storage.Attachments.IterateObjects failed: %v", err) + logger.Error("Error whilst iterating %s storage: %v", opts.name, err) return err } - if garbageNum > 0 { + if orphanedCount > 0 { if autofix { var deletedNum int - for _, p := range deletePaths { - if err := storage.Attachments.Delete(p); err != nil { - log.Error("Delete attachment %s failed: %v", p, err) + for _, p := range pathsToDelete { + if err := opts.storer.Delete(p); err != nil { + log.Error("Error whilst deleting %s from %s storage: %v", p, opts.name, err) } else { deletedNum++ } } - logger.Info("%d missed information attachment detected, %d deleted.", garbageNum, deletedNum) + logger.Info("Deleted %d/%d orphaned %s(s)", deletedNum, orphanedCount, opts.name) } else { - logger.Warn("Checked %d attachment, %d missed information.", total, garbageNum) + logger.Warn("Found %d/%d (%s/%s) orphaned %s(s)", orphanedCount, totalCount, base.FileSize(orphanedSize), base.FileSize(totalSize), opts.name) } + } else { + logger.Info("Found %d (%s) %s(s)", totalCount, base.FileSize(totalSize), opts.name) } return nil } -func checkStorageFiles(ctx context.Context, logger log.Logger, autofix bool) error { - if err := storage.Init(); err != nil { - logger.Error("storage.Init failed: %v", err) - return err +type checkStorageOptions struct { + All bool + Attachments bool + LFS bool + Avatars bool + RepoAvatars bool + RepoArchives bool + Packages bool +} + +// checkStorage will return a doctor check function to check the requested storage types for "orphaned" stored object/files and optionally delete them +func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger log.Logger, autofix bool) error { + return func(ctx context.Context, logger log.Logger, autofix bool) error { + if err := storage.Init(); err != nil { + logger.Error("storage.Init failed: %v", err) + return err + } + + if opts.Attachments || opts.All { + if err := commonCheckStorage(ctx, logger, autofix, + &commonStorageCheckOptions{ + storer: storage.Attachments, + isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { + exists, err := repo.ExistAttachmentsByUUID(ctx, stat.Name()) + return !exists, err + }, + name: "attachment", + }); err != nil { + return err + } + } + + if opts.LFS || opts.All { + if err := commonCheckStorage(ctx, logger, autofix, + &commonStorageCheckOptions{ + storer: storage.LFS, + isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { + // The oid of an LFS stored object is the name but with all the path.Separators removed + oid := strings.ReplaceAll(path, "/", "") + exists, err := git.ExistsLFSObject(ctx, oid) + return !exists, err + }, + name: "LFS file", + }); err != nil { + return err + } + } + + if opts.Avatars || opts.All { + if err := commonCheckStorage(ctx, logger, autofix, + &commonStorageCheckOptions{ + storer: storage.Avatars, + isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { + exists, err := user.ExistsWithAvatarAtStoragePath(ctx, path) + return !exists, err + }, + name: "avatar", + }); err != nil { + return err + } + } + + if opts.RepoAvatars || opts.All { + if err := commonCheckStorage(ctx, logger, autofix, + &commonStorageCheckOptions{ + storer: storage.RepoAvatars, + isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { + exists, err := repo.ExistsWithAvatarAtStoragePath(ctx, path) + return !exists, err + }, + name: "repo avatar", + }); err != nil { + return err + } + } + + if opts.RepoArchives || opts.All { + if err := commonCheckStorage(ctx, logger, autofix, + &commonStorageCheckOptions{ + storer: storage.RepoAvatars, + isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { + exists, err := repo.ExistsRepoArchiverWithStoragePath(ctx, path) + if err == nil || errors.Is(err, util.ErrInvalidArgument) { + // invalid arguments mean that the object is not a valid repo archiver and it should be removed + return !exists, nil + } + return !exists, err + }, + name: "repo archive", + }); err != nil { + return err + } + } + + if opts.Packages || opts.All { + if err := commonCheckStorage(ctx, logger, autofix, + &commonStorageCheckOptions{ + storer: storage.Packages, + isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { + key, err := packages_module.RelativePathToKey(path) + if err != nil { + // If there is an error here then the relative path does not match a valid package + // Therefore it is orphaned by default + return true, nil + } + + exists, err := packages.ExistPackageBlobWithSHA(ctx, string(key)) + + return !exists, err + }, + name: "package blob", + }); err != nil { + return err + } + } + + return nil } - return checkAttachmentStorageFiles(logger, autofix) } func init() { Register(&Check{ - Title: "Check if there is garbage storage files", + Title: "Check if there are orphaned storage files", Name: "storages", IsDefault: false, - Run: checkStorageFiles, + Run: checkStorage(&checkStorageOptions{All: true}), + AbortIfFailed: false, + SkipDatabaseInitialization: false, + Priority: 1, + }) + + Register(&Check{ + Title: "Check if there are orphaned attachments in storage", + Name: "storage-attachments", + IsDefault: false, + Run: checkStorage(&checkStorageOptions{Attachments: true}), + AbortIfFailed: false, + SkipDatabaseInitialization: false, + Priority: 1, + }) + + Register(&Check{ + Title: "Check if there are orphaned lfs files in storage", + Name: "storage-lfs", + IsDefault: false, + Run: checkStorage(&checkStorageOptions{LFS: true}), + AbortIfFailed: false, + SkipDatabaseInitialization: false, + Priority: 1, + }) + + Register(&Check{ + Title: "Check if there are orphaned avatars in storage", + Name: "storage-avatars", + IsDefault: false, + Run: checkStorage(&checkStorageOptions{Avatars: true, RepoAvatars: true}), + AbortIfFailed: false, + SkipDatabaseInitialization: false, + Priority: 1, + }) + + Register(&Check{ + Title: "Check if there are orphaned archives in storage", + Name: "storage-archives", + IsDefault: false, + Run: checkStorage(&checkStorageOptions{RepoArchives: true}), + AbortIfFailed: false, + SkipDatabaseInitialization: false, + Priority: 1, + }) + + Register(&Check{ + Title: "Check if there are orphaned package blobs in storage", + Name: "storage-packages", + IsDefault: false, + Run: checkStorage(&checkStorageOptions{Packages: true}), AbortIfFailed: false, SkipDatabaseInitialization: false, Priority: 1, diff --git a/modules/git/repo_archive.go b/modules/git/repo_archive.go index a0cbfba5d9..13be2004ca 100644 --- a/modules/git/repo_archive.go +++ b/modules/git/repo_archive.go @@ -38,6 +38,18 @@ func (a ArchiveType) String() string { return "unknown" } +func ToArchiveType(s string) ArchiveType { + switch s { + case "zip": + return ZIP + case "tar.gz": + return TARGZ + case "bundle": + return BUNDLE + } + return 0 +} + // CreateArchive create archive content to the target path func (repo *Repository) CreateArchive(ctx context.Context, format ArchiveType, target io.Writer, usePrefix bool, commitID string) error { if format.String() == "unknown" { diff --git a/modules/packages/content_store.go b/modules/packages/content_store.go index a3a5d1a666..be416ac269 100644 --- a/modules/packages/content_store.go +++ b/modules/packages/content_store.go @@ -7,8 +7,10 @@ package packages import ( "io" "path" + "strings" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/util" ) // BlobHash256Key is the key to address a blob content @@ -45,3 +47,13 @@ func (s *ContentStore) Delete(key BlobHash256Key) error { func KeyToRelativePath(key BlobHash256Key) string { return path.Join(string(key)[0:2], string(key)[2:4], string(key)) } + +// RelativePathToKey converts a relative path aa/bb/aabb000000... to the sha256 key aabb000000... +func RelativePathToKey(relativePath string) (BlobHash256Key, error) { + parts := strings.SplitN(relativePath, "/", 3) + if len(parts) != 3 || len(parts[0]) != 2 || len(parts[1]) != 2 || len(parts[2]) < 4 || parts[0]+parts[1] != parts[2][0:4] { + return "", util.ErrInvalidArgument + } + + return BlobHash256Key(parts[2]), nil +} diff --git a/routers/web/repo/lfs.go b/routers/web/repo/lfs.go index 67cb6837a5..9bf4307bfe 100644 --- a/routers/web/repo/lfs.go +++ b/routers/web/repo/lfs.go @@ -478,7 +478,7 @@ func LFSPointerFiles(ctx *context.Context) { return err } if !result.Associatable { - associated, err := git_model.LFSObjectIsAssociated(pointerBlob.Oid) + associated, err := git_model.ExistsLFSObject(ctx, pointerBlob.Oid) if err != nil { return err } From 6c8ff32511f4295fa381a0144a7200e4eff273d6 Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Tue, 15 Nov 2022 11:33:52 +0200 Subject: [PATCH 033/149] Add `updated_at` field to PullReview API object (#21812) * Closes #19997 Adds an `updated_at` time field to the `PullReview` API object to specify when the pull request review's state changed. Signed-off-by: Yarden Shoham Co-authored-by: Lunny Xiao --- modules/convert/pull_review.go | 1 + modules/structs/pull_review.go | 2 ++ templates/swagger/v1_json.tmpl | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/modules/convert/pull_review.go b/modules/convert/pull_review.go index 93ce208224..e8a543fea9 100644 --- a/modules/convert/pull_review.go +++ b/modules/convert/pull_review.go @@ -39,6 +39,7 @@ func ToPullReview(ctx context.Context, r *issues_model.Review, doer *user_model. Dismissed: r.Dismissed, CodeCommentsCount: r.GetCodeCommentsCount(), Submitted: r.CreatedUnix.AsTime(), + Updated: r.UpdatedUnix.AsTime(), HTMLURL: r.HTMLURL(), HTMLPullURL: r.Issue.HTMLURL(), } diff --git a/modules/structs/pull_review.go b/modules/structs/pull_review.go index 7c9360a0c2..ca2af48657 100644 --- a/modules/structs/pull_review.go +++ b/modules/structs/pull_review.go @@ -40,6 +40,8 @@ type PullReview struct { CodeCommentsCount int `json:"comments_count"` // swagger:strfmt date-time Submitted time.Time `json:"submitted_at"` + // swagger:strfmt date-time + Updated time.Time `json:"updated_at"` HTMLURL string `json:"html_url"` HTMLPullURL string `json:"pull_request_url"` diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 229e219064..fe3185ea77 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -17891,6 +17891,11 @@ "team": { "$ref": "#/definitions/Team" }, + "updated_at": { + "type": "string", + "format": "date-time", + "x-go-name": "Updated" + }, "user": { "$ref": "#/definitions/User" } From 40229a7dd8edc0f07fb1982c0912fdf4df083871 Mon Sep 17 00:00:00 2001 From: Gary Moon Date: Tue, 15 Nov 2022 15:22:16 -0500 Subject: [PATCH 034/149] Skip GitHub migration tests if the API token is undefined (#21824) GitHub migration tests will be skipped if the secret for the GitHub API token hasn't been set. This change should make all tests pass (or skip in the case of this one) for anyone running the pipeline on their own infrastructure without further action on their part. Resolves https://github.com/go-gitea/gitea/issues/21739 Signed-off-by: Gary Moon --- services/migrations/github_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/migrations/github_test.go b/services/migrations/github_test.go index 90c1fcaef5..7bbbbb6168 100644 --- a/services/migrations/github_test.go +++ b/services/migrations/github_test.go @@ -18,7 +18,11 @@ import ( func TestGitHubDownloadRepo(t *testing.T) { GithubLimitRateRemaining = 3 // Wait at 3 remaining since we could have 3 CI in // - downloader := NewGithubDownloaderV3(context.Background(), "https://github.com", "", "", os.Getenv("GITHUB_READ_TOKEN"), "go-gitea", "test_repo") + token := os.Getenv("GITHUB_READ_TOKEN") + if token == "" { + t.Skip("Skipping GitHub migration test because GITHUB_READ_TOKEN is empty") + } + downloader := NewGithubDownloaderV3(context.Background(), "https://github.com", "", "", token, "go-gitea", "test_repo") err := downloader.RefreshRate() assert.NoError(t, err) From f311d15a0ba6e4864d7e5dea83364f93e8eadca4 Mon Sep 17 00:00:00 2001 From: May Date: Tue, 15 Nov 2022 22:36:53 +0100 Subject: [PATCH 035/149] Added space between avatar and username (#21825) Added space between avatar and username which is missing on verified commit message and avatar is too close to username which is don't look nice. Current state ![image](https://user-images.githubusercontent.com/3164256/202007728-d7d6ecac-f754-454c-a67f-e422f4aac5a5.png) This is how it looks after change ![image](https://user-images.githubusercontent.com/3164256/202007984-d4a38a1c-7c24-4278-aa0f-9aa51c10f772.png) Co-authored-by: zeripath Co-authored-by: silverwind Co-authored-by: techknowlogick --- templates/repo/commit_page.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 8ece768832..2dcd02ad98 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -200,7 +200,7 @@ {{else}} {{.locale.Tr "repo.commits.signed_by_untrusted_user_unmatched"}}: {{end}} - {{avatar .Verification.SigningUser 28}} + {{avatar .Verification.SigningUser 28 "mr-3"}} {{.Verification.SigningUser.GetDisplayName}} {{else}} {{svg "gitea-lock-cog" 16 "mr-3"}} From 92dd24716d22bbb849365605a13b94e8897d06fd Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 16 Nov 2022 19:14:58 +0800 Subject: [PATCH 036/149] Ignore issue template with a special name (#21830) A file in `ISSUE_TEMPLATE` with the name `config.yml` shouldn't be treated as a YAML template, it's for [configuring the template chooser](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser). The old code tried to ignore the file, but it didn't work, caused by #20987. That's why the warning is displayed: image Note that this PR is not an implementation of `config.yml`, there will be another one to do it. --- modules/structs/issue.go | 6 ++--- modules/structs/issue_test.go | 43 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 modules/structs/issue_test.go diff --git a/modules/structs/issue.go b/modules/structs/issue.go index 70f5e1ba8e..25c6251fbf 100644 --- a/modules/structs/issue.go +++ b/modules/structs/issue.go @@ -5,7 +5,7 @@ package structs import ( - "path/filepath" + "path" "time" ) @@ -163,11 +163,11 @@ const ( // Type returns the type of IssueTemplate, can be "md", "yaml" or empty for known func (it IssueTemplate) Type() IssueTemplateType { - if it.Name == "config.yaml" || it.Name == "config.yml" { + if base := path.Base(it.FileName); base == "config.yaml" || base == "config.yml" { // ignore config.yaml which is a special configuration file return "" } - if ext := filepath.Ext(it.FileName); ext == ".md" { + if ext := path.Ext(it.FileName); ext == ".md" { return IssueTemplateTypeMarkdown } else if ext == ".yaml" || ext == ".yml" { return IssueTemplateTypeYaml diff --git a/modules/structs/issue_test.go b/modules/structs/issue_test.go new file mode 100644 index 0000000000..5312585d0f --- /dev/null +++ b/modules/structs/issue_test.go @@ -0,0 +1,43 @@ +// 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 structs + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIssueTemplate_Type(t *testing.T) { + tests := []struct { + fileName string + want IssueTemplateType + }{ + { + fileName: ".gitea/ISSUE_TEMPLATE/bug_report.yaml", + want: IssueTemplateTypeYaml, + }, + { + fileName: ".gitea/ISSUE_TEMPLATE/bug_report.md", + want: IssueTemplateTypeMarkdown, + }, + { + fileName: ".gitea/ISSUE_TEMPLATE/bug_report.txt", + want: "", + }, + { + fileName: ".gitea/ISSUE_TEMPLATE/config.yaml", + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.fileName, func(t *testing.T) { + it := IssueTemplate{ + FileName: tt.fileName, + } + assert.Equal(t, tt.want, it.Type()) + }) + } +} From c144942b23eb6e05a60526cc6d2b88b488ca75dd Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 17 Nov 2022 02:04:09 +0100 Subject: [PATCH 037/149] Tweak katex options (#21828) - Render directly into DOM, skipping string conversion - Add limiting options to prevent excessive size/macros - Remove invalid `display` option previously passed Ref: https://katex.org/docs/options.html Co-authored-by: John Olheiser --- web_src/js/markup/math.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/web_src/js/markup/math.js b/web_src/js/markup/math.js index 5790a327a5..d4e40d5be2 100644 --- a/web_src/js/markup/math.js +++ b/web_src/js/markup/math.js @@ -23,12 +23,14 @@ export async function renderMath() { for (const el of els) { const source = el.textContent; - const options = {display: el.classList.contains('display')}; + const nodeName = el.classList.contains('display') ? 'p' : 'span'; try { - const markup = katex.renderToString(source, options); - const tempEl = document.createElement(options.display ? 'p' : 'span'); - tempEl.innerHTML = markup; + const tempEl = document.createElement(nodeName); + katex.render(source, tempEl, { + maxSize: 25, + maxExpand: 50, + }); targetElement(el).replaceWith(tempEl); } catch (error) { displayError(el, error); From 43ab9324c579a393f778d6842c577a872d0e4265 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Thu, 17 Nov 2022 18:55:15 +0100 Subject: [PATCH 038/149] Fix setting HTTP headers after write (#21833) The headers can't be modified after it was send to the client. --- modules/context/context.go | 66 +++++++++++++++-------- routers/api/packages/rubygems/rubygems.go | 8 ++- routers/common/repo.go | 49 +++++++---------- routers/web/feed/profile.go | 2 - routers/web/web.go | 5 +- 5 files changed, 72 insertions(+), 58 deletions(-) diff --git a/modules/context/context.go b/modules/context/context.go index 4b6a21b217..697eb76904 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -34,6 +34,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/services/auth" @@ -322,9 +323,9 @@ func (ctx *Context) plainTextInternal(skip, status int, bs []byte) { if statusPrefix == 4 || statusPrefix == 5 { log.Log(skip, log.TRACE, "plainTextInternal (status=%d): %s", status, string(bs)) } - ctx.Resp.WriteHeader(status) ctx.Resp.Header().Set("Content-Type", "text/plain;charset=utf-8") ctx.Resp.Header().Set("X-Content-Type-Options", "nosniff") + ctx.Resp.WriteHeader(status) if _, err := ctx.Resp.Write(bs); err != nil { log.ErrorWithSkip(skip, "plainTextInternal (status=%d): write bytes failed: %v", status, err) } @@ -345,36 +346,55 @@ func (ctx *Context) RespHeader() http.Header { return ctx.Resp.Header() } +type ServeHeaderOptions struct { + ContentType string // defaults to "application/octet-stream" + ContentTypeCharset string + Disposition string // defaults to "attachment" + Filename string + CacheDuration time.Duration // defaults to 5 minutes +} + // SetServeHeaders sets necessary content serve headers -func (ctx *Context) SetServeHeaders(filename string) { - ctx.Resp.Header().Set("Content-Description", "File Transfer") - ctx.Resp.Header().Set("Content-Type", "application/octet-stream") - ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+filename) - ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary") - ctx.Resp.Header().Set("Expires", "0") - ctx.Resp.Header().Set("Cache-Control", "must-revalidate") - ctx.Resp.Header().Set("Pragma", "public") - ctx.Resp.Header().Set("Access-Control-Expose-Headers", "Content-Disposition") +func (ctx *Context) SetServeHeaders(opts *ServeHeaderOptions) { + header := ctx.Resp.Header() + + contentType := typesniffer.ApplicationOctetStream + if opts.ContentType != "" { + if opts.ContentTypeCharset != "" { + contentType = opts.ContentType + "; charset=" + strings.ToLower(opts.ContentTypeCharset) + } else { + contentType = opts.ContentType + } + } + header.Set("Content-Type", contentType) + header.Set("X-Content-Type-Options", "nosniff") + + if opts.Filename != "" { + disposition := opts.Disposition + if disposition == "" { + disposition = "attachment" + } + + backslashEscapedName := strings.ReplaceAll(strings.ReplaceAll(opts.Filename, `\`, `\\`), `"`, `\"`) // \ -> \\, " -> \" + header.Set("Content-Disposition", fmt.Sprintf(`%s; filename="%s"; filename*=UTF-8''%s`, disposition, backslashEscapedName, url.PathEscape(opts.Filename))) + header.Set("Access-Control-Expose-Headers", "Content-Disposition") + } + + duration := opts.CacheDuration + if duration == 0 { + duration = 5 * time.Minute + } + httpcache.AddCacheControlToHeader(header, duration) } // ServeContent serves content to http request func (ctx *Context) ServeContent(name string, r io.ReadSeeker, modTime time.Time) { - ctx.SetServeHeaders(name) + ctx.SetServeHeaders(&ServeHeaderOptions{ + Filename: name, + }) http.ServeContent(ctx.Resp, ctx.Req, name, modTime, r) } -// ServeFile serves given file to response. -func (ctx *Context) ServeFile(file string, names ...string) { - var name string - if len(names) > 0 { - name = names[0] - } else { - name = path.Base(file) - } - ctx.SetServeHeaders(name) - http.ServeFile(ctx.Resp, ctx.Req, file) -} - // UploadStream returns the request body or the first form file // Only form files need to get closed. func (ctx *Context) UploadStream() (rd io.ReadCloser, needToClose bool, err error) { diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go index eeae21146c..4adfb15731 100644 --- a/routers/api/packages/rubygems/rubygems.go +++ b/routers/api/packages/rubygems/rubygems.go @@ -77,7 +77,9 @@ func enumeratePackages(ctx *context.Context, filename string, pvs []*packages_mo }) } - ctx.SetServeHeaders(filename + ".gz") + ctx.SetServeHeaders(&context.ServeHeaderOptions{ + Filename: filename + ".gz", + }) zw := gzip.NewWriter(ctx.Resp) defer zw.Close() @@ -115,7 +117,9 @@ func ServePackageSpecification(ctx *context.Context) { return } - ctx.SetServeHeaders(filename) + ctx.SetServeHeaders(&context.ServeHeaderOptions{ + Filename: filename, + }) zw := zlib.NewWriter(ctx.Resp) defer zw.Close() diff --git a/routers/common/repo.go b/routers/common/repo.go index a9e80fad48..f4b813d6b4 100644 --- a/routers/common/repo.go +++ b/routers/common/repo.go @@ -7,7 +7,6 @@ package common import ( "fmt" "io" - "net/url" "path" "path/filepath" "strings" @@ -53,50 +52,44 @@ func ServeData(ctx *context.Context, filePath string, size int64, reader io.Read buf = buf[:n] } - httpcache.AddCacheControlToHeader(ctx.Resp.Header(), 5*time.Minute) - if size >= 0 { ctx.Resp.Header().Set("Content-Length", fmt.Sprintf("%d", size)) } else { log.Error("ServeData called to serve data: %s with size < 0: %d", filePath, size) } - fileName := path.Base(filePath) - sniffedType := typesniffer.DetectContentType(buf) - isPlain := sniffedType.IsText() || ctx.FormBool("render") - mimeType := "" - charset := "" - - if setting.MimeTypeMap.Enabled { - fileExtension := strings.ToLower(filepath.Ext(fileName)) - mimeType = setting.MimeTypeMap.Map[fileExtension] + opts := &context.ServeHeaderOptions{ + Filename: path.Base(filePath), } - if mimeType == "" { + sniffedType := typesniffer.DetectContentType(buf) + isPlain := sniffedType.IsText() || ctx.FormBool("render") + + if setting.MimeTypeMap.Enabled { + fileExtension := strings.ToLower(filepath.Ext(filePath)) + opts.ContentType = setting.MimeTypeMap.Map[fileExtension] + } + + if opts.ContentType == "" { if sniffedType.IsBrowsableBinaryType() { - mimeType = sniffedType.GetMimeType() + opts.ContentType = sniffedType.GetMimeType() } else if isPlain { - mimeType = "text/plain" + opts.ContentType = "text/plain" } else { - mimeType = typesniffer.ApplicationOctetStream + opts.ContentType = typesniffer.ApplicationOctetStream } } if isPlain { + var charset string charset, err = charsetModule.DetectEncoding(buf) if err != nil { log.Error("Detect raw file %s charset failed: %v, using by default utf-8", filePath, err) charset = "utf-8" } + opts.ContentTypeCharset = strings.ToLower(charset) } - if charset != "" { - ctx.Resp.Header().Set("Content-Type", mimeType+"; charset="+strings.ToLower(charset)) - } else { - ctx.Resp.Header().Set("Content-Type", mimeType) - } - ctx.Resp.Header().Set("X-Content-Type-Options", "nosniff") - isSVG := sniffedType.IsSvgImage() // serve types that can present a security risk with CSP @@ -109,16 +102,12 @@ func ServeData(ctx *context.Context, filePath string, size int64, reader io.Read ctx.Resp.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'") } - disposition := "inline" + opts.Disposition = "inline" if isSVG && !setting.UI.SVG.Enabled { - disposition = "attachment" + opts.Disposition = "attachment" } - // encode filename per https://datatracker.ietf.org/doc/html/rfc5987 - encodedFileName := `filename*=UTF-8''` + url.PathEscape(fileName) - - ctx.Resp.Header().Set("Content-Disposition", disposition+"; "+encodedFileName) - ctx.Resp.Header().Set("Access-Control-Expose-Headers", "Content-Disposition") + ctx.SetServeHeaders(opts) _, err = ctx.Resp.Write(buf) if err != nil { diff --git a/routers/web/feed/profile.go b/routers/web/feed/profile.go index 0e11f210ce..ffa34572bc 100644 --- a/routers/web/feed/profile.go +++ b/routers/web/feed/profile.go @@ -5,7 +5,6 @@ package feed import ( - "net/http" "time" activities_model "code.gitea.io/gitea/models/activities" @@ -59,7 +58,6 @@ func showUserFeed(ctx *context.Context, formatType string) { // writeFeed write a feeds.Feed as atom or rss to ctx.Resp func writeFeed(ctx *context.Context, feed *feeds.Feed, formatType string) { - ctx.Resp.WriteHeader(http.StatusOK) if formatType == "atom" { ctx.Resp.Header().Set("Content-Type", "application/atom+xml;charset=utf-8") if err := feed.WriteAtom(ctx.Resp); err != nil { diff --git a/routers/web/web.go b/routers/web/web.go index d0ee9c5eac..5fefbad88a 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -604,7 +604,10 @@ func RegisterRoutes(m *web.Route) { m.Group("", func() { m.Get("/favicon.ico", func(ctx *context.Context) { - ctx.ServeFile(path.Join(setting.StaticRootPath, "public/img/favicon.png")) + ctx.SetServeHeaders(&context.ServeHeaderOptions{ + Filename: "favicon.png", + }) + http.ServeFile(ctx.Resp, ctx.Req, path.Join(setting.StaticRootPath, "public/img/favicon.png")) }) m.Group("/{username}", func() { m.Get(".png", func(ctx *context.Context) { ctx.Error(http.StatusNotFound) }) From 88d5275614a82f01ddf728435803ff6000a2262e Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Thu, 17 Nov 2022 20:29:33 +0100 Subject: [PATCH 039/149] Do not allow Ghost access to limited visible user/org (#21849) The Ghost user should not be allowed to have access to a limited visible user/org. Co-authored-by: Lauris BH --- models/organization/org.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/models/organization/org.go b/models/organization/org.go index af9c1f307c..6bb982b281 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -458,8 +458,9 @@ func CountOrgs(opts FindOrgOptions) (int64, error) { // HasOrgOrUserVisible tells if the given user can see the given org or user func HasOrgOrUserVisible(ctx context.Context, orgOrUser, user *user_model.User) bool { - // Not SignedUser - if user == nil { + // If user is nil, it's an anonymous user/request. + // The Ghost user is handled like an anonymous user. + if user == nil || user.IsGhost() { return orgOrUser.Visibility == structs.VisibleTypePublic } From 6dbcf724accbd4041b655861db9083199ded4967 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Nov 2022 21:32:59 -0500 Subject: [PATCH 040/149] Bump loader-utils from 2.0.3 to 2.0.4 (#21852) Bumps [loader-utils](https://github.com/webpack/loader-utils) from 2.0.3 to 2.0.4.
Release notes

Sourced from loader-utils's releases.

v2.0.4

2.0.4 (2022-11-11)

Bug Fixes

Changelog

Sourced from loader-utils's changelog.

2.0.4 (2022-11-11)

Bug Fixes

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=loader-utils&package-manager=npm_and_yarn&previous-version=2.0.3&new-version=2.0.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language - `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language - `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language - `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/go-gitea/gitea/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index bf8d4b05e2..d46d3a15ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6182,9 +6182,9 @@ } }, "node_modules/loader-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", - "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -14465,9 +14465,9 @@ "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==" }, "loader-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", - "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", From 0b993a0d04c9e542f1584ce00eab7ee4af0321d2 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 18 Nov 2022 14:34:39 +0800 Subject: [PATCH 041/149] Fix "build from source" document to clarify the `bindata` tag is required. (#21853) --- docs/content/doc/installation/from-source.en-us.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/content/doc/installation/from-source.en-us.md b/docs/content/doc/installation/from-source.en-us.md index a6493598be..01a5e1eaee 100644 --- a/docs/content/doc/installation/from-source.en-us.md +++ b/docs/content/doc/installation/from-source.en-us.md @@ -94,7 +94,7 @@ are provided to keep the build process as simple as possible. Depending on requirements, the following build tags can be included. -- `bindata`: Build a single monolithic binary, with all assets included. +- `bindata`: Build a single monolithic binary, with all assets included. Required for production build. - `sqlite sqlite_unlock_notify`: Enable support for a [SQLite3](https://sqlite.org/) database. Suggested only for tiny installations. @@ -103,11 +103,10 @@ Depending on requirements, the following build tags can be included. available to PAM. - `gogit`: (EXPERIMENTAL) Use go-git variants of Git commands. -Bundling assets into the binary using the `bindata` build tag is recommended for -production deployments. It is possible to serve the static assets directly via a reverse proxy, -but in most cases it is not necessary, and assets should still be bundled in the binary. -You may want to exclude bindata while developing/testing Gitea. -To include assets, add the `bindata` tag: +Bundling all assets (JS/CSS/templates, etc) into the binary. Using the `bindata` build tag is required for +production deployments. You could exclude `bindata` when you are developing/testing Gitea or able to separate the assets correctly. + +To include all assets, use the `bindata` tag: ```bash TAGS="bindata" make build From 20385b52a3381964b3ab8b1708817b3578a76aca Mon Sep 17 00:00:00 2001 From: Gusted Date: Fri, 18 Nov 2022 15:23:34 +0100 Subject: [PATCH 042/149] Prevent dangling user redirects (#21856) - It's possible that the `user_redirect` table contains a user id that no longer exists. - Delete a user redirect upon deleting the user. - Add a check for these dangling user redirects to check-db-consistency. --- models/user.go | 1 + modules/doctor/dbconsistency.go | 3 +++ 2 files changed, 4 insertions(+) diff --git a/models/user.go b/models/user.go index 85f465127a..0fc28ff055 100644 --- a/models/user.go +++ b/models/user.go @@ -89,6 +89,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) (err error) &user_model.UserBadge{UserID: u.ID}, &pull_model.AutoMerge{DoerID: u.ID}, &pull_model.ReviewState{UserID: u.ID}, + &user_model.Redirect{RedirectUserID: u.ID}, ); err != nil { return fmt.Errorf("deleteBeans: %w", err) } diff --git a/modules/doctor/dbconsistency.go b/modules/doctor/dbconsistency.go index 7ae349908e..89d974a350 100644 --- a/modules/doctor/dbconsistency.go +++ b/modules/doctor/dbconsistency.go @@ -205,6 +205,9 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er // find stopwatches without existing issue genericOrphanCheck("Orphaned Stopwatches without existing Issue", "stopwatch", "issue", "stopwatch.issue_id=`issue`.id"), + // find redirects without existing user. + genericOrphanCheck("Orphaned Redirects without existing redirect user", + "user_redirect", "user", "user_redirect.redirect_user_id=`user`.id"), ) for _, c := range consistencyChecks { From 6da8bc6be9fedf8956b25680077941ed3f081d75 Mon Sep 17 00:00:00 2001 From: Percy Ma Date: Sat, 19 Nov 2022 01:01:06 +0800 Subject: [PATCH 043/149] chore: add webpack export type check (#21857) add webpack export type check Co-authored-by: techknowlogick --- webpack.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/webpack.config.js b/webpack.config.js index 2663242992..4ad5d69bbf 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -47,6 +47,7 @@ const filterCssImport = (url, ...args) => { return true; }; +/** @type {import("webpack").Configuration} */ export default { mode: isProduction ? 'production' : 'development', entry: { From 595d940daada0a50bf2d3e31c1849e5580810847 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 18 Nov 2022 18:54:32 +0100 Subject: [PATCH 044/149] Fix webpack license warning (#21815) #19999 introduced a indirect dependency with a license that was not on our allowlist yet which produced this warning during webpack: ```` WARNING in License: citeproc@2.4.62 has disallowed license CPAL-1.0 OR AGPL-1.0 ```` I've added both licenses to the allowed list and made it so webpack will now abort on such license errors so that we don't miss those next time. Co-authored-by: John Olheiser Co-authored-by: Lunny Xiao --- webpack.config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webpack.config.js b/webpack.config.js index 4ad5d69bbf..a8363051df 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -229,7 +229,8 @@ export default { override: { 'jquery.are-you-sure@*': {licenseName: 'MIT'}, }, - allow: '(Apache-2.0 OR BSD-2-Clause OR BSD-3-Clause OR MIT OR ISC)', + emitError: true, + allow: '(Apache-2.0 OR BSD-2-Clause OR BSD-3-Clause OR MIT OR ISC OR CPAL-1.0)', ignore: [ 'font-awesome', ], From fefdb7ffd11bbfbff66dae8e88681ec840dedfde Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 19 Nov 2022 05:02:30 +0100 Subject: [PATCH 045/149] Timeline and color tweaks (#21799) Followup to https://github.com/go-gitea/gitea/pull/21784. - Restore muted effect on timeline author and issuelist comment icon - Remove whitespace inside shared user templates, fixing link hover underline - Use shared author link template more - Use `bold` class instead of CSS - Fix grey-light color being too dark on arc-green - Add missing black-light color - Fix issuelist progress bar color - Fix various other cases of missing `.muted` Screenshot 2022-11-13 at 12 15 22 Screenshot 2022-11-13 at 12 16 52 Screenshot 2022-11-13 at 12 30 55 Screenshot 2022-11-13 at 12 41 03 Screenshot 2022-11-13 at 12 52 54 Screenshot 2022-11-13 at 12 56 16 Co-authored-by: Lauris BH Co-authored-by: techknowlogick Co-authored-by: wxiaoguang --- templates/explore/repo_list.tmpl | 6 +++--- templates/org/home.tmpl | 4 ++-- templates/repo/diff/comments.tmpl | 2 +- templates/repo/issue/view_content.tmpl | 4 ++-- .../repo/issue/view_content/comments.tmpl | 20 +++++++++---------- .../repo/issue/view_content/sidebar.tmpl | 2 +- templates/shared/issuelist.tmpl | 2 +- templates/shared/user/authorlink.tmpl | 4 +--- templates/shared/user/avatarlink.tmpl | 4 +--- templates/shared/user/namelink.tmpl | 4 +--- web_src/less/_base.less | 7 +++++-- web_src/less/_repository.less | 18 +++++++---------- web_src/less/shared/issuelist.less | 8 ++++++++ web_src/less/themes/theme-arc-green.less | 9 +++++---- 14 files changed, 47 insertions(+), 47 deletions(-) diff --git a/templates/explore/repo_list.tmpl b/templates/explore/repo_list.tmpl index 2a5c444dce..044af9522e 100644 --- a/templates/explore/repo_list.tmpl +++ b/templates/explore/repo_list.tmpl @@ -38,10 +38,10 @@ {{end}} -
+
{{if .PrimaryLanguage}} - - {{.PrimaryLanguage.Language}} + + {{.PrimaryLanguage.Language}} {{end}} {{if not $.DisableStars}} diff --git a/templates/org/home.tmpl b/templates/org/home.tmpl index 3ff86259d5..448639975f 100644 --- a/templates/org/home.tmpl +++ b/templates/org/home.tmpl @@ -68,8 +68,8 @@ {{end}} diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index 5d298f820c..647c662d51 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -11,7 +11,7 @@
{{if .OriginalAuthor}} - + {{svg (MigrationIcon $.root.Repository.GetOriginalURLHostname)}} {{.OriginalAuthor}} diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index de11846af7..0cb74e8182 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -30,7 +30,7 @@
{{if .Issue.OriginalAuthor}} - + {{svg (MigrationIcon .Repository.GetOriginalURLHostname)}} {{.Issue.OriginalAuthor}} @@ -45,7 +45,7 @@ {{avatar .Issue.Poster}} - {{.Issue.Poster.GetDisplayName}} + {{template "shared/user/authorlink" .Issue.Poster}} {{.locale.Tr "repo.issues.commented_at" (.Issue.HashTag|Escape) $createdStr | Safe}} {{end}} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 7ed8cf3bde..e9b7172d1b 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -25,7 +25,7 @@
{{if .OriginalAuthor}} - + {{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}} {{.OriginalAuthor}} @@ -42,9 +42,7 @@ {{end}} - - {{.Poster.GetDisplayName}} - + {{template "shared/user/authorlink" .Poster}} {{$.locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr | Safe}} {{end}} @@ -151,14 +149,14 @@ {{svg "octicon-bookmark"}} {{template "shared/user/avatarlink" .Poster}} {{if eq .RefAction 3}}{{end}} - + {{template "shared/user/authorlink" .Poster}} {{$.locale.Tr $refTr (.EventTag|Escape) $createdStr (.RefCommentHTMLURL|Escape) $refFrom | Safe}} {{if eq .RefAction 3}}{{end}}
{{else if eq .Type 4}} @@ -207,7 +205,7 @@ {{if .RemovedAssignee}} {{template "shared/user/avatarlink" .Assignee}} - {{.Assignee.GetDisplayName}} + {{template "shared/user/authorlink" .Assignee}} {{if eq .Poster.ID .Assignee.ID}} {{$.locale.Tr "repo.issues.remove_self_assignment" $createdStr | Safe}} {{else}} @@ -331,7 +329,7 @@
{{svg "octicon-plus"}} - + {{if eq .DependentIssue.RepoID .Issue.RepoID}} #{{.DependentIssue.Index}} {{.DependentIssue.Title}} {{else}} @@ -354,7 +352,7 @@
{{svg "octicon-trash"}} - + {{if eq .DependentIssue.RepoID .Issue.RepoID}} #{{.DependentIssue.Index}} {{.DependentIssue.Title}} {{else}} @@ -408,7 +406,7 @@
{{if .OriginalAuthor}} - + {{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}} {{.OriginalAuthor}} @@ -536,7 +534,7 @@ {{end}} {{if .OriginalAuthor}} - + {{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}} {{.OriginalAuthor}} diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index eb95674b13..af648387db 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -389,7 +389,7 @@ {{avatar $user}}
- {{$user.DisplayName}} + {{template "shared/user/authorlink" $user}}
{{$trackedtime}}
diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index 6fce412ffa..e8ad8406cd 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -160,7 +160,7 @@
{{if .NumComments}} - + {{svg "octicon-comment" 16 "mr-2"}}{{.NumComments}} {{end}} diff --git a/templates/shared/user/authorlink.tmpl b/templates/shared/user/authorlink.tmpl index 81c2a4ed5e..4a6672181f 100644 --- a/templates/shared/user/authorlink.tmpl +++ b/templates/shared/user/authorlink.tmpl @@ -1,3 +1 @@ - - {{.GetDisplayName}} - +{{.GetDisplayName}} diff --git a/templates/shared/user/avatarlink.tmpl b/templates/shared/user/avatarlink.tmpl index 40f5ee7129..90f5d96700 100644 --- a/templates/shared/user/avatarlink.tmpl +++ b/templates/shared/user/avatarlink.tmpl @@ -1,3 +1 @@ - - {{avatar .}} - +{{avatar .}} diff --git a/templates/shared/user/namelink.tmpl b/templates/shared/user/namelink.tmpl index 25dff36a78..a122f4f45b 100644 --- a/templates/shared/user/namelink.tmpl +++ b/templates/shared/user/namelink.tmpl @@ -1,3 +1 @@ - - {{.GetDisplayName}} - +{{.GetDisplayName}} diff --git a/web_src/less/_base.less b/web_src/less/_base.less index dc0e69c6d1..f2173d6d2b 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -79,6 +79,7 @@ --color-pink: #e03997; --color-brown: #a5673f; --color-grey: #888888; + --color-black: #1b1c1d; /* light variants - produced via Sass scale-color(color, $lightness: +25%) */ --color-red-light: #e45e5e; --color-orange-light: #f59555; @@ -92,9 +93,9 @@ --color-pink-light: #e86bb1; --color-brown-light: #c58b66; --color-grey-light: #a6a6a6; + --color-black-light: #525558; /* other colors */ --color-gold: #a1882b; - --color-black: #1b1c1d; --color-white: #ffffff; --color-diff-removed-word-bg: #fdb8c0; --color-diff-added-word-bg: #acf2bd; @@ -293,13 +294,15 @@ a, text-decoration-skip-ink: all; } -a.muted { +a.muted, +.muted-links a { color: inherit; } a:hover, a.muted:hover, a.muted:hover [class*="color-text"], +.muted-links a:hover, .ui.breadcrumb a:hover { color: var(--color-primary); } diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less index bf1fb53e2b..63f1f954a0 100644 --- a/web_src/less/_repository.less +++ b/web_src/less/_repository.less @@ -829,7 +829,7 @@ .timeline-avatar { position: absolute; - left: -72px; + left: -68px; img { width: 40px !important; @@ -846,7 +846,6 @@ .avatar img { width: 20px; height: 20px; - margin: 0 .25rem; vertical-align: middle; } @@ -981,10 +980,6 @@ margin-top: 4px; } - .author { - font-weight: 600; - } - .comment-form-reply .footer { padding-bottom: 1em; } @@ -1165,9 +1160,12 @@ padding-left: 15px; .detail { - font-size: .9rem; - margin-top: 5px; - margin-left: 8px; + margin-top: 4px; + margin-left: 14px; + + .svg { + margin-right: 2px; + } } .segments { @@ -2723,12 +2721,10 @@ a { color: var(--color-text); - text-decoration: none; } a:hover { color: var(--color-primary); - text-decoration: none; } } diff --git a/web_src/less/shared/issuelist.less b/web_src/less/shared/issuelist.less index 2dffe19909..8d4cfc46d4 100644 --- a/web_src/less/shared/issuelist.less +++ b/web_src/less/shared/issuelist.less @@ -91,6 +91,14 @@ border-radius: 3px; vertical-align: 2px !important; } + + progress::-webkit-progress-value { + background-color: var(--color-secondary-dark-4); + } + + progress::-moz-progress-bar { + background-color: var(--color-secondary-dark-4); + } } .conflicting { diff --git a/web_src/less/themes/theme-arc-green.less b/web_src/less/themes/theme-arc-green.less index 370a866abb..b793f99509 100644 --- a/web_src/less/themes/theme-arc-green.less +++ b/web_src/less/themes/theme-arc-green.less @@ -67,8 +67,9 @@ --color-purple: #b259d0; --color-pink: #d22e8b; --color-brown: #a47252; - --color-grey: #5e626a; - /* light variants */ + --color-grey: #9ea2aa; + --color-black: #1e222e; + /* light variants - produced via Sass scale-color(color, $lightness: -10%) */ --color-red-light: #c23636; --color-orange-light: #b84f0b; --color-yellow-light: #b88a03; @@ -80,9 +81,9 @@ --color-purple-light: #a742c9; --color-pink-light: #be297d; --color-brown-light: #94674a; - --color-grey-light: #55585f; + --color-grey-light: #8d919b; + --color-black-light: #1b1f29; /* other colors */ - --color-black: #1e222e; --color-gold: #b1983b; --color-white: #ffffff; --color-diff-removed-word-bg: #6f3333; From 044c754ea53f5b81f451451df53aea366f6f700a Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Sat, 19 Nov 2022 09:12:33 +0100 Subject: [PATCH 046/149] Add `context.Context` to more methods (#21546) This PR adds a context parameter to a bunch of methods. Some helper `xxxCtx()` methods got replaced with the normal name now. Co-authored-by: delvh Co-authored-by: Lunny Xiao --- cmd/admin.go | 2 +- models/activities/action.go | 18 +- models/activities/action_test.go | 10 +- models/activities/notification.go | 96 +++--- models/activities/notification_test.go | 8 +- models/db/consistency.go | 15 +- models/db/engine_test.go | 4 +- models/db/sequence.go | 5 +- models/fixture_generation.go | 2 +- models/git/protected_tag.go | 17 +- models/git/protected_tag_test.go | 19 +- models/issues/assignees.go | 9 +- models/issues/assignees_test.go | 10 +- models/issues/comment.go | 63 ++-- models/issues/comment_list.go | 30 +- models/issues/issue.go | 120 +++---- models/issues/issue_list.go | 38 +-- models/issues/issue_list_test.go | 3 +- models/issues/issue_project.go | 12 +- models/issues/issue_test.go | 4 +- models/issues/issue_xref.go | 2 +- models/issues/label.go | 44 +-- models/issues/label_test.go | 4 +- models/issues/pull.go | 66 ++-- models/issues/pull_list.go | 2 +- models/issues/pull_test.go | 30 +- models/issues/review.go | 20 +- models/issues/review_test.go | 2 +- models/org_team_test.go | 2 +- models/perm/access/access_test.go | 14 +- models/perm/access/repo_permission.go | 12 +- models/repo/attachment.go | 12 +- models/repo/pushmirror.go | 4 +- models/repo/release.go | 16 +- models/repo/repo.go | 24 +- models/repo/repo_list.go | 11 +- models/repo/repo_list_test.go | 18 +- models/repo/user_repo.go | 10 +- models/user/user.go | 12 +- models/user/user_test.go | 8 +- modules/convert/issue.go | 29 +- modules/convert/issue_comment.go | 27 +- modules/convert/pull.go | 6 +- modules/convert/pull_test.go | 9 +- modules/doctor/dbconsistency.go | 22 +- modules/indexer/issues/indexer.go | 18 +- modules/notification/action/action.go | 117 +++---- modules/notification/action/action_test.go | 3 +- modules/notification/base/notifier.go | 90 ++--- modules/notification/base/null.go | 92 ++--- modules/notification/indexer/indexer.go | 44 +-- modules/notification/mail/mail.go | 91 ++--- modules/notification/mirror/mirror.go | 14 +- modules/notification/notification.go | 180 +++++----- modules/notification/ui/ui.go | 47 +-- modules/notification/webhook/webhook.go | 321 +++++++----------- modules/repository/repo.go | 2 +- routers/api/packages/conan/conan.go | 2 +- routers/api/v1/misc/nodeinfo.go | 2 +- routers/api/v1/notify/repo.go | 8 +- routers/api/v1/notify/threads.go | 8 +- routers/api/v1/notify/user.go | 8 +- routers/api/v1/org/team.go | 8 +- routers/api/v1/repo/branch.go | 12 +- routers/api/v1/repo/fork.go | 2 +- routers/api/v1/repo/issue.go | 28 +- routers/api/v1/repo/issue_comment.go | 24 +- routers/api/v1/repo/issue_reaction.go | 4 +- routers/api/v1/repo/issue_tracked_time.go | 10 +- routers/api/v1/repo/migrate.go | 2 +- routers/api/v1/repo/pull.go | 52 +-- routers/api/v1/repo/pull_review.go | 4 +- routers/api/v1/repo/release.go | 8 +- routers/api/v1/repo/release_attachment.go | 2 +- routers/api/v1/repo/release_tags.go | 2 +- routers/api/v1/repo/repo.go | 4 +- routers/api/v1/repo/wiki.go | 6 +- routers/api/v1/user/repo.go | 6 +- routers/api/v1/user/star.go | 11 +- routers/api/v1/user/watch.go | 11 +- routers/private/hook_post_receive.go | 2 +- routers/private/hook_pre_receive.go | 4 +- routers/web/explore/repo.go | 2 +- routers/web/home.go | 2 +- routers/web/org/home.go | 2 +- routers/web/repo/branch.go | 8 +- routers/web/repo/compare.go | 4 +- routers/web/repo/issue.go | 60 ++-- routers/web/repo/issue_label.go | 2 +- routers/web/repo/projects.go | 4 +- routers/web/repo/pull.go | 30 +- routers/web/repo/pull_review.go | 4 +- routers/web/repo/release.go | 8 +- routers/web/repo/repo.go | 2 +- routers/web/repo/tag.go | 4 +- routers/web/repo/wiki.go | 6 +- routers/web/user/home.go | 6 +- routers/web/user/notification.go | 220 ++++++------ routers/web/user/profile.go | 6 +- services/agit/agit.go | 10 +- services/asymkey/sign.go | 2 +- services/automerge/automerge.go | 8 +- services/comments/comments.go | 34 +- services/issue/assignee.go | 10 +- services/issue/content.go | 3 +- services/issue/issue.go | 18 +- services/issue/label.go | 10 +- services/issue/milestone.go | 2 +- services/issue/status.go | 2 +- services/lfs/locks.go | 8 +- services/mailer/mail.go | 9 +- services/mailer/mail_issue.go | 20 +- services/mailer/mail_release.go | 2 +- services/mailer/mail_repo.go | 6 +- services/migrations/gitea_uploader_test.go | 12 +- services/mirror/mirror_pull.go | 8 +- services/packages/packages.go | 6 +- services/pull/check.go | 14 +- services/pull/commit_status.go | 4 +- services/pull/edits.go | 2 +- services/pull/merge.go | 36 +- services/pull/patch.go | 2 +- services/pull/pull.go | 48 +-- services/pull/pull_test.go | 13 +- services/pull/review.go | 18 +- services/pull/temp_repo.go | 4 +- services/pull/update.go | 8 +- services/release/release.go | 42 +-- services/release/release_test.go | 12 +- services/repository/adopt.go | 2 +- services/repository/branch.go | 5 +- services/repository/fork.go | 2 +- services/repository/push.go | 14 +- services/repository/repository.go | 4 +- services/repository/template.go | 2 +- services/repository/transfer.go | 6 +- services/task/migrate.go | 2 +- services/user/user.go | 2 +- services/webhook/webhook.go | 2 +- .../user/notification/notification_div.tmpl | 5 +- tests/integration/api_comment_test.go | 5 +- tests/integration/api_issue_reaction_test.go | 2 +- tests/integration/api_notification_test.go | 5 +- tests/integration/api_pull_commits_test.go | 9 +- tests/integration/api_pull_test.go | 5 +- tests/integration/eventsource_test.go | 3 +- tests/integration/pull_update_test.go | 8 +- tests/integration/repo_tag_test.go | 9 +- 148 files changed, 1411 insertions(+), 1564 deletions(-) diff --git a/cmd/admin.go b/cmd/admin.go index d33d17a53d..80b5d4853c 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -727,7 +727,7 @@ func runRepoSyncReleases(_ *cli.Context) error { log.Trace("Synchronizing repository releases (this may take a while)") for page := 1; ; page++ { - repos, count, err := repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ + repos, count, err := repo_model.SearchRepositoryByName(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: repo_model.RepositoryListDefaultPageSize, Page: page, diff --git a/models/activities/action.go b/models/activities/action.go index 5c3419c5ec..bbb6073265 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -461,7 +461,8 @@ func DeleteOldActions(olderThan time.Duration) (err error) { return err } -func notifyWatchers(ctx context.Context, actions ...*Action) error { +// NotifyWatchers creates batch of actions for every watcher. +func NotifyWatchers(ctx context.Context, actions ...*Action) error { var watchers []*repo_model.Watch var repo *repo_model.Repository var err error @@ -565,11 +566,6 @@ func notifyWatchers(ctx context.Context, actions ...*Action) error { return nil } -// NotifyWatchers creates batch of actions for every watcher. -func NotifyWatchers(actions ...*Action) error { - return notifyWatchers(db.DefaultContext, actions...) -} - // NotifyWatchersActions creates batch of actions for every watcher. func NotifyWatchersActions(acts []*Action) error { ctx, committer, err := db.TxContext(db.DefaultContext) @@ -578,7 +574,7 @@ func NotifyWatchersActions(acts []*Action) error { } defer committer.Close() for _, act := range acts { - if err := notifyWatchers(ctx, act); err != nil { + if err := NotifyWatchers(ctx, act); err != nil { return err } } @@ -603,17 +599,17 @@ func DeleteIssueActions(ctx context.Context, repoID, issueID int64) error { } // CountActionCreatedUnixString count actions where created_unix is an empty string -func CountActionCreatedUnixString() (int64, error) { +func CountActionCreatedUnixString(ctx context.Context) (int64, error) { if setting.Database.UseSQLite3 { - return db.GetEngine(db.DefaultContext).Where(`created_unix = ""`).Count(new(Action)) + return db.GetEngine(ctx).Where(`created_unix = ""`).Count(new(Action)) } return 0, nil } // FixActionCreatedUnixString set created_unix to zero if it is an empty string -func FixActionCreatedUnixString() (int64, error) { +func FixActionCreatedUnixString(ctx context.Context) (int64, error) { if setting.Database.UseSQLite3 { - res, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`) + res, err := db.GetEngine(ctx).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`) if err != nil { return 0, err } diff --git a/models/activities/action_test.go b/models/activities/action_test.go index ac2a3043a6..b79eb0d08d 100644 --- a/models/activities/action_test.go +++ b/models/activities/action_test.go @@ -188,7 +188,7 @@ func TestNotifyWatchers(t *testing.T) { RepoID: 1, OpType: activities_model.ActionStarRepo, } - assert.NoError(t, activities_model.NotifyWatchers(action)) + assert.NoError(t, activities_model.NotifyWatchers(db.DefaultContext, action)) // One watchers are inactive, thus action is only created for user 8, 1, 4, 11 unittest.AssertExistsAndLoadBean(t, &activities_model.Action{ @@ -256,17 +256,17 @@ func TestConsistencyUpdateAction(t *testing.T) { // // Get rid of incorrectly set created_unix // - count, err := activities_model.CountActionCreatedUnixString() + count, err := activities_model.CountActionCreatedUnixString(db.DefaultContext) assert.NoError(t, err) assert.EqualValues(t, 1, count) - count, err = activities_model.FixActionCreatedUnixString() + count, err = activities_model.FixActionCreatedUnixString(db.DefaultContext) assert.NoError(t, err) assert.EqualValues(t, 1, count) - count, err = activities_model.CountActionCreatedUnixString() + count, err = activities_model.CountActionCreatedUnixString(db.DefaultContext) assert.NoError(t, err) assert.EqualValues(t, 0, count) - count, err = activities_model.FixActionCreatedUnixString() + count, err = activities_model.FixActionCreatedUnixString(db.DefaultContext) assert.NoError(t, err) assert.EqualValues(t, 0, count) diff --git a/models/activities/notification.go b/models/activities/notification.go index 28adc8cc4e..10b3a76713 100644 --- a/models/activities/notification.go +++ b/models/activities/notification.go @@ -136,49 +136,41 @@ func GetNotifications(ctx context.Context, options *FindNotificationOptions) (nl } // CountNotifications count all notifications that fit to the given options and ignore pagination. -func CountNotifications(opts *FindNotificationOptions) (int64, error) { - return db.GetEngine(db.DefaultContext).Where(opts.ToCond()).Count(&Notification{}) +func CountNotifications(ctx context.Context, opts *FindNotificationOptions) (int64, error) { + return db.GetEngine(ctx).Where(opts.ToCond()).Count(&Notification{}) } // CreateRepoTransferNotification creates notification for the user a repository was transferred to -func CreateRepoTransferNotification(doer, newOwner *user_model.User, repo *repo_model.Repository) error { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return err - } - defer committer.Close() +func CreateRepoTransferNotification(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) error { + return db.AutoTx(ctx, func(ctx context.Context) error { + var notify []*Notification - var notify []*Notification - - if newOwner.IsOrganization() { - users, err := organization.GetUsersWhoCanCreateOrgRepo(ctx, newOwner.ID) - if err != nil || len(users) == 0 { - return err - } - for i := range users { - notify = append(notify, &Notification{ - UserID: users[i].ID, + if newOwner.IsOrganization() { + users, err := organization.GetUsersWhoCanCreateOrgRepo(ctx, newOwner.ID) + if err != nil || len(users) == 0 { + return err + } + for i := range users { + notify = append(notify, &Notification{ + UserID: users[i].ID, + RepoID: repo.ID, + Status: NotificationStatusUnread, + UpdatedBy: doer.ID, + Source: NotificationSourceRepository, + }) + } + } else { + notify = []*Notification{{ + UserID: newOwner.ID, RepoID: repo.ID, Status: NotificationStatusUnread, UpdatedBy: doer.ID, Source: NotificationSourceRepository, - }) + }} } - } else { - notify = []*Notification{{ - UserID: newOwner.ID, - RepoID: repo.ID, - Status: NotificationStatusUnread, - UpdatedBy: doer.ID, - Source: NotificationSourceRepository, - }} - } - if err := db.Insert(ctx, notify); err != nil { - return err - } - - return committer.Commit() + return db.Insert(ctx, notify) + }) } // CreateOrUpdateIssueNotifications creates an issue notification @@ -379,11 +371,7 @@ func CountUnread(ctx context.Context, userID int64) int64 { } // LoadAttributes load Repo Issue User and Comment if not loaded -func (n *Notification) LoadAttributes() (err error) { - return n.loadAttributes(db.DefaultContext) -} - -func (n *Notification) loadAttributes(ctx context.Context) (err error) { +func (n *Notification) LoadAttributes(ctx context.Context) (err error) { if err = n.loadRepo(ctx); err != nil { return } @@ -481,10 +469,10 @@ func (n *Notification) APIURL() string { type NotificationList []*Notification // LoadAttributes load Repo Issue User and Comment if not loaded -func (nl NotificationList) LoadAttributes() error { +func (nl NotificationList) LoadAttributes(ctx context.Context) error { var err error for i := 0; i < len(nl); i++ { - err = nl[i].LoadAttributes() + err = nl[i].LoadAttributes(ctx) if err != nil && !issues_model.IsErrCommentNotExist(err) { return err } @@ -504,7 +492,7 @@ func (nl NotificationList) getPendingRepoIDs() []int64 { } // LoadRepos loads repositories from database -func (nl NotificationList) LoadRepos() (repo_model.RepositoryList, []int, error) { +func (nl NotificationList) LoadRepos(ctx context.Context) (repo_model.RepositoryList, []int, error) { if len(nl) == 0 { return repo_model.RepositoryList{}, []int{}, nil } @@ -517,7 +505,7 @@ func (nl NotificationList) LoadRepos() (repo_model.RepositoryList, []int, error) if left < limit { limit = left } - rows, err := db.GetEngine(db.DefaultContext). + rows, err := db.GetEngine(ctx). In("id", repoIDs[:limit]). Rows(new(repo_model.Repository)) if err != nil { @@ -578,7 +566,7 @@ func (nl NotificationList) getPendingIssueIDs() []int64 { } // LoadIssues loads issues from database -func (nl NotificationList) LoadIssues() ([]int, error) { +func (nl NotificationList) LoadIssues(ctx context.Context) ([]int, error) { if len(nl) == 0 { return []int{}, nil } @@ -591,7 +579,7 @@ func (nl NotificationList) LoadIssues() ([]int, error) { if left < limit { limit = left } - rows, err := db.GetEngine(db.DefaultContext). + rows, err := db.GetEngine(ctx). In("id", issueIDs[:limit]). Rows(new(issues_model.Issue)) if err != nil { @@ -662,7 +650,7 @@ func (nl NotificationList) getPendingCommentIDs() []int64 { } // LoadComments loads comments from database -func (nl NotificationList) LoadComments() ([]int, error) { +func (nl NotificationList) LoadComments(ctx context.Context) ([]int, error) { if len(nl) == 0 { return []int{}, nil } @@ -675,7 +663,7 @@ func (nl NotificationList) LoadComments() ([]int, error) { if left < limit { limit = left } - rows, err := db.GetEngine(db.DefaultContext). + rows, err := db.GetEngine(ctx). In("id", commentIDs[:limit]). Rows(new(issues_model.Comment)) if err != nil { @@ -775,8 +763,8 @@ func SetRepoReadBy(ctx context.Context, userID, repoID int64) error { } // SetNotificationStatus change the notification status -func SetNotificationStatus(notificationID int64, user *user_model.User, status NotificationStatus) (*Notification, error) { - notification, err := getNotificationByID(db.DefaultContext, notificationID) +func SetNotificationStatus(ctx context.Context, notificationID int64, user *user_model.User, status NotificationStatus) (*Notification, error) { + notification, err := GetNotificationByID(ctx, notificationID) if err != nil { return notification, err } @@ -787,16 +775,12 @@ func SetNotificationStatus(notificationID int64, user *user_model.User, status N notification.Status = status - _, err = db.GetEngine(db.DefaultContext).ID(notificationID).Update(notification) + _, err = db.GetEngine(ctx).ID(notificationID).Update(notification) return notification, err } // GetNotificationByID return notification by ID -func GetNotificationByID(notificationID int64) (*Notification, error) { - return getNotificationByID(db.DefaultContext, notificationID) -} - -func getNotificationByID(ctx context.Context, notificationID int64) (*Notification, error) { +func GetNotificationByID(ctx context.Context, notificationID int64) (*Notification, error) { notification := new(Notification) ok, err := db.GetEngine(ctx). Where("id = ?", notificationID). @@ -813,9 +797,9 @@ func getNotificationByID(ctx context.Context, notificationID int64) (*Notificati } // UpdateNotificationStatuses updates the statuses of all of a user's notifications that are of the currentStatus type to the desiredStatus -func UpdateNotificationStatuses(user *user_model.User, currentStatus, desiredStatus NotificationStatus) error { +func UpdateNotificationStatuses(ctx context.Context, user *user_model.User, currentStatus, desiredStatus NotificationStatus) error { n := &Notification{Status: desiredStatus, UpdatedBy: user.ID} - _, err := db.GetEngine(db.DefaultContext). + _, err := db.GetEngine(ctx). Where("user_id = ? AND status = ?", user.ID, currentStatus). Cols("status", "updated_by", "updated_unix"). Update(n) diff --git a/models/activities/notification_test.go b/models/activities/notification_test.go index 4ee16af076..d871891001 100644 --- a/models/activities/notification_test.go +++ b/models/activities/notification_test.go @@ -82,14 +82,14 @@ func TestSetNotificationStatus(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusRead}) - _, err := activities_model.SetNotificationStatus(notf.ID, user, activities_model.NotificationStatusPinned) + _, err := activities_model.SetNotificationStatus(db.DefaultContext, notf.ID, user, activities_model.NotificationStatusPinned) assert.NoError(t, err) unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{ID: notf.ID, Status: activities_model.NotificationStatusPinned}) - _, err = activities_model.SetNotificationStatus(1, user, activities_model.NotificationStatusRead) + _, err = activities_model.SetNotificationStatus(db.DefaultContext, 1, user, activities_model.NotificationStatusRead) assert.Error(t, err) - _, err = activities_model.SetNotificationStatus(unittest.NonexistentID, user, activities_model.NotificationStatusRead) + _, err = activities_model.SetNotificationStatus(db.DefaultContext, unittest.NonexistentID, user, activities_model.NotificationStatusRead) assert.Error(t, err) } @@ -102,7 +102,7 @@ func TestUpdateNotificationStatuses(t *testing.T) { &activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusRead}) notfPinned := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusPinned}) - assert.NoError(t, activities_model.UpdateNotificationStatuses(user, activities_model.NotificationStatusUnread, activities_model.NotificationStatusRead)) + assert.NoError(t, activities_model.UpdateNotificationStatuses(db.DefaultContext, user, activities_model.NotificationStatusUnread, activities_model.NotificationStatusRead)) unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{ID: notfUnread.ID, Status: activities_model.NotificationStatusRead}) unittest.AssertExistsAndLoadBean(t, diff --git a/models/db/consistency.go b/models/db/consistency.go index 7addb174c4..5a7878c74d 100644 --- a/models/db/consistency.go +++ b/models/db/consistency.go @@ -4,11 +4,16 @@ package db -import "xorm.io/builder" +import ( + "context" + + "xorm.io/builder" +) // CountOrphanedObjects count subjects with have no existing refobject anymore -func CountOrphanedObjects(subject, refobject, joinCond string) (int64, error) { - return GetEngine(DefaultContext).Table("`"+subject+"`"). +func CountOrphanedObjects(ctx context.Context, subject, refobject, joinCond string) (int64, error) { + return GetEngine(ctx). + Table("`"+subject+"`"). Join("LEFT", "`"+refobject+"`", joinCond). Where(builder.IsNull{"`" + refobject + "`.id"}). Select("COUNT(`" + subject + "`.`id`)"). @@ -16,12 +21,12 @@ func CountOrphanedObjects(subject, refobject, joinCond string) (int64, error) { } // DeleteOrphanedObjects delete subjects with have no existing refobject anymore -func DeleteOrphanedObjects(subject, refobject, joinCond string) error { +func DeleteOrphanedObjects(ctx context.Context, subject, refobject, joinCond string) error { subQuery := builder.Select("`"+subject+"`.id"). From("`"+subject+"`"). Join("LEFT", "`"+refobject+"`", joinCond). Where(builder.IsNull{"`" + refobject + "`.id"}) b := builder.Delete(builder.In("id", subQuery)).From("`" + subject + "`") - _, err := GetEngine(DefaultContext).Exec(b) + _, err := GetEngine(ctx).Exec(b) return err } diff --git a/models/db/engine_test.go b/models/db/engine_test.go index c26d94c340..c2ba9614aa 100644 --- a/models/db/engine_test.go +++ b/models/db/engine_test.go @@ -41,11 +41,11 @@ func TestDeleteOrphanedObjects(t *testing.T) { _, err = db.GetEngine(db.DefaultContext).Insert(&issues_model.PullRequest{IssueID: 1000}, &issues_model.PullRequest{IssueID: 1001}, &issues_model.PullRequest{IssueID: 1003}) assert.NoError(t, err) - orphaned, err := db.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id") + orphaned, err := db.CountOrphanedObjects(db.DefaultContext, "pull_request", "issue", "pull_request.issue_id=issue.id") assert.NoError(t, err) assert.EqualValues(t, 3, orphaned) - err = db.DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id") + err = db.DeleteOrphanedObjects(db.DefaultContext, "pull_request", "issue", "pull_request.issue_id=issue.id") assert.NoError(t, err) countAfter, err := db.GetEngine(db.DefaultContext).Count(&issues_model.PullRequest{}) diff --git a/models/db/sequence.go b/models/db/sequence.go index 48e4a8f1ac..0daacee70c 100644 --- a/models/db/sequence.go +++ b/models/db/sequence.go @@ -5,6 +5,7 @@ package db import ( + "context" "fmt" "regexp" @@ -12,7 +13,7 @@ import ( ) // CountBadSequences looks for broken sequences from recreate-table mistakes -func CountBadSequences() (int64, error) { +func CountBadSequences(_ context.Context) (int64, error) { if !setting.Database.UsePostgreSQL { return 0, nil } @@ -33,7 +34,7 @@ func CountBadSequences() (int64, error) { } // FixBadSequences fixes for broken sequences from recreate-table mistakes -func FixBadSequences() error { +func FixBadSequences(_ context.Context) error { if !setting.Database.UsePostgreSQL { return nil } diff --git a/models/fixture_generation.go b/models/fixture_generation.go index f4644859eb..50b983fa82 100644 --- a/models/fixture_generation.go +++ b/models/fixture_generation.go @@ -22,7 +22,7 @@ func GetYamlFixturesAccess() (string, error) { } for _, repo := range repos { - repo.MustOwner() + repo.MustOwner(db.DefaultContext) if err := access_model.RecalculateAccesses(db.DefaultContext, repo); err != nil { return "", err } diff --git a/models/git/protected_tag.go b/models/git/protected_tag.go index 7c3881643d..4640a77b20 100644 --- a/models/git/protected_tag.go +++ b/models/git/protected_tag.go @@ -5,6 +5,7 @@ package git import ( + "context" "regexp" "strings" @@ -69,13 +70,13 @@ func UpdateProtectedTag(pt *ProtectedTag) error { } // DeleteProtectedTag deletes a protected tag by ID -func DeleteProtectedTag(pt *ProtectedTag) error { - _, err := db.GetEngine(db.DefaultContext).ID(pt.ID).Delete(&ProtectedTag{}) +func DeleteProtectedTag(ctx context.Context, pt *ProtectedTag) error { + _, err := db.GetEngine(ctx).ID(pt.ID).Delete(&ProtectedTag{}) return err } // IsUserAllowedModifyTag returns true if the user is allowed to modify the tag -func IsUserAllowedModifyTag(pt *ProtectedTag, userID int64) (bool, error) { +func IsUserAllowedModifyTag(ctx context.Context, pt *ProtectedTag, userID int64) (bool, error) { if base.Int64sContains(pt.AllowlistUserIDs, userID) { return true, nil } @@ -84,7 +85,7 @@ func IsUserAllowedModifyTag(pt *ProtectedTag, userID int64) (bool, error) { return false, nil } - in, err := organization.IsUserInTeams(db.DefaultContext, userID, pt.AllowlistTeamIDs) + in, err := organization.IsUserInTeams(ctx, userID, pt.AllowlistTeamIDs) if err != nil { return false, err } @@ -92,9 +93,9 @@ func IsUserAllowedModifyTag(pt *ProtectedTag, userID int64) (bool, error) { } // GetProtectedTags gets all protected tags of the repository -func GetProtectedTags(repoID int64) ([]*ProtectedTag, error) { +func GetProtectedTags(ctx context.Context, repoID int64) ([]*ProtectedTag, error) { tags := make([]*ProtectedTag, 0) - return tags, db.GetEngine(db.DefaultContext).Find(&tags, &ProtectedTag{RepoID: repoID}) + return tags, db.GetEngine(ctx).Find(&tags, &ProtectedTag{RepoID: repoID}) } // GetProtectedTagByID gets the protected tag with the specific id @@ -112,7 +113,7 @@ func GetProtectedTagByID(id int64) (*ProtectedTag, error) { // IsUserAllowedToControlTag checks if a user can control the specific tag. // It returns true if the tag name is not protected or the user is allowed to control it. -func IsUserAllowedToControlTag(tags []*ProtectedTag, tagName string, userID int64) (bool, error) { +func IsUserAllowedToControlTag(ctx context.Context, tags []*ProtectedTag, tagName string, userID int64) (bool, error) { isAllowed := true for _, tag := range tags { err := tag.EnsureCompiledPattern() @@ -124,7 +125,7 @@ func IsUserAllowedToControlTag(tags []*ProtectedTag, tagName string, userID int6 continue } - isAllowed, err = IsUserAllowedModifyTag(tag, userID) + isAllowed, err = IsUserAllowedModifyTag(ctx, tag, userID) if err != nil { return false, err } diff --git a/models/git/protected_tag_test.go b/models/git/protected_tag_test.go index b496688b25..352eed0060 100644 --- a/models/git/protected_tag_test.go +++ b/models/git/protected_tag_test.go @@ -7,6 +7,7 @@ package git_test import ( "testing" + "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/unittest" @@ -17,29 +18,29 @@ func TestIsUserAllowed(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) pt := &git_model.ProtectedTag{} - allowed, err := git_model.IsUserAllowedModifyTag(pt, 1) + allowed, err := git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 1) assert.NoError(t, err) assert.False(t, allowed) pt = &git_model.ProtectedTag{ AllowlistUserIDs: []int64{1}, } - allowed, err = git_model.IsUserAllowedModifyTag(pt, 1) + allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 1) assert.NoError(t, err) assert.True(t, allowed) - allowed, err = git_model.IsUserAllowedModifyTag(pt, 2) + allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 2) assert.NoError(t, err) assert.False(t, allowed) pt = &git_model.ProtectedTag{ AllowlistTeamIDs: []int64{1}, } - allowed, err = git_model.IsUserAllowedModifyTag(pt, 1) + allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 1) assert.NoError(t, err) assert.False(t, allowed) - allowed, err = git_model.IsUserAllowedModifyTag(pt, 2) + allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 2) assert.NoError(t, err) assert.True(t, allowed) @@ -47,11 +48,11 @@ func TestIsUserAllowed(t *testing.T) { AllowlistUserIDs: []int64{1}, AllowlistTeamIDs: []int64{1}, } - allowed, err = git_model.IsUserAllowedModifyTag(pt, 1) + allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 1) assert.NoError(t, err) assert.True(t, allowed) - allowed, err = git_model.IsUserAllowedModifyTag(pt, 2) + allowed, err = git_model.IsUserAllowedModifyTag(db.DefaultContext, pt, 2) assert.NoError(t, err) assert.True(t, allowed) } @@ -135,7 +136,7 @@ func TestIsUserAllowedToControlTag(t *testing.T) { } for n, c := range cases { - isAllowed, err := git_model.IsUserAllowedToControlTag(protectedTags, c.name, c.userid) + isAllowed, err := git_model.IsUserAllowedToControlTag(db.DefaultContext, protectedTags, c.name, c.userid) assert.NoError(t, err) assert.Equal(t, c.allowed, isAllowed, "case %d: error should match", n) } @@ -157,7 +158,7 @@ func TestIsUserAllowedToControlTag(t *testing.T) { } for n, c := range cases { - isAllowed, err := git_model.IsUserAllowedToControlTag(protectedTags, c.name, c.userid) + isAllowed, err := git_model.IsUserAllowedToControlTag(db.DefaultContext, protectedTags, c.name, c.userid) assert.NoError(t, err) assert.Equal(t, c.allowed, isAllowed, "case %d: error should match", n) } diff --git a/models/issues/assignees.go b/models/issues/assignees.go index ce497b116d..19480fa1e1 100644 --- a/models/issues/assignees.go +++ b/models/issues/assignees.go @@ -48,9 +48,10 @@ func (issue *Issue) LoadAssignees(ctx context.Context) (err error) { // GetAssigneeIDsByIssue returns the IDs of users assigned to an issue // but skips joining with `user` for performance reasons. // User permissions must be verified elsewhere if required. -func GetAssigneeIDsByIssue(issueID int64) ([]int64, error) { +func GetAssigneeIDsByIssue(ctx context.Context, issueID int64) ([]int64, error) { userIDs := make([]int64, 0, 5) - return userIDs, db.GetEngine(db.DefaultContext).Table("issue_assignees"). + return userIDs, db.GetEngine(ctx). + Table("issue_assignees"). Cols("assignee_id"). Where("issue_id = ?", issueID). Distinct("assignee_id"). @@ -151,7 +152,7 @@ func toggleUserAssignee(ctx context.Context, issue *Issue, assigneeID int64) (re } // MakeIDsFromAPIAssigneesToAdd returns an array with all assignee IDs -func MakeIDsFromAPIAssigneesToAdd(oneAssignee string, multipleAssignees []string) (assigneeIDs []int64, err error) { +func MakeIDsFromAPIAssigneesToAdd(ctx context.Context, oneAssignee string, multipleAssignees []string) (assigneeIDs []int64, err error) { var requestAssignees []string // Keeping the old assigning method for compatibility reasons @@ -165,7 +166,7 @@ func MakeIDsFromAPIAssigneesToAdd(oneAssignee string, multipleAssignees []string } // Get the IDs of all assignees - assigneeIDs, err = user_model.GetUserIDsByNames(requestAssignees, false) + assigneeIDs, err = user_model.GetUserIDsByNames(ctx, requestAssignees, false) return assigneeIDs, err } diff --git a/models/issues/assignees_test.go b/models/issues/assignees_test.go index 291bb673da..4286bdd7ee 100644 --- a/models/issues/assignees_test.go +++ b/models/issues/assignees_test.go @@ -71,22 +71,22 @@ func TestMakeIDsFromAPIAssigneesToAdd(t *testing.T) { _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - IDs, err := issues_model.MakeIDsFromAPIAssigneesToAdd("", []string{""}) + IDs, err := issues_model.MakeIDsFromAPIAssigneesToAdd(db.DefaultContext, "", []string{""}) assert.NoError(t, err) assert.Equal(t, []int64{}, IDs) - _, err = issues_model.MakeIDsFromAPIAssigneesToAdd("", []string{"none_existing_user"}) + _, err = issues_model.MakeIDsFromAPIAssigneesToAdd(db.DefaultContext, "", []string{"none_existing_user"}) assert.Error(t, err) - IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd("user1", []string{"user1"}) + IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd(db.DefaultContext, "user1", []string{"user1"}) assert.NoError(t, err) assert.Equal(t, []int64{1}, IDs) - IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd("user2", []string{""}) + IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd(db.DefaultContext, "user2", []string{""}) assert.NoError(t, err) assert.Equal(t, []int64{2}, IDs) - IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd("", []string{"user1", "user2"}) + IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd(db.DefaultContext, "", []string{"user1", "user2"}) assert.NoError(t, err) assert.Equal(t, []int64{1, 2}, IDs) } diff --git a/models/issues/comment.go b/models/issues/comment.go index d71c675d23..9483814a19 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -309,13 +309,8 @@ type PushActionContent struct { CommitIDs []string `json:"commit_ids"` } -// LoadIssue loads issue from database -func (c *Comment) LoadIssue() (err error) { - return c.LoadIssueCtx(db.DefaultContext) -} - -// LoadIssueCtx loads issue from database -func (c *Comment) LoadIssueCtx(ctx context.Context) (err error) { +// LoadIssue loads the issue reference for the comment +func (c *Comment) LoadIssue(ctx context.Context) (err error) { if c.Issue != nil { return nil } @@ -350,7 +345,8 @@ func (c *Comment) AfterLoad(session *xorm.Session) { } } -func (c *Comment) loadPoster(ctx context.Context) (err error) { +// LoadPoster loads comment poster +func (c *Comment) LoadPoster(ctx context.Context) (err error) { if c.PosterID <= 0 || c.Poster != nil { return nil } @@ -381,7 +377,7 @@ func (c *Comment) AfterDelete() { // HTMLURL formats a URL-string to the issue-comment func (c *Comment) HTMLURL() string { - err := c.LoadIssue() + err := c.LoadIssue(db.DefaultContext) if err != nil { // Silently dropping errors :unamused: log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" @@ -410,7 +406,7 @@ func (c *Comment) HTMLURL() string { // APIURL formats a API-string to the issue-comment func (c *Comment) APIURL() string { - err := c.LoadIssue() + err := c.LoadIssue(db.DefaultContext) if err != nil { // Silently dropping errors :unamused: log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" @@ -426,7 +422,7 @@ func (c *Comment) APIURL() string { // IssueURL formats a URL-string to the issue func (c *Comment) IssueURL() string { - err := c.LoadIssue() + err := c.LoadIssue(db.DefaultContext) if err != nil { // Silently dropping errors :unamused: log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" @@ -446,7 +442,7 @@ func (c *Comment) IssueURL() string { // PRURL formats a URL-string to the pull-request func (c *Comment) PRURL() string { - err := c.LoadIssue() + err := c.LoadIssue(db.DefaultContext) if err != nil { // Silently dropping errors :unamused: log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" @@ -521,10 +517,10 @@ func (c *Comment) LoadProject() error { } // LoadMilestone if comment.Type is CommentTypeMilestone, then load milestone -func (c *Comment) LoadMilestone() error { +func (c *Comment) LoadMilestone(ctx context.Context) error { if c.OldMilestoneID > 0 { var oldMilestone Milestone - has, err := db.GetEngine(db.DefaultContext).ID(c.OldMilestoneID).Get(&oldMilestone) + has, err := db.GetEngine(ctx).ID(c.OldMilestoneID).Get(&oldMilestone) if err != nil { return err } else if has { @@ -534,7 +530,7 @@ func (c *Comment) LoadMilestone() error { if c.MilestoneID > 0 { var milestone Milestone - has, err := db.GetEngine(db.DefaultContext).ID(c.MilestoneID).Get(&milestone) + has, err := db.GetEngine(ctx).ID(c.MilestoneID).Get(&milestone) if err != nil { return err } else if has { @@ -544,19 +540,14 @@ func (c *Comment) LoadMilestone() error { return nil } -// LoadPoster loads comment poster -func (c *Comment) LoadPoster() error { - return c.loadPoster(db.DefaultContext) -} - // LoadAttachments loads attachments (it never returns error, the error during `GetAttachmentsByCommentIDCtx` is ignored) -func (c *Comment) LoadAttachments() error { +func (c *Comment) LoadAttachments(ctx context.Context) error { if len(c.Attachments) > 0 { return nil } var err error - c.Attachments, err = repo_model.GetAttachmentsByCommentID(db.DefaultContext, c.ID) + c.Attachments, err = repo_model.GetAttachmentsByCommentID(ctx, c.ID) if err != nil { log.Error("getAttachmentsByCommentID[%d]: %v", c.ID, err) } @@ -598,7 +589,7 @@ func (c *Comment) LoadAssigneeUserAndTeam() error { c.Assignee = user_model.NewGhostUser() } } else if c.AssigneeTeamID > 0 && c.AssigneeTeam == nil { - if err = c.LoadIssue(); err != nil { + if err = c.LoadIssue(db.DefaultContext); err != nil { return err } @@ -740,7 +731,7 @@ func (c *Comment) UnsignedLine() uint64 { // CodeCommentURL returns the url to a comment in code func (c *Comment) CodeCommentURL() string { - err := c.LoadIssue() + err := c.LoadIssue(db.DefaultContext) if err != nil { // Silently dropping errors :unamused: log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" @@ -1145,7 +1136,7 @@ func UpdateComment(c *Comment, doer *user_model.User) error { if _, err := sess.ID(c.ID).AllCols().Update(c); err != nil { return err } - if err := c.LoadIssueCtx(ctx); err != nil { + if err := c.LoadIssue(ctx); err != nil { return err } if err := c.AddCrossReferences(ctx, doer, true); err != nil { @@ -1245,7 +1236,7 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu return nil, err } - if err := CommentList(comments).loadPosters(ctx); err != nil { + if err := CommentList(comments).LoadPosters(ctx); err != nil { return nil, err } @@ -1363,11 +1354,11 @@ func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullReques if typ != CommentTypePRScheduledToAutoMerge && typ != CommentTypePRUnScheduledToAutoMerge { return nil, fmt.Errorf("comment type %d cannot be used to create an auto merge comment", typ) } - if err = pr.LoadIssueCtx(ctx); err != nil { + if err = pr.LoadIssue(ctx); err != nil { return } - if err = pr.LoadBaseRepoCtx(ctx); err != nil { + if err = pr.LoadBaseRepo(ctx); err != nil { return } @@ -1512,18 +1503,18 @@ func (c *Comment) GetExternalName() string { return c.OriginalAuthor } func (c *Comment) GetExternalID() int64 { return c.OriginalAuthorID } // CountCommentTypeLabelWithEmptyLabel count label comments with empty label -func CountCommentTypeLabelWithEmptyLabel() (int64, error) { - return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Count(new(Comment)) +func CountCommentTypeLabelWithEmptyLabel(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Count(new(Comment)) } // FixCommentTypeLabelWithEmptyLabel count label comments with empty label -func FixCommentTypeLabelWithEmptyLabel() (int64, error) { - return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Delete(new(Comment)) +func FixCommentTypeLabelWithEmptyLabel(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Delete(new(Comment)) } // CountCommentTypeLabelWithOutsideLabels count label comments with outside label -func CountCommentTypeLabelWithOutsideLabels() (int64, error) { - return db.GetEngine(db.DefaultContext).Where("comment.type = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id))", CommentTypeLabel). +func CountCommentTypeLabelWithOutsideLabels(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Where("comment.type = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id))", CommentTypeLabel). Table("comment"). Join("inner", "label", "label.id = comment.label_id"). Join("inner", "issue", "issue.id = comment.issue_id "). @@ -1532,8 +1523,8 @@ func CountCommentTypeLabelWithOutsideLabels() (int64, error) { } // FixCommentTypeLabelWithOutsideLabels count label comments with outside label -func FixCommentTypeLabelWithOutsideLabels() (int64, error) { - res, err := db.GetEngine(db.DefaultContext).Exec(`DELETE FROM comment WHERE comment.id IN ( +func FixCommentTypeLabelWithOutsideLabels(ctx context.Context) (int64, error) { + res, err := db.GetEngine(ctx).Exec(`DELETE FROM comment WHERE comment.id IN ( SELECT il_too.id FROM ( SELECT com.id FROM comment AS com diff --git a/models/issues/comment_list.go b/models/issues/comment_list.go index 70105d7ff0..e42b8605f9 100644 --- a/models/issues/comment_list.go +++ b/models/issues/comment_list.go @@ -24,7 +24,8 @@ func (comments CommentList) getPosterIDs() []int64 { return posterIDs.Values() } -func (comments CommentList) loadPosters(ctx context.Context) error { +// LoadPosters loads posters +func (comments CommentList) LoadPosters(ctx context.Context) error { if len(comments) == 0 { return nil } @@ -277,7 +278,8 @@ func (comments CommentList) Issues() IssueList { return issueList } -func (comments CommentList) loadIssues(ctx context.Context) error { +// LoadIssues loads issues of comments +func (comments CommentList) LoadIssues(ctx context.Context) error { if len(comments) == 0 { return nil } @@ -382,7 +384,8 @@ func (comments CommentList) loadDependentIssues(ctx context.Context) error { return nil } -func (comments CommentList) loadAttachments(ctx context.Context) (err error) { +// LoadAttachments loads attachments +func (comments CommentList) LoadAttachments(ctx context.Context) (err error) { if len(comments) == 0 { return nil } @@ -476,7 +479,7 @@ func (comments CommentList) loadReviews(ctx context.Context) error { //nolint // loadAttributes loads all attributes func (comments CommentList) loadAttributes(ctx context.Context) (err error) { - if err = comments.loadPosters(ctx); err != nil { + if err = comments.LoadPosters(ctx); err != nil { return } @@ -496,7 +499,7 @@ func (comments CommentList) loadAttributes(ctx context.Context) (err error) { return } - if err = comments.loadAttachments(ctx); err != nil { + if err = comments.LoadAttachments(ctx); err != nil { return } @@ -504,7 +507,7 @@ func (comments CommentList) loadAttributes(ctx context.Context) (err error) { return } - if err = comments.loadIssues(ctx); err != nil { + if err = comments.LoadIssues(ctx); err != nil { return } @@ -520,18 +523,3 @@ func (comments CommentList) loadAttributes(ctx context.Context) (err error) { func (comments CommentList) LoadAttributes() error { return comments.loadAttributes(db.DefaultContext) } - -// LoadAttachments loads attachments -func (comments CommentList) LoadAttachments() error { - return comments.loadAttachments(db.DefaultContext) -} - -// LoadPosters loads posters -func (comments CommentList) LoadPosters() error { - return comments.loadPosters(db.DefaultContext) -} - -// LoadIssues loads issues of comments -func (comments CommentList) LoadIssues() error { - return comments.loadIssues(db.DefaultContext) -} diff --git a/models/issues/issue.go b/models/issues/issue.go index c2f7cb6578..69d6657d46 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -241,11 +241,7 @@ func (issue *Issue) LoadLabels(ctx context.Context) (err error) { } // LoadPoster loads poster -func (issue *Issue) LoadPoster() error { - return issue.loadPoster(db.DefaultContext) -} - -func (issue *Issue) loadPoster(ctx context.Context) (err error) { +func (issue *Issue) LoadPoster(ctx context.Context) (err error) { if issue.Poster == nil { issue.Poster, err = user_model.GetUserByIDCtx(ctx, issue.PosterID) if err != nil { @@ -261,7 +257,8 @@ func (issue *Issue) loadPoster(ctx context.Context) (err error) { return err } -func (issue *Issue) loadPullRequest(ctx context.Context) (err error) { +// LoadPullRequest loads pull request info +func (issue *Issue) LoadPullRequest(ctx context.Context) (err error) { if issue.IsPull && issue.PullRequest == nil { issue.PullRequest, err = GetPullRequestByIssueID(ctx, issue.ID) if err != nil { @@ -275,18 +272,13 @@ func (issue *Issue) loadPullRequest(ctx context.Context) (err error) { return nil } -// LoadPullRequest loads pull request info -func (issue *Issue) LoadPullRequest() error { - return issue.loadPullRequest(db.DefaultContext) -} - func (issue *Issue) loadComments(ctx context.Context) (err error) { return issue.loadCommentsByType(ctx, CommentTypeUnknown) } // LoadDiscussComments loads discuss comments -func (issue *Issue) LoadDiscussComments() error { - return issue.loadCommentsByType(db.DefaultContext, CommentTypeComment) +func (issue *Issue) LoadDiscussComments(ctx context.Context) error { + return issue.loadCommentsByType(ctx, CommentTypeComment) } func (issue *Issue) loadCommentsByType(ctx context.Context, tp CommentType) (err error) { @@ -357,7 +349,8 @@ func (issue *Issue) loadForeignReference(ctx context.Context) (err error) { return nil } -func (issue *Issue) loadMilestone(ctx context.Context) (err error) { +// LoadMilestone load milestone of this issue. +func (issue *Issue) LoadMilestone(ctx context.Context) (err error) { if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 { issue.Milestone, err = GetMilestoneByRepoID(ctx, issue.RepoID, issue.MilestoneID) if err != nil && !IsErrMilestoneNotExist(err) { @@ -373,7 +366,7 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) { return } - if err = issue.loadPoster(ctx); err != nil { + if err = issue.LoadPoster(ctx); err != nil { return } @@ -381,7 +374,7 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) { return } - if err = issue.loadMilestone(ctx); err != nil { + if err = issue.LoadMilestone(ctx); err != nil { return } @@ -393,7 +386,7 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) { return } - if err = issue.loadPullRequest(ctx); err != nil && !IsErrPullRequestNotExist(err) { + if err = issue.LoadPullRequest(ctx); err != nil && !IsErrPullRequestNotExist(err) { // It is possible pull request is not yet created. return err } @@ -425,11 +418,6 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) { return issue.loadReactions(ctx) } -// LoadMilestone load milestone of this issue. -func (issue *Issue) LoadMilestone() error { - return issue.loadMilestone(db.DefaultContext) -} - // GetIsRead load the `IsRead` field of the issue func (issue *Issue) GetIsRead(userID int64) error { issueUser := &IssueUser{IssueID: issue.ID, UID: userID} @@ -548,7 +536,7 @@ func ClearIssueLabels(issue *Issue, doer *user_model.User) (err error) { if err := issue.LoadRepo(ctx); err != nil { return err - } else if err = issue.loadPullRequest(ctx); err != nil { + } else if err = issue.LoadPullRequest(ctx); err != nil { return err } @@ -751,7 +739,7 @@ func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, if err := issue.LoadRepo(ctx); err != nil { return nil, err } - if err := issue.loadPoster(ctx); err != nil { + if err := issue.LoadPoster(ctx); err != nil { return nil, err } @@ -1027,7 +1015,7 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue return fmt.Errorf("find all labels [label_ids: %v]: %w", opts.LabelIDs, err) } - if err = opts.Issue.loadPoster(ctx); err != nil { + if err = opts.Issue.LoadPoster(ctx); err != nil { return err } @@ -1505,10 +1493,9 @@ func applySubscribedCondition(sess *xorm.Session, subscriberID int64) *xorm.Sess } // CountIssuesByRepo map from repoID to number of issues matching the options -func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) { - e := db.GetEngine(db.DefaultContext) - - sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") +func CountIssuesByRepo(ctx context.Context, opts *IssuesOptions) (map[int64]int64, error) { + sess := db.GetEngine(ctx). + Join("INNER", "repository", "`issue`.repo_id = `repository`.id") opts.setupSessionNoLimit(sess) @@ -1551,10 +1538,9 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i } // Issues returns a list of issues by given conditions. -func Issues(opts *IssuesOptions) ([]*Issue, error) { - e := db.GetEngine(db.DefaultContext) - - sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") +func Issues(ctx context.Context, opts *IssuesOptions) ([]*Issue, error) { + sess := db.GetEngine(ctx). + Join("INNER", "repository", "`issue`.repo_id = `repository`.id") opts.setupSessionWithLimit(sess) sortIssuesSession(sess, opts.SortType, opts.PriorityRepoID) @@ -1572,11 +1558,11 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) { } // CountIssues number return of issues by given conditions. -func CountIssues(opts *IssuesOptions) (int64, error) { - e := db.GetEngine(db.DefaultContext) - - sess := e.Select("COUNT(issue.id) AS count").Table("issue") - sess.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") +func CountIssues(ctx context.Context, opts *IssuesOptions) (int64, error) { + sess := db.GetEngine(ctx). + Select("COUNT(issue.id) AS count"). + Table("issue"). + Join("INNER", "repository", "`issue`.repo_id = `repository`.id") opts.setupSessionNoLimit(sess) return sess.Count() @@ -1585,9 +1571,10 @@ func CountIssues(opts *IssuesOptions) (int64, error) { // GetParticipantsIDsByIssueID returns the IDs of all users who participated in comments of an issue, // but skips joining with `user` for performance reasons. // User permissions must be verified elsewhere if required. -func GetParticipantsIDsByIssueID(issueID int64) ([]int64, error) { +func GetParticipantsIDsByIssueID(ctx context.Context, issueID int64) ([]int64, error) { userIDs := make([]int64, 0, 5) - return userIDs, db.GetEngine(db.DefaultContext).Table("comment"). + return userIDs, db.GetEngine(ctx). + Table("comment"). Cols("poster_id"). Where("issue_id = ?", issueID). And("type in (?,?,?)", CommentTypeComment, CommentTypeCode, CommentTypeReview). @@ -2426,8 +2413,9 @@ func (issue *Issue) GetExternalName() string { return issue.OriginalAuthor } func (issue *Issue) GetExternalID() int64 { return issue.OriginalAuthorID } // CountOrphanedIssues count issues without a repo -func CountOrphanedIssues() (int64, error) { - return db.GetEngine(db.DefaultContext).Table("issue"). +func CountOrphanedIssues(ctx context.Context) (int64, error) { + return db.GetEngine(ctx). + Table("issue"). Join("LEFT", "repository", "issue.repo_id=repository.id"). Where(builder.IsNull{"repository.id"}). Select("COUNT(`issue`.`id`)"). @@ -2435,35 +2423,31 @@ func CountOrphanedIssues() (int64, error) { } // DeleteOrphanedIssues delete issues without a repo -func DeleteOrphanedIssues() error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func DeleteOrphanedIssues(ctx context.Context) error { + var attachmentPaths []string + err := db.AutoTx(ctx, func(ctx context.Context) error { + var ids []int64 + + if err := db.GetEngine(ctx).Table("issue").Distinct("issue.repo_id"). + Join("LEFT", "repository", "issue.repo_id=repository.id"). + Where(builder.IsNull{"repository.id"}).GroupBy("issue.repo_id"). + Find(&ids); err != nil { + return err + } + + for i := range ids { + paths, err := DeleteIssuesByRepoID(ctx, ids[i]) + if err != nil { + return err + } + attachmentPaths = append(attachmentPaths, paths...) + } + + return nil + }) if err != nil { return err } - defer committer.Close() - - var ids []int64 - - if err := db.GetEngine(ctx).Table("issue").Distinct("issue.repo_id"). - Join("LEFT", "repository", "issue.repo_id=repository.id"). - Where(builder.IsNull{"repository.id"}).GroupBy("issue.repo_id"). - Find(&ids); err != nil { - return err - } - - var attachmentPaths []string - for i := range ids { - paths, err := DeleteIssuesByRepoID(ctx, ids[i]) - if err != nil { - return err - } - attachmentPaths = append(attachmentPaths, paths...) - } - - if err := committer.Commit(); err != nil { - return err - } - committer.Close() // Remove issue attachment files. for i := range attachmentPaths { diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go index bbe2292dd1..d9dff4cb4d 100644 --- a/models/issues/issue_list.go +++ b/models/issues/issue_list.go @@ -34,7 +34,8 @@ func (issues IssueList) getRepoIDs() []int64 { return repoIDs.Values() } -func (issues IssueList) loadRepositories(ctx context.Context) ([]*repo_model.Repository, error) { +// LoadRepositories loads issues' all repositories +func (issues IssueList) LoadRepositories(ctx context.Context) ([]*repo_model.Repository, error) { if len(issues) == 0 { return nil, nil } @@ -73,11 +74,6 @@ func (issues IssueList) loadRepositories(ctx context.Context) ([]*repo_model.Rep return repo_model.ValuesRepository(repoMaps), nil } -// LoadRepositories loads issues' all repositories -func (issues IssueList) LoadRepositories() ([]*repo_model.Repository, error) { - return issues.loadRepositories(db.DefaultContext) -} - func (issues IssueList) getPosterIDs() []int64 { posterIDs := make(container.Set[int64], len(issues)) for _, issue := range issues { @@ -317,7 +313,8 @@ func (issues IssueList) getPullIssueIDs() []int64 { return ids } -func (issues IssueList) loadPullRequests(ctx context.Context) error { +// LoadPullRequests loads pull requests +func (issues IssueList) LoadPullRequests(ctx context.Context) error { issuesIDs := issues.getPullIssueIDs() if len(issuesIDs) == 0 { return nil @@ -361,7 +358,8 @@ func (issues IssueList) loadPullRequests(ctx context.Context) error { return nil } -func (issues IssueList) loadAttachments(ctx context.Context) (err error) { +// LoadAttachments loads attachments +func (issues IssueList) LoadAttachments(ctx context.Context) (err error) { if len(issues) == 0 { return nil } @@ -513,8 +511,8 @@ func (issues IssueList) loadTotalTrackedTimes(ctx context.Context) (err error) { // loadAttributes loads all attributes, expect for attachments and comments func (issues IssueList) loadAttributes(ctx context.Context) error { - if _, err := issues.loadRepositories(ctx); err != nil { - return fmt.Errorf("issue.loadAttributes: loadRepositories: %w", err) + if _, err := issues.LoadRepositories(ctx); err != nil { + return fmt.Errorf("issue.loadAttributes: LoadRepositories: %w", err) } if err := issues.loadPosters(ctx); err != nil { @@ -537,7 +535,7 @@ func (issues IssueList) loadAttributes(ctx context.Context) error { return fmt.Errorf("issue.loadAttributes: loadAssignees: %w", err) } - if err := issues.loadPullRequests(ctx); err != nil { + if err := issues.LoadPullRequests(ctx); err != nil { return fmt.Errorf("issue.loadAttributes: loadPullRequests: %w", err) } @@ -554,24 +552,14 @@ func (issues IssueList) LoadAttributes() error { return issues.loadAttributes(db.DefaultContext) } -// LoadAttachments loads attachments -func (issues IssueList) LoadAttachments() error { - return issues.loadAttachments(db.DefaultContext) -} - // LoadComments loads comments -func (issues IssueList) LoadComments() error { - return issues.loadComments(db.DefaultContext, builder.NewCond()) +func (issues IssueList) LoadComments(ctx context.Context) error { + return issues.loadComments(ctx, builder.NewCond()) } // LoadDiscussComments loads discuss comments -func (issues IssueList) LoadDiscussComments() error { - return issues.loadComments(db.DefaultContext, builder.Eq{"comment.type": CommentTypeComment}) -} - -// LoadPullRequests loads pull requests -func (issues IssueList) LoadPullRequests() error { - return issues.loadPullRequests(db.DefaultContext) +func (issues IssueList) LoadDiscussComments(ctx context.Context) error { + return issues.loadComments(ctx, builder.Eq{"comment.type": CommentTypeComment}) } // GetApprovalCounts returns a map of issue ID to slice of approval counts diff --git a/models/issues/issue_list_test.go b/models/issues/issue_list_test.go index f2cfca9bc0..c38a405e02 100644 --- a/models/issues/issue_list_test.go +++ b/models/issues/issue_list_test.go @@ -7,6 +7,7 @@ package issues_test import ( "testing" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/setting" @@ -23,7 +24,7 @@ func TestIssueList_LoadRepositories(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}), } - repos, err := issueList.LoadRepositories() + repos, err := issueList.LoadRepositories(db.DefaultContext) assert.NoError(t, err) assert.Len(t, repos, 2) for _, issue := range issueList { diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go index 0c59f4e82b..39a27abd3e 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -61,11 +61,11 @@ func (issue *Issue) projectBoardID(ctx context.Context) int64 { } // LoadIssuesFromBoard load issues assigned to this board -func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) { +func LoadIssuesFromBoard(ctx context.Context, b *project_model.Board) (IssueList, error) { issueList := make([]*Issue, 0, 10) if b.ID != 0 { - issues, err := Issues(&IssuesOptions{ + issues, err := Issues(ctx, &IssuesOptions{ ProjectBoardID: b.ID, ProjectID: b.ProjectID, SortType: "project-column-sorting", @@ -77,7 +77,7 @@ func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) { } if b.Default { - issues, err := Issues(&IssuesOptions{ + issues, err := Issues(ctx, &IssuesOptions{ ProjectBoardID: -1, // Issues without ProjectBoardID ProjectID: b.ProjectID, SortType: "project-column-sorting", @@ -88,7 +88,7 @@ func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) { issueList = append(issueList, issues...) } - if err := IssueList(issueList).LoadComments(); err != nil { + if err := IssueList(issueList).LoadComments(ctx); err != nil { return nil, err } @@ -96,10 +96,10 @@ func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) { } // LoadIssuesFromBoardList load issues assigned to the boards -func LoadIssuesFromBoardList(bs project_model.BoardList) (map[int64]IssueList, error) { +func LoadIssuesFromBoardList(ctx context.Context, bs project_model.BoardList) (map[int64]IssueList, error) { issuesMap := make(map[int64]IssueList, len(bs)) for i := range bs { - il, err := LoadIssuesFromBoard(bs[i]) + il, err := LoadIssuesFromBoard(ctx, bs[i]) if err != nil { return nil, err } diff --git a/models/issues/issue_test.go b/models/issues/issue_test.go index bef5d03e8a..2c8728e71a 100644 --- a/models/issues/issue_test.go +++ b/models/issues/issue_test.go @@ -189,7 +189,7 @@ func TestIssues(t *testing.T) { []int64{}, // issues with **both** label 1 and 2, none of these issues matches, TODO: add more tests }, } { - issues, err := issues_model.Issues(&test.Opts) + issues, err := issues_model.Issues(db.DefaultContext, &test.Opts) assert.NoError(t, err) if assert.Len(t, issues, len(test.ExpectedIssueIDs)) { for i, issue := range issues { @@ -556,7 +556,7 @@ func TestLoadTotalTrackedTime(t *testing.T) { func TestCountIssues(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - count, err := issues_model.CountIssues(&issues_model.IssuesOptions{}) + count, err := issues_model.CountIssues(db.DefaultContext, &issues_model.IssuesOptions{}) assert.NoError(t, err) assert.EqualValues(t, 17, count) } diff --git a/models/issues/issue_xref.go b/models/issues/issue_xref.go index e389f63d72..4c6601a0a2 100644 --- a/models/issues/issue_xref.go +++ b/models/issues/issue_xref.go @@ -235,7 +235,7 @@ func (c *Comment) AddCrossReferences(stdCtx context.Context, doer *user_model.Us if c.Type != CommentTypeCode && c.Type != CommentTypeComment { return nil } - if err := c.LoadIssueCtx(stdCtx); err != nil { + if err := c.LoadIssue(stdCtx); err != nil { return err } ctx := &crossReferencesContext{ diff --git a/models/issues/label.go b/models/issues/label.go index 0b0d1419b1..dc7058d643 100644 --- a/models/issues/label.go +++ b/models/issues/label.go @@ -116,8 +116,8 @@ func (label *Label) CalOpenIssues() { } // CalOpenOrgIssues calculates the open issues of a label for a specific repo -func (label *Label) CalOpenOrgIssues(repoID, labelID int64) { - counts, _ := CountIssuesByRepo(&IssuesOptions{ +func (label *Label) CalOpenOrgIssues(ctx context.Context, repoID, labelID int64) { + counts, _ := CountIssuesByRepo(ctx, &IssuesOptions{ RepoID: repoID, LabelIDs: []int64{labelID}, IsClosed: util.OptionalBoolFalse, @@ -395,9 +395,9 @@ func BuildLabelNamesIssueIDsCondition(labelNames []string) *builder.Builder { // GetLabelsInRepoByIDs returns a list of labels by IDs in given repository, // it silently ignores label IDs that do not belong to the repository. -func GetLabelsInRepoByIDs(repoID int64, labelIDs []int64) ([]*Label, error) { +func GetLabelsInRepoByIDs(ctx context.Context, repoID int64, labelIDs []int64) ([]*Label, error) { labels := make([]*Label, 0, len(labelIDs)) - return labels, db.GetEngine(db.DefaultContext). + return labels, db.GetEngine(ctx). Where("repo_id = ?", repoID). In("id", labelIDs). Asc("name"). @@ -498,9 +498,9 @@ func GetLabelIDsInOrgByNames(orgID int64, labelNames []string) ([]int64, error) // GetLabelsInOrgByIDs returns a list of labels by IDs in given organization, // it silently ignores label IDs that do not belong to the organization. -func GetLabelsInOrgByIDs(orgID int64, labelIDs []int64) ([]*Label, error) { +func GetLabelsInOrgByIDs(ctx context.Context, orgID int64, labelIDs []int64) ([]*Label, error) { labels := make([]*Label, 0, len(labelIDs)) - return labels, db.GetEngine(db.DefaultContext). + return labels, db.GetEngine(ctx). Where("org_id = ?", orgID). In("id", labelIDs). Asc("name"). @@ -746,13 +746,13 @@ func DeleteLabelsByRepoID(ctx context.Context, repoID int64) error { } // CountOrphanedLabels return count of labels witch are broken and not accessible via ui anymore -func CountOrphanedLabels() (int64, error) { - noref, err := db.GetEngine(db.DefaultContext).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Count() +func CountOrphanedLabels(ctx context.Context) (int64, error) { + noref, err := db.GetEngine(ctx).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Count() if err != nil { return 0, err } - norepo, err := db.GetEngine(db.DefaultContext).Table("label"). + norepo, err := db.GetEngine(ctx).Table("label"). Where(builder.And( builder.Gt{"repo_id": 0}, builder.NotIn("repo_id", builder.Select("id").From("repository")), @@ -762,7 +762,7 @@ func CountOrphanedLabels() (int64, error) { return 0, err } - noorg, err := db.GetEngine(db.DefaultContext).Table("label"). + noorg, err := db.GetEngine(ctx).Table("label"). Where(builder.And( builder.Gt{"org_id": 0}, builder.NotIn("org_id", builder.Select("id").From("user")), @@ -776,14 +776,14 @@ func CountOrphanedLabels() (int64, error) { } // DeleteOrphanedLabels delete labels witch are broken and not accessible via ui anymore -func DeleteOrphanedLabels() error { +func DeleteOrphanedLabels(ctx context.Context) error { // delete labels with no reference - if _, err := db.GetEngine(db.DefaultContext).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Delete(new(Label)); err != nil { + if _, err := db.GetEngine(ctx).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Delete(new(Label)); err != nil { return err } // delete labels with none existing repos - if _, err := db.GetEngine(db.DefaultContext). + if _, err := db.GetEngine(ctx). Where(builder.And( builder.Gt{"repo_id": 0}, builder.NotIn("repo_id", builder.Select("id").From("repository")), @@ -793,7 +793,7 @@ func DeleteOrphanedLabels() error { } // delete labels with none existing orgs - if _, err := db.GetEngine(db.DefaultContext). + if _, err := db.GetEngine(ctx). Where(builder.And( builder.Gt{"org_id": 0}, builder.NotIn("org_id", builder.Select("id").From("user")), @@ -806,23 +806,23 @@ func DeleteOrphanedLabels() error { } // CountOrphanedIssueLabels return count of IssueLabels witch have no label behind anymore -func CountOrphanedIssueLabels() (int64, error) { - return db.GetEngine(db.DefaultContext).Table("issue_label"). +func CountOrphanedIssueLabels(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Table("issue_label"). NotIn("label_id", builder.Select("id").From("label")). Count() } // DeleteOrphanedIssueLabels delete IssueLabels witch have no label behind anymore -func DeleteOrphanedIssueLabels() error { - _, err := db.GetEngine(db.DefaultContext). +func DeleteOrphanedIssueLabels(ctx context.Context) error { + _, err := db.GetEngine(ctx). NotIn("label_id", builder.Select("id").From("label")). Delete(IssueLabel{}) return err } // CountIssueLabelWithOutsideLabels count label comments with outside label -func CountIssueLabelWithOutsideLabels() (int64, error) { - return db.GetEngine(db.DefaultContext).Where(builder.Expr("(label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id)")). +func CountIssueLabelWithOutsideLabels(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Where(builder.Expr("(label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id)")). Table("issue_label"). Join("inner", "label", "issue_label.label_id = label.id "). Join("inner", "issue", "issue.id = issue_label.issue_id "). @@ -831,8 +831,8 @@ func CountIssueLabelWithOutsideLabels() (int64, error) { } // FixIssueLabelWithOutsideLabels fix label comments with outside label -func FixIssueLabelWithOutsideLabels() (int64, error) { - res, err := db.GetEngine(db.DefaultContext).Exec(`DELETE FROM issue_label WHERE issue_label.id IN ( +func FixIssueLabelWithOutsideLabels(ctx context.Context) (int64, error) { + res, err := db.GetEngine(ctx).Exec(`DELETE FROM issue_label WHERE issue_label.id IN ( SELECT il_too.id FROM ( SELECT il_too_too.id FROM issue_label AS il_too_too diff --git a/models/issues/label_test.go b/models/issues/label_test.go index 5e6cc9a2a0..077e0eeb67 100644 --- a/models/issues/label_test.go +++ b/models/issues/label_test.go @@ -121,7 +121,7 @@ func TestGetLabelInRepoByID(t *testing.T) { func TestGetLabelsInRepoByIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - labels, err := issues_model.GetLabelsInRepoByIDs(1, []int64{1, 2, unittest.NonexistentID}) + labels, err := issues_model.GetLabelsInRepoByIDs(db.DefaultContext, 1, []int64{1, 2, unittest.NonexistentID}) assert.NoError(t, err) if assert.Len(t, labels, 2) { assert.EqualValues(t, 1, labels[0].ID) @@ -212,7 +212,7 @@ func TestGetLabelInOrgByID(t *testing.T) { func TestGetLabelsInOrgByIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - labels, err := issues_model.GetLabelsInOrgByIDs(3, []int64{3, 4, unittest.NonexistentID}) + labels, err := issues_model.GetLabelsInOrgByIDs(db.DefaultContext, 3, []int64{3, 4, unittest.NonexistentID}) assert.NoError(t, err) if assert.Len(t, labels, 2) { assert.EqualValues(t, 3, labels[0].ID) diff --git a/models/issues/pull.go b/models/issues/pull.go index e906407d31..993a1ba8bd 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -205,8 +205,8 @@ func DeletePullsByBaseRepoID(ctx context.Context, repoID int64) error { } // MustHeadUserName returns the HeadRepo's username if failed return blank -func (pr *PullRequest) MustHeadUserName() string { - if err := pr.LoadHeadRepo(); err != nil { +func (pr *PullRequest) MustHeadUserName(ctx context.Context) string { + if err := pr.LoadHeadRepo(ctx); err != nil { if !repo_model.IsErrRepoNotExist(err) { log.Error("LoadHeadRepo: %v", err) } else { @@ -220,8 +220,9 @@ func (pr *PullRequest) MustHeadUserName() string { return pr.HeadRepo.OwnerName } +// LoadAttributes loads pull request attributes from database // Note: don't try to get Issue because will end up recursive querying. -func (pr *PullRequest) loadAttributes(ctx context.Context) (err error) { +func (pr *PullRequest) LoadAttributes(ctx context.Context) (err error) { if pr.HasMerged && pr.Merger == nil { pr.Merger, err = user_model.GetUserByIDCtx(ctx, pr.MergerID) if user_model.IsErrUserNotExist(err) { @@ -235,13 +236,8 @@ func (pr *PullRequest) loadAttributes(ctx context.Context) (err error) { return nil } -// LoadAttributes loads pull request attributes from database -func (pr *PullRequest) LoadAttributes() error { - return pr.loadAttributes(db.DefaultContext) -} - -// LoadHeadRepoCtx loads the head repository -func (pr *PullRequest) LoadHeadRepoCtx(ctx context.Context) (err error) { +// LoadHeadRepo loads the head repository +func (pr *PullRequest) LoadHeadRepo(ctx context.Context) (err error) { if !pr.isHeadRepoLoaded && pr.HeadRepo == nil && pr.HeadRepoID > 0 { if pr.HeadRepoID == pr.BaseRepoID { if pr.BaseRepo != nil { @@ -262,18 +258,8 @@ func (pr *PullRequest) LoadHeadRepoCtx(ctx context.Context) (err error) { return nil } -// LoadHeadRepo loads the head repository -func (pr *PullRequest) LoadHeadRepo() error { - return pr.LoadHeadRepoCtx(db.DefaultContext) -} - // LoadBaseRepo loads the target repository -func (pr *PullRequest) LoadBaseRepo() error { - return pr.LoadBaseRepoCtx(db.DefaultContext) -} - -// LoadBaseRepoCtx loads the target repository -func (pr *PullRequest) LoadBaseRepoCtx(ctx context.Context) (err error) { +func (pr *PullRequest) LoadBaseRepo(ctx context.Context) (err error) { if pr.BaseRepo != nil { return nil } @@ -296,12 +282,7 @@ func (pr *PullRequest) LoadBaseRepoCtx(ctx context.Context) (err error) { } // LoadIssue loads issue information from database -func (pr *PullRequest) LoadIssue() (err error) { - return pr.LoadIssueCtx(db.DefaultContext) -} - -// LoadIssueCtx loads issue information from database -func (pr *PullRequest) LoadIssueCtx(ctx context.Context) (err error) { +func (pr *PullRequest) LoadIssue(ctx context.Context) (err error) { if pr.Issue != nil { return nil } @@ -392,7 +373,7 @@ func (pr *PullRequest) getReviewedByLines(writer io.Writer) error { break } - if err := review.loadReviewer(ctx); err != nil && !user_model.IsErrUserNotExist(err) { + if err := review.LoadReviewer(ctx); err != nil && !user_model.IsErrUserNotExist(err) { log.Error("Unable to LoadReviewer[%d] for PR ID %d : %v", review.ReviewerID, pr.ID, err) return err } else if review.Reviewer == nil { @@ -458,7 +439,7 @@ func (pr *PullRequest) SetMerged(ctx context.Context) (bool, error) { } pr.Issue = nil - if err := pr.LoadIssueCtx(ctx); err != nil { + if err := pr.LoadIssue(ctx); err != nil { return false, err } @@ -541,9 +522,9 @@ func NewPullRequest(outerCtx context.Context, repo *repo_model.Repository, issue // GetUnmergedPullRequest returns a pull request that is open and has not been merged // by given head/base and repo/branch. -func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch string, flow PullRequestFlow) (*PullRequest, error) { +func GetUnmergedPullRequest(ctx context.Context, headRepoID, baseRepoID int64, headBranch, baseBranch string, flow PullRequestFlow) (*PullRequest, error) { pr := new(PullRequest) - has, err := db.GetEngine(db.DefaultContext). + has, err := db.GetEngine(ctx). Where("head_repo_id=? AND head_branch=? AND base_repo_id=? AND base_branch=? AND has_merged=? AND flow = ? AND issue.is_closed=?", headRepoID, headBranch, baseRepoID, baseBranch, false, flow, false). Join("INNER", "issue", "issue.id=pull_request.issue_id"). @@ -588,10 +569,10 @@ func GetPullRequestByIndex(ctx context.Context, repoID, index int64) (*PullReque return nil, ErrPullRequestNotExist{0, 0, 0, repoID, "", ""} } - if err = pr.loadAttributes(ctx); err != nil { + if err = pr.LoadAttributes(ctx); err != nil { return nil, err } - if err = pr.LoadIssueCtx(ctx); err != nil { + if err = pr.LoadIssue(ctx); err != nil { return nil, err } @@ -607,7 +588,7 @@ func GetPullRequestByID(ctx context.Context, id int64) (*PullRequest, error) { } else if !has { return nil, ErrPullRequestNotExist{id, 0, 0, 0, "", ""} } - return pr, pr.loadAttributes(ctx) + return pr, pr.LoadAttributes(ctx) } // GetPullRequestByIssueIDWithNoAttributes returns pull request with no attributes loaded by given issue ID. @@ -634,7 +615,7 @@ func GetPullRequestByIssueID(ctx context.Context, issueID int64) (*PullRequest, } else if !has { return nil, ErrPullRequestNotExist{0, issueID, 0, 0, "", ""} } - return pr, pr.loadAttributes(ctx) + return pr, pr.LoadAttributes(ctx) } // GetAllUnmergedAgitPullRequestByPoster get all unmerged agit flow pull request @@ -664,14 +645,15 @@ func (pr *PullRequest) UpdateCols(cols ...string) error { } // UpdateColsIfNotMerged updates specific fields of a pull request if it has not been merged -func (pr *PullRequest) UpdateColsIfNotMerged(cols ...string) error { - _, err := db.GetEngine(db.DefaultContext).Where("id = ? AND has_merged = ?", pr.ID, false).Cols(cols...).Update(pr) +func (pr *PullRequest) UpdateColsIfNotMerged(ctx context.Context, cols ...string) error { + _, err := db.GetEngine(ctx).Where("id = ? AND has_merged = ?", pr.ID, false).Cols(cols...).Update(pr) return err } // IsWorkInProgress determine if the Pull Request is a Work In Progress by its title +// Issue must be set before this method can be called. func (pr *PullRequest) IsWorkInProgress() bool { - if err := pr.LoadIssue(); err != nil { + if err := pr.LoadIssue(db.DefaultContext); err != nil { log.Error("LoadIssue: %v", err) return false } @@ -695,8 +677,8 @@ func (pr *PullRequest) IsFilesConflicted() bool { // GetWorkInProgressPrefix returns the prefix used to mark the pull request as a work in progress. // It returns an empty string when none were found -func (pr *PullRequest) GetWorkInProgressPrefix() string { - if err := pr.LoadIssue(); err != nil { +func (pr *PullRequest) GetWorkInProgressPrefix(ctx context.Context) string { + if err := pr.LoadIssue(ctx); err != nil { log.Error("LoadIssue: %v", err) return "" } @@ -739,7 +721,7 @@ func GetPullRequestsByHeadBranch(ctx context.Context, headBranch string, headRep // GetBaseBranchHTMLURL returns the HTML URL of the base branch func (pr *PullRequest) GetBaseBranchHTMLURL() string { - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepo(db.DefaultContext); err != nil { log.Error("LoadBaseRepo: %v", err) return "" } @@ -755,7 +737,7 @@ func (pr *PullRequest) GetHeadBranchHTMLURL() string { return "" } - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepo(db.DefaultContext); err != nil { log.Error("LoadHeadRepo: %v", err) return "" } diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go index c69f18492b..6110ba77fa 100644 --- a/models/issues/pull_list.go +++ b/models/issues/pull_list.go @@ -79,7 +79,7 @@ func CanMaintainerWriteToBranch(p access_model.Permission, branch string, user * for _, pr := range prs { if pr.AllowMaintainerEdit { - err = pr.LoadBaseRepo() + err = pr.LoadBaseRepo(db.DefaultContext) if err != nil { continue } diff --git a/models/issues/pull_test.go b/models/issues/pull_test.go index fb46e3071e..d88f9d4f54 100644 --- a/models/issues/pull_test.go +++ b/models/issues/pull_test.go @@ -17,7 +17,7 @@ import ( func TestPullRequest_LoadAttributes(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) - assert.NoError(t, pr.LoadAttributes()) + assert.NoError(t, pr.LoadAttributes(db.DefaultContext)) assert.NotNil(t, pr.Merger) assert.Equal(t, pr.MergerID, pr.Merger.ID) } @@ -25,10 +25,10 @@ func TestPullRequest_LoadAttributes(t *testing.T) { func TestPullRequest_LoadIssue(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) - assert.NoError(t, pr.LoadIssue()) + assert.NoError(t, pr.LoadIssue(db.DefaultContext)) assert.NotNil(t, pr.Issue) assert.Equal(t, int64(2), pr.Issue.ID) - assert.NoError(t, pr.LoadIssue()) + assert.NoError(t, pr.LoadIssue(db.DefaultContext)) assert.NotNil(t, pr.Issue) assert.Equal(t, int64(2), pr.Issue.ID) } @@ -36,10 +36,10 @@ func TestPullRequest_LoadIssue(t *testing.T) { func TestPullRequest_LoadBaseRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) - assert.NoError(t, pr.LoadBaseRepo()) + assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext)) assert.NotNil(t, pr.BaseRepo) assert.Equal(t, pr.BaseRepoID, pr.BaseRepo.ID) - assert.NoError(t, pr.LoadBaseRepo()) + assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext)) assert.NotNil(t, pr.BaseRepo) assert.Equal(t, pr.BaseRepoID, pr.BaseRepo.ID) } @@ -47,7 +47,7 @@ func TestPullRequest_LoadBaseRepo(t *testing.T) { func TestPullRequest_LoadHeadRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) - assert.NoError(t, pr.LoadHeadRepo()) + assert.NoError(t, pr.LoadHeadRepo(db.DefaultContext)) assert.NotNil(t, pr.HeadRepo) assert.Equal(t, pr.HeadRepoID, pr.HeadRepo.ID) } @@ -96,11 +96,11 @@ func TestPullRequestsOldest(t *testing.T) { func TestGetUnmergedPullRequest(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr, err := issues_model.GetUnmergedPullRequest(1, 1, "branch2", "master", issues_model.PullRequestFlowGithub) + pr, err := issues_model.GetUnmergedPullRequest(db.DefaultContext, 1, 1, "branch2", "master", issues_model.PullRequestFlowGithub) assert.NoError(t, err) assert.Equal(t, int64(2), pr.ID) - _, err = issues_model.GetUnmergedPullRequest(1, 9223372036854775807, "branch1", "master", issues_model.PullRequestFlowGithub) + _, err = issues_model.GetUnmergedPullRequest(db.DefaultContext, 1, 9223372036854775807, "branch1", "master", issues_model.PullRequestFlowGithub) assert.Error(t, err) assert.True(t, issues_model.IsErrPullRequestNotExist(err)) } @@ -228,7 +228,7 @@ func TestPullRequest_IsWorkInProgress(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) - pr.LoadIssue() + pr.LoadIssue(db.DefaultContext) assert.False(t, pr.IsWorkInProgress()) @@ -243,16 +243,16 @@ func TestPullRequest_GetWorkInProgressPrefixWorkInProgress(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) - pr.LoadIssue() + pr.LoadIssue(db.DefaultContext) - assert.Empty(t, pr.GetWorkInProgressPrefix()) + assert.Empty(t, pr.GetWorkInProgressPrefix(db.DefaultContext)) original := pr.Issue.Title pr.Issue.Title = "WIP: " + original - assert.Equal(t, "WIP:", pr.GetWorkInProgressPrefix()) + assert.Equal(t, "WIP:", pr.GetWorkInProgressPrefix(db.DefaultContext)) pr.Issue.Title = "[wip] " + original - assert.Equal(t, "[wip]", pr.GetWorkInProgressPrefix()) + assert.Equal(t, "[wip]", pr.GetWorkInProgressPrefix(db.DefaultContext)) } func TestDeleteOrphanedObjects(t *testing.T) { @@ -264,11 +264,11 @@ func TestDeleteOrphanedObjects(t *testing.T) { _, err = db.GetEngine(db.DefaultContext).Insert(&issues_model.PullRequest{IssueID: 1000}, &issues_model.PullRequest{IssueID: 1001}, &issues_model.PullRequest{IssueID: 1003}) assert.NoError(t, err) - orphaned, err := db.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id") + orphaned, err := db.CountOrphanedObjects(db.DefaultContext, "pull_request", "issue", "pull_request.issue_id=issue.id") assert.NoError(t, err) assert.EqualValues(t, 3, orphaned) - err = db.DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id") + err = db.DeleteOrphanedObjects(db.DefaultContext, "pull_request", "issue", "pull_request.issue_id=issue.id") assert.NoError(t, err) countAfter, err := db.GetEngine(db.DefaultContext).Count(&issues_model.PullRequest{}) diff --git a/models/issues/review.go b/models/issues/review.go index f66c70c1fc..5cf7d4c3da 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -154,7 +154,8 @@ func (r *Review) loadIssue(ctx context.Context) (err error) { return err } -func (r *Review) loadReviewer(ctx context.Context) (err error) { +// LoadReviewer loads reviewer +func (r *Review) LoadReviewer(ctx context.Context) (err error) { if r.ReviewerID == 0 || r.Reviewer != nil { return } @@ -162,7 +163,8 @@ func (r *Review) loadReviewer(ctx context.Context) (err error) { return err } -func (r *Review) loadReviewerTeam(ctx context.Context) (err error) { +// LoadReviewerTeam loads reviewer team +func (r *Review) LoadReviewerTeam(ctx context.Context) (err error) { if r.ReviewerTeamID == 0 || r.ReviewerTeam != nil { return } @@ -171,16 +173,6 @@ func (r *Review) loadReviewerTeam(ctx context.Context) (err error) { return err } -// LoadReviewer loads reviewer -func (r *Review) LoadReviewer() error { - return r.loadReviewer(db.DefaultContext) -} - -// LoadReviewerTeam loads reviewer team -func (r *Review) LoadReviewerTeam() error { - return r.loadReviewerTeam(db.DefaultContext) -} - // LoadAttributes loads all attributes except CodeComments func (r *Review) LoadAttributes(ctx context.Context) (err error) { if err = r.loadIssue(ctx); err != nil { @@ -189,10 +181,10 @@ func (r *Review) LoadAttributes(ctx context.Context) (err error) { if err = r.LoadCodeComments(ctx); err != nil { return } - if err = r.loadReviewer(ctx); err != nil { + if err = r.LoadReviewer(ctx); err != nil { return } - if err = r.loadReviewerTeam(ctx); err != nil { + if err = r.LoadReviewerTeam(ctx); err != nil { return } return err diff --git a/models/issues/review_test.go b/models/issues/review_test.go index 46d1cc777b..39ad14c65f 100644 --- a/models/issues/review_test.go +++ b/models/issues/review_test.go @@ -135,7 +135,7 @@ func TestGetReviewersByIssueID(t *testing.T) { allReviews, err := issues_model.GetReviewersByIssueID(issue.ID) for _, reviewer := range allReviews { - assert.NoError(t, reviewer.LoadReviewer()) + assert.NoError(t, reviewer.LoadReviewer(db.DefaultContext)) } assert.NoError(t, err) if assert.Len(t, allReviews, 3) { diff --git a/models/org_team_test.go b/models/org_team_test.go index a600d07c0c..3b1fabf1c3 100644 --- a/models/org_team_test.go +++ b/models/org_team_test.go @@ -143,7 +143,7 @@ func TestDeleteTeam(t *testing.T) { // check that team members don't have "leftover" access to repos user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) - accessMode, err := access_model.AccessLevel(user, repo) + accessMode, err := access_model.AccessLevel(db.DefaultContext, user, repo) assert.NoError(t, err) assert.True(t, accessMode < perm.AccessModeWrite) } diff --git a/models/perm/access/access_test.go b/models/perm/access/access_test.go index 7f58be4f39..dc707b971b 100644 --- a/models/perm/access/access_test.go +++ b/models/perm/access/access_test.go @@ -36,34 +36,34 @@ func TestAccessLevel(t *testing.T) { // org. owned private repo repo24 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 24}) - level, err := access_model.AccessLevel(user2, repo1) + level, err := access_model.AccessLevel(db.DefaultContext, user2, repo1) assert.NoError(t, err) assert.Equal(t, perm_model.AccessModeOwner, level) - level, err = access_model.AccessLevel(user2, repo3) + level, err = access_model.AccessLevel(db.DefaultContext, user2, repo3) assert.NoError(t, err) assert.Equal(t, perm_model.AccessModeOwner, level) - level, err = access_model.AccessLevel(user5, repo1) + level, err = access_model.AccessLevel(db.DefaultContext, user5, repo1) assert.NoError(t, err) assert.Equal(t, perm_model.AccessModeRead, level) - level, err = access_model.AccessLevel(user5, repo3) + level, err = access_model.AccessLevel(db.DefaultContext, user5, repo3) assert.NoError(t, err) assert.Equal(t, perm_model.AccessModeNone, level) // restricted user has no access to a public repo - level, err = access_model.AccessLevel(user29, repo1) + level, err = access_model.AccessLevel(db.DefaultContext, user29, repo1) assert.NoError(t, err) assert.Equal(t, perm_model.AccessModeNone, level) // ... unless he's a collaborator - level, err = access_model.AccessLevel(user29, repo4) + level, err = access_model.AccessLevel(db.DefaultContext, user29, repo4) assert.NoError(t, err) assert.Equal(t, perm_model.AccessModeWrite, level) // ... or a team member - level, err = access_model.AccessLevel(user29, repo24) + level, err = access_model.AccessLevel(db.DefaultContext, user29, repo24) assert.NoError(t, err) assert.Equal(t, perm_model.AccessModeRead, level) } diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index 93e3bdd6d8..3b709a3e85 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -326,17 +326,13 @@ func IsUserRepoAdmin(ctx context.Context, repo *repo_model.Repository, user *use // AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the // user does not have access. -func AccessLevel(user *user_model.User, repo *repo_model.Repository) (perm_model.AccessMode, error) { //nolint - return AccessLevelUnit(user, repo, unit.TypeCode) +func AccessLevel(ctx context.Context, user *user_model.User, repo *repo_model.Repository) (perm_model.AccessMode, error) { //nolint + return AccessLevelUnit(ctx, user, repo, unit.TypeCode) } // AccessLevelUnit returns the Access a user has to a repository's. Will return NoneAccess if the // user does not have access. -func AccessLevelUnit(user *user_model.User, repo *repo_model.Repository, unitType unit.Type) (perm_model.AccessMode, error) { //nolint - return accessLevelUnit(db.DefaultContext, user, repo, unitType) -} - -func accessLevelUnit(ctx context.Context, user *user_model.User, repo *repo_model.Repository, unitType unit.Type) (perm_model.AccessMode, error) { +func AccessLevelUnit(ctx context.Context, user *user_model.User, repo *repo_model.Repository, unitType unit.Type) (perm_model.AccessMode, error) { //nolint perm, err := GetUserRepoPermission(ctx, repo, user) if err != nil { return perm_model.AccessModeNone, err @@ -346,7 +342,7 @@ func accessLevelUnit(ctx context.Context, user *user_model.User, repo *repo_mode // HasAccessUnit returns true if user has testMode to the unit of the repository func HasAccessUnit(ctx context.Context, user *user_model.User, repo *repo_model.Repository, unitType unit.Type, testMode perm_model.AccessMode) (bool, error) { - mode, err := accessLevelUnit(ctx, user, repo, unitType) + mode, err := AccessLevelUnit(ctx, user, repo, unitType) return testMode <= mode, err } diff --git a/models/repo/attachment.go b/models/repo/attachment.go index df7528df09..428f370a0b 100644 --- a/models/repo/attachment.go +++ b/models/repo/attachment.go @@ -226,20 +226,20 @@ func UpdateAttachment(ctx context.Context, atta *Attachment) error { } // DeleteAttachmentsByRelease deletes all attachments associated with the given release. -func DeleteAttachmentsByRelease(releaseID int64) error { - _, err := db.GetEngine(db.DefaultContext).Where("release_id = ?", releaseID).Delete(&Attachment{}) +func DeleteAttachmentsByRelease(ctx context.Context, releaseID int64) error { + _, err := db.GetEngine(ctx).Where("release_id = ?", releaseID).Delete(&Attachment{}) return err } // CountOrphanedAttachments returns the number of bad attachments -func CountOrphanedAttachments() (int64, error) { - return db.GetEngine(db.DefaultContext).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))"). +func CountOrphanedAttachments(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))"). Count(new(Attachment)) } // DeleteOrphanedAttachments delete all bad attachments -func DeleteOrphanedAttachments() error { - _, err := db.GetEngine(db.DefaultContext).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))"). +func DeleteOrphanedAttachments(ctx context.Context) error { + _, err := db.GetEngine(ctx).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))"). Delete(new(Attachment)) return err } diff --git a/models/repo/pushmirror.go b/models/repo/pushmirror.go index 38d6e72019..fa876ee560 100644 --- a/models/repo/pushmirror.go +++ b/models/repo/pushmirror.go @@ -120,9 +120,9 @@ func GetPushMirrorsByRepoID(ctx context.Context, repoID int64, listOptions db.Li } // GetPushMirrorsSyncedOnCommit returns push-mirrors for this repo that should be updated by new commits -func GetPushMirrorsSyncedOnCommit(repoID int64) ([]*PushMirror, error) { +func GetPushMirrorsSyncedOnCommit(ctx context.Context, repoID int64) ([]*PushMirror, error) { mirrors := make([]*PushMirror, 0, 10) - return mirrors, db.GetEngine(db.DefaultContext). + return mirrors, db.GetEngine(ctx). Where("repo_id=? AND sync_on_commit=?", repoID, true). Find(&mirrors) } diff --git a/models/repo/release.go b/models/repo/release.go index 14428f15f7..a92e4bb6e5 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -90,7 +90,8 @@ func init() { db.RegisterModel(new(Release)) } -func (r *Release) loadAttributes(ctx context.Context) error { +// LoadAttributes load repo and publisher attributes for a release +func (r *Release) LoadAttributes(ctx context.Context) error { var err error if r.Repo == nil { r.Repo, err = GetRepositoryByIDCtx(ctx, r.RepoID) @@ -111,11 +112,6 @@ func (r *Release) loadAttributes(ctx context.Context) error { return GetReleaseAttachments(ctx, r) } -// LoadAttributes load repo and publisher attributes for a release -func (r *Release) LoadAttributes() error { - return r.loadAttributes(db.DefaultContext) -} - // APIURL the api url for a release. release must have attributes loaded func (r *Release) APIURL() string { return r.Repo.APIURL() + "/releases/" + strconv.FormatInt(r.ID, 10) @@ -241,8 +237,8 @@ func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond { } // GetReleasesByRepoID returns a list of releases of repository. -func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions) ([]*Release, error) { - sess := db.GetEngine(db.DefaultContext). +func GetReleasesByRepoID(ctx context.Context, repoID int64, opts FindReleasesOptions) ([]*Release, error) { + sess := db.GetEngine(ctx). Desc("created_unix", "id"). Where(opts.toConds(repoID)) @@ -381,8 +377,8 @@ func SortReleases(rels []*Release) { } // DeleteReleaseByID deletes a release from database by given ID. -func DeleteReleaseByID(id int64) error { - _, err := db.GetEngine(db.DefaultContext).ID(id).Delete(new(Release)) +func DeleteReleaseByID(ctx context.Context, id int64) error { + _, err := db.GetEngine(ctx).ID(id).Delete(new(Release)) return err } diff --git a/models/repo/repo.go b/models/repo/repo.go index 77e0367a5a..a3dac8383f 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -236,14 +236,6 @@ func (repo *Repository) AfterLoad() { repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects } -// MustOwner always returns a valid *user_model.User object to avoid -// conceptually impossible error handling. -// It creates a fake object that contains error details -// when error occurs. -func (repo *Repository) MustOwner() *user_model.User { - return repo.mustOwner(db.DefaultContext) -} - // LoadAttributes loads attributes of the repository. func (repo *Repository) LoadAttributes(ctx context.Context) error { // Load owner @@ -403,7 +395,11 @@ func (repo *Repository) GetOwner(ctx context.Context) (err error) { return err } -func (repo *Repository) mustOwner(ctx context.Context) *user_model.User { +// MustOwner always returns a valid *user_model.User object to avoid +// conceptually impossible error handling. +// It creates a fake object that contains error details +// when error occurs. +func (repo *Repository) MustOwner(ctx context.Context) *user_model.User { if err := repo.GetOwner(ctx); err != nil { return &user_model.User{ Name: "error", @@ -438,7 +434,7 @@ func (repo *Repository) ComposeMetas() map[string]string { } } - repo.MustOwner() + repo.MustOwner(db.DefaultContext) if repo.Owner.IsOrganization() { teams := make([]string, 0, 5) _ = db.GetEngine(db.DefaultContext).Table("team_repo"). @@ -792,13 +788,13 @@ func UpdateRepoIssueNumbers(ctx context.Context, repoID int64, isPull, isClosed } // CountNullArchivedRepository counts the number of repositories with is_archived is null -func CountNullArchivedRepository() (int64, error) { - return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Count(new(Repository)) +func CountNullArchivedRepository(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Where(builder.IsNull{"is_archived"}).Count(new(Repository)) } // FixNullArchivedRepository sets is_archived to false where it is null -func FixNullArchivedRepository() (int64, error) { - return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Cols("is_archived").NoAutoTime().Update(&Repository{ +func FixNullArchivedRepository(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Where(builder.IsNull{"is_archived"}).Cols("is_archived").NoAutoTime().Update(&Repository{ IsArchived: false, }) } diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index 191970d275..abfa73abb9 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -518,14 +518,13 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { // SearchRepository returns repositories based on search options, // it returns results in given range and number of total results. -func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) { +func SearchRepository(ctx context.Context, opts *SearchRepoOptions) (RepositoryList, int64, error) { cond := SearchRepositoryCondition(opts) - return SearchRepositoryByCondition(opts, cond, true) + return SearchRepositoryByCondition(ctx, opts, cond, true) } // SearchRepositoryByCondition search repositories by condition -func SearchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) { - ctx := db.DefaultContext +func SearchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) { sess, count, err := searchRepositoryByCondition(ctx, opts, cond) if err != nil { return nil, 0, err @@ -652,9 +651,9 @@ func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) bu // SearchRepositoryByName takes keyword and part of repository name to search, // it returns results in given range and number of total results. -func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, error) { +func SearchRepositoryByName(ctx context.Context, opts *SearchRepoOptions) (RepositoryList, int64, error) { opts.IncludeDescription = false - return SearchRepository(opts) + return SearchRepository(ctx, opts) } // SearchRepositoryIDs takes keyword and part of repository name to search, diff --git a/models/repo/repo_list_test.go b/models/repo/repo_list_test.go index f9c84a0f3f..926ed07e9e 100644 --- a/models/repo/repo_list_test.go +++ b/models/repo/repo_list_test.go @@ -20,7 +20,7 @@ func TestSearchRepository(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // test search public repository on explore page - repos, count, err := repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ + repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -35,7 +35,7 @@ func TestSearchRepository(t *testing.T) { } assert.Equal(t, int64(1), count) - repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -49,7 +49,7 @@ func TestSearchRepository(t *testing.T) { assert.Len(t, repos, 2) // test search private repository on explore page - repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -65,7 +65,7 @@ func TestSearchRepository(t *testing.T) { } assert.Equal(t, int64(1), count) - repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -80,14 +80,14 @@ func TestSearchRepository(t *testing.T) { assert.Len(t, repos, 3) // Test non existing owner - repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID}) + repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID}) assert.NoError(t, err) assert.Empty(t, repos) assert.Equal(t, int64(0), count) // Test search within description - repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -104,7 +104,7 @@ func TestSearchRepository(t *testing.T) { assert.Equal(t, int64(1), count) // Test NOT search within description - repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -277,7 +277,7 @@ func TestSearchRepository(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - repos, count, err := repo_model.SearchRepositoryByName(testCase.opts) + repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, testCase.opts) assert.NoError(t, err) assert.Equal(t, int64(testCase.count), count) @@ -377,7 +377,7 @@ func TestSearchRepositoryByTopicName(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - _, count, err := repo_model.SearchRepositoryByName(testCase.opts) + _, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, testCase.opts) assert.NoError(t, err) assert.Equal(t, int64(testCase.count), count) }) diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go index e7125f70f8..9ca367f556 100644 --- a/models/repo/user_repo.go +++ b/models/repo/user_repo.go @@ -17,8 +17,9 @@ import ( ) // GetStarredRepos returns the repos starred by a particular user -func GetStarredRepos(userID int64, private bool, listOptions db.ListOptions) ([]*Repository, error) { - sess := db.GetEngine(db.DefaultContext).Where("star.uid=?", userID). +func GetStarredRepos(ctx context.Context, userID int64, private bool, listOptions db.ListOptions) ([]*Repository, error) { + sess := db.GetEngine(ctx). + Where("star.uid=?", userID). Join("LEFT", "star", "`repository`.id=`star`.repo_id") if !private { sess = sess.And("is_private=?", false) @@ -36,8 +37,9 @@ func GetStarredRepos(userID int64, private bool, listOptions db.ListOptions) ([] } // GetWatchedRepos returns the repos watched by a particular user -func GetWatchedRepos(userID int64, private bool, listOptions db.ListOptions) ([]*Repository, int64, error) { - sess := db.GetEngine(db.DefaultContext).Where("watch.user_id=?", userID). +func GetWatchedRepos(ctx context.Context, userID int64, private bool, listOptions db.ListOptions) ([]*Repository, int64, error) { + sess := db.GetEngine(ctx). + Where("watch.user_id=?", userID). And("`watch`.mode<>?", WatchModeDont). Join("LEFT", "watch", "`repository`.id=`watch`.repo_id") if !private { diff --git a/models/user/user.go b/models/user/user.go index c36fc21c77..1a71acb0b7 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -1042,14 +1042,15 @@ func GetUserEmailsByNames(ctx context.Context, names []string) []string { } // GetMaileableUsersByIDs gets users from ids, but only if they can receive mails -func GetMaileableUsersByIDs(ids []int64, isMention bool) ([]*User, error) { +func GetMaileableUsersByIDs(ctx context.Context, ids []int64, isMention bool) ([]*User, error) { if len(ids) == 0 { return nil, nil } ous := make([]*User, 0, len(ids)) if isMention { - return ous, db.GetEngine(db.DefaultContext).In("id", ids). + return ous, db.GetEngine(ctx). + In("id", ids). Where("`type` = ?", UserTypeIndividual). And("`prohibit_login` = ?", false). And("`is_active` = ?", true). @@ -1057,7 +1058,8 @@ func GetMaileableUsersByIDs(ids []int64, isMention bool) ([]*User, error) { Find(&ous) } - return ous, db.GetEngine(db.DefaultContext).In("id", ids). + return ous, db.GetEngine(ctx). + In("id", ids). Where("`type` = ?", UserTypeIndividual). And("`prohibit_login` = ?", false). And("`is_active` = ?", true). @@ -1090,10 +1092,10 @@ func GetUserNameByID(ctx context.Context, id int64) (string, error) { } // GetUserIDsByNames returns a slice of ids corresponds to names. -func GetUserIDsByNames(names []string, ignoreNonExistent bool) ([]int64, error) { +func GetUserIDsByNames(ctx context.Context, names []string, ignoreNonExistent bool) ([]int64, error) { ids := make([]int64, 0, len(names)) for _, name := range names { - u, err := GetUserByName(db.DefaultContext, name) + u, err := GetUserByName(ctx, name) if err != nil { if ignoreNonExistent { continue diff --git a/models/user/user_test.go b/models/user/user_test.go index 5f2ac0a60c..1cdfb5978c 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -257,12 +257,12 @@ func TestGetUserIDsByNames(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // ignore non existing - IDs, err := user_model.GetUserIDsByNames([]string{"user1", "user2", "none_existing_user"}, true) + IDs, err := user_model.GetUserIDsByNames(db.DefaultContext, []string{"user1", "user2", "none_existing_user"}, true) assert.NoError(t, err) assert.Equal(t, []int64{1, 2}, IDs) // ignore non existing - IDs, err = user_model.GetUserIDsByNames([]string{"user1", "do_not_exist"}, false) + IDs, err = user_model.GetUserIDsByNames(db.DefaultContext, []string{"user1", "do_not_exist"}, false) assert.Error(t, err) assert.Equal(t, []int64(nil), IDs) } @@ -270,14 +270,14 @@ func TestGetUserIDsByNames(t *testing.T) { func TestGetMaileableUsersByIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - results, err := user_model.GetMaileableUsersByIDs([]int64{1, 4}, false) + results, err := user_model.GetMaileableUsersByIDs(db.DefaultContext, []int64{1, 4}, false) assert.NoError(t, err) assert.Len(t, results, 1) if len(results) > 1 { assert.Equal(t, results[0].ID, 1) } - results, err = user_model.GetMaileableUsersByIDs([]int64{1, 4}, true) + results, err = user_model.GetMaileableUsersByIDs(db.DefaultContext, []int64{1, 4}, true) assert.NoError(t, err) assert.Len(t, results, 2) if len(results) > 2 { diff --git a/modules/convert/issue.go b/modules/convert/issue.go index 5364367a80..7c11b2a89f 100644 --- a/modules/convert/issue.go +++ b/modules/convert/issue.go @@ -5,6 +5,7 @@ package convert import ( + "context" "fmt" "net/url" "strings" @@ -22,17 +23,17 @@ import ( // it assumes some fields assigned with values: // Required - Poster, Labels, // Optional - Milestone, Assignee, PullRequest -func ToAPIIssue(issue *issues_model.Issue) *api.Issue { - if err := issue.LoadLabels(db.DefaultContext); err != nil { +func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue { + if err := issue.LoadLabels(ctx); err != nil { return &api.Issue{} } - if err := issue.LoadPoster(); err != nil { + if err := issue.LoadPoster(ctx); err != nil { return &api.Issue{} } - if err := issue.LoadRepo(db.DefaultContext); err != nil { + if err := issue.LoadRepo(ctx); err != nil { return &api.Issue{} } - if err := issue.Repo.GetOwner(db.DefaultContext); err != nil { + if err := issue.Repo.GetOwner(ctx); err != nil { return &api.Issue{} } @@ -64,14 +65,14 @@ func ToAPIIssue(issue *issues_model.Issue) *api.Issue { apiIssue.Closed = issue.ClosedUnix.AsTimePtr() } - if err := issue.LoadMilestone(); err != nil { + if err := issue.LoadMilestone(ctx); err != nil { return &api.Issue{} } if issue.Milestone != nil { apiIssue.Milestone = ToAPIMilestone(issue.Milestone) } - if err := issue.LoadAssignees(db.DefaultContext); err != nil { + if err := issue.LoadAssignees(ctx); err != nil { return &api.Issue{} } if len(issue.Assignees) > 0 { @@ -81,7 +82,7 @@ func ToAPIIssue(issue *issues_model.Issue) *api.Issue { apiIssue.Assignee = ToUser(issue.Assignees[0], nil) // For compatibility, we're keeping the first assignee as `apiIssue.Assignee` } if issue.IsPull { - if err := issue.LoadPullRequest(); err != nil { + if err := issue.LoadPullRequest(ctx); err != nil { return &api.Issue{} } apiIssue.PullRequest = &api.PullRequestMeta{ @@ -99,16 +100,16 @@ func ToAPIIssue(issue *issues_model.Issue) *api.Issue { } // ToAPIIssueList converts an IssueList to API format -func ToAPIIssueList(il issues_model.IssueList) []*api.Issue { +func ToAPIIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue { result := make([]*api.Issue, len(il)) for i := range il { - result[i] = ToAPIIssue(il[i]) + result[i] = ToAPIIssue(ctx, il[i]) } return result } // ToTrackedTime converts TrackedTime to API format -func ToTrackedTime(t *issues_model.TrackedTime) (apiT *api.TrackedTime) { +func ToTrackedTime(ctx context.Context, t *issues_model.TrackedTime) (apiT *api.TrackedTime) { apiT = &api.TrackedTime{ ID: t.ID, IssueID: t.IssueID, @@ -118,7 +119,7 @@ func ToTrackedTime(t *issues_model.TrackedTime) (apiT *api.TrackedTime) { Created: t.Created, } if t.Issue != nil { - apiT.Issue = ToAPIIssue(t.Issue) + apiT.Issue = ToAPIIssue(ctx, t.Issue) } if t.User != nil { apiT.UserName = t.User.Name @@ -169,10 +170,10 @@ func ToStopWatches(sws []*issues_model.Stopwatch) (api.StopWatches, error) { } // ToTrackedTimeList converts TrackedTimeList to API format -func ToTrackedTimeList(tl issues_model.TrackedTimeList) api.TrackedTimeList { +func ToTrackedTimeList(ctx context.Context, tl issues_model.TrackedTimeList) api.TrackedTimeList { result := make([]*api.TrackedTime, 0, len(tl)) for _, t := range tl { - result = append(result, ToTrackedTime(t)) + result = append(result, ToTrackedTime(ctx, t)) } return result } diff --git a/modules/convert/issue_comment.go b/modules/convert/issue_comment.go index 73ad345fa4..c33cf5c111 100644 --- a/modules/convert/issue_comment.go +++ b/modules/convert/issue_comment.go @@ -5,7 +5,8 @@ package convert import ( - "code.gitea.io/gitea/models/db" + "context" + issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -28,8 +29,8 @@ func ToComment(c *issues_model.Comment) *api.Comment { } // ToTimelineComment converts a issues_model.Comment to the api.TimelineComment format -func ToTimelineComment(c *issues_model.Comment, doer *user_model.User) *api.TimelineComment { - err := c.LoadMilestone() +func ToTimelineComment(ctx context.Context, c *issues_model.Comment, doer *user_model.User) *api.TimelineComment { + err := c.LoadMilestone(ctx) if err != nil { log.Error("LoadMilestone: %v", err) return nil @@ -107,25 +108,25 @@ func ToTimelineComment(c *issues_model.Comment, doer *user_model.User) *api.Time return nil } - comment.TrackedTime = ToTrackedTime(c.Time) + comment.TrackedTime = ToTrackedTime(ctx, c.Time) } if c.RefIssueID != 0 { - issue, err := issues_model.GetIssueByID(db.DefaultContext, c.RefIssueID) + issue, err := issues_model.GetIssueByID(ctx, c.RefIssueID) if err != nil { log.Error("GetIssueByID(%d): %v", c.RefIssueID, err) return nil } - comment.RefIssue = ToAPIIssue(issue) + comment.RefIssue = ToAPIIssue(ctx, issue) } if c.RefCommentID != 0 { - com, err := issues_model.GetCommentByID(db.DefaultContext, c.RefCommentID) + com, err := issues_model.GetCommentByID(ctx, c.RefCommentID) if err != nil { log.Error("GetCommentByID(%d): %v", c.RefCommentID, err) return nil } - err = com.LoadPoster() + err = com.LoadPoster(ctx) if err != nil { log.Error("LoadPoster: %v", err) return nil @@ -138,17 +139,17 @@ func ToTimelineComment(c *issues_model.Comment, doer *user_model.User) *api.Time var repo *repo_model.Repository if c.Label.BelongsToOrg() { var err error - org, err = user_model.GetUserByID(c.Label.OrgID) + org, err = user_model.GetUserByIDCtx(ctx, c.Label.OrgID) if err != nil { - log.Error("GetUserByID(%d): %v", c.Label.OrgID, err) + log.Error("GetUserByIDCtx(%d): %v", c.Label.OrgID, err) return nil } } if c.Label.BelongsToRepo() { var err error - repo, err = repo_model.GetRepositoryByID(c.Label.RepoID) + repo, err = repo_model.GetRepositoryByIDCtx(ctx, c.Label.RepoID) if err != nil { - log.Error("GetRepositoryByID(%d): %v", c.Label.RepoID, err) + log.Error("GetRepositoryByIDCtx(%d): %v", c.Label.RepoID, err) return nil } } @@ -167,7 +168,7 @@ func ToTimelineComment(c *issues_model.Comment, doer *user_model.User) *api.Time } if c.DependentIssue != nil { - comment.DependentIssue = ToAPIIssue(c.DependentIssue) + comment.DependentIssue = ToAPIIssue(ctx, c.DependentIssue) } return comment diff --git a/modules/convert/pull.go b/modules/convert/pull.go index 9c31f9bd2c..ca9a4c39c5 100644 --- a/modules/convert/pull.go +++ b/modules/convert/pull.go @@ -33,13 +33,13 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u return nil } - apiIssue := ToAPIIssue(pr.Issue) - if err := pr.LoadBaseRepoCtx(ctx); err != nil { + apiIssue := ToAPIIssue(ctx, pr.Issue) + if err := pr.LoadBaseRepo(ctx); err != nil { log.Error("GetRepositoryById[%d]: %v", pr.ID, err) return nil } - if err := pr.LoadHeadRepoCtx(ctx); err != nil { + if err := pr.LoadHeadRepo(ctx); err != nil { log.Error("GetRepositoryById[%d]: %v", pr.ID, err) return nil } diff --git a/modules/convert/pull_test.go b/modules/convert/pull_test.go index a6ccbaca58..a0a672d3a5 100644 --- a/modules/convert/pull_test.go +++ b/modules/convert/pull_test.go @@ -7,6 +7,7 @@ package convert import ( "testing" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" @@ -22,8 +23,8 @@ func TestPullRequest_APIFormat(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) - assert.NoError(t, pr.LoadAttributes()) - assert.NoError(t, pr.LoadIssue()) + assert.NoError(t, pr.LoadAttributes(db.DefaultContext)) + assert.NoError(t, pr.LoadIssue(db.DefaultContext)) apiPullRequest := ToAPIPullRequest(git.DefaultContext, pr, nil) assert.NotNil(t, apiPullRequest) assert.EqualValues(t, &structs.PRBranchInfo{ @@ -36,8 +37,8 @@ func TestPullRequest_APIFormat(t *testing.T) { // withOut HeadRepo pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) - assert.NoError(t, pr.LoadIssue()) - assert.NoError(t, pr.LoadAttributes()) + assert.NoError(t, pr.LoadIssue(db.DefaultContext)) + assert.NoError(t, pr.LoadAttributes(db.DefaultContext)) // simulate fork deletion pr.HeadRepo = nil pr.HeadRepoID = 100000 diff --git a/modules/doctor/dbconsistency.go b/modules/doctor/dbconsistency.go index 89d974a350..602b2e523e 100644 --- a/modules/doctor/dbconsistency.go +++ b/modules/doctor/dbconsistency.go @@ -18,13 +18,13 @@ import ( type consistencyCheck struct { Name string - Counter func() (int64, error) - Fixer func() (int64, error) + Counter func(context.Context) (int64, error) + Fixer func(context.Context) (int64, error) FixedMessage string } func (c *consistencyCheck) Run(ctx context.Context, logger log.Logger, autofix bool) error { - count, err := c.Counter() + count, err := c.Counter(ctx) if err != nil { logger.Critical("Error: %v whilst counting %s", err, c.Name) return err @@ -32,7 +32,7 @@ func (c *consistencyCheck) Run(ctx context.Context, logger log.Logger, autofix b if count > 0 { if autofix { var fixed int64 - if fixed, err = c.Fixer(); err != nil { + if fixed, err = c.Fixer(ctx); err != nil { logger.Critical("Error: %v whilst fixing %s", err, c.Name) return err } @@ -54,9 +54,9 @@ func (c *consistencyCheck) Run(ctx context.Context, logger log.Logger, autofix b return nil } -func asFixer(fn func() error) func() (int64, error) { - return func() (int64, error) { - err := fn() +func asFixer(fn func(ctx context.Context) error) func(ctx context.Context) (int64, error) { + return func(ctx context.Context) (int64, error) { + err := fn(ctx) return -1, err } } @@ -64,11 +64,11 @@ func asFixer(fn func() error) func() (int64, error) { func genericOrphanCheck(name, subject, refobject, joincond string) consistencyCheck { return consistencyCheck{ Name: name, - Counter: func() (int64, error) { - return db.CountOrphanedObjects(subject, refobject, joincond) + Counter: func(ctx context.Context) (int64, error) { + return db.CountOrphanedObjects(ctx, subject, refobject, joincond) }, - Fixer: func() (int64, error) { - err := db.DeleteOrphanedObjects(subject, refobject, joincond) + Fixer: func(ctx context.Context) (int64, error) { + err := db.DeleteOrphanedObjects(ctx, subject, refobject, joincond) return -1, err }, } diff --git a/modules/indexer/issues/indexer.go b/modules/indexer/issues/indexer.go index da6a200aef..5b0279d1ab 100644 --- a/modules/indexer/issues/indexer.go +++ b/modules/indexer/issues/indexer.go @@ -291,7 +291,7 @@ func populateIssueIndexer(ctx context.Context) { return default: } - repos, _, err := repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ + repos, _, err := repo_model.SearchRepositoryByName(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{Page: page, PageSize: repo_model.RepositoryListDefaultPageSize}, OrderBy: db.SearchOrderByID, Private: true, @@ -313,14 +313,14 @@ func populateIssueIndexer(ctx context.Context) { return default: } - UpdateRepoIndexer(repo) + UpdateRepoIndexer(ctx, repo) } } } // UpdateRepoIndexer add/update all issues of the repositories -func UpdateRepoIndexer(repo *repo_model.Repository) { - is, err := issues_model.Issues(&issues_model.IssuesOptions{ +func UpdateRepoIndexer(ctx context.Context, repo *repo_model.Repository) { + is, err := issues_model.Issues(ctx, &issues_model.IssuesOptions{ RepoID: repo.ID, IsClosed: util.OptionalBoolNone, IsPull: util.OptionalBoolNone, @@ -329,8 +329,8 @@ func UpdateRepoIndexer(repo *repo_model.Repository) { log.Error("Issues: %v", err) return } - if err = issues_model.IssueList(is).LoadDiscussComments(); err != nil { - log.Error("LoadComments: %v", err) + if err = issues_model.IssueList(is).LoadDiscussComments(ctx); err != nil { + log.Error("LoadDiscussComments: %v", err) return } for _, issue := range is { @@ -360,11 +360,11 @@ func UpdateIssueIndexer(issue *issues_model.Issue) { } // DeleteRepoIssueIndexer deletes repo's all issues indexes -func DeleteRepoIssueIndexer(repo *repo_model.Repository) { +func DeleteRepoIssueIndexer(ctx context.Context, repo *repo_model.Repository) { var ids []int64 - ids, err := issues_model.GetIssueIDsByRepoID(db.DefaultContext, repo.ID) + ids, err := issues_model.GetIssueIDsByRepoID(ctx, repo.ID) if err != nil { - log.Error("getIssueIDsByRepoID failed: %v", err) + log.Error("GetIssueIDsByRepoID failed: %v", err) return } diff --git a/modules/notification/action/action.go b/modules/notification/action/action.go index 44d115f3d7..d029405664 100644 --- a/modules/notification/action/action.go +++ b/modules/notification/action/action.go @@ -5,20 +5,18 @@ package action import ( + "context" "fmt" "path" "strings" activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification/base" - "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/util" ) @@ -34,18 +32,18 @@ func NewNotifier() base.Notifier { return &actionNotifier{} } -func (a *actionNotifier) NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) { - if err := issue.LoadPoster(); err != nil { +func (a *actionNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) { + if err := issue.LoadPoster(ctx); err != nil { log.Error("issue.LoadPoster: %v", err) return } - if err := issue.LoadRepo(db.DefaultContext); err != nil { + if err := issue.LoadRepo(ctx); err != nil { log.Error("issue.LoadRepo: %v", err) return } repo := issue.Repo - if err := activities_model.NotifyWatchers(&activities_model.Action{ + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: issue.Poster.ID, ActUser: issue.Poster, OpType: activities_model.ActionCreateIssue, @@ -59,7 +57,7 @@ func (a *actionNotifier) NotifyNewIssue(issue *issues_model.Issue, mentions []*u } // NotifyIssueChangeStatus notifies close or reopen issue to notifiers -func (a *actionNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) { +func (a *actionNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) { // Compose comment action, could be plain comment, close or reopen issue/pull request. // This object will be used to notify watchers in the end of function. act := &activities_model.Action{ @@ -86,13 +84,13 @@ func (a *actionNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *i } // Notify watchers for whatever action comes in, ignore if no action type. - if err := activities_model.NotifyWatchers(act); err != nil { + if err := activities_model.NotifyWatchers(ctx, act); err != nil { log.Error("NotifyWatchers: %v", err) } } // NotifyCreateIssueComment notifies comment on an issue to notifiers -func (a *actionNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository, +func (a *actionNotifier) NotifyCreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User, ) { act := &activities_model.Action{ @@ -122,26 +120,26 @@ func (a *actionNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *r } // Notify watchers for whatever action comes in, ignore if no action type. - if err := activities_model.NotifyWatchers(act); err != nil { + if err := activities_model.NotifyWatchers(ctx, act); err != nil { log.Error("NotifyWatchers: %v", err) } } -func (a *actionNotifier) NotifyNewPullRequest(pull *issues_model.PullRequest, mentions []*user_model.User) { - if err := pull.LoadIssue(); err != nil { +func (a *actionNotifier) NotifyNewPullRequest(ctx context.Context, pull *issues_model.PullRequest, mentions []*user_model.User) { + if err := pull.LoadIssue(ctx); err != nil { log.Error("pull.LoadIssue: %v", err) return } - if err := pull.Issue.LoadRepo(db.DefaultContext); err != nil { + if err := pull.Issue.LoadRepo(ctx); err != nil { log.Error("pull.Issue.LoadRepo: %v", err) return } - if err := pull.Issue.LoadPoster(); err != nil { + if err := pull.Issue.LoadPoster(ctx); err != nil { log.Error("pull.Issue.LoadPoster: %v", err) return } - if err := activities_model.NotifyWatchers(&activities_model.Action{ + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: pull.Issue.Poster.ID, ActUser: pull.Issue.Poster, OpType: activities_model.ActionCreatePullRequest, @@ -154,8 +152,8 @@ func (a *actionNotifier) NotifyNewPullRequest(pull *issues_model.PullRequest, me } } -func (a *actionNotifier) NotifyRenameRepository(doer *user_model.User, repo *repo_model.Repository, oldRepoName string) { - if err := activities_model.NotifyWatchers(&activities_model.Action{ +func (a *actionNotifier) NotifyRenameRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldRepoName string) { + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: doer.ID, ActUser: doer, OpType: activities_model.ActionRenameRepo, @@ -168,8 +166,8 @@ func (a *actionNotifier) NotifyRenameRepository(doer *user_model.User, repo *rep } } -func (a *actionNotifier) NotifyTransferRepository(doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) { - if err := activities_model.NotifyWatchers(&activities_model.Action{ +func (a *actionNotifier) NotifyTransferRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) { + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: doer.ID, ActUser: doer, OpType: activities_model.ActionTransferRepo, @@ -182,8 +180,8 @@ func (a *actionNotifier) NotifyTransferRepository(doer *user_model.User, repo *r } } -func (a *actionNotifier) NotifyCreateRepository(doer, u *user_model.User, repo *repo_model.Repository) { - if err := activities_model.NotifyWatchers(&activities_model.Action{ +func (a *actionNotifier) NotifyCreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: doer.ID, ActUser: doer, OpType: activities_model.ActionCreateRepo, @@ -195,8 +193,8 @@ func (a *actionNotifier) NotifyCreateRepository(doer, u *user_model.User, repo * } } -func (a *actionNotifier) NotifyForkRepository(doer *user_model.User, oldRepo, repo *repo_model.Repository) { - if err := activities_model.NotifyWatchers(&activities_model.Action{ +func (a *actionNotifier) NotifyForkRepository(ctx context.Context, doer *user_model.User, oldRepo, repo *repo_model.Repository) { + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: doer.ID, ActUser: doer, OpType: activities_model.ActionCreateRepo, @@ -208,11 +206,8 @@ func (a *actionNotifier) NotifyForkRepository(doer *user_model.User, oldRepo, re } } -func (a *actionNotifier) NotifyPullRequestReview(pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("actionNotifier.NotifyPullRequestReview Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID)) - defer finished() - - if err := review.LoadReviewer(); err != nil { +func (a *actionNotifier) NotifyPullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { + if err := review.LoadReviewer(ctx); err != nil { log.Error("LoadReviewer '%d/%d': %v", review.ID, review.ReviewerID, err) return } @@ -269,8 +264,8 @@ func (a *actionNotifier) NotifyPullRequestReview(pr *issues_model.PullRequest, r } } -func (*actionNotifier) NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { - if err := activities_model.NotifyWatchers(&activities_model.Action{ +func (*actionNotifier) NotifyMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: doer.ID, ActUser: doer, OpType: activities_model.ActionMergePullRequest, @@ -283,8 +278,8 @@ func (*actionNotifier) NotifyMergePullRequest(pr *issues_model.PullRequest, doer } } -func (*actionNotifier) NotifyAutoMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { - if err := activities_model.NotifyWatchers(&activities_model.Action{ +func (*actionNotifier) NotifyAutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: doer.ID, ActUser: doer, OpType: activities_model.ActionAutoMergePullRequest, @@ -297,12 +292,12 @@ func (*actionNotifier) NotifyAutoMergePullRequest(pr *issues_model.PullRequest, } } -func (*actionNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) { +func (*actionNotifier) NotifyPullRevieweDismiss(ctx context.Context, doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) { reviewerName := review.Reviewer.Name if len(review.OriginalAuthor) > 0 { reviewerName = review.OriginalAuthor } - if err := activities_model.NotifyWatchers(&activities_model.Action{ + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: doer.ID, ActUser: doer, OpType: activities_model.ActionPullReviewDismissed, @@ -317,7 +312,7 @@ func (*actionNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *i } } -func (a *actionNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { +func (a *actionNotifier) NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { data, err := json.Marshal(commits) if err != nil { log.Error("Marshal: %v", err) @@ -336,7 +331,7 @@ func (a *actionNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_m opType = activities_model.ActionDeleteBranch } - if err = activities_model.NotifyWatchers(&activities_model.Action{ + if err = activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: pusher.ID, ActUser: pusher, OpType: opType, @@ -346,17 +341,17 @@ func (a *actionNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_m RefName: opts.RefFullName, IsPrivate: repo.IsPrivate, }); err != nil { - log.Error("notifyWatchers: %v", err) + log.Error("NotifyWatchers: %v", err) } } -func (a *actionNotifier) NotifyCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func (a *actionNotifier) NotifyCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { opType := activities_model.ActionCommitRepo if refType == "tag" { // has sent same action in `NotifyPushCommits`, so skip it. return } - if err := activities_model.NotifyWatchers(&activities_model.Action{ + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: doer.ID, ActUser: doer, OpType: opType, @@ -365,17 +360,17 @@ func (a *actionNotifier) NotifyCreateRef(doer *user_model.User, repo *repo_model IsPrivate: repo.IsPrivate, RefName: refFullName, }); err != nil { - log.Error("notifyWatchers: %v", err) + log.Error("NotifyWatchers: %v", err) } } -func (a *actionNotifier) NotifyDeleteRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func (a *actionNotifier) NotifyDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { opType := activities_model.ActionDeleteBranch if refType == "tag" { // has sent same action in `NotifyPushCommits`, so skip it. return } - if err := activities_model.NotifyWatchers(&activities_model.Action{ + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: doer.ID, ActUser: doer, OpType: opType, @@ -384,20 +379,20 @@ func (a *actionNotifier) NotifyDeleteRef(doer *user_model.User, repo *repo_model IsPrivate: repo.IsPrivate, RefName: refFullName, }); err != nil { - log.Error("notifyWatchers: %v", err) + log.Error("NotifyWatchers: %v", err) } } -func (a *actionNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { +func (a *actionNotifier) NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { data, err := json.Marshal(commits) if err != nil { log.Error("json.Marshal: %v", err) return } - if err := activities_model.NotifyWatchers(&activities_model.Action{ + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: repo.OwnerID, - ActUser: repo.MustOwner(), + ActUser: repo.MustOwner(ctx), OpType: activities_model.ActionMirrorSyncPush, RepoID: repo.ID, Repo: repo, @@ -405,44 +400,44 @@ func (a *actionNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *re RefName: opts.RefFullName, Content: string(data), }); err != nil { - log.Error("notifyWatchers: %v", err) + log.Error("NotifyWatchers: %v", err) } } -func (a *actionNotifier) NotifySyncCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { - if err := activities_model.NotifyWatchers(&activities_model.Action{ +func (a *actionNotifier) NotifySyncCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: repo.OwnerID, - ActUser: repo.MustOwner(), + ActUser: repo.MustOwner(ctx), OpType: activities_model.ActionMirrorSyncCreate, RepoID: repo.ID, Repo: repo, IsPrivate: repo.IsPrivate, RefName: refFullName, }); err != nil { - log.Error("notifyWatchers: %v", err) + log.Error("NotifyWatchers: %v", err) } } -func (a *actionNotifier) NotifySyncDeleteRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { - if err := activities_model.NotifyWatchers(&activities_model.Action{ +func (a *actionNotifier) NotifySyncDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: repo.OwnerID, - ActUser: repo.MustOwner(), + ActUser: repo.MustOwner(ctx), OpType: activities_model.ActionMirrorSyncDelete, RepoID: repo.ID, Repo: repo, IsPrivate: repo.IsPrivate, RefName: refFullName, }); err != nil { - log.Error("notifyWatchers: %v", err) + log.Error("NotifyWatchers: %v", err) } } -func (a *actionNotifier) NotifyNewRelease(rel *repo_model.Release) { - if err := rel.LoadAttributes(); err != nil { - log.Error("NotifyNewRelease: %v", err) +func (a *actionNotifier) NotifyNewRelease(ctx context.Context, rel *repo_model.Release) { + if err := rel.LoadAttributes(ctx); err != nil { + log.Error("LoadAttributes: %v", err) return } - if err := activities_model.NotifyWatchers(&activities_model.Action{ + if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: rel.PublisherID, ActUser: rel.Publisher, OpType: activities_model.ActionPublishRelease, @@ -452,6 +447,6 @@ func (a *actionNotifier) NotifyNewRelease(rel *repo_model.Release) { Content: rel.Title, RefName: rel.TagName, }); err != nil { - log.Error("notifyWatchers: %v", err) + log.Error("NotifyWatchers: %v", err) } } diff --git a/modules/notification/action/action_test.go b/modules/notification/action/action_test.go index 79a938d6cd..dc31b3189b 100644 --- a/modules/notification/action/action_test.go +++ b/modules/notification/action/action_test.go @@ -10,6 +10,7 @@ import ( "testing" activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -46,7 +47,7 @@ func TestRenameRepoAction(t *testing.T) { } unittest.AssertNotExistsBean(t, actionBean) - NewNotifier().NotifyRenameRepository(user, repo, oldRepoName) + NewNotifier().NotifyRenameRepository(db.DefaultContext, user, repo, oldRepoName) unittest.AssertExistsAndLoadBean(t, actionBean) unittest.CheckConsistencyFor(t, &activities_model.Action{}) diff --git a/modules/notification/base/notifier.go b/modules/notification/base/notifier.go index 9edab8213f..2f7deac88e 100644 --- a/modules/notification/base/notifier.go +++ b/modules/notification/base/notifier.go @@ -5,6 +5,8 @@ package base import ( + "context" + issues_model "code.gitea.io/gitea/models/issues" packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" @@ -15,50 +17,50 @@ import ( // Notifier defines an interface to notify receiver type Notifier interface { Run() - NotifyCreateRepository(doer, u *user_model.User, repo *repo_model.Repository) - NotifyMigrateRepository(doer, u *user_model.User, repo *repo_model.Repository) - NotifyDeleteRepository(doer *user_model.User, repo *repo_model.Repository) - NotifyForkRepository(doer *user_model.User, oldRepo, repo *repo_model.Repository) - NotifyRenameRepository(doer *user_model.User, repo *repo_model.Repository, oldRepoName string) - NotifyTransferRepository(doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) - NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) - NotifyIssueChangeStatus(*user_model.User, *issues_model.Issue, *issues_model.Comment, bool) - NotifyDeleteIssue(*user_model.User, *issues_model.Issue) - NotifyIssueChangeMilestone(doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) - NotifyIssueChangeAssignee(doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) - NotifyPullReviewRequest(doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) - NotifyIssueChangeContent(doer *user_model.User, issue *issues_model.Issue, oldContent string) - NotifyIssueClearLabels(doer *user_model.User, issue *issues_model.Issue) - NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) - NotifyIssueChangeRef(doer *user_model.User, issue *issues_model.Issue, oldRef string) - NotifyIssueChangeLabels(doer *user_model.User, issue *issues_model.Issue, + NotifyCreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) + NotifyMigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) + NotifyDeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) + NotifyForkRepository(ctx context.Context, doer *user_model.User, oldRepo, repo *repo_model.Repository) + NotifyRenameRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldRepoName string) + NotifyTransferRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) + NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) + NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) + NotifyDeleteIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) + NotifyIssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) + NotifyIssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) + NotifyPullReviewRequest(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) + NotifyIssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) + NotifyIssueClearLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) + NotifyIssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) + NotifyIssueChangeRef(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldRef string) + NotifyIssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, addedLabels, removedLabels []*issues_model.Label) - NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User) - NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) - NotifyAutoMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) - NotifyPullRequestSynchronized(doer *user_model.User, pr *issues_model.PullRequest) - NotifyPullRequestReview(pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) - NotifyPullRequestCodeComment(pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) - NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) - NotifyPullRequestPushCommits(doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) - NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) - NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository, + NotifyNewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) + NotifyMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) + NotifyAutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) + NotifyPullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) + NotifyPullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) + NotifyPullRequestCodeComment(ctx context.Context, pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) + NotifyPullRequestChangeTargetBranch(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) + NotifyPullRequestPushCommits(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) + NotifyPullReviewDismiss(ctx context.Context, doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) + NotifyCreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User) - NotifyUpdateComment(*user_model.User, *issues_model.Comment, string) - NotifyDeleteComment(*user_model.User, *issues_model.Comment) - NotifyNewWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) - NotifyEditWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) - NotifyDeleteWikiPage(doer *user_model.User, repo *repo_model.Repository, page string) - NotifyNewRelease(rel *repo_model.Release) - NotifyUpdateRelease(doer *user_model.User, rel *repo_model.Release) - NotifyDeleteRelease(doer *user_model.User, rel *repo_model.Release) - NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) - NotifyCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) - NotifyDeleteRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) - NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) - NotifySyncCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) - NotifySyncDeleteRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) - NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository) - NotifyPackageCreate(doer *user_model.User, pd *packages_model.PackageDescriptor) - NotifyPackageDelete(doer *user_model.User, pd *packages_model.PackageDescriptor) + NotifyUpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) + NotifyDeleteComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment) + NotifyNewWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) + NotifyEditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) + NotifyDeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page string) + NotifyNewRelease(ctx context.Context, rel *repo_model.Release) + NotifyUpdateRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) + NotifyDeleteRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) + NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) + NotifyCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) + NotifyDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) + NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) + NotifySyncCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) + NotifySyncDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) + NotifyRepoPendingTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) + NotifyPackageCreate(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) + NotifyPackageDelete(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) } diff --git a/modules/notification/base/null.go b/modules/notification/base/null.go index f051fbc26f..88e0c93de1 100644 --- a/modules/notification/base/null.go +++ b/modules/notification/base/null.go @@ -5,6 +5,8 @@ package base import ( + "context" + issues_model "code.gitea.io/gitea/models/issues" packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" @@ -22,179 +24,179 @@ func (*NullNotifier) Run() { } // NotifyCreateIssueComment places a place holder function -func (*NullNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository, +func (*NullNotifier) NotifyCreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User) { } // NotifyNewIssue places a place holder function -func (*NullNotifier) NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) { +func (*NullNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) { } // NotifyIssueChangeStatus places a place holder function -func (*NullNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { +func (*NullNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { } // NotifyDeleteIssue notify when some issue deleted -func (*NullNotifier) NotifyDeleteIssue(doer *user_model.User, issue *issues_model.Issue) { +func (*NullNotifier) NotifyDeleteIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) { } // NotifyNewPullRequest places a place holder function -func (*NullNotifier) NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User) { +func (*NullNotifier) NotifyNewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) { } // NotifyPullRequestReview places a place holder function -func (*NullNotifier) NotifyPullRequestReview(pr *issues_model.PullRequest, r *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { +func (*NullNotifier) NotifyPullRequestReview(ctx context.Context, pr *issues_model.PullRequest, r *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { } // NotifyPullRequestCodeComment places a place holder function -func (*NullNotifier) NotifyPullRequestCodeComment(pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) { +func (*NullNotifier) NotifyPullRequestCodeComment(ctx context.Context, pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) { } // NotifyMergePullRequest places a place holder function -func (*NullNotifier) NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { +func (*NullNotifier) NotifyMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { } // NotifyAutoMergePullRequest places a place holder function -func (*NullNotifier) NotifyAutoMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { +func (*NullNotifier) NotifyAutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { } // NotifyPullRequestSynchronized places a place holder function -func (*NullNotifier) NotifyPullRequestSynchronized(doer *user_model.User, pr *issues_model.PullRequest) { +func (*NullNotifier) NotifyPullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { } // NotifyPullRequestChangeTargetBranch places a place holder function -func (*NullNotifier) NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) { +func (*NullNotifier) NotifyPullRequestChangeTargetBranch(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) { } // NotifyPullRequestPushCommits notifies when push commits to pull request's head branch -func (*NullNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) { +func (*NullNotifier) NotifyPullRequestPushCommits(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) { } -// NotifyPullRevieweDismiss notifies when a review was dismissed by repo admin -func (*NullNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) { +// NotifyPullReviewDismiss notifies when a review was dismissed by repo admin +func (*NullNotifier) NotifyPullReviewDismiss(ctx context.Context, doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) { } // NotifyUpdateComment places a place holder function -func (*NullNotifier) NotifyUpdateComment(doer *user_model.User, c *issues_model.Comment, oldContent string) { +func (*NullNotifier) NotifyUpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) { } // NotifyDeleteComment places a place holder function -func (*NullNotifier) NotifyDeleteComment(doer *user_model.User, c *issues_model.Comment) { +func (*NullNotifier) NotifyDeleteComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment) { } // NotifyNewWikiPage places a place holder function -func (*NullNotifier) NotifyNewWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { +func (*NullNotifier) NotifyNewWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) { } // NotifyEditWikiPage places a place holder function -func (*NullNotifier) NotifyEditWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { +func (*NullNotifier) NotifyEditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) { } // NotifyDeleteWikiPage places a place holder function -func (*NullNotifier) NotifyDeleteWikiPage(doer *user_model.User, repo *repo_model.Repository, page string) { +func (*NullNotifier) NotifyDeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page string) { } // NotifyNewRelease places a place holder function -func (*NullNotifier) NotifyNewRelease(rel *repo_model.Release) { +func (*NullNotifier) NotifyNewRelease(ctx context.Context, rel *repo_model.Release) { } // NotifyUpdateRelease places a place holder function -func (*NullNotifier) NotifyUpdateRelease(doer *user_model.User, rel *repo_model.Release) { +func (*NullNotifier) NotifyUpdateRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) { } // NotifyDeleteRelease places a place holder function -func (*NullNotifier) NotifyDeleteRelease(doer *user_model.User, rel *repo_model.Release) { +func (*NullNotifier) NotifyDeleteRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) { } // NotifyIssueChangeMilestone places a place holder function -func (*NullNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) { +func (*NullNotifier) NotifyIssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) { } // NotifyIssueChangeContent places a place holder function -func (*NullNotifier) NotifyIssueChangeContent(doer *user_model.User, issue *issues_model.Issue, oldContent string) { +func (*NullNotifier) NotifyIssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) { } // NotifyIssueChangeAssignee places a place holder function -func (*NullNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) { +func (*NullNotifier) NotifyIssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) { } // NotifyPullReviewRequest places a place holder function -func (*NullNotifier) NotifyPullReviewRequest(doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) { +func (*NullNotifier) NotifyPullReviewRequest(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) { } // NotifyIssueClearLabels places a place holder function -func (*NullNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *issues_model.Issue) { +func (*NullNotifier) NotifyIssueClearLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) { } // NotifyIssueChangeTitle places a place holder function -func (*NullNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) { +func (*NullNotifier) NotifyIssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) { } // NotifyIssueChangeRef places a place holder function -func (*NullNotifier) NotifyIssueChangeRef(doer *user_model.User, issue *issues_model.Issue, oldTitle string) { +func (*NullNotifier) NotifyIssueChangeRef(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) { } // NotifyIssueChangeLabels places a place holder function -func (*NullNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue *issues_model.Issue, +func (*NullNotifier) NotifyIssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, addedLabels, removedLabels []*issues_model.Label) { } // NotifyCreateRepository places a place holder function -func (*NullNotifier) NotifyCreateRepository(doer, u *user_model.User, repo *repo_model.Repository) { +func (*NullNotifier) NotifyCreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { } // NotifyDeleteRepository places a place holder function -func (*NullNotifier) NotifyDeleteRepository(doer *user_model.User, repo *repo_model.Repository) { +func (*NullNotifier) NotifyDeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) { } // NotifyForkRepository places a place holder function -func (*NullNotifier) NotifyForkRepository(doer *user_model.User, oldRepo, repo *repo_model.Repository) { +func (*NullNotifier) NotifyForkRepository(ctx context.Context, doer *user_model.User, oldRepo, repo *repo_model.Repository) { } // NotifyMigrateRepository places a place holder function -func (*NullNotifier) NotifyMigrateRepository(doer, u *user_model.User, repo *repo_model.Repository) { +func (*NullNotifier) NotifyMigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { } // NotifyPushCommits notifies commits pushed to notifiers -func (*NullNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { +func (*NullNotifier) NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { } // NotifyCreateRef notifies branch or tag creation to notifiers -func (*NullNotifier) NotifyCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func (*NullNotifier) NotifyCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { } // NotifyDeleteRef notifies branch or tag deletion to notifiers -func (*NullNotifier) NotifyDeleteRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func (*NullNotifier) NotifyDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { } // NotifyRenameRepository places a place holder function -func (*NullNotifier) NotifyRenameRepository(doer *user_model.User, repo *repo_model.Repository, oldRepoName string) { +func (*NullNotifier) NotifyRenameRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldRepoName string) { } // NotifyTransferRepository places a place holder function -func (*NullNotifier) NotifyTransferRepository(doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) { +func (*NullNotifier) NotifyTransferRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) { } // NotifySyncPushCommits places a place holder function -func (*NullNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { +func (*NullNotifier) NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { } // NotifySyncCreateRef places a place holder function -func (*NullNotifier) NotifySyncCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func (*NullNotifier) NotifySyncCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { } // NotifySyncDeleteRef places a place holder function -func (*NullNotifier) NotifySyncDeleteRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func (*NullNotifier) NotifySyncDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { } // NotifyRepoPendingTransfer places a place holder function -func (*NullNotifier) NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository) { +func (*NullNotifier) NotifyRepoPendingTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) { } // NotifyPackageCreate places a place holder function -func (*NullNotifier) NotifyPackageCreate(doer *user_model.User, pd *packages_model.PackageDescriptor) { +func (*NullNotifier) NotifyPackageCreate(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) { } // NotifyPackageDelete places a place holder function -func (*NullNotifier) NotifyPackageDelete(doer *user_model.User, pd *packages_model.PackageDescriptor) { +func (*NullNotifier) NotifyPackageDelete(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) { } diff --git a/modules/notification/indexer/indexer.go b/modules/notification/indexer/indexer.go index fc9afdd4bc..2bacd5dec0 100644 --- a/modules/notification/indexer/indexer.go +++ b/modules/notification/indexer/indexer.go @@ -5,6 +5,8 @@ package indexer import ( + "context" + issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -29,13 +31,13 @@ func NewNotifier() base.Notifier { return &indexerNotifier{} } -func (r *indexerNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository, +func (r *indexerNotifier) NotifyCreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User, ) { if comment.Type == issues_model.CommentTypeComment { if issue.Comments == nil { - if err := issue.LoadDiscussComments(); err != nil { - log.Error("LoadComments failed: %v", err) + if err := issue.LoadDiscussComments(ctx); err != nil { + log.Error("LoadDiscussComments failed: %v", err) return } } else { @@ -46,15 +48,15 @@ func (r *indexerNotifier) NotifyCreateIssueComment(doer *user_model.User, repo * } } -func (r *indexerNotifier) NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) { +func (r *indexerNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) { issue_indexer.UpdateIssueIndexer(issue) } -func (r *indexerNotifier) NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User) { +func (r *indexerNotifier) NotifyNewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) { issue_indexer.UpdateIssueIndexer(pr.Issue) } -func (r *indexerNotifier) NotifyUpdateComment(doer *user_model.User, c *issues_model.Comment, oldContent string) { +func (r *indexerNotifier) NotifyUpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) { if c.Type == issues_model.CommentTypeComment { var found bool if c.Issue.Comments != nil { @@ -68,8 +70,8 @@ func (r *indexerNotifier) NotifyUpdateComment(doer *user_model.User, c *issues_m } if !found { - if err := c.Issue.LoadDiscussComments(); err != nil { - log.Error("LoadComments failed: %v", err) + if err := c.Issue.LoadDiscussComments(ctx); err != nil { + log.Error("LoadDiscussComments failed: %v", err) return } } @@ -78,9 +80,9 @@ func (r *indexerNotifier) NotifyUpdateComment(doer *user_model.User, c *issues_m } } -func (r *indexerNotifier) NotifyDeleteComment(doer *user_model.User, comment *issues_model.Comment) { +func (r *indexerNotifier) NotifyDeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) { if comment.Type == issues_model.CommentTypeComment { - if err := comment.LoadIssue(); err != nil { + if err := comment.LoadIssue(ctx); err != nil { log.Error("LoadIssue: %v", err) return } @@ -97,8 +99,8 @@ func (r *indexerNotifier) NotifyDeleteComment(doer *user_model.User, comment *is } if !found { - if err := comment.Issue.LoadDiscussComments(); err != nil { - log.Error("LoadComments failed: %v", err) + if err := comment.Issue.LoadDiscussComments(ctx); err != nil { + log.Error("LoadDiscussComments failed: %v", err) return } } @@ -107,15 +109,15 @@ func (r *indexerNotifier) NotifyDeleteComment(doer *user_model.User, comment *is } } -func (r *indexerNotifier) NotifyDeleteRepository(doer *user_model.User, repo *repo_model.Repository) { - issue_indexer.DeleteRepoIssueIndexer(repo) +func (r *indexerNotifier) NotifyDeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) { + issue_indexer.DeleteRepoIssueIndexer(ctx, repo) if setting.Indexer.RepoIndexerEnabled { code_indexer.UpdateRepoIndexer(repo) } } -func (r *indexerNotifier) NotifyMigrateRepository(doer, u *user_model.User, repo *repo_model.Repository) { - issue_indexer.UpdateRepoIndexer(repo) +func (r *indexerNotifier) NotifyMigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { + issue_indexer.UpdateRepoIndexer(ctx, repo) if setting.Indexer.RepoIndexerEnabled && !repo.IsEmpty { code_indexer.UpdateRepoIndexer(repo) } @@ -124,7 +126,7 @@ func (r *indexerNotifier) NotifyMigrateRepository(doer, u *user_model.User, repo } } -func (r *indexerNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { +func (r *indexerNotifier) NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { if setting.Indexer.RepoIndexerEnabled && opts.RefFullName == git.BranchPrefix+repo.DefaultBranch { code_indexer.UpdateRepoIndexer(repo) } @@ -133,7 +135,7 @@ func (r *indexerNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_ } } -func (r *indexerNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { +func (r *indexerNotifier) NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { if setting.Indexer.RepoIndexerEnabled && opts.RefFullName == git.BranchPrefix+repo.DefaultBranch { code_indexer.UpdateRepoIndexer(repo) } @@ -142,14 +144,14 @@ func (r *indexerNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *r } } -func (r *indexerNotifier) NotifyIssueChangeContent(doer *user_model.User, issue *issues_model.Issue, oldContent string) { +func (r *indexerNotifier) NotifyIssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) { issue_indexer.UpdateIssueIndexer(issue) } -func (r *indexerNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) { +func (r *indexerNotifier) NotifyIssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) { issue_indexer.UpdateIssueIndexer(issue) } -func (r *indexerNotifier) NotifyIssueChangeRef(doer *user_model.User, issue *issues_model.Issue, oldRef string) { +func (r *indexerNotifier) NotifyIssueChangeRef(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldRef string) { issue_indexer.UpdateIssueIndexer(issue) } diff --git a/modules/notification/mail/mail.go b/modules/notification/mail/mail.go index 54f561839d..123fa0e65a 100644 --- a/modules/notification/mail/mail.go +++ b/modules/notification/mail/mail.go @@ -5,16 +5,15 @@ package mail import ( + "context" "fmt" activities_model "code.gitea.io/gitea/models/activities" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification/base" - "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/services/mailer" ) @@ -29,12 +28,9 @@ func NewNotifier() base.Notifier { return &mailNotifier{} } -func (m *mailNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository, +func (m *mailNotifier) NotifyCreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User, ) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyCreateIssueComment Issue[%d] #%d in [%d]", issue.ID, issue.Index, issue.RepoID)) - defer finished() - var act activities_model.ActionType if comment.Type == issues_model.CommentTypeClose { act = activities_model.ActionCloseIssue @@ -53,13 +49,13 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *rep } } -func (m *mailNotifier) NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) { - if err := mailer.MailParticipants(issue, issue.Poster, activities_model.ActionCreateIssue, mentions); err != nil { +func (m *mailNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) { + if err := mailer.MailParticipants(ctx, issue, issue.Poster, activities_model.ActionCreateIssue, mentions); err != nil { log.Error("MailParticipants: %v", err) } } -func (m *mailNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { +func (m *mailNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { var actionType activities_model.ActionType if issue.IsPull { if isClosed { @@ -75,33 +71,30 @@ func (m *mailNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *iss } } - if err := mailer.MailParticipants(issue, doer, actionType, nil); err != nil { + if err := mailer.MailParticipants(ctx, issue, doer, actionType, nil); err != nil { log.Error("MailParticipants: %v", err) } } -func (m *mailNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) { - if err := issue.LoadPullRequest(); err != nil { +func (m *mailNotifier) NotifyIssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) { + if err := issue.LoadPullRequest(ctx); err != nil { log.Error("issue.LoadPullRequest: %v", err) return } if issue.IsPull && issues_model.HasWorkInProgressPrefix(oldTitle) && !issue.PullRequest.IsWorkInProgress() { - if err := mailer.MailParticipants(issue, doer, activities_model.ActionPullRequestReadyForReview, nil); err != nil { + if err := mailer.MailParticipants(ctx, issue, doer, activities_model.ActionPullRequestReadyForReview, nil); err != nil { log.Error("MailParticipants: %v", err) } } } -func (m *mailNotifier) NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User) { - if err := mailer.MailParticipants(pr.Issue, pr.Issue.Poster, activities_model.ActionCreatePullRequest, mentions); err != nil { +func (m *mailNotifier) NotifyNewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) { + if err := mailer.MailParticipants(ctx, pr.Issue, pr.Issue.Poster, activities_model.ActionCreatePullRequest, mentions); err != nil { log.Error("MailParticipants: %v", err) } } -func (m *mailNotifier) NotifyPullRequestReview(pr *issues_model.PullRequest, r *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestReview Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID)) - defer finished() - +func (m *mailNotifier) NotifyPullRequestReview(ctx context.Context, pr *issues_model.PullRequest, r *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { var act activities_model.ActionType if comment.Type == issues_model.CommentTypeClose { act = activities_model.ActionCloseIssue @@ -115,60 +108,54 @@ func (m *mailNotifier) NotifyPullRequestReview(pr *issues_model.PullRequest, r * } } -func (m *mailNotifier) NotifyPullRequestCodeComment(pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestCodeComment Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID)) - defer finished() - +func (m *mailNotifier) NotifyPullRequestCodeComment(ctx context.Context, pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) { if err := mailer.MailMentionsComment(ctx, pr, comment, mentions); err != nil { log.Error("MailMentionsComment: %v", err) } } -func (m *mailNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) { +func (m *mailNotifier) NotifyIssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) { // mail only sent to added assignees and not self-assignee if !removed && doer.ID != assignee.ID && assignee.EmailNotifications() != user_model.EmailNotificationsDisabled { ct := fmt.Sprintf("Assigned #%d.", issue.Index) - if err := mailer.SendIssueAssignedMail(issue, doer, ct, comment, []*user_model.User{assignee}); err != nil { + if err := mailer.SendIssueAssignedMail(ctx, issue, doer, ct, comment, []*user_model.User{assignee}); err != nil { log.Error("Error in SendIssueAssignedMail for issue[%d] to assignee[%d]: %v", issue.ID, assignee.ID, err) } } } -func (m *mailNotifier) NotifyPullReviewRequest(doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) { +func (m *mailNotifier) NotifyPullReviewRequest(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) { if isRequest && doer.ID != reviewer.ID && reviewer.EmailNotifications() != user_model.EmailNotificationsDisabled { ct := fmt.Sprintf("Requested to review %s.", issue.HTMLURL()) - if err := mailer.SendIssueAssignedMail(issue, doer, ct, comment, []*user_model.User{reviewer}); err != nil { + if err := mailer.SendIssueAssignedMail(ctx, issue, doer, ct, comment, []*user_model.User{reviewer}); err != nil { log.Error("Error in SendIssueAssignedMail for issue[%d] to reviewer[%d]: %v", issue.ID, reviewer.ID, err) } } } -func (m *mailNotifier) NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { - if err := pr.LoadIssue(); err != nil { - log.Error("pr.LoadIssue: %v", err) +func (m *mailNotifier) NotifyMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { + if err := pr.LoadIssue(ctx); err != nil { + log.Error("LoadIssue: %v", err) return } - if err := mailer.MailParticipants(pr.Issue, doer, activities_model.ActionMergePullRequest, nil); err != nil { + if err := mailer.MailParticipants(ctx, pr.Issue, doer, activities_model.ActionMergePullRequest, nil); err != nil { log.Error("MailParticipants: %v", err) } } -func (m *mailNotifier) NotifyAutoMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { - if err := pr.LoadIssue(); err != nil { +func (m *mailNotifier) NotifyAutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { + if err := pr.LoadIssue(ctx); err != nil { log.Error("pr.LoadIssue: %v", err) return } - if err := mailer.MailParticipants(pr.Issue, doer, activities_model.ActionAutoMergePullRequest, nil); err != nil { + if err := mailer.MailParticipants(ctx, pr.Issue, doer, activities_model.ActionAutoMergePullRequest, nil); err != nil { log.Error("MailParticipants: %v", err) } } -func (m *mailNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestPushCommits Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID)) - defer finished() - +func (m *mailNotifier) NotifyPullRequestPushCommits(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) { var err error - if err = comment.LoadIssue(); err != nil { + if err = comment.LoadIssue(ctx); err != nil { log.Error("comment.LoadIssue: %v", err) return } @@ -176,35 +163,29 @@ func (m *mailNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *i log.Error("comment.Issue.LoadRepo: %v", err) return } - if err = comment.Issue.LoadPullRequest(); err != nil { + if err = comment.Issue.LoadPullRequest(ctx); err != nil { log.Error("comment.Issue.LoadPullRequest: %v", err) return } - if err = comment.Issue.PullRequest.LoadBaseRepoCtx(ctx); err != nil { + if err = comment.Issue.PullRequest.LoadBaseRepo(ctx); err != nil { log.Error("comment.Issue.PullRequest.LoadBaseRepo: %v", err) return } if err := comment.LoadPushCommits(ctx); err != nil { log.Error("comment.LoadPushCommits: %v", err) } - m.NotifyCreateIssueComment(doer, comment.Issue.Repo, comment.Issue, comment, nil) + m.NotifyCreateIssueComment(ctx, doer, comment.Issue.Repo, comment.Issue, comment, nil) } -func (m *mailNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRevieweDismiss Review[%d] in Issue[%d]", review.ID, review.IssueID)) - defer finished() - +func (m *mailNotifier) NotifyPullReviewDismiss(ctx context.Context, doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) { if err := mailer.MailParticipantsComment(ctx, comment, activities_model.ActionPullReviewDismissed, review.Issue, nil); err != nil { log.Error("MailParticipantsComment: %v", err) } } -func (m *mailNotifier) NotifyNewRelease(rel *repo_model.Release) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyNewRelease rel[%d]%s in [%d]", rel.ID, rel.Title, rel.RepoID)) - defer finished() - - if err := rel.LoadAttributes(); err != nil { - log.Error("NotifyNewRelease: %v", err) +func (m *mailNotifier) NotifyNewRelease(ctx context.Context, rel *repo_model.Release) { + if err := rel.LoadAttributes(ctx); err != nil { + log.Error("LoadAttributes: %v", err) return } @@ -215,8 +196,8 @@ func (m *mailNotifier) NotifyNewRelease(rel *repo_model.Release) { mailer.MailNewRelease(ctx, rel) } -func (m *mailNotifier) NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository) { - if err := mailer.SendRepoTransferNotifyMail(doer, newOwner, repo); err != nil { - log.Error("NotifyRepoPendingTransfer: %v", err) +func (m *mailNotifier) NotifyRepoPendingTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) { + if err := mailer.SendRepoTransferNotifyMail(ctx, doer, newOwner, repo); err != nil { + log.Error("SendRepoTransferNotifyMail: %v", err) } } diff --git a/modules/notification/mirror/mirror.go b/modules/notification/mirror/mirror.go index 646b09a4ab..159c44ee6c 100644 --- a/modules/notification/mirror/mirror.go +++ b/modules/notification/mirror/mirror.go @@ -5,6 +5,8 @@ package mirror import ( + "context" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" @@ -24,16 +26,16 @@ func NewNotifier() base.Notifier { return &mirrorNotifier{} } -func (m *mirrorNotifier) NotifyPushCommits(_ *user_model.User, repo *repo_model.Repository, _ *repository.PushUpdateOptions, _ *repository.PushCommits) { - syncPushMirrorWithSyncOnCommit(repo.ID) +func (m *mirrorNotifier) NotifyPushCommits(ctx context.Context, _ *user_model.User, repo *repo_model.Repository, _ *repository.PushUpdateOptions, _ *repository.PushCommits) { + syncPushMirrorWithSyncOnCommit(ctx, repo.ID) } -func (m *mirrorNotifier) NotifySyncPushCommits(_ *user_model.User, repo *repo_model.Repository, _ *repository.PushUpdateOptions, _ *repository.PushCommits) { - syncPushMirrorWithSyncOnCommit(repo.ID) +func (m *mirrorNotifier) NotifySyncPushCommits(ctx context.Context, _ *user_model.User, repo *repo_model.Repository, _ *repository.PushUpdateOptions, _ *repository.PushCommits) { + syncPushMirrorWithSyncOnCommit(ctx, repo.ID) } -func syncPushMirrorWithSyncOnCommit(repoID int64) { - pushMirrors, err := repo_model.GetPushMirrorsSyncedOnCommit(repoID) +func syncPushMirrorWithSyncOnCommit(ctx context.Context, repoID int64) { + pushMirrors, err := repo_model.GetPushMirrorsSyncedOnCommit(ctx, repoID) if err != nil { log.Error("repo_model.GetPushMirrorsSyncedOnCommit failed: %v", err) return diff --git a/modules/notification/notification.go b/modules/notification/notification.go index 7bdc0a04c4..a117a60815 100644 --- a/modules/notification/notification.go +++ b/modules/notification/notification.go @@ -5,6 +5,8 @@ package notification import ( + "context" + issues_model "code.gitea.io/gitea/models/issues" packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" @@ -41,313 +43,313 @@ func NewContext() { } // NotifyNewWikiPage notifies creating new wiki pages to notifiers -func NotifyNewWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { +func NotifyNewWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) { for _, notifier := range notifiers { - notifier.NotifyNewWikiPage(doer, repo, page, comment) + notifier.NotifyNewWikiPage(ctx, doer, repo, page, comment) } } // NotifyEditWikiPage notifies editing or renaming wiki pages to notifiers -func NotifyEditWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { +func NotifyEditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) { for _, notifier := range notifiers { - notifier.NotifyEditWikiPage(doer, repo, page, comment) + notifier.NotifyEditWikiPage(ctx, doer, repo, page, comment) } } // NotifyDeleteWikiPage notifies deleting wiki pages to notifiers -func NotifyDeleteWikiPage(doer *user_model.User, repo *repo_model.Repository, page string) { +func NotifyDeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page string) { for _, notifier := range notifiers { - notifier.NotifyDeleteWikiPage(doer, repo, page) + notifier.NotifyDeleteWikiPage(ctx, doer, repo, page) } } // NotifyCreateIssueComment notifies issue comment related message to notifiers -func NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository, +func NotifyCreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User, ) { for _, notifier := range notifiers { - notifier.NotifyCreateIssueComment(doer, repo, issue, comment, mentions) + notifier.NotifyCreateIssueComment(ctx, doer, repo, issue, comment, mentions) } } // NotifyNewIssue notifies new issue to notifiers -func NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) { +func NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) { for _, notifier := range notifiers { - notifier.NotifyNewIssue(issue, mentions) + notifier.NotifyNewIssue(ctx, issue, mentions) } } // NotifyIssueChangeStatus notifies close or reopen issue to notifiers -func NotifyIssueChangeStatus(doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) { +func NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) { for _, notifier := range notifiers { - notifier.NotifyIssueChangeStatus(doer, issue, actionComment, closeOrReopen) + notifier.NotifyIssueChangeStatus(ctx, doer, issue, actionComment, closeOrReopen) } } // NotifyDeleteIssue notify when some issue deleted -func NotifyDeleteIssue(doer *user_model.User, issue *issues_model.Issue) { +func NotifyDeleteIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) { for _, notifier := range notifiers { - notifier.NotifyDeleteIssue(doer, issue) + notifier.NotifyDeleteIssue(ctx, doer, issue) } } // NotifyMergePullRequest notifies merge pull request to notifiers -func NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { +func NotifyMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { for _, notifier := range notifiers { - notifier.NotifyMergePullRequest(pr, doer) + notifier.NotifyMergePullRequest(ctx, doer, pr) } } // NotifyAutoMergePullRequest notifies merge pull request to notifiers -func NotifyAutoMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { +func NotifyAutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { for _, notifier := range notifiers { - notifier.NotifyAutoMergePullRequest(pr, doer) + notifier.NotifyAutoMergePullRequest(ctx, doer, pr) } } // NotifyNewPullRequest notifies new pull request to notifiers -func NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User) { +func NotifyNewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) { for _, notifier := range notifiers { - notifier.NotifyNewPullRequest(pr, mentions) + notifier.NotifyNewPullRequest(ctx, pr, mentions) } } // NotifyPullRequestSynchronized notifies Synchronized pull request -func NotifyPullRequestSynchronized(doer *user_model.User, pr *issues_model.PullRequest) { +func NotifyPullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { for _, notifier := range notifiers { - notifier.NotifyPullRequestSynchronized(doer, pr) + notifier.NotifyPullRequestSynchronized(ctx, doer, pr) } } // NotifyPullRequestReview notifies new pull request review -func NotifyPullRequestReview(pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { +func NotifyPullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { for _, notifier := range notifiers { - notifier.NotifyPullRequestReview(pr, review, comment, mentions) + notifier.NotifyPullRequestReview(ctx, pr, review, comment, mentions) } } // NotifyPullRequestCodeComment notifies new pull request code comment -func NotifyPullRequestCodeComment(pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) { +func NotifyPullRequestCodeComment(ctx context.Context, pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) { for _, notifier := range notifiers { - notifier.NotifyPullRequestCodeComment(pr, comment, mentions) + notifier.NotifyPullRequestCodeComment(ctx, pr, comment, mentions) } } // NotifyPullRequestChangeTargetBranch notifies when a pull request's target branch was changed -func NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) { +func NotifyPullRequestChangeTargetBranch(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) { for _, notifier := range notifiers { - notifier.NotifyPullRequestChangeTargetBranch(doer, pr, oldBranch) + notifier.NotifyPullRequestChangeTargetBranch(ctx, doer, pr, oldBranch) } } // NotifyPullRequestPushCommits notifies when push commits to pull request's head branch -func NotifyPullRequestPushCommits(doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) { +func NotifyPullRequestPushCommits(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) { for _, notifier := range notifiers { - notifier.NotifyPullRequestPushCommits(doer, pr, comment) + notifier.NotifyPullRequestPushCommits(ctx, doer, pr, comment) } } -// NotifyPullRevieweDismiss notifies when a review was dismissed by repo admin -func NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) { +// NotifyPullReviewDismiss notifies when a review was dismissed by repo admin +func NotifyPullReviewDismiss(ctx context.Context, doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) { for _, notifier := range notifiers { - notifier.NotifyPullRevieweDismiss(doer, review, comment) + notifier.NotifyPullReviewDismiss(ctx, doer, review, comment) } } // NotifyUpdateComment notifies update comment to notifiers -func NotifyUpdateComment(doer *user_model.User, c *issues_model.Comment, oldContent string) { +func NotifyUpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) { for _, notifier := range notifiers { - notifier.NotifyUpdateComment(doer, c, oldContent) + notifier.NotifyUpdateComment(ctx, doer, c, oldContent) } } // NotifyDeleteComment notifies delete comment to notifiers -func NotifyDeleteComment(doer *user_model.User, c *issues_model.Comment) { +func NotifyDeleteComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment) { for _, notifier := range notifiers { - notifier.NotifyDeleteComment(doer, c) + notifier.NotifyDeleteComment(ctx, doer, c) } } // NotifyNewRelease notifies new release to notifiers -func NotifyNewRelease(rel *repo_model.Release) { +func NotifyNewRelease(ctx context.Context, rel *repo_model.Release) { for _, notifier := range notifiers { - notifier.NotifyNewRelease(rel) + notifier.NotifyNewRelease(ctx, rel) } } // NotifyUpdateRelease notifies update release to notifiers -func NotifyUpdateRelease(doer *user_model.User, rel *repo_model.Release) { +func NotifyUpdateRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) { for _, notifier := range notifiers { - notifier.NotifyUpdateRelease(doer, rel) + notifier.NotifyUpdateRelease(ctx, doer, rel) } } // NotifyDeleteRelease notifies delete release to notifiers -func NotifyDeleteRelease(doer *user_model.User, rel *repo_model.Release) { +func NotifyDeleteRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) { for _, notifier := range notifiers { - notifier.NotifyDeleteRelease(doer, rel) + notifier.NotifyDeleteRelease(ctx, doer, rel) } } // NotifyIssueChangeMilestone notifies change milestone to notifiers -func NotifyIssueChangeMilestone(doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) { +func NotifyIssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) { for _, notifier := range notifiers { - notifier.NotifyIssueChangeMilestone(doer, issue, oldMilestoneID) + notifier.NotifyIssueChangeMilestone(ctx, doer, issue, oldMilestoneID) } } // NotifyIssueChangeContent notifies change content to notifiers -func NotifyIssueChangeContent(doer *user_model.User, issue *issues_model.Issue, oldContent string) { +func NotifyIssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) { for _, notifier := range notifiers { - notifier.NotifyIssueChangeContent(doer, issue, oldContent) + notifier.NotifyIssueChangeContent(ctx, doer, issue, oldContent) } } // NotifyIssueChangeAssignee notifies change content to notifiers -func NotifyIssueChangeAssignee(doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) { +func NotifyIssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) { for _, notifier := range notifiers { - notifier.NotifyIssueChangeAssignee(doer, issue, assignee, removed, comment) + notifier.NotifyIssueChangeAssignee(ctx, doer, issue, assignee, removed, comment) } } // NotifyPullReviewRequest notifies Request Review change -func NotifyPullReviewRequest(doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) { +func NotifyPullReviewRequest(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) { for _, notifier := range notifiers { - notifier.NotifyPullReviewRequest(doer, issue, reviewer, isRequest, comment) + notifier.NotifyPullReviewRequest(ctx, doer, issue, reviewer, isRequest, comment) } } // NotifyIssueClearLabels notifies clear labels to notifiers -func NotifyIssueClearLabels(doer *user_model.User, issue *issues_model.Issue) { +func NotifyIssueClearLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) { for _, notifier := range notifiers { - notifier.NotifyIssueClearLabels(doer, issue) + notifier.NotifyIssueClearLabels(ctx, doer, issue) } } // NotifyIssueChangeTitle notifies change title to notifiers -func NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) { +func NotifyIssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) { for _, notifier := range notifiers { - notifier.NotifyIssueChangeTitle(doer, issue, oldTitle) + notifier.NotifyIssueChangeTitle(ctx, doer, issue, oldTitle) } } // NotifyIssueChangeRef notifies change reference to notifiers -func NotifyIssueChangeRef(doer *user_model.User, issue *issues_model.Issue, oldRef string) { +func NotifyIssueChangeRef(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldRef string) { for _, notifier := range notifiers { - notifier.NotifyIssueChangeRef(doer, issue, oldRef) + notifier.NotifyIssueChangeRef(ctx, doer, issue, oldRef) } } // NotifyIssueChangeLabels notifies change labels to notifiers -func NotifyIssueChangeLabels(doer *user_model.User, issue *issues_model.Issue, +func NotifyIssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, addedLabels, removedLabels []*issues_model.Label, ) { for _, notifier := range notifiers { - notifier.NotifyIssueChangeLabels(doer, issue, addedLabels, removedLabels) + notifier.NotifyIssueChangeLabels(ctx, doer, issue, addedLabels, removedLabels) } } // NotifyCreateRepository notifies create repository to notifiers -func NotifyCreateRepository(doer, u *user_model.User, repo *repo_model.Repository) { +func NotifyCreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { for _, notifier := range notifiers { - notifier.NotifyCreateRepository(doer, u, repo) + notifier.NotifyCreateRepository(ctx, doer, u, repo) } } // NotifyMigrateRepository notifies create repository to notifiers -func NotifyMigrateRepository(doer, u *user_model.User, repo *repo_model.Repository) { +func NotifyMigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { for _, notifier := range notifiers { - notifier.NotifyMigrateRepository(doer, u, repo) + notifier.NotifyMigrateRepository(ctx, doer, u, repo) } } // NotifyTransferRepository notifies create repository to notifiers -func NotifyTransferRepository(doer *user_model.User, repo *repo_model.Repository, newOwnerName string) { +func NotifyTransferRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, newOwnerName string) { for _, notifier := range notifiers { - notifier.NotifyTransferRepository(doer, repo, newOwnerName) + notifier.NotifyTransferRepository(ctx, doer, repo, newOwnerName) } } // NotifyDeleteRepository notifies delete repository to notifiers -func NotifyDeleteRepository(doer *user_model.User, repo *repo_model.Repository) { +func NotifyDeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) { for _, notifier := range notifiers { - notifier.NotifyDeleteRepository(doer, repo) + notifier.NotifyDeleteRepository(ctx, doer, repo) } } // NotifyForkRepository notifies fork repository to notifiers -func NotifyForkRepository(doer *user_model.User, oldRepo, repo *repo_model.Repository) { +func NotifyForkRepository(ctx context.Context, doer *user_model.User, oldRepo, repo *repo_model.Repository) { for _, notifier := range notifiers { - notifier.NotifyForkRepository(doer, oldRepo, repo) + notifier.NotifyForkRepository(ctx, doer, oldRepo, repo) } } // NotifyRenameRepository notifies repository renamed -func NotifyRenameRepository(doer *user_model.User, repo *repo_model.Repository, oldName string) { +func NotifyRenameRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldName string) { for _, notifier := range notifiers { - notifier.NotifyRenameRepository(doer, repo, oldName) + notifier.NotifyRenameRepository(ctx, doer, repo, oldName) } } // NotifyPushCommits notifies commits pushed to notifiers -func NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { +func NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { for _, notifier := range notifiers { - notifier.NotifyPushCommits(pusher, repo, opts, commits) + notifier.NotifyPushCommits(ctx, pusher, repo, opts, commits) } } // NotifyCreateRef notifies branch or tag creation to notifiers -func NotifyCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { for _, notifier := range notifiers { - notifier.NotifyCreateRef(pusher, repo, refType, refFullName, refID) + notifier.NotifyCreateRef(ctx, pusher, repo, refType, refFullName, refID) } } // NotifyDeleteRef notifies branch or tag deletion to notifiers -func NotifyDeleteRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { for _, notifier := range notifiers { - notifier.NotifyDeleteRef(pusher, repo, refType, refFullName) + notifier.NotifyDeleteRef(ctx, pusher, repo, refType, refFullName) } } // NotifySyncPushCommits notifies commits pushed to notifiers -func NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { +func NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { for _, notifier := range notifiers { - notifier.NotifySyncPushCommits(pusher, repo, opts, commits) + notifier.NotifySyncPushCommits(ctx, pusher, repo, opts, commits) } } // NotifySyncCreateRef notifies branch or tag creation to notifiers -func NotifySyncCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func NotifySyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { for _, notifier := range notifiers { - notifier.NotifySyncCreateRef(pusher, repo, refType, refFullName, refID) + notifier.NotifySyncCreateRef(ctx, pusher, repo, refType, refFullName, refID) } } // NotifySyncDeleteRef notifies branch or tag deletion to notifiers -func NotifySyncDeleteRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func NotifySyncDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { for _, notifier := range notifiers { - notifier.NotifySyncDeleteRef(pusher, repo, refType, refFullName) + notifier.NotifySyncDeleteRef(ctx, pusher, repo, refType, refFullName) } } // NotifyRepoPendingTransfer notifies creation of pending transfer to notifiers -func NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository) { +func NotifyRepoPendingTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) { for _, notifier := range notifiers { - notifier.NotifyRepoPendingTransfer(doer, newOwner, repo) + notifier.NotifyRepoPendingTransfer(ctx, doer, newOwner, repo) } } // NotifyPackageCreate notifies creation of a package to notifiers -func NotifyPackageCreate(doer *user_model.User, pd *packages_model.PackageDescriptor) { +func NotifyPackageCreate(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) { for _, notifier := range notifiers { - notifier.NotifyPackageCreate(doer, pd) + notifier.NotifyPackageCreate(ctx, doer, pd) } } // NotifyPackageDelete notifies deletion of a package to notifiers -func NotifyPackageDelete(doer *user_model.User, pd *packages_model.PackageDescriptor) { +func NotifyPackageDelete(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) { for _, notifier := range notifiers { - notifier.NotifyPackageDelete(doer, pd) + notifier.NotifyPackageDelete(ctx, doer, pd) } } diff --git a/modules/notification/ui/ui.go b/modules/notification/ui/ui.go index 0e2b3e67c7..a38289c976 100644 --- a/modules/notification/ui/ui.go +++ b/modules/notification/ui/ui.go @@ -5,6 +5,8 @@ package ui import ( + "context" + activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" @@ -54,7 +56,7 @@ func (ns *notificationService) Run() { graceful.GetManager().RunWithShutdownFns(ns.issueQueue.Run) } -func (ns *notificationService) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository, +func (ns *notificationService) NotifyCreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User, ) { opts := issueNotificationOpts{ @@ -78,7 +80,7 @@ func (ns *notificationService) NotifyCreateIssueComment(doer *user_model.User, r } } -func (ns *notificationService) NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) { +func (ns *notificationService) NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) { _ = ns.issueQueue.Push(issueNotificationOpts{ IssueID: issue.ID, NotificationAuthorID: issue.Poster.ID, @@ -92,15 +94,15 @@ func (ns *notificationService) NotifyNewIssue(issue *issues_model.Issue, mention } } -func (ns *notificationService) NotifyIssueChangeStatus(doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { +func (ns *notificationService) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { _ = ns.issueQueue.Push(issueNotificationOpts{ IssueID: issue.ID, NotificationAuthorID: doer.ID, }) } -func (ns *notificationService) NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) { - if err := issue.LoadPullRequest(); err != nil { +func (ns *notificationService) NotifyIssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) { + if err := issue.LoadPullRequest(ctx); err != nil { log.Error("issue.LoadPullRequest: %v", err) return } @@ -112,24 +114,24 @@ func (ns *notificationService) NotifyIssueChangeTitle(doer *user_model.User, iss } } -func (ns *notificationService) NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { +func (ns *notificationService) NotifyMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { _ = ns.issueQueue.Push(issueNotificationOpts{ IssueID: pr.Issue.ID, NotificationAuthorID: doer.ID, }) } -func (ns *notificationService) NotifyAutoMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { - ns.NotifyMergePullRequest(pr, doer) +func (ns *notificationService) NotifyAutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { + ns.NotifyMergePullRequest(ctx, doer, pr) } -func (ns *notificationService) NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User) { - if err := pr.LoadIssue(); err != nil { +func (ns *notificationService) NotifyNewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) { + if err := pr.LoadIssue(ctx); err != nil { log.Error("Unable to load issue: %d for pr: %d: Error: %v", pr.IssueID, pr.ID, err) return } toNotify := make(container.Set[int64], 32) - repoWatchers, err := repo_model.GetRepoWatchersIDs(db.DefaultContext, pr.Issue.RepoID) + repoWatchers, err := repo_model.GetRepoWatchersIDs(ctx, pr.Issue.RepoID) if err != nil { log.Error("GetRepoWatchersIDs: %v", err) return @@ -137,7 +139,7 @@ func (ns *notificationService) NotifyNewPullRequest(pr *issues_model.PullRequest for _, id := range repoWatchers { toNotify.Add(id) } - issueParticipants, err := issues_model.GetParticipantsIDsByIssueID(pr.IssueID) + issueParticipants, err := issues_model.GetParticipantsIDsByIssueID(ctx, pr.IssueID) if err != nil { log.Error("GetParticipantsIDsByIssueID: %v", err) return @@ -158,7 +160,7 @@ func (ns *notificationService) NotifyNewPullRequest(pr *issues_model.PullRequest } } -func (ns *notificationService) NotifyPullRequestReview(pr *issues_model.PullRequest, r *issues_model.Review, c *issues_model.Comment, mentions []*user_model.User) { +func (ns *notificationService) NotifyPullRequestReview(ctx context.Context, pr *issues_model.PullRequest, r *issues_model.Review, c *issues_model.Comment, mentions []*user_model.User) { opts := issueNotificationOpts{ IssueID: pr.Issue.ID, NotificationAuthorID: r.Reviewer.ID, @@ -180,7 +182,7 @@ func (ns *notificationService) NotifyPullRequestReview(pr *issues_model.PullRequ } } -func (ns *notificationService) NotifyPullRequestCodeComment(pr *issues_model.PullRequest, c *issues_model.Comment, mentions []*user_model.User) { +func (ns *notificationService) NotifyPullRequestCodeComment(ctx context.Context, pr *issues_model.PullRequest, c *issues_model.Comment, mentions []*user_model.User) { for _, mention := range mentions { _ = ns.issueQueue.Push(issueNotificationOpts{ IssueID: pr.Issue.ID, @@ -191,7 +193,7 @@ func (ns *notificationService) NotifyPullRequestCodeComment(pr *issues_model.Pul } } -func (ns *notificationService) NotifyPullRequestPushCommits(doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) { +func (ns *notificationService) NotifyPullRequestPushCommits(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) { opts := issueNotificationOpts{ IssueID: pr.IssueID, NotificationAuthorID: doer.ID, @@ -200,7 +202,7 @@ func (ns *notificationService) NotifyPullRequestPushCommits(doer *user_model.Use _ = ns.issueQueue.Push(opts) } -func (ns *notificationService) NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) { +func (ns *notificationService) NotifyPullReviewDismiss(ctx context.Context, doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) { opts := issueNotificationOpts{ IssueID: review.IssueID, NotificationAuthorID: doer.ID, @@ -209,7 +211,7 @@ func (ns *notificationService) NotifyPullRevieweDismiss(doer *user_model.User, r _ = ns.issueQueue.Push(opts) } -func (ns *notificationService) NotifyIssueChangeAssignee(doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) { +func (ns *notificationService) NotifyIssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) { if !removed && doer.ID != assignee.ID { opts := issueNotificationOpts{ IssueID: issue.ID, @@ -225,7 +227,7 @@ func (ns *notificationService) NotifyIssueChangeAssignee(doer *user_model.User, } } -func (ns *notificationService) NotifyPullReviewRequest(doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) { +func (ns *notificationService) NotifyPullReviewRequest(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) { if isRequest { opts := issueNotificationOpts{ IssueID: issue.ID, @@ -241,8 +243,11 @@ func (ns *notificationService) NotifyPullReviewRequest(doer *user_model.User, is } } -func (ns *notificationService) NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository) { - if err := activities_model.CreateRepoTransferNotification(doer, newOwner, repo); err != nil { - log.Error("NotifyRepoPendingTransfer: %v", err) +func (ns *notificationService) NotifyRepoPendingTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) { + err := db.AutoTx(ctx, func(ctx context.Context) error { + return activities_model.CreateRepoTransferNotification(ctx, doer, newOwner, repo) + }) + if err != nil { + log.Error("CreateRepoTransferNotification: %v", err) } } diff --git a/modules/notification/webhook/webhook.go b/modules/notification/webhook/webhook.go index c591e1e34d..37ce7661f2 100644 --- a/modules/notification/webhook/webhook.go +++ b/modules/notification/webhook/webhook.go @@ -5,9 +5,8 @@ package webhook import ( - "fmt" + "context" - "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" packages_model "code.gitea.io/gitea/models/packages" "code.gitea.io/gitea/models/perm" @@ -18,10 +17,8 @@ import ( "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification/base" - "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" @@ -39,12 +36,9 @@ func NewNotifier() base.Notifier { return &webhookNotifier{} } -func (m *webhookNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *issues_model.Issue) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueClearLabels User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID)) - defer finished() - - if err := issue.LoadPoster(); err != nil { - log.Error("loadPoster: %v", err) +func (m *webhookNotifier) NotifyIssueClearLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) { + if err := issue.LoadPoster(ctx); err != nil { + log.Error("LoadPoster: %v", err) return } @@ -53,10 +47,10 @@ func (m *webhookNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *i return } - mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) + mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) var err error if issue.IsPull { - if err = issue.LoadPullRequest(); err != nil { + if err = issue.LoadPullRequest(ctx); err != nil { log.Error("LoadPullRequest: %v", err) return } @@ -72,7 +66,7 @@ func (m *webhookNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *i err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssueLabel, &api.IssuePayload{ Action: api.HookIssueLabelCleared, Index: issue.Index, - Issue: convert.ToAPIIssue(issue), + Issue: convert.ToAPIIssue(ctx, issue), Repository: convert.ToRepo(issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) @@ -82,12 +76,12 @@ func (m *webhookNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *i } } -func (m *webhookNotifier) NotifyForkRepository(doer *user_model.User, oldRepo, repo *repo_model.Repository) { - oldMode, _ := access_model.AccessLevel(doer, oldRepo) - mode, _ := access_model.AccessLevel(doer, repo) +func (m *webhookNotifier) NotifyForkRepository(ctx context.Context, doer *user_model.User, oldRepo, repo *repo_model.Repository) { + oldMode, _ := access_model.AccessLevel(ctx, doer, oldRepo) + mode, _ := access_model.AccessLevel(ctx, doer, repo) // forked webhook - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: oldRepo}, webhook.HookEventFork, &api.ForkPayload{ + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: oldRepo}, webhook.HookEventFork, &api.ForkPayload{ Forkee: convert.ToRepo(oldRepo, oldMode), Repo: convert.ToRepo(repo, mode), Sender: convert.ToUser(doer, nil), @@ -95,11 +89,11 @@ func (m *webhookNotifier) NotifyForkRepository(doer *user_model.User, oldRepo, r log.Error("PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err) } - u := repo.MustOwner() + u := repo.MustOwner(ctx) // Add to hook queue for created repo after session commit. if u.IsOrganization() { - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoCreated, Repository: convert.ToRepo(repo, perm.AccessModeOwner), Organization: convert.ToUser(u, nil), @@ -110,9 +104,9 @@ func (m *webhookNotifier) NotifyForkRepository(doer *user_model.User, oldRepo, r } } -func (m *webhookNotifier) NotifyCreateRepository(doer, u *user_model.User, repo *repo_model.Repository) { +func (m *webhookNotifier) NotifyCreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { // Add to hook queue for created repo after session commit. - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoCreated, Repository: convert.ToRepo(repo, perm.AccessModeOwner), Organization: convert.ToUser(u, nil), @@ -122,22 +116,20 @@ func (m *webhookNotifier) NotifyCreateRepository(doer, u *user_model.User, repo } } -func (m *webhookNotifier) NotifyDeleteRepository(doer *user_model.User, repo *repo_model.Repository) { - u := repo.MustOwner() - - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ +func (m *webhookNotifier) NotifyDeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) { + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoDeleted, Repository: convert.ToRepo(repo, perm.AccessModeOwner), - Organization: convert.ToUser(u, nil), + Organization: convert.ToUser(repo.MustOwner(ctx), nil), Sender: convert.ToUser(doer, nil), }); err != nil { log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) } } -func (m *webhookNotifier) NotifyMigrateRepository(doer, u *user_model.User, repo *repo_model.Repository) { +func (m *webhookNotifier) NotifyMigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { // Add to hook queue for created repo after session commit. - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoCreated, Repository: convert.ToRepo(repo, perm.AccessModeOwner), Organization: convert.ToUser(u, nil), @@ -147,14 +139,11 @@ func (m *webhookNotifier) NotifyMigrateRepository(doer, u *user_model.User, repo } } -func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeAssignee User: %s[%d] Issue[%d] #%d in [%d] Assignee %s[%d] removed: %t", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID, assignee.Name, assignee.ID, removed)) - defer finished() - +func (m *webhookNotifier) NotifyIssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) { if issue.IsPull { - mode, _ := access_model.AccessLevelUnit(doer, issue.Repo, unit.TypePullRequests) + mode, _ := access_model.AccessLevelUnit(ctx, doer, issue.Repo, unit.TypePullRequests) - if err := issue.LoadPullRequest(); err != nil { + if err := issue.LoadPullRequest(ctx); err != nil { log.Error("LoadPullRequest failed: %v", err) return } @@ -176,10 +165,10 @@ func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue return } } else { - mode, _ := access_model.AccessLevelUnit(doer, issue.Repo, unit.TypeIssues) + mode, _ := access_model.AccessLevelUnit(ctx, doer, issue.Repo, unit.TypeIssues) apiIssue := &api.IssuePayload{ Index: issue.Index, - Issue: convert.ToAPIIssue(issue), + Issue: convert.ToAPIIssue(ctx, issue), Repository: convert.ToRepo(issue.Repo, mode), Sender: convert.ToUser(doer, nil), } @@ -196,14 +185,11 @@ func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue } } -func (m *webhookNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeTitle User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID)) - defer finished() - - mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) +func (m *webhookNotifier) NotifyIssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) { + mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) var err error if issue.IsPull { - if err = issue.LoadPullRequest(); err != nil { + if err = issue.LoadPullRequest(ctx); err != nil { log.Error("LoadPullRequest failed: %v", err) return } @@ -229,7 +215,7 @@ func (m *webhookNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *i From: oldTitle, }, }, - Issue: convert.ToAPIIssue(issue), + Issue: convert.ToAPIIssue(ctx, issue), Repository: convert.ToRepo(issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) @@ -240,14 +226,11 @@ func (m *webhookNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *i } } -func (m *webhookNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeStatus User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID)) - defer finished() - - mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) +func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { + mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) var err error if issue.IsPull { - if err = issue.LoadPullRequest(); err != nil { + if err = issue.LoadPullRequest(ctx); err != nil { log.Error("LoadPullRequest: %v", err) return } @@ -267,7 +250,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue * } else { apiIssue := &api.IssuePayload{ Index: issue.Index, - Issue: convert.ToAPIIssue(issue), + Issue: convert.ToAPIIssue(ctx, issue), Repository: convert.ToRepo(issue.Repo, mode), Sender: convert.ToUser(doer, nil), } @@ -283,21 +266,21 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue * } } -func (m *webhookNotifier) NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) { - if err := issue.LoadRepo(db.DefaultContext); err != nil { +func (m *webhookNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) { + if err := issue.LoadRepo(ctx); err != nil { log.Error("issue.LoadRepo: %v", err) return } - if err := issue.LoadPoster(); err != nil { + if err := issue.LoadPoster(ctx); err != nil { log.Error("issue.LoadPoster: %v", err) return } - mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssues, &api.IssuePayload{ + mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssues, &api.IssuePayload{ Action: api.HookIssueOpened, Index: issue.Index, - Issue: convert.ToAPIIssue(issue), + Issue: convert.ToAPIIssue(ctx, issue), Repository: convert.ToRepo(issue.Repo, mode), Sender: convert.ToUser(issue.Poster, nil), }); err != nil { @@ -305,11 +288,8 @@ func (m *webhookNotifier) NotifyNewIssue(issue *issues_model.Issue, mentions []* } } -func (m *webhookNotifier) NotifyNewPullRequest(pull *issues_model.PullRequest, mentions []*user_model.User) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyNewPullRequest Pull[%d] #%d in [%d]", pull.ID, pull.Index, pull.BaseRepoID)) - defer finished() - - if err := pull.LoadIssue(); err != nil { +func (m *webhookNotifier) NotifyNewPullRequest(ctx context.Context, pull *issues_model.PullRequest, mentions []*user_model.User) { + if err := pull.LoadIssue(ctx); err != nil { log.Error("pull.LoadIssue: %v", err) return } @@ -317,12 +297,12 @@ func (m *webhookNotifier) NotifyNewPullRequest(pull *issues_model.PullRequest, m log.Error("pull.Issue.LoadRepo: %v", err) return } - if err := pull.Issue.LoadPoster(); err != nil { + if err := pull.Issue.LoadPoster(ctx); err != nil { log.Error("pull.Issue.LoadPoster: %v", err) return } - mode, _ := access_model.AccessLevel(pull.Issue.Poster, pull.Issue.Repo) + mode, _ := access_model.AccessLevel(ctx, pull.Issue.Poster, pull.Issue.Repo) if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: pull.Issue.Repo}, webhook.HookEventPullRequest, &api.PullRequestPayload{ Action: api.HookIssueOpened, Index: pull.Issue.Index, @@ -334,11 +314,8 @@ func (m *webhookNotifier) NotifyNewPullRequest(pull *issues_model.PullRequest, m } } -func (m *webhookNotifier) NotifyIssueChangeContent(doer *user_model.User, issue *issues_model.Issue, oldContent string) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeContent User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID)) - defer finished() - - mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) +func (m *webhookNotifier) NotifyIssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) { + mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) var err error if issue.IsPull { issue.PullRequest.Issue = issue @@ -363,7 +340,7 @@ func (m *webhookNotifier) NotifyIssueChangeContent(doer *user_model.User, issue From: oldContent, }, }, - Issue: convert.ToAPIIssue(issue), + Issue: convert.ToAPIIssue(ctx, issue), Repository: convert.ToRepo(issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) @@ -373,17 +350,17 @@ func (m *webhookNotifier) NotifyIssueChangeContent(doer *user_model.User, issue } } -func (m *webhookNotifier) NotifyUpdateComment(doer *user_model.User, c *issues_model.Comment, oldContent string) { - if err := c.LoadPoster(); err != nil { +func (m *webhookNotifier) NotifyUpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) { + if err := c.LoadPoster(ctx); err != nil { log.Error("LoadPoster: %v", err) return } - if err := c.LoadIssue(); err != nil { + if err := c.LoadIssue(ctx); err != nil { log.Error("LoadIssue: %v", err) return } - if err := c.Issue.LoadAttributes(db.DefaultContext); err != nil { + if err := c.Issue.LoadAttributes(ctx); err != nil { log.Error("LoadAttributes: %v", err) return } @@ -395,10 +372,10 @@ func (m *webhookNotifier) NotifyUpdateComment(doer *user_model.User, c *issues_m eventType = webhook.HookEventIssueComment } - mode, _ := access_model.AccessLevel(doer, c.Issue.Repo) - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{ + mode, _ := access_model.AccessLevel(ctx, doer, c.Issue.Repo) + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentEdited, - Issue: convert.ToAPIIssue(c.Issue), + Issue: convert.ToAPIIssue(ctx, c.Issue), Comment: convert.ToComment(c), Changes: &api.ChangesPayload{ Body: &api.ChangesFromPayload{ @@ -413,7 +390,7 @@ func (m *webhookNotifier) NotifyUpdateComment(doer *user_model.User, c *issues_m } } -func (m *webhookNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository, +func (m *webhookNotifier) NotifyCreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User, ) { var eventType webhook.HookEventType @@ -423,10 +400,10 @@ func (m *webhookNotifier) NotifyCreateIssueComment(doer *user_model.User, repo * eventType = webhook.HookEventIssueComment } - mode, _ := access_model.AccessLevel(doer, repo) - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{ + mode, _ := access_model.AccessLevel(ctx, doer, repo) + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentCreated, - Issue: convert.ToAPIIssue(issue), + Issue: convert.ToAPIIssue(ctx, issue), Comment: convert.ToComment(comment), Repository: convert.ToRepo(repo, mode), Sender: convert.ToUser(doer, nil), @@ -436,19 +413,19 @@ func (m *webhookNotifier) NotifyCreateIssueComment(doer *user_model.User, repo * } } -func (m *webhookNotifier) NotifyDeleteComment(doer *user_model.User, comment *issues_model.Comment) { +func (m *webhookNotifier) NotifyDeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) { var err error - if err = comment.LoadPoster(); err != nil { + if err = comment.LoadPoster(ctx); err != nil { log.Error("LoadPoster: %v", err) return } - if err = comment.LoadIssue(); err != nil { + if err = comment.LoadIssue(ctx); err != nil { log.Error("LoadIssue: %v", err) return } - if err = comment.Issue.LoadAttributes(db.DefaultContext); err != nil { + if err = comment.Issue.LoadAttributes(ctx); err != nil { log.Error("LoadAttributes: %v", err) return } @@ -460,10 +437,10 @@ func (m *webhookNotifier) NotifyDeleteComment(doer *user_model.User, comment *is eventType = webhook.HookEventIssueComment } - mode, _ := access_model.AccessLevel(doer, comment.Issue.Repo) - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{ + mode, _ := access_model.AccessLevel(ctx, doer, comment.Issue.Repo) + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentDeleted, - Issue: convert.ToAPIIssue(comment.Issue), + Issue: convert.ToAPIIssue(ctx, comment.Issue), Comment: convert.ToComment(comment), Repository: convert.ToRepo(comment.Issue.Repo, mode), Sender: convert.ToUser(doer, nil), @@ -473,9 +450,9 @@ func (m *webhookNotifier) NotifyDeleteComment(doer *user_model.User, comment *is } } -func (m *webhookNotifier) NotifyNewWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { +func (m *webhookNotifier) NotifyNewWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) { // Add to hook queue for created wiki page. - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ Action: api.HookWikiCreated, Repository: convert.ToRepo(repo, perm.AccessModeOwner), Sender: convert.ToUser(doer, nil), @@ -486,9 +463,9 @@ func (m *webhookNotifier) NotifyNewWikiPage(doer *user_model.User, repo *repo_mo } } -func (m *webhookNotifier) NotifyEditWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { +func (m *webhookNotifier) NotifyEditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) { // Add to hook queue for edit wiki page. - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ Action: api.HookWikiEdited, Repository: convert.ToRepo(repo, perm.AccessModeOwner), Sender: convert.ToUser(doer, nil), @@ -499,9 +476,9 @@ func (m *webhookNotifier) NotifyEditWikiPage(doer *user_model.User, repo *repo_m } } -func (m *webhookNotifier) NotifyDeleteWikiPage(doer *user_model.User, repo *repo_model.Repository, page string) { +func (m *webhookNotifier) NotifyDeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page string) { // Add to hook queue for edit wiki page. - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ Action: api.HookWikiDeleted, Repository: convert.ToRepo(repo, perm.AccessModeOwner), Sender: convert.ToUser(doer, nil), @@ -511,12 +488,9 @@ func (m *webhookNotifier) NotifyDeleteWikiPage(doer *user_model.User, repo *repo } } -func (m *webhookNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue *issues_model.Issue, +func (m *webhookNotifier) NotifyIssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, addedLabels, removedLabels []*issues_model.Label, ) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeLabels User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID)) - defer finished() - var err error if err = issue.LoadRepo(ctx); err != nil { @@ -524,18 +498,18 @@ func (m *webhookNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue * return } - if err = issue.LoadPoster(); err != nil { + if err = issue.LoadPoster(ctx); err != nil { log.Error("LoadPoster: %v", err) return } - mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) + mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) if issue.IsPull { - if err = issue.LoadPullRequest(); err != nil { + if err = issue.LoadPullRequest(ctx); err != nil { log.Error("loadPullRequest: %v", err) return } - if err = issue.PullRequest.LoadIssue(); err != nil { + if err = issue.PullRequest.LoadIssue(ctx); err != nil { log.Error("LoadIssue: %v", err) return } @@ -550,7 +524,7 @@ func (m *webhookNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue * err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssueLabel, &api.IssuePayload{ Action: api.HookIssueLabelUpdated, Index: issue.Index, - Issue: convert.ToAPIIssue(issue), + Issue: convert.ToAPIIssue(ctx, issue), Repository: convert.ToRepo(issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) @@ -560,10 +534,7 @@ func (m *webhookNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue * } } -func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeMilestone User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID)) - defer finished() - +func (m *webhookNotifier) NotifyIssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) { var hookAction api.HookIssueAction var err error if issue.MilestoneID > 0 { @@ -572,14 +543,14 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issu hookAction = api.HookIssueDemilestoned } - if err = issue.LoadAttributes(db.DefaultContext); err != nil { + if err = issue.LoadAttributes(ctx); err != nil { log.Error("issue.LoadAttributes failed: %v", err) return } - mode, _ := access_model.AccessLevel(doer, issue.Repo) + mode, _ := access_model.AccessLevel(ctx, doer, issue.Repo) if issue.IsPull { - err = issue.PullRequest.LoadIssue() + err = issue.PullRequest.LoadIssue(ctx) if err != nil { log.Error("LoadIssue: %v", err) return @@ -595,7 +566,7 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issu err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssueMilestone, &api.IssuePayload{ Action: hookAction, Index: issue.Index, - Issue: convert.ToAPIIssue(issue), + Issue: convert.ToAPIIssue(ctx, issue), Repository: convert.ToRepo(issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) @@ -605,10 +576,7 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issu } } -func (m *webhookNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyPushCommits User: %s[%d] in %s[%d]", pusher.Name, pusher.ID, repo.FullName(), repo.ID)) - defer finished() - +func (m *webhookNotifier) NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { apiPusher := convert.ToUser(pusher, nil) apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL()) if err != nil { @@ -632,23 +600,20 @@ func (m *webhookNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_ } } -func (m *webhookNotifier) NotifyAutoMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { +func (m *webhookNotifier) NotifyAutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { // just redirect to the NotifyMergePullRequest - m.NotifyMergePullRequest(pr, doer) + m.NotifyMergePullRequest(ctx, doer, pr) } -func (*webhookNotifier) NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyMergePullRequest Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID)) - defer finished() - +func (*webhookNotifier) NotifyMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { // Reload pull request information. - if err := pr.LoadAttributes(); err != nil { + if err := pr.LoadAttributes(ctx); err != nil { log.Error("LoadAttributes: %v", err) return } - if err := pr.LoadIssue(); err != nil { - log.Error("LoadAttributes: %v", err) + if err := pr.LoadIssue(ctx); err != nil { + log.Error("LoadIssue: %v", err) return } @@ -657,7 +622,7 @@ func (*webhookNotifier) NotifyMergePullRequest(pr *issues_model.PullRequest, doe return } - mode, err := access_model.AccessLevel(doer, pr.Issue.Repo) + mode, err := access_model.AccessLevel(ctx, doer, pr.Issue.Repo) if err != nil { log.Error("models.AccessLevel: %v", err) return @@ -672,29 +637,21 @@ func (*webhookNotifier) NotifyMergePullRequest(pr *issues_model.PullRequest, doe Action: api.HookIssueClosed, } - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: pr.Issue.Repo}, webhook.HookEventPullRequest, apiPullRequest) - if err != nil { + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: pr.Issue.Repo}, webhook.HookEventPullRequest, apiPullRequest); err != nil { log.Error("PrepareWebhooks: %v", err) } } -func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyPullRequestChangeTargetBranch Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID)) - defer finished() +func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) { + if err := pr.LoadIssue(ctx); err != nil { + log.Error("LoadIssue: %v", err) + return + } issue := pr.Issue - if !issue.IsPull { - return - } - var err error - if err = issue.LoadPullRequest(); err != nil { - log.Error("LoadPullRequest failed: %v", err) - return - } - issue.PullRequest.Issue = issue - mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequest, &api.PullRequestPayload{ + mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequest, &api.PullRequestPayload{ Action: api.HookIssueEdited, Index: issue.Index, Changes: &api.ChangesPayload{ @@ -702,20 +659,15 @@ func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(doer *user_model.U From: oldBranch, }, }, - PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), + PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), Repository: convert.ToRepo(issue.Repo, mode), Sender: convert.ToUser(doer, nil), - }) - - if err != nil { - log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) + }); err != nil { + log.Error("PrepareWebhooks [pr: %d]: %v", pr.ID, err) } } -func (m *webhookNotifier) NotifyPullRequestReview(pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyPullRequestReview Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID)) - defer finished() - +func (m *webhookNotifier) NotifyPullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { var reviewHookType webhook.HookEventType switch review.Type { @@ -731,12 +683,12 @@ func (m *webhookNotifier) NotifyPullRequestReview(pr *issues_model.PullRequest, return } - if err := pr.LoadIssue(); err != nil { - log.Error("pr.LoadIssue: %v", err) + if err := pr.LoadIssue(ctx); err != nil { + log.Error("LoadIssue: %v", err) return } - mode, err := access_model.AccessLevel(review.Issue.Poster, review.Issue.Repo) + mode, err := access_model.AccessLevel(ctx, review.Issue.Poster, review.Issue.Repo) if err != nil { log.Error("models.AccessLevel: %v", err) return @@ -756,12 +708,12 @@ func (m *webhookNotifier) NotifyPullRequestReview(pr *issues_model.PullRequest, } } -func (m *webhookNotifier) NotifyCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func (m *webhookNotifier) NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { apiPusher := convert.ToUser(pusher, nil) apiRepo := convert.ToRepo(repo, perm.AccessModeNone) refName := git.RefEndName(refFullName) - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: repo}, webhook.HookEventCreate, &api.CreatePayload{ + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventCreate, &api.CreatePayload{ Ref: refName, Sha: refID, RefType: refType, @@ -772,15 +724,12 @@ func (m *webhookNotifier) NotifyCreateRef(pusher *user_model.User, repo *repo_mo } } -func (m *webhookNotifier) NotifyPullRequestSynchronized(doer *user_model.User, pr *issues_model.PullRequest) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyPullRequestSynchronized Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID)) - defer finished() - - if err := pr.LoadIssue(); err != nil { - log.Error("pr.LoadIssue: %v", err) +func (m *webhookNotifier) NotifyPullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { + if err := pr.LoadIssue(ctx); err != nil { + log.Error("LoadIssue: %v", err) return } - if err := pr.Issue.LoadAttributes(db.DefaultContext); err != nil { + if err := pr.Issue.LoadAttributes(ctx); err != nil { log.Error("LoadAttributes: %v", err) return } @@ -796,12 +745,12 @@ func (m *webhookNotifier) NotifyPullRequestSynchronized(doer *user_model.User, p } } -func (m *webhookNotifier) NotifyDeleteRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func (m *webhookNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { apiPusher := convert.ToUser(pusher, nil) apiRepo := convert.ToRepo(repo, perm.AccessModeNone) refName := git.RefEndName(refFullName) - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: repo}, webhook.HookEventDelete, &api.DeletePayload{ + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventDelete, &api.DeletePayload{ Ref: refName, RefType: refType, PusherType: api.PusherTypeUser, @@ -812,14 +761,14 @@ func (m *webhookNotifier) NotifyDeleteRef(pusher *user_model.User, repo *repo_mo } } -func sendReleaseHook(doer *user_model.User, rel *repo_model.Release, action api.HookReleaseAction) { - if err := rel.LoadAttributes(); err != nil { +func sendReleaseHook(ctx context.Context, doer *user_model.User, rel *repo_model.Release, action api.HookReleaseAction) { + if err := rel.LoadAttributes(ctx); err != nil { log.Error("LoadAttributes: %v", err) return } - mode, _ := access_model.AccessLevel(doer, rel.Repo) - if err := webhook_services.PrepareWebhooks(db.DefaultContext, webhook_services.EventSource{Repository: rel.Repo}, webhook.HookEventRelease, &api.ReleasePayload{ + mode, _ := access_model.AccessLevel(ctx, doer, rel.Repo) + if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: rel.Repo}, webhook.HookEventRelease, &api.ReleasePayload{ Action: action, Release: convert.ToRelease(rel), Repository: convert.ToRepo(rel.Repo, mode), @@ -829,22 +778,19 @@ func sendReleaseHook(doer *user_model.User, rel *repo_model.Release, action api. } } -func (m *webhookNotifier) NotifyNewRelease(rel *repo_model.Release) { - sendReleaseHook(rel.Publisher, rel, api.HookReleasePublished) +func (m *webhookNotifier) NotifyNewRelease(ctx context.Context, rel *repo_model.Release) { + sendReleaseHook(ctx, rel.Publisher, rel, api.HookReleasePublished) } -func (m *webhookNotifier) NotifyUpdateRelease(doer *user_model.User, rel *repo_model.Release) { - sendReleaseHook(doer, rel, api.HookReleaseUpdated) +func (m *webhookNotifier) NotifyUpdateRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) { + sendReleaseHook(ctx, doer, rel, api.HookReleaseUpdated) } -func (m *webhookNotifier) NotifyDeleteRelease(doer *user_model.User, rel *repo_model.Release) { - sendReleaseHook(doer, rel, api.HookReleaseDeleted) +func (m *webhookNotifier) NotifyDeleteRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) { + sendReleaseHook(ctx, doer, rel, api.HookReleaseDeleted) } -func (m *webhookNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifySyncPushCommits User: %s[%d] in %s[%d]", pusher.Name, pusher.ID, repo.FullName(), repo.ID)) - defer finished() - +func (m *webhookNotifier) NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { apiPusher := convert.ToUser(pusher, nil) apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL()) if err != nil { @@ -868,31 +814,28 @@ func (m *webhookNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *r } } -func (m *webhookNotifier) NotifySyncCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { - m.NotifyCreateRef(pusher, repo, refType, refFullName, refID) +func (m *webhookNotifier) NotifySyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { + m.NotifyCreateRef(ctx, pusher, repo, refType, refFullName, refID) } -func (m *webhookNotifier) NotifySyncDeleteRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { - m.NotifyDeleteRef(pusher, repo, refType, refFullName) +func (m *webhookNotifier) NotifySyncDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { + m.NotifyDeleteRef(ctx, pusher, repo, refType, refFullName) } -func (m *webhookNotifier) NotifyPackageCreate(doer *user_model.User, pd *packages_model.PackageDescriptor) { - notifyPackage(doer, pd, api.HookPackageCreated) +func (m *webhookNotifier) NotifyPackageCreate(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) { + notifyPackage(ctx, doer, pd, api.HookPackageCreated) } -func (m *webhookNotifier) NotifyPackageDelete(doer *user_model.User, pd *packages_model.PackageDescriptor) { - notifyPackage(doer, pd, api.HookPackageDeleted) +func (m *webhookNotifier) NotifyPackageDelete(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) { + notifyPackage(ctx, doer, pd, api.HookPackageDeleted) } -func notifyPackage(sender *user_model.User, pd *packages_model.PackageDescriptor, action api.HookPackageAction) { +func notifyPackage(ctx context.Context, sender *user_model.User, pd *packages_model.PackageDescriptor, action api.HookPackageAction) { source := webhook_services.EventSource{ Repository: pd.Repository, Owner: pd.Owner, } - ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.notifyPackage Package: %s[%d]", pd.Package.Name, pd.Package.ID)) - defer finished() - apiPackage, err := convert.ToPackage(ctx, pd, sender) if err != nil { log.Error("Error converting package: %v", err) diff --git a/modules/repository/repo.go b/modules/repository/repo.go index 1d3a4658c2..f1360f4478 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -288,7 +288,7 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository) } for page := 1; ; page++ { opts.Page = page - rels, err := repo_model.GetReleasesByRepoID(repo.ID, opts) + rels, err := repo_model.GetReleasesByRepoID(gitRepo.Ctx, repo.ID, opts) if err != nil { return fmt.Errorf("unable to GetReleasesByRepoID in Repo[%d:%s/%s]: %w", repo.ID, repo.OwnerName, repo.Name, err) } diff --git a/routers/api/packages/conan/conan.go b/routers/api/packages/conan/conan.go index b69a674106..188cfce287 100644 --- a/routers/api/packages/conan/conan.go +++ b/routers/api/packages/conan/conan.go @@ -676,7 +676,7 @@ func deleteRecipeOrPackage(apictx *context.Context, rref *conan_module.RecipeRef } if versionDeleted { - notification.NotifyPackageDelete(apictx.Doer, pd) + notification.NotifyPackageDelete(apictx, apictx.Doer, pd) } return nil diff --git a/routers/api/v1/misc/nodeinfo.go b/routers/api/v1/misc/nodeinfo.go index bd629b87ca..a4ba440356 100644 --- a/routers/api/v1/misc/nodeinfo.go +++ b/routers/api/v1/misc/nodeinfo.go @@ -42,7 +42,7 @@ func NodeInfo(ctx *context.APIContext) { usersActiveMonth := int(user_model.CountUsers(&user_model.CountUserFilter{LastLoginSince: &timeOneMonthAgo})) usersActiveHalfyear := int(user_model.CountUsers(&user_model.CountUserFilter{LastLoginSince: &timeHaveYearAgo})) - allIssues, _ := issues_model.CountIssues(&issues_model.IssuesOptions{}) + allIssues, _ := issues_model.CountIssues(ctx, &issues_model.IssuesOptions{}) allComments, _ := issues_model.CountComments(&issues_model.FindCommentsOptions{}) nodeInfoUsage = structs.NodeInfoUsage{ diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go index f8e1fb0865..6d9664400a 100644 --- a/routers/api/v1/notify/repo.go +++ b/routers/api/v1/notify/repo.go @@ -109,7 +109,7 @@ func ListRepoNotifications(ctx *context.APIContext) { } opts.RepoID = ctx.Repo.Repository.ID - totalCount, err := activities_model.CountNotifications(opts) + totalCount, err := activities_model.CountNotifications(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -120,7 +120,7 @@ func ListRepoNotifications(ctx *context.APIContext) { ctx.InternalServerError(err) return } - err = nl.LoadAttributes() + err = nl.LoadAttributes(ctx) if err != nil { ctx.InternalServerError(err) return @@ -217,12 +217,12 @@ func ReadRepoNotifications(ctx *context.APIContext) { changed := make([]*structs.NotificationThread, 0, len(nl)) for _, n := range nl { - notif, err := activities_model.SetNotificationStatus(n.ID, ctx.Doer, targetStatus) + notif, err := activities_model.SetNotificationStatus(ctx, n.ID, ctx.Doer, targetStatus) if err != nil { ctx.InternalServerError(err) return } - _ = notif.LoadAttributes() + _ = notif.LoadAttributes(ctx) changed = append(changed, convert.ToNotificationThread(notif)) } ctx.JSON(http.StatusResetContent, changed) diff --git a/routers/api/v1/notify/threads.go b/routers/api/v1/notify/threads.go index 44a1d30a55..f8e4960912 100644 --- a/routers/api/v1/notify/threads.go +++ b/routers/api/v1/notify/threads.go @@ -42,7 +42,7 @@ func GetThread(ctx *context.APIContext) { if n == nil { return } - if err := n.LoadAttributes(); err != nil && !issues_model.IsErrCommentNotExist(err) { + if err := n.LoadAttributes(ctx); err != nil && !issues_model.IsErrCommentNotExist(err) { ctx.InternalServerError(err) return } @@ -89,12 +89,12 @@ func ReadThread(ctx *context.APIContext) { targetStatus = activities_model.NotificationStatusRead } - notif, err := activities_model.SetNotificationStatus(n.ID, ctx.Doer, targetStatus) + notif, err := activities_model.SetNotificationStatus(ctx, n.ID, ctx.Doer, targetStatus) if err != nil { ctx.InternalServerError(err) return } - if err = notif.LoadAttributes(); err != nil && !issues_model.IsErrCommentNotExist(err) { + if err = notif.LoadAttributes(ctx); err != nil && !issues_model.IsErrCommentNotExist(err) { ctx.InternalServerError(err) return } @@ -102,7 +102,7 @@ func ReadThread(ctx *context.APIContext) { } func getThread(ctx *context.APIContext) *activities_model.Notification { - n, err := activities_model.GetNotificationByID(ctx.ParamsInt64(":id")) + n, err := activities_model.GetNotificationByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if db.IsErrNotExist(err) { ctx.Error(http.StatusNotFound, "GetNotificationByID", err) diff --git a/routers/api/v1/notify/user.go b/routers/api/v1/notify/user.go index 1b6706e16f..5f4d8b35c2 100644 --- a/routers/api/v1/notify/user.go +++ b/routers/api/v1/notify/user.go @@ -69,7 +69,7 @@ func ListNotifications(ctx *context.APIContext) { return } - totalCount, err := activities_model.CountNotifications(opts) + totalCount, err := activities_model.CountNotifications(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -80,7 +80,7 @@ func ListNotifications(ctx *context.APIContext) { ctx.InternalServerError(err) return } - err = nl.LoadAttributes() + err = nl.LoadAttributes(ctx) if err != nil { ctx.InternalServerError(err) return @@ -162,12 +162,12 @@ func ReadNotifications(ctx *context.APIContext) { changed := make([]*structs.NotificationThread, 0, len(nl)) for _, n := range nl { - notif, err := activities_model.SetNotificationStatus(n.ID, ctx.Doer, targetStatus) + notif, err := activities_model.SetNotificationStatus(ctx, n.ID, ctx.Doer, targetStatus) if err != nil { ctx.InternalServerError(err) return } - _ = notif.LoadAttributes() + _ = notif.LoadAttributes(ctx) changed = append(changed, convert.ToNotificationThread(notif)) } diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index f3e7834a49..b2bcc4d586 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -542,7 +542,7 @@ func GetTeamRepos(ctx *context.APIContext) { } repos := make([]*api.Repository, len(teamRepos)) for i, repo := range teamRepos { - access, err := access_model.AccessLevel(ctx.Doer, repo) + access, err := access_model.AccessLevel(ctx, ctx.Doer, repo) if err != nil { ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) return @@ -593,7 +593,7 @@ func GetTeamRepo(ctx *context.APIContext) { return } - access, err := access_model.AccessLevel(ctx.Doer, repo) + access, err := access_model.AccessLevel(ctx, ctx.Doer, repo) if err != nil { ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) return @@ -650,7 +650,7 @@ func AddTeamRepository(ctx *context.APIContext) { if ctx.Written() { return } - if access, err := access_model.AccessLevel(ctx.Doer, repo); err != nil { + if access, err := access_model.AccessLevel(ctx, ctx.Doer, repo); err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) return } else if access < perm.AccessModeAdmin { @@ -700,7 +700,7 @@ func RemoveTeamRepository(ctx *context.APIContext) { if ctx.Written() { return } - if access, err := access_model.AccessLevel(ctx.Doer, repo); err != nil { + if access, err := access_model.AccessLevel(ctx, ctx.Doer, repo); err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) return } else if access < perm.AccessModeAdmin { diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 84a172e92b..d10a308df3 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -427,7 +427,7 @@ func CreateBranchProtection(ctx *context.APIContext) { requiredApprovals = form.RequiredApprovals } - whitelistUsers, err := user_model.GetUserIDsByNames(form.PushWhitelistUsernames, false) + whitelistUsers, err := user_model.GetUserIDsByNames(ctx, form.PushWhitelistUsernames, false) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err) @@ -436,7 +436,7 @@ func CreateBranchProtection(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err) return } - mergeWhitelistUsers, err := user_model.GetUserIDsByNames(form.MergeWhitelistUsernames, false) + mergeWhitelistUsers, err := user_model.GetUserIDsByNames(ctx, form.MergeWhitelistUsernames, false) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err) @@ -445,7 +445,7 @@ func CreateBranchProtection(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err) return } - approvalsWhitelistUsers, err := user_model.GetUserIDsByNames(form.ApprovalsWhitelistUsernames, false) + approvalsWhitelistUsers, err := user_model.GetUserIDsByNames(ctx, form.ApprovalsWhitelistUsernames, false) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err) @@ -656,7 +656,7 @@ func EditBranchProtection(ctx *context.APIContext) { var whitelistUsers []int64 if form.PushWhitelistUsernames != nil { - whitelistUsers, err = user_model.GetUserIDsByNames(form.PushWhitelistUsernames, false) + whitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.PushWhitelistUsernames, false) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err) @@ -670,7 +670,7 @@ func EditBranchProtection(ctx *context.APIContext) { } var mergeWhitelistUsers []int64 if form.MergeWhitelistUsernames != nil { - mergeWhitelistUsers, err = user_model.GetUserIDsByNames(form.MergeWhitelistUsernames, false) + mergeWhitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.MergeWhitelistUsernames, false) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err) @@ -684,7 +684,7 @@ func EditBranchProtection(ctx *context.APIContext) { } var approvalsWhitelistUsers []int64 if form.ApprovalsWhitelistUsernames != nil { - approvalsWhitelistUsers, err = user_model.GetUserIDsByNames(form.ApprovalsWhitelistUsernames, false) + approvalsWhitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.ApprovalsWhitelistUsernames, false) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err) diff --git a/routers/api/v1/repo/fork.go b/routers/api/v1/repo/fork.go index 112a9562f0..c0a79d1a63 100644 --- a/routers/api/v1/repo/fork.go +++ b/routers/api/v1/repo/fork.go @@ -59,7 +59,7 @@ func ListForks(ctx *context.APIContext) { } apiForks := make([]*api.Repository, len(forks)) for i, fork := range forks { - access, err := access_model.AccessLevel(ctx.Doer, fork) + access, err := access_model.AccessLevel(ctx, ctx.Doer, fork) if err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) return diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 08e3e03741..60f9859e10 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -179,7 +179,7 @@ func SearchIssues(ctx *context.APIContext) { repoCond := repo_model.SearchRepositoryCondition(opts) repoIDs, _, err := repo_model.SearchRepositoryIDs(opts) if err != nil { - ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err) + ctx.Error(http.StatusInternalServerError, "SearchRepositoryIDs", err) return } @@ -268,7 +268,7 @@ func SearchIssues(ctx *context.APIContext) { issuesOpt.ReviewRequestedID = ctxUserID } - if issues, err = issues_model.Issues(issuesOpt); err != nil { + if issues, err = issues_model.Issues(ctx, issuesOpt); err != nil { ctx.Error(http.StatusInternalServerError, "Issues", err) return } @@ -276,7 +276,7 @@ func SearchIssues(ctx *context.APIContext) { issuesOpt.ListOptions = db.ListOptions{ Page: -1, } - if filteredCount, err = issues_model.CountIssues(issuesOpt); err != nil { + if filteredCount, err = issues_model.CountIssues(ctx, issuesOpt); err != nil { ctx.Error(http.StatusInternalServerError, "CountIssues", err) return } @@ -284,7 +284,7 @@ func SearchIssues(ctx *context.APIContext) { ctx.SetLinkHeader(int(filteredCount), limit) ctx.SetTotalCountHeader(filteredCount) - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) } // ListIssues list the issues of a repository @@ -477,7 +477,7 @@ func ListIssues(ctx *context.APIContext) { MentionedID: mentionedByID, } - if issues, err = issues_model.Issues(issuesOpt); err != nil { + if issues, err = issues_model.Issues(ctx, issuesOpt); err != nil { ctx.Error(http.StatusInternalServerError, "Issues", err) return } @@ -485,7 +485,7 @@ func ListIssues(ctx *context.APIContext) { issuesOpt.ListOptions = db.ListOptions{ Page: -1, } - if filteredCount, err = issues_model.CountIssues(issuesOpt); err != nil { + if filteredCount, err = issues_model.CountIssues(ctx, issuesOpt); err != nil { ctx.Error(http.StatusInternalServerError, "CountIssues", err) return } @@ -493,7 +493,7 @@ func ListIssues(ctx *context.APIContext) { ctx.SetLinkHeader(int(filteredCount), listOptions.PageSize) ctx.SetTotalCountHeader(filteredCount) - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) } func getUserIDForFilter(ctx *context.APIContext, queryName string) int64 { @@ -555,7 +555,7 @@ func GetIssue(ctx *context.APIContext) { } return } - ctx.JSON(http.StatusOK, convert.ToAPIIssue(issue)) + ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue)) } // CreateIssue create an issue of a repository @@ -612,7 +612,7 @@ func CreateIssue(ctx *context.APIContext) { var err error if ctx.Repo.CanWrite(unit.TypeIssues) { issue.MilestoneID = form.Milestone - assigneeIDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd(form.Assignee, form.Assignees) + assigneeIDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd(ctx, form.Assignee, form.Assignees) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err)) @@ -671,7 +671,7 @@ func CreateIssue(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetIssueByID", err) return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(issue)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, issue)) } // EditIssue modify an issue of a repository @@ -823,11 +823,11 @@ func EditIssue(ctx *context.APIContext) { } if titleChanged { - notification.NotifyIssueChangeTitle(ctx.Doer, issue, oldTitle) + notification.NotifyIssueChangeTitle(ctx, ctx.Doer, issue, oldTitle) } if statusChangeComment != nil { - notification.NotifyIssueChangeStatus(ctx.Doer, issue, statusChangeComment, issue.IsClosed) + notification.NotifyIssueChangeStatus(ctx, ctx.Doer, issue, statusChangeComment, issue.IsClosed) } // Refetch from database to assign some automatic values @@ -836,11 +836,11 @@ func EditIssue(ctx *context.APIContext) { ctx.InternalServerError(err) return } - if err = issue.LoadMilestone(); err != nil { + if err = issue.LoadMilestone(ctx); err != nil { ctx.InternalServerError(err) return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(issue)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, issue)) } func DeleteIssue(ctx *context.APIContext) { diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index 89038e4f16..a5da091727 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -91,7 +91,7 @@ func ListIssueComments(ctx *context.APIContext) { return } - if err := issues_model.CommentList(comments).LoadPosters(); err != nil { + if err := issues_model.CommentList(comments).LoadPosters(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadPosters", err) return } @@ -178,7 +178,7 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) { return } - if err := issues_model.CommentList(comments).LoadPosters(); err != nil { + if err := issues_model.CommentList(comments).LoadPosters(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadPosters", err) return } @@ -187,7 +187,7 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) { for _, comment := range comments { if comment.Type != issues_model.CommentTypeCode && isXRefCommentAccessible(ctx, ctx.Doer, comment, issue.RepoID) { comment.Issue = issue - apiComments = append(apiComments, convert.ToTimelineComment(comment, ctx.Doer)) + apiComments = append(apiComments, convert.ToTimelineComment(ctx, comment, ctx.Doer)) } } @@ -281,21 +281,21 @@ func ListRepoIssueComments(ctx *context.APIContext) { return } - if err = issues_model.CommentList(comments).LoadPosters(); err != nil { + if err = issues_model.CommentList(comments).LoadPosters(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadPosters", err) return } apiComments := make([]*api.Comment, len(comments)) - if err := issues_model.CommentList(comments).LoadIssues(); err != nil { + if err := issues_model.CommentList(comments).LoadIssues(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadIssues", err) return } - if err := issues_model.CommentList(comments).LoadPosters(); err != nil { + if err := issues_model.CommentList(comments).LoadPosters(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadPosters", err) return } - if _, err := issues_model.CommentList(comments).Issues().LoadRepositories(); err != nil { + if _, err := issues_model.CommentList(comments).Issues().LoadRepositories(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadRepositories", err) return } @@ -354,7 +354,7 @@ func CreateIssueComment(ctx *context.APIContext) { return } - comment, err := comment_service.CreateIssueComment(ctx.Doer, ctx.Repo.Repository, issue, form.Body, nil) + comment, err := comment_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Body, nil) if err != nil { ctx.Error(http.StatusInternalServerError, "CreateIssueComment", err) return @@ -409,7 +409,7 @@ func GetIssueComment(ctx *context.APIContext) { return } - if err = comment.LoadIssue(); err != nil { + if err = comment.LoadIssue(ctx); err != nil { ctx.InternalServerError(err) return } @@ -423,7 +423,7 @@ func GetIssueComment(ctx *context.APIContext) { return } - if err := comment.LoadPoster(); err != nil { + if err := comment.LoadPoster(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "comment.LoadPoster", err) return } @@ -548,7 +548,7 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption) oldContent := comment.Content comment.Content = form.Body - if err := comment_service.UpdateComment(comment, ctx.Doer, oldContent); err != nil { + if err := comment_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateComment", err) return } @@ -647,7 +647,7 @@ func deleteIssueComment(ctx *context.APIContext) { return } - if err = comment_service.DeleteComment(ctx.Doer, comment); err != nil { + if err = comment_service.DeleteComment(ctx, ctx.Doer, comment); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteCommentByID", err) return } diff --git a/routers/api/v1/repo/issue_reaction.go b/routers/api/v1/repo/issue_reaction.go index f4c40d2bcd..fb7fd713b3 100644 --- a/routers/api/v1/repo/issue_reaction.go +++ b/routers/api/v1/repo/issue_reaction.go @@ -58,7 +58,7 @@ func GetIssueCommentReactions(ctx *context.APIContext) { return } - if err := comment.LoadIssue(); err != nil { + if err := comment.LoadIssue(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "comment.LoadIssue", err) } @@ -185,7 +185,7 @@ func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOp return } - err = comment.LoadIssue() + err = comment.LoadIssue(ctx) if err != nil { ctx.Error(http.StatusInternalServerError, "comment.LoadIssue() failed", err) } diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index 1e26403ec8..e3abb973be 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -139,7 +139,7 @@ func ListTrackedTimes(ctx *context.APIContext) { } ctx.SetTotalCountHeader(count) - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) } // AddTime add time manual to the given issue @@ -224,7 +224,7 @@ func AddTime(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } - ctx.JSON(http.StatusOK, convert.ToTrackedTime(trackedTime)) + ctx.JSON(http.StatusOK, convert.ToTrackedTime(ctx, trackedTime)) } // ResetIssueTime reset time manual to the given issue @@ -448,7 +448,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) } // ListTrackedTimesByRepository lists all tracked times of the repository @@ -558,7 +558,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { } ctx.SetTotalCountHeader(count) - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) } // ListMyTrackedTimes lists all tracked times of the current user @@ -620,5 +620,5 @@ func ListMyTrackedTimes(ctx *context.APIContext) { } ctx.SetTotalCountHeader(count) - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) } diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index ed371d787c..aeef862b1f 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -195,7 +195,7 @@ func Migrate(ctx *context.APIContext) { } if err == nil { - notification.NotifyMigrateRepository(ctx.Doer, repoOwner, repo) + notification.NotifyMigrateRepository(ctx, ctx.Doer, repoOwner, repo) return } diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index f7e82dab37..fba7ed6462 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -109,19 +109,19 @@ func ListPullRequests(ctx *context.APIContext) { apiPrs := make([]*api.PullRequest, len(prs)) for i := range prs { - if err = prs[i].LoadIssue(); err != nil { + if err = prs[i].LoadIssue(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadIssue", err) return } - if err = prs[i].LoadAttributes(); err != nil { + if err = prs[i].LoadAttributes(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } - if err = prs[i].LoadBaseRepoCtx(ctx); err != nil { + if err = prs[i].LoadBaseRepo(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err) return } - if err = prs[i].LoadHeadRepoCtx(ctx); err != nil { + if err = prs[i].LoadHeadRepo(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err) return } @@ -173,11 +173,11 @@ func GetPullRequest(ctx *context.APIContext) { return } - if err = pr.LoadBaseRepoCtx(ctx); err != nil { + if err = pr.LoadBaseRepo(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err) return } - if err = pr.LoadHeadRepoCtx(ctx); err != nil { + if err = pr.LoadHeadRepo(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err) return } @@ -300,7 +300,7 @@ func CreatePullRequest(ctx *context.APIContext) { defer headGitRepo.Close() // Check if another PR exists with the same targets - existingPr, err := issues_model.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch, issues_model.PullRequestFlowGithub) + existingPr, err := issues_model.GetUnmergedPullRequest(ctx, headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch, issues_model.PullRequestFlowGithub) if err != nil { if !issues_model.IsErrPullRequestNotExist(err) { ctx.Error(http.StatusInternalServerError, "GetUnmergedPullRequest", err) @@ -320,7 +320,7 @@ func CreatePullRequest(ctx *context.APIContext) { } if len(form.Labels) > 0 { - labels, err := issues_model.GetLabelsInRepoByIDs(ctx.Repo.Repository.ID, form.Labels) + labels, err := issues_model.GetLabelsInRepoByIDs(ctx, ctx.Repo.Repository.ID, form.Labels) if err != nil { ctx.Error(http.StatusInternalServerError, "GetLabelsInRepoByIDs", err) return @@ -334,7 +334,7 @@ func CreatePullRequest(ctx *context.APIContext) { } if ctx.Repo.Owner.IsOrganization() { - orgLabels, err := issues_model.GetLabelsInOrgByIDs(ctx.Repo.Owner.ID, form.Labels) + orgLabels, err := issues_model.GetLabelsInOrgByIDs(ctx, ctx.Repo.Owner.ID, form.Labels) if err != nil { ctx.Error(http.StatusInternalServerError, "GetLabelsInOrgByIDs", err) return @@ -389,7 +389,7 @@ func CreatePullRequest(ctx *context.APIContext) { } // Get all assignee IDs - assigneeIDs, err := issues_model.MakeIDsFromAPIAssigneesToAdd(form.Assignee, form.Assignees) + assigneeIDs, err := issues_model.MakeIDsFromAPIAssigneesToAdd(ctx, form.Assignee, form.Assignees) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err)) @@ -400,7 +400,7 @@ func CreatePullRequest(ctx *context.APIContext) { } // Check if the passed assignees is assignable for _, aID := range assigneeIDs { - assignee, err := user_model.GetUserByID(aID) + assignee, err := user_model.GetUserByIDCtx(ctx, aID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserByID", err) return @@ -483,7 +483,7 @@ func EditPullRequest(ctx *context.APIContext) { return } - err = pr.LoadIssue() + err = pr.LoadIssue(ctx) if err != nil { ctx.Error(http.StatusInternalServerError, "LoadIssue", err) return @@ -551,14 +551,14 @@ func EditPullRequest(ctx *context.APIContext) { } if ctx.Repo.CanWrite(unit.TypePullRequests) && form.Labels != nil { - labels, err := issues_model.GetLabelsInRepoByIDs(ctx.Repo.Repository.ID, form.Labels) + labels, err := issues_model.GetLabelsInRepoByIDs(ctx, ctx.Repo.Repository.ID, form.Labels) if err != nil { ctx.Error(http.StatusInternalServerError, "GetLabelsInRepoByIDsError", err) return } if ctx.Repo.Owner.IsOrganization() { - orgLabels, err := issues_model.GetLabelsInOrgByIDs(ctx.Repo.Owner.ID, form.Labels) + orgLabels, err := issues_model.GetLabelsInOrgByIDs(ctx, ctx.Repo.Owner.ID, form.Labels) if err != nil { ctx.Error(http.StatusInternalServerError, "GetLabelsInOrgByIDs", err) return @@ -591,11 +591,11 @@ func EditPullRequest(ctx *context.APIContext) { } if titleChanged { - notification.NotifyIssueChangeTitle(ctx.Doer, issue, oldTitle) + notification.NotifyIssueChangeTitle(ctx, ctx.Doer, issue, oldTitle) } if statusChangeComment != nil { - notification.NotifyIssueChangeStatus(ctx.Doer, issue, statusChangeComment, issue.IsClosed) + notification.NotifyIssueChangeStatus(ctx, ctx.Doer, issue, statusChangeComment, issue.IsClosed) } // change pull target branch @@ -619,7 +619,7 @@ func EditPullRequest(ctx *context.APIContext) { } return } - notification.NotifyPullRequestChangeTargetBranch(ctx.Doer, pr, form.Base) + notification.NotifyPullRequestChangeTargetBranch(ctx, ctx.Doer, pr, form.Base) } // update allow edits @@ -743,12 +743,12 @@ func MergePullRequest(ctx *context.APIContext) { return } - if err := pr.LoadHeadRepoCtx(ctx); err != nil { + if err := pr.LoadHeadRepo(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err) return } - if err := pr.LoadIssueCtx(ctx); err != nil { + if err := pr.LoadIssue(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadIssue", err) return } @@ -811,7 +811,7 @@ func MergePullRequest(ctx *context.APIContext) { message := strings.TrimSpace(form.MergeTitleField) if len(message) == 0 { - message, err = pull_service.GetDefaultMergeMessage(ctx.Repo.GitRepo, pr, repo_model.MergeStyle(form.Do)) + message, err = pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pr, repo_model.MergeStyle(form.Do)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetDefaultMergeMessage", err) return @@ -1097,7 +1097,7 @@ func UpdatePullRequest(ctx *context.APIContext) { return } - if err = pr.LoadIssue(); err != nil { + if err = pr.LoadIssue(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadIssue", err) return } @@ -1107,11 +1107,11 @@ func UpdatePullRequest(ctx *context.APIContext) { return } - if err = pr.LoadBaseRepoCtx(ctx); err != nil { + if err = pr.LoadBaseRepo(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err) return } - if err = pr.LoadHeadRepoCtx(ctx); err != nil { + if err = pr.LoadHeadRepo(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err) return } @@ -1267,7 +1267,7 @@ func GetPullRequestCommits(ctx *context.APIContext) { return } - if err := pr.LoadBaseRepoCtx(ctx); err != nil { + if err := pr.LoadBaseRepo(ctx); err != nil { ctx.InternalServerError(err) return } @@ -1383,12 +1383,12 @@ func GetPullRequestFiles(ctx *context.APIContext) { return } - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepo(ctx); err != nil { ctx.InternalServerError(err) return } - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepo(ctx); err != nil { ctx.InternalServerError(err) return } diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index f36d0586ab..df88e2a57b 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -71,7 +71,7 @@ func ListPullReviews(ctx *context.APIContext) { return } - if err = pr.LoadIssue(); err != nil { + if err = pr.LoadIssue(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadIssue", err) return } @@ -476,7 +476,7 @@ func SubmitPullReview(ctx *context.APIContext) { // preparePullReviewType return ReviewType and false or nil and true if an error happen func preparePullReviewType(ctx *context.APIContext, pr *issues_model.PullRequest, event api.ReviewStateType, body string, hasComments bool) (issues_model.ReviewType, bool) { - if err := pr.LoadIssue(); err != nil { + if err := pr.LoadIssue(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadIssue", err) return -1, true } diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index acc9696e1b..60cc19d565 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -61,7 +61,7 @@ func GetRelease(ctx *context.APIContext) { return } - if err := release.LoadAttributes(); err != nil { + if err := release.LoadAttributes(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } @@ -123,14 +123,14 @@ func ListReleases(ctx *context.APIContext) { IsPreRelease: ctx.FormOptionalBool("pre-release"), } - releases, err := repo_model.GetReleasesByRepoID(ctx.Repo.Repository.ID, opts) + releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "GetReleasesByRepoID", err) return } rels := make([]*api.Release, len(releases)) for i, release := range releases { - if err := release.LoadAttributes(); err != nil { + if err := release.LoadAttributes(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } @@ -313,7 +313,7 @@ func EditRelease(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err) return } - if err := rel.LoadAttributes(); err != nil { + if err := rel.LoadAttributes(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go index a469877c13..02f85d384a 100644 --- a/routers/api/v1/repo/release_attachment.go +++ b/routers/api/v1/repo/release_attachment.go @@ -114,7 +114,7 @@ func ListReleaseAttachments(ctx *context.APIContext) { ctx.NotFound() return } - if err := release.LoadAttributes(); err != nil { + if err := release.LoadAttributes(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } diff --git a/routers/api/v1/repo/release_tags.go b/routers/api/v1/repo/release_tags.go index 2cb97c58a0..77395bb469 100644 --- a/routers/api/v1/repo/release_tags.go +++ b/routers/api/v1/repo/release_tags.go @@ -60,7 +60,7 @@ func GetReleaseByTag(ctx *context.APIContext) { return } - if err = release.LoadAttributes(); err != nil { + if err = release.LoadAttributes(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index de8a4d1864..29febe751c 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -191,7 +191,7 @@ func Search(ctx *context.APIContext) { } var err error - repos, count, err := repo_model.SearchRepository(opts) + repos, count, err := repo_model.SearchRepository(ctx, opts) if err != nil { ctx.JSON(http.StatusInternalServerError, api.SearchError{ OK: false, @@ -209,7 +209,7 @@ func Search(ctx *context.APIContext) { }) return } - accessMode, err := access_model.AccessLevel(ctx.Doer, repo) + accessMode, err := access_model.AccessLevel(ctx, ctx.Doer, repo) if err != nil { ctx.JSON(http.StatusInternalServerError, api.SearchError{ OK: false, diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index 6d95648542..734a550a71 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -86,7 +86,7 @@ func NewWikiPage(ctx *context.APIContext) { wikiPage := getWikiPage(ctx, wikiName) if !ctx.Written() { - notification.NotifyNewWikiPage(ctx.Doer, ctx.Repo.Repository, wikiName, form.Message) + notification.NotifyNewWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName, form.Message) ctx.JSON(http.StatusCreated, wikiPage) } } @@ -154,7 +154,7 @@ func EditWikiPage(ctx *context.APIContext) { wikiPage := getWikiPage(ctx, newWikiName) if !ctx.Written() { - notification.NotifyEditWikiPage(ctx.Doer, ctx.Repo.Repository, newWikiName, form.Message) + notification.NotifyEditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, newWikiName, form.Message) ctx.JSON(http.StatusOK, wikiPage) } } @@ -245,7 +245,7 @@ func DeleteWikiPage(ctx *context.APIContext) { return } - notification.NotifyDeleteWikiPage(ctx.Doer, ctx.Repo.Repository, wikiName) + notification.NotifyDeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName) ctx.Status(http.StatusNoContent) } diff --git a/routers/api/v1/user/repo.go b/routers/api/v1/user/repo.go index 709e3a6c54..d1917a9938 100644 --- a/routers/api/v1/user/repo.go +++ b/routers/api/v1/user/repo.go @@ -39,7 +39,7 @@ func listUserRepos(ctx *context.APIContext, u *user_model.User, private bool) { apiRepos := make([]*api.Repository, 0, len(repos)) for i := range repos { - access, err := access_model.AccessLevel(ctx.Doer, repos[i]) + access, err := access_model.AccessLevel(ctx, ctx.Doer, repos[i]) if err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) return @@ -112,7 +112,7 @@ func ListMyRepos(ctx *context.APIContext) { } var err error - repos, count, err := repo_model.SearchRepository(opts) + repos, count, err := repo_model.SearchRepository(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "SearchRepository", err) return @@ -124,7 +124,7 @@ func ListMyRepos(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetOwner", err) return } - accessMode, err := access_model.AccessLevel(ctx.Doer, repo) + accessMode, err := access_model.AccessLevel(ctx, ctx.Doer, repo) if err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) } diff --git a/routers/api/v1/user/star.go b/routers/api/v1/user/star.go index 9cb9ec79b8..96748c630d 100644 --- a/routers/api/v1/user/star.go +++ b/routers/api/v1/user/star.go @@ -6,6 +6,7 @@ package user import ( + std_context "context" "net/http" "code.gitea.io/gitea/models/db" @@ -20,15 +21,15 @@ import ( // getStarredRepos returns the repos that the user with the specified userID has // starred -func getStarredRepos(user *user_model.User, private bool, listOptions db.ListOptions) ([]*api.Repository, error) { - starredRepos, err := repo_model.GetStarredRepos(user.ID, private, listOptions) +func getStarredRepos(ctx std_context.Context, user *user_model.User, private bool, listOptions db.ListOptions) ([]*api.Repository, error) { + starredRepos, err := repo_model.GetStarredRepos(ctx, user.ID, private, listOptions) if err != nil { return nil, err } repos := make([]*api.Repository, len(starredRepos)) for i, starred := range starredRepos { - access, err := access_model.AccessLevel(user, starred) + access, err := access_model.AccessLevel(ctx, user, starred) if err != nil { return nil, err } @@ -63,7 +64,7 @@ func GetStarredRepos(ctx *context.APIContext) { // "$ref": "#/responses/RepositoryList" private := ctx.ContextUser.ID == ctx.Doer.ID - repos, err := getStarredRepos(ctx.ContextUser, private, utils.GetListOptions(ctx)) + repos, err := getStarredRepos(ctx, ctx.ContextUser, private, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "getStarredRepos", err) return @@ -93,7 +94,7 @@ func GetMyStarredRepos(ctx *context.APIContext) { // "200": // "$ref": "#/responses/RepositoryList" - repos, err := getStarredRepos(ctx.Doer, true, utils.GetListOptions(ctx)) + repos, err := getStarredRepos(ctx, ctx.Doer, true, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "getStarredRepos", err) } diff --git a/routers/api/v1/user/watch.go b/routers/api/v1/user/watch.go index 83f23db15c..7765a399f3 100644 --- a/routers/api/v1/user/watch.go +++ b/routers/api/v1/user/watch.go @@ -5,6 +5,7 @@ package user import ( + std_context "context" "net/http" "code.gitea.io/gitea/models/db" @@ -18,15 +19,15 @@ import ( ) // getWatchedRepos returns the repos that the user with the specified userID is watching -func getWatchedRepos(user *user_model.User, private bool, listOptions db.ListOptions) ([]*api.Repository, int64, error) { - watchedRepos, total, err := repo_model.GetWatchedRepos(user.ID, private, listOptions) +func getWatchedRepos(ctx std_context.Context, user *user_model.User, private bool, listOptions db.ListOptions) ([]*api.Repository, int64, error) { + watchedRepos, total, err := repo_model.GetWatchedRepos(ctx, user.ID, private, listOptions) if err != nil { return nil, 0, err } repos := make([]*api.Repository, len(watchedRepos)) for i, watched := range watchedRepos { - access, err := access_model.AccessLevel(user, watched) + access, err := access_model.AccessLevel(ctx, user, watched) if err != nil { return nil, 0, err } @@ -61,7 +62,7 @@ func GetWatchedRepos(ctx *context.APIContext) { // "$ref": "#/responses/RepositoryList" private := ctx.ContextUser.ID == ctx.Doer.ID - repos, total, err := getWatchedRepos(ctx.ContextUser, private, utils.GetListOptions(ctx)) + repos, total, err := getWatchedRepos(ctx, ctx.ContextUser, private, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "getWatchedRepos", err) } @@ -90,7 +91,7 @@ func GetMyWatchedRepos(ctx *context.APIContext) { // "200": // "$ref": "#/responses/RepositoryList" - repos, total, err := getWatchedRepos(ctx.Doer, true, utils.GetListOptions(ctx)) + repos, total, err := getWatchedRepos(ctx, ctx.Doer, true, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "getWatchedRepos", err) } diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 93aa450f9c..1370e5302b 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -202,7 +202,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { continue } - pr, err := issues_model.GetUnmergedPullRequest(repo.ID, baseRepo.ID, branch, baseRepo.DefaultBranch, issues_model.PullRequestFlowGithub) + pr, err := issues_model.GetUnmergedPullRequest(ctx, repo.ID, baseRepo.ID, branch, baseRepo.DefaultBranch, issues_model.PullRequestFlowGithub) if err != nil && !issues_model.IsErrPullRequestNotExist(err) { log.Error("Failed to get active PR in: %-v Branch: %s to: %-v Branch: %s Error: %v", repo, branch, baseRepo, baseRepo.DefaultBranch, err) ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index fdd0a0bc3a..86bdf60ab9 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -372,7 +372,7 @@ func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID, refFullName if !ctx.gotProtectedTags { var err error - ctx.protectedTags, err = git_model.GetProtectedTags(ctx.Repo.Repository.ID) + ctx.protectedTags, err = git_model.GetProtectedTags(ctx, ctx.Repo.Repository.ID) if err != nil { log.Error("Unable to get protected tags for %-v Error: %v", ctx.Repo.Repository, err) ctx.JSON(http.StatusInternalServerError, private.Response{ @@ -383,7 +383,7 @@ func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID, refFullName ctx.gotProtectedTags = true } - isAllowed, err := git_model.IsUserAllowedToControlTag(ctx.protectedTags, tagName, ctx.opts.UserID) + isAllowed, err := git_model.IsUserAllowedToControlTag(ctx, ctx.protectedTags, tagName, ctx.opts.UserID) if err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), diff --git a/routers/web/explore/repo.go b/routers/web/explore/repo.go index 8cb615b7bc..8d4ecf1bc0 100644 --- a/routers/web/explore/repo.go +++ b/routers/web/explore/repo.go @@ -98,7 +98,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { language := ctx.FormTrim("language") ctx.Data["Language"] = language - repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: page, PageSize: opts.PageSize, diff --git a/routers/web/home.go b/routers/web/home.go index 0c74987ba7..7640243ba0 100644 --- a/routers/web/home.go +++ b/routers/web/home.go @@ -88,7 +88,7 @@ func HomeSitemap(ctx *context.Context) { } } - _, cnt, err := repo_model.SearchRepository(&repo_model.SearchRepoOptions{ + _, cnt, err := repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: 1, }, diff --git a/routers/web/org/home.go b/routers/web/org/home.go index 63243a391f..6bd8a89d12 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -99,7 +99,7 @@ func Home(ctx *context.Context) { count int64 err error ) - repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index d1f1255db4..a7588d275d 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -275,14 +275,14 @@ func loadOneBranch(ctx *context.Context, rawBranch, defaultBranch *git.Branch, p mergeMovedOn := false if pr != nil { pr.HeadRepo = ctx.Repo.Repository - if err := pr.LoadIssue(); err != nil { - ctx.ServerError("pr.LoadIssue", err) + if err := pr.LoadIssue(ctx); err != nil { + ctx.ServerError("LoadIssue", err) return nil } if repo, ok := repoIDToRepo[pr.BaseRepoID]; ok { pr.BaseRepo = repo - } else if err := pr.LoadBaseRepoCtx(ctx); err != nil { - ctx.ServerError("pr.LoadBaseRepo", err) + } else if err := pr.LoadBaseRepo(ctx); err != nil { + ctx.ServerError("LoadBaseRepo", err) return nil } else { repoIDToRepo[pr.BaseRepoID] = pr.BaseRepo diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index db6b59471f..0fb8e44725 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -747,7 +747,7 @@ func CompareDiff(ctx *context.Context) { ctx.Data["HeadTags"] = headTags if ctx.Data["PageIsComparePull"] == true { - pr, err := issues_model.GetUnmergedPullRequest(ci.HeadRepo.ID, ctx.Repo.Repository.ID, ci.HeadBranch, ci.BaseBranch, issues_model.PullRequestFlowGithub) + pr, err := issues_model.GetUnmergedPullRequest(ctx, ci.HeadRepo.ID, ctx.Repo.Repository.ID, ci.HeadBranch, ci.BaseBranch, issues_model.PullRequestFlowGithub) if err != nil { if !issues_model.IsErrPullRequestNotExist(err) { ctx.ServerError("GetUnmergedPullRequest", err) @@ -755,7 +755,7 @@ func CompareDiff(ctx *context.Context) { } } else { ctx.Data["HasPullRequest"] = true - if err := pr.LoadIssue(); err != nil { + if err := pr.LoadIssue(ctx); err != nil { ctx.ServerError("LoadIssue", err) return } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 38ad593c17..a62084fdca 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -246,7 +246,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti if forceEmpty { issues = []*issues_model.Issue{} } else { - issues, err = issues_model.Issues(&issues_model.IssuesOptions{ + issues, err = issues_model.Issues(ctx, &issues_model.IssuesOptions{ ListOptions: db.ListOptions{ Page: pager.Paginater.Current(), PageSize: setting.UI.IssuePagingNum, @@ -608,7 +608,7 @@ func RetrieveRepoReviewers(ctx *context.Context, repo *repo_model.Repository, is currentPullReviewers := make([]*repoReviewerSelection, 0, len(pullReviews)) for _, item := range pullReviews { if item.Review.ReviewerID > 0 { - if err = item.Review.LoadReviewer(); err != nil { + if err = item.Review.LoadReviewer(ctx); err != nil { if user_model.IsErrUserNotExist(err) { continue } @@ -617,7 +617,7 @@ func RetrieveRepoReviewers(ctx *context.Context, repo *repo_model.Repository, is } item.User = item.Review.Reviewer } else if item.Review.ReviewerTeamID > 0 { - if err = item.Review.LoadReviewerTeam(); err != nil { + if err = item.Review.LoadReviewerTeam(ctx); err != nil { if organization.IsErrTeamNotExist(err) { continue } @@ -1163,7 +1163,7 @@ func getBranchData(ctx *context.Context, issue *issues_model.Issue) { pull := issue.PullRequest ctx.Data["BaseBranch"] = pull.BaseBranch ctx.Data["HeadBranch"] = pull.HeadBranch - ctx.Data["HeadUserName"] = pull.MustHeadUserName() + ctx.Data["HeadUserName"] = pull.MustHeadUserName(ctx) } } @@ -1426,13 +1426,13 @@ func ViewIssue(ctx *context.Context) { for _, comment = range issue.Comments { comment.Issue = issue - if err := comment.LoadPoster(); err != nil { + if err := comment.LoadPoster(ctx); err != nil { ctx.ServerError("LoadPoster", err) return } if comment.Type == issues_model.CommentTypeComment || comment.Type == issues_model.CommentTypeReview { - if err := comment.LoadAttachments(); err != nil { + if err := comment.LoadAttachments(ctx); err != nil { ctx.ServerError("LoadAttachments", err) return } @@ -1467,7 +1467,7 @@ func ViewIssue(ctx *context.Context) { return } } else if comment.Type == issues_model.CommentTypeMilestone { - if err = comment.LoadMilestone(); err != nil { + if err = comment.LoadMilestone(ctx); err != nil { ctx.ServerError("LoadMilestone", err) return } @@ -1591,7 +1591,7 @@ func ViewIssue(ctx *context.Context) { ctx.Data["AllowMerge"] = false if ctx.IsSigned { - if err := pull.LoadHeadRepoCtx(ctx); err != nil { + if err := pull.LoadHeadRepo(ctx); err != nil { log.Error("LoadHeadRepo: %v", err) } else if pull.HeadRepo != nil { perm, err := access_model.GetUserRepoPermission(ctx, pull.HeadRepo, ctx.Doer) @@ -1613,7 +1613,7 @@ func ViewIssue(ctx *context.Context) { } } - if err := pull.LoadBaseRepoCtx(ctx); err != nil { + if err := pull.LoadBaseRepo(ctx); err != nil { log.Error("LoadBaseRepo: %v", err) } perm, err := access_model.GetUserRepoPermission(ctx, pull.BaseRepo, ctx.Doer) @@ -1662,14 +1662,14 @@ func ViewIssue(ctx *context.Context) { ctx.Data["MergeStyle"] = mergeStyle - defaultMergeMessage, err := pull_service.GetDefaultMergeMessage(ctx.Repo.GitRepo, pull, mergeStyle) + defaultMergeMessage, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, mergeStyle) if err != nil { ctx.ServerError("GetDefaultMergeMessage", err) return } ctx.Data["DefaultMergeMessage"] = defaultMergeMessage - defaultSquashMergeMessage, err := pull_service.GetDefaultMergeMessage(ctx.Repo.GitRepo, pull, repo_model.MergeStyleSquash) + defaultSquashMergeMessage, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, repo_model.MergeStyleSquash) if err != nil { ctx.ServerError("GetDefaultSquashMergeMessage", err) return @@ -1885,7 +1885,7 @@ func GetIssueInfo(ctx *context.Context) { } } - ctx.JSON(http.StatusOK, convert.ToAPIIssue(issue)) + ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue)) } // UpdateIssueTitle change issue's title @@ -2280,7 +2280,7 @@ func SearchIssues(ctx *context.Context) { repoCond := repo_model.SearchRepositoryCondition(opts) repoIDs, _, err := repo_model.SearchRepositoryIDs(opts) if err != nil { - ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err.Error()) + ctx.Error(http.StatusInternalServerError, "SearchRepositoryIDs", err.Error()) return } @@ -2369,7 +2369,7 @@ func SearchIssues(ctx *context.Context) { issuesOpt.ReviewRequestedID = ctxUserID } - if issues, err = issues_model.Issues(issuesOpt); err != nil { + if issues, err = issues_model.Issues(ctx, issuesOpt); err != nil { ctx.Error(http.StatusInternalServerError, "Issues", err.Error()) return } @@ -2377,14 +2377,14 @@ func SearchIssues(ctx *context.Context) { issuesOpt.ListOptions = db.ListOptions{ Page: -1, } - if filteredCount, err = issues_model.CountIssues(issuesOpt); err != nil { + if filteredCount, err = issues_model.CountIssues(ctx, issuesOpt); err != nil { ctx.Error(http.StatusInternalServerError, "CountIssues", err.Error()) return } } ctx.SetTotalCountHeader(filteredCount) - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) } func getUserIDForFilter(ctx *context.Context, queryName string) int64 { @@ -2527,7 +2527,7 @@ func ListIssues(ctx *context.Context) { MentionedID: mentionedByID, } - if issues, err = issues_model.Issues(issuesOpt); err != nil { + if issues, err = issues_model.Issues(ctx, issuesOpt); err != nil { ctx.Error(http.StatusInternalServerError, err.Error()) return } @@ -2535,14 +2535,14 @@ func ListIssues(ctx *context.Context) { issuesOpt.ListOptions = db.ListOptions{ Page: -1, } - if filteredCount, err = issues_model.CountIssues(issuesOpt); err != nil { + if filteredCount, err = issues_model.CountIssues(ctx, issuesOpt); err != nil { ctx.Error(http.StatusInternalServerError, err.Error()) return } } ctx.SetTotalCountHeader(filteredCount) - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) } // UpdateIssueStatus change issue's status @@ -2562,7 +2562,7 @@ func UpdateIssueStatus(ctx *context.Context) { log.Warn("Unrecognized action: %s", action) } - if _, err := issues_model.IssueList(issues).LoadRepositories(); err != nil { + if _, err := issues_model.IssueList(issues).LoadRepositories(ctx); err != nil { ctx.ServerError("LoadRepositories", err) return } @@ -2646,7 +2646,7 @@ func NewComment(ctx *context.Context) { if form.Status == "reopen" && issue.IsPull { pull := issue.PullRequest var err error - pr, err = issues_model.GetUnmergedPullRequest(pull.HeadRepoID, pull.BaseRepoID, pull.HeadBranch, pull.BaseBranch, pull.Flow) + pr, err = issues_model.GetUnmergedPullRequest(ctx, pull.HeadRepoID, pull.BaseRepoID, pull.HeadBranch, pull.BaseBranch, pull.Flow) if err != nil { if !issues_model.IsErrPullRequestNotExist(err) { ctx.ServerError("GetUnmergedPullRequest", err) @@ -2706,7 +2706,7 @@ func NewComment(ctx *context.Context) { return } - comment, err := comment_service.CreateIssueComment(ctx.Doer, ctx.Repo.Repository, issue, form.Content, attachments) + comment, err := comment_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Content, attachments) if err != nil { ctx.ServerError("CreateIssueComment", err) return @@ -2723,7 +2723,7 @@ func UpdateCommentContent(ctx *context.Context) { return } - if err := comment.LoadIssue(); err != nil { + if err := comment.LoadIssue(ctx); err != nil { ctx.NotFoundOrServerError("LoadIssue", issues_model.IsErrIssueNotExist, err) return } @@ -2746,12 +2746,12 @@ func UpdateCommentContent(ctx *context.Context) { }) return } - if err = comment_service.UpdateComment(comment, ctx.Doer, oldContent); err != nil { + if err = comment_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { ctx.ServerError("UpdateComment", err) return } - if err := comment.LoadAttachments(); err != nil { + if err := comment.LoadAttachments(ctx); err != nil { ctx.ServerError("LoadAttachments", err) return } @@ -2789,7 +2789,7 @@ func DeleteComment(ctx *context.Context) { return } - if err := comment.LoadIssue(); err != nil { + if err := comment.LoadIssue(ctx); err != nil { ctx.NotFoundOrServerError("LoadIssue", issues_model.IsErrIssueNotExist, err) return } @@ -2802,8 +2802,8 @@ func DeleteComment(ctx *context.Context) { return } - if err = comment_service.DeleteComment(ctx.Doer, comment); err != nil { - ctx.ServerError("DeleteCommentByID", err) + if err = comment_service.DeleteComment(ctx, ctx.Doer, comment); err != nil { + ctx.ServerError("DeleteComment", err) return } @@ -2915,7 +2915,7 @@ func ChangeCommentReaction(ctx *context.Context) { return } - if err := comment.LoadIssue(); err != nil { + if err := comment.LoadIssue(ctx); err != nil { ctx.NotFoundOrServerError("LoadIssue", issues_model.IsErrIssueNotExist, err) return } @@ -3061,7 +3061,7 @@ func GetCommentAttachments(ctx *context.Context) { } attachments := make([]*api.Attachment, 0) if comment.Type == issues_model.CommentTypeComment { - if err := comment.LoadAttachments(); err != nil { + if err := comment.LoadAttachments(ctx); err != nil { ctx.ServerError("LoadAttachments", err) return } diff --git a/routers/web/repo/issue_label.go b/routers/web/repo/issue_label.go index 7af415a8fa..560f25a0af 100644 --- a/routers/web/repo/issue_label.go +++ b/routers/web/repo/issue_label.go @@ -75,7 +75,7 @@ func RetrieveLabels(ctx *context.Context) { return } for _, l := range orgLabels { - l.CalOpenOrgIssues(ctx.Repo.Repository.ID, l.ID) + l.CalOpenOrgIssues(ctx, ctx.Repo.Repository.ID, l.ID) } ctx.Data["OrgLabels"] = orgLabels diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index f054ad6e54..fb2d25a22b 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -297,7 +297,7 @@ func ViewProject(ctx *context.Context) { boards[0].Title = ctx.Tr("repo.projects.type.uncategorized") } - issuesMap, err := issues_model.LoadIssuesFromBoardList(boards) + issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards) if err != nil { ctx.ServerError("LoadIssuesOfBoards", err) return @@ -314,7 +314,7 @@ func ViewProject(ctx *context.Context) { } if len(referencedIds) > 0 { - if linkedPrs, err := issues_model.Issues(&issues_model.IssuesOptions{ + if linkedPrs, err := issues_model.Issues(ctx, &issues_model.IssuesOptions{ IssueIDs: referencedIds, IsPull: util.OptionalBoolTrue, }); err == nil { diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 41eac7cc39..870bc1773b 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -281,7 +281,7 @@ func checkPullInfo(ctx *context.Context) *issues_model.Issue { } return nil } - if err = issue.LoadPoster(); err != nil { + if err = issue.LoadPoster(ctx); err != nil { ctx.ServerError("LoadPoster", err) return nil } @@ -297,12 +297,12 @@ func checkPullInfo(ctx *context.Context) *issues_model.Issue { return nil } - if err = issue.LoadPullRequest(); err != nil { + if err = issue.LoadPullRequest(ctx); err != nil { ctx.ServerError("LoadPullRequest", err) return nil } - if err = issue.PullRequest.LoadHeadRepoCtx(ctx); err != nil { + if err = issue.PullRequest.LoadHeadRepo(ctx); err != nil { ctx.ServerError("LoadHeadRepo", err) return nil } @@ -319,12 +319,12 @@ func checkPullInfo(ctx *context.Context) *issues_model.Issue { } func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) { - if ctx.Repo.Owner.Name == pull.MustHeadUserName() { + if ctx.Repo.Owner.Name == pull.MustHeadUserName(ctx) { ctx.Data["HeadTarget"] = pull.HeadBranch } else if pull.HeadRepo == nil { - ctx.Data["HeadTarget"] = pull.MustHeadUserName() + ":" + pull.HeadBranch + ctx.Data["HeadTarget"] = pull.MustHeadUserName(ctx) + ":" + pull.HeadBranch } else { - ctx.Data["HeadTarget"] = pull.MustHeadUserName() + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch + ctx.Data["HeadTarget"] = pull.MustHeadUserName(ctx) + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch } ctx.Data["BaseTarget"] = pull.BaseBranch ctx.Data["HeadBranchHTMLURL"] = pull.GetHeadBranchHTMLURL() @@ -416,12 +416,12 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C repo := ctx.Repo.Repository pull := issue.PullRequest - if err := pull.LoadHeadRepoCtx(ctx); err != nil { + if err := pull.LoadHeadRepo(ctx); err != nil { ctx.ServerError("LoadHeadRepo", err) return nil } - if err := pull.LoadBaseRepoCtx(ctx); err != nil { + if err := pull.LoadBaseRepo(ctx); err != nil { ctx.ServerError("LoadBaseRepo", err) return nil } @@ -606,7 +606,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C if pull.IsWorkInProgress() { ctx.Data["IsPullWorkInProgress"] = true - ctx.Data["WorkInProgressPrefix"] = pull.GetWorkInProgressPrefix() + ctx.Data["WorkInProgressPrefix"] = pull.GetWorkInProgressPrefix(ctx) } if pull.IsFilesConflicted() { @@ -834,11 +834,11 @@ func UpdatePullRequest(ctx *context.Context) { rebase := ctx.FormString("style") == "rebase" - if err := issue.PullRequest.LoadBaseRepoCtx(ctx); err != nil { + if err := issue.PullRequest.LoadBaseRepo(ctx); err != nil { ctx.ServerError("LoadBaseRepo", err) return } - if err := issue.PullRequest.LoadHeadRepoCtx(ctx); err != nil { + if err := issue.PullRequest.LoadHeadRepo(ctx); err != nil { ctx.ServerError("LoadHeadRepo", err) return } @@ -974,7 +974,7 @@ func MergePullRequest(ctx *context.Context) { message := strings.TrimSpace(form.MergeTitleField) if len(message) == 0 { var err error - message, err = pull_service.GetDefaultMergeMessage(ctx.Repo.GitRepo, pr, repo_model.MergeStyle(form.Do)) + message, err = pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pr, repo_model.MergeStyle(form.Do)) if err != nil { ctx.ServerError("GetDefaultMergeMessage", err) return @@ -1296,14 +1296,14 @@ func CleanUpPullRequest(ctx *context.Context) { return } - if err := pr.LoadHeadRepoCtx(ctx); err != nil { + if err := pr.LoadHeadRepo(ctx); err != nil { ctx.ServerError("LoadHeadRepo", err) return } else if pr.HeadRepo == nil { // Forked repository has already been deleted ctx.NotFound("CleanUpPullRequest", nil) return - } else if err = pr.LoadBaseRepoCtx(ctx); err != nil { + } else if err = pr.LoadBaseRepo(ctx); err != nil { ctx.ServerError("LoadBaseRepo", err) return } else if err = pr.HeadRepo.GetOwner(ctx); err != nil { @@ -1499,7 +1499,7 @@ func UpdatePullRequestTarget(ctx *context.Context) { } return } - notification.NotifyPullRequestChangeTargetBranch(ctx.Doer, pr, targetBranch) + notification.NotifyPullRequestChangeTargetBranch(ctx, ctx.Doer, pr, targetBranch) ctx.JSON(http.StatusOK, map[string]interface{}{ "base_branch": pr.BaseBranch, diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go index bc64f35472..bbaacc234c 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -114,7 +114,7 @@ func UpdateResolveConversation(ctx *context.Context) { return } - if err = comment.LoadIssue(); err != nil { + if err = comment.LoadIssue(ctx); err != nil { ctx.ServerError("comment.LoadIssue", err) return } @@ -169,7 +169,7 @@ func renderConversation(ctx *context.Context, comment *issues_model.Comment) { ctx.Data["comments"] = comments ctx.Data["CanMarkConversation"] = true ctx.Data["Issue"] = comment.Issue - if err = comment.Issue.LoadPullRequest(); err != nil { + if err = comment.Issue.LoadPullRequest(ctx); err != nil { ctx.ServerError("comment.Issue.LoadPullRequest", err) return } diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 0cb85f3798..0373d5b158 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -130,7 +130,7 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { opts.IncludeDrafts = writeAccess } - releases, err := repo_model.GetReleasesByRepoID(ctx.Repo.Repository.ID, opts) + releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, opts) if err != nil { ctx.ServerError("GetReleasesByRepoID", err) return @@ -266,7 +266,7 @@ func LatestRelease(ctx *context.Context) { return } - if err := release.LoadAttributes(); err != nil { + if err := release.LoadAttributes(ctx); err != nil { ctx.ServerError("LoadAttributes", err) return } @@ -289,7 +289,7 @@ func NewRelease(ctx *context.Context) { if rel != nil { rel.Repo = ctx.Repo.Repository - if err := rel.LoadAttributes(); err != nil { + if err := rel.LoadAttributes(ctx); err != nil { ctx.ServerError("LoadAttributes", err) return } @@ -454,7 +454,7 @@ func EditRelease(ctx *context.Context) { ctx.Data["IsDraft"] = rel.IsDraft rel.Repo = ctx.Repo.Repository - if err := rel.LoadAttributes(); err != nil { + if err := rel.LoadAttributes(ctx); err != nil { ctx.ServerError("LoadAttributes", err) return } diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 3e746d3f05..7bcca1d02a 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -540,7 +540,7 @@ func SearchRepo(ctx *context.Context) { } var err error - repos, count, err := repo_model.SearchRepository(opts) + repos, count, err := repo_model.SearchRepository(ctx, opts) if err != nil { ctx.JSON(http.StatusInternalServerError, api.SearchError{ OK: false, diff --git a/routers/web/repo/tag.go b/routers/web/repo/tag.go index f63a50782b..4d46716c30 100644 --- a/routers/web/repo/tag.go +++ b/routers/web/repo/tag.go @@ -124,7 +124,7 @@ func DeleteProtectedTagPost(ctx *context.Context) { return } - if err := git_model.DeleteProtectedTag(pt); err != nil { + if err := git_model.DeleteProtectedTag(ctx, pt); err != nil { ctx.ServerError("DeleteProtectedTag", err) return } @@ -137,7 +137,7 @@ func setTagsContext(ctx *context.Context) error { ctx.Data["Title"] = ctx.Tr("repo.settings") ctx.Data["PageIsSettingsTags"] = true - protectedTags, err := git_model.GetProtectedTags(ctx.Repo.Repository.ID) + protectedTags, err := git_model.GetProtectedTags(ctx, ctx.Repo.Repository.ID) if err != nil { ctx.ServerError("GetProtectedTags", err) return err diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index a10e12ee63..24d851762b 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -706,7 +706,7 @@ func NewWikiPost(ctx *context.Context) { return } - notification.NotifyNewWikiPage(ctx.Doer, ctx.Repo.Repository, wikiName, form.Message) + notification.NotifyNewWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName, form.Message) ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + wiki_service.NameToSubURL(wikiName)) } @@ -750,7 +750,7 @@ func EditWikiPost(ctx *context.Context) { return } - notification.NotifyEditWikiPage(ctx.Doer, ctx.Repo.Repository, newWikiName, form.Message) + notification.NotifyEditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, newWikiName, form.Message) ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + wiki_service.NameToSubURL(newWikiName)) } @@ -767,7 +767,7 @@ func DeleteWikiPagePost(ctx *context.Context) { return } - notification.NotifyDeleteWikiPage(ctx.Doer, ctx.Repo.Repository, wikiName) + notification.NotifyDeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName) ctx.JSON(http.StatusOK, map[string]interface{}{ "redirect": ctx.Repo.RepoLink + "/wiki/", diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 95ec1aa2fa..e67202b284 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -202,7 +202,7 @@ func Milestones(ctx *context.Context) { return } - showRepos, _, err := repo_model.SearchRepositoryByCondition(&repoOpts, userRepoCond, false) + showRepos, _, err := repo_model.SearchRepositoryByCondition(ctx, &repoOpts, userRepoCond, false) if err != nil { ctx.ServerError("SearchRepositoryByCondition", err) return @@ -461,7 +461,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { // USING NON-FINAL STATE OF opts FOR A QUERY. var issueCountByRepo map[int64]int64 if !forceEmpty { - issueCountByRepo, err = issues_model.CountIssuesByRepo(opts) + issueCountByRepo, err = issues_model.CountIssuesByRepo(ctx, opts) if err != nil { ctx.ServerError("CountIssuesByRepo", err) return @@ -504,7 +504,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { // USING FINAL STATE OF opts FOR A QUERY. var issues []*issues_model.Issue if !forceEmpty { - issues, err = issues_model.Issues(opts) + issues, err = issues_model.Issues(ctx, opts) if err != nil { ctx.ServerError("Issues", err) return diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go index b4753a603e..323422a1b9 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -33,20 +33,20 @@ const ( ) // GetNotificationCount is the middleware that sets the notification count in the context -func GetNotificationCount(c *context.Context) { - if strings.HasPrefix(c.Req.URL.Path, "/api") { +func GetNotificationCount(ctx *context.Context) { + if strings.HasPrefix(ctx.Req.URL.Path, "/api") { return } - if !c.IsSigned { + if !ctx.IsSigned { return } - c.Data["NotificationUnreadCount"] = func() int64 { - count, err := activities_model.GetNotificationCount(c, c.Doer, activities_model.NotificationStatusUnread) + ctx.Data["NotificationUnreadCount"] = func() int64 { + count, err := activities_model.GetNotificationCount(ctx, ctx.Doer, activities_model.NotificationStatusUnread) if err != nil { if err != goctx.Canceled { - log.Error("Unable to GetNotificationCount for user:%-v: %v", c.Doer, err) + log.Error("Unable to GetNotificationCount for user:%-v: %v", ctx.Doer, err) } return -1 } @@ -56,25 +56,25 @@ func GetNotificationCount(c *context.Context) { } // Notifications is the notifications page -func Notifications(c *context.Context) { - getNotifications(c) - if c.Written() { +func Notifications(ctx *context.Context) { + getNotifications(ctx) + if ctx.Written() { return } - if c.FormBool("div-only") { - c.Data["SequenceNumber"] = c.FormString("sequence-number") - c.HTML(http.StatusOK, tplNotificationDiv) + if ctx.FormBool("div-only") { + ctx.Data["SequenceNumber"] = ctx.FormString("sequence-number") + ctx.HTML(http.StatusOK, tplNotificationDiv) return } - c.HTML(http.StatusOK, tplNotification) + ctx.HTML(http.StatusOK, tplNotification) } -func getNotifications(c *context.Context) { +func getNotifications(ctx *context.Context) { var ( - keyword = c.FormTrim("q") + keyword = ctx.FormTrim("q") status activities_model.NotificationStatus - page = c.FormInt("page") - perPage = c.FormInt("perPage") + page = ctx.FormInt("page") + perPage = ctx.FormInt("perPage") ) if page < 1 { page = 1 @@ -90,74 +90,74 @@ func getNotifications(c *context.Context) { status = activities_model.NotificationStatusUnread } - total, err := activities_model.GetNotificationCount(c, c.Doer, status) + total, err := activities_model.GetNotificationCount(ctx, ctx.Doer, status) if err != nil { - c.ServerError("ErrGetNotificationCount", err) + ctx.ServerError("ErrGetNotificationCount", err) return } // redirect to last page if request page is more than total pages pager := context.NewPagination(int(total), perPage, page, 5) if pager.Paginater.Current() < page { - c.Redirect(fmt.Sprintf("%s/notifications?q=%s&page=%d", setting.AppSubURL, url.QueryEscape(c.FormString("q")), pager.Paginater.Current())) + ctx.Redirect(fmt.Sprintf("%s/notifications?q=%s&page=%d", setting.AppSubURL, url.QueryEscape(ctx.FormString("q")), pager.Paginater.Current())) return } statuses := []activities_model.NotificationStatus{status, activities_model.NotificationStatusPinned} - notifications, err := activities_model.NotificationsForUser(c, c.Doer, statuses, page, perPage) + notifications, err := activities_model.NotificationsForUser(ctx, ctx.Doer, statuses, page, perPage) if err != nil { - c.ServerError("ErrNotificationsForUser", err) + ctx.ServerError("ErrNotificationsForUser", err) return } failCount := 0 - repos, failures, err := notifications.LoadRepos() + repos, failures, err := notifications.LoadRepos(ctx) if err != nil { - c.ServerError("LoadRepos", err) + ctx.ServerError("LoadRepos", err) return } notifications = notifications.Without(failures) - if err := repos.LoadAttributes(); err != nil { - c.ServerError("LoadAttributes", err) + if err := repos.LoadAttributes(); err != nil { // TODO + ctx.ServerError("LoadAttributes", err) return } failCount += len(failures) - failures, err = notifications.LoadIssues() + failures, err = notifications.LoadIssues(ctx) if err != nil { - c.ServerError("LoadIssues", err) + ctx.ServerError("LoadIssues", err) return } notifications = notifications.Without(failures) failCount += len(failures) - failures, err = notifications.LoadComments() + failures, err = notifications.LoadComments(ctx) if err != nil { - c.ServerError("LoadComments", err) + ctx.ServerError("LoadComments", err) return } notifications = notifications.Without(failures) failCount += len(failures) if failCount > 0 { - c.Flash.Error(fmt.Sprintf("ERROR: %d notifications were removed due to missing parts - check the logs", failCount)) + ctx.Flash.Error(fmt.Sprintf("ERROR: %d notifications were removed due to missing parts - check the logs", failCount)) } - c.Data["Title"] = c.Tr("notifications") - c.Data["Keyword"] = keyword - c.Data["Status"] = status - c.Data["Notifications"] = notifications + ctx.Data["Title"] = ctx.Tr("notifications") + ctx.Data["Keyword"] = keyword + ctx.Data["Status"] = status + ctx.Data["Notifications"] = notifications - pager.SetDefaultParams(c) - c.Data["Page"] = pager + pager.SetDefaultParams(ctx) + ctx.Data["Page"] = pager } // NotificationStatusPost is a route for changing the status of a notification -func NotificationStatusPost(c *context.Context) { +func NotificationStatusPost(ctx *context.Context) { var ( - notificationID = c.FormInt64("notification_id") - statusStr = c.FormString("status") + notificationID = ctx.FormInt64("notification_id") + statusStr = ctx.FormString("status") status activities_model.NotificationStatus ) @@ -169,56 +169,56 @@ func NotificationStatusPost(c *context.Context) { case "pinned": status = activities_model.NotificationStatusPinned default: - c.ServerError("InvalidNotificationStatus", errors.New("Invalid notification status")) + ctx.ServerError("InvalidNotificationStatus", errors.New("Invalid notification status")) return } - if _, err := activities_model.SetNotificationStatus(notificationID, c.Doer, status); err != nil { - c.ServerError("SetNotificationStatus", err) + if _, err := activities_model.SetNotificationStatus(ctx, notificationID, ctx.Doer, status); err != nil { + ctx.ServerError("SetNotificationStatus", err) return } - if !c.FormBool("noredirect") { - url := fmt.Sprintf("%s/notifications?page=%s", setting.AppSubURL, url.QueryEscape(c.FormString("page"))) - c.Redirect(url, http.StatusSeeOther) + if !ctx.FormBool("noredirect") { + url := fmt.Sprintf("%s/notifications?page=%s", setting.AppSubURL, url.QueryEscape(ctx.FormString("page"))) + ctx.Redirect(url, http.StatusSeeOther) } - getNotifications(c) - if c.Written() { + getNotifications(ctx) + if ctx.Written() { return } - c.Data["Link"] = setting.AppURL + "notifications" - c.Data["SequenceNumber"] = c.Req.PostFormValue("sequence-number") + ctx.Data["Link"] = setting.AppURL + "notifications" + ctx.Data["SequenceNumber"] = ctx.Req.PostFormValue("sequence-number") - c.HTML(http.StatusOK, tplNotificationDiv) + ctx.HTML(http.StatusOK, tplNotificationDiv) } // NotificationPurgePost is a route for 'purging' the list of notifications - marking all unread as read -func NotificationPurgePost(c *context.Context) { - err := activities_model.UpdateNotificationStatuses(c.Doer, activities_model.NotificationStatusUnread, activities_model.NotificationStatusRead) +func NotificationPurgePost(ctx *context.Context) { + err := activities_model.UpdateNotificationStatuses(ctx, ctx.Doer, activities_model.NotificationStatusUnread, activities_model.NotificationStatusRead) if err != nil { - c.ServerError("ErrUpdateNotificationStatuses", err) + ctx.ServerError("UpdateNotificationStatuses", err) return } - c.Redirect(setting.AppSubURL+"/notifications", http.StatusSeeOther) + ctx.Redirect(setting.AppSubURL+"/notifications", http.StatusSeeOther) } // NotificationSubscriptions returns the list of subscribed issues -func NotificationSubscriptions(c *context.Context) { - page := c.FormInt("page") +func NotificationSubscriptions(ctx *context.Context) { + page := ctx.FormInt("page") if page < 1 { page = 1 } - sortType := c.FormString("sort") - c.Data["SortType"] = sortType + sortType := ctx.FormString("sort") + ctx.Data["SortType"] = sortType - state := c.FormString("state") + state := ctx.FormString("state") if !util.IsStringInSlice(state, []string{"all", "open", "closed"}, true) { state = "all" } - c.Data["State"] = state + ctx.Data["State"] = state var showClosed util.OptionalBool switch state { case "all": @@ -230,7 +230,7 @@ func NotificationSubscriptions(c *context.Context) { } var issueTypeBool util.OptionalBool - issueType := c.FormString("issueType") + issueType := ctx.FormString("issueType") switch issueType { case "issues": issueTypeBool = util.OptionalBoolFalse @@ -239,71 +239,71 @@ func NotificationSubscriptions(c *context.Context) { default: issueTypeBool = util.OptionalBoolNone } - c.Data["IssueType"] = issueType + ctx.Data["IssueType"] = issueType var labelIDs []int64 - selectedLabels := c.FormString("labels") - c.Data["Labels"] = selectedLabels + selectedLabels := ctx.FormString("labels") + ctx.Data["Labels"] = selectedLabels if len(selectedLabels) > 0 && selectedLabels != "0" { var err error labelIDs, err = base.StringsToInt64s(strings.Split(selectedLabels, ",")) if err != nil { - c.ServerError("StringsToInt64s", err) + ctx.ServerError("StringsToInt64s", err) return } } - count, err := issues_model.CountIssues(&issues_model.IssuesOptions{ - SubscriberID: c.Doer.ID, + count, err := issues_model.CountIssues(ctx, &issues_model.IssuesOptions{ + SubscriberID: ctx.Doer.ID, IsClosed: showClosed, IsPull: issueTypeBool, LabelIDs: labelIDs, }) if err != nil { - c.ServerError("CountIssues", err) + ctx.ServerError("CountIssues", err) return } - issues, err := issues_model.Issues(&issues_model.IssuesOptions{ + issues, err := issues_model.Issues(ctx, &issues_model.IssuesOptions{ ListOptions: db.ListOptions{ PageSize: setting.UI.IssuePagingNum, Page: page, }, - SubscriberID: c.Doer.ID, + SubscriberID: ctx.Doer.ID, SortType: sortType, IsClosed: showClosed, IsPull: issueTypeBool, LabelIDs: labelIDs, }) if err != nil { - c.ServerError("Issues", err) + ctx.ServerError("Issues", err) return } - commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(c, issues) + commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues) if err != nil { - c.ServerError("GetIssuesAllCommitStatus", err) + ctx.ServerError("GetIssuesAllCommitStatus", err) return } - c.Data["CommitLastStatus"] = lastStatus - c.Data["CommitStatuses"] = commitStatuses - c.Data["Issues"] = issues + ctx.Data["CommitLastStatus"] = lastStatus + ctx.Data["CommitStatuses"] = commitStatuses + ctx.Data["Issues"] = issues - c.Data["IssueRefEndNames"], c.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, "") + ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, "") - commitStatus, err := pull_service.GetIssuesLastCommitStatus(c, issues) + commitStatus, err := pull_service.GetIssuesLastCommitStatus(ctx, issues) if err != nil { - c.ServerError("GetIssuesLastCommitStatus", err) + ctx.ServerError("GetIssuesLastCommitStatus", err) return } - c.Data["CommitStatus"] = commitStatus + ctx.Data["CommitStatus"] = commitStatus issueList := issues_model.IssueList(issues) - approvalCounts, err := issueList.GetApprovalCounts(c) + approvalCounts, err := issueList.GetApprovalCounts(ctx) if err != nil { - c.ServerError("ApprovalCounts", err) + ctx.ServerError("ApprovalCounts", err) return } - c.Data["ApprovalCounts"] = func(issueID int64, typ string) int64 { + ctx.Data["ApprovalCounts"] = func(issueID int64, typ string) int64 { counts, ok := approvalCounts[issueID] if !ok || len(counts) == 0 { return 0 @@ -322,32 +322,32 @@ func NotificationSubscriptions(c *context.Context) { return 0 } - c.Data["Status"] = 1 - c.Data["Title"] = c.Tr("notification.subscriptions") + ctx.Data["Status"] = 1 + ctx.Data["Title"] = ctx.Tr("notification.subscriptions") // redirect to last page if request page is more than total pages pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) if pager.Paginater.Current() < page { - c.Redirect(fmt.Sprintf("/notifications/subscriptions?page=%d", pager.Paginater.Current())) + ctx.Redirect(fmt.Sprintf("/notifications/subscriptions?page=%d", pager.Paginater.Current())) return } - pager.AddParam(c, "sort", "SortType") - pager.AddParam(c, "state", "State") - c.Data["Page"] = pager + pager.AddParam(ctx, "sort", "SortType") + pager.AddParam(ctx, "state", "State") + ctx.Data["Page"] = pager - c.HTML(http.StatusOK, tplNotificationSubscriptions) + ctx.HTML(http.StatusOK, tplNotificationSubscriptions) } // NotificationWatching returns the list of watching repos -func NotificationWatching(c *context.Context) { - page := c.FormInt("page") +func NotificationWatching(ctx *context.Context) { + page := ctx.FormInt("page") if page < 1 { page = 1 } var orderBy db.SearchOrderBy - c.Data["SortType"] = c.FormString("sort") - switch c.FormString("sort") { + ctx.Data["SortType"] = ctx.FormString("sort") + switch ctx.FormString("sort") { case "newest": orderBy = db.SearchOrderByNewest case "oldest": @@ -369,41 +369,41 @@ func NotificationWatching(c *context.Context) { case "fewestforks": orderBy = db.SearchOrderByForks default: - c.Data["SortType"] = "recentupdate" + ctx.Data["SortType"] = "recentupdate" orderBy = db.SearchOrderByRecentUpdated } - repos, count, err := repo_model.SearchRepository(&repo_model.SearchRepoOptions{ + repos, count, err := repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, }, - Actor: c.Doer, - Keyword: c.FormTrim("q"), + Actor: ctx.Doer, + Keyword: ctx.FormTrim("q"), OrderBy: orderBy, - Private: c.IsSigned, - WatchedByID: c.Doer.ID, + Private: ctx.IsSigned, + WatchedByID: ctx.Doer.ID, Collaborate: util.OptionalBoolFalse, - TopicOnly: c.FormBool("topic"), + TopicOnly: ctx.FormBool("topic"), IncludeDescription: setting.UI.SearchRepoDescription, }) if err != nil { - c.ServerError("ErrSearchRepository", err) + ctx.ServerError("SearchRepository", err) return } total := int(count) - c.Data["Total"] = total - c.Data["Repos"] = repos + ctx.Data["Total"] = total + ctx.Data["Repos"] = repos // redirect to last page if request page is more than total pages pager := context.NewPagination(total, setting.UI.User.RepoPagingNum, page, 5) - pager.SetDefaultParams(c) - c.Data["Page"] = pager + pager.SetDefaultParams(ctx) + ctx.Data["Page"] = pager - c.Data["Status"] = 2 - c.Data["Title"] = c.Tr("notification.watching") + ctx.Data["Status"] = 2 + ctx.Data["Title"] = ctx.Tr("notification.watching") - c.HTML(http.StatusOK, tplNotificationSubscriptions) + ctx.HTML(http.StatusOK, tplNotificationSubscriptions) } // NewAvailable returns the notification counts diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 6e16b377db..982290e0ab 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -203,7 +203,7 @@ func Profile(ctx *context.Context) { } case "stars": ctx.Data["PageIsProfileStarList"] = true - repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, @@ -235,7 +235,7 @@ func Profile(ctx *context.Context) { return } case "watching": - repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, @@ -257,7 +257,7 @@ func Profile(ctx *context.Context) { total = int(count) default: - repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, diff --git a/services/agit/agit.go b/services/agit/agit.go index a7e701d6c4..803ff696b0 100644 --- a/services/agit/agit.go +++ b/services/agit/agit.go @@ -96,7 +96,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. headBranch = curentTopicBranch } - pr, err := issues_model.GetUnmergedPullRequest(repo.ID, repo.ID, headBranch, baseBranchName, issues_model.PullRequestFlowAGit) + pr, err := issues_model.GetUnmergedPullRequest(ctx, repo.ID, repo.ID, headBranch, baseBranchName, issues_model.PullRequestFlowAGit) if err != nil { if !issues_model.IsErrPullRequestNotExist(err) { return nil, fmt.Errorf("Failed to get unmerged agit flow pull request in repository: %s/%s Error: %w", ownerName, repoName, err) @@ -159,7 +159,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. } // update exist pull request - if err := pr.LoadBaseRepoCtx(ctx); err != nil { + if err := pr.LoadBaseRepo(ctx); err != nil { return nil, fmt.Errorf("Unable to load base repository for PR[%d] Error: %w", pr.ID, err) } @@ -203,15 +203,15 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. if err != nil { return nil, fmt.Errorf("Failed to get user. Error: %w", err) } - err = pr.LoadIssue() + err = pr.LoadIssue(ctx) if err != nil { return nil, fmt.Errorf("Failed to load pull issue. Error: %w", err) } comment, err := issues_model.CreatePushPullComment(ctx, pusher, pr, oldCommitID, opts.NewCommitIDs[i]) if err == nil && comment != nil { - notification.NotifyPullRequestPushCommits(pusher, pr, comment) + notification.NotifyPullRequestPushCommits(ctx, pusher, pr, comment) } - notification.NotifyPullRequestSynchronized(pusher, pr) + notification.NotifyPullRequestSynchronized(ctx, pusher, pr) isForcePush := comment != nil && comment.IsForcePush results = append(results, private.HookProcReceiveRefResult{ diff --git a/services/asymkey/sign.go b/services/asymkey/sign.go index edfd0f6cad..a9d1e179ae 100644 --- a/services/asymkey/sign.go +++ b/services/asymkey/sign.go @@ -272,7 +272,7 @@ Loop: // SignMerge determines if we should sign a PR merge commit to the base repository func SignMerge(ctx context.Context, pr *issues_model.PullRequest, u *user_model.User, tmpBasePath, baseCommit, headCommit string) (bool, string, *git.Signature, error) { - if err := pr.LoadBaseRepoCtx(ctx); err != nil { + if err := pr.LoadBaseRepo(ctx); err != nil { log.Error("Unable to get Base Repo for pull request") return false, "", nil, err } diff --git a/services/automerge/automerge.go b/services/automerge/automerge.go index 5c38367e3b..3291ed31f0 100644 --- a/services/automerge/automerge.go +++ b/services/automerge/automerge.go @@ -188,8 +188,8 @@ func handlePull(pullID int64, sha string) { // We get the latest sha commit hash again to handle the case where the check of a previous push // did not succeed or was not finished yet. - if err = pr.LoadHeadRepoCtx(ctx); err != nil { - log.Error("pull[%d] LoadHeadRepoCtx: %v", pr.ID, err) + if err = pr.LoadHeadRepo(ctx); err != nil { + log.Error("pull[%d] LoadHeadRepo: %v", pr.ID, err) return } @@ -244,8 +244,8 @@ func handlePull(pullID int64, sha string) { if pr.BaseRepoID == pr.HeadRepoID { baseGitRepo = headGitRepo } else { - if err = pr.LoadBaseRepoCtx(ctx); err != nil { - log.Error("LoadBaseRepoCtx: %v", err) + if err = pr.LoadBaseRepo(ctx); err != nil { + log.Error("LoadBaseRepo: %v", err) return } diff --git a/services/comments/comments.go b/services/comments/comments.go index 7167219c20..190b8a6725 100644 --- a/services/comments/comments.go +++ b/services/comments/comments.go @@ -5,6 +5,8 @@ package comments import ( + "context" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" @@ -14,7 +16,7 @@ import ( ) // CreateIssueComment creates a plain issue comment. -func CreateIssueComment(doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, content string, attachments []string) (*issues_model.Comment, error) { +func CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, content string, attachments []string) (*issues_model.Comment, error) { comment, err := issues_model.CreateComment(&issues_model.CreateCommentOptions{ Type: issues_model.CommentTypeComment, Doer: doer, @@ -27,27 +29,27 @@ func CreateIssueComment(doer *user_model.User, repo *repo_model.Repository, issu return nil, err } - mentions, err := issues_model.FindAndUpdateIssueMentions(db.DefaultContext, issue, doer, comment.Content) + mentions, err := issues_model.FindAndUpdateIssueMentions(ctx, issue, doer, comment.Content) if err != nil { return nil, err } - notification.NotifyCreateIssueComment(doer, repo, issue, comment, mentions) + notification.NotifyCreateIssueComment(ctx, doer, repo, issue, comment, mentions) return comment, nil } // UpdateComment updates information of comment. -func UpdateComment(c *issues_model.Comment, doer *user_model.User, oldContent string) error { +func UpdateComment(ctx context.Context, c *issues_model.Comment, doer *user_model.User, oldContent string) error { needsContentHistory := c.Content != oldContent && (c.Type == issues_model.CommentTypeComment || c.Type == issues_model.CommentTypeReview || c.Type == issues_model.CommentTypeCode) if needsContentHistory { - hasContentHistory, err := issues_model.HasIssueContentHistory(db.DefaultContext, c.IssueID, c.ID) + hasContentHistory, err := issues_model.HasIssueContentHistory(ctx, c.IssueID, c.ID) if err != nil { return err } if !hasContentHistory { - if err = issues_model.SaveIssueContentHistory(db.DefaultContext, c.PosterID, c.IssueID, c.ID, + if err = issues_model.SaveIssueContentHistory(ctx, c.PosterID, c.IssueID, c.ID, c.CreatedUnix, oldContent, true); err != nil { return err } @@ -59,33 +61,27 @@ func UpdateComment(c *issues_model.Comment, doer *user_model.User, oldContent st } if needsContentHistory { - err := issues_model.SaveIssueContentHistory(db.DefaultContext, doer.ID, c.IssueID, c.ID, timeutil.TimeStampNow(), c.Content, false) + err := issues_model.SaveIssueContentHistory(ctx, doer.ID, c.IssueID, c.ID, timeutil.TimeStampNow(), c.Content, false) if err != nil { return err } } - notification.NotifyUpdateComment(doer, c, oldContent) + notification.NotifyUpdateComment(ctx, doer, c, oldContent) return nil } // DeleteComment deletes the comment -func DeleteComment(doer *user_model.User, comment *issues_model.Comment) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func DeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) error { + err := db.AutoTx(ctx, func(ctx context.Context) error { + return issues_model.DeleteComment(ctx, comment) + }) if err != nil { return err } - defer committer.Close() - if err := issues_model.DeleteComment(ctx, comment); err != nil { - return err - } - if err := committer.Commit(); err != nil { - return err - } - - notification.NotifyDeleteComment(doer, comment) + notification.NotifyDeleteComment(ctx, doer, comment) return nil } diff --git a/services/issue/assignee.go b/services/issue/assignee.go index e24f8500c9..291fc31637 100644 --- a/services/issue/assignee.go +++ b/services/issue/assignee.go @@ -51,13 +51,13 @@ func ToggleAssignee(issue *issues_model.Issue, doer *user_model.User, assigneeID return } - assignee, err1 := user_model.GetUserByID(assigneeID) + assignee, err1 := user_model.GetUserByIDCtx(db.DefaultContext, assigneeID) if err1 != nil { err = err1 return } - notification.NotifyIssueChangeAssignee(doer, issue, assignee, removed, comment) + notification.NotifyIssueChangeAssignee(db.DefaultContext, doer, issue, assignee, removed, comment) return removed, comment, err } @@ -75,7 +75,7 @@ func ReviewRequest(issue *issues_model.Issue, doer, reviewer *user_model.User, i } if comment != nil { - notification.NotifyPullReviewRequest(doer, issue, reviewer, isAdd, comment) + notification.NotifyPullReviewRequest(db.DefaultContext, doer, issue, reviewer, isAdd, comment) } return comment, err @@ -246,7 +246,7 @@ func TeamReviewRequest(issue *issues_model.Issue, doer *user_model.User, reviewe } // notify all user in this team - if err = comment.LoadIssue(); err != nil { + if err = comment.LoadIssue(db.DefaultContext); err != nil { return } @@ -262,7 +262,7 @@ func TeamReviewRequest(issue *issues_model.Issue, doer *user_model.User, reviewe continue } comment.AssigneeID = member.ID - notification.NotifyPullReviewRequest(doer, issue, member, isAdd, comment) + notification.NotifyPullReviewRequest(db.DefaultContext, doer, issue, member, isAdd, comment) } return comment, err diff --git a/services/issue/content.go b/services/issue/content.go index 6f493892f4..851d986de3 100644 --- a/services/issue/content.go +++ b/services/issue/content.go @@ -5,6 +5,7 @@ package issue import ( + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/notification" @@ -18,7 +19,7 @@ func ChangeContent(issue *issues_model.Issue, doer *user_model.User, content str return err } - notification.NotifyIssueChangeContent(doer, issue, oldContent) + notification.NotifyIssueChangeContent(db.DefaultContext, doer, issue, oldContent) return nil } diff --git a/services/issue/issue.go b/services/issue/issue.go index 8342d7f5d2..ba9b17a0c8 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -38,12 +38,12 @@ func NewIssue(repo *repo_model.Repository, issue *issues_model.Issue, labelIDs [ return err } - notification.NotifyNewIssue(issue, mentions) + notification.NotifyNewIssue(db.DefaultContext, issue, mentions) if len(issue.Labels) > 0 { - notification.NotifyIssueChangeLabels(issue.Poster, issue, issue.Labels, nil) + notification.NotifyIssueChangeLabels(db.DefaultContext, issue.Poster, issue, issue.Labels, nil) } if issue.Milestone != nil { - notification.NotifyIssueChangeMilestone(issue.Poster, issue, 0) + notification.NotifyIssueChangeMilestone(db.DefaultContext, issue.Poster, issue, 0) } return nil @@ -58,7 +58,7 @@ func ChangeTitle(issue *issues_model.Issue, doer *user_model.User, title string) return } - notification.NotifyIssueChangeTitle(doer, issue, oldTitle) + notification.NotifyIssueChangeTitle(db.DefaultContext, doer, issue, oldTitle) return nil } @@ -72,7 +72,7 @@ func ChangeIssueRef(issue *issues_model.Issue, doer *user_model.User, ref string return err } - notification.NotifyIssueChangeRef(doer, issue, oldRef) + notification.NotifyIssueChangeRef(db.DefaultContext, doer, issue, oldRef) return nil } @@ -135,10 +135,10 @@ func UpdateAssignees(issue *issues_model.Issue, oneAssignee string, multipleAssi // DeleteIssue deletes an issue func DeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *issues_model.Issue) error { // load issue before deleting it - if err := issue.LoadAttributes(db.DefaultContext); err != nil { + if err := issue.LoadAttributes(gitRepo.Ctx); err != nil { return err } - if err := issue.LoadPullRequest(); err != nil { + if err := issue.LoadPullRequest(gitRepo.Ctx); err != nil { return err } @@ -154,7 +154,7 @@ func DeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *issues_m } } - notification.NotifyDeleteIssue(doer, issue) + notification.NotifyDeleteIssue(gitRepo.Ctx, doer, issue) return nil } @@ -162,7 +162,7 @@ func DeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *issues_m // AddAssigneeIfNotAssigned adds an assignee only if he isn't already assigned to the issue. // Also checks for access of assigned user func AddAssigneeIfNotAssigned(issue *issues_model.Issue, doer *user_model.User, assigneeID int64) (err error) { - assignee, err := user_model.GetUserByID(assigneeID) + assignee, err := user_model.GetUserByIDCtx(db.DefaultContext, assigneeID) if err != nil { return err } diff --git a/services/issue/label.go b/services/issue/label.go index a9a0c20b01..cd29fcebae 100644 --- a/services/issue/label.go +++ b/services/issue/label.go @@ -18,7 +18,7 @@ func ClearLabels(issue *issues_model.Issue, doer *user_model.User) (err error) { return } - notification.NotifyIssueClearLabels(doer, issue) + notification.NotifyIssueClearLabels(db.DefaultContext, doer, issue) return nil } @@ -29,7 +29,7 @@ func AddLabel(issue *issues_model.Issue, doer *user_model.User, label *issues_mo return err } - notification.NotifyIssueChangeLabels(doer, issue, []*issues_model.Label{label}, nil) + notification.NotifyIssueChangeLabels(db.DefaultContext, doer, issue, []*issues_model.Label{label}, nil) return nil } @@ -39,7 +39,7 @@ func AddLabels(issue *issues_model.Issue, doer *user_model.User, labels []*issue return err } - notification.NotifyIssueChangeLabels(doer, issue, labels, nil) + notification.NotifyIssueChangeLabels(db.DefaultContext, doer, issue, labels, nil) return nil } @@ -74,7 +74,7 @@ func RemoveLabel(issue *issues_model.Issue, doer *user_model.User, label *issues return err } - notification.NotifyIssueChangeLabels(doer, issue, nil, []*issues_model.Label{label}) + notification.NotifyIssueChangeLabels(db.DefaultContext, doer, issue, nil, []*issues_model.Label{label}) return nil } @@ -89,6 +89,6 @@ func ReplaceLabels(issue *issues_model.Issue, doer *user_model.User, labels []*i return err } - notification.NotifyIssueChangeLabels(doer, issue, labels, old) + notification.NotifyIssueChangeLabels(db.DefaultContext, doer, issue, labels, old) return nil } diff --git a/services/issue/milestone.go b/services/issue/milestone.go index 965b07556d..2be4a9e70a 100644 --- a/services/issue/milestone.go +++ b/services/issue/milestone.go @@ -79,7 +79,7 @@ func ChangeMilestoneAssign(issue *issues_model.Issue, doer *user_model.User, old return fmt.Errorf("Commit: %w", err) } - notification.NotifyIssueChangeMilestone(doer, issue, oldMilestoneID) + notification.NotifyIssueChangeMilestone(db.DefaultContext, doer, issue, oldMilestoneID) return nil } diff --git a/services/issue/status.go b/services/issue/status.go index 0da5c88762..2d4622324c 100644 --- a/services/issue/status.go +++ b/services/issue/status.go @@ -38,7 +38,7 @@ func changeStatusCtx(ctx context.Context, issue *issues_model.Issue, doer *user_ } } - notification.NotifyIssueChangeStatus(doer, issue, comment, closed) + notification.NotifyIssueChangeStatus(ctx, doer, issue, comment, closed) return nil } diff --git a/services/lfs/locks.go b/services/lfs/locks.go index e87589d124..45ba8faacd 100644 --- a/services/lfs/locks.go +++ b/services/lfs/locks.go @@ -57,7 +57,7 @@ func GetListLockHandler(ctx *context.Context) { }) return } - repository.MustOwner() + repository.MustOwner(ctx) authenticated := authenticate(ctx, repository, rv.Authorization, true, false) if !authenticated { @@ -144,7 +144,7 @@ func PostLockHandler(ctx *context.Context) { }) return } - repository.MustOwner() + repository.MustOwner(ctx) authenticated := authenticate(ctx, repository, authorization, true, true) if !authenticated { @@ -211,7 +211,7 @@ func VerifyLockHandler(ctx *context.Context) { }) return } - repository.MustOwner() + repository.MustOwner(ctx) authenticated := authenticate(ctx, repository, authorization, true, true) if !authenticated { @@ -277,7 +277,7 @@ func UnLockHandler(ctx *context.Context) { }) return } - repository.MustOwner() + repository.MustOwner(ctx) authenticated := authenticate(ctx, repository, authorization, true, true) if !authenticated { diff --git a/services/mailer/mail.go b/services/mailer/mail.go index 85a7d107e5..a9e36e10f8 100644 --- a/services/mailer/mail.go +++ b/services/mailer/mail.go @@ -18,7 +18,6 @@ import ( "time" activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -265,7 +264,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient "Issue": ctx.Issue, "Comment": ctx.Comment, "IsPull": ctx.Issue.IsPull, - "User": ctx.Issue.Repo.MustOwner(), + "User": ctx.Issue.Repo.MustOwner(ctx), "Repo": ctx.Issue.Repo.FullName(), "Doer": ctx.Doer, "IsMention": fromMention, @@ -395,13 +394,13 @@ func sanitizeSubject(subject string) string { } // SendIssueAssignedMail composes and sends issue assigned email -func SendIssueAssignedMail(issue *issues_model.Issue, doer *user_model.User, content string, comment *issues_model.Comment, recipients []*user_model.User) error { +func SendIssueAssignedMail(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, content string, comment *issues_model.Comment, recipients []*user_model.User) error { if setting.MailService == nil { // No mail service configured return nil } - if err := issue.LoadRepo(db.DefaultContext); err != nil { + if err := issue.LoadRepo(ctx); err != nil { log.Error("Unable to load repo [%d] for issue #%d [%d]. Error: %v", issue.RepoID, issue.Index, issue.ID, err) return err } @@ -417,7 +416,7 @@ func SendIssueAssignedMail(issue *issues_model.Issue, doer *user_model.User, con for lang, tos := range langMap { msgs, err := composeIssueCommentMessages(&mailCommentContext{ - Context: context.TODO(), // TODO: use a correct context + Context: ctx, Issue: issue, Doer: doer, ActionType: activities_model.ActionType(0), diff --git a/services/mailer/mail_issue.go b/services/mailer/mail_issue.go index 61e276805d..e7ff1d59d6 100644 --- a/services/mailer/mail_issue.go +++ b/services/mailer/mail_issue.go @@ -45,13 +45,13 @@ const ( func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []*user_model.User) error { // Required by the mail composer; make sure to load these before calling the async function if err := ctx.Issue.LoadRepo(ctx); err != nil { - return fmt.Errorf("LoadRepo(): %w", err) + return fmt.Errorf("LoadRepo: %w", err) } - if err := ctx.Issue.LoadPoster(); err != nil { - return fmt.Errorf("LoadPoster(): %w", err) + if err := ctx.Issue.LoadPoster(ctx); err != nil { + return fmt.Errorf("LoadPoster: %w", err) } - if err := ctx.Issue.LoadPullRequest(); err != nil { - return fmt.Errorf("LoadPullRequest(): %w", err) + if err := ctx.Issue.LoadPullRequest(ctx); err != nil { + return fmt.Errorf("LoadPullRequest: %w", err) } // Enough room to avoid reallocations @@ -61,14 +61,14 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []*user_mo unfiltered[0] = ctx.Issue.PosterID // =========== Assignees =========== - ids, err := issues_model.GetAssigneeIDsByIssue(ctx.Issue.ID) + ids, err := issues_model.GetAssigneeIDsByIssue(ctx, ctx.Issue.ID) if err != nil { return fmt.Errorf("GetAssigneeIDsByIssue(%d): %w", ctx.Issue.ID, err) } unfiltered = append(unfiltered, ids...) // =========== Participants (i.e. commenters, reviewers) =========== - ids, err = issues_model.GetParticipantsIDsByIssueID(ctx.Issue.ID) + ids, err = issues_model.GetParticipantsIDsByIssueID(ctx, ctx.Issue.ID) if err != nil { return fmt.Errorf("GetParticipantsIDsByIssueID(%d): %w", ctx.Issue.ID, err) } @@ -110,7 +110,7 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []*user_mo } visited.AddMultiple(ids...) - unfilteredUsers, err := user_model.GetMaileableUsersByIDs(unfiltered, false) + unfilteredUsers, err := user_model.GetMaileableUsersByIDs(ctx, unfiltered, false) if err != nil { return err } @@ -173,7 +173,7 @@ func mailIssueCommentBatch(ctx *mailCommentContext, users []*user_model.User, vi // MailParticipants sends new issue thread created emails to repository watchers // and mentioned people. -func MailParticipants(issue *issues_model.Issue, doer *user_model.User, opType activities_model.ActionType, mentions []*user_model.User) error { +func MailParticipants(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, opType activities_model.ActionType, mentions []*user_model.User) error { if setting.MailService == nil { // No mail service configured return nil @@ -188,7 +188,7 @@ func MailParticipants(issue *issues_model.Issue, doer *user_model.User, opType a forceDoerNotification := opType == activities_model.ActionAutoMergePullRequest if err := mailIssueCommentToParticipants( &mailCommentContext{ - Context: context.TODO(), // TODO: use a correct context + Context: ctx, Issue: issue, Doer: doer, ActionType: opType, diff --git a/services/mailer/mail_release.go b/services/mailer/mail_release.go index 6df3fbbf1d..b15fc05ce9 100644 --- a/services/mailer/mail_release.go +++ b/services/mailer/mail_release.go @@ -36,7 +36,7 @@ func MailNewRelease(ctx context.Context, rel *repo_model.Release) { return } - recipients, err := user_model.GetMaileableUsersByIDs(watcherIDList, false) + recipients, err := user_model.GetMaileableUsersByIDs(ctx, watcherIDList, false) if err != nil { log.Error("user_model.GetMaileableUsersByIDs: %v", err) return diff --git a/services/mailer/mail_repo.go b/services/mailer/mail_repo.go index 6fe9df0926..d3f5120929 100644 --- a/services/mailer/mail_repo.go +++ b/services/mailer/mail_repo.go @@ -6,9 +6,9 @@ package mailer import ( "bytes" + "context" "fmt" - "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -18,14 +18,14 @@ import ( ) // SendRepoTransferNotifyMail triggers a notification e-mail when a pending repository transfer was created -func SendRepoTransferNotifyMail(doer, newOwner *user_model.User, repo *repo_model.Repository) error { +func SendRepoTransferNotifyMail(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) error { if setting.MailService == nil { // No mail service configured return nil } if newOwner.IsOrganization() { - users, err := organization.GetUsersWhoCanCreateOrgRepo(db.DefaultContext, newOwner.ID) + users, err := organization.GetUsersWhoCanCreateOrgRepo(ctx, newOwner.ID) if err != nil { return err } diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index 68a7182b07..362492631f 100644 --- a/services/migrations/gitea_uploader_test.go +++ b/services/migrations/gitea_uploader_test.go @@ -84,7 +84,7 @@ func TestGiteaUploadRepo(t *testing.T) { assert.NoError(t, err) assert.Len(t, labels, 12) - releases, err := repo_model.GetReleasesByRepoID(repo.ID, repo_model.FindReleasesOptions{ + releases, err := repo_model.GetReleasesByRepoID(db.DefaultContext, repo.ID, repo_model.FindReleasesOptions{ ListOptions: db.ListOptions{ PageSize: 10, Page: 0, @@ -94,7 +94,7 @@ func TestGiteaUploadRepo(t *testing.T) { assert.NoError(t, err) assert.Len(t, releases, 8) - releases, err = repo_model.GetReleasesByRepoID(repo.ID, repo_model.FindReleasesOptions{ + releases, err = repo_model.GetReleasesByRepoID(db.DefaultContext, repo.ID, repo_model.FindReleasesOptions{ ListOptions: db.ListOptions{ PageSize: 10, Page: 0, @@ -104,14 +104,14 @@ func TestGiteaUploadRepo(t *testing.T) { assert.NoError(t, err) assert.Len(t, releases, 1) - issues, err := issues_model.Issues(&issues_model.IssuesOptions{ + issues, err := issues_model.Issues(db.DefaultContext, &issues_model.IssuesOptions{ RepoID: repo.ID, IsPull: util.OptionalBoolFalse, SortType: "oldest", }) assert.NoError(t, err) assert.Len(t, issues, 15) - assert.NoError(t, issues[0].LoadDiscussComments()) + assert.NoError(t, issues[0].LoadDiscussComments(db.DefaultContext)) assert.Empty(t, issues[0].Comments) pulls, _, err := issues_model.PullRequests(repo.ID, &issues_model.PullRequestsOptions{ @@ -119,8 +119,8 @@ func TestGiteaUploadRepo(t *testing.T) { }) assert.NoError(t, err) assert.Len(t, pulls, 30) - assert.NoError(t, pulls[0].LoadIssue()) - assert.NoError(t, pulls[0].Issue.LoadDiscussComments()) + assert.NoError(t, pulls[0].LoadIssue(db.DefaultContext)) + assert.NoError(t, pulls[0].Issue.LoadDiscussComments(db.DefaultContext)) assert.Len(t, pulls[0].Issue.Comments, 2) } diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 6002e6b8ed..4a77569d86 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -459,18 +459,18 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { log.Error("SyncMirrors [repo: %-v]: unable to GetRefCommitID [ref_name: %s]: %v", m.Repo, result.refName, err) continue } - notification.NotifySyncPushCommits(m.Repo.MustOwner(), m.Repo, &repo_module.PushUpdateOptions{ + notification.NotifySyncPushCommits(ctx, m.Repo.MustOwner(ctx), m.Repo, &repo_module.PushUpdateOptions{ RefFullName: result.refName, OldCommitID: git.EmptySHA, NewCommitID: commitID, }, repo_module.NewPushCommits()) - notification.NotifySyncCreateRef(m.Repo.MustOwner(), m.Repo, tp, result.refName, commitID) + notification.NotifySyncCreateRef(ctx, m.Repo.MustOwner(ctx), m.Repo, tp, result.refName, commitID) continue } // Delete reference if result.newCommitID == gitShortEmptySha { - notification.NotifySyncDeleteRef(m.Repo.MustOwner(), m.Repo, tp, result.refName) + notification.NotifySyncDeleteRef(ctx, m.Repo.MustOwner(ctx), m.Repo, tp, result.refName) continue } @@ -498,7 +498,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { theCommits.CompareURL = m.Repo.ComposeCompareURL(oldCommitID, newCommitID) - notification.NotifySyncPushCommits(m.Repo.MustOwner(), m.Repo, &repo_module.PushUpdateOptions{ + notification.NotifySyncPushCommits(ctx, m.Repo.MustOwner(ctx), m.Repo, &repo_module.PushUpdateOptions{ RefFullName: result.refName, OldCommitID: oldCommitID, NewCommitID: newCommitID, diff --git a/services/packages/packages.go b/services/packages/packages.go index 4513215ae1..76fdd02bf2 100644 --- a/services/packages/packages.go +++ b/services/packages/packages.go @@ -108,12 +108,12 @@ func createPackageAndAddFile(pvci *PackageCreationInfo, pfci *PackageFileCreatio } if created { - pd, err := packages_model.GetPackageDescriptor(ctx, pv) + pd, err := packages_model.GetPackageDescriptor(db.DefaultContext, pv) if err != nil { return nil, nil, err } - notification.NotifyPackageCreate(pvci.Creator, pd) + notification.NotifyPackageCreate(db.DefaultContext, pvci.Creator, pd) } return pv, pf, nil @@ -409,7 +409,7 @@ func RemovePackageVersion(doer *user_model.User, pv *packages_model.PackageVersi return err } - notification.NotifyPackageDelete(doer, pd) + notification.NotifyPackageDelete(db.DefaultContext, doer, pd) return nil } diff --git a/services/pull/check.go b/services/pull/check.go index 6e91c22f3e..faf3459f16 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -48,7 +48,7 @@ var ( func AddToTaskQueue(pr *issues_model.PullRequest) { err := prPatchCheckerQueue.PushFunc(strconv.FormatInt(pr.ID, 10), func() error { pr.Status = issues_model.PullRequestStatusChecking - err := pr.UpdateColsIfNotMerged("status") + err := pr.UpdateColsIfNotMerged(db.DefaultContext, "status") if err != nil { log.Error("AddToTaskQueue.UpdateCols[%d].(add to queue): %v", pr.ID, err) } else { @@ -68,7 +68,7 @@ func CheckPullMergable(stdCtx context.Context, doer *user_model.User, perm *acce return ErrHasMerged } - if err := pr.LoadIssueCtx(ctx); err != nil { + if err := pr.LoadIssue(ctx); err != nil { return err } else if pr.Issue.IsClosed { return ErrIsClosed @@ -142,7 +142,7 @@ func isSignedIfRequired(ctx context.Context, pr *issues_model.PullRequest, doer // checkAndUpdateStatus checks if pull request is possible to leaving checking status, // and set to be either conflict or mergeable. -func checkAndUpdateStatus(pr *issues_model.PullRequest) { +func checkAndUpdateStatus(ctx context.Context, pr *issues_model.PullRequest) { // Status is not changed to conflict means mergeable. if pr.Status == issues_model.PullRequestStatusChecking { pr.Status = issues_model.PullRequestStatusMergeable @@ -155,7 +155,7 @@ func checkAndUpdateStatus(pr *issues_model.PullRequest) { } if !has { - if err := pr.UpdateColsIfNotMerged("merge_base", "status", "conflicted_files", "changed_protected_files"); err != nil { + if err := pr.UpdateColsIfNotMerged(ctx, "merge_base", "status", "conflicted_files", "changed_protected_files"); err != nil { log.Error("Update[%d]: %v", pr.ID, err) } } @@ -232,7 +232,7 @@ func getMergeCommit(ctx context.Context, pr *issues_model.PullRequest) (*git.Com // manuallyMerged checks if a pull request got manually merged // When a pull request got manually merged mark the pull request as merged func manuallyMerged(ctx context.Context, pr *issues_model.PullRequest) bool { - if err := pr.LoadBaseRepoCtx(ctx); err != nil { + if err := pr.LoadBaseRepo(ctx); err != nil { log.Error("PullRequest[%d].LoadBaseRepo: %v", pr.ID, err) return false } @@ -278,7 +278,7 @@ func manuallyMerged(ctx context.Context, pr *issues_model.PullRequest) bool { return false } - notification.NotifyMergePullRequest(pr, merger) + notification.NotifyMergePullRequest(ctx, merger, pr) log.Info("manuallyMerged[%d]: Marked as manually merged into %s/%s by commit id: %s", pr.ID, pr.BaseRepo.Name, pr.BaseBranch, commit.ID.String()) return true @@ -346,7 +346,7 @@ func testPR(id int64) { } return } - checkAndUpdateStatus(pr) + checkAndUpdateStatus(ctx, pr) } // CheckPrsForBaseBranch check all pulls with bseBrannch diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index 5d846129f6..10692221a4 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -101,7 +101,7 @@ func IsPullCommitStatusPass(ctx context.Context, pr *issues_model.PullRequest) ( // GetPullRequestCommitStatusState returns pull request merged commit status state func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullRequest) (structs.CommitStatusState, error) { // Ensure HeadRepo is loaded - if err := pr.LoadHeadRepoCtx(ctx); err != nil { + if err := pr.LoadHeadRepo(ctx); err != nil { return "", errors.Wrap(err, "LoadHeadRepo") } @@ -129,7 +129,7 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullR return "", err } - if err := pr.LoadBaseRepoCtx(ctx); err != nil { + if err := pr.LoadBaseRepo(ctx); err != nil { return "", errors.Wrap(err, "LoadBaseRepo") } diff --git a/services/pull/edits.go b/services/pull/edits.go index 2938f2b108..84f7c80da7 100644 --- a/services/pull/edits.go +++ b/services/pull/edits.go @@ -23,7 +23,7 @@ func SetAllowEdits(ctx context.Context, doer *user_model.User, pr *issues_model. return ErrUserHasNoPermissionForAction } - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepo(ctx); err != nil { return err } diff --git a/services/pull/merge.go b/services/pull/merge.go index 6f37a887db..b29c9bc859 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -40,18 +40,18 @@ import ( ) // GetDefaultMergeMessage returns default message used when merging pull request -func GetDefaultMergeMessage(baseGitRepo *git.Repository, pr *issues_model.PullRequest, mergeStyle repo_model.MergeStyle) (string, error) { - if err := pr.LoadHeadRepo(); err != nil { +func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issues_model.PullRequest, mergeStyle repo_model.MergeStyle) (string, error) { + if err := pr.LoadHeadRepo(ctx); err != nil { return "", err } - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepo(ctx); err != nil { return "", err } if pr.BaseRepo == nil { return "", repo_model.ErrRepoNotExist{ID: pr.BaseRepoID} } - if err := pr.LoadIssue(); err != nil { + if err := pr.LoadIssue(ctx); err != nil { return "", err } @@ -90,7 +90,7 @@ func GetDefaultMergeMessage(baseGitRepo *git.Repository, pr *issues_model.PullRe vars["HeadRepoOwnerName"] = pr.HeadRepo.OwnerName vars["HeadRepoName"] = pr.HeadRepo.Name } - refs, err := pr.ResolveCrossReferences(baseGitRepo.Ctx) + refs, err := pr.ResolveCrossReferences(ctx) if err == nil { closeIssueIndexes := make([]string, 0, len(refs)) closeWord := "close" @@ -134,10 +134,10 @@ func GetDefaultMergeMessage(baseGitRepo *git.Repository, pr *issues_model.PullRe // Merge merges pull request to base repository. // Caller should check PR is ready to be merged (review and status checks) func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, baseGitRepo *git.Repository, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string, wasAutoMerged bool) error { - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepo(ctx); err != nil { log.Error("LoadHeadRepo: %v", err) return fmt.Errorf("LoadHeadRepo: %w", err) - } else if err := pr.LoadBaseRepo(); err != nil { + } else if err := pr.LoadBaseRepo(ctx); err != nil { log.Error("LoadBaseRepo: %v", err) return fmt.Errorf("LoadBaseRepo: %w", err) } @@ -179,24 +179,24 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U pr.MergerID = doer.ID if _, err := pr.SetMerged(hammerCtx); err != nil { - log.Error("setMerged [%d]: %v", pr.ID, err) + log.Error("SetMerged [%d]: %v", pr.ID, err) } - if err := pr.LoadIssueCtx(hammerCtx); err != nil { - log.Error("loadIssue [%d]: %v", pr.ID, err) + if err := pr.LoadIssue(hammerCtx); err != nil { + log.Error("LoadIssue [%d]: %v", pr.ID, err) } if err := pr.Issue.LoadRepo(hammerCtx); err != nil { - log.Error("loadRepo for issue [%d]: %v", pr.ID, err) + log.Error("LoadRepo for issue [%d]: %v", pr.ID, err) } if err := pr.Issue.Repo.GetOwner(hammerCtx); err != nil { - log.Error("GetOwner for issue repo [%d]: %v", pr.ID, err) + log.Error("GetOwner for PR [%d]: %v", pr.ID, err) } if wasAutoMerged { - notification.NotifyAutoMergePullRequest(pr, doer) + notification.NotifyAutoMergePullRequest(hammerCtx, doer, pr) } else { - notification.NotifyMergePullRequest(pr, doer) + notification.NotifyMergePullRequest(hammerCtx, doer, pr) } // Reset cached commit count @@ -210,7 +210,7 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U } for _, ref := range refs { - if err = ref.LoadIssueCtx(hammerCtx); err != nil { + if err = ref.LoadIssue(hammerCtx); err != nil { return err } if err = ref.Issue.LoadRepo(hammerCtx); err != nil { @@ -511,7 +511,7 @@ func rawMerge(ctx context.Context, pr *issues_model.PullRequest, doer *user_mode return "", err } - if err = pr.Issue.LoadPoster(); err != nil { + if err = pr.Issue.LoadPoster(ctx); err != nil { log.Error("LoadPoster: %v", err) return "", fmt.Errorf("LoadPoster: %w", err) } @@ -767,7 +767,7 @@ func IsUserAllowedToMerge(ctx context.Context, pr *issues_model.PullRequest, p a // CheckPullBranchProtections checks whether the PR is ready to be merged (reviews and status checks) func CheckPullBranchProtections(ctx context.Context, pr *issues_model.PullRequest, skipProtectedFilesCheck bool) (err error) { - if err = pr.LoadBaseRepoCtx(ctx); err != nil { + if err = pr.LoadBaseRepo(ctx); err != nil { return fmt.Errorf("LoadBaseRepo: %w", err) } @@ -878,7 +878,7 @@ func MergedManually(pr *issues_model.PullRequest, doer *user_model.User, baseGit return err } - notification.NotifyMergePullRequest(pr, doer) + notification.NotifyMergePullRequest(baseGitRepo.Ctx, doer, pr) log.Info("manuallyMerged[%d]: Marked as manually merged into %s/%s by commit id: %s", pr.ID, pr.BaseRepo.Name, pr.BaseBranch, commitID) return nil } diff --git a/services/pull/patch.go b/services/pull/patch.go index 9b87ac22e2..1046095ff1 100644 --- a/services/pull/patch.go +++ b/services/pull/patch.go @@ -30,7 +30,7 @@ import ( // DownloadDiffOrPatch will write the patch for the pr to the writer func DownloadDiffOrPatch(ctx context.Context, pr *issues_model.PullRequest, w io.Writer, patch, binary bool) error { - if err := pr.LoadBaseRepoCtx(ctx); err != nil { + if err := pr.LoadBaseRepo(ctx); err != nil { log.Error("Unable to load base repository ID %d for pr #%d [%d]", pr.BaseRepoID, pr.Index, pr.ID) return err } diff --git a/services/pull/pull.go b/services/pull/pull.go index 5f8bd6b671..e0dcefe141 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -82,12 +82,12 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, pull *issu return err } - notification.NotifyNewPullRequest(pr, mentions) + notification.NotifyNewPullRequest(prCtx, pr, mentions) if len(pull.Labels) > 0 { - notification.NotifyIssueChangeLabels(pull.Poster, pull, pull.Labels, nil) + notification.NotifyIssueChangeLabels(prCtx, pull.Poster, pull, pull.Labels, nil) } if pull.Milestone != nil { - notification.NotifyIssueChangeMilestone(pull.Poster, pull, 0) + notification.NotifyIssueChangeMilestone(prCtx, pull.Poster, pull, 0) } // add first push codes comment @@ -172,7 +172,7 @@ func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer } // Check if pull request for the new target branch already exists - existingPr, err := issues_model.GetUnmergedPullRequest(pr.HeadRepoID, pr.BaseRepoID, pr.HeadBranch, targetBranch, issues_model.PullRequestFlowGithub) + existingPr, err := issues_model.GetUnmergedPullRequest(ctx, pr.HeadRepoID, pr.BaseRepoID, pr.HeadBranch, targetBranch, issues_model.PullRequestFlowGithub) if existingPr != nil { return issues_model.ErrPullRequestAlreadyExists{ ID: existingPr.ID, @@ -210,7 +210,7 @@ func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer pr.CommitsAhead = divergence.Ahead pr.CommitsBehind = divergence.Behind - if err := pr.UpdateColsIfNotMerged("merge_base", "status", "conflicted_files", "changed_protected_files", "base_branch", "commits_ahead", "commits_behind"); err != nil { + if err := pr.UpdateColsIfNotMerged(ctx, "merge_base", "status", "conflicted_files", "changed_protected_files", "base_branch", "commits_ahead", "commits_behind"); err != nil { return err } @@ -231,9 +231,9 @@ func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer } func checkForInvalidation(ctx context.Context, requests issues_model.PullRequestList, repoID int64, doer *user_model.User, branch string) error { - repo, err := repo_model.GetRepositoryByID(repoID) + repo, err := repo_model.GetRepositoryByIDCtx(ctx, repoID) if err != nil { - return fmt.Errorf("GetRepositoryByID: %w", err) + return fmt.Errorf("GetRepositoryByIDCtx: %w", err) } gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) if err != nil { @@ -301,7 +301,7 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string, } pr.Issue.PullRequest = pr - notification.NotifyPullRequestSynchronized(doer, pr) + notification.NotifyPullRequestSynchronized(ctx, doer, pr) } } } @@ -320,7 +320,7 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string, AddToTaskQueue(pr) comment, err := issues_model.CreatePushPullComment(ctx, doer, pr, oldCommitID, newCommitID) if err == nil && comment != nil { - notification.NotifyPullRequestPushCommits(doer, pr, comment) + notification.NotifyPullRequestPushCommits(ctx, doer, pr, comment) } } @@ -352,14 +352,14 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string, // checkIfPRContentChanged checks if diff to target branch has changed by push // A commit can be considered to leave the PR untouched if the patch/diff with its merge base is unchanged func checkIfPRContentChanged(ctx context.Context, pr *issues_model.PullRequest, oldCommitID, newCommitID string) (hasChanged bool, err error) { - if err = pr.LoadHeadRepoCtx(ctx); err != nil { + if err = pr.LoadHeadRepo(ctx); err != nil { return false, fmt.Errorf("LoadHeadRepo: %w", err) } else if pr.HeadRepo == nil { // corrupt data assumed changed return true, nil } - if err = pr.LoadBaseRepoCtx(ctx); err != nil { + if err = pr.LoadBaseRepo(ctx); err != nil { return false, fmt.Errorf("LoadBaseRepo: %w", err) } @@ -430,22 +430,22 @@ func PushToBaseRepo(ctx context.Context, pr *issues_model.PullRequest) (err erro func pushToBaseRepoHelper(ctx context.Context, pr *issues_model.PullRequest, prefixHeadBranch string) (err error) { log.Trace("PushToBaseRepo[%d]: pushing commits to base repo '%s'", pr.BaseRepoID, pr.GetGitRefName()) - if err := pr.LoadHeadRepoCtx(ctx); err != nil { + if err := pr.LoadHeadRepo(ctx); err != nil { log.Error("Unable to load head repository for PR[%d] Error: %v", pr.ID, err) return err } headRepoPath := pr.HeadRepo.RepoPath() - if err := pr.LoadBaseRepoCtx(ctx); err != nil { + if err := pr.LoadBaseRepo(ctx); err != nil { log.Error("Unable to load base repository for PR[%d] Error: %v", pr.ID, err) return err } baseRepoPath := pr.BaseRepo.RepoPath() - if err = pr.LoadIssue(); err != nil { + if err = pr.LoadIssue(ctx); err != nil { return fmt.Errorf("unable to load issue %d for pr %d: %w", pr.IssueID, pr.ID, err) } - if err = pr.Issue.LoadPoster(); err != nil { + if err = pr.Issue.LoadPoster(ctx); err != nil { return fmt.Errorf("unable to load poster %d for pr %d: %w", pr.Issue.PosterID, pr.ID, err) } @@ -485,7 +485,7 @@ func pushToBaseRepoHelper(ctx context.Context, pr *issues_model.PullRequest, pre // UpdateRef update refs/pull/id/head directly for agit flow pull request func UpdateRef(ctx context.Context, pr *issues_model.PullRequest) (err error) { log.Trace("UpdateRef[%d]: upgate pull request ref in base repo '%s'", pr.ID, pr.GetGitRefName()) - if err := pr.LoadBaseRepoCtx(ctx); err != nil { + if err := pr.LoadBaseRepo(ctx); err != nil { log.Error("Unable to load base repository for PR[%d] Error: %v", pr.ID, err) return err } @@ -583,21 +583,21 @@ var commitMessageTrailersPattern = regexp.MustCompile(`(?:^|\n\n)(?:[\w-]+[ \t]* // GetSquashMergeCommitMessages returns the commit messages between head and merge base (if there is one) func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequest) string { - if err := pr.LoadIssue(); err != nil { + if err := pr.LoadIssue(ctx); err != nil { log.Error("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err) return "" } - if err := pr.Issue.LoadPoster(); err != nil { + if err := pr.Issue.LoadPoster(ctx); err != nil { log.Error("Cannot load poster %d for pr id %d, index %d Error: %v", pr.Issue.PosterID, pr.ID, pr.Index, err) return "" } if pr.HeadRepo == nil { var err error - pr.HeadRepo, err = repo_model.GetRepositoryByID(pr.HeadRepoID) + pr.HeadRepo, err = repo_model.GetRepositoryByIDCtx(ctx, pr.HeadRepoID) if err != nil { - log.Error("GetRepositoryById[%d]: %v", pr.HeadRepoID, err) + log.Error("GetRepositoryByIdCtx[%d]: %v", pr.HeadRepoID, err) return "" } } @@ -743,10 +743,10 @@ func GetIssuesLastCommitStatus(ctx context.Context, issues issues_model.IssueLis // GetIssuesAllCommitStatus returns a map of issue ID to a list of all statuses for the most recent commit as well as a map of issue ID to only the commit's latest status func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList) (map[int64][]*git_model.CommitStatus, map[int64]*git_model.CommitStatus, error) { - if err := issues.LoadPullRequests(); err != nil { + if err := issues.LoadPullRequests(ctx); err != nil { return nil, nil, err } - if _, err := issues.LoadRepositories(); err != nil { + if _, err := issues.LoadRepositories(ctx); err != nil { return nil, nil, err } @@ -802,7 +802,7 @@ func getAllCommitStatus(gitRepo *git.Repository, pr *issues_model.PullRequest) ( // IsHeadEqualWithBranch returns if the commits of branchName are available in pull request head func IsHeadEqualWithBranch(ctx context.Context, pr *issues_model.PullRequest, branchName string) (bool, error) { var err error - if err = pr.LoadBaseRepoCtx(ctx); err != nil { + if err = pr.LoadBaseRepo(ctx); err != nil { return false, err } baseGitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, pr.BaseRepo.RepoPath()) @@ -816,7 +816,7 @@ func IsHeadEqualWithBranch(ctx context.Context, pr *issues_model.PullRequest, br return false, err } - if err = pr.LoadHeadRepoCtx(ctx); err != nil { + if err = pr.LoadHeadRepo(ctx); err != nil { return false, err } var headGitRepo *git.Repository diff --git a/services/pull/pull_test.go b/services/pull/pull_test.go index 769e3c72e9..22eefd1624 100644 --- a/services/pull/pull_test.go +++ b/services/pull/pull_test.go @@ -8,6 +8,7 @@ package pull import ( "testing" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" @@ -40,18 +41,18 @@ func TestPullRequest_GetDefaultMergeMessage_InternalTracker(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) - assert.NoError(t, pr.LoadBaseRepo()) + assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext)) gitRepo, err := git.OpenRepository(git.DefaultContext, pr.BaseRepo.RepoPath()) assert.NoError(t, err) defer gitRepo.Close() - mergeMessage, err := GetDefaultMergeMessage(gitRepo, pr, "") + mergeMessage, err := GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") assert.NoError(t, err) assert.Equal(t, "Merge pull request 'issue3' (#3) from branch2 into master", mergeMessage) pr.BaseRepoID = 1 pr.HeadRepoID = 2 - mergeMessage, err = GetDefaultMergeMessage(gitRepo, pr, "") + mergeMessage, err = GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") assert.NoError(t, err) assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo1:branch2 into master", mergeMessage) } @@ -70,12 +71,12 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) { pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2, BaseRepo: baseRepo}) - assert.NoError(t, pr.LoadBaseRepo()) + assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext)) gitRepo, err := git.OpenRepository(git.DefaultContext, pr.BaseRepo.RepoPath()) assert.NoError(t, err) defer gitRepo.Close() - mergeMessage, err := GetDefaultMergeMessage(gitRepo, pr, "") + mergeMessage, err := GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") assert.NoError(t, err) assert.Equal(t, "Merge pull request 'issue3' (!3) from branch2 into master", mergeMessage) @@ -84,7 +85,7 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) { pr.HeadRepoID = 2 pr.BaseRepo = nil pr.HeadRepo = nil - mergeMessage, err = GetDefaultMergeMessage(gitRepo, pr, "") + mergeMessage, err = GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") assert.NoError(t, err) assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo2:branch2 into master", mergeMessage) diff --git a/services/pull/review.go b/services/pull/review.go index 16c9e108ee..2555e1b3b3 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -67,7 +67,7 @@ func CreateCodeComment(ctx context.Context, doer *user_model.User, gitRepo *git. return nil, err } - notification.NotifyCreateIssueComment(doer, issue.Repo, issue, comment, mentions) + notification.NotifyCreateIssueComment(ctx, doer, issue.Repo, issue, comment, mentions) return comment, nil } @@ -119,12 +119,12 @@ var notEnoughLines = regexp.MustCompile(`exit status 128 - fatal: file .* has on // createCodeComment creates a plain code comment at the specified line / path func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, content, treePath string, line, reviewID int64) (*issues_model.Comment, error) { var commitID, patch string - if err := issue.LoadPullRequest(); err != nil { - return nil, fmt.Errorf("GetPullRequestByIssueID: %w", err) + if err := issue.LoadPullRequest(ctx); err != nil { + return nil, fmt.Errorf("LoadPullRequest: %w", err) } pr := issue.PullRequest - if err := pr.LoadBaseRepoCtx(ctx); err != nil { - return nil, fmt.Errorf("LoadHeadRepo: %w", err) + if err := pr.LoadBaseRepo(ctx); err != nil { + return nil, fmt.Errorf("LoadBaseRepo: %w", err) } gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, pr.BaseRepo.RepoPath()) if err != nil { @@ -254,7 +254,7 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos return nil, nil, err } - notification.NotifyPullRequestReview(pr, review, comm, mentions) + notification.NotifyPullRequestReview(ctx, pr, review, comm, mentions) for _, lines := range review.CodeComments { for _, comments := range lines { @@ -263,7 +263,7 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos if err != nil { return nil, nil, err } - notification.NotifyPullRequestCodeComment(pr, codeComment, mentions) + notification.NotifyPullRequestCodeComment(ctx, pr, codeComment, mentions) } } } @@ -316,7 +316,7 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string, return nil, nil } - if err = review.Issue.LoadPullRequest(); err != nil { + if err = review.Issue.LoadPullRequest(ctx); err != nil { return } if err = review.Issue.LoadAttributes(ctx); err != nil { @@ -339,7 +339,7 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string, comment.Poster = doer comment.Issue = review.Issue - notification.NotifyPullRevieweDismiss(doer, review, comment) + notification.NotifyPullReviewDismiss(ctx, doer, review, comment) return comment, err } diff --git a/services/pull/temp_repo.go b/services/pull/temp_repo.go index 15e776c4b9..9c04aa1c92 100644 --- a/services/pull/temp_repo.go +++ b/services/pull/temp_repo.go @@ -23,7 +23,7 @@ import ( // createTemporaryRepo creates a temporary repo with "base" for pr.BaseBranch and "tracking" for pr.HeadBranch // it also create a second base branch called "original_base" func createTemporaryRepo(ctx context.Context, pr *issues_model.PullRequest) (string, error) { - if err := pr.LoadHeadRepoCtx(ctx); err != nil { + if err := pr.LoadHeadRepo(ctx); err != nil { log.Error("LoadHeadRepo: %v", err) return "", fmt.Errorf("LoadHeadRepo: %w", err) } else if pr.HeadRepo == nil { @@ -31,7 +31,7 @@ func createTemporaryRepo(ctx context.Context, pr *issues_model.PullRequest) (str return "", &repo_model.ErrRepoNotExist{ ID: pr.HeadRepoID, } - } else if err := pr.LoadBaseRepoCtx(ctx); err != nil { + } else if err := pr.LoadBaseRepo(ctx); err != nil { log.Error("LoadBaseRepo: %v", err) return "", fmt.Errorf("LoadBaseRepo: %w", err) } else if pr.BaseRepo == nil { diff --git a/services/pull/update.go b/services/pull/update.go index bd4880a2fc..36e66bb7a9 100644 --- a/services/pull/update.go +++ b/services/pull/update.go @@ -48,10 +48,10 @@ func Update(ctx context.Context, pull *issues_model.PullRequest, doer *user_mode return fmt.Errorf("Not support update agit flow pull request's head branch") } - if err := pr.LoadHeadRepoCtx(ctx); err != nil { + if err := pr.LoadHeadRepo(ctx); err != nil { log.Error("LoadHeadRepo: %v", err) return fmt.Errorf("LoadHeadRepo: %w", err) - } else if err = pr.LoadBaseRepoCtx(ctx); err != nil { + } else if err = pr.LoadBaseRepo(ctx); err != nil { log.Error("LoadBaseRepo: %v", err) return fmt.Errorf("LoadBaseRepo: %w", err) } @@ -145,10 +145,10 @@ func IsUserAllowedToUpdate(ctx context.Context, pull *issues_model.PullRequest, // GetDiverging determines how many commits a PR is ahead or behind the PR base branch func GetDiverging(ctx context.Context, pr *issues_model.PullRequest) (*git.DivergeObject, error) { log.Trace("GetDiverging[%d]: compare commits", pr.ID) - if err := pr.LoadBaseRepoCtx(ctx); err != nil { + if err := pr.LoadBaseRepo(ctx); err != nil { return nil, err } - if err := pr.LoadHeadRepoCtx(ctx); err != nil { + if err := pr.LoadHeadRepo(ctx); err != nil { return nil, err } diff --git a/services/release/release.go b/services/release/release.go index cf398debbb..eb989381f0 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -24,24 +24,24 @@ import ( "code.gitea.io/gitea/modules/timeutil" ) -func createTag(gitRepo *git.Repository, rel *repo_model.Release, msg string) (bool, error) { +func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Release, msg string) (bool, error) { var created bool // Only actual create when publish. if !rel.IsDraft { if !gitRepo.IsTagExist(rel.TagName) { - if err := rel.LoadAttributes(); err != nil { + if err := rel.LoadAttributes(ctx); err != nil { log.Error("LoadAttributes: %v", err) return false, err } - protectedTags, err := git_model.GetProtectedTags(rel.Repo.ID) + protectedTags, err := git_model.GetProtectedTags(ctx, rel.Repo.ID) if err != nil { return false, fmt.Errorf("GetProtectedTags: %w", err) } // Trim '--' prefix to prevent command line argument vulnerability. rel.TagName = strings.TrimPrefix(rel.TagName, "--") - isAllowed, err := git_model.IsUserAllowedToControlTag(protectedTags, rel.TagName, rel.PublisherID) + isAllowed, err := git_model.IsUserAllowedToControlTag(ctx, protectedTags, rel.TagName, rel.PublisherID) if err != nil { return false, err } @@ -81,13 +81,13 @@ func createTag(gitRepo *git.Repository, rel *repo_model.Release, msg string) (bo commits.CompareURL = rel.Repo.ComposeCompareURL(git.EmptySHA, commit.ID.String()) notification.NotifyPushCommits( - rel.Publisher, rel.Repo, + ctx, rel.Publisher, rel.Repo, &repository.PushUpdateOptions{ RefFullName: git.TagPrefix + rel.TagName, OldCommitID: git.EmptySHA, NewCommitID: commit.ID.String(), }, commits) - notification.NotifyCreateRef(rel.Publisher, rel.Repo, "tag", git.TagPrefix+rel.TagName, commit.ID.String()) + notification.NotifyCreateRef(ctx, rel.Publisher, rel.Repo, "tag", git.TagPrefix+rel.TagName, commit.ID.String()) rel.CreatedUnix = timeutil.TimeStampNow() } commit, err := gitRepo.GetTagCommit(rel.TagName) @@ -102,7 +102,7 @@ func createTag(gitRepo *git.Repository, rel *repo_model.Release, msg string) (bo } if rel.PublisherID <= 0 { - u, err := user_model.GetUserByEmail(commit.Author.Email) + u, err := user_model.GetUserByEmailContext(ctx, commit.Author.Email) if err == nil { rel.PublisherID = u.ID } @@ -124,7 +124,7 @@ func CreateRelease(gitRepo *git.Repository, rel *repo_model.Release, attachmentU } } - if _, err = createTag(gitRepo, rel, msg); err != nil { + if _, err = createTag(gitRepo.Ctx, gitRepo, rel, msg); err != nil { return err } @@ -138,7 +138,7 @@ func CreateRelease(gitRepo *git.Repository, rel *repo_model.Release, attachmentU } if !rel.IsDraft { - notification.NotifyNewRelease(rel) + notification.NotifyNewRelease(gitRepo.Ctx, rel) } return nil @@ -173,7 +173,7 @@ func CreateNewTag(ctx context.Context, doer *user_model.User, repo *repo_model.R IsTag: true, } - if _, err = createTag(gitRepo, rel, msg); err != nil { + if _, err = createTag(ctx, gitRepo, rel, msg); err != nil { return err } @@ -190,7 +190,7 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod if rel.ID == 0 { return errors.New("UpdateRelease only accepts an exist release") } - isCreated, err := createTag(gitRepo, rel, "") + isCreated, err := createTag(gitRepo.Ctx, gitRepo, rel, "") if err != nil { return err } @@ -272,12 +272,12 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod } if !isCreated { - notification.NotifyUpdateRelease(doer, rel) + notification.NotifyUpdateRelease(gitRepo.Ctx, doer, rel) return } if !rel.IsDraft { - notification.NotifyNewRelease(rel) + notification.NotifyNewRelease(gitRepo.Ctx, rel) } return err @@ -296,11 +296,11 @@ func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, del } if delTag { - protectedTags, err := git_model.GetProtectedTags(rel.RepoID) + protectedTags, err := git_model.GetProtectedTags(ctx, rel.RepoID) if err != nil { return fmt.Errorf("GetProtectedTags: %w", err) } - isAllowed, err := git_model.IsUserAllowedToControlTag(protectedTags, rel.TagName, rel.PublisherID) + isAllowed, err := git_model.IsUserAllowedToControlTag(ctx, protectedTags, rel.TagName, rel.PublisherID) if err != nil { return err } @@ -318,15 +318,15 @@ func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, del } notification.NotifyPushCommits( - doer, repo, + ctx, doer, repo, &repository.PushUpdateOptions{ RefFullName: git.TagPrefix + rel.TagName, OldCommitID: rel.Sha1, NewCommitID: git.EmptySHA, }, repository.NewPushCommits()) - notification.NotifyDeleteRef(doer, repo, "tag", git.TagPrefix+rel.TagName) + notification.NotifyDeleteRef(ctx, doer, repo, "tag", git.TagPrefix+rel.TagName) - if err := repo_model.DeleteReleaseByID(id); err != nil { + if err := repo_model.DeleteReleaseByID(ctx, id); err != nil { return fmt.Errorf("DeleteReleaseByID: %w", err) } } else { @@ -338,11 +338,11 @@ func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, del } rel.Repo = repo - if err = rel.LoadAttributes(); err != nil { + if err = rel.LoadAttributes(ctx); err != nil { return fmt.Errorf("LoadAttributes: %w", err) } - if err := repo_model.DeleteAttachmentsByRelease(rel.ID); err != nil { + if err := repo_model.DeleteAttachmentsByRelease(ctx, rel.ID); err != nil { return fmt.Errorf("DeleteAttachments: %w", err) } @@ -353,7 +353,7 @@ func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, del } } - notification.NotifyDeleteRelease(doer, rel) + notification.NotifyDeleteRelease(ctx, doer, rel) return nil } diff --git a/services/release/release_test.go b/services/release/release_test.go index c0cafb5fcc..1ade9bed37 100644 --- a/services/release/release_test.go +++ b/services/release/release_test.go @@ -297,13 +297,13 @@ func TestRelease_createTag(t *testing.T) { IsPrerelease: false, IsTag: false, } - _, err = createTag(gitRepo, release, "") + _, err = createTag(db.DefaultContext, gitRepo, release, "") assert.NoError(t, err) assert.NotEmpty(t, release.CreatedUnix) releaseCreatedUnix := release.CreatedUnix time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp release.Note = "Changed note" - _, err = createTag(gitRepo, release, "") + _, err = createTag(db.DefaultContext, gitRepo, release, "") assert.NoError(t, err) assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix)) @@ -321,12 +321,12 @@ func TestRelease_createTag(t *testing.T) { IsPrerelease: false, IsTag: false, } - _, err = createTag(gitRepo, release, "") + _, err = createTag(db.DefaultContext, gitRepo, release, "") assert.NoError(t, err) releaseCreatedUnix = release.CreatedUnix time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp release.Title = "Changed title" - _, err = createTag(gitRepo, release, "") + _, err = createTag(db.DefaultContext, gitRepo, release, "") assert.NoError(t, err) assert.Less(t, int64(releaseCreatedUnix), int64(release.CreatedUnix)) @@ -344,13 +344,13 @@ func TestRelease_createTag(t *testing.T) { IsPrerelease: true, IsTag: false, } - _, err = createTag(gitRepo, release, "") + _, err = createTag(db.DefaultContext, gitRepo, release, "") assert.NoError(t, err) releaseCreatedUnix = release.CreatedUnix time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp release.Title = "Changed title" release.Note = "Changed note" - _, err = createTag(gitRepo, release, "") + _, err = createTag(db.DefaultContext, gitRepo, release, "") assert.NoError(t, err) assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix)) } diff --git a/services/repository/adopt.go b/services/repository/adopt.go index 57a21f500c..3895c54c7b 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -96,7 +96,7 @@ func AdoptRepository(doer, u *user_model.User, opts repo_module.CreateRepoOption return nil, err } - notification.NotifyCreateRepository(doer, u, repo) + notification.NotifyCreateRepository(db.DefaultContext, doer, u, repo) return repo, nil } diff --git a/services/repository/branch.go b/services/repository/branch.go index 1328422582..e1f26b89af 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -11,6 +11,7 @@ import ( "strings" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -141,8 +142,8 @@ func RenameBranch(repo *repo_model.Repository, doer *user_model.User, gitRepo *g return "", err } - notification.NotifyDeleteRef(doer, repo, "branch", git.BranchPrefix+from) - notification.NotifyCreateRef(doer, repo, "branch", git.BranchPrefix+to, refID) + notification.NotifyDeleteRef(db.DefaultContext, doer, repo, "branch", git.BranchPrefix+from) + notification.NotifyCreateRef(db.DefaultContext, doer, repo, "branch", git.BranchPrefix+to, refID) return "", nil } diff --git a/services/repository/fork.go b/services/repository/fork.go index e597bfa449..a9a2b33ed8 100644 --- a/services/repository/fork.go +++ b/services/repository/fork.go @@ -177,7 +177,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork } } - notification.NotifyForkRepository(doer, opts.BaseRepo, repo) + notification.NotifyForkRepository(ctx, doer, opts.BaseRepo, repo) return repo, nil } diff --git a/services/repository/push.go b/services/repository/push.go index 6776ff9f74..e2db18e1f7 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -117,7 +117,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { tagName := opts.TagName() if opts.IsDelRef() { notification.NotifyPushCommits( - pusher, repo, + db.DefaultContext, pusher, repo, &repo_module.PushUpdateOptions{ RefFullName: git.TagPrefix + tagName, OldCommitID: opts.OldCommitID, @@ -125,7 +125,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { }, repo_module.NewPushCommits()) delTags = append(delTags, tagName) - notification.NotifyDeleteRef(pusher, repo, "tag", opts.RefFullName) + notification.NotifyDeleteRef(db.DefaultContext, pusher, repo, "tag", opts.RefFullName) } else { // is new tag newCommit, err := gitRepo.GetCommit(opts.NewCommitID) if err != nil { @@ -137,7 +137,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { commits.CompareURL = repo.ComposeCompareURL(git.EmptySHA, opts.NewCommitID) notification.NotifyPushCommits( - pusher, repo, + db.DefaultContext, pusher, repo, &repo_module.PushUpdateOptions{ RefFullName: git.TagPrefix + tagName, OldCommitID: git.EmptySHA, @@ -145,7 +145,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { }, commits) addTags = append(addTags, tagName) - notification.NotifyCreateRef(pusher, repo, "tag", opts.RefFullName, opts.NewCommitID) + notification.NotifyCreateRef(db.DefaultContext, pusher, repo, "tag", opts.RefFullName, opts.NewCommitID) } } else if opts.IsBranch() { // If is branch reference if pusher == nil || pusher.ID != opts.PusherID { @@ -190,7 +190,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { if err != nil { return fmt.Errorf("newCommit.CommitsBeforeLimit: %w", err) } - notification.NotifyCreateRef(pusher, repo, "branch", opts.RefFullName, opts.NewCommitID) + notification.NotifyCreateRef(db.DefaultContext, pusher, repo, "branch", opts.RefFullName, opts.NewCommitID) } else { l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID) if err != nil { @@ -250,7 +250,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { commits.Commits = commits.Commits[:setting.UI.FeedMaxCommitNum] } - notification.NotifyPushCommits(pusher, repo, opts, commits) + notification.NotifyPushCommits(db.DefaultContext, pusher, repo, opts, commits) if err = git_model.RemoveDeletedBranchByName(repo.ID, branch); err != nil { log.Error("models.RemoveDeletedBranch %s/%s failed: %v", repo.ID, branch, err) @@ -261,7 +261,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { log.Error("repo_module.CacheRef %s/%s failed: %v", repo.ID, branch, err) } } else { - notification.NotifyDeleteRef(pusher, repo, "branch", opts.RefFullName) + notification.NotifyDeleteRef(db.DefaultContext, pusher, repo, "branch", opts.RefFullName) if err = pull_service.CloseBranchPulls(pusher, repo.ID, branch); err != nil { // close all related pulls log.Error("close related pull request failed: %v", err) diff --git a/services/repository/repository.go b/services/repository/repository.go index 2f2c27ff20..c369b98aae 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -32,7 +32,7 @@ func CreateRepository(doer, owner *user_model.User, opts repo_module.CreateRepoO return nil, err } - notification.NotifyCreateRepository(doer, owner, repo) + notification.NotifyCreateRepository(db.DefaultContext, doer, owner, repo) return repo, nil } @@ -45,7 +45,7 @@ func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_mod if notify { // If the repo itself has webhooks, we need to trigger them before deleting it... - notification.NotifyDeleteRepository(doer, repo) + notification.NotifyDeleteRepository(ctx, doer, repo) } if err := models.DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil { diff --git a/services/repository/template.go b/services/repository/template.go index bb5e3f4668..625bc305de 100644 --- a/services/repository/template.go +++ b/services/repository/template.go @@ -101,7 +101,7 @@ func GenerateRepository(doer, owner *user_model.User, templateRepo *repo_model.R return nil, err } - notification.NotifyCreateRepository(doer, owner, generateRepo) + notification.NotifyCreateRepository(db.DefaultContext, doer, owner, generateRepo) return generateRepo, nil } diff --git a/services/repository/transfer.go b/services/repository/transfer.go index a0f4a7685c..2778f2e744 100644 --- a/services/repository/transfer.go +++ b/services/repository/transfer.go @@ -55,7 +55,7 @@ func TransferOwnership(doer, newOwner *user_model.User, repo *repo_model.Reposit } } - notification.NotifyTransferRepository(doer, repo, oldOwner.Name) + notification.NotifyTransferRepository(db.DefaultContext, doer, repo, oldOwner.Name) return nil } @@ -78,7 +78,7 @@ func ChangeRepositoryName(doer *user_model.User, repo *repo_model.Repository, ne repoWorkingPool.CheckOut(fmt.Sprint(repo.ID)) repo.Name = newRepoName - notification.NotifyRenameRepository(doer, repo, oldRepoName) + notification.NotifyRenameRepository(db.DefaultContext, doer, repo, oldRepoName) return nil } @@ -127,7 +127,7 @@ func StartRepositoryTransfer(doer, newOwner *user_model.User, repo *repo_model.R } // notify users who are able to accept / reject transfer - notification.NotifyRepoPendingTransfer(doer, newOwner, repo) + notification.NotifyRepoPendingTransfer(db.DefaultContext, doer, newOwner, repo) return nil } diff --git a/services/task/migrate.go b/services/task/migrate.go index faca6908a2..307c60a09a 100644 --- a/services/task/migrate.go +++ b/services/task/migrate.go @@ -51,7 +51,7 @@ func runMigrateTask(t *admin_model.Task) (err error) { if err == nil { err = admin_model.FinishMigrateTask(t) if err == nil { - notification.NotifyMigrateRepository(t.Doer, t.Owner, t.Repo) + notification.NotifyMigrateRepository(db.DefaultContext, t.Doer, t.Owner, t.Repo) return } diff --git a/services/user/user.go b/services/user/user.go index 4186efe682..9976bc7bd3 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -78,7 +78,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { Actor: u, }) if err != nil { - return fmt.Errorf("SearchRepositoryByName: %w", err) + return fmt.Errorf("GetUserRepositories: %w", err) } if len(repos) == 0 { break diff --git a/services/webhook/webhook.go b/services/webhook/webhook.go index 342e764f4d..1780022eb4 100644 --- a/services/webhook/webhook.go +++ b/services/webhook/webhook.go @@ -224,7 +224,7 @@ func PrepareWebhooks(ctx context.Context, source EventSource, event webhook_mode } ws = append(ws, repoHooks...) - owner = source.Repository.MustOwner() + owner = source.Repository.MustOwner(ctx) } // check if owner is an org and append additional webhooks diff --git a/templates/user/notification/notification_div.tmpl b/templates/user/notification/notification_div.tmpl index 192652d06b..18071549a0 100644 --- a/templates/user/notification/notification_div.tmpl +++ b/templates/user/notification/notification_div.tmpl @@ -34,7 +34,6 @@ {{range $notification := .Notifications}} {{$issue := .Issue}} {{$repo := .Repository}} - {{$repoOwner := $repo.MustOwner}} {{if eq .Status 3}} @@ -69,9 +68,7 @@ - - {{$repoOwner.Name}}/{{$repo.Name}} - + {{$repo.FullName}} {{if ne .Status 3}} diff --git a/tests/integration/api_comment_test.go b/tests/integration/api_comment_test.go index 126d886842..9cac32b9b9 100644 --- a/tests/integration/api_comment_test.go +++ b/tests/integration/api_comment_test.go @@ -10,6 +10,7 @@ import ( "net/url" "testing" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" @@ -115,7 +116,7 @@ func TestAPIGetComment(t *testing.T) { defer tests.PrepareTestEnv(t)() comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2}) - assert.NoError(t, comment.LoadIssue()) + assert.NoError(t, comment.LoadIssue(db.DefaultContext)) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID}) repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) @@ -129,7 +130,7 @@ func TestAPIGetComment(t *testing.T) { var apiComment api.Comment DecodeJSON(t, resp, &apiComment) - assert.NoError(t, comment.LoadPoster()) + assert.NoError(t, comment.LoadPoster(db.DefaultContext)) expect := convert.ToComment(comment) assert.Equal(t, expect.ID, apiComment.ID) diff --git a/tests/integration/api_issue_reaction_test.go b/tests/integration/api_issue_reaction_test.go index a3cb9303fb..9afc7475e2 100644 --- a/tests/integration/api_issue_reaction_test.go +++ b/tests/integration/api_issue_reaction_test.go @@ -82,7 +82,7 @@ func TestAPICommentReactions(t *testing.T) { defer tests.PrepareTestEnv(t)() comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2}) - _ = comment.LoadIssue() + _ = comment.LoadIssue(db.DefaultContext) issue := comment.Issue _ = issue.LoadRepo(db.DefaultContext) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}) diff --git a/tests/integration/api_notification_test.go b/tests/integration/api_notification_test.go index bf85520bb5..f143802228 100644 --- a/tests/integration/api_notification_test.go +++ b/tests/integration/api_notification_test.go @@ -10,6 +10,7 @@ import ( "testing" activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -25,7 +26,7 @@ func TestAPINotification(t *testing.T) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) thread5 := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{ID: 5}) - assert.NoError(t, thread5.LoadAttributes()) + assert.NoError(t, thread5.LoadAttributes(db.DefaultContext)) session := loginUser(t, user2.Name) token := getTokenForLoggedInUser(t, session) @@ -143,7 +144,7 @@ func TestAPINotificationPUT(t *testing.T) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) thread5 := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{ID: 5}) - assert.NoError(t, thread5.LoadAttributes()) + assert.NoError(t, thread5.LoadAttributes(db.DefaultContext)) session := loginUser(t, user2.Name) token := getTokenForLoggedInUser(t, session) diff --git a/tests/integration/api_pull_commits_test.go b/tests/integration/api_pull_commits_test.go index aa58f44bbe..6753ceaa97 100644 --- a/tests/integration/api_pull_commits_test.go +++ b/tests/integration/api_pull_commits_test.go @@ -8,6 +8,7 @@ import ( "net/http" "testing" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" @@ -19,12 +20,12 @@ import ( func TestAPIPullCommits(t *testing.T) { defer tests.PrepareTestEnv(t)() - pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) - assert.NoError(t, pullIssue.LoadIssue()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.HeadRepoID}) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) + assert.NoError(t, pr.LoadIssue(db.DefaultContext)) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pr.HeadRepoID}) session := loginUser(t, "user2") - req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/commits", repo.OwnerName, repo.Name, pullIssue.Index) + req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/commits", repo.OwnerName, repo.Name, pr.Index) resp := session.MakeRequest(t, req, http.StatusOK) var commits []*api.Commit diff --git a/tests/integration/api_pull_test.go b/tests/integration/api_pull_test.go index 8ce92f3d4a..81842b05fb 100644 --- a/tests/integration/api_pull_test.go +++ b/tests/integration/api_pull_test.go @@ -10,6 +10,7 @@ import ( "net/http" "testing" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" @@ -65,11 +66,11 @@ func TestAPIMergePullWIP(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{Status: issues_model.PullRequestStatusMergeable}, unittest.Cond("has_merged = ?", false)) - pr.LoadIssue() + pr.LoadIssue(db.DefaultContext) issue_service.ChangeTitle(pr.Issue, owner, setting.Repository.PullRequest.WorkInProgressPrefixes[0]+" "+pr.Issue.Title) // force reload - pr.LoadAttributes() + pr.LoadAttributes(db.DefaultContext) assert.Contains(t, pr.Issue.Title, setting.Repository.PullRequest.WorkInProgressPrefixes[0]) diff --git a/tests/integration/eventsource_test.go b/tests/integration/eventsource_test.go index cd496e0129..2f698659cb 100644 --- a/tests/integration/eventsource_test.go +++ b/tests/integration/eventsource_test.go @@ -11,6 +11,7 @@ import ( "time" activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -57,7 +58,7 @@ func TestEventSourceManagerRun(t *testing.T) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) thread5 := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{ID: 5}) - assert.NoError(t, thread5.LoadAttributes()) + assert.NoError(t, thread5.LoadAttributes(db.DefaultContext)) session := loginUser(t, user2.Name) token := getTokenForLoggedInUser(t, session) diff --git a/tests/integration/pull_update_test.go b/tests/integration/pull_update_test.go index c08faaaeb6..1bfe5c7050 100644 --- a/tests/integration/pull_update_test.go +++ b/tests/integration/pull_update_test.go @@ -35,8 +35,8 @@ func TestAPIPullUpdate(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, 1, diffCount.Behind) assert.EqualValues(t, 1, diffCount.Ahead) - assert.NoError(t, pr.LoadBaseRepo()) - assert.NoError(t, pr.LoadIssue()) + assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext)) + assert.NoError(t, pr.LoadIssue(db.DefaultContext)) session := loginUser(t, "user2") token := getTokenForLoggedInUser(t, session) @@ -63,8 +63,8 @@ func TestAPIPullUpdateByRebase(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, 1, diffCount.Behind) assert.EqualValues(t, 1, diffCount.Ahead) - assert.NoError(t, pr.LoadBaseRepo()) - assert.NoError(t, pr.LoadIssue()) + assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext)) + assert.NoError(t, pr.LoadIssue(db.DefaultContext)) session := loginUser(t, "user2") token := getTokenForLoggedInUser(t, session) diff --git a/tests/integration/repo_tag_test.go b/tests/integration/repo_tag_test.go index fb08895e21..e20c725915 100644 --- a/tests/integration/repo_tag_test.go +++ b/tests/integration/repo_tag_test.go @@ -9,6 +9,7 @@ import ( "testing" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" @@ -74,22 +75,22 @@ func TestCreateNewTagProtected(t *testing.T) { }) // Cleanup - releases, err := repo_model.GetReleasesByRepoID(repo.ID, repo_model.FindReleasesOptions{ + releases, err := repo_model.GetReleasesByRepoID(db.DefaultContext, repo.ID, repo_model.FindReleasesOptions{ IncludeTags: true, TagNames: []string{"v-1", "v-1.1"}, }) assert.NoError(t, err) for _, release := range releases { - err = repo_model.DeleteReleaseByID(release.ID) + err = repo_model.DeleteReleaseByID(db.DefaultContext, release.ID) assert.NoError(t, err) } - protectedTags, err := git_model.GetProtectedTags(repo.ID) + protectedTags, err := git_model.GetProtectedTags(db.DefaultContext, repo.ID) assert.NoError(t, err) for _, protectedTag := range protectedTags { - err = git_model.DeleteProtectedTag(protectedTag) + err = git_model.DeleteProtectedTag(db.DefaultContext, protectedTag) assert.NoError(t, err) } } From eec1c718806797b21ba5f6c1ceddf711e9d4801a Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 19 Nov 2022 12:08:06 +0100 Subject: [PATCH 047/149] Show syntax lexer name in file view/blame (#21814) Show which Chroma Lexer is used to highlight the file in the file header. It's useful for development to see what was detected, and I think it's not bad info to have for the user: Screenshot 2022-11-14 at 22 31 16 Screenshot 2022-11-14 at 22 36 06 Screenshot 2022-11-14 at 22 36 26 Also, I improved the way this header overflows on small screens: Screenshot 2022-11-14 at 22 44 36 Co-authored-by: delvh Co-authored-by: Lauris BH Co-authored-by: Lunny Xiao Co-authored-by: John Olheiser --- modules/highlight/highlight.go | 36 ++++++++++++------ modules/highlight/highlight_test.go | 59 +++++++++++++++++++---------- modules/indexer/code/search.go | 5 ++- modules/util/util.go | 10 ++++- routers/web/repo/blame.go | 13 ++++++- routers/web/repo/view.go | 3 +- services/gitdiff/gitdiff.go | 3 +- services/gitdiff/highlightdiff.go | 4 +- templates/repo/blame.tmpl | 13 ++----- templates/repo/file_info.tmpl | 28 ++++++++++++++ templates/repo/view_file.tmpl | 30 ++------------- 11 files changed, 132 insertions(+), 72 deletions(-) create mode 100644 templates/repo/file_info.tmpl diff --git a/modules/highlight/highlight.go b/modules/highlight/highlight.go index 65ed74b019..3836c05880 100644 --- a/modules/highlight/highlight.go +++ b/modules/highlight/highlight.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/analyze" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "github.com/alecthomas/chroma/v2" "github.com/alecthomas/chroma/v2/formatters/html" @@ -56,18 +57,18 @@ func NewContext() { }) } -// Code returns a HTML version of code string with chroma syntax highlighting classes -func Code(fileName, language, code string) string { +// Code returns a HTML version of code string with chroma syntax highlighting classes and the matched lexer name +func Code(fileName, language, code string) (string, string) { NewContext() // diff view newline will be passed as empty, change to literal '\n' so it can be copied // preserve literal newline in blame view if code == "" || code == "\n" { - return "\n" + return "\n", "" } if len(code) > sizeLimit { - return code + return code, "" } var lexer chroma.Lexer @@ -103,7 +104,10 @@ func Code(fileName, language, code string) string { } cache.Add(fileName, lexer) } - return CodeFromLexer(lexer, code) + + lexerName := formatLexerName(lexer.Config().Name) + + return CodeFromLexer(lexer, code), lexerName } // CodeFromLexer returns a HTML version of code string with chroma syntax highlighting classes @@ -134,12 +138,12 @@ func CodeFromLexer(lexer chroma.Lexer, code string) string { return strings.TrimSuffix(htmlbuf.String(), "\n") } -// File returns a slice of chroma syntax highlighted HTML lines of code -func File(fileName, language string, code []byte) ([]string, error) { +// File returns a slice of chroma syntax highlighted HTML lines of code and the matched lexer name +func File(fileName, language string, code []byte) ([]string, string, error) { NewContext() if len(code) > sizeLimit { - return PlainText(code), nil + return PlainText(code), "", nil } formatter := html.New(html.WithClasses(true), @@ -172,9 +176,11 @@ func File(fileName, language string, code []byte) ([]string, error) { } } + lexerName := formatLexerName(lexer.Config().Name) + iterator, err := lexer.Tokenise(nil, string(code)) if err != nil { - return nil, fmt.Errorf("can't tokenize code: %w", err) + return nil, "", fmt.Errorf("can't tokenize code: %w", err) } tokensLines := chroma.SplitTokensIntoLines(iterator.Tokens()) @@ -185,13 +191,13 @@ func File(fileName, language string, code []byte) ([]string, error) { iterator = chroma.Literator(tokens...) err = formatter.Format(htmlBuf, styles.GitHub, iterator) if err != nil { - return nil, fmt.Errorf("can't format code: %w", err) + return nil, "", fmt.Errorf("can't format code: %w", err) } lines = append(lines, htmlBuf.String()) htmlBuf.Reset() } - return lines, nil + return lines, lexerName, nil } // PlainText returns non-highlighted HTML for code @@ -212,3 +218,11 @@ func PlainText(code []byte) []string { } return m } + +func formatLexerName(name string) string { + if name == "fallback" { + return "Plaintext" + } + + return util.ToTitleCaseNoLower(name) +} diff --git a/modules/highlight/highlight_test.go b/modules/highlight/highlight_test.go index 8f83f4a2f6..1899753746 100644 --- a/modules/highlight/highlight_test.go +++ b/modules/highlight/highlight_test.go @@ -17,34 +17,52 @@ func lines(s string) []string { func TestFile(t *testing.T) { tests := []struct { - name string - code string - want []string + name string + code string + want []string + lexerName string }{ { - name: "empty.py", - code: "", - want: lines(""), + name: "empty.py", + code: "", + want: lines(""), + lexerName: "Python", }, { - name: "tags.txt", - code: "<>", - want: lines("<>"), + name: "empty.js", + code: "", + want: lines(""), + lexerName: "JavaScript", }, { - name: "tags.py", - code: "<>", - want: lines(`<>`), + name: "empty.yaml", + code: "", + want: lines(""), + lexerName: "YAML", }, { - name: "eol-no.py", - code: "a=1", - want: lines(`a=1`), + name: "tags.txt", + code: "<>", + want: lines("<>"), + lexerName: "Plaintext", }, { - name: "eol-newline1.py", - code: "a=1\n", - want: lines(`a=1\n`), + name: "tags.py", + code: "<>", + want: lines(`<>`), + lexerName: "Python", + }, + { + name: "eol-no.py", + code: "a=1", + want: lines(`a=1`), + lexerName: "Python", + }, + { + name: "eol-newline1.py", + code: "a=1\n", + want: lines(`a=1\n`), + lexerName: "Python", }, { name: "eol-newline2.py", @@ -54,6 +72,7 @@ func TestFile(t *testing.T) { \n `, ), + lexerName: "Python", }, { name: "empty-line-with-space.py", @@ -73,17 +92,19 @@ c=2 \n c=2`, ), + lexerName: "Python", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - out, err := File(tt.name, "", []byte(tt.code)) + out, lexerName, err := File(tt.name, "", []byte(tt.code)) assert.NoError(t, err) expected := strings.Join(tt.want, "\n") actual := strings.Join(out, "\n") assert.Equal(t, strings.Count(actual, "")) assert.EqualValues(t, expected, actual) + assert.Equal(t, tt.lexerName, lexerName) }) } } diff --git a/modules/indexer/code/search.go b/modules/indexer/code/search.go index bb7715bafc..df255fa875 100644 --- a/modules/indexer/code/search.go +++ b/modules/indexer/code/search.go @@ -94,6 +94,9 @@ func searchResult(result *SearchResult, startIndex, endIndex int) (*Result, erro lineNumbers[i] = startLineNum + i index += len(line) } + + highlighted, _ := highlight.Code(result.Filename, "", formattedLinesBuffer.String()) + return &Result{ RepoID: result.RepoID, Filename: result.Filename, @@ -102,7 +105,7 @@ func searchResult(result *SearchResult, startIndex, endIndex int) (*Result, erro Language: result.Language, Color: result.Color, LineNumbers: lineNumbers, - FormattedLines: highlight.Code(result.Filename, "", formattedLinesBuffer.String()), + FormattedLines: highlighted, }, nil } diff --git a/modules/util/util.go b/modules/util/util.go index be60fe4b4b..6df47ca568 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -186,13 +186,21 @@ func ToUpperASCII(s string) string { return string(b) } -var titleCaser = cases.Title(language.English) +var ( + titleCaser = cases.Title(language.English) + titleCaserNoLower = cases.Title(language.English, cases.NoLower) +) // ToTitleCase returns s with all english words capitalized func ToTitleCase(s string) string { return titleCaser.String(s) } +// ToTitleCaseNoLower returns s with all english words capitalized without lowercasing +func ToTitleCaseNoLower(s string) string { + return titleCaserNoLower.String(s) +} + var ( whitespaceOnly = regexp.MustCompile("(?m)^[ \t]+$") leadingWhitespace = regexp.MustCompile("(?m)(^[ \t]*)(?:[^ \t\n])") diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index 64a6f0ec53..52d5c3c6e6 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -100,6 +100,8 @@ func RefBlame(ctx *context.Context) { ctx.Data["FileName"] = blob.Name() ctx.Data["NumLines"], err = blob.GetBlobLineCount() + ctx.Data["NumLinesSet"] = true + if err != nil { ctx.NotFound("GetBlobLineCount", err) return @@ -237,6 +239,8 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m rows := make([]*blameRow, 0) escapeStatus := &charset.EscapeStatus{} + var lexerName string + i := 0 commitCnt := 0 for _, part := range blameParts { @@ -278,7 +282,13 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m line += "\n" } fileName := fmt.Sprintf("%v", ctx.Data["FileName"]) - line = highlight.Code(fileName, language, line) + line, lexerNameForLine := highlight.Code(fileName, language, line) + + // set lexer name to the first detected lexer. this is certainly suboptimal and + // we should instead highlight the whole file at once + if lexerName == "" { + lexerName = lexerNameForLine + } br.EscapeStatus, line = charset.EscapeControlHTML(line, ctx.Locale) br.Code = gotemplate.HTML(line) @@ -290,4 +300,5 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m ctx.Data["EscapeStatus"] = escapeStatus ctx.Data["BlameRows"] = rows ctx.Data["CommitCnt"] = commitCnt + ctx.Data["LexerName"] = lexerName } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index e7aca04819..7500dbb34b 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -568,7 +568,8 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st language = "" } } - fileContent, err := highlight.File(blob.Name(), language, buf) + fileContent, lexerName, err := highlight.File(blob.Name(), language, buf) + ctx.Data["LexerName"] = lexerName if err != nil { log.Error("highlight.File failed, fallback to plain text: %v", err) fileContent = highlight.PlainText(buf) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 3c8c5c81a5..d24c0ac082 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -280,7 +280,8 @@ func DiffInlineWithUnicodeEscape(s template.HTML, locale translation.Locale) Dif // DiffInlineWithHighlightCode makes a DiffInline with code highlight and hidden unicode characters escaped func DiffInlineWithHighlightCode(fileName, language, code string, locale translation.Locale) DiffInline { - status, content := charset.EscapeControlHTML(highlight.Code(fileName, language, code), locale) + highlighted, _ := highlight.Code(fileName, language, code) + status, content := charset.EscapeControlHTML(highlighted, locale) return DiffInline{EscapeStatus: status, Content: template.HTML(content)} } diff --git a/services/gitdiff/highlightdiff.go b/services/gitdiff/highlightdiff.go index 4ceada4d7e..727827232d 100644 --- a/services/gitdiff/highlightdiff.go +++ b/services/gitdiff/highlightdiff.go @@ -91,8 +91,8 @@ func (hcd *highlightCodeDiff) diffWithHighlight(filename, language, codeA, codeB hcd.collectUsedRunes(codeA) hcd.collectUsedRunes(codeB) - highlightCodeA := highlight.Code(filename, language, codeA) - highlightCodeB := highlight.Code(filename, language, codeB) + highlightCodeA, _ := highlight.Code(filename, language, codeA) + highlightCodeB, _ := highlight.Code(filename, language, codeB) highlightCodeA = hcd.convertToPlaceholders(highlightCodeA) highlightCodeB = hcd.convertToPlaceholders(highlightCodeB) diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl index b697573d24..e4a10ee57d 100644 --- a/templates/repo/blame.tmpl +++ b/templates/repo/blame.tmpl @@ -1,14 +1,9 @@
-

-
-
-
- {{.NumLines}} {{.locale.TrN .NumLines "repo.line" "repo.lines"}} -
-
{{FileSize .FileSize}}
-
+

+
+ {{template "repo/file_info" .}}
-
+
{{.locale.Tr "repo.file_raw"}} {{if not .IsViewCommit}} diff --git a/templates/repo/file_info.tmpl b/templates/repo/file_info.tmpl new file mode 100644 index 0000000000..90a831fb8e --- /dev/null +++ b/templates/repo/file_info.tmpl @@ -0,0 +1,28 @@ +
+ {{if .FileIsSymlink}} +
+ {{.locale.Tr "repo.symbolic_link"}} +
+ {{end}} + {{if .NumLinesSet}}{{/* Explicit attribute needed to show 0 line changes */}} +
+ {{.NumLines}} {{.locale.TrN .NumLines "repo.line" "repo.lines"}} +
+ {{end}} + {{if .FileSize}} +
+ {{FileSize .FileSize}}{{if .IsLFSFile}} ({{.locale.Tr "repo.stored_lfs"}}){{end}} +
+ {{end}} + {{if .LFSLock}} +
+ {{svg "octicon-lock" 16 "mr-2"}} + {{.LFSLockOwner}} +
+ {{end}} + {{if .LexerName}} +
+ {{.LexerName}} +
+ {{end}} +
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 60d2a812de..321600a997 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -6,38 +6,16 @@
{{end}} -

-
+

+
{{if .ReadmeInList}} {{svg "octicon-book" 16 "mr-3"}} {{.FileName}} {{else}} -
- {{if .FileIsSymlink}} -
- {{.locale.Tr "repo.symbolic_link"}} -
- {{end}} - {{if .NumLinesSet}} -
- {{.NumLines}} {{.locale.TrN .NumLines "repo.line" "repo.lines"}} -
- {{end}} - {{if .FileSize}} -
- {{FileSize .FileSize}}{{if .IsLFSFile}} ({{.locale.Tr "repo.stored_lfs"}}){{end}} -
- {{end}} - {{if .LFSLock}} -
- {{svg "octicon-lock" 16 "mr-2"}} - {{.LFSLockOwner}} -
- {{end}} -
+ {{template "repo/file_info" .}} {{end}}
-
+
{{if .HasSourceRenderedToggle}}
{{svg "octicon-code" 15}} From c8f3eb6acbf16b9f2e74fa2bfabb384359fbadd8 Mon Sep 17 00:00:00 2001 From: Jim Kirisame Date: Sat, 19 Nov 2022 23:19:14 +0800 Subject: [PATCH 048/149] Fix wechatwork webhook sends empty content in PR review (#21762) Wechatwork webhook is sending the following string for pull request reviews: ``` markdown # > ``` This commit fixes this problem. --- services/webhook/wechatwork.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/webhook/wechatwork.go b/services/webhook/wechatwork.go index 5344ccaa22..acaa12253b 100644 --- a/services/webhook/wechatwork.go +++ b/services/webhook/wechatwork.go @@ -139,7 +139,7 @@ func (f *WechatworkPayload) PullRequest(p *api.PullRequestPayload) (api.Payloade func (f *WechatworkPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { var text, title string switch p.Action { - case api.HookIssueSynchronized: + case api.HookIssueReviewed: action, err := parseHookPullRequestEventType(event) if err != nil { return nil, err From d3f850cc0e791fa5ee5b25d824c475505fc12444 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Sat, 19 Nov 2022 23:22:15 +0800 Subject: [PATCH 049/149] Support comma-delimited string as labels in issue template (#21831) The [labels in issue YAML templates](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms#top-level-syntax) can be a string array or a comma-delimited string, so a single string should be valid labels. The old codes committed in #20987 ignore this, that's why the warning is displayed: image Fixes #17877. --- modules/issue/template/template.go | 4 +- modules/issue/template/template_test.go | 326 ++++++++++++++++-------- modules/issue/template/unmarshal.go | 2 +- modules/markup/markdown/meta_test.go | 48 ++-- modules/structs/issue.go | 53 +++- modules/structs/issue_test.go | 63 +++++ templates/swagger/v1_json.tmpl | 13 +- 7 files changed, 369 insertions(+), 140 deletions(-) diff --git a/modules/issue/template/template.go b/modules/issue/template/template.go index 3b33852cb5..0bdf5a1987 100644 --- a/modules/issue/template/template.go +++ b/modules/issue/template/template.go @@ -165,7 +165,7 @@ func validateOptions(field *api.IssueFormField, idx int) error { return position.Errorf("should be a string") } case api.IssueFormFieldTypeCheckboxes: - opt, ok := option.(map[interface{}]interface{}) + opt, ok := option.(map[string]interface{}) if !ok { return position.Errorf("should be a dictionary") } @@ -351,7 +351,7 @@ func (o *valuedOption) Label() string { return label } case api.IssueFormFieldTypeCheckboxes: - if vs, ok := o.data.(map[interface{}]interface{}); ok { + if vs, ok := o.data.(map[string]interface{}); ok { if v, ok := vs["label"].(string); ok { return v } diff --git a/modules/issue/template/template_test.go b/modules/issue/template/template_test.go index 883e1e0780..c3863a64a6 100644 --- a/modules/issue/template/template_test.go +++ b/modules/issue/template/template_test.go @@ -6,18 +6,21 @@ package template import ( "net/url" - "reflect" "testing" "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" + + "github.com/stretchr/testify/require" ) func TestValidate(t *testing.T) { tests := []struct { - name string - content string - wantErr string + name string + filename string + content string + want *api.IssueTemplate + wantErr string }{ { name: "miss name", @@ -316,21 +319,9 @@ body: `, wantErr: "body[0](checkboxes), option[0]: 'required' should be a bool", }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tmpl, err := unmarshal("test.yaml", []byte(tt.content)) - if err != nil { - t.Fatal(err) - } - if err := Validate(tmpl); (err == nil) != (tt.wantErr == "") || err != nil && err.Error() != tt.wantErr { - t.Errorf("Validate() error = %v, wantErr %q", err, tt.wantErr) - } - }) - } - - t.Run("valid", func(t *testing.T) { - content := ` + { + name: "valid", + content: ` name: Name title: Title about: About @@ -386,96 +377,227 @@ body: required: false - label: Option 3 of checkboxes required: true -` - want := &api.IssueTemplate{ - Name: "Name", - Title: "Title", - About: "About", - Labels: []string{"label1", "label2"}, - Ref: "Ref", - Fields: []*api.IssueFormField{ - { - Type: "markdown", - ID: "id1", - Attributes: map[string]interface{}{ - "value": "Value of the markdown", - }, - }, - { - Type: "textarea", - ID: "id2", - Attributes: map[string]interface{}{ - "label": "Label of textarea", - "description": "Description of textarea", - "placeholder": "Placeholder of textarea", - "value": "Value of textarea", - "render": "bash", - }, - Validations: map[string]interface{}{ - "required": true, - }, - }, - { - Type: "input", - ID: "id3", - Attributes: map[string]interface{}{ - "label": "Label of input", - "description": "Description of input", - "placeholder": "Placeholder of input", - "value": "Value of input", - }, - Validations: map[string]interface{}{ - "required": true, - "is_number": true, - "regex": "[a-zA-Z0-9]+", - }, - }, - { - Type: "dropdown", - ID: "id4", - Attributes: map[string]interface{}{ - "label": "Label of dropdown", - "description": "Description of dropdown", - "multiple": true, - "options": []interface{}{ - "Option 1 of dropdown", - "Option 2 of dropdown", - "Option 3 of dropdown", +`, + want: &api.IssueTemplate{ + Name: "Name", + Title: "Title", + About: "About", + Labels: []string{"label1", "label2"}, + Ref: "Ref", + Fields: []*api.IssueFormField{ + { + Type: "markdown", + ID: "id1", + Attributes: map[string]interface{}{ + "value": "Value of the markdown", }, }, - Validations: map[string]interface{}{ - "required": true, + { + Type: "textarea", + ID: "id2", + Attributes: map[string]interface{}{ + "label": "Label of textarea", + "description": "Description of textarea", + "placeholder": "Placeholder of textarea", + "value": "Value of textarea", + "render": "bash", + }, + Validations: map[string]interface{}{ + "required": true, + }, }, - }, - { - Type: "checkboxes", - ID: "id5", - Attributes: map[string]interface{}{ - "label": "Label of checkboxes", - "description": "Description of checkboxes", - "options": []interface{}{ - map[interface{}]interface{}{"label": "Option 1 of checkboxes", "required": true}, - map[interface{}]interface{}{"label": "Option 2 of checkboxes", "required": false}, - map[interface{}]interface{}{"label": "Option 3 of checkboxes", "required": true}, + { + Type: "input", + ID: "id3", + Attributes: map[string]interface{}{ + "label": "Label of input", + "description": "Description of input", + "placeholder": "Placeholder of input", + "value": "Value of input", + }, + Validations: map[string]interface{}{ + "required": true, + "is_number": true, + "regex": "[a-zA-Z0-9]+", + }, + }, + { + Type: "dropdown", + ID: "id4", + Attributes: map[string]interface{}{ + "label": "Label of dropdown", + "description": "Description of dropdown", + "multiple": true, + "options": []interface{}{ + "Option 1 of dropdown", + "Option 2 of dropdown", + "Option 3 of dropdown", + }, + }, + Validations: map[string]interface{}{ + "required": true, + }, + }, + { + Type: "checkboxes", + ID: "id5", + Attributes: map[string]interface{}{ + "label": "Label of checkboxes", + "description": "Description of checkboxes", + "options": []interface{}{ + map[string]interface{}{"label": "Option 1 of checkboxes", "required": true}, + map[string]interface{}{"label": "Option 2 of checkboxes", "required": false}, + map[string]interface{}{"label": "Option 3 of checkboxes", "required": true}, + }, }, }, }, + FileName: "test.yaml", }, - FileName: "test.yaml", - } - got, err := unmarshal("test.yaml", []byte(content)) - if err != nil { - t.Fatal(err) - } - if err := Validate(got); err != nil { - t.Errorf("Validate() error = %v", err) - } - if !reflect.DeepEqual(want, got) { - jsonWant, _ := json.Marshal(want) - jsonGot, _ := json.Marshal(got) - t.Errorf("want:\n%s\ngot:\n%s", jsonWant, jsonGot) - } - }) + wantErr: "", + }, + { + name: "single label", + content: ` +name: Name +title: Title +about: About +labels: label1 +ref: Ref +body: + - type: markdown + id: id1 + attributes: + value: Value of the markdown +`, + want: &api.IssueTemplate{ + Name: "Name", + Title: "Title", + About: "About", + Labels: []string{"label1"}, + Ref: "Ref", + Fields: []*api.IssueFormField{ + { + Type: "markdown", + ID: "id1", + Attributes: map[string]interface{}{ + "value": "Value of the markdown", + }, + }, + }, + FileName: "test.yaml", + }, + wantErr: "", + }, + { + name: "comma-delimited labels", + content: ` +name: Name +title: Title +about: About +labels: label1,label2,,label3 ,, +ref: Ref +body: + - type: markdown + id: id1 + attributes: + value: Value of the markdown +`, + want: &api.IssueTemplate{ + Name: "Name", + Title: "Title", + About: "About", + Labels: []string{"label1", "label2", "label3"}, + Ref: "Ref", + Fields: []*api.IssueFormField{ + { + Type: "markdown", + ID: "id1", + Attributes: map[string]interface{}{ + "value": "Value of the markdown", + }, + }, + }, + FileName: "test.yaml", + }, + wantErr: "", + }, + { + name: "empty string as labels", + content: ` +name: Name +title: Title +about: About +labels: '' +ref: Ref +body: + - type: markdown + id: id1 + attributes: + value: Value of the markdown +`, + want: &api.IssueTemplate{ + Name: "Name", + Title: "Title", + About: "About", + Labels: nil, + Ref: "Ref", + Fields: []*api.IssueFormField{ + { + Type: "markdown", + ID: "id1", + Attributes: map[string]interface{}{ + "value": "Value of the markdown", + }, + }, + }, + FileName: "test.yaml", + }, + wantErr: "", + }, + { + name: "comma delimited labels in markdown", + filename: "test.md", + content: `--- +name: Name +title: Title +about: About +labels: label1,label2,,label3 ,, +ref: Ref +--- +Content +`, + want: &api.IssueTemplate{ + Name: "Name", + Title: "Title", + About: "About", + Labels: []string{"label1", "label2", "label3"}, + Ref: "Ref", + Fields: nil, + Content: "Content\n", + FileName: "test.md", + }, + wantErr: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + filename := "test.yaml" + if tt.filename != "" { + filename = tt.filename + } + tmpl, err := unmarshal(filename, []byte(tt.content)) + require.NoError(t, err) + if tt.wantErr != "" { + require.EqualError(t, Validate(tmpl), tt.wantErr) + } else { + require.NoError(t, Validate(tmpl)) + want, _ := json.Marshal(tt.want) + got, _ := json.Marshal(tmpl) + require.JSONEq(t, string(want), string(got)) + } + }) + } } func TestRenderToMarkdown(t *testing.T) { diff --git a/modules/issue/template/unmarshal.go b/modules/issue/template/unmarshal.go index 24587b0fed..3398719cf6 100644 --- a/modules/issue/template/unmarshal.go +++ b/modules/issue/template/unmarshal.go @@ -16,7 +16,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) // CouldBe indicates a file with the filename could be a template, diff --git a/modules/markup/markdown/meta_test.go b/modules/markup/markdown/meta_test.go index 720d0066f4..1e9768e618 100644 --- a/modules/markup/markdown/meta_test.go +++ b/modules/markup/markdown/meta_test.go @@ -9,82 +9,86 @@ import ( "strings" "testing" - "code.gitea.io/gitea/modules/structs" - "github.com/stretchr/testify/assert" ) -func validateMetadata(it structs.IssueTemplate) bool { - /* - A legacy to keep the unit tests working. - Copied from the method "func (it IssueTemplate) Valid() bool", the original method has been removed. - Because it becomes quite complicated to validate an issue template which is support yaml form now. - The new way to validate an issue template is to call the Validate in modules/issue/template, - */ +/* +IssueTemplate is a legacy to keep the unit tests working. +Copied from structs.IssueTemplate, the original type has been changed a lot to support yaml template. +*/ +type IssueTemplate struct { + Name string `json:"name" yaml:"name"` + Title string `json:"title" yaml:"title"` + About string `json:"about" yaml:"about"` + Labels []string `json:"labels" yaml:"labels"` + Ref string `json:"ref" yaml:"ref"` +} + +func (it *IssueTemplate) Valid() bool { return strings.TrimSpace(it.Name) != "" && strings.TrimSpace(it.About) != "" } func TestExtractMetadata(t *testing.T) { t.Run("ValidFrontAndBody", func(t *testing.T) { - var meta structs.IssueTemplate + var meta IssueTemplate body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest), &meta) assert.NoError(t, err) assert.Equal(t, bodyTest, body) assert.Equal(t, metaTest, meta) - assert.True(t, validateMetadata(meta)) + assert.True(t, meta.Valid()) }) t.Run("NoFirstSeparator", func(t *testing.T) { - var meta structs.IssueTemplate + var meta IssueTemplate _, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", frontTest, sepTest, bodyTest), &meta) assert.Error(t, err) }) t.Run("NoLastSeparator", func(t *testing.T) { - var meta structs.IssueTemplate + var meta IssueTemplate _, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, bodyTest), &meta) assert.Error(t, err) }) t.Run("NoBody", func(t *testing.T) { - var meta structs.IssueTemplate + var meta IssueTemplate body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, sepTest), &meta) assert.NoError(t, err) assert.Equal(t, "", body) assert.Equal(t, metaTest, meta) - assert.True(t, validateMetadata(meta)) + assert.True(t, meta.Valid()) }) } func TestExtractMetadataBytes(t *testing.T) { t.Run("ValidFrontAndBody", func(t *testing.T) { - var meta structs.IssueTemplate + var meta IssueTemplate body, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest)), &meta) assert.NoError(t, err) assert.Equal(t, bodyTest, string(body)) assert.Equal(t, metaTest, meta) - assert.True(t, validateMetadata(meta)) + assert.True(t, meta.Valid()) }) t.Run("NoFirstSeparator", func(t *testing.T) { - var meta structs.IssueTemplate + var meta IssueTemplate _, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", frontTest, sepTest, bodyTest)), &meta) assert.Error(t, err) }) t.Run("NoLastSeparator", func(t *testing.T) { - var meta structs.IssueTemplate + var meta IssueTemplate _, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, bodyTest)), &meta) assert.Error(t, err) }) t.Run("NoBody", func(t *testing.T) { - var meta structs.IssueTemplate + var meta IssueTemplate body, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, sepTest)), &meta) assert.NoError(t, err) assert.Equal(t, "", string(body)) assert.Equal(t, metaTest, meta) - assert.True(t, validateMetadata(meta)) + assert.True(t, meta.Valid()) }) } @@ -97,7 +101,7 @@ labels: - bug - "test label"` bodyTest = "This is the body" - metaTest = structs.IssueTemplate{ + metaTest = IssueTemplate{ Name: "Test", About: "A Test", Title: "Test Title", diff --git a/modules/structs/issue.go b/modules/structs/issue.go index 25c6251fbf..45c3f6294a 100644 --- a/modules/structs/issue.go +++ b/modules/structs/issue.go @@ -5,8 +5,12 @@ package structs import ( + "fmt" "path" + "strings" "time" + + "gopkg.in/yaml.v3" ) // StateType issue state type @@ -143,14 +147,47 @@ type IssueFormField struct { // IssueTemplate represents an issue template for a repository // swagger:model type IssueTemplate struct { - Name string `json:"name" yaml:"name"` - Title string `json:"title" yaml:"title"` - About string `json:"about" yaml:"about"` // Using "description" in a template file is compatible - Labels []string `json:"labels" yaml:"labels"` - Ref string `json:"ref" yaml:"ref"` - Content string `json:"content" yaml:"-"` - Fields []*IssueFormField `json:"body" yaml:"body"` - FileName string `json:"file_name" yaml:"-"` + Name string `json:"name" yaml:"name"` + Title string `json:"title" yaml:"title"` + About string `json:"about" yaml:"about"` // Using "description" in a template file is compatible + Labels IssueTemplateLabels `json:"labels" yaml:"labels"` + Ref string `json:"ref" yaml:"ref"` + Content string `json:"content" yaml:"-"` + Fields []*IssueFormField `json:"body" yaml:"body"` + FileName string `json:"file_name" yaml:"-"` +} + +type IssueTemplateLabels []string + +func (l *IssueTemplateLabels) UnmarshalYAML(value *yaml.Node) error { + var labels []string + if value.IsZero() { + *l = labels + return nil + } + switch value.Kind { + case yaml.ScalarNode: + str := "" + err := value.Decode(&str) + if err != nil { + return err + } + for _, v := range strings.Split(str, ",") { + if v = strings.TrimSpace(v); v == "" { + continue + } + labels = append(labels, v) + } + *l = labels + return nil + case yaml.SequenceNode: + if err := value.Decode(&labels); err != nil { + return err + } + *l = labels + return nil + } + return fmt.Errorf("line %d: cannot unmarshal %s into IssueTemplateLabels", value.Line, value.ShortTag()) } // IssueTemplateType defines issue template type diff --git a/modules/structs/issue_test.go b/modules/structs/issue_test.go index 5312585d0f..72b40f7cf2 100644 --- a/modules/structs/issue_test.go +++ b/modules/structs/issue_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" ) func TestIssueTemplate_Type(t *testing.T) { @@ -41,3 +42,65 @@ func TestIssueTemplate_Type(t *testing.T) { }) } } + +func TestIssueTemplateLabels_UnmarshalYAML(t *testing.T) { + tests := []struct { + name string + content string + tmpl *IssueTemplate + want *IssueTemplate + wantErr string + }{ + { + name: "array", + content: `labels: ["a", "b", "c"]`, + tmpl: &IssueTemplate{ + Labels: []string{"should_be_overwrote"}, + }, + want: &IssueTemplate{ + Labels: []string{"a", "b", "c"}, + }, + }, + { + name: "string", + content: `labels: "a,b,c"`, + tmpl: &IssueTemplate{ + Labels: []string{"should_be_overwrote"}, + }, + want: &IssueTemplate{ + Labels: []string{"a", "b", "c"}, + }, + }, + { + name: "empty", + content: `labels:`, + tmpl: &IssueTemplate{ + Labels: []string{"should_be_overwrote"}, + }, + want: &IssueTemplate{ + Labels: nil, + }, + }, + { + name: "error", + content: ` +labels: + a: aa + b: bb +`, + tmpl: &IssueTemplate{}, + wantErr: "line 3: cannot unmarshal !!map into IssueTemplateLabels", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := yaml.Unmarshal([]byte(tt.content), tt.tmpl) + if tt.wantErr != "" { + assert.EqualError(t, err, tt.wantErr) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.want, tt.tmpl) + } + }) + } +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index fe3185ea77..ddafc146a1 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -16818,11 +16818,7 @@ "x-go-name": "FileName" }, "labels": { - "type": "array", - "items": { - "type": "string" - }, - "x-go-name": "Labels" + "$ref": "#/definitions/IssueTemplateLabels" }, "name": { "type": "string", @@ -16839,6 +16835,13 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "IssueTemplateLabels": { + "type": "array", + "items": { + "type": "string" + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "Label": { "description": "Label a label to an issue or a pr", "type": "object", From 32db62515f2e2109dd4f2d7136e4005d20d0def4 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Sun, 20 Nov 2022 15:08:38 +0100 Subject: [PATCH 050/149] Add package registry cleanup rules (#21658) Fixes #20514 Fixes #20766 Fixes #20631 This PR adds Cleanup Rules for the package registry. This allows to delete unneeded packages automatically. Cleanup rules can be set up from the user or org settings. Please have a look at the documentation because I'm not a native english speaker. Rule Form ![grafik](https://user-images.githubusercontent.com/1666336/199330792-c13918a6-e196-4e71-9f53-18554515edca.png) Rule List ![grafik](https://user-images.githubusercontent.com/1666336/199331261-5f6878e8-a80c-4985-800d-ebb3524b1a8d.png) Rule Preview ![grafik](https://user-images.githubusercontent.com/1666336/199330917-c95e4017-cf64-4142-a3e4-af18c4f127c3.png) Co-authored-by: Lunny Xiao --- docs/content/doc/packages/storage.en-us.md | 84 +++++++ models/migrations/migrations.go | 2 + models/migrations/v1_19/v234.go | 29 +++ models/packages/package.go | 15 ++ models/packages/package_cleanup_rule.go | 110 +++++++++ models/packages/package_version.go | 9 + options/locale/locale_en-US.ini | 23 ++ routers/web/org/setting_packages.go | 87 +++++++ routers/web/shared/packages/packages.go | 226 ++++++++++++++++++ routers/web/user/setting/packages.go | 80 +++++++ routers/web/web.go | 48 +++- services/forms/package_form.go | 31 +++ services/packages/container/cleanup.go | 35 +-- services/packages/container/common.go | 36 +++ services/packages/packages.go | 71 +++++- templates/org/settings/navbar.tmpl | 5 + templates/org/settings/packages.tmpl | 14 ++ .../settings/packages_cleanup_rules_edit.tmpl | 14 ++ .../packages_cleanup_rules_preview.tmpl | 13 + .../package/shared/cleanup_rules/edit.tmpl | 73 ++++++ .../package/shared/cleanup_rules/list.tmpl | 34 +++ .../package/shared/cleanup_rules/preview.tmpl | 34 +++ templates/user/settings/navbar.tmpl | 5 + templates/user/settings/packages.tmpl | 9 + .../settings/packages_cleanup_rules_edit.tmpl | 9 + .../packages_cleanup_rules_preview.tmpl | 8 + tests/integration/api_packages_test.go | 175 +++++++++++++- 27 files changed, 1243 insertions(+), 36 deletions(-) create mode 100644 docs/content/doc/packages/storage.en-us.md create mode 100644 models/migrations/v1_19/v234.go create mode 100644 models/packages/package_cleanup_rule.go create mode 100644 routers/web/org/setting_packages.go create mode 100644 routers/web/shared/packages/packages.go create mode 100644 routers/web/user/setting/packages.go create mode 100644 services/forms/package_form.go create mode 100644 services/packages/container/common.go create mode 100644 templates/org/settings/packages.tmpl create mode 100644 templates/org/settings/packages_cleanup_rules_edit.tmpl create mode 100644 templates/org/settings/packages_cleanup_rules_preview.tmpl create mode 100644 templates/package/shared/cleanup_rules/edit.tmpl create mode 100644 templates/package/shared/cleanup_rules/list.tmpl create mode 100644 templates/package/shared/cleanup_rules/preview.tmpl create mode 100644 templates/user/settings/packages.tmpl create mode 100644 templates/user/settings/packages_cleanup_rules_edit.tmpl create mode 100644 templates/user/settings/packages_cleanup_rules_preview.tmpl diff --git a/docs/content/doc/packages/storage.en-us.md b/docs/content/doc/packages/storage.en-us.md new file mode 100644 index 0000000000..c922496a99 --- /dev/null +++ b/docs/content/doc/packages/storage.en-us.md @@ -0,0 +1,84 @@ +--- +date: "2022-11-01T00:00:00+00:00" +title: "Storage" +slug: "packages/storage" +draft: false +toc: false +menu: + sidebar: + parent: "packages" + name: "storage" + weight: 5 + identifier: "storage" +--- + +# Storage + +This document describes the storage of the package registry and how it can be managed. + +**Table of Contents** + +{{< toc >}} + +## Deduplication + +The package registry has a build-in deduplication of uploaded blobs. +If two identical files are uploaded only one blob is saved on the filesystem. +This ensures no space is wasted for duplicated files. + +If two packages are uploaded with identical files, both packages will display the same size but on the filesystem they require only half of the size. +Whenever a package gets deleted only the references to the underlaying blobs are removed. +The blobs get not removed at this moment, so they still require space on the filesystem. +When a new package gets uploaded the existing blobs may get referenced again. + +These unreferenced blobs get deleted by a [clean up job]({{< relref "doc/advanced/config-cheat-sheet.en-us.md#cron---cleanup-expired-packages-croncleanup_packages" >}}). +The config setting `OLDER_THAN` configures how long unreferenced blobs are kept before they get deleted. + +## Cleanup Rules + +Package registries can become large over time without cleanup. +It's recommended to delete unnecessary packages and set up cleanup rules to automatically manage the package registry usage. +Every package owner (user or organization) manages the cleanup rules which are applied to their packages. + +|Setting|Description| +|-|-| +|Enabled|Turn the cleanup rule on or off.| +|Type|Every rule manages a specific package type.| +|Apply pattern to full package name|If enabled, the patterns below are applied to the full package name (`package/version`). Otherwise only the version (`version`) is used.| +|Keep the most recent|How many versions to *always* keep for each package.| +|Keep versions matching|The regex pattern that determines which versions to keep. An empty pattern keeps no version while `.+` keeps all versions. The container registry will always keep the `latest` version even if not configured.| +|Remove versions older than|Remove only versions older than the selected days.| +|Remove versions matching|The regex pattern that determines which versions to remove. An empty pattern or `.+` leads to the removal of every package if no other setting tells otherwise.| + +Every cleanup rule can show a preview of the affected packages. +This can be used to check if the cleanup rules is proper configured. + +### Regex examples + +Regex patterns are automatically surrounded with `\A` and `\z` anchors. +Do not include any `\A`, `\z`, `^` or `$` token in the regex patterns as they are not necessary. +The patterns are case-insensitive which matches the behaviour of the package registry in Gitea. + +|Pattern|Description| +|-|-| +|`.*`|Match every possible version.| +|`v.+`|Match versions that start with `v`.| +|`release`|Match only the version `release`.| +|`release.*`|Match versions that are either named or start with `release`.| +|`.+-temp-.+`|Match versions that contain `-temp-`.| +|`v.+\|release`|Match versions that either start with `v` or are named `release`.| +|`package/v.+\|other/release`|Match versions of the package `package` that start with `v` or the version `release` of the package `other`. This needs the setting *Apply pattern to full package name* enabled.| + +### How the cleanup rules work + +The cleanup rules are part of the [clean up job]({{< relref "doc/advanced/config-cheat-sheet.en-us.md#cron---cleanup-expired-packages-croncleanup_packages" >}}) and run periodicly. + +The cleanup rule: + +1. Collects all packages of the package type for the owners registry. +1. For every package it collects all versions. +1. Excludes from the list the # versions based on the *Keep the most recent* value. +1. Excludes from the list any versions matching the *Keep versions matching* value. +1. Excludes from the list the versions more recent than the *Remove versions older than* value. +1. Excludes from the list any versions not matching the *Remove versions matching* value. +1. Deletes the remaining versions. diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 6ef4ef5617..c48fc8d9a8 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -439,6 +439,8 @@ var migrations = []Migration{ NewMigration("Alter package_version.metadata_json to LONGTEXT", v1_19.AlterPackageVersionMetadataToLongText), // v233 -> v234 NewMigration("Add header_authorization_encrypted column to webhook table", v1_19.AddHeaderAuthorizationEncryptedColWebhook), + // v234 -> v235 + NewMigration("Add package cleanup rule table", v1_19.CreatePackageCleanupRuleTable), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_19/v234.go b/models/migrations/v1_19/v234.go new file mode 100644 index 0000000000..9d609c58d3 --- /dev/null +++ b/models/migrations/v1_19/v234.go @@ -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 v1_19 //nolint + +import ( + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/xorm" +) + +func CreatePackageCleanupRuleTable(x *xorm.Engine) error { + type PackageCleanupRule struct { + ID int64 `xorm:"pk autoincr"` + Enabled bool `xorm:"INDEX NOT NULL DEFAULT false"` + OwnerID int64 `xorm:"UNIQUE(s) INDEX NOT NULL DEFAULT 0"` + Type string `xorm:"UNIQUE(s) INDEX NOT NULL"` + KeepCount int `xorm:"NOT NULL DEFAULT 0"` + KeepPattern string `xorm:"NOT NULL DEFAULT ''"` + RemoveDays int `xorm:"NOT NULL DEFAULT 0"` + RemovePattern string `xorm:"NOT NULL DEFAULT ''"` + MatchFullName bool `xorm:"NOT NULL DEFAULT false"` + CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL DEFAULT 0"` + UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL DEFAULT 0"` + } + + return x.Sync2(new(PackageCleanupRule)) +} diff --git a/models/packages/package.go b/models/packages/package.go index e39a7c4e41..cea04a0957 100644 --- a/models/packages/package.go +++ b/models/packages/package.go @@ -45,6 +45,21 @@ const ( TypeVagrant Type = "vagrant" ) +var TypeList = []Type{ + TypeComposer, + TypeConan, + TypeContainer, + TypeGeneric, + TypeHelm, + TypeMaven, + TypeNpm, + TypeNuGet, + TypePub, + TypePyPI, + TypeRubyGems, + TypeVagrant, +} + // Name gets the name of the package type func (pt Type) Name() string { switch pt { diff --git a/models/packages/package_cleanup_rule.go b/models/packages/package_cleanup_rule.go new file mode 100644 index 0000000000..ab45226cf1 --- /dev/null +++ b/models/packages/package_cleanup_rule.go @@ -0,0 +1,110 @@ +// 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 packages + +import ( + "context" + "errors" + "fmt" + "regexp" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/builder" +) + +var ErrPackageCleanupRuleNotExist = errors.New("Package blob does not exist") + +func init() { + db.RegisterModel(new(PackageCleanupRule)) +} + +// PackageCleanupRule represents a rule which describes when to clean up package versions +type PackageCleanupRule struct { + ID int64 `xorm:"pk autoincr"` + Enabled bool `xorm:"INDEX NOT NULL DEFAULT false"` + OwnerID int64 `xorm:"UNIQUE(s) INDEX NOT NULL DEFAULT 0"` + Type Type `xorm:"UNIQUE(s) INDEX NOT NULL"` + KeepCount int `xorm:"NOT NULL DEFAULT 0"` + KeepPattern string `xorm:"NOT NULL DEFAULT ''"` + KeepPatternMatcher *regexp.Regexp `xorm:"-"` + RemoveDays int `xorm:"NOT NULL DEFAULT 0"` + RemovePattern string `xorm:"NOT NULL DEFAULT ''"` + RemovePatternMatcher *regexp.Regexp `xorm:"-"` + MatchFullName bool `xorm:"NOT NULL DEFAULT false"` + CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL DEFAULT 0"` + UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL DEFAULT 0"` +} + +func (pcr *PackageCleanupRule) CompiledPattern() error { + if pcr.KeepPatternMatcher != nil || pcr.RemovePatternMatcher != nil { + return nil + } + + if pcr.KeepPattern != "" { + var err error + pcr.KeepPatternMatcher, err = regexp.Compile(fmt.Sprintf(`(?i)\A%s\z`, pcr.KeepPattern)) + if err != nil { + return err + } + } + + if pcr.RemovePattern != "" { + var err error + pcr.RemovePatternMatcher, err = regexp.Compile(fmt.Sprintf(`(?i)\A%s\z`, pcr.RemovePattern)) + if err != nil { + return err + } + } + + return nil +} + +func InsertCleanupRule(ctx context.Context, pcr *PackageCleanupRule) (*PackageCleanupRule, error) { + return pcr, db.Insert(ctx, pcr) +} + +func GetCleanupRuleByID(ctx context.Context, id int64) (*PackageCleanupRule, error) { + pcr := &PackageCleanupRule{} + + has, err := db.GetEngine(ctx).ID(id).Get(pcr) + if err != nil { + return nil, err + } + if !has { + return nil, ErrPackageCleanupRuleNotExist + } + return pcr, nil +} + +func UpdateCleanupRule(ctx context.Context, pcr *PackageCleanupRule) error { + _, err := db.GetEngine(ctx).ID(pcr.ID).AllCols().Update(pcr) + return err +} + +func GetCleanupRulesByOwner(ctx context.Context, ownerID int64) ([]*PackageCleanupRule, error) { + pcrs := make([]*PackageCleanupRule, 0, 10) + return pcrs, db.GetEngine(ctx).Where("owner_id = ?", ownerID).Find(&pcrs) +} + +func DeleteCleanupRuleByID(ctx context.Context, ruleID int64) error { + _, err := db.GetEngine(ctx).ID(ruleID).Delete(&PackageCleanupRule{}) + return err +} + +func HasOwnerCleanupRuleForPackageType(ctx context.Context, ownerID int64, packageType Type) (bool, error) { + return db.GetEngine(ctx). + Where("owner_id = ? AND type = ?", ownerID, packageType). + Exist(&PackageCleanupRule{}) +} + +func IterateEnabledCleanupRules(ctx context.Context, callback func(context.Context, *PackageCleanupRule) error) error { + return db.Iterate( + ctx, + builder.Eq{"enabled": true}, + callback, + ) +} diff --git a/models/packages/package_version.go b/models/packages/package_version.go index 48c6aa7d60..6ee362502f 100644 --- a/models/packages/package_version.go +++ b/models/packages/package_version.go @@ -320,6 +320,15 @@ func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*P return pvs, count, err } +// ExistVersion checks if a version matching the search options exist +func ExistVersion(ctx context.Context, opts *PackageSearchOptions) (bool, error) { + return db.GetEngine(ctx). + Where(opts.toConds()). + Table("package_version"). + Join("INNER", "package", "package.id = package_version.package_id"). + Exist(new(PackageVersion)) +} + // CountVersions counts all versions of packages matching the search options func CountVersions(ctx context.Context, opts *PackageSearchOptions) (int64, error) { return db.GetEngine(ctx). diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index eb2a1c86db..ce93e92d34 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -86,6 +86,9 @@ remove = Remove remove_all = Remove All edit = Edit +enabled = Enabled +disabled = Disabled + copy = Copy copy_url = Copy URL copy_content = Copy content @@ -3186,3 +3189,23 @@ settings.delete.description = Deleting a package is permanent and cannot be undo settings.delete.notice = You are about to delete %s (%s). This operation is irreversible, are you sure? settings.delete.success = The package has been deleted. settings.delete.error = Failed to delete the package. +owner.settings.cleanuprules.title = Manage Cleanup Rules +owner.settings.cleanuprules.add = Add Cleanup Rule +owner.settings.cleanuprules.edit = Edit Cleanup Rule +owner.settings.cleanuprules.none = No cleanup rules available. Read the docs to learn more. +owner.settings.cleanuprules.preview = Cleanup Rule Preview +owner.settings.cleanuprules.preview.overview = %d packages are scheduled to be removed. +owner.settings.cleanuprules.preview.none = Cleanup rule does not match any packages. +owner.settings.cleanuprules.enabled = Enabled +owner.settings.cleanuprules.pattern_full_match = Apply pattern to full package name +owner.settings.cleanuprules.keep.title = Versions that match these rules are kept, even if they match a removal rule below. +owner.settings.cleanuprules.keep.count = Keep the most recent +owner.settings.cleanuprules.keep.count.1 = 1 version per package +owner.settings.cleanuprules.keep.count.n = %d versions per package +owner.settings.cleanuprules.keep.pattern = Keep versions matching +owner.settings.cleanuprules.keep.pattern.container = The latest version is always kept for Container packages. +owner.settings.cleanuprules.remove.title = Versions that match these rules are removed, unless a rule above says to keep them. +owner.settings.cleanuprules.remove.days = Remove versions older than +owner.settings.cleanuprules.remove.pattern = Remove versions matching +owner.settings.cleanuprules.success.update = Cleanup rule has been updated. +owner.settings.cleanuprules.success.delete = Cleanup rule has been deleted. diff --git a/routers/web/org/setting_packages.go b/routers/web/org/setting_packages.go new file mode 100644 index 0000000000..c7edf4a185 --- /dev/null +++ b/routers/web/org/setting_packages.go @@ -0,0 +1,87 @@ +// 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 org + +import ( + "fmt" + "net/http" + + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/setting" + shared "code.gitea.io/gitea/routers/web/shared/packages" +) + +const ( + tplSettingsPackages base.TplName = "org/settings/packages" + tplSettingsPackagesRuleEdit base.TplName = "org/settings/packages_cleanup_rules_edit" + tplSettingsPackagesRulePreview base.TplName = "org/settings/packages_cleanup_rules_preview" +) + +func Packages(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + shared.SetPackagesContext(ctx, ctx.ContextUser) + + ctx.HTML(http.StatusOK, tplSettingsPackages) +} + +func PackagesRuleAdd(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + shared.SetRuleAddContext(ctx) + + ctx.HTML(http.StatusOK, tplSettingsPackagesRuleEdit) +} + +func PackagesRuleEdit(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + shared.SetRuleEditContext(ctx, ctx.ContextUser) + + ctx.HTML(http.StatusOK, tplSettingsPackagesRuleEdit) +} + +func PackagesRuleAddPost(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + shared.PerformRuleAddPost( + ctx, + ctx.ContextUser, + fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name), + tplSettingsPackagesRuleEdit, + ) +} + +func PackagesRuleEditPost(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + shared.PerformRuleEditPost( + ctx, + ctx.ContextUser, + fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name), + tplSettingsPackagesRuleEdit, + ) +} + +func PackagesRulePreview(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + shared.SetRulePreviewContext(ctx, ctx.ContextUser) + + ctx.HTML(http.StatusOK, tplSettingsPackagesRulePreview) +} diff --git a/routers/web/shared/packages/packages.go b/routers/web/shared/packages/packages.go new file mode 100644 index 0000000000..5e934d707e --- /dev/null +++ b/routers/web/shared/packages/packages.go @@ -0,0 +1,226 @@ +// 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 packages + +import ( + "fmt" + "net/http" + "time" + + "code.gitea.io/gitea/models/db" + packages_model "code.gitea.io/gitea/models/packages" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/forms" + container_service "code.gitea.io/gitea/services/packages/container" +) + +func SetPackagesContext(ctx *context.Context, owner *user_model.User) { + pcrs, err := packages_model.GetCleanupRulesByOwner(ctx, owner.ID) + if err != nil { + ctx.ServerError("GetCleanupRulesByOwner", err) + return + } + + ctx.Data["CleanupRules"] = pcrs +} + +func SetRuleAddContext(ctx *context.Context) { + setRuleEditContext(ctx, nil) +} + +func SetRuleEditContext(ctx *context.Context, owner *user_model.User) { + pcr := getCleanupRuleByContext(ctx, owner) + if pcr == nil { + return + } + + setRuleEditContext(ctx, pcr) +} + +func setRuleEditContext(ctx *context.Context, pcr *packages_model.PackageCleanupRule) { + ctx.Data["IsEditRule"] = pcr != nil + + if pcr == nil { + pcr = &packages_model.PackageCleanupRule{} + } + ctx.Data["CleanupRule"] = pcr + ctx.Data["AvailableTypes"] = packages_model.TypeList +} + +func PerformRuleAddPost(ctx *context.Context, owner *user_model.User, redirectURL string, template base.TplName) { + performRuleEditPost(ctx, owner, nil, redirectURL, template) +} + +func PerformRuleEditPost(ctx *context.Context, owner *user_model.User, redirectURL string, template base.TplName) { + pcr := getCleanupRuleByContext(ctx, owner) + if pcr == nil { + return + } + + form := web.GetForm(ctx).(*forms.PackageCleanupRuleForm) + + if form.Action == "remove" { + if err := packages_model.DeleteCleanupRuleByID(ctx, pcr.ID); err != nil { + ctx.ServerError("DeleteCleanupRuleByID", err) + return + } + + ctx.Flash.Success(ctx.Tr("packages.owner.settings.cleanuprules.success.delete")) + ctx.Redirect(redirectURL) + } else { + performRuleEditPost(ctx, owner, pcr, redirectURL, template) + } +} + +func performRuleEditPost(ctx *context.Context, owner *user_model.User, pcr *packages_model.PackageCleanupRule, redirectURL string, template base.TplName) { + isEditRule := pcr != nil + + if pcr == nil { + pcr = &packages_model.PackageCleanupRule{} + } + + form := web.GetForm(ctx).(*forms.PackageCleanupRuleForm) + + pcr.Enabled = form.Enabled + pcr.OwnerID = owner.ID + pcr.KeepCount = form.KeepCount + pcr.KeepPattern = form.KeepPattern + pcr.RemoveDays = form.RemoveDays + pcr.RemovePattern = form.RemovePattern + pcr.MatchFullName = form.MatchFullName + + ctx.Data["IsEditRule"] = isEditRule + ctx.Data["CleanupRule"] = pcr + ctx.Data["AvailableTypes"] = packages_model.TypeList + + if ctx.HasError() { + ctx.HTML(http.StatusOK, template) + return + } + + if isEditRule { + if err := packages_model.UpdateCleanupRule(ctx, pcr); err != nil { + ctx.ServerError("UpdateCleanupRule", err) + return + } + } else { + pcr.Type = packages_model.Type(form.Type) + + if has, err := packages_model.HasOwnerCleanupRuleForPackageType(ctx, owner.ID, pcr.Type); err != nil { + ctx.ServerError("HasOwnerCleanupRuleForPackageType", err) + return + } else if has { + ctx.Data["Err_Type"] = true + ctx.HTML(http.StatusOK, template) + return + } + + var err error + if pcr, err = packages_model.InsertCleanupRule(ctx, pcr); err != nil { + ctx.ServerError("InsertCleanupRule", err) + return + } + } + + ctx.Flash.Success(ctx.Tr("packages.owner.settings.cleanuprules.success.update")) + ctx.Redirect(fmt.Sprintf("%s/rules/%d", redirectURL, pcr.ID)) +} + +func SetRulePreviewContext(ctx *context.Context, owner *user_model.User) { + pcr := getCleanupRuleByContext(ctx, owner) + if pcr == nil { + return + } + + if err := pcr.CompiledPattern(); err != nil { + ctx.ServerError("CompiledPattern", err) + return + } + + olderThan := time.Now().AddDate(0, 0, -pcr.RemoveDays) + + packages, err := packages_model.GetPackagesByType(ctx, pcr.OwnerID, pcr.Type) + if err != nil { + ctx.ServerError("GetPackagesByType", err) + return + } + + versionsToRemove := make([]*packages_model.PackageDescriptor, 0, 10) + + for _, p := range packages { + pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{ + PackageID: p.ID, + IsInternal: util.OptionalBoolFalse, + Sort: packages_model.SortCreatedDesc, + Paginator: db.NewAbsoluteListOptions(pcr.KeepCount, 200), + }) + if err != nil { + ctx.ServerError("SearchVersions", err) + return + } + for _, pv := range pvs { + if skip, err := container_service.ShouldBeSkipped(ctx, pcr, p, pv); err != nil { + ctx.ServerError("ShouldBeSkipped", err) + return + } else if skip { + continue + } + + toMatch := pv.LowerVersion + if pcr.MatchFullName { + toMatch = p.LowerName + "/" + pv.LowerVersion + } + + if pcr.KeepPatternMatcher != nil && pcr.KeepPatternMatcher.MatchString(toMatch) { + continue + } + if pv.CreatedUnix.AsLocalTime().After(olderThan) { + continue + } + if pcr.RemovePatternMatcher != nil && !pcr.RemovePatternMatcher.MatchString(toMatch) { + continue + } + + pd, err := packages_model.GetPackageDescriptor(ctx, pv) + if err != nil { + ctx.ServerError("GetPackageDescriptor", err) + return + } + versionsToRemove = append(versionsToRemove, pd) + } + } + + ctx.Data["CleanupRule"] = pcr + ctx.Data["VersionsToRemove"] = versionsToRemove +} + +func getCleanupRuleByContext(ctx *context.Context, owner *user_model.User) *packages_model.PackageCleanupRule { + id := ctx.FormInt64("id") + if id == 0 { + id = ctx.ParamsInt64("id") + } + + pcr, err := packages_model.GetCleanupRuleByID(ctx, id) + if err != nil { + if err == packages_model.ErrPackageCleanupRuleNotExist { + ctx.NotFound("", err) + } else { + ctx.ServerError("GetCleanupRuleByID", err) + } + return nil + } + + if pcr != nil && pcr.OwnerID == owner.ID { + return pcr + } + + ctx.NotFound("", fmt.Errorf("PackageCleanupRule[%v] not associated to owner %v", id, owner)) + + return nil +} diff --git a/routers/web/user/setting/packages.go b/routers/web/user/setting/packages.go new file mode 100644 index 0000000000..d44e904556 --- /dev/null +++ b/routers/web/user/setting/packages.go @@ -0,0 +1,80 @@ +// 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 setting + +import ( + "net/http" + + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/setting" + shared "code.gitea.io/gitea/routers/web/shared/packages" +) + +const ( + tplSettingsPackages base.TplName = "user/settings/packages" + tplSettingsPackagesRuleEdit base.TplName = "user/settings/packages_cleanup_rules_edit" + tplSettingsPackagesRulePreview base.TplName = "user/settings/packages_cleanup_rules_preview" +) + +func Packages(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsSettingsPackages"] = true + + shared.SetPackagesContext(ctx, ctx.Doer) + + ctx.HTML(http.StatusOK, tplSettingsPackages) +} + +func PackagesRuleAdd(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsSettingsPackages"] = true + + shared.SetRuleAddContext(ctx) + + ctx.HTML(http.StatusOK, tplSettingsPackagesRuleEdit) +} + +func PackagesRuleEdit(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsSettingsPackages"] = true + + shared.SetRuleEditContext(ctx, ctx.Doer) + + ctx.HTML(http.StatusOK, tplSettingsPackagesRuleEdit) +} + +func PackagesRuleAddPost(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("settings") + ctx.Data["PageIsSettingsPackages"] = true + + shared.PerformRuleAddPost( + ctx, + ctx.Doer, + setting.AppSubURL+"/user/settings/packages", + tplSettingsPackagesRuleEdit, + ) +} + +func PackagesRuleEditPost(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsSettingsPackages"] = true + + shared.PerformRuleEditPost( + ctx, + ctx.Doer, + setting.AppSubURL+"/user/settings/packages", + tplSettingsPackagesRuleEdit, + ) +} + +func PackagesRulePreview(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsSettingsPackages"] = true + + shared.SetRulePreviewContext(ctx, ctx.Doer) + + ctx.HTML(http.StatusOK, tplSettingsPackagesRulePreview) +} diff --git a/routers/web/web.go b/routers/web/web.go index 5fefbad88a..142f2384eb 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -303,6 +303,13 @@ func RegisterRoutes(m *web.Route) { } } + packagesEnabled := func(ctx *context.Context) { + if !setting.Packages.Enabled { + ctx.Error(http.StatusForbidden) + return + } + } + // FIXME: not all routes need go through same middleware. // Especially some AJAX requests, we can reduce middleware number to improve performance. // Routers. @@ -443,12 +450,27 @@ func RegisterRoutes(m *web.Route) { m.Combo("/keys").Get(user_setting.Keys). Post(bindIgnErr(forms.AddKeyForm{}), user_setting.KeysPost) m.Post("/keys/delete", user_setting.DeleteKey) + m.Group("/packages", func() { + m.Get("", user_setting.Packages) + m.Group("/rules", func() { + m.Group("/add", func() { + m.Get("", user_setting.PackagesRuleAdd) + m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), user_setting.PackagesRuleAddPost) + }) + m.Group("/{id}", func() { + m.Get("", user_setting.PackagesRuleEdit) + m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), user_setting.PackagesRuleEditPost) + m.Get("/preview", user_setting.PackagesRulePreview) + }) + }) + }, packagesEnabled) m.Get("/organization", user_setting.Organization) m.Get("/repos", user_setting.Repos) m.Post("/repos/unadopted", user_setting.AdoptOrDeleteRepository) }, reqSignIn, func(ctx *context.Context) { ctx.Data["PageIsUserSettings"] = true ctx.Data["AllThemes"] = setting.UI.Themes + ctx.Data["EnablePackages"] = setting.Packages.Enabled }) m.Group("/user", func() { @@ -526,12 +548,10 @@ func RegisterRoutes(m *web.Route) { m.Post("/delete", admin.DeleteRepo) }) - if setting.Packages.Enabled { - m.Group("/packages", func() { - m.Get("", admin.Packages) - m.Post("/delete", admin.DeletePackageVersion) - }) - } + m.Group("/packages", func() { + m.Get("", admin.Packages) + m.Post("/delete", admin.DeletePackageVersion) + }, packagesEnabled) m.Group("/hooks", func() { m.Get("", admin.DefaultOrSystemWebhooks) @@ -750,8 +770,24 @@ func RegisterRoutes(m *web.Route) { }) m.Route("/delete", "GET,POST", org.SettingsDelete) + + m.Group("/packages", func() { + m.Get("", org.Packages) + m.Group("/rules", func() { + m.Group("/add", func() { + m.Get("", org.PackagesRuleAdd) + m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), org.PackagesRuleAddPost) + }) + m.Group("/{id}", func() { + m.Get("", org.PackagesRuleEdit) + m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), org.PackagesRuleEditPost) + m.Get("/preview", org.PackagesRulePreview) + }) + }) + }, packagesEnabled) }, func(ctx *context.Context) { ctx.Data["EnableOAuth2"] = setting.OAuth2.Enable + ctx.Data["EnablePackages"] = setting.Packages.Enabled }) }, context.OrgAssignment(true, true)) }, reqSignIn) diff --git a/services/forms/package_form.go b/services/forms/package_form.go new file mode 100644 index 0000000000..6c3ff52a9c --- /dev/null +++ b/services/forms/package_form.go @@ -0,0 +1,31 @@ +// 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 forms + +import ( + "net/http" + + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/web/middleware" + + "gitea.com/go-chi/binding" +) + +type PackageCleanupRuleForm struct { + ID int64 + Enabled bool + Type string `binding:"Required;In(composer,conan,container,generic,helm,maven,npm,nuget,pub,pypi,rubygems,vagrant)"` + KeepCount int `binding:"In(0,1,5,10,25,50,100)"` + KeepPattern string `binding:"RegexPattern"` + RemoveDays int `binding:"In(0,7,14,30,60,90,180)"` + RemovePattern string `binding:"RegexPattern"` + MatchFullName bool + Action string `binding:"Required;In(save,remove)"` +} + +func (f *PackageCleanupRuleForm) Validate(req *http.Request, errs binding.Errors) binding.Errors { + ctx := context.GetContext(req) + return middleware.Validate(errs, ctx.Data, f, ctx.Locale) +} diff --git a/services/packages/container/cleanup.go b/services/packages/container/cleanup.go index d23a481f27..e3d414d45c 100644 --- a/services/packages/container/cleanup.go +++ b/services/packages/container/cleanup.go @@ -6,13 +6,12 @@ package container import ( "context" - "strings" "time" packages_model "code.gitea.io/gitea/models/packages" container_model "code.gitea.io/gitea/models/packages/container" - user_model "code.gitea.io/gitea/models/user" container_module "code.gitea.io/gitea/modules/packages/container" + "code.gitea.io/gitea/modules/packages/container/oci" "code.gitea.io/gitea/modules/util" ) @@ -82,24 +81,30 @@ func cleanupExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) e return nil } -// UpdateRepositoryNames updates the repository name property for all packages of the specific owner -func UpdateRepositoryNames(ctx context.Context, owner *user_model.User, newOwnerName string) error { - ps, err := packages_model.GetPackagesByType(ctx, owner.ID, packages_model.TypeContainer) - if err != nil { - return err +func ShouldBeSkipped(ctx context.Context, pcr *packages_model.PackageCleanupRule, p *packages_model.Package, pv *packages_model.PackageVersion) (bool, error) { + // Always skip the "latest" tag + if pv.LowerVersion == "latest" { + return true, nil } - newOwnerName = strings.ToLower(newOwnerName) - - for _, p := range ps { - if err := packages_model.DeletePropertyByName(ctx, packages_model.PropertyTypePackage, p.ID, container_module.PropertyRepository); err != nil { - return err + // Check if the version is a digest (or untagged) + if oci.Digest(pv.LowerVersion).Validate() { + // Check if there is another manifest referencing this version + has, err := packages_model.ExistVersion(ctx, &packages_model.PackageSearchOptions{ + PackageID: p.ID, + Properties: map[string]string{ + container_module.PropertyManifestReference: pv.LowerVersion, + }, + }) + if err != nil { + return false, err } - if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypePackage, p.ID, container_module.PropertyRepository, newOwnerName+"/"+p.LowerName); err != nil { - return err + // Skip it if the version is referenced + if has { + return true, nil } } - return nil + return false, nil } diff --git a/services/packages/container/common.go b/services/packages/container/common.go new file mode 100644 index 0000000000..40d8914a01 --- /dev/null +++ b/services/packages/container/common.go @@ -0,0 +1,36 @@ +// 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 container + +import ( + "context" + "strings" + + packages_model "code.gitea.io/gitea/models/packages" + user_model "code.gitea.io/gitea/models/user" + container_module "code.gitea.io/gitea/modules/packages/container" +) + +// UpdateRepositoryNames updates the repository name property for all packages of the specific owner +func UpdateRepositoryNames(ctx context.Context, owner *user_model.User, newOwnerName string) error { + ps, err := packages_model.GetPackagesByType(ctx, owner.ID, packages_model.TypeContainer) + if err != nil { + return err + } + + newOwnerName = strings.ToLower(newOwnerName) + + for _, p := range ps { + if err := packages_model.DeletePropertyByName(ctx, packages_model.PropertyTypePackage, p.ID, container_module.PropertyRepository); err != nil { + return err + } + + if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypePackage, p.ID, container_module.PropertyRepository, newOwnerName+"/"+p.LowerName); err != nil { + return err + } + } + + return nil +} diff --git a/services/packages/packages.go b/services/packages/packages.go index 76fdd02bf2..7343ffc530 100644 --- a/services/packages/packages.go +++ b/services/packages/packages.go @@ -443,13 +443,80 @@ func DeletePackageFile(ctx context.Context, pf *packages_model.PackageFile) erro } // Cleanup removes expired package data -func Cleanup(unused context.Context, olderThan time.Duration) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func Cleanup(taskCtx context.Context, olderThan time.Duration) error { + ctx, committer, err := db.TxContext(taskCtx) if err != nil { return err } defer committer.Close() + err = packages_model.IterateEnabledCleanupRules(ctx, func(ctx context.Context, pcr *packages_model.PackageCleanupRule) error { + select { + case <-taskCtx.Done(): + return db.ErrCancelledf("While processing package cleanup rules") + default: + } + + if err := pcr.CompiledPattern(); err != nil { + return fmt.Errorf("CleanupRule [%d]: CompilePattern failed: %w", pcr.ID, err) + } + + olderThan := time.Now().AddDate(0, 0, -pcr.RemoveDays) + + packages, err := packages_model.GetPackagesByType(ctx, pcr.OwnerID, pcr.Type) + if err != nil { + return fmt.Errorf("CleanupRule [%d]: GetPackagesByType failed: %w", pcr.ID, err) + } + + for _, p := range packages { + pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{ + PackageID: p.ID, + IsInternal: util.OptionalBoolFalse, + Sort: packages_model.SortCreatedDesc, + Paginator: db.NewAbsoluteListOptions(pcr.KeepCount, 200), + }) + if err != nil { + return fmt.Errorf("CleanupRule [%d]: SearchVersions failed: %w", pcr.ID, err) + } + for _, pv := range pvs { + if skip, err := container_service.ShouldBeSkipped(ctx, pcr, p, pv); err != nil { + return fmt.Errorf("CleanupRule [%d]: container.ShouldBeSkipped failed: %w", pcr.ID, err) + } else if skip { + log.Debug("Rule[%d]: keep '%s/%s' (container)", pcr.ID, p.Name, pv.Version) + continue + } + + toMatch := pv.LowerVersion + if pcr.MatchFullName { + toMatch = p.LowerName + "/" + pv.LowerVersion + } + + if pcr.KeepPatternMatcher != nil && pcr.KeepPatternMatcher.MatchString(toMatch) { + log.Debug("Rule[%d]: keep '%s/%s' (keep pattern)", pcr.ID, p.Name, pv.Version) + continue + } + if pv.CreatedUnix.AsLocalTime().After(olderThan) { + log.Debug("Rule[%d]: keep '%s/%s' (remove days)", pcr.ID, p.Name, pv.Version) + continue + } + if pcr.RemovePatternMatcher != nil && !pcr.RemovePatternMatcher.MatchString(toMatch) { + log.Debug("Rule[%d]: keep '%s/%s' (remove pattern)", pcr.ID, p.Name, pv.Version) + continue + } + + log.Debug("Rule[%d]: remove '%s/%s'", pcr.ID, p.Name, pv.Version) + + if err := DeletePackageVersionAndReferences(ctx, pv); err != nil { + return fmt.Errorf("CleanupRule [%d]: DeletePackageVersionAndReferences failed: %w", pcr.ID, err) + } + } + } + return nil + }) + if err != nil { + return err + } + if err := container_service.Cleanup(ctx, olderThan); err != nil { return err } diff --git a/templates/org/settings/navbar.tmpl b/templates/org/settings/navbar.tmpl index e7cbb87344..7df1c85903 100644 --- a/templates/org/settings/navbar.tmpl +++ b/templates/org/settings/navbar.tmpl @@ -17,6 +17,11 @@ {{.locale.Tr "settings.applications"}} {{end}} + {{if .EnablePackages}} + + {{.locale.Tr "packages.title"}} + + {{end}} {{.locale.Tr "org.settings.delete"}} diff --git a/templates/org/settings/packages.tmpl b/templates/org/settings/packages.tmpl new file mode 100644 index 0000000000..bb5d95e107 --- /dev/null +++ b/templates/org/settings/packages.tmpl @@ -0,0 +1,14 @@ +{{template "base/head" .}} +
+ {{template "org/header" .}} +
+
+ {{template "org/settings/navbar" .}} +
+ {{template "base/alert" .}} + {{template "package/shared/cleanup_rules/list" .}} +
+
+
+
+{{template "base/footer" .}} diff --git a/templates/org/settings/packages_cleanup_rules_edit.tmpl b/templates/org/settings/packages_cleanup_rules_edit.tmpl new file mode 100644 index 0000000000..8c3725f4d7 --- /dev/null +++ b/templates/org/settings/packages_cleanup_rules_edit.tmpl @@ -0,0 +1,14 @@ +{{template "base/head" .}} +
+ {{template "org/header" .}} +
+
+ {{template "org/settings/navbar" .}} +
+ {{template "base/alert" .}} + {{template "package/shared/cleanup_rules/edit" .}} +
+
+
+
+{{template "base/footer" .}} diff --git a/templates/org/settings/packages_cleanup_rules_preview.tmpl b/templates/org/settings/packages_cleanup_rules_preview.tmpl new file mode 100644 index 0000000000..e0e4652c36 --- /dev/null +++ b/templates/org/settings/packages_cleanup_rules_preview.tmpl @@ -0,0 +1,13 @@ +{{template "base/head" .}} +
+ {{template "org/header" .}} +
+
+ {{template "org/settings/navbar" .}} +
+ {{template "package/shared/cleanup_rules/preview" .}} +
+
+
+
+{{template "base/footer" .}} diff --git a/templates/package/shared/cleanup_rules/edit.tmpl b/templates/package/shared/cleanup_rules/edit.tmpl new file mode 100644 index 0000000000..f8525afb70 --- /dev/null +++ b/templates/package/shared/cleanup_rules/edit.tmpl @@ -0,0 +1,73 @@ +

{{if .IsEditRule}}{{.locale.Tr "packages.owner.settings.cleanuprules.edit"}}{{else}}{{.locale.Tr "packages.owner.settings.cleanuprules.add"}}{{end}}

+
+
+ {{.CsrfTokenHtml}} + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+

{{.locale.Tr "packages.owner.settings.cleanuprules.keep.title"}}

+
+ + +
+
+ + +

{{.locale.Tr "packages.owner.settings.cleanuprules.keep.pattern.container" | Safe}}

+
+
+

{{.locale.Tr "packages.owner.settings.cleanuprules.remove.title"}}

+
+ + +
+
+ + +
+
+ {{if .IsEditRule}} + + + {{.locale.Tr "packages.owner.settings.cleanuprules.preview"}} + {{else}} + + {{end}} +
+
+
diff --git a/templates/package/shared/cleanup_rules/list.tmpl b/templates/package/shared/cleanup_rules/list.tmpl new file mode 100644 index 0000000000..09f95e4f4a --- /dev/null +++ b/templates/package/shared/cleanup_rules/list.tmpl @@ -0,0 +1,34 @@ +

+ {{.locale.Tr "packages.owner.settings.cleanuprules.title"}} + +

+
+
+ {{range .CleanupRules}} +
+ + {{svg .Type.SVGName 36}} +
+ {{.Type.Name}} +
{{if .Enabled}}{{$.locale.Tr "enabled"}}{{else}}{{$.locale.Tr "disabled"}}{{end}}
+ {{if .KeepCount}}
{{$.locale.Tr "packages.owner.settings.cleanuprules.keep.count"}}: {{if eq .KeepCount 1}}{{$.locale.Tr "packages.owner.settings.cleanuprules.keep.count.1"}}{{else}}{{$.locale.Tr "packages.owner.settings.cleanuprules.keep.count.n" .KeepCount}}{{end}}
{{end}} + {{if .KeepPattern}}
{{$.locale.Tr "packages.owner.settings.cleanuprules.keep.pattern"}}: {{EllipsisString .KeepPattern 100}}
{{end}} + {{if .RemoveDays}}
{{$.locale.Tr "packages.owner.settings.cleanuprules.remove.days"}}: {{$.locale.Tr "tool.days" .RemoveDays}}
{{end}} + {{if .RemovePattern}}
{{$.locale.Tr "packages.owner.settings.cleanuprules.remove.pattern"}}: {{EllipsisString .RemovePattern 100}}
{{end}} +
+
+ {{else}} +
{{.locale.Tr "packages.owner.settings.cleanuprules.none"}}
+ {{end}} +
+
diff --git a/templates/package/shared/cleanup_rules/preview.tmpl b/templates/package/shared/cleanup_rules/preview.tmpl new file mode 100644 index 0000000000..c59ad67f77 --- /dev/null +++ b/templates/package/shared/cleanup_rules/preview.tmpl @@ -0,0 +1,34 @@ +

{{.locale.Tr "packages.owner.settings.cleanuprules.preview"}}

+
+

{{.locale.Tr "packages.owner.settings.cleanuprules.preview.overview" (len .VersionsToRemove)}}

+
+
+ + + + + + + + + + + + + {{range .VersionsToRemove}} + + + + + + + + + {{else}} + + + + {{end}} + +
{{.locale.Tr "admin.packages.type"}}{{.locale.Tr "admin.packages.name"}}{{.locale.Tr "admin.packages.version"}}{{.locale.Tr "admin.packages.creator"}}{{.locale.Tr "admin.packages.size"}}{{.locale.Tr "admin.packages.published"}}
{{.Package.Type.Name}}{{.Package.Name}}{{.Version.Version}}{{.Creator.Name}}{{FileSize .CalculateBlobSize}}
{{.locale.Tr "packages.owner.settings.cleanuprules.preview.none"}}
+
diff --git a/templates/user/settings/navbar.tmpl b/templates/user/settings/navbar.tmpl index 01ae055d79..d17494fc04 100644 --- a/templates/user/settings/navbar.tmpl +++ b/templates/user/settings/navbar.tmpl @@ -18,6 +18,11 @@ {{.locale.Tr "settings.ssh_gpg_keys"}} + {{if .EnablePackages}} + + {{.locale.Tr "packages.title"}} + + {{end}} {{.locale.Tr "settings.organization"}} diff --git a/templates/user/settings/packages.tmpl b/templates/user/settings/packages.tmpl new file mode 100644 index 0000000000..2612313454 --- /dev/null +++ b/templates/user/settings/packages.tmpl @@ -0,0 +1,9 @@ +{{template "base/head" .}} +
+ {{template "user/settings/navbar" .}} +
+ {{template "base/alert" .}} + {{template "package/shared/cleanup_rules/list" .}} +
+
+{{template "base/footer" .}} diff --git a/templates/user/settings/packages_cleanup_rules_edit.tmpl b/templates/user/settings/packages_cleanup_rules_edit.tmpl new file mode 100644 index 0000000000..4cf642b7e1 --- /dev/null +++ b/templates/user/settings/packages_cleanup_rules_edit.tmpl @@ -0,0 +1,9 @@ +{{template "base/head" .}} +
+ {{template "user/settings/navbar" .}} +
+ {{template "base/alert" .}} + {{template "package/shared/cleanup_rules/edit" .}} +
+
+{{template "base/footer" .}} diff --git a/templates/user/settings/packages_cleanup_rules_preview.tmpl b/templates/user/settings/packages_cleanup_rules_preview.tmpl new file mode 100644 index 0000000000..20041f9a42 --- /dev/null +++ b/templates/user/settings/packages_cleanup_rules_preview.tmpl @@ -0,0 +1,8 @@ +{{template "base/head" .}} +
+ {{template "user/settings/navbar" .}} +
+ {{template "package/shared/cleanup_rules/preview" .}} +
+
+{{template "base/footer" .}} diff --git a/tests/integration/api_packages_test.go b/tests/integration/api_packages_test.go index 815685ea79..8efb70848b 100644 --- a/tests/integration/api_packages_test.go +++ b/tests/integration/api_packages_test.go @@ -203,22 +203,171 @@ func TestPackageQuota(t *testing.T) { func TestPackageCleanup(t *testing.T) { defer tests.PrepareTestEnv(t)() - time.Sleep(time.Second) + duration, _ := time.ParseDuration("-1h") - pbs, err := packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, time.Duration(0)) - assert.NoError(t, err) - assert.NotEmpty(t, pbs) + t.Run("Common", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() - _, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, 2, packages_model.TypeContainer, "test", container_model.UploadVersion) - assert.NoError(t, err) + pbs, err := packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, duration) + assert.NoError(t, err) + assert.NotEmpty(t, pbs) - err = packages_service.Cleanup(nil, time.Duration(0)) - assert.NoError(t, err) + _, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, 2, packages_model.TypeContainer, "test", container_model.UploadVersion) + assert.NoError(t, err) - pbs, err = packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, time.Duration(0)) - assert.NoError(t, err) - assert.Empty(t, pbs) + err = packages_service.Cleanup(db.DefaultContext, duration) + assert.NoError(t, err) - _, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, 2, packages_model.TypeContainer, "test", container_model.UploadVersion) - assert.ErrorIs(t, err, packages_model.ErrPackageNotExist) + pbs, err = packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, duration) + assert.NoError(t, err) + assert.Empty(t, pbs) + + _, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, 2, packages_model.TypeContainer, "test", container_model.UploadVersion) + assert.ErrorIs(t, err, packages_model.ErrPackageNotExist) + }) + + t.Run("CleanupRules", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + type version struct { + Version string + ShouldExist bool + Created int64 + } + + cases := []struct { + Name string + Versions []version + Rule *packages_model.PackageCleanupRule + }{ + { + Name: "Disabled", + Versions: []version{ + {Version: "keep", ShouldExist: true}, + }, + Rule: &packages_model.PackageCleanupRule{ + Enabled: false, + }, + }, + { + Name: "KeepCount", + Versions: []version{ + {Version: "keep", ShouldExist: true}, + {Version: "v1.0", ShouldExist: true}, + {Version: "test-3", ShouldExist: false, Created: 1}, + {Version: "test-4", ShouldExist: false, Created: 1}, + }, + Rule: &packages_model.PackageCleanupRule{ + Enabled: true, + KeepCount: 2, + }, + }, + { + Name: "KeepPattern", + Versions: []version{ + {Version: "keep", ShouldExist: true}, + {Version: "v1.0", ShouldExist: false}, + }, + Rule: &packages_model.PackageCleanupRule{ + Enabled: true, + KeepPattern: "k.+p", + }, + }, + { + Name: "RemoveDays", + Versions: []version{ + {Version: "keep", ShouldExist: true}, + {Version: "v1.0", ShouldExist: false, Created: 1}, + }, + Rule: &packages_model.PackageCleanupRule{ + Enabled: true, + RemoveDays: 60, + }, + }, + { + Name: "RemovePattern", + Versions: []version{ + {Version: "test", ShouldExist: true}, + {Version: "test-3", ShouldExist: false}, + {Version: "test-4", ShouldExist: false}, + }, + Rule: &packages_model.PackageCleanupRule{ + Enabled: true, + RemovePattern: `t[e]+st-\d+`, + }, + }, + { + Name: "MatchFullName", + Versions: []version{ + {Version: "keep", ShouldExist: true}, + {Version: "test", ShouldExist: false}, + }, + Rule: &packages_model.PackageCleanupRule{ + Enabled: true, + RemovePattern: `package/test|different/keep`, + MatchFullName: true, + }, + }, + { + Name: "Mixed", + Versions: []version{ + {Version: "keep", ShouldExist: true, Created: time.Now().Add(time.Duration(10000)).Unix()}, + {Version: "dummy", ShouldExist: true, Created: 1}, + {Version: "test-3", ShouldExist: true}, + {Version: "test-4", ShouldExist: false, Created: 1}, + }, + Rule: &packages_model.PackageCleanupRule{ + Enabled: true, + KeepCount: 1, + KeepPattern: `dummy`, + RemoveDays: 7, + RemovePattern: `t[e]+st-\d+`, + }, + }, + } + + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + for _, v := range c.Versions { + url := fmt.Sprintf("/api/packages/%s/generic/package/%s/file.bin", user.Name, v.Version) + req := NewRequestWithBody(t, "PUT", url, bytes.NewReader([]byte{1})) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusCreated) + + if v.Created != 0 { + pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeGeneric, "package", v.Version) + assert.NoError(t, err) + _, err = db.GetEngine(db.DefaultContext).Exec("UPDATE package_version SET created_unix = ? WHERE id = ?", v.Created, pv.ID) + assert.NoError(t, err) + } + } + + c.Rule.OwnerID = user.ID + c.Rule.Type = packages_model.TypeGeneric + + pcr, err := packages_model.InsertCleanupRule(db.DefaultContext, c.Rule) + assert.NoError(t, err) + + err = packages_service.Cleanup(db.DefaultContext, duration) + assert.NoError(t, err) + + for _, v := range c.Versions { + pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeGeneric, "package", v.Version) + if v.ShouldExist { + assert.NoError(t, err) + err = packages_service.DeletePackageVersionAndReferences(db.DefaultContext, pv) + assert.NoError(t, err) + } else { + assert.ErrorIs(t, err, packages_model.ErrPackageNotExist) + } + } + + assert.NoError(t, packages_model.DeleteCleanupRuleByID(db.DefaultContext, pcr.ID)) + }) + } + }) } From 43aafc5ba189efe9750326b21ee5a7c827929b75 Mon Sep 17 00:00:00 2001 From: Andrew Buettner <82419291+KB3HNS@users.noreply.github.com> Date: Sun, 20 Nov 2022 14:14:03 -0600 Subject: [PATCH 051/149] Improve documentation for PAM and static deployment (#21866) ## Changes proposed in [referenced issue 21845][1] - Expand PAM configuration description with working examples. - Clarify `STATIC_URL_PREFIX` use (include "assets" and only works after database has been initialized) - Add note for HTTPS proxy support VIA Apache. [1]: https://github.com/go-gitea/gitea/issues/21845 --- .../doc/advanced/config-cheat-sheet.en-us.md | 7 ++- .../doc/features/authentication.en-us.md | 44 +++++++++++++++++-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index aece6afc08..92758c61e4 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -289,8 +289,13 @@ The following configuration set `Content-Type: application/vnd.android.package-a This includes CSS files, images, JS files and web fonts. Avatar images are dynamic resources and still served by Gitea. The option can be just a different path, as in `/static`, or another domain, as in `https://cdn.example.com`. - Requests are then made as `%(ROOT_URL)s/static/css/index.css` and `https://cdn.example.com/css/index.css` respective. + Requests are then made as `%(ROOT_URL)s/static/assets/css/index.css` or `https://cdn.example.com/assets/css/index.css` respectively. The static files are located in the `public/` directory of the Gitea source repository. + You can proxy the STATIC_URL_PREFIX requests to Gitea server to serve the static + assets, or copy the manually built Gitea assets from `$GITEA_BUILD/public` to + the assets location, eg: `/var/www/assets`, make sure `$STATIC_URL_PREFIX/assets/css/index.css` + points to `/var/www/assets/css/index.css`. + - `HTTP_ADDR`: **0.0.0.0**: HTTP listen address. - If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings. diff --git a/docs/content/doc/features/authentication.en-us.md b/docs/content/doc/features/authentication.en-us.md index 7d555d1dcc..f25065d9c4 100644 --- a/docs/content/doc/features/authentication.en-us.md +++ b/docs/content/doc/features/authentication.en-us.md @@ -166,11 +166,47 @@ Uses the following fields: ## PAM (Pluggable Authentication Module) -To configure PAM, set the 'PAM Service Name' to a filename in `/etc/pam.d/`. To -work with normal Linux passwords, the user running Gitea must have read access -to `/etc/shadow`. +This procedure enables PAM authentication. Users may still be added to the +system manually using the user administration. PAM provides a mechanism to +automatically add users to the current database by testing them against PAM +authentication. To work with normal Linux passwords, the user running Gitea +must also have read access to `/etc/shadow` in order to check the validity of +the account when logging in using a public key. -**Note**: PAM support is added via [build-time flags](https://docs.gitea.io/en-us/install-from-source/#build), and the official binaries provided do not have this enabled. +**Note**: If a user has added SSH public keys into Gitea, the use of these +keys _may_ bypass the login check system. Therefore, if you wish to disable a user who +authenticates with PAM, you _should_ also manually disable the account in Gitea using the +built-in user manager. + +1. Configure and prepare the installation. + - It is recommended that you create an administrative user. + - Deselecting automatic sign-up may also be desired. +1. Once the database has been initialized, log in as the newly created +administrative user. +1. Navigate to the user setting (icon in top-right corner), and select +`Site Administration` -> `Authentication Sources`, and select +`Add Authentication Source`. +1. Fill out the field as follows: + - `Authentication Type` : `PAM` + - `Name` : Any value should be valid here, use "System Authentication" if + you'd like. + - `PAM Service Name` : Select the appropriate file listed under `/etc/pam.d/` + that performs the authentication desired.[^1] + - `PAM Email Domain` : The e-mail suffix to append to user authentication. + For example, if the login system expects a user called `gituser`, and this + field is set to `mail.com`, then Gitea will expect the `user email` field + for an authenticated GIT instance to be `gituser@mail.com`.[^2] + +**Note**: PAM support is added via [build-time flags](https://docs.gitea.io/en-us/install-from-source/#build), +and the official binaries provided do not have this enabled. PAM requires that +the necessary libpam dynamic library be available and the necessary PAM +development headers be accessible to the compiler. + +[^1]: For example, using standard Linux log-in on Debian "Bullseye" use +`common-session-noninteractive` - this value may be valid for other flavors of +Debian including Ubuntu and Mint, consult your distribution's documentation. +[^2]: **This is a required field for PAM**. Be aware: In the above example, the +user will log into the Gitea web interface as `gituser` and not `gituser@mail.com` ## SMTP (Simple Mail Transfer Protocol) From 9380bb6d0c7fb8d2652d19a9aec87994a6e99f8c Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 21 Nov 2022 03:39:00 +0100 Subject: [PATCH 052/149] Consolidate security-check into checks-backend (#21882) Also, run it via exact version instead of relying on global binary. --- .drone.yml | 10 ---------- Makefile | 4 ++-- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/.drone.yml b/.drone.yml index f2b34ef7e3..5127b54377 100644 --- a/.drone.yml +++ b/.drone.yml @@ -39,16 +39,6 @@ steps: - make lint-frontend depends_on: [deps-frontend] - - name: security-check - image: golang:1.19 - pull: always - commands: - - make security-check - depends_on: [deps-backend] - volumes: - - name: deps - path: /go - - name: lint-backend image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env pull: always diff --git a/Makefile b/Makefile index 4ca346c63e..4d78944de1 100644 --- a/Makefile +++ b/Makefile @@ -333,7 +333,7 @@ checks: checks-frontend checks-backend checks-frontend: lockfile-check svg-check .PHONY: checks-backend -checks-backend: tidy-check swagger-check fmt-check misspell-check swagger-validate +checks-backend: tidy-check swagger-check fmt-check misspell-check swagger-validate security-check .PHONY: lint lint: lint-frontend lint-backend @@ -745,7 +745,7 @@ generate-go: $(TAGS_PREREQ) .PHONY: security-check security-check: - govulncheck -v ./... + go run $(GOVULNCHECK_PACKAGE) -v ./... $(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@ From b4802b9b2eae044e35f022dc7116986e4762a944 Mon Sep 17 00:00:00 2001 From: Xinyu Zhou Date: Mon, 21 Nov 2022 13:14:58 +0800 Subject: [PATCH 053/149] Allow disable RSS/Atom feed (#21622) This patch provide a mechanism to disable RSS/Atom feed. Signed-off-by: Xinyu Zhou Co-authored-by: Lunny Xiao Co-authored-by: 6543 <6543@obermui.de> --- custom/conf/app.example.ini | 4 +++- .../doc/advanced/config-cheat-sheet.en-us.md | 1 + modules/context/repo.go | 6 ++++-- modules/setting/setting.go | 2 ++ routers/web/repo/view.go | 15 +++++++++------ routers/web/web.go | 13 +++++++++++-- templates/base/head.tmpl | 2 +- templates/org/home.tmpl | 4 +++- templates/repo/header.tmpl | 4 +++- templates/user/profile.tmpl | 4 +++- 10 files changed, 40 insertions(+), 15 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 8e85394d34..76482bf607 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2234,7 +2234,9 @@ ROUTER = console ;; Show template execution time in the footer ;SHOW_FOOTER_TEMPLATE_LOAD_TIME = true ;; Generate sitemap. Defaults to `true`. -; ENABLE_SITEMAP = true +;ENABLE_SITEMAP = true +;; Enable/Disable RSS/Atom feed +;ENABLE_FEED = true ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 92758c61e4..4e7ef492f9 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -1288,3 +1288,4 @@ PROXY_HOSTS = *.github.com - `SHOW_FOOTER_VERSION`: **true**: Show Gitea and Go version information in the footer. - `SHOW_FOOTER_TEMPLATE_LOAD_TIME`: **true**: Show time of template execution in the footer. - `ENABLE_SITEMAP`: **true**: Generate sitemap. +- `ENABLE_FEED`: **true**: Enable/Disable RSS/Atom feed. diff --git a/modules/context/repo.go b/modules/context/repo.go index 1a0263a330..c363c36994 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -441,8 +441,10 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { userName := ctx.Params(":username") repoName := ctx.Params(":reponame") repoName = strings.TrimSuffix(repoName, ".git") - repoName = strings.TrimSuffix(repoName, ".rss") - repoName = strings.TrimSuffix(repoName, ".atom") + if setting.EnableFeed { + repoName = strings.TrimSuffix(repoName, ".rss") + repoName = strings.TrimSuffix(repoName, ".atom") + } // Check if the user is the same as the repository owner if ctx.IsSigned && ctx.Doer.LowerName == strings.ToLower(userName) { diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 12558da494..fb425c8717 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -440,6 +440,7 @@ var ( ShowFooterBranding bool ShowFooterVersion bool ShowFooterTemplateLoadTime bool + EnableFeed bool // Global setting objects Cfg *ini.File @@ -1102,6 +1103,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { ShowFooterVersion = Cfg.Section("other").Key("SHOW_FOOTER_VERSION").MustBool(true) ShowFooterTemplateLoadTime = Cfg.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool(true) EnableSitemap = Cfg.Section("other").Key("ENABLE_SITEMAP").MustBool(true) + EnableFeed = Cfg.Section("other").Key("ENABLE_FEED").MustBool(true) UI.ShowUserEmail = Cfg.Section("ui").Key("SHOW_USER_EMAIL").MustBool(true) UI.DefaultShowFullName = Cfg.Section("ui").Key("DEFAULT_SHOW_FULL_NAME").MustBool(false) diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 7500dbb34b..7a9e44ff5e 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -771,13 +771,16 @@ func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) { // Home render repository home page func Home(ctx *context.Context) { - isFeed, _, showFeedType := feed.GetFeedType(ctx.Params(":reponame"), ctx.Req) - if isFeed { - feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType) - return - } + if setting.EnableFeed { + isFeed, _, showFeedType := feed.GetFeedType(ctx.Params(":reponame"), ctx.Req) + if isFeed { + feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType) + return + } - ctx.Data["FeedURL"] = ctx.Repo.Repository.HTMLURL() + ctx.Data["EnableFeed"] = true + ctx.Data["FeedURL"] = ctx.Repo.Repository.HTMLURL() + } checkHomeCodeViewable(ctx) if ctx.Written() { diff --git a/routers/web/web.go b/routers/web/web.go index 142f2384eb..fe5007abb7 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -310,6 +310,13 @@ func RegisterRoutes(m *web.Route) { } } + feedEnabled := func(ctx *context.Context) { + if !setting.EnableFeed { + ctx.Error(http.StatusNotFound) + return + } + } + // FIXME: not all routes need go through same middleware. // Especially some AJAX requests, we can reduce middleware number to improve performance. // Routers. @@ -633,9 +640,11 @@ func RegisterRoutes(m *web.Route) { m.Get(".png", func(ctx *context.Context) { ctx.Error(http.StatusNotFound) }) m.Get(".keys", user.ShowSSHKeys) m.Get(".gpg", user.ShowGPGKeys) - m.Get(".rss", feed.ShowUserFeedRSS) - m.Get(".atom", feed.ShowUserFeedAtom) + m.Get(".rss", feedEnabled, feed.ShowUserFeedRSS) + m.Get(".atom", feedEnabled, feed.ShowUserFeedAtom) m.Get("", user.Profile) + }, func(ctx *context.Context) { + ctx.Data["EnableFeed"] = setting.EnableFeed }, context_service.UserAssignmentWeb()) m.Get("/attachments/{uuid}", repo.GetAttachment) }, ignSignIn) diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index 70a88ff755..e2fc8434aa 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -15,7 +15,7 @@ {{end}} -{{if .FeedURL}} +{{if and .EnableFeed .FeedURL}} {{end}} diff --git a/templates/org/home.tmpl b/templates/org/home.tmpl index 448639975f..358f045bc6 100644 --- a/templates/org/home.tmpl +++ b/templates/org/home.tmpl @@ -5,7 +5,9 @@
{{.Org.DisplayName}} - {{svg "octicon-rss" 36}} + {{if .EnableFeed}} + {{svg "octicon-rss" 36}} + {{end}} {{if .Org.Visibility.IsLimited}}
{{.locale.Tr "org.settings.visibility.limited_shortname"}}
{{end}} {{if .Org.Visibility.IsPrivate}}
{{.locale.Tr "org.settings.visibility.private_shortname"}}
{{end}} diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 831784a623..e6bd839f57 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -13,7 +13,9 @@ {{.Owner.Name}}
/
{{.Name}} - {{svg "octicon-rss" 18}} + {{if $.EnableFeed}} + {{svg "octicon-rss" 18}} + {{end}}
{{if .IsTemplate}} {{if .IsPrivate}} diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl index 3b776bc16d..70a49235ed 100644 --- a/templates/user/profile.tmpl +++ b/templates/user/profile.tmpl @@ -18,7 +18,9 @@
{{if .Owner.FullName}}{{.Owner.FullName}}{{end}} {{.Owner.Name}} - {{svg "octicon-rss" 18}} + {{if .EnableFeed}} + {{svg "octicon-rss" 18}} + {{end}} From e4eaa68a2b2355c7333406fdcbb8b118677b95df Mon Sep 17 00:00:00 2001 From: Jason Song Date: Mon, 21 Nov 2022 16:36:59 +0800 Subject: [PATCH 054/149] Replace yaml.v2 with yaml.v3 (#21832) I don't see why we have to use two versions of yaml. The difference between the two versions has nothing to do with our usage. --- go.mod | 2 +- modules/migration/file_format.go | 11 +++++------ modules/packages/helm/metadata.go | 2 +- modules/packages/pub/metadata.go | 2 +- modules/packages/rubygems/metadata.go | 4 ++-- routers/api/packages/helm/helm.go | 2 +- services/migrations/dump.go | 2 +- services/migrations/restore.go | 2 +- tests/integration/api_packages_helm_test.go | 2 +- tests/integration/dump_restore_test.go | 2 +- 10 files changed, 15 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index cf1397c468..ca8c79c689 100644 --- a/go.mod +++ b/go.mod @@ -102,7 +102,6 @@ require ( golang.org/x/tools v0.1.12 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.67.0 - gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 mvdan.cc/xurls/v2 v2.4.0 strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 @@ -293,6 +292,7 @@ require ( gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect sigs.k8s.io/yaml v1.2.0 // indirect ) diff --git a/modules/migration/file_format.go b/modules/migration/file_format.go index 30e1d256cd..92cf71407d 100644 --- a/modules/migration/file_format.go +++ b/modules/migration/file_format.go @@ -8,12 +8,13 @@ import ( "fmt" "os" "strings" + "time" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "github.com/santhosh-tekuri/jsonschema/v5" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) // Load project data from file, with optional validation @@ -84,13 +85,9 @@ func validate(bs []byte, datatype interface{}, isJSON bool) error { func toStringKeys(val interface{}) (interface{}, error) { var err error switch val := val.(type) { - case map[interface{}]interface{}: + case map[string]interface{}: m := make(map[string]interface{}) for k, v := range val { - k, ok := k.(string) - if !ok { - return nil, fmt.Errorf("found non-string key %T %s", k, k) - } m[k], err = toStringKeys(v) if err != nil { return nil, err @@ -106,6 +103,8 @@ func toStringKeys(val interface{}) (interface{}, error) { } } return l, nil + case time.Time: + return val.Format(time.RFC3339), nil default: return val, nil } diff --git a/modules/packages/helm/metadata.go b/modules/packages/helm/metadata.go index 9517448ca6..fb5e51d0c5 100644 --- a/modules/packages/helm/metadata.go +++ b/modules/packages/helm/metadata.go @@ -14,7 +14,7 @@ import ( "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) var ( diff --git a/modules/packages/pub/metadata.go b/modules/packages/pub/metadata.go index 1fc4908b91..f3e9bf20bc 100644 --- a/modules/packages/pub/metadata.go +++ b/modules/packages/pub/metadata.go @@ -15,7 +15,7 @@ import ( "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) var ( diff --git a/modules/packages/rubygems/metadata.go b/modules/packages/rubygems/metadata.go index 05c1a8a719..f1fc399918 100644 --- a/modules/packages/rubygems/metadata.go +++ b/modules/packages/rubygems/metadata.go @@ -14,7 +14,7 @@ import ( "code.gitea.io/gitea/modules/validation" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) var ( @@ -120,7 +120,7 @@ func (r requirement) AsVersionRequirement() []VersionRequirement { if !ok { continue } - vm, ok := req[1].(map[interface{}]interface{}) + vm, ok := req[1].(map[string]interface{}) if !ok { continue } diff --git a/routers/api/packages/helm/helm.go b/routers/api/packages/helm/helm.go index 662d9a5dda..17f0a0d311 100644 --- a/routers/api/packages/helm/helm.go +++ b/routers/api/packages/helm/helm.go @@ -23,7 +23,7 @@ import ( "code.gitea.io/gitea/routers/api/packages/helper" packages_service "code.gitea.io/gitea/services/packages" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) func apiError(ctx *context.Context, status int, obj interface{}) { diff --git a/services/migrations/dump.go b/services/migrations/dump.go index 4ab4539c89..8103e2faac 100644 --- a/services/migrations/dump.go +++ b/services/migrations/dump.go @@ -26,7 +26,7 @@ import ( "code.gitea.io/gitea/modules/structs" "github.com/google/uuid" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) var _ base.Uploader = &RepositoryDumper{} diff --git a/services/migrations/restore.go b/services/migrations/restore.go index c3fbcbb25f..10fe8c4ee8 100644 --- a/services/migrations/restore.go +++ b/services/migrations/restore.go @@ -13,7 +13,7 @@ import ( base "code.gitea.io/gitea/modules/migration" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) // RepositoryRestorer implements an Downloader from the local directory diff --git a/tests/integration/api_packages_helm_test.go b/tests/integration/api_packages_helm_test.go index 393bf3cbe2..3c30a6848e 100644 --- a/tests/integration/api_packages_helm_test.go +++ b/tests/integration/api_packages_helm_test.go @@ -22,7 +22,7 @@ import ( "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) func TestPackageHelm(t *testing.T) { diff --git a/tests/integration/dump_restore_test.go b/tests/integration/dump_restore_test.go index 19513d0271..80c71810e3 100644 --- a/tests/integration/dump_restore_test.go +++ b/tests/integration/dump_restore_test.go @@ -25,7 +25,7 @@ import ( "code.gitea.io/gitea/services/migrations" "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) func TestDumpRestore(t *testing.T) { From c2fb27beb4a0f9a9ad1478937439bcf4c43aff4a Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 21 Nov 2022 10:59:42 +0100 Subject: [PATCH 055/149] Improvements for Content Copy (#21842) It now supports copying Markdown, SVG and Images (not in Firefox currently because of lacking [`ClipboardItem`](https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem) support, but can be enabled in `about:config` and works). It will fetch the data if in a rendered view or when it's an image. Followup to https://github.com/go-gitea/gitea/pull/21629. --- .eslintrc.yaml | 2 +- options/locale/locale_en-US.ini | 2 +- routers/web/repo/view.go | 9 ++++- templates/repo/view_file.tmpl | 6 +-- web_src/js/features/clipboard.js | 15 +++++--- web_src/js/features/copycontent.js | 59 ++++++++++++++++++++++++++++++ web_src/js/features/repo-code.js | 16 +------- web_src/js/index.js | 2 + web_src/js/modules/tippy.js | 1 + web_src/js/utils.js | 48 ++++++++++++++++++++++++ web_src/js/utils.test.js | 7 +++- web_src/less/animations.less | 6 +++ 12 files changed, 144 insertions(+), 29 deletions(-) create mode 100644 web_src/js/features/copycontent.js diff --git a/.eslintrc.yaml b/.eslintrc.yaml index cd86b680ee..2f213db37d 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -199,7 +199,7 @@ rules: newline-per-chained-call: [0] no-alert: [0] no-array-constructor: [2] - no-async-promise-executor: [2] + no-async-promise-executor: [0] no-await-in-loop: [0] no-bitwise: [0] no-buffer-constructor: [0] diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index ce93e92d34..02598dc3dc 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -95,6 +95,7 @@ copy_content = Copy content copy_branch = Copy branch name copy_success = Copied! copy_error = Copy failed +copy_type_unsupported = This file type can not be copied write = Write preview = Preview @@ -1096,7 +1097,6 @@ editor.cannot_edit_non_text_files = Binary files cannot be edited in the web int editor.edit_this_file = Edit File editor.this_file_locked = File is locked editor.must_be_on_a_branch = You must be on a branch to make or propose changes to this file. -editor.only_copy_raw = You may only copy raw text files. editor.fork_before_edit = You must fork this repository to make or propose changes to this file. editor.delete_this_file = Delete File editor.must_have_write_access = You must have write access to make or propose changes to this file. diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 7a9e44ff5e..1d1ba25064 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -443,7 +443,12 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["IsRepresentableAsText"] = isRepresentableAsText ctx.Data["IsDisplayingSource"] = isDisplayingSource ctx.Data["IsDisplayingRendered"] = isDisplayingRendered - ctx.Data["IsTextSource"] = isTextFile || isDisplayingSource + + isTextSource := isTextFile || isDisplayingSource + ctx.Data["IsTextSource"] = isTextSource + if isTextSource { + ctx.Data["CanCopyContent"] = true + } // Check LFS Lock lfsLock, err := git_model.GetTreePathLock(ctx.Repo.Repository.ID, ctx.Repo.TreePath) @@ -474,6 +479,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st case isRepresentableAsText: if st.IsSvgImage() { ctx.Data["IsImageFile"] = true + ctx.Data["CanCopyContent"] = true ctx.Data["HasSourceRenderedToggle"] = true } @@ -608,6 +614,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["IsAudioFile"] = true case st.IsImage() && (setting.UI.SVG.Enabled || !st.IsSvgImage()): ctx.Data["IsImageFile"] = true + ctx.Data["CanCopyContent"] = true default: if fileSize >= setting.UI.MaxDisplayFileSize { ctx.Data["IsFileTooLarge"] = true diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 321600a997..0fe0a13198 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -38,11 +38,7 @@ {{end}}
{{svg "octicon-download"}} - {{if or .IsMarkup .IsRenderedHTML (not .IsTextSource)}} - {{svg "octicon-copy" 14}} - {{else}} - {{svg "octicon-copy" 14}} - {{end}} + {{svg "octicon-copy" 14}} {{if .Repository.CanEnableEditor}} {{if .CanEditFile}} {{svg "octicon-pencil"}} diff --git a/web_src/js/features/clipboard.js b/web_src/js/features/clipboard.js index 85324303e3..f266d4f64d 100644 --- a/web_src/js/features/clipboard.js +++ b/web_src/js/features/clipboard.js @@ -2,11 +2,16 @@ import {showTemporaryTooltip} from '../modules/tippy.js'; const {copy_success, copy_error} = window.config.i18n; -export async function copyToClipboard(text) { - try { - await navigator.clipboard.writeText(text); - } catch { - return fallbackCopyToClipboard(text); +export async function copyToClipboard(content) { + if (content instanceof Blob) { + const item = new window.ClipboardItem({[content.type]: content}); + await navigator.clipboard.write([item]); + } else { // text + try { + await navigator.clipboard.writeText(content); + } catch { + return fallbackCopyToClipboard(content); + } } return true; } diff --git a/web_src/js/features/copycontent.js b/web_src/js/features/copycontent.js new file mode 100644 index 0000000000..9b791bedba --- /dev/null +++ b/web_src/js/features/copycontent.js @@ -0,0 +1,59 @@ +import {copyToClipboard} from './clipboard.js'; +import {showTemporaryTooltip} from '../modules/tippy.js'; +import {convertImage} from '../utils.js'; +const {i18n} = window.config; + +async function doCopy(content, btn) { + const success = await copyToClipboard(content); + showTemporaryTooltip(btn, success ? i18n.copy_success : i18n.copy_error); +} + +export function initCopyContent() { + const btn = document.getElementById('copy-content'); + if (!btn || btn.classList.contains('disabled')) return; + + btn.addEventListener('click', async () => { + if (btn.classList.contains('is-loading')) return; + let content, isImage; + const link = btn.getAttribute('data-link'); + + // when data-link is present, we perform a fetch. this is either because + // the text to copy is not in the DOM or it is an image which should be + // fetched to copy in full resolution + if (link) { + btn.classList.add('is-loading'); + try { + const res = await fetch(link, {credentials: 'include', redirect: 'follow'}); + const contentType = res.headers.get('content-type'); + + if (contentType.startsWith('image/') && !contentType.startsWith('image/svg')) { + isImage = true; + content = await res.blob(); + } else { + content = await res.text(); + } + } catch { + return showTemporaryTooltip(btn, i18n.copy_error); + } finally { + btn.classList.remove('is-loading'); + } + } else { // text, read from DOM + const lineEls = document.querySelectorAll('.file-view .lines-code'); + content = Array.from(lineEls).map((el) => el.textContent).join(''); + } + + try { + await doCopy(content, btn); + } catch { + if (isImage) { // convert image to png as last-resort as some browser only support png copy + try { + await doCopy(await convertImage(content, 'image/png'), btn); + } catch { + showTemporaryTooltip(btn, i18n.copy_error); + } + } else { + showTemporaryTooltip(btn, i18n.copy_error); + } + } + }); +} diff --git a/web_src/js/features/repo-code.js b/web_src/js/features/repo-code.js index ef6b61196b..083a17bf21 100644 --- a/web_src/js/features/repo-code.js +++ b/web_src/js/features/repo-code.js @@ -1,10 +1,9 @@ import $ from 'jquery'; import {svg} from '../svg.js'; import {invertFileFolding} from './file-fold.js'; -import {createTippy, showTemporaryTooltip} from '../modules/tippy.js'; +import {createTippy} from '../modules/tippy.js'; import {copyToClipboard} from './clipboard.js'; -const {i18n} = window.config; export const singleAnchorRegex = /^#(L|n)([1-9][0-9]*)$/; export const rangeAnchorRegex = /^#(L[1-9][0-9]*)-(L[1-9][0-9]*)$/; @@ -114,18 +113,6 @@ function showLineButton() { }); } -function initCopyFileContent() { - // get raw text for copy content button, at the moment, only one button (and one related file content) is supported. - const copyFileContent = document.querySelector('#copy-file-content'); - if (!copyFileContent) return; - - copyFileContent.addEventListener('click', async () => { - const text = Array.from(document.querySelectorAll('.file-view .lines-code')).map((el) => el.textContent).join(''); - const success = await copyToClipboard(text); - showTemporaryTooltip(copyFileContent, success ? i18n.copy_success : i18n.copy_error); - }); -} - export function initRepoCodeView() { if ($('.code-view .lines-num').length > 0) { $(document).on('click', '.lines-num span', function (e) { @@ -205,5 +192,4 @@ export function initRepoCodeView() { if (!success) return; document.querySelector('.code-line-button')?._tippy?.hide(); }); - initCopyFileContent(); } diff --git a/web_src/js/index.js b/web_src/js/index.js index a829deaf11..f4638a60e0 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -89,6 +89,7 @@ import {initRepoWikiForm} from './features/repo-wiki.js'; import {initRepoCommentForm, initRepository} from './features/repo-legacy.js'; import {initFormattingReplacements} from './features/formatting.js'; import {initMcaptcha} from './features/mcaptcha.js'; +import {initCopyContent} from './features/copycontent.js'; // Run time-critical code as soon as possible. This is safe to do because this // script appears at the end of and rendered HTML is accessible at that point. @@ -136,6 +137,7 @@ $(document).ready(() => { initStopwatch(); initTableSort(); initFindFileInRepo(); + initCopyContent(); initAdminCommon(); initAdminEmails(); diff --git a/web_src/js/modules/tippy.js b/web_src/js/modules/tippy.js index 045df6f0a0..6a89151691 100644 --- a/web_src/js/modules/tippy.js +++ b/web_src/js/modules/tippy.js @@ -27,6 +27,7 @@ export function createTippy(target, opts = {}) { export function initTooltip(el, props = {}) { const content = el.getAttribute('data-content') || props.content; if (!content) return null; + if (!el.hasAttribute('aria-label')) el.setAttribute('aria-label', content); return createTippy(el, { content, delay: 100, diff --git a/web_src/js/utils.js b/web_src/js/utils.js index 9b8bf925a9..62ee11c2eb 100644 --- a/web_src/js/utils.js +++ b/web_src/js/utils.js @@ -85,3 +85,51 @@ export function translateMonth(month) { export function translateDay(day) { return new Date(Date.UTC(2022, 7, day)).toLocaleString(getCurrentLocale(), {weekday: 'short'}); } + +// convert a Blob to a DataURI +export function blobToDataURI(blob) { + return new Promise((resolve, reject) => { + try { + const reader = new FileReader(); + reader.addEventListener('load', (e) => { + resolve(e.target.result); + }); + reader.addEventListener('error', () => { + reject(new Error('FileReader failed')); + }); + reader.readAsDataURL(blob); + } catch (err) { + reject(err); + } + }); +} + +// convert image Blob to another mime-type format. +export function convertImage(blob, mime) { + return new Promise(async (resolve, reject) => { + try { + const img = new Image(); + const canvas = document.createElement('canvas'); + img.addEventListener('load', () => { + try { + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + const context = canvas.getContext('2d'); + context.drawImage(img, 0, 0); + canvas.toBlob((blob) => { + if (!(blob instanceof Blob)) return reject(new Error('imageBlobToPng failed')); + resolve(blob); + }, mime); + } catch (err) { + reject(err); + } + }); + img.addEventListener('error', () => { + reject(new Error('imageBlobToPng failed')); + }); + img.src = await blobToDataURI(blob); + } catch (err) { + reject(err); + } + }); +} diff --git a/web_src/js/utils.test.js b/web_src/js/utils.test.js index 0567a5c64a..1df0caa211 100644 --- a/web_src/js/utils.test.js +++ b/web_src/js/utils.test.js @@ -1,7 +1,7 @@ import {expect, test} from 'vitest'; import { basename, extname, isObject, uniq, stripTags, joinPaths, parseIssueHref, - prettyNumber, parseUrl, translateMonth, translateDay + prettyNumber, parseUrl, translateMonth, translateDay, blobToDataURI, } from './utils.js'; test('basename', () => { @@ -131,3 +131,8 @@ test('translateDay', () => { expect(translateDay(5)).toEqual('pt.'); document.documentElement.lang = originalLang; }); + +test('blobToDataURI', async () => { + const blob = new Blob([JSON.stringify({test: true})], {type: 'application/json'}); + expect(await blobToDataURI(blob)).toEqual('data:application/json;base64,eyJ0ZXN0Ijp0cnVlfQ=='); +}); diff --git a/web_src/less/animations.less b/web_src/less/animations.less index 6d32625704..689898da2a 100644 --- a/web_src/less/animations.less +++ b/web_src/less/animations.less @@ -33,6 +33,12 @@ height: var(--height-loading); } +.btn-octicon.is-loading::after { + border-width: 2px; + height: 1.25rem; + width: 1.25rem; +} + code.language-math.is-loading::after { padding: 0; border-width: 2px; From 2836382f3487ed3f9ebd57b4356b72784fdf97cb Mon Sep 17 00:00:00 2001 From: Percy Ma Date: Tue, 22 Nov 2022 04:09:55 +0800 Subject: [PATCH 056/149] fix(web): add `alt` for logo in home page (#21887) add `alt` for logo in home page --- templates/home.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/home.tmpl b/templates/home.tmpl index 7667db27a1..87192fa55b 100644 --- a/templates/home.tmpl +++ b/templates/home.tmpl @@ -3,7 +3,7 @@
- +

From 2e5ac53bdcbdc796dc4d1597bdf6d717e211bf24 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 21 Nov 2022 21:25:26 +0100 Subject: [PATCH 057/149] Embed Matrix icon as SVG (#21890) Embed the SVG icon directly, making further invertion unnecessary because the icon color can now follow text color. Screenshot 2022-11-21 at 20 16 32 Screenshot 2022-11-21 at 20 16 46 --- public/img/svg/gitea-matrix.svg | 1 + templates/admin/hook_new.tmpl | 2 +- templates/org/settings/hook_new.tmpl | 2 +- templates/repo/settings/webhook/base_list.tmpl | 2 +- templates/repo/settings/webhook/new.tmpl | 2 +- web_src/less/_base.less | 3 +++ web_src/less/themes/theme-arc-green.less | 4 ---- public/img/matrix.svg => web_src/svg/gitea-matrix.svg | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 public/img/svg/gitea-matrix.svg rename public/img/matrix.svg => web_src/svg/gitea-matrix.svg (99%) diff --git a/public/img/svg/gitea-matrix.svg b/public/img/svg/gitea-matrix.svg new file mode 100644 index 0000000000..cc5e08d3c7 --- /dev/null +++ b/public/img/svg/gitea-matrix.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/admin/hook_new.tmpl b/templates/admin/hook_new.tmpl index c5196fce4e..407eae9646 100644 --- a/templates/admin/hook_new.tmpl +++ b/templates/admin/hook_new.tmpl @@ -31,7 +31,7 @@ {{else if eq .HookType "feishu"}} {{else if eq .HookType "matrix"}} - + {{svg "gitea-matrix" 26}} {{else if eq .HookType "wechatwork"}} {{else if eq .HookType "packagist"}} diff --git a/templates/org/settings/hook_new.tmpl b/templates/org/settings/hook_new.tmpl index 7308cafa20..081f5a2839 100644 --- a/templates/org/settings/hook_new.tmpl +++ b/templates/org/settings/hook_new.tmpl @@ -26,7 +26,7 @@ {{else if eq .HookType "feishu"}} {{else if eq .HookType "matrix"}} - + {{svg "gitea-matrix" 26}} {{else if eq .HookType "wechatwork"}} {{else if eq .HookType "packagist"}} diff --git a/templates/repo/settings/webhook/base_list.tmpl b/templates/repo/settings/webhook/base_list.tmpl index fa68e12ce9..f96c48d4cd 100644 --- a/templates/repo/settings/webhook/base_list.tmpl +++ b/templates/repo/settings/webhook/base_list.tmpl @@ -29,7 +29,7 @@ {{.locale.Tr "repo.settings.web_hook_name_feishu_or_larksuite"}} - {{.locale.Tr "repo.settings.web_hook_name_matrix"}} + {{svg "gitea-matrix" 20 "img"}}{{.locale.Tr "repo.settings.web_hook_name_matrix"}} {{.locale.Tr "repo.settings.web_hook_name_wechatwork"}} diff --git a/templates/repo/settings/webhook/new.tmpl b/templates/repo/settings/webhook/new.tmpl index ea5a3eca3c..2722e099be 100644 --- a/templates/repo/settings/webhook/new.tmpl +++ b/templates/repo/settings/webhook/new.tmpl @@ -24,7 +24,7 @@ {{else if eq .HookType "feishu"}} {{else if eq .HookType "matrix"}} - + {{svg "gitea-matrix" 26}} {{else if eq .HookType "wechatwork"}} {{else if eq .HookType "packagist"}} diff --git a/web_src/less/_base.less b/web_src/less/_base.less index f2173d6d2b..e49721f7e0 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -784,6 +784,9 @@ a.commit-statuses-trigger { margin-top: -.25rem; margin-bottom: -.25rem; } +.ui.dropdown .menu > .item > svg.img { + margin-right: .78571429rem; +} .ui.selection.dropdown .menu > .item { border-color: var(--color-secondary); diff --git a/web_src/less/themes/theme-arc-green.less b/web_src/less/themes/theme-arc-green.less index b793f99509..fab1b9c3b4 100644 --- a/web_src/less/themes/theme-arc-green.less +++ b/web_src/less/themes/theme-arc-green.less @@ -182,7 +182,3 @@ .emoji[aria-label="musical notes"] { filter: invert(100%) hue-rotate(180deg); } - -img[src$="/img/matrix.svg"] { - filter: invert(80%); -} diff --git a/public/img/matrix.svg b/web_src/svg/gitea-matrix.svg similarity index 99% rename from public/img/matrix.svg rename to web_src/svg/gitea-matrix.svg index 9a255fd758..63b23fc671 100644 --- a/public/img/matrix.svg +++ b/web_src/svg/gitea-matrix.svg @@ -11,4 +11,4 @@ c-4.2-2.7-10.3-4.1-18.5-4.1c-2.4,0-5.6,0.5-9.5,1.6c-3.9,1.1-7.8,3.1-11.5,6.1c-3.7,3-6.9,7.3-9.5,12.9c-2.6,5.6-3.9,13-3.9,22.1 v107.6h-50.9V169.2H166.3z"/> - + \ No newline at end of file From 1c7496c7a7e4c3145ab90bbef129dd7c1a0189dd Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 22 Nov 2022 00:10:42 +0100 Subject: [PATCH 058/149] Webhook list enhancements (#21893) --- templates/admin/queue.tmpl | 2 +- templates/repo/settings/webhook/base_list.tmpl | 8 +++----- web_src/less/_admin.less | 4 ++-- web_src/less/_base.less | 6 ++++++ web_src/less/_repository.less | 4 ++-- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/templates/admin/queue.tmpl b/templates/admin/queue.tmpl index cd50798f80..675ec417e4 100644 --- a/templates/admin/queue.tmpl +++ b/templates/admin/queue.tmpl @@ -161,7 +161,7 @@ {{DateFmtLong .Start}} {{if .HasTimeout}}{{DateFmtLong .Timeout}}{{else}}-{{end}} - {{svg "octicon-trash"}} + {{svg "octicon-trash"}} {{else}} diff --git a/templates/repo/settings/webhook/base_list.tmpl b/templates/repo/settings/webhook/base_list.tmpl index f96c48d4cd..333764a7eb 100644 --- a/templates/repo/settings/webhook/base_list.tmpl +++ b/templates/repo/settings/webhook/base_list.tmpl @@ -55,11 +55,9 @@ {{else}} {{svg "octicon-dot-fill"}} {{end}} - {{.URL}} - + {{.URL}} + {{svg "octicon-pencil"}} + {{svg "octicon-trash"}}

{{end}}
diff --git a/web_src/less/_admin.less b/web_src/less/_admin.less index b18bc7c5e0..26417d42ee 100644 --- a/web_src/less/_admin.less +++ b/web_src/less/_admin.less @@ -3,8 +3,8 @@ > .item { &:not(:first-child) { border-top: 1px solid var(--color-secondary); - padding: 1rem; - margin: 15px -1rem -1rem; + padding: .25rem 1rem; + margin: 12px -1rem -1rem; } } } diff --git a/web_src/less/_base.less b/web_src/less/_base.less index e49721f7e0..6054331ec4 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -307,6 +307,11 @@ a.muted:hover [class*="color-text"], color: var(--color-primary); } +.delete-button, +.delete-button:hover { + color: var(--color-red); +} + a.label, .repository-menu a, .ui.search .results a, @@ -2571,6 +2576,7 @@ table th[data-sortt-desc] { .truncated-item-container { display: flex !important; + align-items: center; } .ellipsis-button { diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less index 63f1f954a0..f89a5df33d 100644 --- a/web_src/less/_repository.less +++ b/web_src/less/_repository.less @@ -2616,8 +2616,8 @@ > .item { &:not(:first-child) { border-top: 1px solid var(--color-secondary); - padding: 1rem; - margin: 15px -1rem -1rem; + padding: .25rem 1rem; + margin: 12px -1rem -1rem; } > .svg { From c8b217110ba44ca50f565aa521d5ae63003d8b5a Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 22 Nov 2022 01:58:55 +0100 Subject: [PATCH 059/149] Update JS dependencies (#21881) - Update all JS deps - Regenerate SVGs - Add new eslint rules, fix issues - Tested Mermaid, Swagger, Vue, Webpack, Citation Co-authored-by: Lunny Xiao --- .drone.yml | 2 +- .eslintrc.yaml | 5 + package-lock.json | 2333 ++++++++----------- package.json | 42 +- public/img/svg/octicon-arrow-down-left.svg | 1 + public/img/svg/octicon-arrow-down-right.svg | 1 + public/img/svg/octicon-arrow-up-left.svg | 1 + public/img/svg/octicon-arrow-up-right.svg | 1 + public/img/svg/octicon-clock-fill.svg | 1 + public/img/svg/octicon-issue-tracked-by.svg | 1 + public/img/svg/octicon-issue-tracked-in.svg | 1 + public/img/svg/octicon-project-roadmap.svg | 1 + public/img/svg/octicon-project-symlink.svg | 1 + public/img/svg/octicon-skip-fill.svg | 1 + web_src/js/features/clipboard.js | 2 +- web_src/js/features/repo-legacy.js | 4 +- web_src/js/features/repo-migrate.js | 2 +- web_src/js/features/tribute.js | 2 +- webpack.config.js | 5 +- 19 files changed, 1076 insertions(+), 1331 deletions(-) create mode 100644 public/img/svg/octicon-arrow-down-left.svg create mode 100644 public/img/svg/octicon-arrow-down-right.svg create mode 100644 public/img/svg/octicon-arrow-up-left.svg create mode 100644 public/img/svg/octicon-arrow-up-right.svg create mode 100644 public/img/svg/octicon-clock-fill.svg create mode 100644 public/img/svg/octicon-issue-tracked-by.svg create mode 100644 public/img/svg/octicon-issue-tracked-in.svg create mode 100644 public/img/svg/octicon-project-roadmap.svg create mode 100644 public/img/svg/octicon-project-symlink.svg create mode 100644 public/img/svg/octicon-skip-fill.svg diff --git a/.drone.yml b/.drone.yml index 5127b54377..d349a5f2fc 100644 --- a/.drone.yml +++ b/.drone.yml @@ -551,7 +551,7 @@ steps: # TODO: We should probably build all dependencies into a test image - name: test-e2e - image: mcr.microsoft.com/playwright:v1.27.1-focal + image: mcr.microsoft.com/playwright:v1.28.0-focal commands: - curl -sLO https://go.dev/dl/go1.19.linux-amd64.tar.gz && tar -C /usr/local -xzf go1.19.linux-amd64.tar.gz - groupadd --gid 1001 gitea && useradd -m --gid 1001 --uid 1001 gitea diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 2f213db37d..5e5cda7dc8 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -229,6 +229,7 @@ rules: no-empty-character-class: [2] no-empty-function: [0] no-empty-pattern: [2] + no-empty-static-block: [2] no-empty: [2, {allowEmptyCatch: true}] no-eq-null: [2] no-eval: [2] @@ -269,6 +270,7 @@ rules: no-negated-condition: [0] no-nested-ternary: [0] no-new-func: [2] + no-new-native-nonconstructor: [2] no-new-object: [2] no-new-symbol: [2] no-new-wrappers: [2] @@ -443,6 +445,7 @@ rules: unicorn/no-invalid-remove-event-listener: [2] unicorn/no-keyword-prefix: [0] unicorn/no-lonely-if: [2] + unicorn/no-negated-condition: [0] unicorn/no-nested-ternary: [0] unicorn/no-new-array: [0] unicorn/no-new-buffer: [0] @@ -453,6 +456,7 @@ rules: unicorn/no-static-only-class: [2] unicorn/no-thenable: [2] unicorn/no-this-assignment: [2] + unicorn/no-typeof-undefined: [2] unicorn/no-unnecessary-await: [2] unicorn/no-unreadable-array-destructuring: [0] unicorn/no-unreadable-iife: [2] @@ -503,6 +507,7 @@ rules: unicorn/prefer-regexp-test: [2] unicorn/prefer-replace-all: [0] unicorn/prefer-set-has: [0] + unicorn/prefer-set-size: [2] unicorn/prefer-spread: [0] unicorn/prefer-starts-ends-with: [2] unicorn/prefer-string-slice: [0] diff --git a/package-lock.json b/package-lock.json index d46d3a15ca..346dae412d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,14 +9,14 @@ "dependencies": { "@citation-js/core": "0.6.1", "@citation-js/plugin-bibtex": "0.6.1", - "@citation-js/plugin-csl": "0.6.3", + "@citation-js/plugin-csl": "0.6.4", "@citation-js/plugin-software-formats": "0.6.0", "@claviska/jquery-minicolors": "2.3.6", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "17.7.0", - "@vue/compiler-sfc": "3.2.41", + "@primer/octicons": "17.9.0", + "@vue/compiler-sfc": "3.2.45", "add-asset-webpack-plugin": "2.0.1", - "css-loader": "6.7.1", + "css-loader": "6.7.2", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", "esbuild-loader": "2.20.0", @@ -29,45 +29,45 @@ "less": "4.1.3", "less-loader": "11.1.0", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "9.1.7", - "mini-css-extract-plugin": "2.6.1", + "mermaid": "9.2.2", + "mini-css-extract-plugin": "2.7.0", "monaco-editor": "0.34.1", "monaco-editor-webpack-plugin": "7.0.1", "pretty-ms": "8.0.0", "sortablejs": "1.15.0", - "swagger-ui-dist": "4.15.0", + "swagger-ui-dist": "4.15.5", "tippy.js": "6.3.7", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", - "vue": "3.2.41", + "vue": "3.2.45", "vue-bar-graph": "2.0.0", - "vue-loader": "17.0.0", + "vue-loader": "17.0.1", "vue3-calendar-heatmap": "2.0.0", - "webpack": "5.74.0", - "webpack-cli": "4.10.0", + "webpack": "5.75.0", + "webpack-cli": "5.0.0", "workbox-routing": "6.5.4", "workbox-strategies": "6.5.4", "worker-loader": "3.0.8", "wrap-ansi": "8.0.1" }, "devDependencies": { - "@playwright/test": "1.27.1", + "@playwright/test": "1.28.0", "@rollup/pluginutils": "5.0.2", - "@stoplight/spectral-cli": "6.5.1", - "eslint": "8.26.0", + "@stoplight/spectral-cli": "6.6.0", + "eslint": "8.28.0", "eslint-plugin-import": "2.26.0", "eslint-plugin-jquery": "1.5.1", "eslint-plugin-sonarjs": "0.16.0", - "eslint-plugin-unicorn": "44.0.2", - "eslint-plugin-vue": "9.6.0", - "jsdom": "20.0.1", + "eslint-plugin-unicorn": "45.0.0", + "eslint-plugin-vue": "9.7.0", + "jsdom": "20.0.3", "markdownlint-cli": "0.32.2", "postcss-less": "6.0.0", - "stylelint": "14.14.0", + "stylelint": "14.15.0", "stylelint-config-standard": "29.0.0", - "svgo": "3.0.0", - "updates": "13.1.10", - "vitest": "0.24.3" + "svgo": "3.0.2", + "updates": "13.2.1", + "vitest": "0.25.2" }, "engines": { "node": ">= 14.0.0" @@ -186,9 +186,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", - "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", + "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -197,9 +197,9 @@ } }, "node_modules/@braintree/sanitize-url": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.1.tgz", - "integrity": "sha512-zr9Qs9KFQiEvMWdZesjcmRJlUck5NR+eKGS1uyKk+oYTWwlYrsoPEi6VmG6/TzBD1hKCGEimrhTgGS6hvn/xIQ==" + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz", + "integrity": "sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg==" }, "node_modules/@citation-js/core": { "version": "0.6.1", @@ -248,9 +248,9 @@ } }, "node_modules/@citation-js/plugin-csl": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.3.tgz", - "integrity": "sha512-SP1/QyHfhcNufQ6VTJUM04Ti0XEWSWYMUhkDGG2lQtnDJU7pSDeAwtsE1kYUIJ9Np0Gm8IEZAfJ3CslMfsbimg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.4.tgz", + "integrity": "sha512-RG4NrFIx0CZTfNeMCC8CL7UGFRiUv5/bNd/Nc6Q/NHx0cS/tYDQcKt0M24dpOI7PAZwVoddbDW4Iakn6nS4QsQ==", "dependencies": { "@citation-js/date": "^0.5.0", "citeproc": "^2.4.6" @@ -309,9 +309,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.12.tgz", - "integrity": "sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.14.tgz", + "integrity": "sha512-+Rb20XXxRGisNu2WmNKk+scpanb7nL5yhuI1KR9wQFiC43ddPj/V1fmNyzlFC9bKiG4mYzxW7egtoHVcynr+OA==", "cpu": [ "arm" ], @@ -324,9 +324,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.12.tgz", - "integrity": "sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.14.tgz", + "integrity": "sha512-eQi9rosGNVQFJyJWV0HCA5WZae/qWIQME7s8/j8DMvnylfBv62Pbu+zJ2eUDqNf2O4u3WB+OEXyfkpBoe194sg==", "cpu": [ "loong64" ], @@ -384,14 +384,14 @@ "dev": true }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.6", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.6.tgz", - "integrity": "sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==", + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", + "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" @@ -574,13 +574,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.27.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.27.1.tgz", - "integrity": "sha512-mrL2q0an/7tVqniQQF6RBL2saskjljXzqNcCOVMUjRIgE6Y38nCNaP+Dc2FBW06bcpD3tqIws/HT9qiMHbNU0A==", + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz", + "integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==", "dev": true, "dependencies": { "@types/node": "*", - "playwright-core": "1.27.1" + "playwright-core": "1.28.0" }, "bin": { "playwright": "cli.js" @@ -599,17 +599,17 @@ } }, "node_modules/@primer/octicons": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.7.0.tgz", - "integrity": "sha512-J5cVJDhExmqLGLWu8zHTOqcC8g1rQL7QzQZdbvHxW85u8ya82GtF5F68uHMDI5En3fsMlbkkF8Rz6dCaV3r+KA==", + "version": "17.9.0", + "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.9.0.tgz", + "integrity": "sha512-B6y3VxPrF6U+GUjZR883NsstI7v/Qcup9puDG+fOJvCm8b7UXNl46TbRrctMCZnYlyIzUF3/SgjJhr5od/Y6sw==", "dependencies": { "object-assign": "^4.1.1" } }, "node_modules/@rollup/plugin-commonjs": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-20.0.0.tgz", - "integrity": "sha512-5K0g5W2Ol8hAcTHqcTBHiA7M58tfmYi1o9KxeJuuRNpGaTa5iLjcyemBitCBcKXaHamOBBEH2dGom6v6Unmqjg==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.2.tgz", + "integrity": "sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==", "dev": true, "dependencies": { "@rollup/pluginutils": "^3.1.0", @@ -621,10 +621,10 @@ "resolve": "^1.17.0" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 12.0.0" }, "peerDependencies": { - "rollup": "^2.38.3" + "rollup": "^2.68.0" } }, "node_modules/@rollup/plugin-commonjs/node_modules/@rollup/pluginutils": { @@ -695,13 +695,14 @@ } }, "node_modules/@stoplight/json": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.17.0.tgz", - "integrity": "sha512-WW0z2bb0D4t8FTl+zNTCu46J8lEOsrUhBPgwEYQ3Ri2Y0MiRE4U1/9ZV8Ki+pIJznZgY9i42bbFwOBxyZn5/6w==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.20.1.tgz", + "integrity": "sha512-FXfud+uWgIj1xv6nUO9WnmgmnVikaxJcbtR4XQt4C42n5c2qua3U05Z/3B57hP5TJRSj+tpn9ID6/bFeyYYlEg==", "dev": true, "dependencies": { - "@stoplight/ordered-object-literal": "^1.0.2", - "@stoplight/types": "^12.3.0", + "@stoplight/ordered-object-literal": "^1.0.3", + "@stoplight/path": "^1.3.2", + "@stoplight/types": "^13.6.0", "jsonc-parser": "~2.2.1", "lodash": "^4.17.21", "safe-stable-stringify": "^1.1" @@ -730,22 +731,21 @@ "dev": true }, "node_modules/@stoplight/json-ref-resolver": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.3.tgz", - "integrity": "sha512-SgoKXwVnlpIZUyAFX4W79eeuTWvXmNlMfICZixL16GZXnkjcW+uZnfmAU0ZIjcnaTgaI4mjfxn8LAP2KR6Cr0A==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.4.tgz", + "integrity": "sha512-842JVmMsi++qpDuIX+JpQvK7YY8FXEZZb+/z4xuRfStOAVEryJT/tbgGOWxniSdxEl9Eni5D/I2afMyy6BuiNw==", "dev": true, "dependencies": { "@stoplight/json": "^3.17.0", "@stoplight/path": "^1.3.2", - "@stoplight/types": "^12.3.0", - "@types/urijs": "^1.19.16", + "@stoplight/types": "^12.3.0 || ^13.0.0", + "@types/urijs": "^1.19.19", "dependency-graph": "~0.11.0", "fast-memoize": "^2.5.2", "immer": "^9.0.6", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", + "lodash": "^4.17.21", "tslib": "^2.3.1", - "urijs": "^1.19.6" + "urijs": "^1.19.11" }, "engines": { "node": ">=8.3.0" @@ -770,22 +770,21 @@ } }, "node_modules/@stoplight/spectral-cli": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.5.1.tgz", - "integrity": "sha512-+qpwsDG2jQ4ULQmegBWonI3UnF6tUh351WDnV1GU8acl8eaeKbS+ZUNBgoP2f9tnMTfITdctVRFEGC3D6P7f9g==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.6.0.tgz", + "integrity": "sha512-z46fnrvraaWMio8Y9RYYkLO+XdmtxOWpy5qNJF3CsmWua0FZ4iOTryb5Cm3GkB0wEtqxNUCBUHvoo4hS6Noyqg==", "dev": true, "dependencies": { - "@rollup/plugin-commonjs": "^20.0.0", - "@stoplight/json": "3.17.0", + "@stoplight/json": "~3.20.1", "@stoplight/path": "1.3.2", - "@stoplight/spectral-core": "^1.5.1", - "@stoplight/spectral-parsers": "^1.0.1", - "@stoplight/spectral-ref-resolver": "1.0.1", - "@stoplight/spectral-ruleset-bundler": "^1.0.0", - "@stoplight/spectral-ruleset-migrator": "^1.5.0", + "@stoplight/spectral-core": "^1.15.1", + "@stoplight/spectral-parsers": "^1.0.2", + "@stoplight/spectral-ref-resolver": "1.0.2", + "@stoplight/spectral-ruleset-bundler": "^1.4.0", + "@stoplight/spectral-ruleset-migrator": "^1.9.0", "@stoplight/spectral-rulesets": ">=1", - "@stoplight/spectral-runtime": "^1.1.0", - "@stoplight/types": "12.3.0", + "@stoplight/spectral-runtime": "^1.1.2", + "@stoplight/types": "^13.6.0", "chalk": "4.1.2", "cliui": "7.0.4", "eol": "0.9.1", @@ -835,9 +834,9 @@ } }, "node_modules/@stoplight/spectral-core": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.15.0.tgz", - "integrity": "sha512-+DwK8SmnujMZJaxJeNU11vWY+DFOnt4oQM1TzAuvufdd3Y6Lsno88Jl31OaR1M9Fn7l/u3v1anBB/SSl/fI5rQ==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.15.1.tgz", + "integrity": "sha512-IZV8L1Hyz9759KdqJIA90W5uvurHplMmaPPIZjQzG2Bq/39kN/sbLA/Js8uOf3xB9cHBbG599t4AB+uGsI8t0g==", "dev": true, "dependencies": { "@stoplight/better-ajv-errors": "1.0.3", @@ -852,7 +851,6 @@ "ajv": "^8.6.0", "ajv-errors": "~3.0.0", "ajv-formats": "~2.1.0", - "blueimp-md5": "2.18.0", "es-aggregate-error": "^1.0.7", "jsonpath-plus": "7.1.0", "lodash": "~4.17.21", @@ -867,23 +865,6 @@ "node": "^12.20 || >= 14.13" } }, - "node_modules/@stoplight/spectral-core/node_modules/@stoplight/json": { - "version": "3.20.1", - "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.20.1.tgz", - "integrity": "sha512-FXfud+uWgIj1xv6nUO9WnmgmnVikaxJcbtR4XQt4C42n5c2qua3U05Z/3B57hP5TJRSj+tpn9ID6/bFeyYYlEg==", - "dev": true, - "dependencies": { - "@stoplight/ordered-object-literal": "^1.0.3", - "@stoplight/path": "^1.3.2", - "@stoplight/types": "^13.6.0", - "jsonc-parser": "~2.2.1", - "lodash": "^4.17.21", - "safe-stable-stringify": "^1.1" - }, - "engines": { - "node": ">=8.3.0" - } - }, "node_modules/@stoplight/spectral-core/node_modules/@stoplight/types": { "version": "13.6.0", "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.6.0.tgz", @@ -934,36 +915,6 @@ "node": ">=12" } }, - "node_modules/@stoplight/spectral-functions/node_modules/@stoplight/json": { - "version": "3.20.1", - "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.20.1.tgz", - "integrity": "sha512-FXfud+uWgIj1xv6nUO9WnmgmnVikaxJcbtR4XQt4C42n5c2qua3U05Z/3B57hP5TJRSj+tpn9ID6/bFeyYYlEg==", - "dev": true, - "dependencies": { - "@stoplight/ordered-object-literal": "^1.0.3", - "@stoplight/path": "^1.3.2", - "@stoplight/types": "^13.6.0", - "jsonc-parser": "~2.2.1", - "lodash": "^4.17.21", - "safe-stable-stringify": "^1.1" - }, - "engines": { - "node": ">=8.3.0" - } - }, - "node_modules/@stoplight/spectral-functions/node_modules/@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - }, - "engines": { - "node": "^12.20 || >=14.13" - } - }, "node_modules/@stoplight/spectral-parsers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@stoplight/spectral-parsers/-/spectral-parsers-1.0.2.tgz", @@ -979,45 +930,15 @@ "node": ">=12" } }, - "node_modules/@stoplight/spectral-parsers/node_modules/@stoplight/json": { - "version": "3.20.1", - "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.20.1.tgz", - "integrity": "sha512-FXfud+uWgIj1xv6nUO9WnmgmnVikaxJcbtR4XQt4C42n5c2qua3U05Z/3B57hP5TJRSj+tpn9ID6/bFeyYYlEg==", - "dev": true, - "dependencies": { - "@stoplight/ordered-object-literal": "^1.0.3", - "@stoplight/path": "^1.3.2", - "@stoplight/types": "^13.6.0", - "jsonc-parser": "~2.2.1", - "lodash": "^4.17.21", - "safe-stable-stringify": "^1.1" - }, - "engines": { - "node": ">=8.3.0" - } - }, - "node_modules/@stoplight/spectral-parsers/node_modules/@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - }, - "engines": { - "node": "^12.20 || >=14.13" - } - }, "node_modules/@stoplight/spectral-ref-resolver": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ref-resolver/-/spectral-ref-resolver-1.0.1.tgz", - "integrity": "sha512-0tY7nTOccvTsa3c4QbSWfJ8wGfPO1RXvmKnmBjuyLfoTMNuhkHPII9gKhCjygsshzsBLxs2IyRHZYhWYVnEbCA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ref-resolver/-/spectral-ref-resolver-1.0.2.tgz", + "integrity": "sha512-ah6NIB/O1EdEaEu89So3LmtbKRXPVnSElgQ7oBRE9S4/VOedSqyXn+qqMd40tGnO2CsKgZaFUYXdSEHOshpHYw==", "dev": true, "dependencies": { "@stoplight/json-ref-readers": "1.2.2", - "@stoplight/json-ref-resolver": "3.1.3", - "@stoplight/spectral-runtime": "^1.0.0", + "@stoplight/json-ref-resolver": "~3.1.4", + "@stoplight/spectral-runtime": "^1.1.2", "dependency-graph": "0.11.0", "tslib": "^2.3.1" }, @@ -1026,9 +947,9 @@ } }, "node_modules/@stoplight/spectral-ruleset-bundler": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.3.3.tgz", - "integrity": "sha512-hfHl7XZeF/wWMpSrsLqLnH2GevRHjSIqtBL2aRjO2SjMCTbO9LVz80p4sYaxrCcu4wQ6K71gMZXsG687+3fAeg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.4.0.tgz", + "integrity": "sha512-aYDI4a145IXED+6jvRjj9Ha0fnB+s54cr8KbQbPCEyhCHW1cP8UGVeOuwAfk+9C4ZIg40OuYrugN5EhA35oQtA==", "dev": true, "dependencies": { "@rollup/plugin-commonjs": "~22.0.2", @@ -1052,73 +973,10 @@ "node": "^12.20 || >= 14.13" } }, - "node_modules/@stoplight/spectral-ruleset-bundler/node_modules/@rollup/plugin-commonjs": { - "version": "22.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.2.tgz", - "integrity": "sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "rollup": "^2.68.0" - } - }, - "node_modules/@stoplight/spectral-ruleset-bundler/node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@stoplight/spectral-ruleset-bundler/node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/@stoplight/spectral-ruleset-bundler/node_modules/@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - }, - "engines": { - "node": "^12.20 || >=14.13" - } - }, - "node_modules/@stoplight/spectral-ruleset-bundler/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, "node_modules/@stoplight/spectral-ruleset-migrator": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.8.0.tgz", - "integrity": "sha512-zg6RPF+d8uS7zAp5TzUph3hQG4sgGcG5Fsw8Zx24H1REyuSkjiIfyee2Kf13c3BcIlTXvnFc4csz2rNXpZO7Ug==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.9.0.tgz", + "integrity": "sha512-hPSjgXsTxMQ5UV1hfkVVPknhqRjmjSnCZD5jideM4rRU5NS1fj2Pse1CiXBsRChsuAGi/2s0Ke5uuOmFFsHrxQ==", "dev": true, "dependencies": { "@stoplight/json": "~3.20.1", @@ -1140,36 +998,6 @@ "node": ">=12" } }, - "node_modules/@stoplight/spectral-ruleset-migrator/node_modules/@stoplight/json": { - "version": "3.20.1", - "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.20.1.tgz", - "integrity": "sha512-FXfud+uWgIj1xv6nUO9WnmgmnVikaxJcbtR4XQt4C42n5c2qua3U05Z/3B57hP5TJRSj+tpn9ID6/bFeyYYlEg==", - "dev": true, - "dependencies": { - "@stoplight/ordered-object-literal": "^1.0.3", - "@stoplight/path": "^1.3.2", - "@stoplight/types": "^13.6.0", - "jsonc-parser": "~2.2.1", - "lodash": "^4.17.21", - "safe-stable-stringify": "^1.1" - }, - "engines": { - "node": ">=8.3.0" - } - }, - "node_modules/@stoplight/spectral-ruleset-migrator/node_modules/@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - }, - "engines": { - "node": "^12.20 || >=14.13" - } - }, "node_modules/@stoplight/spectral-rulesets": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.14.1.tgz", @@ -1195,19 +1023,6 @@ "node": ">=12" } }, - "node_modules/@stoplight/spectral-rulesets/node_modules/@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - }, - "engines": { - "node": "^12.20 || >=14.13" - } - }, "node_modules/@stoplight/spectral-runtime": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@stoplight/spectral-runtime/-/spectral-runtime-1.1.2.tgz", @@ -1226,10 +1041,10 @@ "node": ">=12" } }, - "node_modules/@stoplight/types": { - "version": "12.3.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-12.3.0.tgz", - "integrity": "sha512-hgzUR1z5BlYvIzUeFK5pjs5JXSvEutA9Pww31+dVicBlunsG1iXopDx/cvfBY7rHOrgtZDuvyeK4seqkwAZ6Cg==", + "node_modules/@stoplight/spectral-runtime/node_modules/@stoplight/types": { + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-12.5.0.tgz", + "integrity": "sha512-dwqYcDrGmEyUv5TWrDam5TGOxU72ufyQ7hnOIIDdmW5ezOwZaBFoR5XQ9AsH49w7wgvOqB2Bmo799pJPWnpCbg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.4", @@ -1239,6 +1054,19 @@ "node": ">=8" } }, + "node_modules/@stoplight/types": { + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.8.0.tgz", + "integrity": "sha512-5glKswz7y9aACh+a+JegID+4xX//4TsIdv7iPl29hWnOoWrnlPbg3Gjc4nYUXXgMSaSlSsA15JU/0+rE89fR4A==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, "node_modules/@stoplight/yaml": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.2.3.tgz", @@ -1260,19 +1088,6 @@ "integrity": "sha512-sV+51I7WYnLJnKPn2EMWgS4EUfoP4iWEbrWwbXsj0MZCB/xOK8j6+C9fntIdOM50kpx45ZLC3s6kwKivWuqvyg==", "dev": true }, - "node_modules/@stoplight/yaml/node_modules/@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - }, - "engines": { - "node": "^12.20 || >=14.13" - } - }, "node_modules/@swc/helpers": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.2.14.tgz", @@ -1297,9 +1112,9 @@ } }, "node_modules/@types/chai": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", - "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", "dev": true }, "node_modules/@types/chai-subset": { @@ -1329,9 +1144,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.4.7", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.7.tgz", - "integrity": "sha512-ehM7cCt2RSFs42mb+lcmhFT9ouIlV92PuaeRGn8N8c98oMjG4Z5pJHA9b1QiCcuqnbPSHcyfiD3mlhqMaHsQIw==", + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -1374,9 +1189,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.4.tgz", - "integrity": "sha512-BxcJpBu8D3kv/GZkx/gSMz6VnTJREBj/4lbzYOQueUOELkt8WrO6zAcSPmp9uRPEW/d+lUO8QK0W2xnS1hEU0A==" + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -1405,36 +1220,36 @@ "dev": true }, "node_modules/@vue/compiler-core": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.41.tgz", - "integrity": "sha512-oA4mH6SA78DT+96/nsi4p9DX97PHcNROxs51lYk7gb9Z4BPKQ3Mh+BLn6CQZBw857Iuhu28BfMSRHAlPvD4vlw==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz", + "integrity": "sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==", "dependencies": { "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.41", + "@vue/shared": "3.2.45", "estree-walker": "^2.0.2", "source-map": "^0.6.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.41.tgz", - "integrity": "sha512-xe5TbbIsonjENxJsYRbDJvthzqxLNk+tb3d/c47zgREDa/PCp6/Y4gC/skM4H6PIuX5DAxm7fFJdbjjUH2QTMw==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz", + "integrity": "sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==", "dependencies": { - "@vue/compiler-core": "3.2.41", - "@vue/shared": "3.2.41" + "@vue/compiler-core": "3.2.45", + "@vue/shared": "3.2.45" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.41.tgz", - "integrity": "sha512-+1P2m5kxOeaxVmJNXnBskAn3BenbTmbxBxWOtBq3mQTCokIreuMULFantBUclP0+KnzNCMOvcnKinqQZmiOF8w==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz", + "integrity": "sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==", "dependencies": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.41", - "@vue/compiler-dom": "3.2.41", - "@vue/compiler-ssr": "3.2.41", - "@vue/reactivity-transform": "3.2.41", - "@vue/shared": "3.2.41", + "@vue/compiler-core": "3.2.45", + "@vue/compiler-dom": "3.2.45", + "@vue/compiler-ssr": "3.2.45", + "@vue/reactivity-transform": "3.2.45", + "@vue/shared": "3.2.45", "estree-walker": "^2.0.2", "magic-string": "^0.25.7", "postcss": "^8.1.10", @@ -1442,69 +1257,69 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.41.tgz", - "integrity": "sha512-Y5wPiNIiaMz/sps8+DmhaKfDm1xgj6GrH99z4gq2LQenfVQcYXmHIOBcs5qPwl7jaW3SUQWjkAPKMfQemEQZwQ==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz", + "integrity": "sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==", "dependencies": { - "@vue/compiler-dom": "3.2.41", - "@vue/shared": "3.2.41" + "@vue/compiler-dom": "3.2.45", + "@vue/shared": "3.2.45" } }, "node_modules/@vue/reactivity": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.41.tgz", - "integrity": "sha512-9JvCnlj8uc5xRiQGZ28MKGjuCoPhhTwcoAdv3o31+cfGgonwdPNuvqAXLhlzu4zwqavFEG5tvaoINQEfxz+l6g==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz", + "integrity": "sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==", "dependencies": { - "@vue/shared": "3.2.41" + "@vue/shared": "3.2.45" } }, "node_modules/@vue/reactivity-transform": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.41.tgz", - "integrity": "sha512-mK5+BNMsL4hHi+IR3Ft/ho6Za+L3FA5j8WvreJ7XzHrqkPq8jtF/SMo7tuc9gHjLDwKZX1nP1JQOKo9IEAn54A==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz", + "integrity": "sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==", "dependencies": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.41", - "@vue/shared": "3.2.41", + "@vue/compiler-core": "3.2.45", + "@vue/shared": "3.2.45", "estree-walker": "^2.0.2", "magic-string": "^0.25.7" } }, "node_modules/@vue/runtime-core": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.41.tgz", - "integrity": "sha512-0LBBRwqnI0p4FgIkO9q2aJBBTKDSjzhnxrxHYengkAF6dMOjeAIZFDADAlcf2h3GDALWnblbeprYYpItiulSVQ==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz", + "integrity": "sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==", "dependencies": { - "@vue/reactivity": "3.2.41", - "@vue/shared": "3.2.41" + "@vue/reactivity": "3.2.45", + "@vue/shared": "3.2.45" } }, "node_modules/@vue/runtime-dom": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.41.tgz", - "integrity": "sha512-U7zYuR1NVIP8BL6jmOqmapRAHovEFp7CSw4pR2FacqewXNGqZaRfHoNLQsqQvVQ8yuZNZtxSZy0FFyC70YXPpA==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz", + "integrity": "sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==", "dependencies": { - "@vue/runtime-core": "3.2.41", - "@vue/shared": "3.2.41", + "@vue/runtime-core": "3.2.45", + "@vue/shared": "3.2.45", "csstype": "^2.6.8" } }, "node_modules/@vue/server-renderer": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.41.tgz", - "integrity": "sha512-7YHLkfJdTlsZTV0ae5sPwl9Gn/EGr2hrlbcS/8naXm2CDpnKUwC68i1wGlrYAfIgYWL7vUZwk2GkYLQH5CvFig==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz", + "integrity": "sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==", "dependencies": { - "@vue/compiler-ssr": "3.2.41", - "@vue/shared": "3.2.41" + "@vue/compiler-ssr": "3.2.45", + "@vue/shared": "3.2.45" }, "peerDependencies": { - "vue": "3.2.41" + "vue": "3.2.45" } }, "node_modules/@vue/shared": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.41.tgz", - "integrity": "sha512-W9mfWLHmJhkfAmV+7gDjcHeAWALQtgGT3JErxULl0oz6R6+3ug91I7IErs93eCFhPCZPHBs4QJS7YWEV7A3sxw==" + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz", + "integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==" }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", @@ -1638,31 +1453,39 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", - "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.0.tgz", + "integrity": "sha512-war4OU8NGjBqU3DP3bx6ciODXIh7dSXcpQq+P4K2Tqyd8L5OjZ7COx9QXx/QdCIwL2qoX09Wr4Cwf7uS4qdEng==", + "engines": { + "node": ">=14.15.0" + }, "peerDependencies": { - "webpack": "4.x.x || 5.x.x", - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" } }, "node_modules/@webpack-cli/info": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", - "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", - "dependencies": { - "envinfo": "^7.7.3" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.0.tgz", + "integrity": "sha512-NNxDgbo4VOkNhOlTgY0Elhz3vKpOJq4/PKeKg7r8cmYM+GQA9vDofLYyup8jS6EpUvhNmR30cHTCEIyvXpskwA==", + "engines": { + "node": ">=14.15.0" }, "peerDependencies": { - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" } }, "node_modules/@webpack-cli/serve": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", - "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.0.tgz", + "integrity": "sha512-Rumq5mHvGXamnOh3O8yLk1sjx8dB30qF1OeR6VC00DIR6SLJ4bwwUGKC4pE7qBFoQyyh0H9sAg3fikYgAqVR0w==", + "engines": { + "node": ">=14.15.0" + }, "peerDependencies": { - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" }, "peerDependenciesMeta": { "webpack-dev-server": { @@ -1772,9 +1595,9 @@ } }, "node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -1872,15 +1695,15 @@ } }, "node_modules/array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", "is-string": "^1.0.7" }, "engines": { @@ -1900,14 +1723,14 @@ } }, "node_modules/array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -2012,12 +1835,6 @@ "node": "*" } }, - "node_modules/blueimp-md5": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.18.0.tgz", - "integrity": "sha512-vE52okJvzsVWhcgUHOv+69OG3Mdg151xyn41aVQN/5W5S+S43qZhxECtYLAEHMSFWX6Mv5IZrzj3T5+JqXfj5Q==", - "dev": true - }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -2175,9 +1992,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001423", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001423.tgz", - "integrity": "sha512-09iwWGOlifvE1XuHokFMP7eR38a0JnajoyL3/i87c8ZjRWRrdKo1fqjNfugfBD0UDBIOz0U+jtNhJ0EPm1VleQ==", + "version": "1.0.30001431", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", + "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==", "funding": [ { "type": "opencollective", @@ -2190,14 +2007,14 @@ ] }, "node_modules/chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", "dev": true, "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", - "deep-eql": "^3.0.1", + "deep-eql": "^4.1.2", "get-func-name": "^2.0.0", "loupe": "^2.3.1", "pathval": "^1.1.1", @@ -2240,10 +2057,13 @@ } }, "node_modules/ci-info": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", - "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", - "dev": true + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.6.1.tgz", + "integrity": "sha512-up5ggbaDqOqJ4UqLKZ2naVkyqSJQgJi5lwD6b6mM748ysrghDBX0bx/qJTUHzw7zu6Mq4gycviSF5hJnwceD8w==", + "dev": true, + "engines": { + "node": ">=8" + } }, "node_modules/citeproc": { "version": "2.4.62", @@ -2324,9 +2144,9 @@ } }, "node_modules/codemirror": { - "version": "5.65.9", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.9.tgz", - "integrity": "sha512-19Jox5sAKpusTDgqgKB5dawPpQcY+ipQK7xoEI+MVucEF9qqFaXpeqY1KaoyGBso/wHQoDa4HMMxMjdsS3Zzzw==" + "version": "5.65.10", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.10.tgz", + "integrity": "sha512-IXAG5wlhbgcTJ6rZZcmi4+sjWIbJqIGfeg3tNa3yX84Jb3T4huS5qzQAo/cUisc1l3bI47WZodpyf7cYcocDKg==" }, "node_modules/codemirror-spell-checker": { "version": "1.1.2", @@ -2412,9 +2232,9 @@ "dev": true }, "node_modules/cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dev": true, "dependencies": { "@types/parse-json": "^4.0.0", @@ -2450,18 +2270,18 @@ } }, "node_modules/css-loader": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", - "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.2.tgz", + "integrity": "sha512-oqGbbVcBJkm8QwmnNzrFrWTnudnRZC+1eXikLJl0n4ljcfotgRifpg2a1lKy8jTrc4/d9A/ap1GFq1jDKG7J+Q==", "dependencies": { "icss-utils": "^5.1.0", - "postcss": "^8.4.7", + "postcss": "^8.4.18", "postcss-modules-extract-imports": "^3.0.0", "postcss-modules-local-by-default": "^4.0.0", "postcss-modules-scope": "^3.0.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", - "semver": "^7.3.5" + "semver": "^7.3.8" }, "engines": { "node": ">= 12.13.0" @@ -3308,9 +3128,9 @@ } }, "node_modules/decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", "dev": true, "dependencies": { "decamelize": "^1.1.0", @@ -3318,6 +3138,9 @@ }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/decamelize-keys/node_modules/map-obj": { @@ -3336,15 +3159,15 @@ "dev": true }, "node_modules/deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.2.tgz", + "integrity": "sha512-gT18+YW4CcW/DBNTwAmqTtkJh7f9qqScu2qFVlx7kCoeY9tlBu9cUcr7+I+Z/noG8INehS3xQgLpTtd/QUTn4w==", "dev": true, "dependencies": { "type-detect": "^4.0.0" }, "engines": { - "node": ">=0.12" + "node": ">=6" } }, "node_modules/deep-extend": { @@ -3775,17 +3598,17 @@ } }, "node_modules/es-aggregate-error": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.8.tgz", - "integrity": "sha512-AKUb5MKLWMozPlFRHOKqWD7yta5uaEhH21qwtnf6FlKjNjTJOoqFi0/G14+FfSkIQhhu6X68Af4xgRC6y8qG4A==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.9.tgz", + "integrity": "sha512-fvnX40sb538wdU6r4s35cq4EY6Lr09Upj40BEVem4LEsuW8XgQep9yD5Q1U2KftokNp1rWODFJ2qwZSsAjFpbg==", "dev": true, "dependencies": { "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", + "es-abstract": "^1.20.4", "function-bind": "^1.1.1", "functions-have-names": "^1.2.3", - "get-intrinsic": "^1.1.1", - "globalthis": "^1.0.2", + "get-intrinsic": "^1.1.3", + "globalthis": "^1.0.3", "has-property-descriptors": "^1.0.0" }, "engines": { @@ -3827,9 +3650,9 @@ } }, "node_modules/esbuild": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.12.tgz", - "integrity": "sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.14.tgz", + "integrity": "sha512-pJN8j42fvWLFWwSMG4luuupl2Me7mxciUOsMegKvwCmhEbJ2covUdFnihxm0FMIBV+cbwbtMoHgMCCI+pj1btQ==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -3838,34 +3661,34 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.15.12", - "@esbuild/linux-loong64": "0.15.12", - "esbuild-android-64": "0.15.12", - "esbuild-android-arm64": "0.15.12", - "esbuild-darwin-64": "0.15.12", - "esbuild-darwin-arm64": "0.15.12", - "esbuild-freebsd-64": "0.15.12", - "esbuild-freebsd-arm64": "0.15.12", - "esbuild-linux-32": "0.15.12", - "esbuild-linux-64": "0.15.12", - "esbuild-linux-arm": "0.15.12", - "esbuild-linux-arm64": "0.15.12", - "esbuild-linux-mips64le": "0.15.12", - "esbuild-linux-ppc64le": "0.15.12", - "esbuild-linux-riscv64": "0.15.12", - "esbuild-linux-s390x": "0.15.12", - "esbuild-netbsd-64": "0.15.12", - "esbuild-openbsd-64": "0.15.12", - "esbuild-sunos-64": "0.15.12", - "esbuild-windows-32": "0.15.12", - "esbuild-windows-64": "0.15.12", - "esbuild-windows-arm64": "0.15.12" + "@esbuild/android-arm": "0.15.14", + "@esbuild/linux-loong64": "0.15.14", + "esbuild-android-64": "0.15.14", + "esbuild-android-arm64": "0.15.14", + "esbuild-darwin-64": "0.15.14", + "esbuild-darwin-arm64": "0.15.14", + "esbuild-freebsd-64": "0.15.14", + "esbuild-freebsd-arm64": "0.15.14", + "esbuild-linux-32": "0.15.14", + "esbuild-linux-64": "0.15.14", + "esbuild-linux-arm": "0.15.14", + "esbuild-linux-arm64": "0.15.14", + "esbuild-linux-mips64le": "0.15.14", + "esbuild-linux-ppc64le": "0.15.14", + "esbuild-linux-riscv64": "0.15.14", + "esbuild-linux-s390x": "0.15.14", + "esbuild-netbsd-64": "0.15.14", + "esbuild-openbsd-64": "0.15.14", + "esbuild-sunos-64": "0.15.14", + "esbuild-windows-32": "0.15.14", + "esbuild-windows-64": "0.15.14", + "esbuild-windows-arm64": "0.15.14" } }, "node_modules/esbuild-android-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.12.tgz", - "integrity": "sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.14.tgz", + "integrity": "sha512-HuilVIb4rk9abT4U6bcFdU35UHOzcWVGLSjEmC58OVr96q5UiRqzDtWjPlCMugjhgUGKEs8Zf4ueIvYbOStbIg==", "cpu": [ "x64" ], @@ -3878,9 +3701,9 @@ } }, "node_modules/esbuild-android-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.12.tgz", - "integrity": "sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.14.tgz", + "integrity": "sha512-/QnxRVxsR2Vtf3XottAHj7hENAMW2wCs6S+OZcAbc/8nlhbAL/bCQRCVD78VtI5mdwqWkVi3wMqM94kScQCgqg==", "cpu": [ "arm64" ], @@ -3893,9 +3716,9 @@ } }, "node_modules/esbuild-darwin-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.12.tgz", - "integrity": "sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.14.tgz", + "integrity": "sha512-ToNuf1uifu8hhwWvoZJGCdLIX/1zpo8cOGnT0XAhDQXiKOKYaotVNx7pOVB1f+wHoWwTLInrOmh3EmA7Fd+8Vg==", "cpu": [ "x64" ], @@ -3908,9 +3731,9 @@ } }, "node_modules/esbuild-darwin-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.12.tgz", - "integrity": "sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.14.tgz", + "integrity": "sha512-KgGP+y77GszfYJgceO0Wi/PiRtYo5y2Xo9rhBUpxTPaBgWDJ14gqYN0+NMbu+qC2fykxXaipHxN4Scaj9tUS1A==", "cpu": [ "arm64" ], @@ -3923,9 +3746,9 @@ } }, "node_modules/esbuild-freebsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.12.tgz", - "integrity": "sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.14.tgz", + "integrity": "sha512-xr0E2n5lyWw3uFSwwUXHc0EcaBDtsal/iIfLioflHdhAe10KSctV978Te7YsfnsMKzcoGeS366+tqbCXdqDHQA==", "cpu": [ "x64" ], @@ -3938,9 +3761,9 @@ } }, "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.12.tgz", - "integrity": "sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.14.tgz", + "integrity": "sha512-8XH96sOQ4b1LhMlO10eEWOjEngmZ2oyw3pW4o8kvBcpF6pULr56eeYVP5radtgw54g3T8nKHDHYEI5AItvskZg==", "cpu": [ "arm64" ], @@ -3953,9 +3776,9 @@ } }, "node_modules/esbuild-linux-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.12.tgz", - "integrity": "sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.14.tgz", + "integrity": "sha512-6ssnvwaTAi8AzKN8By2V0nS+WF5jTP7SfuK6sStGnDP7MCJo/4zHgM9oE1eQTS2jPmo3D673rckuCzRlig+HMA==", "cpu": [ "ia32" ], @@ -3968,9 +3791,9 @@ } }, "node_modules/esbuild-linux-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.12.tgz", - "integrity": "sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.14.tgz", + "integrity": "sha512-ONySx3U0wAJOJuxGUlXBWxVKFVpWv88JEv0NZ6NlHknmDd1yCbf4AEdClSgLrqKQDXYywmw4gYDvdLsS6z0hcw==", "cpu": [ "x64" ], @@ -3983,9 +3806,9 @@ } }, "node_modules/esbuild-linux-arm": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.12.tgz", - "integrity": "sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.14.tgz", + "integrity": "sha512-D2LImAIV3QzL7lHURyCHBkycVFbKwkDb1XEUWan+2fb4qfW7qAeUtul7ZIcIwFKZgPcl+6gKZmvLgPSj26RQ2Q==", "cpu": [ "arm" ], @@ -3998,9 +3821,9 @@ } }, "node_modules/esbuild-linux-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.12.tgz", - "integrity": "sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.14.tgz", + "integrity": "sha512-kle2Ov6a1e5AjlHlMQl1e+c4myGTeggrRzArQFmWp6O6JoqqB9hT+B28EW4tjFWgV/NxUq46pWYpgaWXsXRPAg==", "cpu": [ "arm64" ], @@ -4013,9 +3836,9 @@ } }, "node_modules/esbuild-linux-mips64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.12.tgz", - "integrity": "sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.14.tgz", + "integrity": "sha512-FVdMYIzOLXUq+OE7XYKesuEAqZhmAIV6qOoYahvUp93oXy0MOVTP370ECbPfGXXUdlvc0TNgkJa3YhEwyZ6MRA==", "cpu": [ "mips64el" ], @@ -4028,9 +3851,9 @@ } }, "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.12.tgz", - "integrity": "sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.14.tgz", + "integrity": "sha512-2NzH+iuzMDA+jjtPjuIz/OhRDf8tzbQ1tRZJI//aT25o1HKc0reMMXxKIYq/8nSHXiJSnYV4ODzTiv45s+h73w==", "cpu": [ "ppc64" ], @@ -4043,9 +3866,9 @@ } }, "node_modules/esbuild-linux-riscv64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.12.tgz", - "integrity": "sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.14.tgz", + "integrity": "sha512-VqxvutZNlQxmUNS7Ac+aczttLEoHBJ9e3OYGqnULrfipRvG97qLrAv9EUY9iSrRKBqeEbSvS9bSfstZqwz0T4Q==", "cpu": [ "riscv64" ], @@ -4058,9 +3881,9 @@ } }, "node_modules/esbuild-linux-s390x": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.12.tgz", - "integrity": "sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.14.tgz", + "integrity": "sha512-+KVHEUshX5n6VP6Vp/AKv9fZIl5kr2ph8EUFmQUJnDpHwcfTSn2AQgYYm0HTBR2Mr4d0Wlr0FxF/Cs5pbFgiOw==", "cpu": [ "s390x" ], @@ -4092,9 +3915,9 @@ } }, "node_modules/esbuild-netbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.12.tgz", - "integrity": "sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.14.tgz", + "integrity": "sha512-6D/dr17piEgevIm1xJfZP2SjB9Z+g8ERhNnBdlZPBWZl+KSPUKLGF13AbvC+nzGh8IxOH2TyTIdRMvKMP0nEzQ==", "cpu": [ "x64" ], @@ -4107,9 +3930,9 @@ } }, "node_modules/esbuild-openbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.12.tgz", - "integrity": "sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.14.tgz", + "integrity": "sha512-rREQBIlMibBetgr2E9Lywt2Qxv2ZdpmYahR4IUlAQ1Efv/A5gYdO0/VIN3iowDbCNTLxp0bb57Vf0LFcffD6kA==", "cpu": [ "x64" ], @@ -4122,9 +3945,9 @@ } }, "node_modules/esbuild-sunos-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.12.tgz", - "integrity": "sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.14.tgz", + "integrity": "sha512-DNVjSp/BY4IfwtdUAvWGIDaIjJXY5KI4uD82+15v6k/w7px9dnaDaJJ2R6Mu+KCgr5oklmFc0KjBjh311Gxl9Q==", "cpu": [ "x64" ], @@ -4137,9 +3960,9 @@ } }, "node_modules/esbuild-windows-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.12.tgz", - "integrity": "sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.14.tgz", + "integrity": "sha512-pHBWrcA+/oLgvViuG9FO3kNPO635gkoVrRQwe6ZY1S0jdET07xe2toUvQoJQ8KT3/OkxqUasIty5hpuKFLD+eg==", "cpu": [ "ia32" ], @@ -4152,9 +3975,9 @@ } }, "node_modules/esbuild-windows-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.12.tgz", - "integrity": "sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.14.tgz", + "integrity": "sha512-CszIGQVk/P8FOS5UgAH4hKc9zOaFo69fe+k1rqgBHx3CSK3Opyk5lwYriIamaWOVjBt7IwEP6NALz+tkVWdFog==", "cpu": [ "x64" ], @@ -4167,9 +3990,9 @@ } }, "node_modules/esbuild-windows-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.12.tgz", - "integrity": "sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.14.tgz", + "integrity": "sha512-KW9W4psdZceaS9A7Jsgl4WialOznSURvqX/oHZk3gOP7KbjtHLSsnmSvNdzagGJfxbAe30UVGXRe8q8nDsOSQw==", "cpu": [ "arm64" ], @@ -4286,9 +4109,9 @@ } }, "node_modules/eslint": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", - "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", + "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", "dev": true, "dependencies": { "@eslint/eslintrc": "^1.3.3", @@ -4462,24 +4285,26 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "44.0.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-44.0.2.tgz", - "integrity": "sha512-GLIDX1wmeEqpGaKcnMcqRvMVsoabeF0Ton0EX4Th5u6Kmf7RM9WBl705AXFEsns56ESkEs0uyelLuUTvz9Tr0w==", + "version": "45.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.0.tgz", + "integrity": "sha512-iP8cMRxXKHonKioOhnCoCcqVhoqhAp6rB+nsoLjXFDxTHz3btWMAp8xwzjHA0B1K6YV/U/Yvqn1bUXZt8sJPuQ==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.19.1", - "ci-info": "^3.4.0", + "ci-info": "^3.6.1", "clean-regexp": "^1.0.0", "eslint-utils": "^3.0.0", "esquery": "^1.4.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.0", + "jsesc": "3.0.2", "lodash": "^4.17.21", "pluralize": "^8.0.0", "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.24", + "regjsparser": "0.9.1", "safe-regex": "^2.1.1", - "semver": "^7.3.7", + "semver": "^7.3.8", "strip-indent": "^3.0.0" }, "engines": { @@ -4489,13 +4314,13 @@ "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": ">=8.23.1" + "eslint": ">=8.28.0" } }, "node_modules/eslint-plugin-vue": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.6.0.tgz", - "integrity": "sha512-zzySkJgVbFCylnG2+9MDF7N+2Rjze2y0bF8GyUNpFOnT8mCMfqqtLDJkHBuYu9N/psW1A6DVbQhPkP92E+qakA==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.7.0.tgz", + "integrity": "sha512-DrOO3WZCZEwcLsnd3ohFwqCoipGRSTKTBTnLwdhqAbYZtzWl0o7D+D8ZhlmiZvABKTEl8AFsqH1GHGdybyoQmw==", "dev": true, "dependencies": { "eslint-utils": "^3.0.0", @@ -4585,9 +4410,9 @@ "dev": true }, "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "dependencies": { "acorn": "^8.8.0", @@ -4676,6 +4501,11 @@ "node": ">=0.8.x" } }, + "node_modules/fast-clone": { + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/fast-clone/-/fast-clone-1.5.13.tgz", + "integrity": "sha512-0ez7coyFBQFjZtId+RJqJ+EQs61w9xARfqjqK0AD9vIUkSxWD4HvPt80+5evebZ1tTnv1GYKrPTipx7kOW5ipA==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5098,9 +4928,9 @@ } }, "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -5510,11 +5340,11 @@ } }, "node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, "node_modules/ip": { @@ -5883,18 +5713,18 @@ } }, "node_modules/jsdom": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.1.tgz", - "integrity": "sha512-pksjj7Rqoa+wdpkKcLzQRHhJCEE42qQhl/xLMUKHgoSejaKOdaXEAnqs6uDNwMl/fciHTzKeR8Wm8cw7N+g98A==", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", "dev": true, "dependencies": { "abab": "^2.0.6", - "acorn": "^8.8.0", + "acorn": "^8.8.1", "acorn-globals": "^7.0.0", "cssom": "^0.5.0", "cssstyle": "^2.3.0", "data-urls": "^3.0.2", - "decimal.js": "^10.4.1", + "decimal.js": "^10.4.2", "domexception": "^4.0.0", "escodegen": "^2.0.0", "form-data": "^4.0.0", @@ -5907,12 +5737,12 @@ "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^3.0.0", + "w3c-xmlserializer": "^4.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^2.0.0", "whatwg-mimetype": "^3.0.0", "whatwg-url": "^11.0.0", - "ws": "^8.9.0", + "ws": "^8.11.0", "xml-name-validator": "^4.0.0" }, "engines": { @@ -5936,6 +5766,18 @@ "node": ">= 10.16.0" } }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -6038,9 +5880,9 @@ } }, "node_modules/known-css-properties": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz", - "integrity": "sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.26.0.tgz", + "integrity": "sha512-5FZRzrZzNTBruuurWpvZnvP9pum+fe0HcK8z/ooo+U+Hmp4vtbyp1/QDsqmufirXy4egGzbaH/y2uCZf+6W5Kg==", "dev": true }, "node_modules/less": { @@ -6231,24 +6073,12 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==" }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==", - "dev": true - }, "node_modules/lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -6279,9 +6109,9 @@ "dev": true }, "node_modules/loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", "dev": true, "dependencies": { "get-func-name": "^2.0.0" @@ -6455,9 +6285,9 @@ } }, "node_modules/marked": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz", - "integrity": "sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.3.tgz", + "integrity": "sha512-slWRdJkbTZ+PjkyJnE30Uid64eHwbwa1Q25INCAYfZlK4o6ylagBy/Le9eWntqJFoFT93ikUKMv47GZ4gTwHkw==", "bin": { "marked": "bin/marked.js" }, @@ -6584,19 +6414,23 @@ } }, "node_modules/mermaid": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.1.7.tgz", - "integrity": "sha512-MRVHXy5FLjnUQUG7YS3UN9jEN6FXCJbFCXVGJQjVIbiR6Vhw0j/6pLIjqsiah9xoHmQU6DEaKOvB3S1g/1nBPA==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.2.2.tgz", + "integrity": "sha512-6s7eKMqFJGS+0MYjmx8f6ZigqKBJVoSx5ql2gw6a4Aa+WJ49QiEJg7gPwywaBg3DZMs79UP7trESp4+jmaQccw==", "dependencies": { "@braintree/sanitize-url": "^6.0.0", "d3": "^7.0.0", "dagre": "^0.8.5", "dagre-d3": "^0.6.4", "dompurify": "2.4.0", + "fast-clone": "^1.5.13", "graphlib": "^2.1.8", "khroma": "^2.0.0", - "moment-mini": "2.24.0", - "stylis": "^4.0.10" + "lodash": "^4.17.21", + "moment-mini": "^2.24.0", + "non-layered-tidy-tree-layout": "^2.0.2", + "stylis": "^4.1.2", + "uuid": "^9.0.0" } }, "node_modules/micromatch": { @@ -6652,9 +6486,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", - "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.0.tgz", + "integrity": "sha512-auqtVo8KhTScMsba7MbijqZTfibbXiBNlPAQbsVt7enQfcDYLdgG57eGxMqwVU3mfeWANY4F1wUg+rMF+ycZgw==", "dependencies": { "schema-utils": "^4.0.0" }, @@ -6704,9 +6538,9 @@ } }, "node_modules/moment-mini": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.24.0.tgz", - "integrity": "sha512-9ARkWHBs+6YJIvrIp0Ik5tyTTtP9PoV0Ssu2Ocq5y9v8+NOOpWiRshAp8c4rZVWTOe+157on/5G+zj5pwIQFEQ==" + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.29.4.tgz", + "integrity": "sha512-uhXpYwHFeiTbY9KSgPPRoo1nt8OxNVdMVoTBYHfSEKeRkIkwGpO+gERmhuhBtzfaeOyTkykSrm2+noJBgqt3Hg==" }, "node_modules/monaco-editor": { "version": "0.34.1", @@ -6726,9 +6560,9 @@ } }, "node_modules/moo": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", - "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==" + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==" }, "node_modules/ms": { "version": "2.1.2", @@ -6754,9 +6588,9 @@ "dev": true }, "node_modules/needle": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.1.0.tgz", - "integrity": "sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", "optional": true, "dependencies": { "debug": "^3.2.6", @@ -6865,6 +6699,11 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, + "node_modules/non-layered-tidy-tree-layout": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", + "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==" + }, "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -6958,14 +6797,14 @@ } }, "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" @@ -7299,9 +7138,9 @@ } }, "node_modules/playwright-core": { - "version": "1.27.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.27.1.tgz", - "integrity": "sha512-9EmeXDncC2Pmp/z+teoVYlvmPWUC6ejSSYZUln7YaP89Z6lpAaiaAnqroUt/BoLo8tn7WYShcfaCh+xofZa44Q==", + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz", + "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==", "dev": true, "bin": { "playwright": "cli.js" @@ -7329,9 +7168,9 @@ } }, "node_modules/postcss": { - "version": "8.4.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", - "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", + "version": "8.4.19", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", + "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", "funding": [ { "type": "opencollective", @@ -7447,9 +7286,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -7744,14 +7583,14 @@ } }, "node_modules/rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dependencies": { - "resolve": "^1.9.0" + "resolve": "^1.20.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/redent": { @@ -7805,6 +7644,27 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8373,28 +8233,28 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8463,15 +8323,15 @@ "dev": true }, "node_modules/stylelint": { - "version": "14.14.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.14.0.tgz", - "integrity": "sha512-yUI+4xXfPHVnueYddSQ/e1GuEA/2wVhWQbGj16AmWLtQJtn28lVxfS4b0CsWyVRPgd3Auzi0NXOthIEUhtQmmA==", + "version": "14.15.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.15.0.tgz", + "integrity": "sha512-JOgDAo5QRsqiOZPZO+B9rKJvBm64S0xasbuRPAbPs6/vQDgDCnZLIiw6XcAS6GQKk9k1sBWR6rmH3Mfj8OknKg==", "dev": true, "dependencies": { "@csstools/selector-specificity": "^2.0.2", "balanced-match": "^2.0.0", "colord": "^2.9.3", - "cosmiconfig": "^7.0.1", + "cosmiconfig": "^7.1.0", "css-functions-list": "^3.1.0", "debug": "^4.3.4", "fast-glob": "^3.2.12", @@ -8485,13 +8345,13 @@ "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.25.0", + "known-css-properties": "^0.26.0", "mathml-tag-names": "^2.1.3", "meow": "^9.0.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.17", + "postcss": "^8.4.19", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", @@ -8503,7 +8363,7 @@ "style-search": "^0.1.0", "supports-hyperlinks": "^2.3.0", "svg-tags": "^1.0.0", - "table": "^6.8.0", + "table": "^6.8.1", "v8-compile-cache": "^2.3.0", "write-file-atomic": "^4.0.2" }, @@ -8555,9 +8415,9 @@ } }, "node_modules/stylis": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.2.tgz", - "integrity": "sha512-Nn2CCrG2ZaFziDxaZPN43CXqn+j7tcdjPFCkRBkFue8QYXC2HdEwnw5TCBo4yQZ2WxKYeSi0fdoOrtEqgDrXbA==" + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", + "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" }, "node_modules/superstruct": { "version": "0.10.13", @@ -8606,9 +8466,9 @@ "dev": true }, "node_modules/svgo": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.0.tgz", - "integrity": "sha512-mSqPn6RDeNqJvCeqHERlfWJjd4crP/2PgFelil9WpTwC4D3okAUopPsH3lnEyl7ONXfDVyISOihDjO0uK8YVAA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", + "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", "dev": true, "dependencies": { "@trysound/sax": "0.2.0", @@ -8639,9 +8499,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.15.0.tgz", - "integrity": "sha512-vAsIdNHraLuBRm1vrxcMaLk/y/PGBTvHLf4lQGQ3LaEXkORtIxw11sBMpYJL3keOLaFJ1OqNXuURd6eShoFLZQ==" + "version": "4.15.5", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.15.5.tgz", + "integrity": "sha512-V3eIa28lwB6gg7/wfNvAbjwJYmDXy1Jo1POjyTzlB6wPcHiGlRxq39TSjYGVjQrUSAzpv+a7nzp7mDxgNy57xA==" }, "node_modules/symbol-tree": { "version": "3.2.4", @@ -8662,9 +8522,9 @@ } }, "node_modules/table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, "dependencies": { "ajv": "^8.0.1", @@ -8918,9 +8778,9 @@ } }, "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "node_modules/type-check": { "version": "0.4.0", @@ -9030,9 +8890,9 @@ } }, "node_modules/updates": { - "version": "13.1.10", - "resolved": "https://registry.npmjs.org/updates/-/updates-13.1.10.tgz", - "integrity": "sha512-YSt1ncMoBXAQZndhLwiywvEGHXmA4424SlAf2HMUDuf8qE9Tlqj0s6IANb388HrjkybdZJkaadLSg/hkigwnuQ==", + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/updates/-/updates-13.2.1.tgz", + "integrity": "sha512-d+nIbU2fl/PDEvUkbQch4uRdkXt9AQoPlH6b/FPTOAzF9voGbXgZNNxgO79Jeish24ZMfOqUl5lJcKSwMO2RJQ==", "dev": true, "bin": { "updates": "bin/updates.js" @@ -9079,6 +8939,14 @@ "node": ">= 4" } }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -9105,15 +8973,15 @@ } }, "node_modules/vite": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.1.8.tgz", - "integrity": "sha512-m7jJe3nufUbuOfotkntGFupinL/fmuTNuQmiVE7cH2IZMuf4UbfbGYMUT3jVWgGYuRVLY9j8NnrRqgw5rr5QTg==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.4.tgz", + "integrity": "sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==", "dev": true, "dependencies": { "esbuild": "^0.15.9", - "postcss": "^8.4.16", + "postcss": "^8.4.18", "resolve": "^1.22.1", - "rollup": "~2.78.0" + "rollup": "^2.79.1" }, "bin": { "vite": "bin/vite.js" @@ -9125,12 +8993,17 @@ "fsevents": "~2.3.2" }, "peerDependencies": { + "@types/node": ">= 14", "less": "*", "sass": "*", "stylus": "*", + "sugarss": "*", "terser": "^5.4.0" }, "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, "less": { "optional": true }, @@ -9140,40 +9013,31 @@ "stylus": { "optional": true }, + "sugarss": { + "optional": true + }, "terser": { "optional": true } } }, - "node_modules/vite/node_modules/rollup": { - "version": "2.78.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz", - "integrity": "sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/vitest": { - "version": "0.24.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.24.3.tgz", - "integrity": "sha512-aM0auuPPgMSstWvr851hB74g/LKaKBzSxcG3da7ejfZbx08Y21JpZmbmDYrMTCGhVZKqTGwzcnLMwyfz2WzkhQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.25.2.tgz", + "integrity": "sha512-qqkzfzglEFbQY7IGkgSJkdOhoqHjwAao/OrphnHboeYHC5JzsVFoLCaB2lnAy8krhj7sbrFTVRApzpkTOeuDWQ==", "dev": true, "dependencies": { "@types/chai": "^4.3.3", "@types/chai-subset": "^1.3.3", "@types/node": "*", + "acorn": "^8.8.0", + "acorn-walk": "^8.2.0", "chai": "^4.3.6", "debug": "^4.3.4", "local-pkg": "^0.4.2", + "source-map": "^0.6.1", "strip-literal": "^0.4.2", - "tinybench": "^2.3.0", + "tinybench": "^2.3.1", "tinypool": "^0.3.0", "tinyspy": "^1.0.2", "vite": "^3.0.0" @@ -9229,15 +9093,15 @@ } }, "node_modules/vue": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.41.tgz", - "integrity": "sha512-uuuvnrDXEeZ9VUPljgHkqB5IaVO8SxhPpqF2eWOukVrBnRBx2THPSGQBnVRt0GrIG1gvCmFXMGbd7FqcT1ixNQ==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.45.tgz", + "integrity": "sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==", "dependencies": { - "@vue/compiler-dom": "3.2.41", - "@vue/compiler-sfc": "3.2.41", - "@vue/runtime-dom": "3.2.41", - "@vue/server-renderer": "3.2.41", - "@vue/shared": "3.2.41" + "@vue/compiler-dom": "3.2.45", + "@vue/compiler-sfc": "3.2.45", + "@vue/runtime-dom": "3.2.45", + "@vue/server-renderer": "3.2.45", + "@vue/shared": "3.2.45" } }, "node_modules/vue-bar-graph": { @@ -9274,9 +9138,9 @@ } }, "node_modules/vue-loader": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.0.0.tgz", - "integrity": "sha512-OWSXjrzIvbF2LtOUmxT3HYgwwubbfFelN8PAP9R9dwpIkj48TVioHhWWSx7W7fk+iF5cgg3CBJRxwTdtLU4Ecg==", + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.0.1.tgz", + "integrity": "sha512-/OOyugJnImKCkAKrAvdsWMuwoCqGxWT5USLsjohzWbMgOwpA5wQmzQiLMzZd7DjhIfunzAGIApTOgIylz/kwcg==", "dependencies": { "chalk": "^4.1.0", "hash-sum": "^2.0.0", @@ -9284,6 +9148,14 @@ }, "peerDependencies": { "webpack": "^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + }, + "vue": { + "optional": true + } } }, "node_modules/vue3-calendar-heatmap": { @@ -9301,15 +9173,15 @@ } }, "node_modules/w3c-xmlserializer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", - "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", "dev": true, "dependencies": { "xml-name-validator": "^4.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/watchpack": { @@ -9334,9 +9206,9 @@ } }, "node_modules/webpack": { - "version": "5.74.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", - "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", @@ -9380,43 +9252,41 @@ } }, "node_modules/webpack-cli": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", - "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.0.tgz", + "integrity": "sha512-AACDTo20yG+xn6HPW5xjbn2Be4KUzQPebWXsDMHwPPyKh9OnTOJgZN2Nc+g/FZKV3ObRTYsGvibAvc+5jAUrVA==", "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.2.0", - "@webpack-cli/info": "^1.5.0", - "@webpack-cli/serve": "^1.7.0", + "@webpack-cli/configtest": "^2.0.0", + "@webpack-cli/info": "^2.0.0", + "@webpack-cli/serve": "^2.0.0", "colorette": "^2.0.14", - "commander": "^7.0.0", + "commander": "^9.4.1", "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", "webpack-merge": "^5.7.3" }, "bin": { "webpack-cli": "bin/cli.js" }, "engines": { - "node": ">=10.13.0" + "node": ">=14.15.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "4.x.x || 5.x.x" + "webpack": "5.x.x" }, "peerDependenciesMeta": { "@webpack-cli/generators": { "optional": true }, - "@webpack-cli/migrate": { - "optional": true - }, "webpack-bundle-analyzer": { "optional": true }, @@ -9426,11 +9296,11 @@ } }, "node_modules/webpack-cli/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", "engines": { - "node": ">= 10" + "node": "^12.20.0 || >=14" } }, "node_modules/webpack-merge": { @@ -9790,9 +9660,9 @@ } }, "node_modules/ws": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", - "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, "engines": { "node": ">=10.0.0" @@ -9999,14 +9869,14 @@ } }, "@babel/parser": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", - "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==" + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", + "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==" }, "@braintree/sanitize-url": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.1.tgz", - "integrity": "sha512-zr9Qs9KFQiEvMWdZesjcmRJlUck5NR+eKGS1uyKk+oYTWwlYrsoPEi6VmG6/TzBD1hKCGEimrhTgGS6hvn/xIQ==" + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz", + "integrity": "sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg==" }, "@citation-js/core": { "version": "0.6.1", @@ -10040,9 +9910,9 @@ } }, "@citation-js/plugin-csl": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.3.tgz", - "integrity": "sha512-SP1/QyHfhcNufQ6VTJUM04Ti0XEWSWYMUhkDGG2lQtnDJU7pSDeAwtsE1kYUIJ9Np0Gm8IEZAfJ3CslMfsbimg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.4.tgz", + "integrity": "sha512-RG4NrFIx0CZTfNeMCC8CL7UGFRiUv5/bNd/Nc6Q/NHx0cS/tYDQcKt0M24dpOI7PAZwVoddbDW4Iakn6nS4QsQ==", "requires": { "@citation-js/date": "^0.5.0", "citeproc": "^2.4.6" @@ -10077,15 +9947,15 @@ "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" }, "@esbuild/android-arm": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.12.tgz", - "integrity": "sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.14.tgz", + "integrity": "sha512-+Rb20XXxRGisNu2WmNKk+scpanb7nL5yhuI1KR9wQFiC43ddPj/V1fmNyzlFC9bKiG4mYzxW7egtoHVcynr+OA==", "optional": true }, "@esbuild/linux-loong64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.12.tgz", - "integrity": "sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.14.tgz", + "integrity": "sha512-eQi9rosGNVQFJyJWV0HCA5WZae/qWIQME7s8/j8DMvnylfBv62Pbu+zJ2eUDqNf2O4u3WB+OEXyfkpBoe194sg==", "optional": true }, "@eslint/eslintrc": { @@ -10126,14 +9996,14 @@ } }, "@humanwhocodes/config-array": { - "version": "0.11.6", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.6.tgz", - "integrity": "sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==", + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", + "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" } }, "@humanwhocodes/module-importer": { @@ -10242,13 +10112,13 @@ } }, "@playwright/test": { - "version": "1.27.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.27.1.tgz", - "integrity": "sha512-mrL2q0an/7tVqniQQF6RBL2saskjljXzqNcCOVMUjRIgE6Y38nCNaP+Dc2FBW06bcpD3tqIws/HT9qiMHbNU0A==", + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz", + "integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==", "dev": true, "requires": { "@types/node": "*", - "playwright-core": "1.27.1" + "playwright-core": "1.28.0" } }, "@popperjs/core": { @@ -10257,17 +10127,17 @@ "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" }, "@primer/octicons": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.7.0.tgz", - "integrity": "sha512-J5cVJDhExmqLGLWu8zHTOqcC8g1rQL7QzQZdbvHxW85u8ya82GtF5F68uHMDI5En3fsMlbkkF8Rz6dCaV3r+KA==", + "version": "17.9.0", + "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.9.0.tgz", + "integrity": "sha512-B6y3VxPrF6U+GUjZR883NsstI7v/Qcup9puDG+fOJvCm8b7UXNl46TbRrctMCZnYlyIzUF3/SgjJhr5od/Y6sw==", "requires": { "object-assign": "^4.1.1" } }, "@rollup/plugin-commonjs": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-20.0.0.tgz", - "integrity": "sha512-5K0g5W2Ol8hAcTHqcTBHiA7M58tfmYi1o9KxeJuuRNpGaTa5iLjcyemBitCBcKXaHamOBBEH2dGom6v6Unmqjg==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.2.tgz", + "integrity": "sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -10328,13 +10198,14 @@ } }, "@stoplight/json": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.17.0.tgz", - "integrity": "sha512-WW0z2bb0D4t8FTl+zNTCu46J8lEOsrUhBPgwEYQ3Ri2Y0MiRE4U1/9ZV8Ki+pIJznZgY9i42bbFwOBxyZn5/6w==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.20.1.tgz", + "integrity": "sha512-FXfud+uWgIj1xv6nUO9WnmgmnVikaxJcbtR4XQt4C42n5c2qua3U05Z/3B57hP5TJRSj+tpn9ID6/bFeyYYlEg==", "dev": true, "requires": { - "@stoplight/ordered-object-literal": "^1.0.2", - "@stoplight/types": "^12.3.0", + "@stoplight/ordered-object-literal": "^1.0.3", + "@stoplight/path": "^1.3.2", + "@stoplight/types": "^13.6.0", "jsonc-parser": "~2.2.1", "lodash": "^4.17.21", "safe-stable-stringify": "^1.1" @@ -10359,22 +10230,21 @@ } }, "@stoplight/json-ref-resolver": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.3.tgz", - "integrity": "sha512-SgoKXwVnlpIZUyAFX4W79eeuTWvXmNlMfICZixL16GZXnkjcW+uZnfmAU0ZIjcnaTgaI4mjfxn8LAP2KR6Cr0A==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.4.tgz", + "integrity": "sha512-842JVmMsi++qpDuIX+JpQvK7YY8FXEZZb+/z4xuRfStOAVEryJT/tbgGOWxniSdxEl9Eni5D/I2afMyy6BuiNw==", "dev": true, "requires": { "@stoplight/json": "^3.17.0", "@stoplight/path": "^1.3.2", - "@stoplight/types": "^12.3.0", - "@types/urijs": "^1.19.16", + "@stoplight/types": "^12.3.0 || ^13.0.0", + "@types/urijs": "^1.19.19", "dependency-graph": "~0.11.0", "fast-memoize": "^2.5.2", "immer": "^9.0.6", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", + "lodash": "^4.17.21", "tslib": "^2.3.1", - "urijs": "^1.19.6" + "urijs": "^1.19.11" } }, "@stoplight/ordered-object-literal": { @@ -10390,22 +10260,21 @@ "dev": true }, "@stoplight/spectral-cli": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.5.1.tgz", - "integrity": "sha512-+qpwsDG2jQ4ULQmegBWonI3UnF6tUh351WDnV1GU8acl8eaeKbS+ZUNBgoP2f9tnMTfITdctVRFEGC3D6P7f9g==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.6.0.tgz", + "integrity": "sha512-z46fnrvraaWMio8Y9RYYkLO+XdmtxOWpy5qNJF3CsmWua0FZ4iOTryb5Cm3GkB0wEtqxNUCBUHvoo4hS6Noyqg==", "dev": true, "requires": { - "@rollup/plugin-commonjs": "^20.0.0", - "@stoplight/json": "3.17.0", + "@stoplight/json": "~3.20.1", "@stoplight/path": "1.3.2", - "@stoplight/spectral-core": "^1.5.1", - "@stoplight/spectral-parsers": "^1.0.1", - "@stoplight/spectral-ref-resolver": "1.0.1", - "@stoplight/spectral-ruleset-bundler": "^1.0.0", - "@stoplight/spectral-ruleset-migrator": "^1.5.0", + "@stoplight/spectral-core": "^1.15.1", + "@stoplight/spectral-parsers": "^1.0.2", + "@stoplight/spectral-ref-resolver": "1.0.2", + "@stoplight/spectral-ruleset-bundler": "^1.4.0", + "@stoplight/spectral-ruleset-migrator": "^1.9.0", "@stoplight/spectral-rulesets": ">=1", - "@stoplight/spectral-runtime": "^1.1.0", - "@stoplight/types": "12.3.0", + "@stoplight/spectral-runtime": "^1.1.2", + "@stoplight/types": "^13.6.0", "chalk": "4.1.2", "cliui": "7.0.4", "eol": "0.9.1", @@ -10445,9 +10314,9 @@ } }, "@stoplight/spectral-core": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.15.0.tgz", - "integrity": "sha512-+DwK8SmnujMZJaxJeNU11vWY+DFOnt4oQM1TzAuvufdd3Y6Lsno88Jl31OaR1M9Fn7l/u3v1anBB/SSl/fI5rQ==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.15.1.tgz", + "integrity": "sha512-IZV8L1Hyz9759KdqJIA90W5uvurHplMmaPPIZjQzG2Bq/39kN/sbLA/Js8uOf3xB9cHBbG599t4AB+uGsI8t0g==", "dev": true, "requires": { "@stoplight/better-ajv-errors": "1.0.3", @@ -10462,7 +10331,6 @@ "ajv": "^8.6.0", "ajv-errors": "~3.0.0", "ajv-formats": "~2.1.0", - "blueimp-md5": "2.18.0", "es-aggregate-error": "^1.0.7", "jsonpath-plus": "7.1.0", "lodash": "~4.17.21", @@ -10474,20 +10342,6 @@ "tslib": "^2.3.0" }, "dependencies": { - "@stoplight/json": { - "version": "3.20.1", - "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.20.1.tgz", - "integrity": "sha512-FXfud+uWgIj1xv6nUO9WnmgmnVikaxJcbtR4XQt4C42n5c2qua3U05Z/3B57hP5TJRSj+tpn9ID6/bFeyYYlEg==", - "dev": true, - "requires": { - "@stoplight/ordered-object-literal": "^1.0.3", - "@stoplight/path": "^1.3.2", - "@stoplight/types": "^13.6.0", - "jsonc-parser": "~2.2.1", - "lodash": "^4.17.21", - "safe-stable-stringify": "^1.1" - } - }, "@stoplight/types": { "version": "13.6.0", "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.6.0.tgz", @@ -10529,32 +10383,6 @@ "ajv-formats": "~2.1.0", "lodash": "~4.17.21", "tslib": "^2.3.0" - }, - "dependencies": { - "@stoplight/json": { - "version": "3.20.1", - "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.20.1.tgz", - "integrity": "sha512-FXfud+uWgIj1xv6nUO9WnmgmnVikaxJcbtR4XQt4C42n5c2qua3U05Z/3B57hP5TJRSj+tpn9ID6/bFeyYYlEg==", - "dev": true, - "requires": { - "@stoplight/ordered-object-literal": "^1.0.3", - "@stoplight/path": "^1.3.2", - "@stoplight/types": "^13.6.0", - "jsonc-parser": "~2.2.1", - "lodash": "^4.17.21", - "safe-stable-stringify": "^1.1" - } - }, - "@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - } - } } }, "@stoplight/spectral-parsers": { @@ -10567,51 +10395,25 @@ "@stoplight/types": "^13.6.0", "@stoplight/yaml": "~4.2.3", "tslib": "^2.3.1" - }, - "dependencies": { - "@stoplight/json": { - "version": "3.20.1", - "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.20.1.tgz", - "integrity": "sha512-FXfud+uWgIj1xv6nUO9WnmgmnVikaxJcbtR4XQt4C42n5c2qua3U05Z/3B57hP5TJRSj+tpn9ID6/bFeyYYlEg==", - "dev": true, - "requires": { - "@stoplight/ordered-object-literal": "^1.0.3", - "@stoplight/path": "^1.3.2", - "@stoplight/types": "^13.6.0", - "jsonc-parser": "~2.2.1", - "lodash": "^4.17.21", - "safe-stable-stringify": "^1.1" - } - }, - "@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - } - } } }, "@stoplight/spectral-ref-resolver": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ref-resolver/-/spectral-ref-resolver-1.0.1.tgz", - "integrity": "sha512-0tY7nTOccvTsa3c4QbSWfJ8wGfPO1RXvmKnmBjuyLfoTMNuhkHPII9gKhCjygsshzsBLxs2IyRHZYhWYVnEbCA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ref-resolver/-/spectral-ref-resolver-1.0.2.tgz", + "integrity": "sha512-ah6NIB/O1EdEaEu89So3LmtbKRXPVnSElgQ7oBRE9S4/VOedSqyXn+qqMd40tGnO2CsKgZaFUYXdSEHOshpHYw==", "dev": true, "requires": { "@stoplight/json-ref-readers": "1.2.2", - "@stoplight/json-ref-resolver": "3.1.3", - "@stoplight/spectral-runtime": "^1.0.0", + "@stoplight/json-ref-resolver": "~3.1.4", + "@stoplight/spectral-runtime": "^1.1.2", "dependency-graph": "0.11.0", "tslib": "^2.3.1" } }, "@stoplight/spectral-ruleset-bundler": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.3.3.tgz", - "integrity": "sha512-hfHl7XZeF/wWMpSrsLqLnH2GevRHjSIqtBL2aRjO2SjMCTbO9LVz80p4sYaxrCcu4wQ6K71gMZXsG687+3fAeg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.4.0.tgz", + "integrity": "sha512-aYDI4a145IXED+6jvRjj9Ha0fnB+s54cr8KbQbPCEyhCHW1cP8UGVeOuwAfk+9C4ZIg40OuYrugN5EhA35oQtA==", "dev": true, "requires": { "@rollup/plugin-commonjs": "~22.0.2", @@ -10630,64 +10432,12 @@ "rollup": "~2.79.0", "tslib": "^2.3.1", "validate-npm-package-name": "3.0.0" - }, - "dependencies": { - "@rollup/plugin-commonjs": { - "version": "22.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.2.tgz", - "integrity": "sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - } - }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "dependencies": { - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - } - } - }, - "@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - } - }, - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - } } }, "@stoplight/spectral-ruleset-migrator": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.8.0.tgz", - "integrity": "sha512-zg6RPF+d8uS7zAp5TzUph3hQG4sgGcG5Fsw8Zx24H1REyuSkjiIfyee2Kf13c3BcIlTXvnFc4csz2rNXpZO7Ug==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.9.0.tgz", + "integrity": "sha512-hPSjgXsTxMQ5UV1hfkVVPknhqRjmjSnCZD5jideM4rRU5NS1fj2Pse1CiXBsRChsuAGi/2s0Ke5uuOmFFsHrxQ==", "dev": true, "requires": { "@stoplight/json": "~3.20.1", @@ -10704,32 +10454,6 @@ "reserved": "0.1.2", "tslib": "^2.3.1", "validate-npm-package-name": "3.0.0" - }, - "dependencies": { - "@stoplight/json": { - "version": "3.20.1", - "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.20.1.tgz", - "integrity": "sha512-FXfud+uWgIj1xv6nUO9WnmgmnVikaxJcbtR4XQt4C42n5c2qua3U05Z/3B57hP5TJRSj+tpn9ID6/bFeyYYlEg==", - "dev": true, - "requires": { - "@stoplight/ordered-object-literal": "^1.0.3", - "@stoplight/path": "^1.3.2", - "@stoplight/types": "^13.6.0", - "jsonc-parser": "~2.2.1", - "lodash": "^4.17.21", - "safe-stable-stringify": "^1.1" - } - }, - "@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - } - } } }, "@stoplight/spectral-rulesets": { @@ -10752,18 +10476,6 @@ "json-schema-traverse": "^1.0.0", "lodash": "~4.17.21", "tslib": "^2.3.0" - }, - "dependencies": { - "@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - } - } } }, "@stoplight/spectral-runtime": { @@ -10779,12 +10491,24 @@ "lodash": "^4.17.21", "node-fetch": "^2.6.7", "tslib": "^2.3.1" + }, + "dependencies": { + "@stoplight/types": { + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-12.5.0.tgz", + "integrity": "sha512-dwqYcDrGmEyUv5TWrDam5TGOxU72ufyQ7hnOIIDdmW5ezOwZaBFoR5XQ9AsH49w7wgvOqB2Bmo799pJPWnpCbg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + } + } } }, "@stoplight/types": { - "version": "12.3.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-12.3.0.tgz", - "integrity": "sha512-hgzUR1z5BlYvIzUeFK5pjs5JXSvEutA9Pww31+dVicBlunsG1iXopDx/cvfBY7rHOrgtZDuvyeK4seqkwAZ6Cg==", + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.8.0.tgz", + "integrity": "sha512-5glKswz7y9aACh+a+JegID+4xX//4TsIdv7iPl29hWnOoWrnlPbg3Gjc4nYUXXgMSaSlSsA15JU/0+rE89fR4A==", "dev": true, "requires": { "@types/json-schema": "^7.0.4", @@ -10801,18 +10525,6 @@ "@stoplight/types": "^13.0.0", "@stoplight/yaml-ast-parser": "0.0.48", "tslib": "^2.2.0" - }, - "dependencies": { - "@stoplight/types": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.7.0.tgz", - "integrity": "sha512-7ePIccfTxjEhruv8VrkDv5whP5qd9ijRzAWEbjYpUYnDfaqPTfq8/wMMjMCAKIecboxsAVD9LZy/3puXddGsDQ==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - } - } } }, "@stoplight/yaml-ast-parser": { @@ -10839,9 +10551,9 @@ "dev": true }, "@types/chai": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", - "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", "dev": true }, "@types/chai-subset": { @@ -10871,9 +10583,9 @@ } }, "@types/eslint": { - "version": "8.4.7", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.7.tgz", - "integrity": "sha512-ehM7cCt2RSFs42mb+lcmhFT9ouIlV92PuaeRGn8N8c98oMjG4Z5pJHA9b1QiCcuqnbPSHcyfiD3mlhqMaHsQIw==", + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", "requires": { "@types/estree": "*", "@types/json-schema": "*" @@ -10916,9 +10628,9 @@ "dev": true }, "@types/node": { - "version": "18.11.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.4.tgz", - "integrity": "sha512-BxcJpBu8D3kv/GZkx/gSMz6VnTJREBj/4lbzYOQueUOELkt8WrO6zAcSPmp9uRPEW/d+lUO8QK0W2xnS1hEU0A==" + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==" }, "@types/normalize-package-data": { "version": "2.4.1", @@ -10947,36 +10659,36 @@ "dev": true }, "@vue/compiler-core": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.41.tgz", - "integrity": "sha512-oA4mH6SA78DT+96/nsi4p9DX97PHcNROxs51lYk7gb9Z4BPKQ3Mh+BLn6CQZBw857Iuhu28BfMSRHAlPvD4vlw==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz", + "integrity": "sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==", "requires": { "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.41", + "@vue/shared": "3.2.45", "estree-walker": "^2.0.2", "source-map": "^0.6.1" } }, "@vue/compiler-dom": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.41.tgz", - "integrity": "sha512-xe5TbbIsonjENxJsYRbDJvthzqxLNk+tb3d/c47zgREDa/PCp6/Y4gC/skM4H6PIuX5DAxm7fFJdbjjUH2QTMw==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz", + "integrity": "sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==", "requires": { - "@vue/compiler-core": "3.2.41", - "@vue/shared": "3.2.41" + "@vue/compiler-core": "3.2.45", + "@vue/shared": "3.2.45" } }, "@vue/compiler-sfc": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.41.tgz", - "integrity": "sha512-+1P2m5kxOeaxVmJNXnBskAn3BenbTmbxBxWOtBq3mQTCokIreuMULFantBUclP0+KnzNCMOvcnKinqQZmiOF8w==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz", + "integrity": "sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==", "requires": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.41", - "@vue/compiler-dom": "3.2.41", - "@vue/compiler-ssr": "3.2.41", - "@vue/reactivity-transform": "3.2.41", - "@vue/shared": "3.2.41", + "@vue/compiler-core": "3.2.45", + "@vue/compiler-dom": "3.2.45", + "@vue/compiler-ssr": "3.2.45", + "@vue/reactivity-transform": "3.2.45", + "@vue/shared": "3.2.45", "estree-walker": "^2.0.2", "magic-string": "^0.25.7", "postcss": "^8.1.10", @@ -10984,66 +10696,66 @@ } }, "@vue/compiler-ssr": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.41.tgz", - "integrity": "sha512-Y5wPiNIiaMz/sps8+DmhaKfDm1xgj6GrH99z4gq2LQenfVQcYXmHIOBcs5qPwl7jaW3SUQWjkAPKMfQemEQZwQ==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz", + "integrity": "sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==", "requires": { - "@vue/compiler-dom": "3.2.41", - "@vue/shared": "3.2.41" + "@vue/compiler-dom": "3.2.45", + "@vue/shared": "3.2.45" } }, "@vue/reactivity": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.41.tgz", - "integrity": "sha512-9JvCnlj8uc5xRiQGZ28MKGjuCoPhhTwcoAdv3o31+cfGgonwdPNuvqAXLhlzu4zwqavFEG5tvaoINQEfxz+l6g==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz", + "integrity": "sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==", "requires": { - "@vue/shared": "3.2.41" + "@vue/shared": "3.2.45" } }, "@vue/reactivity-transform": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.41.tgz", - "integrity": "sha512-mK5+BNMsL4hHi+IR3Ft/ho6Za+L3FA5j8WvreJ7XzHrqkPq8jtF/SMo7tuc9gHjLDwKZX1nP1JQOKo9IEAn54A==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz", + "integrity": "sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==", "requires": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.41", - "@vue/shared": "3.2.41", + "@vue/compiler-core": "3.2.45", + "@vue/shared": "3.2.45", "estree-walker": "^2.0.2", "magic-string": "^0.25.7" } }, "@vue/runtime-core": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.41.tgz", - "integrity": "sha512-0LBBRwqnI0p4FgIkO9q2aJBBTKDSjzhnxrxHYengkAF6dMOjeAIZFDADAlcf2h3GDALWnblbeprYYpItiulSVQ==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz", + "integrity": "sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==", "requires": { - "@vue/reactivity": "3.2.41", - "@vue/shared": "3.2.41" + "@vue/reactivity": "3.2.45", + "@vue/shared": "3.2.45" } }, "@vue/runtime-dom": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.41.tgz", - "integrity": "sha512-U7zYuR1NVIP8BL6jmOqmapRAHovEFp7CSw4pR2FacqewXNGqZaRfHoNLQsqQvVQ8yuZNZtxSZy0FFyC70YXPpA==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz", + "integrity": "sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==", "requires": { - "@vue/runtime-core": "3.2.41", - "@vue/shared": "3.2.41", + "@vue/runtime-core": "3.2.45", + "@vue/shared": "3.2.45", "csstype": "^2.6.8" } }, "@vue/server-renderer": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.41.tgz", - "integrity": "sha512-7YHLkfJdTlsZTV0ae5sPwl9Gn/EGr2hrlbcS/8naXm2CDpnKUwC68i1wGlrYAfIgYWL7vUZwk2GkYLQH5CvFig==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz", + "integrity": "sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==", "requires": { - "@vue/compiler-ssr": "3.2.41", - "@vue/shared": "3.2.41" + "@vue/compiler-ssr": "3.2.45", + "@vue/shared": "3.2.45" } }, "@vue/shared": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.41.tgz", - "integrity": "sha512-W9mfWLHmJhkfAmV+7gDjcHeAWALQtgGT3JErxULl0oz6R6+3ug91I7IErs93eCFhPCZPHBs4QJS7YWEV7A3sxw==" + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz", + "integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==" }, "@webassemblyjs/ast": { "version": "1.11.1", @@ -11177,23 +10889,21 @@ } }, "@webpack-cli/configtest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", - "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.0.tgz", + "integrity": "sha512-war4OU8NGjBqU3DP3bx6ciODXIh7dSXcpQq+P4K2Tqyd8L5OjZ7COx9QXx/QdCIwL2qoX09Wr4Cwf7uS4qdEng==", "requires": {} }, "@webpack-cli/info": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", - "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", - "requires": { - "envinfo": "^7.7.3" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.0.tgz", + "integrity": "sha512-NNxDgbo4VOkNhOlTgY0Elhz3vKpOJq4/PKeKg7r8cmYM+GQA9vDofLYyup8jS6EpUvhNmR30cHTCEIyvXpskwA==", + "requires": {} }, "@webpack-cli/serve": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", - "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.0.tgz", + "integrity": "sha512-Rumq5mHvGXamnOh3O8yLk1sjx8dB30qF1OeR6VC00DIR6SLJ4bwwUGKC4pE7qBFoQyyh0H9sAg3fikYgAqVR0w==", "requires": {} }, "@xtuc/ieee754": { @@ -11271,9 +10981,9 @@ } }, "ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -11335,15 +11045,15 @@ "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==" }, "array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", "is-string": "^1.0.7" } }, @@ -11354,14 +11064,14 @@ "dev": true }, "array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", "es-shim-unscopables": "^1.0.0" } }, @@ -11428,12 +11138,6 @@ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" }, - "blueimp-md5": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.18.0.tgz", - "integrity": "sha512-vE52okJvzsVWhcgUHOv+69OG3Mdg151xyn41aVQN/5W5S+S43qZhxECtYLAEHMSFWX6Mv5IZrzj3T5+JqXfj5Q==", - "dev": true - }, "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -11534,19 +11238,19 @@ } }, "caniuse-lite": { - "version": "1.0.30001423", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001423.tgz", - "integrity": "sha512-09iwWGOlifvE1XuHokFMP7eR38a0JnajoyL3/i87c8ZjRWRrdKo1fqjNfugfBD0UDBIOz0U+jtNhJ0EPm1VleQ==" + "version": "1.0.30001431", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", + "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==" }, "chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", "dev": true, "requires": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", - "deep-eql": "^3.0.1", + "deep-eql": "^4.1.2", "get-func-name": "^2.0.0", "loupe": "^2.3.1", "pathval": "^1.1.1", @@ -11574,9 +11278,9 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" }, "ci-info": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", - "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.6.1.tgz", + "integrity": "sha512-up5ggbaDqOqJ4UqLKZ2naVkyqSJQgJi5lwD6b6mM748ysrghDBX0bx/qJTUHzw7zu6Mq4gycviSF5hJnwceD8w==", "dev": true }, "citeproc": { @@ -11646,9 +11350,9 @@ } }, "codemirror": { - "version": "5.65.9", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.9.tgz", - "integrity": "sha512-19Jox5sAKpusTDgqgKB5dawPpQcY+ipQK7xoEI+MVucEF9qqFaXpeqY1KaoyGBso/wHQoDa4HMMxMjdsS3Zzzw==" + "version": "5.65.10", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.10.tgz", + "integrity": "sha512-IXAG5wlhbgcTJ6rZZcmi4+sjWIbJqIGfeg3tNa3yX84Jb3T4huS5qzQAo/cUisc1l3bI47WZodpyf7cYcocDKg==" }, "codemirror-spell-checker": { "version": "1.1.2", @@ -11722,9 +11426,9 @@ "dev": true }, "cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dev": true, "requires": { "@types/parse-json": "^4.0.0", @@ -11751,18 +11455,18 @@ "dev": true }, "css-loader": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", - "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.2.tgz", + "integrity": "sha512-oqGbbVcBJkm8QwmnNzrFrWTnudnRZC+1eXikLJl0n4ljcfotgRifpg2a1lKy8jTrc4/d9A/ap1GFq1jDKG7J+Q==", "requires": { "icss-utils": "^5.1.0", - "postcss": "^8.4.7", + "postcss": "^8.4.18", "postcss-modules-extract-imports": "^3.0.0", "postcss-modules-local-by-default": "^4.0.0", "postcss-modules-scope": "^3.0.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", - "semver": "^7.3.5" + "semver": "^7.3.8" } }, "css-select": { @@ -12438,9 +12142,9 @@ "dev": true }, "decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", "dev": true, "requires": { "decamelize": "^1.1.0", @@ -12462,9 +12166,9 @@ "dev": true }, "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.2.tgz", + "integrity": "sha512-gT18+YW4CcW/DBNTwAmqTtkJh7f9qqScu2qFVlx7kCoeY9tlBu9cUcr7+I+Z/noG8INehS3xQgLpTtd/QUTn4w==", "dev": true, "requires": { "type-detect": "^4.0.0" @@ -12794,17 +12498,17 @@ } }, "es-aggregate-error": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.8.tgz", - "integrity": "sha512-AKUb5MKLWMozPlFRHOKqWD7yta5uaEhH21qwtnf6FlKjNjTJOoqFi0/G14+FfSkIQhhu6X68Af4xgRC6y8qG4A==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.9.tgz", + "integrity": "sha512-fvnX40sb538wdU6r4s35cq4EY6Lr09Upj40BEVem4LEsuW8XgQep9yD5Q1U2KftokNp1rWODFJ2qwZSsAjFpbg==", "dev": true, "requires": { "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", + "es-abstract": "^1.20.4", "function-bind": "^1.1.1", "functions-have-names": "^1.2.3", - "get-intrinsic": "^1.1.1", - "globalthis": "^1.0.2", + "get-intrinsic": "^1.1.3", + "globalthis": "^1.0.3", "has-property-descriptors": "^1.0.0" } }, @@ -12834,116 +12538,116 @@ } }, "esbuild": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.12.tgz", - "integrity": "sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.14.tgz", + "integrity": "sha512-pJN8j42fvWLFWwSMG4luuupl2Me7mxciUOsMegKvwCmhEbJ2covUdFnihxm0FMIBV+cbwbtMoHgMCCI+pj1btQ==", "requires": { - "@esbuild/android-arm": "0.15.12", - "@esbuild/linux-loong64": "0.15.12", - "esbuild-android-64": "0.15.12", - "esbuild-android-arm64": "0.15.12", - "esbuild-darwin-64": "0.15.12", - "esbuild-darwin-arm64": "0.15.12", - "esbuild-freebsd-64": "0.15.12", - "esbuild-freebsd-arm64": "0.15.12", - "esbuild-linux-32": "0.15.12", - "esbuild-linux-64": "0.15.12", - "esbuild-linux-arm": "0.15.12", - "esbuild-linux-arm64": "0.15.12", - "esbuild-linux-mips64le": "0.15.12", - "esbuild-linux-ppc64le": "0.15.12", - "esbuild-linux-riscv64": "0.15.12", - "esbuild-linux-s390x": "0.15.12", - "esbuild-netbsd-64": "0.15.12", - "esbuild-openbsd-64": "0.15.12", - "esbuild-sunos-64": "0.15.12", - "esbuild-windows-32": "0.15.12", - "esbuild-windows-64": "0.15.12", - "esbuild-windows-arm64": "0.15.12" + "@esbuild/android-arm": "0.15.14", + "@esbuild/linux-loong64": "0.15.14", + "esbuild-android-64": "0.15.14", + "esbuild-android-arm64": "0.15.14", + "esbuild-darwin-64": "0.15.14", + "esbuild-darwin-arm64": "0.15.14", + "esbuild-freebsd-64": "0.15.14", + "esbuild-freebsd-arm64": "0.15.14", + "esbuild-linux-32": "0.15.14", + "esbuild-linux-64": "0.15.14", + "esbuild-linux-arm": "0.15.14", + "esbuild-linux-arm64": "0.15.14", + "esbuild-linux-mips64le": "0.15.14", + "esbuild-linux-ppc64le": "0.15.14", + "esbuild-linux-riscv64": "0.15.14", + "esbuild-linux-s390x": "0.15.14", + "esbuild-netbsd-64": "0.15.14", + "esbuild-openbsd-64": "0.15.14", + "esbuild-sunos-64": "0.15.14", + "esbuild-windows-32": "0.15.14", + "esbuild-windows-64": "0.15.14", + "esbuild-windows-arm64": "0.15.14" } }, "esbuild-android-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.12.tgz", - "integrity": "sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.14.tgz", + "integrity": "sha512-HuilVIb4rk9abT4U6bcFdU35UHOzcWVGLSjEmC58OVr96q5UiRqzDtWjPlCMugjhgUGKEs8Zf4ueIvYbOStbIg==", "optional": true }, "esbuild-android-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.12.tgz", - "integrity": "sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.14.tgz", + "integrity": "sha512-/QnxRVxsR2Vtf3XottAHj7hENAMW2wCs6S+OZcAbc/8nlhbAL/bCQRCVD78VtI5mdwqWkVi3wMqM94kScQCgqg==", "optional": true }, "esbuild-darwin-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.12.tgz", - "integrity": "sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.14.tgz", + "integrity": "sha512-ToNuf1uifu8hhwWvoZJGCdLIX/1zpo8cOGnT0XAhDQXiKOKYaotVNx7pOVB1f+wHoWwTLInrOmh3EmA7Fd+8Vg==", "optional": true }, "esbuild-darwin-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.12.tgz", - "integrity": "sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.14.tgz", + "integrity": "sha512-KgGP+y77GszfYJgceO0Wi/PiRtYo5y2Xo9rhBUpxTPaBgWDJ14gqYN0+NMbu+qC2fykxXaipHxN4Scaj9tUS1A==", "optional": true }, "esbuild-freebsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.12.tgz", - "integrity": "sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.14.tgz", + "integrity": "sha512-xr0E2n5lyWw3uFSwwUXHc0EcaBDtsal/iIfLioflHdhAe10KSctV978Te7YsfnsMKzcoGeS366+tqbCXdqDHQA==", "optional": true }, "esbuild-freebsd-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.12.tgz", - "integrity": "sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.14.tgz", + "integrity": "sha512-8XH96sOQ4b1LhMlO10eEWOjEngmZ2oyw3pW4o8kvBcpF6pULr56eeYVP5radtgw54g3T8nKHDHYEI5AItvskZg==", "optional": true }, "esbuild-linux-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.12.tgz", - "integrity": "sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.14.tgz", + "integrity": "sha512-6ssnvwaTAi8AzKN8By2V0nS+WF5jTP7SfuK6sStGnDP7MCJo/4zHgM9oE1eQTS2jPmo3D673rckuCzRlig+HMA==", "optional": true }, "esbuild-linux-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.12.tgz", - "integrity": "sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.14.tgz", + "integrity": "sha512-ONySx3U0wAJOJuxGUlXBWxVKFVpWv88JEv0NZ6NlHknmDd1yCbf4AEdClSgLrqKQDXYywmw4gYDvdLsS6z0hcw==", "optional": true }, "esbuild-linux-arm": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.12.tgz", - "integrity": "sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.14.tgz", + "integrity": "sha512-D2LImAIV3QzL7lHURyCHBkycVFbKwkDb1XEUWan+2fb4qfW7qAeUtul7ZIcIwFKZgPcl+6gKZmvLgPSj26RQ2Q==", "optional": true }, "esbuild-linux-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.12.tgz", - "integrity": "sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.14.tgz", + "integrity": "sha512-kle2Ov6a1e5AjlHlMQl1e+c4myGTeggrRzArQFmWp6O6JoqqB9hT+B28EW4tjFWgV/NxUq46pWYpgaWXsXRPAg==", "optional": true }, "esbuild-linux-mips64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.12.tgz", - "integrity": "sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.14.tgz", + "integrity": "sha512-FVdMYIzOLXUq+OE7XYKesuEAqZhmAIV6qOoYahvUp93oXy0MOVTP370ECbPfGXXUdlvc0TNgkJa3YhEwyZ6MRA==", "optional": true }, "esbuild-linux-ppc64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.12.tgz", - "integrity": "sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.14.tgz", + "integrity": "sha512-2NzH+iuzMDA+jjtPjuIz/OhRDf8tzbQ1tRZJI//aT25o1HKc0reMMXxKIYq/8nSHXiJSnYV4ODzTiv45s+h73w==", "optional": true }, "esbuild-linux-riscv64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.12.tgz", - "integrity": "sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.14.tgz", + "integrity": "sha512-VqxvutZNlQxmUNS7Ac+aczttLEoHBJ9e3OYGqnULrfipRvG97qLrAv9EUY9iSrRKBqeEbSvS9bSfstZqwz0T4Q==", "optional": true }, "esbuild-linux-s390x": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.12.tgz", - "integrity": "sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.14.tgz", + "integrity": "sha512-+KVHEUshX5n6VP6Vp/AKv9fZIl5kr2ph8EUFmQUJnDpHwcfTSn2AQgYYm0HTBR2Mr4d0Wlr0FxF/Cs5pbFgiOw==", "optional": true }, "esbuild-loader": { @@ -12960,39 +12664,39 @@ } }, "esbuild-netbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.12.tgz", - "integrity": "sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.14.tgz", + "integrity": "sha512-6D/dr17piEgevIm1xJfZP2SjB9Z+g8ERhNnBdlZPBWZl+KSPUKLGF13AbvC+nzGh8IxOH2TyTIdRMvKMP0nEzQ==", "optional": true }, "esbuild-openbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.12.tgz", - "integrity": "sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.14.tgz", + "integrity": "sha512-rREQBIlMibBetgr2E9Lywt2Qxv2ZdpmYahR4IUlAQ1Efv/A5gYdO0/VIN3iowDbCNTLxp0bb57Vf0LFcffD6kA==", "optional": true }, "esbuild-sunos-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.12.tgz", - "integrity": "sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.14.tgz", + "integrity": "sha512-DNVjSp/BY4IfwtdUAvWGIDaIjJXY5KI4uD82+15v6k/w7px9dnaDaJJ2R6Mu+KCgr5oklmFc0KjBjh311Gxl9Q==", "optional": true }, "esbuild-windows-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.12.tgz", - "integrity": "sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.14.tgz", + "integrity": "sha512-pHBWrcA+/oLgvViuG9FO3kNPO635gkoVrRQwe6ZY1S0jdET07xe2toUvQoJQ8KT3/OkxqUasIty5hpuKFLD+eg==", "optional": true }, "esbuild-windows-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.12.tgz", - "integrity": "sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.14.tgz", + "integrity": "sha512-CszIGQVk/P8FOS5UgAH4hKc9zOaFo69fe+k1rqgBHx3CSK3Opyk5lwYriIamaWOVjBt7IwEP6NALz+tkVWdFog==", "optional": true }, "esbuild-windows-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.12.tgz", - "integrity": "sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA==", + "version": "0.15.14", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.14.tgz", + "integrity": "sha512-KW9W4psdZceaS9A7Jsgl4WialOznSURvqX/oHZk3gOP7KbjtHLSsnmSvNdzagGJfxbAe30UVGXRe8q8nDsOSQw==", "optional": true }, "escalade": { @@ -13066,9 +12770,9 @@ } }, "eslint": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", - "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", + "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", "dev": true, "requires": { "@eslint/eslintrc": "^1.3.3", @@ -13235,31 +12939,33 @@ "requires": {} }, "eslint-plugin-unicorn": { - "version": "44.0.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-44.0.2.tgz", - "integrity": "sha512-GLIDX1wmeEqpGaKcnMcqRvMVsoabeF0Ton0EX4Th5u6Kmf7RM9WBl705AXFEsns56ESkEs0uyelLuUTvz9Tr0w==", + "version": "45.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.0.tgz", + "integrity": "sha512-iP8cMRxXKHonKioOhnCoCcqVhoqhAp6rB+nsoLjXFDxTHz3btWMAp8xwzjHA0B1K6YV/U/Yvqn1bUXZt8sJPuQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.19.1", - "ci-info": "^3.4.0", + "ci-info": "^3.6.1", "clean-regexp": "^1.0.0", "eslint-utils": "^3.0.0", "esquery": "^1.4.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.0", + "jsesc": "3.0.2", "lodash": "^4.17.21", "pluralize": "^8.0.0", "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.24", + "regjsparser": "0.9.1", "safe-regex": "^2.1.1", - "semver": "^7.3.7", + "semver": "^7.3.8", "strip-indent": "^3.0.0" } }, "eslint-plugin-vue": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.6.0.tgz", - "integrity": "sha512-zzySkJgVbFCylnG2+9MDF7N+2Rjze2y0bF8GyUNpFOnT8mCMfqqtLDJkHBuYu9N/psW1A6DVbQhPkP92E+qakA==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.7.0.tgz", + "integrity": "sha512-DrOO3WZCZEwcLsnd3ohFwqCoipGRSTKTBTnLwdhqAbYZtzWl0o7D+D8ZhlmiZvABKTEl8AFsqH1GHGdybyoQmw==", "dev": true, "requires": { "eslint-utils": "^3.0.0", @@ -13305,9 +13011,9 @@ "dev": true }, "espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "requires": { "acorn": "^8.8.0", @@ -13365,6 +13071,11 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, + "fast-clone": { + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/fast-clone/-/fast-clone-1.5.13.tgz", + "integrity": "sha512-0ez7coyFBQFjZtId+RJqJ+EQs61w9xARfqjqK0AD9vIUkSxWD4HvPt80+5evebZ1tTnv1GYKrPTipx7kOW5ipA==" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -13695,9 +13406,9 @@ } }, "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -13976,9 +13687,9 @@ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" }, "interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==" }, "ip": { "version": "1.1.8", @@ -14240,18 +13951,18 @@ } }, "jsdom": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.1.tgz", - "integrity": "sha512-pksjj7Rqoa+wdpkKcLzQRHhJCEE42qQhl/xLMUKHgoSejaKOdaXEAnqs6uDNwMl/fciHTzKeR8Wm8cw7N+g98A==", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", "dev": true, "requires": { "abab": "^2.0.6", - "acorn": "^8.8.0", + "acorn": "^8.8.1", "acorn-globals": "^7.0.0", "cssom": "^0.5.0", "cssstyle": "^2.3.0", "data-urls": "^3.0.2", - "decimal.js": "^10.4.1", + "decimal.js": "^10.4.2", "domexception": "^4.0.0", "escodegen": "^2.0.0", "form-data": "^4.0.0", @@ -14264,12 +13975,12 @@ "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^3.0.0", + "w3c-xmlserializer": "^4.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^2.0.0", "whatwg-mimetype": "^3.0.0", "whatwg-url": "^11.0.0", - "ws": "^8.9.0", + "ws": "^8.11.0", "xml-name-validator": "^4.0.0" } }, @@ -14279,6 +13990,12 @@ "integrity": "sha512-NFbZTr1t13fPKw53swmZFKwBkEDWDnno7uLJk+a+Rw9tGDTkGgnGdZJ8A/o3gR1+XaAXmSsbpfIBIBgqRBZWDA==", "dev": true }, + "jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true + }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -14356,9 +14073,9 @@ "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==" }, "known-css-properties": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz", - "integrity": "sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.26.0.tgz", + "integrity": "sha512-5FZRzrZzNTBruuurWpvZnvP9pum+fe0HcK8z/ooo+U+Hmp4vtbyp1/QDsqmufirXy4egGzbaH/y2uCZf+6W5Kg==", "dev": true }, "less": { @@ -14499,24 +14216,12 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==" }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==", - "dev": true - }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -14547,9 +14252,9 @@ "dev": true }, "loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", "dev": true, "requires": { "get-func-name": "^2.0.0" @@ -14688,9 +14393,9 @@ "dev": true }, "marked": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz", - "integrity": "sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw==" + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.3.tgz", + "integrity": "sha512-slWRdJkbTZ+PjkyJnE30Uid64eHwbwa1Q25INCAYfZlK4o6ylagBy/Le9eWntqJFoFT93ikUKMv47GZ4gTwHkw==" }, "mathml-tag-names": { "version": "2.1.3", @@ -14785,19 +14490,23 @@ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, "mermaid": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.1.7.tgz", - "integrity": "sha512-MRVHXy5FLjnUQUG7YS3UN9jEN6FXCJbFCXVGJQjVIbiR6Vhw0j/6pLIjqsiah9xoHmQU6DEaKOvB3S1g/1nBPA==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.2.2.tgz", + "integrity": "sha512-6s7eKMqFJGS+0MYjmx8f6ZigqKBJVoSx5ql2gw6a4Aa+WJ49QiEJg7gPwywaBg3DZMs79UP7trESp4+jmaQccw==", "requires": { "@braintree/sanitize-url": "^6.0.0", "d3": "^7.0.0", "dagre": "^0.8.5", "dagre-d3": "^0.6.4", "dompurify": "2.4.0", + "fast-clone": "^1.5.13", "graphlib": "^2.1.8", "khroma": "^2.0.0", - "moment-mini": "2.24.0", - "stylis": "^4.0.10" + "lodash": "^4.17.21", + "moment-mini": "^2.24.0", + "non-layered-tidy-tree-layout": "^2.0.2", + "stylis": "^4.1.2", + "uuid": "^9.0.0" } }, "micromatch": { @@ -14835,9 +14544,9 @@ "dev": true }, "mini-css-extract-plugin": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", - "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.0.tgz", + "integrity": "sha512-auqtVo8KhTScMsba7MbijqZTfibbXiBNlPAQbsVt7enQfcDYLdgG57eGxMqwVU3mfeWANY4F1wUg+rMF+ycZgw==", "requires": { "schema-utils": "^4.0.0" } @@ -14868,9 +14577,9 @@ } }, "moment-mini": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.24.0.tgz", - "integrity": "sha512-9ARkWHBs+6YJIvrIp0Ik5tyTTtP9PoV0Ssu2Ocq5y9v8+NOOpWiRshAp8c4rZVWTOe+157on/5G+zj5pwIQFEQ==" + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.29.4.tgz", + "integrity": "sha512-uhXpYwHFeiTbY9KSgPPRoo1nt8OxNVdMVoTBYHfSEKeRkIkwGpO+gERmhuhBtzfaeOyTkykSrm2+noJBgqt3Hg==" }, "monaco-editor": { "version": "0.34.1", @@ -14886,9 +14595,9 @@ } }, "moo": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", - "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==" + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==" }, "ms": { "version": "2.1.2", @@ -14908,9 +14617,9 @@ "dev": true }, "needle": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.1.0.tgz", - "integrity": "sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", "optional": true, "requires": { "debug": "^3.2.6", @@ -14997,6 +14706,11 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, + "non-layered-tidy-tree-layout": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", + "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==" + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -15068,14 +14782,14 @@ } }, "object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" } }, "once": { @@ -15310,9 +15024,9 @@ } }, "playwright-core": { - "version": "1.27.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.27.1.tgz", - "integrity": "sha512-9EmeXDncC2Pmp/z+teoVYlvmPWUC6ejSSYZUln7YaP89Z6lpAaiaAnqroUt/BoLo8tn7WYShcfaCh+xofZa44Q==", + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz", + "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==", "dev": true }, "pluralize": { @@ -15328,9 +15042,9 @@ "dev": true }, "postcss": { - "version": "8.4.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", - "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", + "version": "8.4.19", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", + "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", "requires": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", @@ -15396,9 +15110,9 @@ "requires": {} }, "postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -15624,11 +15338,11 @@ } }, "rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "requires": { - "resolve": "^1.9.0" + "resolve": "^1.20.0" } }, "redent": { @@ -15664,6 +15378,23 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -16098,25 +15829,25 @@ } }, "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" } }, "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" } }, "strip-ansi": { @@ -16164,15 +15895,15 @@ "dev": true }, "stylelint": { - "version": "14.14.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.14.0.tgz", - "integrity": "sha512-yUI+4xXfPHVnueYddSQ/e1GuEA/2wVhWQbGj16AmWLtQJtn28lVxfS4b0CsWyVRPgd3Auzi0NXOthIEUhtQmmA==", + "version": "14.15.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.15.0.tgz", + "integrity": "sha512-JOgDAo5QRsqiOZPZO+B9rKJvBm64S0xasbuRPAbPs6/vQDgDCnZLIiw6XcAS6GQKk9k1sBWR6rmH3Mfj8OknKg==", "dev": true, "requires": { "@csstools/selector-specificity": "^2.0.2", "balanced-match": "^2.0.0", "colord": "^2.9.3", - "cosmiconfig": "^7.0.1", + "cosmiconfig": "^7.1.0", "css-functions-list": "^3.1.0", "debug": "^4.3.4", "fast-glob": "^3.2.12", @@ -16186,13 +15917,13 @@ "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.25.0", + "known-css-properties": "^0.26.0", "mathml-tag-names": "^2.1.3", "meow": "^9.0.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.17", + "postcss": "^8.4.19", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", @@ -16204,7 +15935,7 @@ "style-search": "^0.1.0", "supports-hyperlinks": "^2.3.0", "svg-tags": "^1.0.0", - "table": "^6.8.0", + "table": "^6.8.1", "v8-compile-cache": "^2.3.0", "write-file-atomic": "^4.0.2" }, @@ -16240,9 +15971,9 @@ } }, "stylis": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.2.tgz", - "integrity": "sha512-Nn2CCrG2ZaFziDxaZPN43CXqn+j7tcdjPFCkRBkFue8QYXC2HdEwnw5TCBo4yQZ2WxKYeSi0fdoOrtEqgDrXbA==" + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", + "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" }, "superstruct": { "version": "0.10.13", @@ -16279,9 +16010,9 @@ "dev": true }, "svgo": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.0.tgz", - "integrity": "sha512-mSqPn6RDeNqJvCeqHERlfWJjd4crP/2PgFelil9WpTwC4D3okAUopPsH3lnEyl7ONXfDVyISOihDjO0uK8YVAA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", + "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", "dev": true, "requires": { "@trysound/sax": "0.2.0", @@ -16301,9 +16032,9 @@ } }, "swagger-ui-dist": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.15.0.tgz", - "integrity": "sha512-vAsIdNHraLuBRm1vrxcMaLk/y/PGBTvHLf4lQGQ3LaEXkORtIxw11sBMpYJL3keOLaFJ1OqNXuURd6eShoFLZQ==" + "version": "4.15.5", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.15.5.tgz", + "integrity": "sha512-V3eIa28lwB6gg7/wfNvAbjwJYmDXy1Jo1POjyTzlB6wPcHiGlRxq39TSjYGVjQrUSAzpv+a7nzp7mDxgNy57xA==" }, "symbol-tree": { "version": "3.2.4", @@ -16321,9 +16052,9 @@ } }, "table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, "requires": { "ajv": "^8.0.1", @@ -16512,9 +16243,9 @@ } }, "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "type-check": { "version": "0.4.0", @@ -16587,9 +16318,9 @@ } }, "updates": { - "version": "13.1.10", - "resolved": "https://registry.npmjs.org/updates/-/updates-13.1.10.tgz", - "integrity": "sha512-YSt1ncMoBXAQZndhLwiywvEGHXmA4424SlAf2HMUDuf8qE9Tlqj0s6IANb388HrjkybdZJkaadLSg/hkigwnuQ==", + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/updates/-/updates-13.2.1.tgz", + "integrity": "sha512-d+nIbU2fl/PDEvUkbQch4uRdkXt9AQoPlH6b/FPTOAzF9voGbXgZNNxgO79Jeish24ZMfOqUl5lJcKSwMO2RJQ==", "dev": true }, "uri-js": { @@ -16627,6 +16358,11 @@ "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", "dev": true }, + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -16653,43 +16389,35 @@ } }, "vite": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.1.8.tgz", - "integrity": "sha512-m7jJe3nufUbuOfotkntGFupinL/fmuTNuQmiVE7cH2IZMuf4UbfbGYMUT3jVWgGYuRVLY9j8NnrRqgw5rr5QTg==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.4.tgz", + "integrity": "sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==", "dev": true, "requires": { "esbuild": "^0.15.9", "fsevents": "~2.3.2", - "postcss": "^8.4.16", + "postcss": "^8.4.18", "resolve": "^1.22.1", - "rollup": "~2.78.0" - }, - "dependencies": { - "rollup": { - "version": "2.78.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz", - "integrity": "sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - } + "rollup": "^2.79.1" } }, "vitest": { - "version": "0.24.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.24.3.tgz", - "integrity": "sha512-aM0auuPPgMSstWvr851hB74g/LKaKBzSxcG3da7ejfZbx08Y21JpZmbmDYrMTCGhVZKqTGwzcnLMwyfz2WzkhQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.25.2.tgz", + "integrity": "sha512-qqkzfzglEFbQY7IGkgSJkdOhoqHjwAao/OrphnHboeYHC5JzsVFoLCaB2lnAy8krhj7sbrFTVRApzpkTOeuDWQ==", "dev": true, "requires": { "@types/chai": "^4.3.3", "@types/chai-subset": "^1.3.3", "@types/node": "*", + "acorn": "^8.8.0", + "acorn-walk": "^8.2.0", "chai": "^4.3.6", "debug": "^4.3.4", "local-pkg": "^0.4.2", + "source-map": "^0.6.1", "strip-literal": "^0.4.2", - "tinybench": "^2.3.0", + "tinybench": "^2.3.1", "tinypool": "^0.3.0", "tinyspy": "^1.0.2", "vite": "^3.0.0" @@ -16706,15 +16434,15 @@ } }, "vue": { - "version": "3.2.41", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.41.tgz", - "integrity": "sha512-uuuvnrDXEeZ9VUPljgHkqB5IaVO8SxhPpqF2eWOukVrBnRBx2THPSGQBnVRt0GrIG1gvCmFXMGbd7FqcT1ixNQ==", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.45.tgz", + "integrity": "sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==", "requires": { - "@vue/compiler-dom": "3.2.41", - "@vue/compiler-sfc": "3.2.41", - "@vue/runtime-dom": "3.2.41", - "@vue/server-renderer": "3.2.41", - "@vue/shared": "3.2.41" + "@vue/compiler-dom": "3.2.45", + "@vue/compiler-sfc": "3.2.45", + "@vue/runtime-dom": "3.2.45", + "@vue/server-renderer": "3.2.45", + "@vue/shared": "3.2.45" } }, "vue-bar-graph": { @@ -16742,9 +16470,9 @@ } }, "vue-loader": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.0.0.tgz", - "integrity": "sha512-OWSXjrzIvbF2LtOUmxT3HYgwwubbfFelN8PAP9R9dwpIkj48TVioHhWWSx7W7fk+iF5cgg3CBJRxwTdtLU4Ecg==", + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.0.1.tgz", + "integrity": "sha512-/OOyugJnImKCkAKrAvdsWMuwoCqGxWT5USLsjohzWbMgOwpA5wQmzQiLMzZd7DjhIfunzAGIApTOgIylz/kwcg==", "requires": { "chalk": "^4.1.0", "hash-sum": "^2.0.0", @@ -16760,9 +16488,9 @@ } }, "w3c-xmlserializer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", - "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", "dev": true, "requires": { "xml-name-validator": "^4.0.0" @@ -16784,9 +16512,9 @@ "dev": true }, "webpack": { - "version": "5.74.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", - "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", "requires": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", @@ -16873,28 +16601,29 @@ } }, "webpack-cli": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", - "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.0.tgz", + "integrity": "sha512-AACDTo20yG+xn6HPW5xjbn2Be4KUzQPebWXsDMHwPPyKh9OnTOJgZN2Nc+g/FZKV3ObRTYsGvibAvc+5jAUrVA==", "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.2.0", - "@webpack-cli/info": "^1.5.0", - "@webpack-cli/serve": "^1.7.0", + "@webpack-cli/configtest": "^2.0.0", + "@webpack-cli/info": "^2.0.0", + "@webpack-cli/serve": "^2.0.0", "colorette": "^2.0.14", - "commander": "^7.0.0", + "commander": "^9.4.1", "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", "webpack-merge": "^5.7.3" }, "dependencies": { "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==" } } }, @@ -17098,9 +16827,9 @@ } }, "ws": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", - "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index d221a1379a..a90c1618fa 100644 --- a/package.json +++ b/package.json @@ -9,14 +9,14 @@ "dependencies": { "@citation-js/core": "0.6.1", "@citation-js/plugin-bibtex": "0.6.1", - "@citation-js/plugin-csl": "0.6.3", + "@citation-js/plugin-csl": "0.6.4", "@citation-js/plugin-software-formats": "0.6.0", "@claviska/jquery-minicolors": "2.3.6", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "17.7.0", - "@vue/compiler-sfc": "3.2.41", + "@primer/octicons": "17.9.0", + "@vue/compiler-sfc": "3.2.45", "add-asset-webpack-plugin": "2.0.1", - "css-loader": "6.7.1", + "css-loader": "6.7.2", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", "esbuild-loader": "2.20.0", @@ -29,45 +29,45 @@ "less": "4.1.3", "less-loader": "11.1.0", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "9.1.7", - "mini-css-extract-plugin": "2.6.1", + "mermaid": "9.2.2", + "mini-css-extract-plugin": "2.7.0", "monaco-editor": "0.34.1", "monaco-editor-webpack-plugin": "7.0.1", "pretty-ms": "8.0.0", "sortablejs": "1.15.0", - "swagger-ui-dist": "4.15.0", + "swagger-ui-dist": "4.15.5", "tippy.js": "6.3.7", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", - "vue": "3.2.41", + "vue": "3.2.45", "vue-bar-graph": "2.0.0", - "vue-loader": "17.0.0", + "vue-loader": "17.0.1", "vue3-calendar-heatmap": "2.0.0", - "webpack": "5.74.0", - "webpack-cli": "4.10.0", + "webpack": "5.75.0", + "webpack-cli": "5.0.0", "workbox-routing": "6.5.4", "workbox-strategies": "6.5.4", "worker-loader": "3.0.8", "wrap-ansi": "8.0.1" }, "devDependencies": { - "@playwright/test": "1.27.1", + "@playwright/test": "1.28.0", "@rollup/pluginutils": "5.0.2", - "@stoplight/spectral-cli": "6.5.1", - "eslint": "8.26.0", + "@stoplight/spectral-cli": "6.6.0", + "eslint": "8.28.0", "eslint-plugin-import": "2.26.0", "eslint-plugin-jquery": "1.5.1", "eslint-plugin-sonarjs": "0.16.0", - "eslint-plugin-unicorn": "44.0.2", - "eslint-plugin-vue": "9.6.0", - "jsdom": "20.0.1", + "eslint-plugin-unicorn": "45.0.0", + "eslint-plugin-vue": "9.7.0", + "jsdom": "20.0.3", "markdownlint-cli": "0.32.2", "postcss-less": "6.0.0", - "stylelint": "14.14.0", + "stylelint": "14.15.0", "stylelint-config-standard": "29.0.0", - "svgo": "3.0.0", - "updates": "13.1.10", - "vitest": "0.24.3" + "svgo": "3.0.2", + "updates": "13.2.1", + "vitest": "0.25.2" }, "browserslist": [ "defaults", diff --git a/public/img/svg/octicon-arrow-down-left.svg b/public/img/svg/octicon-arrow-down-left.svg new file mode 100644 index 0000000000..f02bd330c9 --- /dev/null +++ b/public/img/svg/octicon-arrow-down-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-arrow-down-right.svg b/public/img/svg/octicon-arrow-down-right.svg new file mode 100644 index 0000000000..dff9d36c1b --- /dev/null +++ b/public/img/svg/octicon-arrow-down-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-arrow-up-left.svg b/public/img/svg/octicon-arrow-up-left.svg new file mode 100644 index 0000000000..0f5a452b8a --- /dev/null +++ b/public/img/svg/octicon-arrow-up-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-arrow-up-right.svg b/public/img/svg/octicon-arrow-up-right.svg new file mode 100644 index 0000000000..896c9b60b4 --- /dev/null +++ b/public/img/svg/octicon-arrow-up-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-clock-fill.svg b/public/img/svg/octicon-clock-fill.svg new file mode 100644 index 0000000000..5fcfb477c4 --- /dev/null +++ b/public/img/svg/octicon-clock-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-issue-tracked-by.svg b/public/img/svg/octicon-issue-tracked-by.svg new file mode 100644 index 0000000000..d4352a9430 --- /dev/null +++ b/public/img/svg/octicon-issue-tracked-by.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-issue-tracked-in.svg b/public/img/svg/octicon-issue-tracked-in.svg new file mode 100644 index 0000000000..8910bd7a24 --- /dev/null +++ b/public/img/svg/octicon-issue-tracked-in.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-project-roadmap.svg b/public/img/svg/octicon-project-roadmap.svg new file mode 100644 index 0000000000..afc3b223bd --- /dev/null +++ b/public/img/svg/octicon-project-roadmap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-project-symlink.svg b/public/img/svg/octicon-project-symlink.svg new file mode 100644 index 0000000000..2c889a090c --- /dev/null +++ b/public/img/svg/octicon-project-symlink.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-skip-fill.svg b/public/img/svg/octicon-skip-fill.svg new file mode 100644 index 0000000000..6606a56df9 --- /dev/null +++ b/public/img/svg/octicon-skip-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web_src/js/features/clipboard.js b/web_src/js/features/clipboard.js index f266d4f64d..75b96cb781 100644 --- a/web_src/js/features/clipboard.js +++ b/web_src/js/features/clipboard.js @@ -4,7 +4,7 @@ const {copy_success, copy_error} = window.config.i18n; export async function copyToClipboard(content) { if (content instanceof Blob) { - const item = new window.ClipboardItem({[content.type]: content}); + const item = new ClipboardItem({[content.type]: content}); await navigator.clipboard.write([item]); } else { // text try { diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index e6a7c6dcd1..d438186c5f 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -463,10 +463,10 @@ export function initRepository() { $('.enable-system-radio').on('change', function () { if (this.value === 'false') { $($(this).data('target')).addClass('disabled'); - if (typeof $(this).data('context') !== 'undefined') $($(this).data('context')).removeClass('disabled'); + if ($(this).data('context') !== undefined) $($(this).data('context')).removeClass('disabled'); } else if (this.value === 'true') { $($(this).data('target')).removeClass('disabled'); - if (typeof $(this).data('context') !== 'undefined') $($(this).data('context')).addClass('disabled'); + if ($(this).data('context') !== undefined) $($(this).data('context')).addClass('disabled'); } }); const $trackerIssueStyleRadios = $('.js-tracker-issue-style'); diff --git a/web_src/js/features/repo-migrate.js b/web_src/js/features/repo-migrate.js index 5d61eb410e..d44f540c46 100644 --- a/web_src/js/features/repo-migrate.js +++ b/web_src/js/features/repo-migrate.js @@ -9,7 +9,7 @@ export function initRepoMigrationStatusChecker() { $('#repo_migrating_progress_message').hide(); if (migrating) { const task = migrating.attr('task'); - if (typeof task === 'undefined') { + if (task === undefined) { return; } $.ajax({ diff --git a/web_src/js/features/tribute.js b/web_src/js/features/tribute.js index 5678acdf47..dcee7aa4a3 100644 --- a/web_src/js/features/tribute.js +++ b/web_src/js/features/tribute.js @@ -21,7 +21,7 @@ function makeCollections({mentions, emoji}) { }, lookup: (item) => item, selectTemplate: (item) => { - if (typeof item === 'undefined') return null; + if (item === undefined) return null; return emojiString(item.original); }, menuItemTemplate: (item) => { diff --git a/webpack.config.js b/webpack.config.js index a8363051df..cdd8071d27 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -227,10 +227,11 @@ export default { }).join('\n'); }, override: { - 'jquery.are-you-sure@*': {licenseName: 'MIT'}, + 'jquery.are-you-sure@*': {licenseName: 'MIT'}, // https://github.com/codedance/jquery.AreYouSure/pull/147 + 'khroma@*': {licenseName: 'MIT'}, // https://github.com/fabiospampinato/khroma/pull/33 }, emitError: true, - allow: '(Apache-2.0 OR BSD-2-Clause OR BSD-3-Clause OR MIT OR ISC OR CPAL-1.0)', + allow: '(Apache-2.0 OR BSD-2-Clause OR BSD-3-Clause OR MIT OR ISC OR CPAL-1.0 OR Unlicense)', ignore: [ 'font-awesome', ], From 371dd96e3ec9223dcf8401578afbada07fbabf27 Mon Sep 17 00:00:00 2001 From: mpeter50 <83356418+mpeter50@users.noreply.github.com> Date: Tue, 22 Nov 2022 01:04:29 +0000 Subject: [PATCH 060/149] Clarify logging documentation (#21665) My pull request changes the logging documentation that is visible here: https://docs.gitea.io/en-us/logging-configuration/ The reason behind the changes is that for some time I've found the logging documentation confusing, and wanted to give a try at making it more clear. --- If you find the existing changes to be ok, please don't merge yet, as I have further ideas which I want to discuss with you before making the changes. ### Swap the "Log Groups" and "Log outputs" sections. I want to move the "Log outputs" section before the "Log Groups" section. The reason is that the "Log Groups" section refers to ini sections that are only later explained, and to concepts that are general and should be documented in "Log outputs" or a different section. This change is essentially a swap of the "Log Groups" and "Log outputs" sections. That way the doumentation would follow the structure in which the ini file is built: first explaining the outer sections, and then the inner ones ([log], [log.name], [log.name.default], ...) ### Explain the workings of ambigous settings below the settings listing Right now the basics of a setting is shown later than the explanation of its special workings, for example with `FILE_NAME` at [the file output mode](https://docs.gitea.io/en-us/logging-configuration/#file-mode) (well, if the first changes are taken into account). Currently I have `TODO` witten at 2 settings, which I have to figure out how do they exactly work before I can document them. ### New section about [log] New section after "Collecting Logs for Help" about how the top level [log] itself works and what can go there. Currently, variables that directly go into [log] are noted throughout the whole document. --- Please let me know what you think about the changes. A counterargument that I myself see is that some of this is already present in the cheatsheet, but I think it would be better to have [this document](https://docs.gitea.io/en-us/logging-configuration/) as a throrough explanation of how logging is configured, and the cheatsheet would only have a short outline of the possible sections and variables. Co-authored-by: Lunny Xiao --- .../advanced/logging-documentation.en-us.md | 268 +++++++++++------- 1 file changed, 168 insertions(+), 100 deletions(-) diff --git a/docs/content/doc/advanced/logging-documentation.en-us.md b/docs/content/doc/advanced/logging-documentation.en-us.md index 4e8cbb3282..145c8c320c 100644 --- a/docs/content/doc/advanced/logging-documentation.en-us.md +++ b/docs/content/doc/advanced/logging-documentation.en-us.md @@ -15,6 +15,14 @@ menu: # Logging Configuration +The logging configuration of Gitea mainly consists of 3 types of components: + +- The `[log]` section for general configuration +- `[log.]` sections for the configuration of different log outputs +- `[log..]` sections for output specific configuration of a log group + +As mentioned below, there is a fully functional log output by default, so it is not necessary to define one. + **Table of Contents** {{< toc >}} @@ -23,6 +31,166 @@ menu: To collect logs for help and issue report, see [Support Options]({{< relref "doc/help/seek-help.en-us.md" >}}). +## The `[log]` section + +Configuration of logging facilities in Gitea happen in the `[log]` section and it's subsections. + +In the top level `[log]` section the following configurations can be placed: + +- `ROOT_PATH`: (Default: **%(GITEA_WORK_DIR)/log**): Base path for log files +- `MODE`: (Default: **console**) List of log outputs to use for the Default logger. +- `ROUTER`: (Default: **console**): List of log outputs to use for the Router logger. +- `ACCESS`: List of log outputs to use for the Access logger. +- `XORM`: (Default: **,**) List of log outputs to use for the XORM logger. +- `ENABLE_ACCESS_LOG`: (Default: **false**): whether the Access logger is allowed to emit logs +- `ENABLE_XORM_LOG`: (Default: **true**): whether the XORM logger is allowed to emit logs + +For details on the loggers check the "Log Groups" section. +Important: log outputs won't be used if you don't enable them for the desired loggers in the corresponding list value. + +Lists are specified as comma separated values. This format also works in subsection. + +This section may be used for defining default values for subsections. +Examples: + +- `LEVEL`: (Default: **Info**) Least severe log events to persist. Case insensitive. The full list of levels as of v1.17.3 can be read [here](https://github.com/go-gitea/gitea/blob/v1.17.3/custom/conf/app.example.ini#L507). +- `STACKTRACE_LEVEL`: (Default: **None**) For this and more severe events the stacktrace will be printed upon getting logged. + +Some values are not inherited by subsections. For details see the "Non-inherited default values" section. + +## Log outputs + +Log outputs are the targets to which log messages will be sent. +The content and the format of the log messages to be saved can be configured in these. + +Log outputs are also called subloggers. + +Gitea provides 4 possible log outputs: + +- `console` - Log to `os.Stdout` or `os.Stderr` +- `file` - Log to a file +- `conn` - Log to a socket (network or unix) +- `smtp` - Log via email + +By default, Gitea has a `console` output configured, which is used by the loggers as seen in the section "The log section" above. + +### Common configuration + +Certain configuration is common to all modes of log output: + +- `MODE` is the mode of the log output. It will default to the sublogger + name, thus `[log.console.router]` will default to `MODE = console`. + For mode specific confgurations read further. +- `LEVEL` is the lowest level that this output will log. This value + is inherited from `[log]` and in the case of the non-default loggers + from `[log.sublogger]`. +- `STACKTRACE_LEVEL` is the lowest level that this output will print + a stacktrace. This value is inherited. +- `COLORIZE` will default to `true` for `console` as + described, otherwise it will default to `false`. + +### Non-inherited default values + +There are several values which are not inherited as described above but +rather default to those specific to type of logger, these are: +`EXPRESSION`, `FLAGS`, `PREFIX` and `FILE_NAME`. + +#### `EXPRESSION` + +`EXPRESSION` represents a regular expression that log events must match to be logged by the sublogger. Either the log message, (with colors removed), must match or the `longfilename:linenumber:functionname` must match. NB: the whole message or string doesn't need to completely match. + +Please note this expression will be run in the sublogger's goroutine +not the logging event subroutine. Therefore it can be complicated. + +#### `FLAGS` + +`FLAGS` represents the preceding logging context information that is +printed before each message. It is a comma-separated string set. The order of values does not matter. + +Possible values are: + +- `none` or `,` - No flags. +- `date` - the date in the local time zone: `2009/01/23`. +- `time` - the time in the local time zone: `01:23:23`. +- `microseconds` - microsecond resolution: `01:23:23.123123`. Assumes + time. +- `longfile` - full file name and line number: `/a/b/c/d.go:23`. +- `shortfile` - final file name element and line number: `d.go:23`. +- `funcname` - function name of the caller: `runtime.Caller()`. +- `shortfuncname` - last part of the function name. Overrides + `funcname`. +- `utc` - if date or time is set, use UTC rather than the local time + zone. +- `levelinitial` - Initial character of the provided level in brackets eg. `[I]` for info. +- `level` - Provided level in brackets `[INFO]` +- `medfile` - Last 20 characters of the filename - equivalent to + `shortfile,longfile`. +- `stdflags` - Equivalent to `date,time,medfile,shortfuncname,levelinitial` + +### Console mode + +In this mode the logger will forward log messages to the stdout and +stderr streams attached to the Gitea process. + +For loggers in console mode, `COLORIZE` will default to `true` if not +on windows, or the windows terminal can be set into ANSI mode or is a +cygwin or Msys pipe. + +Settings: + +- `STDERR`: **false**: Whether the logger should print to `stderr` instead of `stdout`. + +### File mode + +In this mode the logger will save log messages to a file. + +Settings: + +- `FILE_NAME`: The file to write the log events to. For details see below. +- `MAX_SIZE_SHIFT`: **28**: Maximum size shift of a single file. 28 represents 256Mb. For details see below. +- `LOG_ROTATE` **true**: Whether to rotate the log files. TODO: if false, will it delete instead on daily rotate, or do nothing?. +- `DAILY_ROTATE`: **true**: Whether to rotate logs daily. +- `MAX_DAYS`: **7**: Delete rotated log files after this number of days. +- `COMPRESS`: **true**: Whether to compress old log files by default with gzip. +- `COMPRESSION_LEVEL`: **-1**: Compression level. For details see below. + +The default value of `FILE_NAME` depends on the respective logger facility. +If unset, their own default will be used. +If set it will be relative to the provided `ROOT_PATH` in the master `[log]` section. + +`MAX_SIZE_SHIFT` defines the maximum size of a file by left shifting 1 the given number of times (`1 << x`). +The exact behavior at the time of v1.17.3 can be seen [here](https://github.com/go-gitea/gitea/blob/v1.17.3/modules/setting/log.go#L185). + +The useful values of `COMPRESSION_LEVEL` are from 1 to (and including) 9, where higher numbers mean better compression. +Beware that better compression might come with higher resource usage. +Must be preceded with a `-` sign. + +### Conn mode + +In this mode the logger will send log messages over a network socket. + +Settings: + +- `ADDR`: **:7020**: Sets the address to connect to. +- `PROTOCOL`: **tcp**: Set the protocol, either "tcp", "unix" or "udp". +- `RECONNECT`: **false**: Try to reconnect when connection is lost. +- `RECONNECT_ON_MSG`: **false**: Reconnect host for every single message. + +### SMTP mode + +In this mode the logger will send log messages in email. + +It is not recommended to use this logger to send general logging +messages. However, you could perhaps set this logger to work on `FATAL` messages only. + +Settings: + +- `HOST`: **127.0.0.1:25**: The SMTP host to connect to. +- `USER`: User email address to send from. +- `PASSWD`: Password for the smtp server. +- `RECEIVERS`: Email addresses to send to. +- `SUBJECT`: **Diagnostic message from Gitea**. The content of the email's subject field. + ## Log Groups The fundamental thing to be aware of in Gitea is that there are several @@ -172,106 +340,6 @@ which will not be inherited from the `[log]` or relevant - `EXPRESSION` will default to `""` - `PREFIX` will default to `""` -## Log outputs - -Gitea provides 4 possible log outputs: - -- `console` - Log to `os.Stdout` or `os.Stderr` -- `file` - Log to a file -- `conn` - Log to a keep-alive TCP connection -- `smtp` - Log via email - -Certain configuration is common to all modes of log output: - -- `LEVEL` is the lowest level that this output will log. This value - is inherited from `[log]` and in the case of the non-default loggers - from `[log.sublogger]`. -- `STACKTRACE_LEVEL` is the lowest level that this output will print - a stacktrace. This value is inherited. -- `MODE` is the mode of the log output. It will default to the sublogger - name. Thus `[log.console.router]` will default to `MODE = console`. -- `COLORIZE` will default to `true` for `console` as - described, otherwise it will default to `false`. - -### Non-inherited default values - -There are several values which are not inherited as described above but -rather default to those specific to type of logger, these are: -`EXPRESSION`, `FLAGS`, `PREFIX` and `FILE_NAME`. - -#### `EXPRESSION` - -`EXPRESSION` represents a regular expression that log events must match to be logged by the sublogger. Either the log message, (with colors removed), must match or the `longfilename:linenumber:functionname` must match. NB: the whole message or string doesn't need to completely match. - -Please note this expression will be run in the sublogger's goroutine -not the logging event subroutine. Therefore it can be complicated. - -#### `FLAGS` - -`FLAGS` represents the preceding logging context information that is -printed before each message. It is a comma-separated string set. The order of values does not matter. - -Possible values are: - -- `none` or `,` - No flags. -- `date` - the date in the local time zone: `2009/01/23`. -- `time` - the time in the local time zone: `01:23:23`. -- `microseconds` - microsecond resolution: `01:23:23.123123`. Assumes - time. -- `longfile` - full file name and line number: `/a/b/c/d.go:23`. -- `shortfile` - final file name element and line number: `d.go:23`. -- `funcname` - function name of the caller: `runtime.Caller()`. -- `shortfuncname` - last part of the function name. Overrides - `funcname`. -- `utc` - if date or time is set, use UTC rather than the local time - zone. -- `levelinitial` - Initial character of the provided level in brackets eg. `[I]` for info. -- `level` - Provided level in brackets `[INFO]` -- `medfile` - Last 20 characters of the filename - equivalent to - `shortfile,longfile`. -- `stdflags` - Equivalent to `date,time,medfile,shortfuncname,levelinitial` - -### Console mode - -For loggers in console mode, `COLORIZE` will default to `true` if not -on windows, or the windows terminal can be set into ANSI mode or is a -cygwin or Msys pipe. - -If `STDERR` is set to `true` the logger will use `os.Stderr` instead of -`os.Stdout`. - -### File mode - -The `FILE_NAME` defaults as described above. If set it will be relative -to the provided `ROOT_PATH` in the master `[log]` section. - -Other values: - -- `LOG_ROTATE`: **true**: Rotate the log files. -- `MAX_SIZE_SHIFT`: **28**: Maximum size shift of a single file, 28 represents 256Mb. -- `DAILY_ROTATE`: **true**: Rotate logs daily. -- `MAX_DAYS`: **7**: Delete the log file after n days -- `COMPRESS`: **true**: Compress old log files by default with gzip -- `COMPRESSION_LEVEL`: **-1**: Compression level - -### Conn mode - -- `RECONNECT_ON_MSG`: **false**: Reconnect host for every single message. -- `RECONNECT`: **false**: Try to reconnect when connection is lost. -- `PROTOCOL`: **tcp**: Set the protocol, either "tcp", "unix" or "udp". -- `ADDR`: **:7020**: Sets the address to connect to. - -### SMTP mode - -It is not recommended to use this logger to send general logging -messages. However, you could perhaps set this logger to work on `FATAL`. - -- `USER`: User email address to send from. -- `PASSWD`: Password for the smtp server. -- `HOST`: **127.0.0.1:25**: The SMTP host to connect to. -- `RECEIVERS`: Email addresses to send to. -- `SUBJECT`: **Diagnostic message from Gitea** - ## Debugging problems When submitting logs in Gitea issues it is often helpful to submit From 1d52228ee7b41546aa4e2d0034f2ae337deaae25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Leopoldo=20Sologuren=20Guti=C3=A9rrez?= Date: Tue, 22 Nov 2022 05:46:29 -0300 Subject: [PATCH 061/149] Fixes #21895: standardize UTC tz for util tests (#21897) Standardize UTC timezone for `translateMonth` and `translateDay` tests. --- web_src/js/utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web_src/js/utils.js b/web_src/js/utils.js index 62ee11c2eb..01c076aeba 100644 --- a/web_src/js/utils.js +++ b/web_src/js/utils.js @@ -78,12 +78,12 @@ function getCurrentLocale() { // given a month (0-11), returns it in the documents language export function translateMonth(month) { - return new Date(Date.UTC(2022, month, 12)).toLocaleString(getCurrentLocale(), {month: 'short'}); + return new Date(Date.UTC(2022, month, 12)).toLocaleString(getCurrentLocale(), {month: 'short', timeZone: 'UTC'}); } // given a weekday (0-6, Sunday to Saturday), returns it in the documents language export function translateDay(day) { - return new Date(Date.UTC(2022, 7, day)).toLocaleString(getCurrentLocale(), {weekday: 'short'}); + return new Date(Date.UTC(2022, 7, day)).toLocaleString(getCurrentLocale(), {weekday: 'short', timeZone: 'UTC'}); } // convert a Blob to a DataURI From e77b76425e5ae205d6db2c78ab7b31fbc1b186a6 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 22 Nov 2022 12:58:49 +0000 Subject: [PATCH 062/149] Prepend refs/heads/ to issue template refs (#20461) Fix #20456 At some point during the 1.17 cycle abbreviated refishs to issue branches started breaking. This is likely due serious inconsistencies in our management of refs throughout Gitea - which is a bug needing to be addressed in a different PR. (Likely more than one) We should try to use non-abbreviated `fullref`s as much as possible. That is where a user has inputted a abbreviated `refish` we should add `refs/heads/` if it is `branch` etc. I know people keep writing and merging PRs that remove prefixes from stored content but it is just wrong and it keeps causing problems like this. We should only remove the prefix at the time of presentation as the prefix is the only way of knowing umambiguously and permanently if the `ref` is referring to a `branch`, `tag` or `commit` / `SHA`. We need to make it so that every ref has the appropriate prefix, and probably also need to come up with some definitely unambiguous way of storing `SHA`s if they're used in a `ref` or `refish` field. We must not store a potentially ambiguous `refish` as a `ref`. (Especially when referring a `tag` - there is no reason why users cannot create a `branch` with the same short name as a `tag` and vice versa and any attempt to prevent this will fail. You can even create a `branch` and a `tag` that matches the `SHA` pattern.) To that end in order to fix this bug, when parsing issue templates check the provided `Ref` (here a `refish` because almost all users do not know or understand the subtly), if it does not start with `refs/` add the `BranchPrefix` to it. This allows people to make their templates refer to a `tag` but not to a `SHA` directly. (I don't think that is particularly unreasonable but if people disagree I can make the `refish` be checked to see if it matches the `SHA` pattern.) Next we need to handle the issue links that are already written. The links here are created with `git.RefURL` Here we see there is a bug introduced in #17551 whereby the provided `ref` argument can be double-escaped so we remove the incorrect external escape. (The escape added in #17551 is in the right place - unfortunately I missed that the calling function was doing the wrong thing.) Then within `RefURL()` we check if an unprefixed `ref` (therefore potentially a `refish`) matches the `SHA` pattern before assuming that is actually a `commit` - otherwise is assumed to be a `branch`. This will handle most of the problem cases excepting the very unusual cases where someone has deliberately written a `branch` to look like a `SHA1`. But please if something is called a `ref` or interpreted as a `ref` make it a full-ref before storing or using it. By all means if something is a `branch` assume the prefix is removed but always add it back in if you are using it as a `ref`. Stop storing abbreviated `branch` names and `tag` names - which are `refish` as a `ref`. It will keep on causing problems like this. Fix #20456 Signed-off-by: Andrew Thornton Co-authored-by: Lauris BH Co-authored-by: wxiaoguang Co-authored-by: Lunny Xiao --- modules/context/repo.go | 3 +++ modules/git/utils.go | 3 +++ routers/web/repo/issue.go | 4 ++++ services/issue/issue.go | 3 +-- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/modules/context/repo.go b/modules/context/repo.go index c363c36994..1a83c49e95 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -1089,6 +1089,9 @@ func (ctx *Context) IssueTemplatesErrorsFromDefaultBranch() ([]*api.IssueTemplat if it, err := template.UnmarshalFromEntry(entry, dirName); err != nil { invalidFiles[fullName] = err } else { + if !strings.HasPrefix(it.Ref, "refs/") { // Assume that the ref intended is always a branch - for tags users should use refs/tags/ + it.Ref = git.BranchPrefix + it.Ref + } issueTemplates = append(issueTemplates, it) } } diff --git a/modules/git/utils.go b/modules/git/utils.go index d6bf9f4413..a439dabae1 100644 --- a/modules/git/utils.go +++ b/modules/git/utils.go @@ -100,6 +100,9 @@ func RefURL(repoURL, ref string) string { return repoURL + "/src/branch/" + refName case strings.HasPrefix(ref, TagPrefix): return repoURL + "/src/tag/" + refName + case !IsValidSHAPattern(ref): + // assume they mean a branch + return repoURL + "/src/branch/" + refName default: return repoURL + "/src/commit/" + refName } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index a62084fdca..318d9af703 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -784,6 +784,10 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles } } } + + } + if !strings.HasPrefix(template.Ref, "refs/") { // Assume that the ref intended is always a branch - for tags users should use refs/tags/ + template.Ref = git.BranchPrefix + template.Ref } ctx.Data["HasSelectedLabel"] = len(labelIDs) > 0 ctx.Data["label_ids"] = strings.Join(labelIDs, ",") diff --git a/services/issue/issue.go b/services/issue/issue.go index ba9b17a0c8..9ec43f8264 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/util" ) // NewIssue creates new issue with labels for repository. @@ -201,7 +200,7 @@ func GetRefEndNamesAndURLs(issues []*issues_model.Issue, repoLink string) (map[i for _, issue := range issues { if issue.Ref != "" { issueRefEndNames[issue.ID] = git.RefEndName(issue.Ref) - issueRefURLs[issue.ID] = git.RefURL(repoLink, util.PathEscapeSegments(issue.Ref)) + issueRefURLs[issue.ID] = git.RefURL(repoLink, issue.Ref) } } return issueRefEndNames, issueRefURLs From 68e934ab5de6a4e8bec6f3faa8bf1e05899b8fb8 Mon Sep 17 00:00:00 2001 From: Xinyu Zhou Date: Wed, 23 Nov 2022 05:13:18 +0800 Subject: [PATCH 063/149] Add option to enable CAPTCHA validation for login (#21638) Enable this to require captcha validation for user login. You also must enable `ENABLE_CAPTCHA`. Summary: - Consolidate CAPTCHA template - add CAPTCHA handle and context - add `REQUIRE_CAPTCHA_FOR_LOGIN` config and docs - Consolidate CAPTCHA set-up and verification code Partially resolved #6049 Signed-off-by: Xinyu Zhou Signed-off-by: Andrew Thornton Co-authored-by: Andrew Thornton --- custom/conf/app.example.ini | 3 + .../doc/advanced/config-cheat-sheet.en-us.md | 1 + .../doc/advanced/config-cheat-sheet.zh-cn.md | 3 +- modules/context/captcha.go | 59 +++++++++++++++++ modules/setting/service.go | 2 + routers/web/auth/auth.go | 63 ++++++------------- routers/web/auth/linkaccount.go | 28 +-------- routers/web/auth/openid.go | 49 ++------------- services/forms/user_form.go | 11 ++-- services/forms/user_form_auth_openid.go | 7 +-- templates/user/auth/captcha.tmpl | 24 +++++++ templates/user/auth/signin_inner.tmpl | 2 + templates/user/auth/signup_inner.tmpl | 28 +-------- .../user/auth/signup_openid_register.tmpl | 28 +-------- 14 files changed, 128 insertions(+), 180 deletions(-) create mode 100644 templates/user/auth/captcha.tmpl diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 76482bf607..e7ddda4b8a 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -759,6 +759,9 @@ ROUTER = console ;; Enable captcha validation for registration ;ENABLE_CAPTCHA = false ;; +;; Enable this to require captcha validation for login +;REQUIRE_CAPTCHA_FOR_LOGIN = false +;; ;; Type of captcha you want to use. Options: image, recaptcha, hcaptcha, mcaptcha. ;CAPTCHA_TYPE = image ;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 4e7ef492f9..468c6d5edc 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -634,6 +634,7 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o - `ENABLE_REVERSE_PROXY_FULL_NAME`: **false**: Enable this to allow to auto-registration with a provided full name for the user. - `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration. +- `REQUIRE_CAPTCHA_FOR_LOGIN`: **false**: Enable this to require captcha validation for login. You also must enable `ENABLE_CAPTCHA`. - `REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA`: **false**: Enable this to force captcha validation even for External Accounts (i.e. GitHub, OpenID Connect, etc). You also must enable `ENABLE_CAPTCHA`. - `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha, mcaptcha\] diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index 576007f75b..f10b6258c8 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -145,7 +145,8 @@ menu: - `ENABLE_NOTIFY_MAIL`: 是否发送工单创建等提醒邮件,需要 `Mailer` 被激活。 - `ENABLE_REVERSE_PROXY_AUTHENTICATION`: 允许反向代理认证,更多细节见:https://github.com/gogits/gogs/issues/165 - `ENABLE_REVERSE_PROXY_AUTO_REGISTRATION`: 允许通过反向认证做自动注册。 -- `ENABLE_CAPTCHA`: 注册时使用图片验证码。 +- `ENABLE_CAPTCHA`: **false**: 注册时使用图片验证码。 +- `REQUIRE_CAPTCHA_FOR_LOGIN`: **false**: 登录时需要图片验证码。需要同时开启 `ENABLE_CAPTCHA`。 ### Service - Expore (`service.explore`) diff --git a/modules/context/captcha.go b/modules/context/captcha.go index 6117d30713..0bd003da6c 100644 --- a/modules/context/captcha.go +++ b/modules/context/captcha.go @@ -5,9 +5,15 @@ package context import ( + "fmt" "sync" + "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/cache" + "code.gitea.io/gitea/modules/hcaptcha" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/mcaptcha" + "code.gitea.io/gitea/modules/recaptcha" "code.gitea.io/gitea/modules/setting" "gitea.com/go-chi/captcha" @@ -28,3 +34,56 @@ func GetImageCaptcha() *captcha.Captcha { }) return cpt } + +// SetCaptchaData sets common captcha data +func SetCaptchaData(ctx *Context) { + if !setting.Service.EnableCaptcha { + return + } + ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha + ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL + ctx.Data["Captcha"] = GetImageCaptcha() + ctx.Data["CaptchaType"] = setting.Service.CaptchaType + ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey + ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey + ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey + ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL +} + +const ( + gRecaptchaResponseField = "g-recaptcha-response" + hCaptchaResponseField = "h-captcha-response" + mCaptchaResponseField = "m-captcha-response" +) + +// VerifyCaptcha verifies Captcha data +// No-op if captchas are not enabled +func VerifyCaptcha(ctx *Context, tpl base.TplName, form interface{}) { + if !setting.Service.EnableCaptcha { + return + } + + var valid bool + var err error + switch setting.Service.CaptchaType { + case setting.ImageCaptcha: + valid = GetImageCaptcha().VerifyReq(ctx.Req) + case setting.ReCaptcha: + valid, err = recaptcha.Verify(ctx, ctx.Req.Form.Get(gRecaptchaResponseField)) + case setting.HCaptcha: + valid, err = hcaptcha.Verify(ctx, ctx.Req.Form.Get(hCaptchaResponseField)) + case setting.MCaptcha: + valid, err = mcaptcha.Verify(ctx, ctx.Req.Form.Get(mCaptchaResponseField)) + default: + ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) + return + } + if err != nil { + log.Debug("%v", err) + } + + if !valid { + ctx.Data["Err_Captcha"] = true + ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tpl, form) + } +} diff --git a/modules/setting/service.go b/modules/setting/service.go index 10e3899950..d2eb6ebcd7 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -40,6 +40,7 @@ var Service = struct { EnableReverseProxyEmail bool EnableReverseProxyFullName bool EnableCaptcha bool + RequireCaptchaForLogin bool RequireExternalRegistrationCaptcha bool RequireExternalRegistrationPassword bool CaptchaType string @@ -130,6 +131,7 @@ func newService() { Service.EnableReverseProxyEmail = sec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool() Service.EnableReverseProxyFullName = sec.Key("ENABLE_REVERSE_PROXY_FULL_NAME").MustBool() Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool(false) + Service.RequireCaptchaForLogin = sec.Key("REQUIRE_CAPTCHA_FOR_LOGIN").MustBool(false) Service.RequireExternalRegistrationCaptcha = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA").MustBool(Service.EnableCaptcha) Service.RequireExternalRegistrationPassword = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_PASSWORD").MustBool() Service.CaptchaType = sec.Key("CAPTCHA_TYPE").MustString(ImageCaptcha) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 2919fd3513..133a7cced1 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -17,11 +17,8 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/eventsource" - "code.gitea.io/gitea/modules/hcaptcha" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/mcaptcha" "code.gitea.io/gitea/modules/password" - "code.gitea.io/gitea/modules/recaptcha" "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" @@ -163,6 +160,10 @@ func SignIn(ctx *context.Context) { ctx.Data["PageIsLogin"] = true ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled() + if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { + context.SetCaptchaData(ctx) + } + ctx.HTML(http.StatusOK, tplSignIn) } @@ -189,6 +190,16 @@ func SignInPost(ctx *context.Context) { } form := web.GetForm(ctx).(*forms.SignInForm) + + if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { + context.SetCaptchaData(ctx) + + context.VerifyCaptcha(ctx, tplSignIn, form) + if ctx.Written() { + return + } + } + u, source, err := auth_service.UserSignIn(form.UserName, form.Password) if err != nil { if user_model.IsErrUserNotExist(err) || user_model.IsErrEmailAddressNotExist(err) { @@ -383,14 +394,7 @@ func SignUp(ctx *context.Context) { ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up" - ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha - ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL - ctx.Data["Captcha"] = context.GetImageCaptcha() - ctx.Data["CaptchaType"] = setting.Service.CaptchaType - ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey - ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey - ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey - ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL + context.SetCaptchaData(ctx) ctx.Data["PageIsSignUp"] = true // Show Disabled Registration message if DisableRegistration or AllowOnlyExternalRegistration options are true @@ -406,14 +410,7 @@ func SignUpPost(ctx *context.Context) { ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up" - ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha - ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL - ctx.Data["Captcha"] = context.GetImageCaptcha() - ctx.Data["CaptchaType"] = setting.Service.CaptchaType - ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey - ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey - ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey - ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL + context.SetCaptchaData(ctx) ctx.Data["PageIsSignUp"] = true // Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true @@ -427,31 +424,9 @@ func SignUpPost(ctx *context.Context) { return } - if setting.Service.EnableCaptcha { - var valid bool - var err error - switch setting.Service.CaptchaType { - case setting.ImageCaptcha: - valid = context.GetImageCaptcha().VerifyReq(ctx.Req) - case setting.ReCaptcha: - valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse) - case setting.HCaptcha: - valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse) - case setting.MCaptcha: - valid, err = mcaptcha.Verify(ctx, form.McaptchaResponse) - default: - ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) - return - } - if err != nil { - log.Debug("%s", err.Error()) - } - - if !valid { - ctx.Data["Err_Captcha"] = true - ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUp, &form) - return - } + context.VerifyCaptcha(ctx, tplSignUp, form) + if ctx.Written() { + return } if !form.IsEmailDomainAllowed() { diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index d3211eaa5c..c36eaee078 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -14,10 +14,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/hcaptcha" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/mcaptcha" - "code.gitea.io/gitea/modules/recaptcha" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" auth_service "code.gitea.io/gitea/services/auth" @@ -221,28 +217,8 @@ func LinkAccountPostRegister(ctx *context.Context) { } if setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha { - var valid bool - var err error - switch setting.Service.CaptchaType { - case setting.ImageCaptcha: - valid = context.GetImageCaptcha().VerifyReq(ctx.Req) - case setting.ReCaptcha: - valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse) - case setting.HCaptcha: - valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse) - case setting.MCaptcha: - valid, err = mcaptcha.Verify(ctx, form.McaptchaResponse) - default: - ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) - return - } - if err != nil { - log.Debug("%s", err.Error()) - } - - if !valid { - ctx.Data["Err_Captcha"] = true - ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplLinkAccount, &form) + context.VerifyCaptcha(ctx, tplLinkAccount, form) + if ctx.Written() { return } } diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index d34f4db7c0..eedf3f5c1b 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -13,10 +13,7 @@ import ( "code.gitea.io/gitea/modules/auth/openid" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/hcaptcha" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/mcaptcha" - "code.gitea.io/gitea/modules/recaptcha" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -357,14 +354,7 @@ func RegisterOpenIDPost(ctx *context.Context) { ctx.Data["PageIsSignIn"] = true ctx.Data["PageIsOpenIDRegister"] = true ctx.Data["EnableOpenIDSignUp"] = setting.Service.EnableOpenIDSignUp - ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha - ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL - ctx.Data["Captcha"] = context.GetImageCaptcha() - ctx.Data["CaptchaType"] = setting.Service.CaptchaType - ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey - ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey - ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey - ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL + context.SetCaptchaData(ctx) ctx.Data["OpenID"] = oid if setting.Service.AllowOnlyInternalRegistration { @@ -373,42 +363,11 @@ func RegisterOpenIDPost(ctx *context.Context) { } if setting.Service.EnableCaptcha { - var valid bool - var err error - switch setting.Service.CaptchaType { - case setting.ImageCaptcha: - valid = context.GetImageCaptcha().VerifyReq(ctx.Req) - case setting.ReCaptcha: - if err := ctx.Req.ParseForm(); err != nil { - ctx.ServerError("", err) - return - } - valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse) - case setting.HCaptcha: - if err := ctx.Req.ParseForm(); err != nil { - ctx.ServerError("", err) - return - } - valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse) - case setting.MCaptcha: - if err := ctx.Req.ParseForm(); err != nil { - ctx.ServerError("", err) - return - } - valid, err = mcaptcha.Verify(ctx, form.McaptchaResponse) - default: - ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) - return - } - if err != nil { - log.Debug("%s", err.Error()) - } - - if !valid { - ctx.Data["Err_Captcha"] = true - ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUpOID, &form) + if err := ctx.Req.ParseForm(); err != nil { + ctx.ServerError("", err) return } + context.VerifyCaptcha(ctx, tplSignUpOID, form) } length := setting.MinPasswordLength diff --git a/services/forms/user_form.go b/services/forms/user_form.go index ed8ccf12ea..da30ae94d6 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -91,13 +91,10 @@ func (f *InstallForm) Validate(req *http.Request, errs binding.Errors) binding.E // RegisterForm form for registering type RegisterForm struct { - UserName string `binding:"Required;Username;MaxSize(40)"` - Email string `binding:"Required;MaxSize(254)"` - Password string `binding:"MaxSize(255)"` - Retype string - GRecaptchaResponse string `form:"g-recaptcha-response"` - HcaptchaResponse string `form:"h-captcha-response"` - McaptchaResponse string `form:"m-captcha-response"` + UserName string `binding:"Required;Username;MaxSize(40)"` + Email string `binding:"Required;MaxSize(254)"` + Password string `binding:"MaxSize(255)"` + Retype string } // Validate validates the fields diff --git a/services/forms/user_form_auth_openid.go b/services/forms/user_form_auth_openid.go index d1ed0a23c7..459c938f08 100644 --- a/services/forms/user_form_auth_openid.go +++ b/services/forms/user_form_auth_openid.go @@ -27,11 +27,8 @@ func (f *SignInOpenIDForm) Validate(req *http.Request, errs binding.Errors) bind // SignUpOpenIDForm form for signin up with OpenID type SignUpOpenIDForm struct { - UserName string `binding:"Required;Username;MaxSize(40)"` - Email string `binding:"Required;Email;MaxSize(254)"` - GRecaptchaResponse string `form:"g-recaptcha-response"` - HcaptchaResponse string `form:"h-captcha-response"` - McaptchaResponse string `form:"m-captcha-response"` + UserName string `binding:"Required;Username;MaxSize(40)"` + Email string `binding:"Required;Email;MaxSize(254)"` } // Validate validates the fields diff --git a/templates/user/auth/captcha.tmpl b/templates/user/auth/captcha.tmpl new file mode 100644 index 0000000000..87b22a0720 --- /dev/null +++ b/templates/user/auth/captcha.tmpl @@ -0,0 +1,24 @@ +{{if .EnableCaptcha}}{{if eq .CaptchaType "image"}} +
+ + {{.Captcha.CreateHTML}} +
+
+ + +
+{{else if eq .CaptchaType "recaptcha"}} +
+
+
+{{else if eq .CaptchaType "hcaptcha"}} +
+
+
+{{else if eq .CaptchaType "mcaptcha"}} +
+ {{.locale.Tr "captcha"}} +
+
+
+{{end}}{{end}} diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl index 18875f45a3..f14bac10ee 100644 --- a/templates/user/auth/signin_inner.tmpl +++ b/templates/user/auth/signin_inner.tmpl @@ -31,6 +31,8 @@
{{end}} + {{template "user/auth/captcha" .}} +
{{end}} - {{if and .EnableCaptcha (eq .CaptchaType "image")}} -
- - {{.Captcha.CreateHTML}} -
-
- - -
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "recaptcha")}} -
-
-
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "hcaptcha")}} -
-
-
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "mcaptcha")}} -
- {{.locale.Tr "captcha"}} -
-
-
- {{end}} + {{template "user/auth/captcha" .}}
diff --git a/templates/user/auth/signup_openid_register.tmpl b/templates/user/auth/signup_openid_register.tmpl index 9c0558311f..e54600ec82 100644 --- a/templates/user/auth/signup_openid_register.tmpl +++ b/templates/user/auth/signup_openid_register.tmpl @@ -20,31 +20,9 @@
- {{if and .EnableCaptcha (eq .CaptchaType "image")}} -
- - {{.Captcha.CreateHTML}} -
-
- - -
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "recaptcha")}} -
-
-
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "hcaptcha")}} -
-
-
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "mcaptcha")}} -
-
-
- {{end}} + + {{template "user/auth/captcha" .}} +
From ee21d5453f335e2530ba947e1896353d663525ad Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 23 Nov 2022 01:22:27 +0100 Subject: [PATCH 064/149] Move all remaining colors into CSS variables (#21903) This should eliminate all non-variable color usage in the styles, making gitea fully themeable via CSS variables. Also, it adds a linter to enforce variables for colors. --- .stylelintrc.yaml | 11 +++ package-lock.json | 120 +++++++++++++++++++++++ package.json | 1 + web_src/less/_base.less | 27 +++-- web_src/less/_dashboard.less | 2 +- web_src/less/_install.less | 2 +- web_src/less/_repository.less | 66 ++++++------- web_src/less/themes/theme-arc-green.less | 13 +++ 8 files changed, 199 insertions(+), 43 deletions(-) diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml index 342bf6a4e8..d51a08bf8e 100644 --- a/.stylelintrc.yaml +++ b/.stylelintrc.yaml @@ -1,8 +1,19 @@ extends: stylelint-config-standard +plugins: + - stylelint-declaration-strict-value + overrides: - files: ["**/*.less"] customSyntax: postcss-less + - files: ["**/*.less"] + rules: + scale-unlimited/declaration-strict-value: [color, { + ignoreValues: /^(inherit|transparent|unset|initial)$/ + }] + - files: ["**/chroma/*", "**/codemirror/*", "**/standalone/*", "**/console/*"] + rules: + scale-unlimited/declaration-strict-value: null rules: alpha-value-notation: null diff --git a/package-lock.json b/package-lock.json index 346dae412d..b9c649c9de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,6 +65,7 @@ "postcss-less": "6.0.0", "stylelint": "14.15.0", "stylelint-config-standard": "29.0.0", + "stylelint-declaration-strict-value": "1.9.1", "svgo": "3.0.2", "updates": "13.2.1", "vitest": "0.25.2" @@ -2260,6 +2261,15 @@ "node": ">= 8" } }, + "node_modules/css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/css-functions-list": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.1.0.tgz", @@ -2310,6 +2320,12 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-shorthand-properties": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-shorthand-properties/-/css-shorthand-properties-1.1.1.tgz", + "integrity": "sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A==", + "dev": true + }, "node_modules/css-tree": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", @@ -2324,6 +2340,23 @@ "npm": ">=7.0.0" } }, + "node_modules/css-values": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/css-values/-/css-values-0.1.0.tgz", + "integrity": "sha512-hQ6JSn4t/70aOCvdlP9zTOsFFUifMSKWz3PX7rz5NZl+uEHCqTFVJJvfP07isErCGEVHYoc8Orja8wLKZRvOeg==", + "dev": true, + "dependencies": { + "css-color-names": "0.0.4", + "ends-with": "^0.2.0", + "postcss-value-parser": "^3.3.0" + } + }, + "node_modules/css-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, "node_modules/css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -3497,6 +3530,15 @@ "node": ">= 4" } }, + "node_modules/ends-with": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ends-with/-/ends-with-0.2.0.tgz", + "integrity": "sha512-lRppY4dK3VkqBdR242sKcAJeYc8Gf/DhoX9AWvWI2RzccmLnqBQfwm2k4oSDv5MPDjUqawCauXhZkyWxkVhRsg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", @@ -7990,6 +8032,15 @@ "node": ">=8" } }, + "node_modules/shortcss": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/shortcss/-/shortcss-0.1.3.tgz", + "integrity": "sha512-MIOoTd99CIGTrAuGiMUx9VZrnrZmWzEHuKbGM/w+ia/w98cezhlN9w4aQOVSxswdoqkUnWrMw3tThOi3sevZAg==", + "dev": true, + "dependencies": { + "css-shorthand-properties": "^1.0.0" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -8399,6 +8450,19 @@ "stylelint": "^14.14.0" } }, + "node_modules/stylelint-declaration-strict-value": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stylelint-declaration-strict-value/-/stylelint-declaration-strict-value-1.9.1.tgz", + "integrity": "sha512-iIkMh2ukIfSTtJoEDgGq5cqUyYWP8NExPk2YSGcePtFikb7KmJoSi0QYajiZRxge/PTbYspci7nIcrtArJlAsw==", + "dev": true, + "dependencies": { + "css-values": "^0.1.0", + "shortcss": "^0.1.3" + }, + "peerDependencies": { + "stylelint": ">=7 <=14" + } + }, "node_modules/stylelint/node_modules/balanced-match": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", @@ -11448,6 +11512,12 @@ "which": "^2.0.1" } }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==", + "dev": true + }, "css-functions-list": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.1.0.tgz", @@ -11482,6 +11552,12 @@ "nth-check": "^2.0.1" } }, + "css-shorthand-properties": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-shorthand-properties/-/css-shorthand-properties-1.1.1.tgz", + "integrity": "sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A==", + "dev": true + }, "css-tree": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", @@ -11492,6 +11568,25 @@ "source-map-js": "^1.0.1" } }, + "css-values": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/css-values/-/css-values-0.1.0.tgz", + "integrity": "sha512-hQ6JSn4t/70aOCvdlP9zTOsFFUifMSKWz3PX7rz5NZl+uEHCqTFVJJvfP07isErCGEVHYoc8Orja8wLKZRvOeg==", + "dev": true, + "requires": { + "css-color-names": "0.0.4", + "ends-with": "^0.2.0", + "postcss-value-parser": "^3.3.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, "css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -12421,6 +12516,12 @@ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" }, + "ends-with": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ends-with/-/ends-with-0.2.0.tgz", + "integrity": "sha512-lRppY4dK3VkqBdR242sKcAJeYc8Gf/DhoX9AWvWI2RzccmLnqBQfwm2k4oSDv5MPDjUqawCauXhZkyWxkVhRsg==", + "dev": true + }, "enhanced-resolve": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", @@ -15622,6 +15723,15 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, + "shortcss": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/shortcss/-/shortcss-0.1.3.tgz", + "integrity": "sha512-MIOoTd99CIGTrAuGiMUx9VZrnrZmWzEHuKbGM/w+ia/w98cezhlN9w4aQOVSxswdoqkUnWrMw3tThOi3sevZAg==", + "dev": true, + "requires": { + "css-shorthand-properties": "^1.0.0" + } + }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -15970,6 +16080,16 @@ "stylelint-config-recommended": "^9.0.0" } }, + "stylelint-declaration-strict-value": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stylelint-declaration-strict-value/-/stylelint-declaration-strict-value-1.9.1.tgz", + "integrity": "sha512-iIkMh2ukIfSTtJoEDgGq5cqUyYWP8NExPk2YSGcePtFikb7KmJoSi0QYajiZRxge/PTbYspci7nIcrtArJlAsw==", + "dev": true, + "requires": { + "css-values": "^0.1.0", + "shortcss": "^0.1.3" + } + }, "stylis": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", diff --git a/package.json b/package.json index a90c1618fa..15c2601cd7 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "postcss-less": "6.0.0", "stylelint": "14.15.0", "stylelint-config-standard": "29.0.0", + "stylelint-declaration-strict-value": "1.9.1", "svgo": "3.0.2", "updates": "13.2.1", "vitest": "0.25.2" diff --git a/web_src/less/_base.less b/web_src/less/_base.less index 6054331ec4..14b69dec49 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -118,6 +118,20 @@ --color-info-border: #a9d5de; --color-info-bg: #f8ffff; --color-info-text: #276f86; + --color-red-badge: #db2828; + --color-red-badge-bg: #db28281a; + --color-red-badge-hover-bg: #db28284d; + --color-green-badge: #21ba45; + --color-green-badge-bg: #21ba451a; + --color-green-badge-hover-bg: #21ba454d; + --color-yellow-badge: #fbbd08; + --color-yellow-badge-bg: #fbbd081a; + --color-yellow-badge-hover-bg: #fbbd084d; + --color-orange-badge: #f2711c; + --color-orange-badge-bg: #f2711c1a; + --color-orange-badge-hover-bg: #f2711c4d; + --color-git: #f05133; + /* target-based colors */ --color-body: #ffffff; --color-text-dark: #080808; --color-text: #212121; @@ -1196,11 +1210,7 @@ a.ui.card:hover, } .searchbox { - background-color: #f4f4f4 !important; - - &:focus { - background-color: #e9e9e9 !important; - } + background-color: var(--color-input-background) !important; } .text .svg { @@ -1932,7 +1942,7 @@ footer { } .archived-icon { - color: lighten(#000000, 70%) !important; + color: var(--color-secondary-dark-2) !important; } .oauth2-authorize-application-box { @@ -2085,7 +2095,7 @@ a.ui.label:hover { .lines-commit { &:extend(.unselectable); vertical-align: top; - color: #999999; + color: var(--color-grey); padding: 0 !important; background: var(--color-code-sidebar-bg); width: 1%; @@ -2161,6 +2171,7 @@ a.ui.label:hover { color: var(--color-text); } +.ui.active.button, .ui.button:active, .ui.active.button:active, .ui.active.button:hover { @@ -2312,7 +2323,7 @@ a.ui.basic.label:hover { } .migrate .svg.gitea-git { - color: #f05133; /* from https://upload.wikimedia.org/wikipedia/commons/e/e0/Git-logo.svg */ + color: var(--color-git); } .color-icon { diff --git a/web_src/less/_dashboard.less b/web_src/less/_dashboard.less index e9a906cbed..4ba0788af1 100644 --- a/web_src/less/_dashboard.less +++ b/web_src/less/_dashboard.less @@ -183,7 +183,7 @@ } #privateFilterCheckbox .svg { - color: #888888; + color: var(--color-grey); margin-right: .25rem; } diff --git a/web_src/less/_install.less b/web_src/less/_install.less index 515d727f8a..026a76fbba 100644 --- a/web_src/less/_install.less +++ b/web_src/less/_install.less @@ -59,7 +59,7 @@ .reinstall-message { width: 70%; margin: 20px auto; - color: red; + color: var(--color-red); text-align: left; font-weight: bold; } diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less index f89a5df33d..85cb842b72 100644 --- a/web_src/less/_repository.less +++ b/web_src/less/_repository.less @@ -548,7 +548,7 @@ position: absolute; top: 9px; left: 10px; - color: #b0c4ce; + color: var(--color-grey); } } } @@ -915,8 +915,8 @@ border: 1px solid var(--color-light-border); &.isSigned.isWarning { - border: 1px solid #db2828; - background: fade(#db2828, 10%); + border: 1px solid var(--color-red-badge); + background: var(--color-red-badge-bg); .shortsha { display: inline-block; @@ -924,13 +924,13 @@ } &:hover { - background: fade(#db2828, 30%) !important; + background: var(--color-red-badge-hover-bg) !important; } } &.isSigned.isVerified { - border: 1px solid #21ba45; - background: fade(#21ba45, 10%); + border: 1px solid var(--color-green-badge); + background: var(--color-green-badge-bg); .shortsha { display: inline-block; @@ -938,13 +938,13 @@ } &:hover { - background: fade(#21ba45, 30%) !important; + background: var(--color-green-badge-hover-bg) !important; } } &.isSigned.isVerifiedUntrusted { - border: 1px solid #fbbd08; - background: fade(#fbbd08, 10%); + border: 1px solid var(--color-yellow-badge); + background: var(--color-yellow-badge-bg); .shortsha { display: inline-block; @@ -952,13 +952,13 @@ } &:hover { - background: fade(#fbbd08, 30%) !important; + background: var(--color-yellow-badge-hover-bg) !important; } } &.isSigned.isVerifiedUnmatched { - border: 1px solid #f2711c; - background: fade(#f2711c, 10%); + border: 1px solid var(--color-orange-badge); + background: var(--color-orange-badge-bg); .shortsha { display: inline-block; @@ -966,7 +966,7 @@ } &:hover { - background: fade(#f2711c, 30%) !important; + background: var(--color-orange-badge-hover-bg) !important; } } } @@ -1433,8 +1433,8 @@ } &.isSigned.isWarning { - border: 1px solid #db2828; - background: fade(#db2828, 10%); + border: 1px solid var(--color-red-badge); + background: var(--color-red-badge-bg); .shortsha { display: inline-block; @@ -1442,18 +1442,18 @@ } .detail.icon { - border-left: 1px solid #db2828; - color: #db2828; + border-left: 1px solid var(--color-red-badge); + color: var(--color-red-badge); } &:hover { - background: fade(#db2828, 30%) !important; + background: var(--color-red-badge-hover-bg) !important; } } &.isSigned.isVerified { - border: 1px solid #21ba45; - background: fade(#21ba45, 10%); + border: 1px solid var(--color-green-badge); + background: var(--color-green-badge-bg); .shortsha { display: inline-block; @@ -1461,18 +1461,18 @@ } .detail.icon { - border-left: 1px solid #21ba45; - color: #21ba45; + border-left: 1px solid var(--color-green-badge); + color: var(--color-green-badge); } &:hover { - background: fade(#21ba45, 30%) !important; + background: var(--color-green-badge-hover-bg) !important; } } &.isSigned.isVerifiedUntrusted { - border: 1px solid #fbbd08; - background: fade(#fbbd08, 10%); + border: 1px solid var(--color-yellow-badge); + background: var(--color-yellow-badge-bg); .shortsha { display: inline-block; @@ -1480,18 +1480,18 @@ } .detail.icon { - border-left: 1px solid #fbbd08; - color: #fbbd08; + border-left: 1px solid var(--color-yellow-badge); + color: var(--color-yellow-badge); } &:hover { - background: fade(#fbbd08, 30%) !important; + background: var(--color-yellow-badge-hover-bg) !important; } } &.isSigned.isVerifiedUnmatched { - border: 1px solid #f2711c; - background: fade(#f2711c, 10%); + border: 1px solid var(--color-orange-badge); + background: var(--color-orange-badge-bg); .shortsha { display: inline-block; @@ -1499,12 +1499,12 @@ } .detail.icon { - border-left: 1px solid #f2711c; - color: #f2711c; + border-left: 1px solid var(--color-orange-badge); + color: var(--color-orange-badge); } &:hover { - background: fade(#f2711c, 30%) !important; + background: var(--color-orange-badge-hover-bg) !important; } } } diff --git a/web_src/less/themes/theme-arc-green.less b/web_src/less/themes/theme-arc-green.less index fab1b9c3b4..8c05ad278f 100644 --- a/web_src/less/themes/theme-arc-green.less +++ b/web_src/less/themes/theme-arc-green.less @@ -107,6 +107,19 @@ --color-info-border: #306090; --color-info-bg: #26354c; --color-info-text: #38a8e8; + --color-red-badge: #db2828; + --color-red-badge-bg: #db28281a; + --color-red-badge-hover-bg: #db28284d; + --color-green-badge: #21ba45; + --color-green-badge-bg: #21ba451a; + --color-green-badge-hover-bg: #21ba454d; + --color-yellow-badge: #fbbd08; + --color-yellow-badge-bg: #fbbd081a; + --color-yellow-badge-hover-bg: #fbbd084d; + --color-orange-badge: #f2711c; + --color-orange-badge-bg: #f2711c1a; + --color-orange-badge-hover-bg: #f2711c4d; + --color-git: #f05133; /* target-based colors */ --color-body: #383c4a; --color-box-header: #404652; From 4d42cbbcc2acbc81102a1abbcc6eec67b6802832 Mon Sep 17 00:00:00 2001 From: zeripath Date: Wed, 23 Nov 2022 00:52:57 +0000 Subject: [PATCH 065/149] Handle empty author names (#21902) Although git does expect that author names should be of the form: `NAME ` some users have been able to create commits with: `` Fix #21900 Signed-off-by: Andrew Thornton Co-authored-by: delvh Co-authored-by: Lauris BH Co-authored-by: Lunny Xiao --- modules/git/signature_gogit.go | 5 ++++- modules/git/signature_nogogit.go | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/git/signature_gogit.go b/modules/git/signature_gogit.go index 6f1c98420d..5ab38cd852 100644 --- a/modules/git/signature_gogit.go +++ b/modules/git/signature_gogit.go @@ -10,6 +10,7 @@ package git import ( "bytes" "strconv" + "strings" "time" "github.com/go-git/go-git/v5/plumbing/object" @@ -30,7 +31,9 @@ type Signature = object.Signature func newSignatureFromCommitline(line []byte) (_ *Signature, err error) { sig := new(Signature) emailStart := bytes.IndexByte(line, '<') - sig.Name = string(line[:emailStart-1]) + if emailStart > 0 { // Empty name has already occurred, even if it shouldn't + sig.Name = strings.TrimSpace(string(line[:emailStart-1])) + } emailEnd := bytes.IndexByte(line, '>') sig.Email = string(line[emailStart+1 : emailEnd]) diff --git a/modules/git/signature_nogogit.go b/modules/git/signature_nogogit.go index 07a3b79f1e..3fa5c8da3e 100644 --- a/modules/git/signature_nogogit.go +++ b/modules/git/signature_nogogit.go @@ -11,6 +11,7 @@ import ( "bytes" "fmt" "strconv" + "strings" "time" ) @@ -51,7 +52,9 @@ func newSignatureFromCommitline(line []byte) (sig *Signature, err error) { return } - sig.Name = string(line[:emailStart-1]) + if emailStart > 0 { // Empty name has already occurred, even if it shouldn't + sig.Name = strings.TrimSpace(string(line[:emailStart-1])) + } sig.Email = string(line[emailStart+1 : emailEnd]) hasTime := emailEnd+2 < len(line) From 13746f070ddb4b7ba93249e9335352431073c271 Mon Sep 17 00:00:00 2001 From: kolaente Date: Wed, 23 Nov 2022 11:24:03 +0100 Subject: [PATCH 066/149] feat: add button to quickly clear merge message (#21548) This PR adds a button to allow quickly clearing the merge message of a PR. The button will remove everything but the git trailers. I found myself often pruning the commit message before merging, especially for PRs generated by renovate - renovate puts a very long and detailed comment with the full changelog in each PR it opens. This clutters the commit message. However, I want to explicitly preserve the git commit trailers. Doing this manually works, but having a button is a lot easier. Screenshot: ![image](https://user-images.githubusercontent.com/13721712/197337525-d456d0f8-1f7c-43a9-815d-ca93b1e7a90a.png) Co-authored-by: Lunny Xiao Co-authored-by: wxiaoguang Co-authored-by: delvh --- options/locale/locale_en-US.ini | 2 ++ templates/repo/issue/view_content/pull.tmpl | 3 +++ web_src/js/components/PullRequestMergeForm.vue | 11 +++++++++++ 3 files changed, 16 insertions(+) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 02598dc3dc..8503cb78d7 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1630,6 +1630,8 @@ pulls.reopened_at = `reopened this pull request %[2] pulls.merge_instruction_hint = `You can also view command line instructions.` pulls.merge_instruction_step1_desc = From your project repository, check out a new branch and test the changes. pulls.merge_instruction_step2_desc = Merge the changes and update on Gitea. +pulls.clear_merge_message = Clear merge message +pulls.clear_merge_message_hint = Clearing the merge message will only remove the commit message content and keep generated git trailers such as "Co-Authored-By …". pulls.auto_merge_button_when_succeed = (When checks succeed) pulls.auto_merge_when_succeed = Auto merge when all checks succeed diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 1e07225300..9e0909064d 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -351,6 +351,8 @@ 'textAutoMergeButtonWhenSucceed': {{$.locale.Tr "repo.pulls.auto_merge_button_when_succeed"}}, 'textAutoMergeWhenSucceed': {{$.locale.Tr "repo.pulls.auto_merge_when_succeed"}}, 'textAutoMergeCancelSchedule': {{$.locale.Tr "repo.pulls.auto_merge_cancel_schedule"}}, + 'textClearMergeMessage': {{$.locale.Tr "repo.pulls.clear_merge_message"}}, + 'textClearMergeMessageHint': {{$.locale.Tr "repo.pulls.clear_merge_message_hint"}}, 'canMergeNow': {{$canMergeNow}}, 'allOverridableChecksOk': {{not $notAllOverridableChecksOk}}, @@ -360,6 +362,7 @@ 'defaultMergeStyle': {{.MergeStyle}}, 'defaultDeleteBranchAfterMerge': {{$prUnit.PullRequestsConfig.DefaultDeleteBranchAfterMerge}}, 'mergeMessageFieldPlaceHolder': {{$.locale.Tr "repo.editor.commit_message_desc"}}, + 'defaultMergeMessage': defaultMergeMessage, 'hasPendingPullRequestMerge': {{.HasPendingPullRequestMerge}}, 'hasPendingPullRequestMergeTip': {{$hasPendingPullRequestMergeTip}}, diff --git a/web_src/js/components/PullRequestMergeForm.vue b/web_src/js/components/PullRequestMergeForm.vue index bfe05628e8..1fec12dd5a 100644 --- a/web_src/js/components/PullRequestMergeForm.vue +++ b/web_src/js/components/PullRequestMergeForm.vue @@ -25,6 +25,14 @@