Compare commits

..

2 commits

Author SHA1 Message Date
be35644fa0 nulo: woodpecker CI
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-10 00:17:42 -03:00
6f5e340458 Dockerfile: rename user to _gitea instead of git 2023-09-10 00:11:52 -03:00
27 changed files with 119 additions and 215 deletions

View file

@ -4,7 +4,7 @@ This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.com).
## [1.20.4](https://github.com/go-gitea/gitea/releases/tag/v1.20.4) - 2023-09-08
## [1.20.4](https://github.com/go-gitea/gitea/releases/tag/1.20.4) - 2023-09-08
* SECURITY
* Check blocklist for emails when adding them to account (#26812) (#26831)

View file

@ -89,7 +89,7 @@ endif
VERSION = ${GITEA_VERSION}
# SemVer
FORGEJO_VERSION := 5.0.4+0-gitea-1.20.4
FORGEJO_VERSION := 5.0.3+0-gitea-1.20.4
LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)" -X "code.gitea.io/gitea/routers/api/forgejo/v1.ForgejoVersion=$(FORGEJO_VERSION)" -X "main.ForgejoVersion=$(FORGEJO_VERSION)"

View file

@ -1724,8 +1724,8 @@ LEVEL = Info
;; Session cookie name
;COOKIE_NAME = i_like_gitea
;;
;; If you use session in https only: true or false. If not set, it defaults to `true` if the ROOT_URL is an HTTPS URL.
;COOKIE_SECURE =
;; If you use session in https only, default is false
;COOKIE_SECURE = false
;;
;; Session GC time interval in seconds, default is 86400 (1 day)
;GC_INTERVAL_TIME = 86400

View file

