mirror of
https://github.com/go-gitea/gitea.git
synced 2025-12-05 01:10:26 +00:00
Compare commits
4 Commits
45cdc5d8fd
...
544450a212
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
544450a212 | ||
|
|
0ab447005d | ||
|
|
52902d4ece | ||
|
|
0e91c8a068 |
2
.github/workflows/cron-licenses.yml
vendored
2
.github/workflows/cron-licenses.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
if: github.repository == 'go-gitea/gitea'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
|
||||
14
.github/workflows/pull-compliance.yml
vendored
14
.github/workflows/pull-compliance.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -84,7 +84,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -101,7 +101,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -116,7 +116,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -145,7 +145,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -190,7 +190,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
|
||||
10
.github/workflows/pull-db-tests.yml
vendored
10
.github/workflows/pull-db-tests.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
- "9000:9000"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -125,7 +125,7 @@ jobs:
|
||||
- 10000:10000
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -178,7 +178,7 @@ jobs:
|
||||
- "993:993"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -218,7 +218,7 @@ jobs:
|
||||
- 10000:10000
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
|
||||
2
.github/workflows/pull-e2e-tests.yml
vendored
2
.github/workflows/pull-e2e-tests.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
|
||||
6
.github/workflows/release-nightly.yml
vendored
6
.github/workflows/release-nightly.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
|
||||
2
.github/workflows/release-tag-rc.yml
vendored
2
.github/workflows/release-tag-rc.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
|
||||
2
.github/workflows/release-tag-version.yml
vendored
2
.github/workflows/release-tag-version.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
|
||||
2
Makefile
2
Makefile
@@ -35,7 +35,7 @@ SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@717e3cb29becaaf0
|
||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1
|
||||
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
|
||||
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1
|
||||
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.8
|
||||
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.20.0
|
||||
GOPLS_MODERNIZE_PACKAGE ?= golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@v0.20.0
|
||||
|
||||
|
||||
4
go.mod
4
go.mod
@@ -1,6 +1,8 @@
|
||||
module code.gitea.io/gitea
|
||||
|
||||
go 1.25.4
|
||||
go 1.25.0
|
||||
|
||||
toolchain go1.25.5
|
||||
|
||||
// rfc5280 said: "The serial number is an integer assigned by the CA to each certificate."
|
||||
// But some CAs use negative serial number, just relax the check. related:
|
||||
|
||||
@@ -76,7 +76,7 @@ func (m *MaterialIconProvider) renderFileIconSVG(p *RenderedIconPool, name, svg,
|
||||
if p.IconSVGs[svgID] == "" {
|
||||
p.IconSVGs[svgID] = svgHTML
|
||||
}
|
||||
return template.HTML(`<svg ` + svgCommonAttrs + `><use xlink:href="#` + svgID + `"></use></svg>`)
|
||||
return template.HTML(`<svg ` + svgCommonAttrs + `><use href="#` + svgID + `"></use></svg>`)
|
||||
}
|
||||
|
||||
func (m *MaterialIconProvider) EntryIconHTML(p *RenderedIconPool, entry *EntryInfo) template.HTML {
|
||||
|
||||
@@ -25,7 +25,7 @@ func (p *RenderedIconPool) RenderToHTML() template.HTML {
|
||||
return ""
|
||||
}
|
||||
sb := &strings.Builder{}
|
||||
sb.WriteString(`<div class=tw-hidden>`)
|
||||
sb.WriteString(`<div class="svg-icon-container">`)
|
||||
for _, icon := range p.IconSVGs {
|
||||
sb.WriteString(string(icon))
|
||||
}
|
||||
|
||||
@@ -216,9 +216,12 @@ func EditUser(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
if form.Email != nil {
|
||||
if err := user_service.AdminAddOrSetPrimaryEmailAddress(ctx, ctx.ContextUser, *form.Email); err != nil {
|
||||
if err := user_service.ReplacePrimaryEmailAddress(ctx, ctx.ContextUser, *form.Email); err != nil {
|
||||
switch {
|
||||
case user_model.IsErrEmailCharIsNotSupported(err), user_model.IsErrEmailInvalid(err):
|
||||
if !user_model.IsEmailDomainAllowed(*form.Email) {
|
||||
err = fmt.Errorf("the domain of user email %s conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST", *form.Email)
|
||||
}
|
||||
ctx.APIError(http.StatusBadRequest, err)
|
||||
case user_model.IsErrEmailAlreadyUsed(err):
|
||||
ctx.APIError(http.StatusBadRequest, err)
|
||||
@@ -227,10 +230,6 @@ func EditUser(ctx *context.APIContext) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !user_model.IsEmailDomainAllowed(*form.Email) {
|
||||
ctx.Resp.Header().Add("X-Gitea-Warning", fmt.Sprintf("the domain of user email %s conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST", *form.Email))
|
||||
}
|
||||
}
|
||||
|
||||
opts := &user_service.UpdateOptions{
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestTransformDiffTreeForWeb(t *testing.T) {
|
||||
})
|
||||
|
||||
mockIconForFile := func(id string) template.HTML {
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file" width="16" height="16" aria-hidden="true"><use xlink:href="#` + id + `"></use></svg>`)
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file" width="16" height="16" aria-hidden="true"><use href="#` + id + `"></use></svg>`)
|
||||
}
|
||||
assert.Equal(t, WebDiffFileTree{
|
||||
TreeRoot: WebDiffFileItem{
|
||||
|
||||
@@ -33,7 +33,13 @@ func (s *SendmailSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
|
||||
args := []string{"-f", envelopeFrom, "-i"}
|
||||
args = append(args, setting.MailService.SendmailArgs...)
|
||||
args = append(args, to...)
|
||||
for _, recipient := range to {
|
||||
smtpTo, err := sanitizeEmailAddress(recipient)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid recipient address %q: %w", recipient, err)
|
||||
}
|
||||
args = append(args, smtpTo)
|
||||
}
|
||||
log.Trace("Sending with: %s %v", setting.MailService.SendmailPath, args)
|
||||
|
||||
desc := fmt.Sprintf("SendMail: %s %v", setting.MailService.SendmailPath, args)
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/mail"
|
||||
"net/smtp"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/wneessen/go-mail/smtp"
|
||||
)
|
||||
|
||||
// SMTPSender Sender SMTP mail sender
|
||||
@@ -108,7 +108,7 @@ func (s *SMTPSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
if strings.Contains(options, "CRAM-MD5") {
|
||||
auth = smtp.CRAMMD5Auth(opts.User, opts.Passwd)
|
||||
} else if strings.Contains(options, "PLAIN") {
|
||||
auth = smtp.PlainAuth("", opts.User, opts.Passwd, host, false)
|
||||
auth = smtp.PlainAuth("", opts.User, opts.Passwd, host)
|
||||
} else if strings.Contains(options, "LOGIN") {
|
||||
// Patch for AUTH LOGIN
|
||||
auth = LoginAuth(opts.User, opts.Passwd)
|
||||
@@ -123,18 +123,24 @@ func (s *SMTPSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
}
|
||||
}
|
||||
|
||||
if opts.OverrideEnvelopeFrom {
|
||||
if err = client.Mail(opts.EnvelopeFrom); err != nil {
|
||||
return fmt.Errorf("failed to issue MAIL command: %w", err)
|
||||
}
|
||||
} else {
|
||||
if err = client.Mail(fmt.Sprintf("<%s>", from)); err != nil {
|
||||
return fmt.Errorf("failed to issue MAIL command: %w", err)
|
||||
}
|
||||
fromAddr := from
|
||||
if opts.OverrideEnvelopeFrom && opts.EnvelopeFrom != "" {
|
||||
fromAddr = opts.EnvelopeFrom
|
||||
}
|
||||
smtpFrom, err := sanitizeEmailAddress(fromAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid envelope from address: %w", err)
|
||||
}
|
||||
if err = client.Mail(smtpFrom); err != nil {
|
||||
return fmt.Errorf("failed to issue MAIL command: %w", err)
|
||||
}
|
||||
|
||||
for _, rec := range to {
|
||||
if err = client.Rcpt(rec); err != nil {
|
||||
smtpTo, err := sanitizeEmailAddress(rec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid recipient address %q: %w", rec, err)
|
||||
}
|
||||
if err = client.Rcpt(smtpTo); err != nil {
|
||||
return fmt.Errorf("failed to issue RCPT command: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -155,3 +161,11 @@ func (s *SMTPSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sanitizeEmailAddress(raw string) (string, error) {
|
||||
addr, err := mail.ParseAddress(strings.TrimSpace(strings.Trim(raw, "<>")))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return addr.Address, nil
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ package sender
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
|
||||
"github.com/Azure/go-ntlmssp"
|
||||
"github.com/wneessen/go-mail/smtp"
|
||||
)
|
||||
|
||||
type loginAuth struct {
|
||||
|
||||
30
services/mailer/sender/smtp_test.go
Normal file
30
services/mailer/sender/smtp_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package sender
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSanitizeEmailAddress(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected string
|
||||
hasError bool
|
||||
}{
|
||||
{"abc@gitea.com", "abc@gitea.com", false},
|
||||
{"<abc@gitea.com>", "abc@gitea.com", false},
|
||||
{"ssss.com", "", true},
|
||||
{"<invalid-email>", "", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
result, err := sanitizeEmailAddress(tt.input)
|
||||
if (err != nil) != tt.hasError {
|
||||
t.Errorf("sanitizeEmailAddress(%q) unexpected error status: got %v, want error: %v", tt.input, err != nil, tt.hasError)
|
||||
continue
|
||||
}
|
||||
if result != tt.expected {
|
||||
t.Errorf("sanitizeEmailAddress(%q) = %q; want %q", tt.input, result, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,13 +67,13 @@ func TestGetTreeViewNodes(t *testing.T) {
|
||||
curRepoLink := "/any/repo-link"
|
||||
renderedIconPool := fileicon.NewRenderedIconPool()
|
||||
mockIconForFile := func(id string) template.HTML {
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file" width="16" height="16" aria-hidden="true"><use xlink:href="#` + id + `"></use></svg>`)
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file" width="16" height="16" aria-hidden="true"><use href="#` + id + `"></use></svg>`)
|
||||
}
|
||||
mockIconForFolder := func(id string) template.HTML {
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file-directory-fill" width="16" height="16" aria-hidden="true"><use xlink:href="#` + id + `"></use></svg>`)
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file-directory-fill" width="16" height="16" aria-hidden="true"><use href="#` + id + `"></use></svg>`)
|
||||
}
|
||||
mockOpenIconForFolder := func(id string) template.HTML {
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file-directory-open-fill" width="16" height="16" aria-hidden="true"><use xlink:href="#` + id + `"></use></svg>`)
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file-directory-open-fill" width="16" height="16" aria-hidden="true"><use href="#` + id + `"></use></svg>`)
|
||||
}
|
||||
treeNodes, err := GetTreeViewNodes(ctx, curRepoLink, renderedIconPool, ctx.Repo.Commit, "", "")
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -14,60 +14,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
// AdminAddOrSetPrimaryEmailAddress is used by admins to add or set a user's primary email address
|
||||
func AdminAddOrSetPrimaryEmailAddress(ctx context.Context, u *user_model.User, emailStr string) error {
|
||||
if strings.EqualFold(u.Email, emailStr) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := user_model.ValidateEmailForAdmin(emailStr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if address exists already
|
||||
email, err := user_model.GetEmailAddressByEmail(ctx, emailStr)
|
||||
if err != nil && !errors.Is(err, util.ErrNotExist) {
|
||||
return err
|
||||
}
|
||||
if email != nil && email.UID != u.ID {
|
||||
return user_model.ErrEmailAlreadyUsed{Email: emailStr}
|
||||
}
|
||||
|
||||
// Update old primary address
|
||||
primary, err := user_model.GetPrimaryEmailAddressOfUser(ctx, u.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
primary.IsPrimary = false
|
||||
if err := user_model.UpdateEmailAddress(ctx, primary); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Insert new or update existing address
|
||||
if email != nil {
|
||||
email.IsPrimary = true
|
||||
email.IsActivated = true
|
||||
if err := user_model.UpdateEmailAddress(ctx, email); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
email = &user_model.EmailAddress{
|
||||
UID: u.ID,
|
||||
Email: emailStr,
|
||||
IsActivated: true,
|
||||
IsPrimary: true,
|
||||
}
|
||||
if _, err := user_model.InsertEmailAddress(ctx, email); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
u.Email = emailStr
|
||||
|
||||
return user_model.UpdateUserCols(ctx, u, "email")
|
||||
}
|
||||
|
||||
func ReplacePrimaryEmailAddress(ctx context.Context, u *user_model.User, emailStr string) error {
|
||||
if strings.EqualFold(u.Email, emailStr) {
|
||||
return nil
|
||||
|
||||
@@ -9,61 +9,10 @@ import (
|
||||
organization_model "code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/glob"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAdminAddOrSetPrimaryEmailAddress(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 27})
|
||||
|
||||
emails, err := user_model.GetEmailAddresses(t.Context(), user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, emails, 1)
|
||||
|
||||
primary, err := user_model.GetPrimaryEmailAddressOfUser(t.Context(), user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, "new-primary@example.com", primary.Email)
|
||||
assert.Equal(t, user.Email, primary.Email)
|
||||
|
||||
assert.NoError(t, AdminAddOrSetPrimaryEmailAddress(t.Context(), user, "new-primary@example.com"))
|
||||
|
||||
primary, err = user_model.GetPrimaryEmailAddressOfUser(t.Context(), user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "new-primary@example.com", primary.Email)
|
||||
assert.Equal(t, user.Email, primary.Email)
|
||||
|
||||
emails, err = user_model.GetEmailAddresses(t.Context(), user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, emails, 2)
|
||||
|
||||
setting.Service.EmailDomainAllowList = []glob.Glob{glob.MustCompile("example.org")}
|
||||
defer func() {
|
||||
setting.Service.EmailDomainAllowList = []glob.Glob{}
|
||||
}()
|
||||
|
||||
assert.NoError(t, AdminAddOrSetPrimaryEmailAddress(t.Context(), user, "new-primary2@example2.com"))
|
||||
|
||||
primary, err = user_model.GetPrimaryEmailAddressOfUser(t.Context(), user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "new-primary2@example2.com", primary.Email)
|
||||
assert.Equal(t, user.Email, primary.Email)
|
||||
|
||||
assert.NoError(t, AdminAddOrSetPrimaryEmailAddress(t.Context(), user, "user27@example.com"))
|
||||
|
||||
primary, err = user_model.GetPrimaryEmailAddressOfUser(t.Context(), user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "user27@example.com", primary.Email)
|
||||
assert.Equal(t, user.Email, primary.Email)
|
||||
|
||||
emails, err = user_model.GetEmailAddresses(t.Context(), user.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, emails, 3)
|
||||
}
|
||||
|
||||
func TestReplacePrimaryEmailAddress(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
|
||||
@@ -382,10 +382,12 @@ func TestAPIEditUser_NotAllowedEmailDomain(t *testing.T) {
|
||||
SourceID: 0,
|
||||
Email: &newEmail,
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, "the domain of user email user2@example1.com conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST", resp.Header().Get("X-Gitea-Warning"))
|
||||
resp := MakeRequest(t, req, http.StatusBadRequest)
|
||||
errMap := make(map[string]string)
|
||||
assert.NoError(t, json.Unmarshal(resp.Body.Bytes(), &errMap))
|
||||
assert.Equal(t, "the domain of user email user2@example1.com conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST", errMap["message"])
|
||||
|
||||
originalEmail := "user2@example.com"
|
||||
originalEmail := "user2@example.org"
|
||||
req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{
|
||||
LoginName: "user2",
|
||||
SourceID: 0,
|
||||
|
||||
@@ -1,17 +1,24 @@
|
||||
.svg {
|
||||
/* some material icons have "fill=none" (e.g.: ".txt -> document"), so the CSS styles shouldn't overwrite it,
|
||||
and material icons should have no "fill" set explicitly, otherwise some like ".editorconfig" won't render correctly */
|
||||
.svg:not(.git-entry-icon) {
|
||||
display: inline-block;
|
||||
vertical-align: text-top;
|
||||
fill: currentcolor;
|
||||
}
|
||||
|
||||
.svg.git-entry-icon {
|
||||
fill: transparent; /* some material icons have dark background fill, so need to reset */
|
||||
}
|
||||
|
||||
.middle .svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* some browsers like Chrome have a bug: when a SVG is in a "display: none" container and referenced
|
||||
somewhere else by `<use href="#id">`, it won't be rendered correctly. e.g.: ".kts -> kotlin" */
|
||||
.svg-icon-container {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* prevent SVGs from shrinking, like in space-starved flexboxes. the sizes
|
||||
here are cherry-picked for our use cases, feel free to add more. after
|
||||
https://developer.mozilla.org/en-US/docs/Web/CSS/attr#type-or-unit is
|
||||
|
||||
@@ -17,7 +17,7 @@ export function createViewFileTreeStore(props: {repoLink: string, treePath: stri
|
||||
if (!document.querySelector(`.global-svg-icon-pool #${svgId}`)) poolSvgs.push(svgContent);
|
||||
}
|
||||
if (poolSvgs.length) {
|
||||
const svgContainer = createElementFromHTML(html`<div class="global-svg-icon-pool tw-hidden"></div>`);
|
||||
const svgContainer = createElementFromHTML(html`<div class="global-svg-icon-pool svg-icon-container"></div>`);
|
||||
svgContainer.innerHTML = poolSvgs.join('');
|
||||
document.body.append(svgContainer);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user