Skip to content

Commit

Permalink
Merge remote-tracking branch 'giteaofficial/main'
Browse files Browse the repository at this point in the history
* giteaofficial/main: (32 commits)
  [skip ci] Updated translations via Crowdin
  Prevent double use of `git cat-file` session. (go-gitea#29298)
  Revert go-gitea#28753 because UI broken. (go-gitea#29293)
  Fix error display when merging PRs (go-gitea#29288)
  Refactor markup rendering to accept general "protocol:" prefix (go-gitea#29276)
  Remove jQuery from the installation page (go-gitea#29284)
  Always write proc-receive hook for all git versions (go-gitea#29287)
  Do not use `ctx.Doer` when reset password (go-gitea#29289)
  Update Discord logo (go-gitea#29285)
  [skip ci] Updated translations via Crowdin
  Remove jQuery .map() and enable eslint rules for it (go-gitea#29272)
  Explained where create issue/PR template (go-gitea#29035) (go-gitea#29266)
  Remove jQuery from repo wiki creation page (go-gitea#29271)
  Do not show delete button when time tracker is disabled (go-gitea#29257)
  Left align the input labels for the link account page (go-gitea#29255)
  [skip ci] Updated translations via Crowdin
  Remove jQuery from the repo migration form (go-gitea#29229)
  Fix content size does not match error when uploading lfs file (go-gitea#29259)
  Workaround to clean up old reviews on creating a new one (go-gitea#28554)
  Deduplicate translations for contributors graph (go-gitea#29256)
  ...
  • Loading branch information
zjjhot committed Feb 22, 2024
2 parents 530f74f + 2bd999a commit cc8215a
Show file tree
Hide file tree
Showing 107 changed files with 1,642 additions and 536 deletions.
6 changes: 3 additions & 3 deletions .eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ rules:
jquery/no-delegate: [2]
jquery/no-each: [0]
jquery/no-extend: [2]
jquery/no-fade: [0]
jquery/no-fade: [2]
jquery/no-filter: [0]
jquery/no-find: [0]
jquery/no-global-eval: [2]
Expand All @@ -309,7 +309,7 @@ rules:
jquery/no-is-function: [2]
jquery/no-is: [0]
jquery/no-load: [2]
jquery/no-map: [0]
jquery/no-map: [2]
jquery/no-merge: [2]
jquery/no-param: [2]
jquery/no-parent: [0]
Expand Down Expand Up @@ -451,7 +451,7 @@ rules:
no-jquery/no-load: [2]
no-jquery/no-map-collection: [0]
no-jquery/no-map-util: [2]
no-jquery/no-map: [0]
no-jquery/no-map: [2]
no-jquery/no-merge: [2]
no-jquery/no-node-name: [2]
no-jquery/no-noop: [2]
Expand Down
3 changes: 2 additions & 1 deletion docs/content/usage/issue-pull-request-templates.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ menu:

Some projects have a standard list of questions that users need to answer
when creating an issue or pull request. Gitea supports adding templates to the
main branch of the repository so that they can autopopulate the form when users are
**default branch of the repository** so that they can autopopulate the form when users are
creating issues and pull requests. This will cut down on the initial back and forth
of getting some clarifying details.
It is currently not possible to provide generic issue/pull-request templates globally.

Additionally, the New Issue page URL can be suffixed with `?title=Issue+Title&body=Issue+Text` and the form will be populated with those strings. Those strings will be used instead of the template if there is one.

Expand Down
40 changes: 35 additions & 5 deletions models/issues/review.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,14 @@ func IsOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organizatio

// CreateReview creates a new review based on opts
func CreateReview(ctx context.Context, opts CreateReviewOptions) (*Review, error) {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return nil, err
}
defer committer.Close()
sess := db.GetEngine(ctx)

review := &Review{
Type: opts.Type,
Issue: opts.Issue,
IssueID: opts.Issue.ID,
Reviewer: opts.Reviewer,
Expand All @@ -303,15 +309,39 @@ func CreateReview(ctx context.Context, opts CreateReviewOptions) (*Review, error
CommitID: opts.CommitID,
Stale: opts.Stale,
}

if opts.Reviewer != nil {
review.Type = opts.Type
review.ReviewerID = opts.Reviewer.ID
} else {
if review.Type != ReviewTypeRequest {
review.Type = ReviewTypeRequest

reviewCond := builder.Eq{"reviewer_id": opts.Reviewer.ID, "issue_id": opts.Issue.ID}
// make sure user review requests are cleared
if opts.Type != ReviewTypePending {
if _, err := sess.Where(reviewCond.And(builder.Eq{"type": ReviewTypeRequest})).Delete(new(Review)); err != nil {
return nil, err
}
}
// make sure if the created review gets dismissed no old review surface
// other types can be ignored, as they don't affect branch protection
if opts.Type == ReviewTypeApprove || opts.Type == ReviewTypeReject {
if _, err := sess.Where(reviewCond.And(builder.In("type", ReviewTypeApprove, ReviewTypeReject))).
Cols("dismissed").Update(&Review{Dismissed: true}); err != nil {
return nil, err
}
}

} else if opts.ReviewerTeam != nil {
review.Type = ReviewTypeRequest
review.ReviewerTeamID = opts.ReviewerTeam.ID

} else {
return nil, fmt.Errorf("provide either reviewer or reviewer team")
}

if _, err := sess.Insert(review); err != nil {
return nil, err
}
return review, db.Insert(ctx, review)
return review, committer.Commit()
}

// GetCurrentReview returns the current pending review of reviewer for given issue
Expand Down
8 changes: 4 additions & 4 deletions models/unittest/unit_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ func AssertSuccessfulInsert(t assert.TestingT, beans ...any) {
}

// AssertCount assert the count of a bean
func AssertCount(t assert.TestingT, bean, expected any) {
assert.EqualValues(t, expected, GetCount(t, bean))
func AssertCount(t assert.TestingT, bean, expected any) bool {
return assert.EqualValues(t, expected, GetCount(t, bean))
}

// AssertInt64InRange assert value is in range [low, high]
Expand All @@ -150,7 +150,7 @@ func GetCountByCond(t assert.TestingT, tableName string, cond builder.Cond) int6
}

// AssertCountByCond test the count of database entries matching bean
func AssertCountByCond(t assert.TestingT, tableName string, cond builder.Cond, expected int) {
assert.EqualValues(t, expected, GetCountByCond(t, tableName, cond),
func AssertCountByCond(t assert.TestingT, tableName string, cond builder.Cond, expected int) bool {
return assert.EqualValues(t, expected, GetCountByCond(t, tableName, cond),
"Failed consistency test, the counted bean (of table %s) was %+v", tableName, cond)
}
2 changes: 1 addition & 1 deletion modules/base/tool.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func CreateTimeLimitCode(data string, minutes int, startInf any) string {

// create sha1 encode string
sh := sha1.New()
_, _ = sh.Write([]byte(fmt.Sprintf("%s%s%s%s%d", data, setting.SecretKey, startStr, endStr, minutes)))
_, _ = sh.Write([]byte(fmt.Sprintf("%s%s%s%s%d", data, hex.EncodeToString(setting.GetGeneralTokenSigningSecret()), startStr, endStr, minutes)))
encoded := hex.EncodeToString(sh.Sum(nil))

code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded)
Expand Down
3 changes: 2 additions & 1 deletion modules/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package context

import (
"context"
"encoding/hex"
"fmt"
"html/template"
"io"
Expand Down Expand Up @@ -124,7 +125,7 @@ func NewWebContext(base *Base, render Render, session session.Store) *Context {
func Contexter() func(next http.Handler) http.Handler {
rnd := templates.HTMLRenderer()
csrfOpts := CsrfOptions{
Secret: setting.SecretKey,
Secret: hex.EncodeToString(setting.GetGeneralTokenSigningSecret()),
Cookie: setting.CSRFCookieName,
SetCookie: true,
Secure: setting.SessionConfig.Secure,
Expand Down
14 changes: 0 additions & 14 deletions modules/context/context_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ package context

import (
"context"
"errors"
"time"

"code.gitea.io/gitea/modules/log"
)

var _ context.Context = TemplateContext(nil)
Expand Down Expand Up @@ -36,14 +33,3 @@ func (c TemplateContext) Err() error {
func (c TemplateContext) Value(key any) any {
return c.parentContext().Value(key)
}

// DataRaceCheck checks whether the template context function "ctx()" returns the consistent context
// as the current template's rendering context (request context), to help to find data race issues as early as possible.
// When the code is proven to be correct and stable, this function should be removed.
func (c TemplateContext) DataRaceCheck(dataCtx context.Context) (string, error) {
if c.parentContext() != dataCtx {
log.Error("TemplateContext.DataRaceCheck: parent context mismatch\n%s", log.Stack(2))
return "", errors.New("parent context mismatch")
}
return "", nil
}
21 changes: 15 additions & 6 deletions modules/git/repo_base_nogogit.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ type Repository struct {

gpgSettings *GPGSettings

batchInUse bool
batchCancel context.CancelFunc
batchReader *bufio.Reader
batchWriter WriteCloserError

checkInUse bool
checkCancel context.CancelFunc
checkReader *bufio.Reader
checkWriter WriteCloserError
Expand Down Expand Up @@ -79,23 +81,28 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) {

// CatFileBatch obtains a CatFileBatch for this repository
func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
if repo.batchCancel == nil || repo.batchReader.Buffered() > 0 {
if repo.batchCancel == nil || repo.batchInUse {
log.Debug("Opening temporary cat file batch for: %s", repo.Path)
return CatFileBatch(ctx, repo.Path)
}
return repo.batchWriter, repo.batchReader, func() {}
repo.batchInUse = true
return repo.batchWriter, repo.batchReader, func() {
repo.batchInUse = false
}
}

// CatFileBatchCheck obtains a CatFileBatchCheck for this repository
func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
if repo.checkCancel == nil || repo.checkReader.Buffered() > 0 {
log.Debug("Opening temporary cat file batch-check: %s", repo.Path)
if repo.checkCancel == nil || repo.checkInUse {
log.Debug("Opening temporary cat file batch-check for: %s", repo.Path)
return CatFileBatchCheck(ctx, repo.Path)
}
return repo.checkWriter, repo.checkReader, func() {}
repo.checkInUse = true
return repo.checkWriter, repo.checkReader, func() {
repo.checkInUse = false
}
}

// Close this repository, in particular close the underlying gogitStorage if this is not nil
func (repo *Repository) Close() (err error) {
if repo == nil {
return nil
Expand All @@ -105,12 +112,14 @@ func (repo *Repository) Close() (err error) {
repo.batchReader = nil
repo.batchWriter = nil
repo.batchCancel = nil
repo.batchInUse = false
}
if repo.checkCancel != nil {
repo.checkCancel()
repo.checkCancel = nil
repo.checkReader = nil
repo.checkWriter = nil
repo.checkInUse = false
}
repo.LastCommitCache = nil
repo.tagCache = nil
Expand Down
34 changes: 17 additions & 17 deletions modules/markup/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,38 +53,38 @@ var (
// shortLinkPattern matches short but difficult to parse [[name|link|arg=test]] syntax
shortLinkPattern = regexp.MustCompile(`\[\[(.*?)\]\](\w*)`)

// anySHA1Pattern splits url containing SHA into parts
// anyHashPattern splits url containing SHA into parts
anyHashPattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40,64})(/[-+~_%.a-zA-Z0-9/]+)?(#[-+~_%.a-zA-Z0-9]+)?`)

// comparePattern matches "http://domain/org/repo/compare/COMMIT1...COMMIT2#hash"
comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{7,64})(\.\.\.?)([0-9a-f]{7,64})?(#[-+~_%.a-zA-Z0-9]+)?`)

validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`)
// fullURLPattern matches full URL like "mailto:...", "https://..." and "ssh+git://..."
fullURLPattern = regexp.MustCompile(`^[a-z][-+\w]+:`)

// While this email regex is definitely not perfect and I'm sure you can come up
// with edge cases, it is still accepted by the CommonMark specification, as
// well as the HTML5 spec:
// emailRegex is definitely not perfect with edge cases,
// it is still accepted by the CommonMark specification, as well as the HTML5 spec:
// http://spec.commonmark.org/0.28/#email-address
// https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type%3Demail)
emailRegex = regexp.MustCompile("(?:\\s|^|\\(|\\[)([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9]{2,}(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+)(?:\\s|$|\\)|\\]|;|,|\\?|!|\\.(\\s|$))")

// blackfriday extensions create IDs like fn:user-content-footnote
// blackfridayExtRegex is for blackfriday extensions create IDs like fn:user-content-footnote
blackfridayExtRegex = regexp.MustCompile(`[^:]*:user-content-`)

// EmojiShortCodeRegex find emoji by alias like :smile:
EmojiShortCodeRegex = regexp.MustCompile(`:[-+\w]+:`)
// emojiShortCodeRegex find emoji by alias like :smile:
emojiShortCodeRegex = regexp.MustCompile(`:[-+\w]+:`)
)

// CSS class for action keywords (e.g. "closes: #1")
const keywordClass = "issue-keyword"

// IsLink reports whether link fits valid format.
func IsLink(link []byte) bool {
return validLinksPattern.Match(link)
// IsFullURLBytes reports whether link fits valid format.
func IsFullURLBytes(link []byte) bool {
return fullURLPattern.Match(link)
}

func IsLinkStr(link string) bool {
return validLinksPattern.MatchString(link)
func IsFullURLString(link string) bool {
return fullURLPattern.MatchString(link)
}

// regexp for full links to issues/pulls
Expand Down Expand Up @@ -399,7 +399,7 @@ func visitNode(ctx *RenderContext, procs []processor, node *html.Node) {
if attr.Key != "src" {
continue
}
if len(attr.Val) > 0 && !IsLinkStr(attr.Val) && !strings.HasPrefix(attr.Val, "data:image/") {
if len(attr.Val) > 0 && !IsFullURLString(attr.Val) && !strings.HasPrefix(attr.Val, "data:image/") {
attr.Val = util.URLJoin(ctx.Links.ResolveMediaLink(ctx.IsWiki), attr.Val)
}
attr.Val = camoHandleLink(attr.Val)
Expand Down Expand Up @@ -650,7 +650,7 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
if equalPos := strings.IndexByte(v, '='); equalPos == -1 {
// There is no equal in this argument; this is a mandatory arg
if props["name"] == "" {
if IsLinkStr(v) {
if IsFullURLString(v) {
// If we clearly see it is a link, we save it so

// But first we need to ensure, that if both mandatory args provided
Expand Down Expand Up @@ -725,7 +725,7 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
DataAtom: atom.A,
}
childNode.Parent = linkNode
absoluteLink := IsLinkStr(link)
absoluteLink := IsFullURLString(link)
if !absoluteLink {
if image {
link = strings.ReplaceAll(link, " ", "+")
Expand Down Expand Up @@ -1059,7 +1059,7 @@ func emojiShortCodeProcessor(ctx *RenderContext, node *html.Node) {
start := 0
next := node.NextSibling
for node != nil && node != next && start < len(node.Data) {
m := EmojiShortCodeRegex.FindStringSubmatchIndex(node.Data[start:])
m := emojiShortCodeRegex.FindStringSubmatchIndex(node.Data[start:])
if m == nil {
return
}
Expand Down
15 changes: 15 additions & 0 deletions modules/markup/html_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,15 @@ func TestRender_links(t *testing.T) {
test(
"magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download",
`<p><a href="magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download" rel="nofollow">magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download</a></p>`)
test(
`[link](https://example.com)`,
`<p><a href="https://example.com" rel="nofollow">link</a></p>`)
test(
`[link](mailto:test@example.com)`,
`<p><a href="mailto:test@example.com" rel="nofollow">link</a></p>`)
test(
`[link](javascript:xss)`,
`<p>link</p>`)

// Test that should *not* be turned into URL
test(
Expand Down Expand Up @@ -673,3 +682,9 @@ func TestIssue18471(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "<a href=\"http://domain/org/repo/compare/783b039...da951ce\" class=\"compare\"><code class=\"nohighlight\">783b039...da951ce</code></a>", res.String())
}

func TestIsFullURL(t *testing.T) {
assert.True(t, markup.IsFullURLString("https://example.com"))
assert.True(t, markup.IsFullURLString("mailto:test@example.com"))
assert.False(t, markup.IsFullURLString("/foo:bar"))
}
18 changes: 5 additions & 13 deletions modules/markup/markdown/goldmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ import (
"github.com/yuin/goldmark/util"
)

var byteMailto = []byte("mailto:")

// ASTTransformer is a default transformer of the goldmark tree.
type ASTTransformer struct{}

Expand Down Expand Up @@ -84,7 +82,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
// 2. If they're not wrapped with a link they need a link wrapper

// Check if the destination is a real link
if len(v.Destination) > 0 && !markup.IsLink(v.Destination) {
if len(v.Destination) > 0 && !markup.IsFullURLBytes(v.Destination) {
v.Destination = []byte(giteautil.URLJoin(
ctx.Links.ResolveMediaLink(ctx.IsWiki),
strings.TrimLeft(string(v.Destination), "/"),
Expand Down Expand Up @@ -130,23 +128,17 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
case *ast.Link:
// Links need their href to munged to be a real value
link := v.Destination
if len(link) > 0 && !markup.IsLink(link) &&
link[0] != '#' && !bytes.HasPrefix(link, byteMailto) {
// special case: this is not a link, a hash link or a mailto:, so it's a
// relative URL

var base string
isAnchorFragment := len(link) > 0 && link[0] == '#'
if !isAnchorFragment && !markup.IsFullURLBytes(link) {
base := ctx.Links.Base
if ctx.IsWiki {
base = ctx.Links.WikiLink()
} else if ctx.Links.HasBranchInfo() {
base = ctx.Links.SrcLink()
} else {
base = ctx.Links.Base
}

link = []byte(giteautil.URLJoin(base, string(link)))
}
if len(link) > 0 && link[0] == '#' {
if isAnchorFragment {
link = []byte("#user-content-" + string(link)[1:])
}
v.Destination = link
Expand Down
Loading

0 comments on commit cc8215a

Please sign in to comment.