@ -443,7 +443,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `ITERATE_BUFFER_SIZE`: **50**: Internal buffer size for iterating.
- `CHARSET`: **utf8mb4**: For MySQL only, either "utf8" or "utf8mb4". NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this.
- `PATH`: **data/gitea.db**: For SQLite3 only, the database file path.
- `LOG_SQL`: **false**: Log the executed SQL.
- `LOG_SQL`: **true**: Log the executed SQL.
- `DB_RETRIES`: **10**: How many ORM init / DB connect attempts allowed.
- `DB_RETRY_BACKOFF`: **3s**: time.Duration to wait before trying another ORM init / DB connect attempt, if failure occurred.
- `MAX_OPEN_CONNS` **0**: Database maximum open connections - default is 0, meaning there is no limit.
@ -772,7 +772,7 @@ and
- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, redis-cluster, 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. Relative paths will be made absolute against _`AppWorkPath`_.
- `COOKIE_SECURE`:**_empty_**: `true` or `false`. Enable this to force using HTTPS for all session access. If not set, it defaults to `true` if the ROOT_URL is an HTTPS URL.
- `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.
- `SESSION_LIFE_TIME`: **86400**: Session life time in seconds, default is 86400 (1 day)

View file

@ -98,7 +98,7 @@ menu:
- `SSL_MODE`: MySQL 或 PostgreSQL数据库是否启用SSL模式。
- `CHARSET`: **utf8mb4**: 仅当数据库为 MySQL 时有效, 可以为 "utf8" 或 "utf8mb4"。注意:如果使用 "utf8mb4",你的 MySQL InnoDB 版本必须在 5.6 以上。
- `PATH`: SQLite3 数据文件存放路径。
- `LOG_SQL`: **false**: 显示生成的SQL默认为真。
- `LOG_SQL`: **true**: 显示生成的SQL默认为真。
- `MAX_IDLE_CONNS` **0**: 最大空闲数据库连接
- `CONN_MAX_LIFETIME` **3s**: 数据库连接最大存活时间
@ -200,7 +200,7 @@ menu:
- `PROVIDER`: Session 内容存储方式,可选 `memory`, `file`, `redis``mysql`
- `PROVIDER_CONFIG`: 如果是文件,那么这里填根目录;其他的要填主机地址和端口。
- `COOKIE_SECURE`: **_empty_**`true` 或 `false`。启用此选项以强制在所有会话访问中使用 HTTPS。如果没有设置当 ROOT_URL 是 https 链接的时候默认设置为 true
- `COOKIE_SECURE`: 强制使用 HTTPS 作为session访问
- `GC_INTERVAL_TIME`: Session失效时间。
## Picture (`picture`)

View file

@ -180,6 +180,3 @@ For events supported only by GitHub, see GitHub's [documentation](https://docs.g
| pull_request_review_comment | `created`, `edited` |
| release | `published`, `edited` |
| registry_package | `published` |
> For `pull_request` events, in [GitHub Actions](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request), the `ref` is `refs/pull/:prNumber/merge`, which is a reference to the merge commit preview. However, Gitea has no such reference.
> Therefore, the `ref` in Gitea Actions is `refs/pull/:prNumber/head`, which points to the head of pull request rather than the preview of the merge commit.

View file

@ -180,6 +180,3 @@ defaults:
| pull_request_review_comment | `created`, `edited` |
| release | `published`, `edited` |
| registry_package | `published` |
> 对于 `pull_request` 事件,在 [GitHub Actions](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request) 中 `ref``refs/pull/:prNumber/merge`,它指向这个拉取请求合并提交的一个预览。但是 Gitea 没有这种 reference。
> 因此Gitea Actions 中 `ref``refs/pull/:prNumber/head`,它指向这个拉取请求的头分支而不是合并提交的预览。

View file

@ -153,12 +153,7 @@ func generateEmailAvatarLink(ctx context.Context, email string, size int, final
return DefaultAvatarLink()
}
disableGravatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar,
setting.GetDefaultDisableGravatar(),
)
enableFederatedAvatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureEnableFederatedAvatar,
setting.GetDefaultEnableFederatedAvatar(disableGravatar))
enableFederatedAvatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureEnableFederatedAvatar)
var err error
if enableFederatedAvatar && system_model.LibravatarService != nil {
@ -179,6 +174,7 @@ func generateEmailAvatarLink(ctx context.Context, email string, size int, final
return urlStr
}
disableGravatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar)
if !disableGravatar {
// copy GravatarSourceURL, because we will modify its Path.
avatarURLCopy := *system_model.GravatarSourceURL

View file

@ -1,6 +1,6 @@
-
id: 1
setting_key: 'picture.disable_gravatar'
setting_key: 'disable_gravatar'
setting_value: 'false'
version: 1
created: 1653533198
@ -8,7 +8,7 @@
-
id: 2
setting_key: 'picture.enable_federated_avatar'
setting_key: 'enable_federated_avatar'
setting_value: 'false'
version: 1
created: 1653533198

View file

@ -348,7 +348,7 @@ func (c *Comment) AfterLoad(session *xorm.Session) {
// LoadPoster loads comment poster
func (c *Comment) LoadPoster(ctx context.Context) (err error) {
if c.Poster != nil {
if c.PosterID <= 0 || c.Poster != nil {
return nil
}

View file

@ -523,9 +523,9 @@ func (repo *Repository) DescriptionHTML(ctx context.Context) template.HTML {
}, repo.Description)
if err != nil {
log.Error("Failed to render description for %s (ID: %d): %v", repo.Name, repo.ID, err)
return template.HTML(markup.SanitizeDescription(repo.Description))
return template.HTML(markup.Sanitize(repo.Description))
}
return template.HTML(markup.SanitizeDescription(desc))
return template.HTML(markup.Sanitize(desc))
}
// CloneLink represents different types of clone URLs of repository.

View file

@ -94,14 +94,11 @@ func GetSetting(ctx context.Context, key string) (*Setting, error) {
const contextCacheKey = "system_setting"
// GetSettingWithCache returns the setting value via the key
func GetSettingWithCache(ctx context.Context, key, defaultVal string) (string, error) {
func GetSettingWithCache(ctx context.Context, key string) (string, error) {
return cache.GetWithContextCache(ctx, contextCacheKey, key, func() (string, error) {
return cache.GetString(genSettingCacheKey(key), func() (string, error) {
res, err := GetSetting(ctx, key)
if err != nil {
if IsErrSettingIsNotExist(err) {
return defaultVal, nil
}
return "", err
}
return res.SettingValue, nil
@ -111,21 +108,17 @@ func GetSettingWithCache(ctx context.Context, key, defaultVal string) (string, e
// GetSettingBool return bool value of setting,
// none existing keys and errors are ignored and result in false
func GetSettingBool(ctx context.Context, key string, defaultVal bool) (bool, error) {
s, err := GetSetting(ctx, key)
switch {
case err == nil:
v, _ := strconv.ParseBool(s.SettingValue)
return v, nil
case IsErrSettingIsNotExist(err):
return defaultVal, nil
default:
return false, err
func GetSettingBool(ctx context.Context, key string) bool {
s, _ := GetSetting(ctx, key)
if s == nil {
return false
}
v, _ := strconv.ParseBool(s.SettingValue)
return v
}
func GetSettingWithCacheBool(ctx context.Context, key string, defaultVal bool) bool {
s, _ := GetSettingWithCache(ctx, key, strconv.FormatBool(defaultVal))
func GetSettingWithCacheBool(ctx context.Context, key string) bool {
s, _ := GetSettingWithCache(ctx, key)
v, _ := strconv.ParseBool(s)
return v
}
@ -266,41 +259,52 @@ var (
)
func Init(ctx context.Context) error {
disableGravatar, err := GetSettingBool(ctx, KeyPictureDisableGravatar, setting_module.GetDefaultDisableGravatar())
if err != nil {
var disableGravatar bool
disableGravatarSetting, err := GetSetting(ctx, KeyPictureDisableGravatar)
if IsErrSettingIsNotExist(err) {
disableGravatar = setting_module.GetDefaultDisableGravatar()
disableGravatarSetting = &Setting{SettingValue: strconv.FormatBool(disableGravatar)}
} else if err != nil {
return err
} else {
disableGravatar = disableGravatarSetting.GetValueBool()
}
enableFederatedAvatar, err := GetSettingBool(ctx, KeyPictureEnableFederatedAvatar, setting_module.GetDefaultEnableFederatedAvatar(disableGravatar))
if err != nil {
var enableFederatedAvatar bool
enableFederatedAvatarSetting, err := GetSetting(ctx, KeyPictureEnableFederatedAvatar)
if IsErrSettingIsNotExist(err) {
enableFederatedAvatar = setting_module.GetDefaultEnableFederatedAvatar(disableGravatar)
enableFederatedAvatarSetting = &Setting{SettingValue: strconv.FormatBool(enableFederatedAvatar)}
} else if err != nil {
return err
} else {
enableFederatedAvatar = disableGravatarSetting.GetValueBool()
}
if setting_module.OfflineMode {
if !disableGravatar {
if err := SetSettingNoVersion(ctx, KeyPictureDisableGravatar, "true"); err != nil {
return fmt.Errorf("failed to set setting %q: %w", KeyPictureDisableGravatar, err)
}
}
disableGravatar = true
if enableFederatedAvatar {
if err := SetSettingNoVersion(ctx, KeyPictureEnableFederatedAvatar, "false"); err != nil {
return fmt.Errorf("failed to set setting %q: %w", KeyPictureEnableFederatedAvatar, err)
enableFederatedAvatar = false
if !GetSettingBool(ctx, KeyPictureDisableGravatar) {
if err := SetSettingNoVersion(ctx, KeyPictureDisableGravatar, "true"); err != nil {
return fmt.Errorf("Failed to set setting %q: %w", KeyPictureDisableGravatar, err)
}
}
if GetSettingBool(ctx, KeyPictureEnableFederatedAvatar) {
if err := SetSettingNoVersion(ctx, KeyPictureEnableFederatedAvatar, "false"); err != nil {
return fmt.Errorf("Failed to set setting %q: %w", KeyPictureEnableFederatedAvatar, err)
}
}
enableFederatedAvatar = false
}
if enableFederatedAvatar || !disableGravatar {
var err error
GravatarSourceURL, err = url.Parse(setting_module.GravatarSource)
if err != nil {
return fmt.Errorf("failed to parse Gravatar URL(%s): %w", setting_module.GravatarSource, err)
return fmt.Errorf("Failed to parse Gravatar URL(%s): %w", setting_module.GravatarSource, err)
}
}
if GravatarSourceURL != nil && enableFederatedAvatar {
if GravatarSourceURL != nil && enableFederatedAvatarSetting.GetValueBool() {
LibravatarService = libravatar.New()
if GravatarSourceURL.Scheme == "https" {
LibravatarService.SetUseHTTPS(true)

View file

@ -67,9 +67,7 @@ func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
useLocalAvatar := false
autoGenerateAvatar := false
disableGravatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar,
setting.GetDefaultDisableGravatar(),
)
disableGravatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar)
switch {
case u.UseCustomAvatar:

View file

@ -18,10 +18,9 @@ import (
// Sanitizer is a protection wrapper of *bluemonday.Policy which does not allow
// any modification to the underlying policies once it's been created.
type Sanitizer struct {
defaultPolicy *bluemonday.Policy
descriptionPolicy *bluemonday.Policy
rendererPolicies map[string]*bluemonday.Policy
init sync.Once
defaultPolicy *bluemonday.Policy
rendererPolicies map[string]*bluemonday.Policy
init sync.Once
}
var (
@ -42,7 +41,6 @@ func NewSanitizer() {
func InitializeSanitizer() {
sanitizer.rendererPolicies = map[string]*bluemonday.Policy{}
sanitizer.defaultPolicy = createDefaultPolicy()
sanitizer.descriptionPolicy = createRepoDescriptionPolicy()
for name, renderer := range renderers {
sanitizerRules := renderer.SanitizerRules()
@ -163,27 +161,6 @@ func createDefaultPolicy() *bluemonday.Policy {
return policy
}
// createRepoDescriptionPolicy returns a minimal more strict policy that is used for
// repository descriptions.
func createRepoDescriptionPolicy() *bluemonday.Policy {
policy := bluemonday.NewPolicy()
// Allow italics and bold.
policy.AllowElements("i", "b", "em", "strong")
// Allow code.
policy.AllowElements("code")
// Allow links
policy.AllowAttrs("href", "target", "rel").OnElements("a")
// Allow classes for emojis
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^emoji$`)).OnElements("img", "span")
policy.AllowAttrs("aria-label").OnElements("span")
return policy
}
func addSanitizerRules(policy *bluemonday.Policy, rules []setting.MarkupSanitizerRule) {
for _, rule := range rules {
if rule.AllowDataURIImages {
@ -199,12 +176,6 @@ func addSanitizerRules(policy *bluemonday.Policy, rules []setting.MarkupSanitize
}
}
// SanitizeDescription sanitizes the HTML generated for a repository description.
func SanitizeDescription(s string) string {
NewSanitizer()
return sanitizer.descriptionPolicy.Sanitize(s)
}
// Sanitize takes a string that contains a HTML fragment or document and applies policy whitelist.
func Sanitize(s string) string {
NewSanitizer()

View file

@ -73,28 +73,6 @@ func Test_Sanitizer(t *testing.T) {
}
}
func TestDescriptionSanitizer(t *testing.T) {
NewSanitizer()
testCases := []string{
`<h1>Title</h1>`, `Title`,
`<img src='img.png' alt='image'>`, ``,
`<span class="emoji" aria-label="thumbs up">THUMBS UP</span>`, `<span class="emoji" aria-label="thumbs up">THUMBS UP</span>`,
`<span style="color: red">Hello World</span>`, `<span>Hello World</span>`,
`<br>`, ``,
`<a href="https://example.com" target="_blank" rel="noopener noreferrer">https://example.com</a>`, `<a href="https://example.com" target="_blank" rel="noopener noreferrer">https://example.com</a>`,
`<mark>Important!</mark>`, `Important!`,
`<details>Click me! <summary>Nothing to see here.</summary></details>`, `Click me! Nothing to see here.`,
`<input type="hidden">`, ``,
`<b>I</b> have a <i>strong</i> <strong>opinion</strong> about <em>this</em>.`, `<b>I</b> have a <i>strong</i> <strong>opinion</strong> about <em>this</em>.`,
`Provides alternative <code>wg(8)</code> tool`, `Provides alternative <code>wg(8)</code> tool`,
}
for i := 0; i < len(testCases); i += 2 {
assert.Equal(t, testCases[i+1], SanitizeDescription(testCases[i]))
}
}
func TestSanitizeNonEscape(t *testing.T) {
descStr := "<scrİpt>&lt;script&gt;alert(document.domain)&lt;/script&gt;</scrİpt>"

View file

@ -177,9 +177,6 @@ func (m *mailNotifier) NotifyPullRequestPushCommits(ctx context.Context, doer *u
}
func (m *mailNotifier) NotifyPullReviewDismiss(ctx context.Context, doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) {
if err := comment.Review.LoadReviewer(ctx); err != nil {
log.Error("Error in PullReviewDismiss while loading reviewer for issue[%d], review[%d] and reviewer[%d]: %v", review.Issue.ID, comment.Review.ID, comment.Review.ReviewerID, err)
}
if err := mailer.MailParticipantsComment(ctx, comment, activities_model.ActionPullReviewDismissed, review.Issue, nil); err != nil {
log.Error("MailParticipantsComment: %v", err)
}

View file

@ -11,7 +11,6 @@ import (
"code.gitea.io/gitea/models/avatars"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@ -35,36 +34,42 @@ type PushCommits struct {
HeadCommit *PushCommit
CompareURL string
Len int
avatars map[string]string
emailUsers map[string]*user_model.User
}
// NewPushCommits creates a new PushCommits object.
func NewPushCommits() *PushCommits {
return &PushCommits{}
return &PushCommits{
avatars: make(map[string]string),
emailUsers: make(map[string]*user_model.User),
}
}
// toAPIPayloadCommit converts a single PushCommit to an api.PayloadCommit object.
func (pc *PushCommits) toAPIPayloadCommit(ctx context.Context, emailUsers map[string]*user_model.User, repoPath, repoLink string, commit *PushCommit) (*api.PayloadCommit, error) {
func (pc *PushCommits) toAPIPayloadCommit(ctx context.Context, repoPath, repoLink string, commit *PushCommit) (*api.PayloadCommit, error) {
var err error
authorUsername := ""
author, ok := emailUsers[commit.AuthorEmail]
author, ok := pc.emailUsers[commit.AuthorEmail]
if !ok {
author, err = user_model.GetUserByEmail(ctx, commit.AuthorEmail)
if err == nil {
authorUsername = author.Name
emailUsers[commit.AuthorEmail] = author
pc.emailUsers[commit.AuthorEmail] = author
}
} else {
authorUsername = author.Name
}
committerUsername := ""
committer, ok := emailUsers[commit.CommitterEmail]
committer, ok := pc.emailUsers[commit.CommitterEmail]
if !ok {
committer, err = user_model.GetUserByEmail(ctx, commit.CommitterEmail)
if err == nil {
// TODO: check errors other than email not found.
committerUsername = committer.Name
emailUsers[commit.CommitterEmail] = committer
pc.emailUsers[commit.CommitterEmail] = committer
}
} else {
committerUsername = committer.Name
@ -102,10 +107,11 @@ func (pc *PushCommits) ToAPIPayloadCommits(ctx context.Context, repoPath, repoLi
commits := make([]*api.PayloadCommit, len(pc.Commits))
var headCommit *api.PayloadCommit
emailUsers := make(map[string]*user_model.User)
if pc.emailUsers == nil {
pc.emailUsers = make(map[string]*user_model.User)
}
for i, commit := range pc.Commits {
apiCommit, err := pc.toAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, commit)
apiCommit, err := pc.toAPIPayloadCommit(ctx, repoPath, repoLink, commit)
if err != nil {
return nil, nil, err
}
@ -117,7 +123,7 @@ func (pc *PushCommits) ToAPIPayloadCommits(ctx context.Context, repoPath, repoLi
}
if pc.HeadCommit != nil && headCommit == nil {
var err error
headCommit, err = pc.toAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, pc.HeadCommit)
headCommit, err = pc.toAPIPayloadCommit(ctx, repoPath, repoLink, pc.HeadCommit)
if err != nil {
return nil, nil, err
}
@ -128,21 +134,35 @@ func (pc *PushCommits) ToAPIPayloadCommits(ctx context.Context, repoPath, repoLi
// AvatarLink tries to match user in database with e-mail
// in order to show custom avatar, and falls back to general avatar link.
func (pc *PushCommits) AvatarLink(ctx context.Context, email string) string {
if pc.avatars == nil {
pc.avatars = make(map[string]string)
}
avatar, ok := pc.avatars[email]
if ok {
return avatar
}
size := avatars.DefaultAvatarPixelSize * setting.Avatar.RenderedSizeFactor
v, _ := cache.GetWithContextCache(ctx, "push_commits", email, func() (string, error) {
u, err := user_model.GetUserByEmail(ctx, email)
u, ok := pc.emailUsers[email]
if !ok {
var err error
u, err = user_model.GetUserByEmail(ctx, email)
if err != nil {
pc.avatars[email] = avatars.GenerateEmailAvatarFastLink(ctx, email, size)
if !user_model.IsErrUserNotExist(err) {
log.Error("GetUserByEmail: %v", err)
return "", err
return ""
}
return avatars.GenerateEmailAvatarFastLink(ctx, email, size), nil
} else {
pc.emailUsers[email] = u
}
return u.AvatarLinkWithSize(ctx, size), nil
})
}
if u != nil {
pc.avatars[email] = u.AvatarLinkWithSize(ctx, size)
}
return v
return pc.avatars[email]
}
// CommitToPushCommit transforms a git.Commit to PushCommit type.
@ -169,5 +189,7 @@ func GitToPushCommits(gitCommits []*git.Commit) *PushCommits {
HeadCommit: nil,
CompareURL: "",
Len: len(commits),
avatars: make(map[string]string),
emailUsers: make(map[string]*user_model.User),
}
}

View file

@ -103,9 +103,11 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) {
assert.EqualValues(t, []string{"readme.md"}, headCommit.Modified)
}
func initGravatarSource(t *testing.T) {
func enableGravatar(t *testing.T) {
err := system_model.SetSettingNoVersion(db.DefaultContext, system_model.KeyPictureDisableGravatar, "false")
assert.NoError(t, err)
setting.GravatarSource = "https://secure.gravatar.com/avatar"
err := system_model.Init(db.DefaultContext)
err = system_model.Init(db.DefaultContext)
assert.NoError(t, err)
}
@ -132,7 +134,7 @@ func TestPushCommits_AvatarLink(t *testing.T) {
},
}
initGravatarSource(t)
enableGravatar(t)
assert.Equal(t,
"https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon&s="+strconv.Itoa(28*setting.Avatar.RenderedSizeFactor),

View file

@ -175,16 +175,9 @@ func (s *iniConfigSection) ChildSections() (sections []ConfigSection) {
return sections
}
func configProviderLoadOptions() ini.LoadOptions {
return ini.LoadOptions{
KeyValueDelimiterOnWrite: " = ",
IgnoreContinuation: true,
}
}
// NewConfigProviderFromData this function is mainly for testing purpose
func NewConfigProviderFromData(configContent string) (ConfigProvider, error) {
cfg, err := ini.LoadSources(configProviderLoadOptions(), strings.NewReader(configContent))
cfg, err := ini.Load(strings.NewReader(configContent))
if err != nil {
return nil, err
}
@ -198,7 +191,7 @@ func NewConfigProviderFromData(configContent string) (ConfigProvider, error) {
// NewConfigProviderFromFile load configuration from file.
// NOTE: do not print any log except error.
func NewConfigProviderFromFile(file string, extraConfigs ...string) (ConfigProvider, error) {
cfg := ini.Empty(configProviderLoadOptions())
cfg := ini.Empty(ini.LoadOptions{KeyValueDelimiterOnWrite: " = "})
loadedFromEmpty := true
if file != "" {
@ -351,7 +344,6 @@ func NewConfigProviderForLocale(source any, others ...any) (ConfigProvider, erro
iniFile, err := ini.LoadSources(ini.LoadOptions{
IgnoreInlineComment: true,
UnescapeValueCommentSymbols: true,
IgnoreContinuation: true,
}, source, others...)
if err != nil {
return nil, fmt.Errorf("unable to load locale ini: %w", err)

View file

@ -30,16 +30,6 @@ key = 123
secSub := cfg.Section("foo.bar.xxx")
assert.Equal(t, "123", secSub.Key("key").String())
})
t.Run("TrailingSlash", func(t *testing.T) {
cfg, _ := NewConfigProviderFromData(`
[foo]
key = E:\
xxx = yyy
`)
sec := cfg.Section("foo")
assert.Equal(t, "E:\\", sec.Key("key").String())
assert.Equal(t, "yyy", sec.Key("xxx").String())
})
}
func TestConfigProviderHelper(t *testing.T) {

View file

@ -50,7 +50,7 @@ func loadSessionFrom(rootCfg ConfigProvider) {
}
SessionConfig.CookieName = sec.Key("COOKIE_NAME").MustString("i_like_gitea")
SessionConfig.CookiePath = AppSubURL + "/" // there was a bug, old code only set CookePath=AppSubURL, no trailing slash
SessionConfig.Secure = sec.Key("COOKIE_SECURE").MustBool(strings.HasPrefix(strings.ToLower(AppURL), "https://"))
SessionConfig.Secure = sec.Key("COOKIE_SECURE").MustBool(false)
SessionConfig.Gclifetime = sec.Key("GC_INTERVAL_TIME").MustInt64(86400)
SessionConfig.Maxlifetime = sec.Key("SESSION_LIFE_TIME").MustInt64(86400)
SessionConfig.Domain = sec.Key("DOMAIN").String()

View file

@ -104,7 +104,7 @@ func NewFuncMap() template.FuncMap {
return setting.AssetVersion
},
"DisableGravatar": func(ctx context.Context) bool {
return system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar, setting.GetDefaultDisableGravatar())
return system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar)
},
"DefaultShowFullName": func() bool {
return setting.UI.DefaultShowFullName

View file

@ -785,7 +785,7 @@ func CompareDiff(ctx *context.Context) {
ctx.Data["IsRepoToolbarCommits"] = true
ctx.Data["IsDiffCompare"] = true
_, templateErrs := setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates)
templateErrs := setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates)
if len(templateErrs) > 0 {
ctx.Flash.Warning(renderErrorOfTemplates(ctx, templateErrs), true)

View file

@ -804,11 +804,10 @@ func RetrieveRepoMetas(ctx *context.Context, repo *repo_model.Repository, isPull
return labels
}
// Tries to load and set an issue template. The first return value indicates if a template was loaded.
func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles []string) (bool, map[string]error) {
func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles []string) map[string]error {
commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
if err != nil {
return false, nil
return nil
}
templateCandidates := make([]string, 0, 1+len(possibleFiles))
@ -871,15 +870,20 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles
ctx.Data["label_ids"] = strings.Join(labelIDs, ",")
ctx.Data["Reference"] = template.Ref
ctx.Data["RefEndName"] = git.RefName(template.Ref).ShortName()
return true, templateErrs
return templateErrs
}
return false, templateErrs
return templateErrs
}
// NewIssue render creating issue page
func NewIssue(ctx *context.Context) {
issueConfig, _ := issue_service.GetTemplateConfigFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo)
hasTemplates := issue_service.HasTemplatesOrContactLinks(ctx.Repo.Repository, ctx.Repo.GitRepo)
if !issueConfig.BlankIssuesEnabled && hasTemplates {
// The "issues/new" and "issues/new/choose" share the same query parameters "project" and "milestone", if blank issues are disabled, just redirect to the "issues/choose" page with these parameters.
ctx.Redirect(fmt.Sprintf("%s/issues/new/choose?%s", ctx.Repo.Repository.Link(), ctx.Req.URL.RawQuery), http.StatusSeeOther)
return
}
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
ctx.Data["PageIsIssueList"] = true
@ -926,8 +930,7 @@ func NewIssue(ctx *context.Context) {
RetrieveRepoMetas(ctx, ctx.Repo.Repository, false)
_, templateErrs := issue_service.GetTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo)
templateLoaded, errs := setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates)
if len(errs) > 0 {
if errs := setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates); len(errs) > 0 {
for k, v := range errs {
templateErrs[k] = v
}
@ -942,12 +945,6 @@ func NewIssue(ctx *context.Context) {
ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(unit.TypeIssues)
if !issueConfig.BlankIssuesEnabled && hasTemplates && !templateLoaded {
// The "issues/new" and "issues/new/choose" share the same query parameters "project" and "milestone", if blank issues are disabled, just redirect to the "issues/choose" page with these parameters.
ctx.Redirect(fmt.Sprintf("%s/issues/new/choose?%s", ctx.Repo.Repository.Link(), ctx.Req.URL.RawQuery), http.StatusSeeOther)
return
}
ctx.HTML(http.StatusOK, tplIssueNew)
}

View file

@ -228,10 +228,10 @@ func Profile(ctx *context.Context) {
switch tab {
case "followers":
ctx.Data["Cards"] = followers
total = int(numFollowers)
total = int(count)
case "following":
ctx.Data["Cards"] = following
total = int(numFollowing)
total = int(count)
case "activity":
date := ctx.FormString("date")
items, count, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{

View file

@ -249,8 +249,8 @@ func TestPrepareWikiFileName(t *testing.T) {
unittest.PrepareTestEnv(t)
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
gitRepo, err := git.OpenRepository(git.DefaultContext, repo.WikiPath())
assert.NoError(t, err)
defer gitRepo.Close()
assert.NoError(t, err)
tests := []struct {
name string
@ -301,8 +301,8 @@ func TestPrepareWikiFileName_FirstPage(t *testing.T) {
assert.NoError(t, err)
gitRepo, err := git.OpenRepository(git.DefaultContext, tmpDir)
assert.NoError(t, err)
defer gitRepo.Close()
assert.NoError(t, err)
existence, newWikiPath, err := prepareGitPath(gitRepo, "Home")
assert.False(t, existence)

View file

@ -136,43 +136,6 @@ func TestAPIGetComment(t *testing.T) {
assert.Equal(t, expect.Created.Unix(), apiComment.Created.Unix())
}
func TestAPIGetSystemUserComment(t *testing.T) {
defer tests.PrepareTestEnv(t)()
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{})
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
for _, systemUser := range []*user_model.User{
user_model.NewGhostUser(),
user_model.NewActionsUser(),
} {
body := fmt.Sprintf("Hello %s", systemUser.Name)
comment, err := issues_model.CreateComment(db.DefaultContext, &issues_model.CreateCommentOptions{
Type: issues_model.CommentTypeComment,
Doer: systemUser,
Repo: repo,
Issue: issue,
Content: body,
})
assert.NoError(t, err)
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d", repoOwner.Name, repo.Name, comment.ID)
resp := MakeRequest(t, req, http.StatusOK)
var apiComment api.Comment
DecodeJSON(t, resp, &apiComment)
if assert.NotNil(t, apiComment.Poster) {
if assert.Equal(t, systemUser.ID, apiComment.Poster.ID) {
assert.NoError(t, comment.LoadPoster(db.DefaultContext))
assert.Equal(t, systemUser.Name, apiComment.Poster.UserName)
}
}
assert.Equal(t, body, apiComment.Body)
}
}
func TestAPIEditComment(t *testing.T) {
defer tests.PrepareTestEnv(t)()
const newCommentBody = "This is the new comment body"