Przeglądaj źródła

Add context cache as a request level cache (#22294)

To avoid duplicated load of the same data in an HTTP request, we can set
a context cache to do that. i.e. Some pages may load a user from a
database with the same id in different areas on the same page. But the
code is hidden in two different deep logic. How should we share the
user? As a result of this PR, now if both entry functions accept
`context.Context` as the first parameter and we just need to refactor
`GetUserByID` to reuse the user from the context cache. Then it will not
be loaded twice on an HTTP request.

But of course, sometimes we would like to reload an object from the
database, that's why `RemoveContextData` is also exposed.

The core context cache is here. It defines a new context
```go
type cacheContext struct {
	ctx  context.Context
	data map[any]map[any]any
        lock sync.RWMutex
}

var cacheContextKey = struct{}{}

func WithCacheContext(ctx context.Context) context.Context {
	return context.WithValue(ctx, cacheContextKey, &cacheContext{
		ctx:  ctx,
		data: make(map[any]map[any]any),
	})
}
```

Then you can use the below 4 methods to read/write/del the data within
the same context.

```go
func GetContextData(ctx context.Context, tp, key any) any
func SetContextData(ctx context.Context, tp, key, value any)
func RemoveContextData(ctx context.Context, tp, key any)
func GetWithContextCache[T any](ctx context.Context, cacheGroupKey string, cacheTargetID any, f func() (T, error)) (T, error)
```

Then let's take a look at how `system.GetString` implement it.

```go
func GetSetting(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 := GetSettingNoCache(ctx, key)
			if err != nil {
				return "", err
			}
			return res.SettingValue, nil
		})
	})
}
```

First, it will check if context data include the setting object with the
key. If not, it will query from the global cache which may be memory or
a Redis cache. If not, it will get the object from the database. In the
end, if the object gets from the global cache or database, it will be
set into the context cache.

An object stored in the context cache will only be destroyed after the
context disappeared.
tags/v1.19.0-rc0
Lunny Xiao 1 rok temu
rodzic
commit
bd820aa9c5
No account linked to committer's email address
100 zmienionych plików z 517 dodań i 374 usunięć
  1. 1
    1
      cmd/admin_user_delete.go
  2. 3
    3
      models/activities/repo_activity.go
  3. 6
    5
      models/asymkey/gpg_key_commit_verification.go
  4. 7
    7
      models/avatars/avatar.go
  5. 6
    5
      models/avatars/avatar_test.go
  6. 2
    1
      models/git/commit_status.go
  7. 2
    2
      models/organization/org.go
  8. 1
    6
      models/repo/avatar.go
  9. 33
    26
      models/system/setting.go
  10. 7
    6
      models/system/setting_test.go
  11. 6
    6
      models/user/avatar.go
  12. 5
    10
      models/user/user.go
  13. 2
    1
      modules/auth/webauthn/webauthn.go
  14. 92
    0
      modules/cache/context.go
  15. 41
    0
      modules/cache/context_test.go
  16. 4
    4
      modules/gitgraph/graph_models.go
  17. 6
    6
      modules/repository/commits.go
  18. 4
    3
      modules/repository/commits_test.go
  19. 3
    3
      modules/repository/repo.go
  20. 11
    12
      modules/templates/helper.go
  21. 1
    1
      routers/api/v1/activitypub/person.go
  22. 2
    2
      routers/api/v1/admin/org.go
  23. 3
    3
      routers/api/v1/admin/user.go
  24. 1
    1
      routers/api/v1/org/member.go
  25. 5
    5
      routers/api/v1/org/org.go
  26. 8
    8
      routers/api/v1/org/team.go
  27. 3
    3
      routers/api/v1/repo/branch.go
  28. 4
    4
      routers/api/v1/repo/collaborators.go
  29. 2
    2
      routers/api/v1/repo/commits.go
  30. 3
    3
      routers/api/v1/repo/hook.go
  31. 5
    5
      routers/api/v1/repo/issue_comment.go
  32. 6
    6
      routers/api/v1/repo/issue_reaction.go
  33. 1
    1
      routers/api/v1/repo/issue_subscription.go
  34. 1
    1
      routers/api/v1/repo/notes.go
  35. 1
    1
      routers/api/v1/repo/pull.go
  36. 1
    1
      routers/api/v1/repo/pull_review.go
  37. 5
    5
      routers/api/v1/repo/release.go
  38. 1
    1
      routers/api/v1/repo/release_attachment.go
  39. 1
    1
      routers/api/v1/repo/release_tags.go
  40. 1
    1
      routers/api/v1/repo/star.go
  41. 1
    1
      routers/api/v1/repo/subscriber.go
  42. 1
    1
      routers/api/v1/repo/tag.go
  43. 2
    2
      routers/api/v1/repo/teams.go
  44. 1
    1
      routers/api/v1/repo/transfer.go
  45. 1
    1
      routers/api/v1/user/follower.go
  46. 7
    6
      routers/api/v1/user/key.go
  47. 3
    3
      routers/api/v1/user/user.go
  48. 2
    1
      routers/common/middleware.go
  49. 2
    2
      routers/install/install.go
  50. 1
    1
      routers/private/hook_verification.go
  51. 1
    1
      routers/web/admin/config.go
  52. 1
    1
      routers/web/auth/linkaccount.go
  53. 2
    2
      routers/web/auth/oauth.go
  54. 2
    2
      routers/web/auth/oauth_test.go
  55. 1
    1
      routers/web/auth/openid.go
  56. 1
    1
      routers/web/auth/password.go
  57. 1
    1
      routers/web/org/teams.go
  58. 3
    3
      routers/web/repo/blame.go
  59. 4
    4
      routers/web/repo/commit.go
  60. 1
    1
      routers/web/repo/issue.go
  61. 2
    2
      routers/web/repo/view.go
  62. 1
    1
      routers/web/repo/webhook.go
  63. 2
    2
      routers/web/user/avatar.go
  64. 1
    1
      routers/web/user/search.go
  65. 2
    2
      routers/web/webfinger.go
  66. 23
    23
      services/actions/notifier.go
  67. 3
    3
      services/actions/notifier_helper.go
  68. 6
    6
      services/asymkey/sign.go
  69. 1
    1
      services/auth/reverseproxy.go
  70. 13
    13
      services/convert/convert.go
  71. 13
    12
      services/convert/git_commit.go
  72. 3
    3
      services/convert/issue.go
  73. 7
    7
      services/convert/issue_comment.go
  74. 2
    2
      services/convert/package.go
  75. 1
    1
      services/convert/pull.go
  76. 4
    4
      services/convert/pull_review.go
  77. 4
    2
      services/convert/release.go
  78. 7
    7
      services/convert/repository.go
  79. 1
    1
      services/convert/status.go
  80. 12
    10
      services/convert/user.go
  81. 5
    4
      services/convert/user_test.go
  82. 1
    1
      services/pull/check.go
  83. 1
    1
      services/release/release.go
  84. 1
    1
      services/repository/files/cherry_pick.go
  85. 2
    2
      services/repository/files/commit.go
  86. 1
    1
      services/repository/files/file.go
  87. 1
    1
      services/repository/files/patch.go
  88. 1
    1
      services/repository/push.go
  89. 1
    1
      services/user/user_test.go
  90. 45
    45
      services/webhook/notifier.go
  91. 1
    1
      templates/admin/user/edit.tmpl
  92. 4
    4
      templates/base/head.tmpl
  93. 2
    2
      templates/base/head_navbar.tmpl
  94. 2
    2
      templates/base/head_script.tmpl
  95. 1
    1
      templates/explore/organizations.tmpl
  96. 1
    1
      templates/explore/users.tmpl
  97. 1
    1
      templates/org/header.tmpl
  98. 2
    2
      templates/org/home.tmpl
  99. 1
    1
      templates/org/member/members.tmpl
  100. 0
    0
      templates/org/team/invite.tmpl

+ 1
- 1
cmd/admin_user_delete.go Wyświetl plik

var err error var err error
var user *user_model.User var user *user_model.User
if c.IsSet("email") { if c.IsSet("email") {
user, err = user_model.GetUserByEmail(c.String("email"))
user, err = user_model.GetUserByEmail(ctx, c.String("email"))
} else if c.IsSet("username") { } else if c.IsSet("username") {
user, err = user_model.GetUserByName(ctx, c.String("username")) user, err = user_model.GetUserByName(ctx, c.String("username"))
} else { } else {

+ 3
- 3
models/activities/repo_activity.go Wyświetl plik

} }
users := make(map[int64]*ActivityAuthorData) users := make(map[int64]*ActivityAuthorData)
var unknownUserID int64 var unknownUserID int64
unknownUserAvatarLink := user_model.NewGhostUser().AvatarLink()
unknownUserAvatarLink := user_model.NewGhostUser().AvatarLink(ctx)
for _, v := range code.Authors { for _, v := range code.Authors {
if len(v.Email) == 0 { if len(v.Email) == 0 {
continue continue
} }
u, err := user_model.GetUserByEmail(v.Email)
u, err := user_model.GetUserByEmail(ctx, v.Email)
if u == nil || user_model.IsErrUserNotExist(err) { if u == nil || user_model.IsErrUserNotExist(err) {
unknownUserID-- unknownUserID--
users[unknownUserID] = &ActivityAuthorData{ users[unknownUserID] = &ActivityAuthorData{
users[u.ID] = &ActivityAuthorData{ users[u.ID] = &ActivityAuthorData{
Name: u.DisplayName(), Name: u.DisplayName(),
Login: u.LowerName, Login: u.LowerName,
AvatarLink: u.AvatarLink(),
AvatarLink: u.AvatarLink(ctx),
HomeLink: u.HomeLink(), HomeLink: u.HomeLink(),
Commits: v.Commits, Commits: v.Commits,
} }

+ 6
- 5
models/asymkey/gpg_key_commit_verification.go Wyświetl plik

package asymkey package asymkey


import ( import (
"context"
"fmt" "fmt"
"hash" "hash"
"strings" "strings"
) )


// ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys. // ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys.
func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repoTrustModel repo_model.TrustModelType, isOwnerMemberCollaborator func(*user_model.User) (bool, error)) []*SignCommit {
func ParseCommitsWithSignature(ctx context.Context, oldCommits []*user_model.UserCommit, repoTrustModel repo_model.TrustModelType, isOwnerMemberCollaborator func(*user_model.User) (bool, error)) []*SignCommit {
newCommits := make([]*SignCommit, 0, len(oldCommits)) newCommits := make([]*SignCommit, 0, len(oldCommits))
keyMap := map[string]bool{} keyMap := map[string]bool{}


for _, c := range oldCommits { for _, c := range oldCommits {
signCommit := &SignCommit{ signCommit := &SignCommit{
UserCommit: c, UserCommit: c,
Verification: ParseCommitWithSignature(c.Commit),
Verification: ParseCommitWithSignature(ctx, c.Commit),
} }


_ = CalculateTrustStatus(signCommit.Verification, repoTrustModel, isOwnerMemberCollaborator, &keyMap) _ = CalculateTrustStatus(signCommit.Verification, repoTrustModel, isOwnerMemberCollaborator, &keyMap)
} }


// ParseCommitWithSignature check if signature is good against keystore. // ParseCommitWithSignature check if signature is good against keystore.
func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerification {
var committer *user_model.User var committer *user_model.User
if c.Committer != nil { if c.Committer != nil {
var err error var err error
// Find Committer account // Find Committer account
committer, err = user_model.GetUserByEmail(c.Committer.Email) // This finds the user by primary email or activated email so commit will not be valid if email is not
if err != nil { // Skipping not user for committer
committer, err = user_model.GetUserByEmail(ctx, c.Committer.Email) // This finds the user by primary email or activated email so commit will not be valid if email is not
if err != nil { // Skipping not user for committer
committer = &user_model.User{ committer = &user_model.User{
Name: c.Committer.Name, Name: c.Committer.Name,
Email: c.Committer.Email, Email: c.Committer.Email,

+ 7
- 7
models/avatars/avatar.go Wyświetl plik

// generateEmailAvatarLink returns a email avatar link. // generateEmailAvatarLink returns a email avatar link.
// if final is true, it may use a slow path (eg: query DNS). // if final is true, it may use a slow path (eg: query DNS).
// if final is false, it always uses a fast path. // if final is false, it always uses a fast path.
func generateEmailAvatarLink(email string, size int, final bool) string {
func generateEmailAvatarLink(ctx context.Context, email string, size int, final bool) string {
email = strings.TrimSpace(email) email = strings.TrimSpace(email)
if email == "" { if email == "" {
return DefaultAvatarLink() return DefaultAvatarLink()
} }


enableFederatedAvatar := system_model.GetSettingBool(system_model.KeyPictureEnableFederatedAvatar)
enableFederatedAvatar := system_model.GetSettingBool(ctx, system_model.KeyPictureEnableFederatedAvatar)


var err error var err error
if enableFederatedAvatar && system_model.LibravatarService != nil { if enableFederatedAvatar && system_model.LibravatarService != nil {
return urlStr return urlStr
} }


disableGravatar := system_model.GetSettingBool(system_model.KeyPictureDisableGravatar)
disableGravatar := system_model.GetSettingBool(ctx, system_model.KeyPictureDisableGravatar)
if !disableGravatar { if !disableGravatar {
// copy GravatarSourceURL, because we will modify its Path. // copy GravatarSourceURL, because we will modify its Path.
avatarURLCopy := *system_model.GravatarSourceURL avatarURLCopy := *system_model.GravatarSourceURL
} }


// GenerateEmailAvatarFastLink returns a avatar link (fast, the link may be a delegated one: "/avatar/${hash}") // GenerateEmailAvatarFastLink returns a avatar link (fast, the link may be a delegated one: "/avatar/${hash}")
func GenerateEmailAvatarFastLink(email string, size int) string {
return generateEmailAvatarLink(email, size, false)
func GenerateEmailAvatarFastLink(ctx context.Context, email string, size int) string {
return generateEmailAvatarLink(ctx, email, size, false)
} }


// GenerateEmailAvatarFinalLink returns a avatar final link (maybe slow) // GenerateEmailAvatarFinalLink returns a avatar final link (maybe slow)
func GenerateEmailAvatarFinalLink(email string, size int) string {
return generateEmailAvatarLink(email, size, true)
func GenerateEmailAvatarFinalLink(ctx context.Context, email string, size int) string {
return generateEmailAvatarLink(ctx, email, size, true)
} }

+ 6
- 5
models/avatars/avatar_test.go Wyświetl plik

"testing" "testing"


avatars_model "code.gitea.io/gitea/models/avatars" avatars_model "code.gitea.io/gitea/models/avatars"
"code.gitea.io/gitea/models/db"
system_model "code.gitea.io/gitea/models/system" system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"


const gravatarSource = "https://secure.gravatar.com/avatar/" const gravatarSource = "https://secure.gravatar.com/avatar/"


func disableGravatar(t *testing.T) { func disableGravatar(t *testing.T) {
err := system_model.SetSettingNoVersion(system_model.KeyPictureEnableFederatedAvatar, "false")
err := system_model.SetSettingNoVersion(db.DefaultContext, system_model.KeyPictureEnableFederatedAvatar, "false")
assert.NoError(t, err) assert.NoError(t, err)
err = system_model.SetSettingNoVersion(system_model.KeyPictureDisableGravatar, "true")
err = system_model.SetSettingNoVersion(db.DefaultContext, system_model.KeyPictureDisableGravatar, "true")
assert.NoError(t, err) assert.NoError(t, err)
system_model.LibravatarService = nil system_model.LibravatarService = nil
} }


func enableGravatar(t *testing.T) { func enableGravatar(t *testing.T) {
err := system_model.SetSettingNoVersion(system_model.KeyPictureDisableGravatar, "false")
err := system_model.SetSettingNoVersion(db.DefaultContext, system_model.KeyPictureDisableGravatar, "false")
assert.NoError(t, err) assert.NoError(t, err)
setting.GravatarSource = gravatarSource setting.GravatarSource = gravatarSource
err = system_model.Init() err = system_model.Init()


disableGravatar(t) disableGravatar(t)
assert.Equal(t, "/testsuburl/assets/img/avatar_default.png", assert.Equal(t, "/testsuburl/assets/img/avatar_default.png",
avatars_model.GenerateEmailAvatarFastLink("gitea@example.com", 100))
avatars_model.GenerateEmailAvatarFastLink(db.DefaultContext, "gitea@example.com", 100))


enableGravatar(t) enableGravatar(t)
assert.Equal(t, assert.Equal(t,
"https://secure.gravatar.com/avatar/353cbad9b58e69c96154ad99f92bedc7?d=identicon&s=100", "https://secure.gravatar.com/avatar/353cbad9b58e69c96154ad99f92bedc7?d=identicon&s=100",
avatars_model.GenerateEmailAvatarFastLink("gitea@example.com", 100),
avatars_model.GenerateEmailAvatarFastLink(db.DefaultContext, "gitea@example.com", 100),
) )
} }

+ 2
- 1
models/git/commit_status.go Wyświetl plik

func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo_model.Repository) []*SignCommitWithStatuses { func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo_model.Repository) []*SignCommitWithStatuses {
return ParseCommitsWithStatus(ctx, return ParseCommitsWithStatus(ctx,
asymkey_model.ParseCommitsWithSignature( asymkey_model.ParseCommitsWithSignature(
user_model.ValidateCommitsWithEmails(commits),
ctx,
user_model.ValidateCommitsWithEmails(ctx, commits),
repo.GetTrustModel(), repo.GetTrustModel(),
func(user *user_model.User) (bool, error) { func(user *user_model.User) (bool, error) {
return repo_model.IsOwnerMemberCollaborator(repo, user.ID) return repo_model.IsOwnerMemberCollaborator(repo, user.ID)

+ 2
- 2
models/organization/org.go Wyświetl plik

} }


// AvatarLink returns the full avatar link with http host // AvatarLink returns the full avatar link with http host
func (org *Organization) AvatarLink() string {
return org.AsUser().AvatarLink()
func (org *Organization) AvatarLink(ctx context.Context) string {
return org.AsUser().AvatarLink(ctx)
} }


// HTMLURL returns the organization's full link. // HTMLURL returns the organization's full link.

+ 1
- 6
models/repo/avatar.go Wyświetl plik

} }


// AvatarLink returns a link to the repository's avatar. // AvatarLink returns a link to the repository's avatar.
func (repo *Repository) AvatarLink() string {
return repo.avatarLink(db.DefaultContext)
}

// avatarLink returns user avatar absolute link.
func (repo *Repository) avatarLink(ctx context.Context) string {
func (repo *Repository) AvatarLink(ctx context.Context) string {
link := repo.relAvatarLink(ctx) link := repo.relAvatarLink(ctx)
// we only prepend our AppURL to our known (relative, internal) avatar link to get an absolute URL // we only prepend our AppURL to our known (relative, internal) avatar link to get an absolute URL
if strings.HasPrefix(link, "/") && !strings.HasPrefix(link, "//") { if strings.HasPrefix(link, "/") && !strings.HasPrefix(link, "//") {

+ 33
- 26
models/system/setting.go Wyświetl plik

} }


// GetSettingNoCache returns specific setting without using the cache // GetSettingNoCache returns specific setting without using the cache
func GetSettingNoCache(key string) (*Setting, error) {
v, err := GetSettings([]string{key})
func GetSettingNoCache(ctx context.Context, key string) (*Setting, error) {
v, err := GetSettings(ctx, []string{key})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return v[strings.ToLower(key)], nil return v[strings.ToLower(key)], nil
} }


const contextCacheKey = "system_setting"

// GetSetting returns the setting value via the key // GetSetting returns the setting value via the key
func GetSetting(key string) (string, error) {
return cache.GetString(genSettingCacheKey(key), func() (string, error) {
res, err := GetSettingNoCache(key)
if err != nil {
return "", err
}
return res.SettingValue, nil
func GetSetting(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 := GetSettingNoCache(ctx, key)
if err != nil {
return "", err
}
return res.SettingValue, nil
})
}) })
} }


// GetSettingBool return bool value of setting, // GetSettingBool return bool value of setting,
// none existing keys and errors are ignored and result in false // none existing keys and errors are ignored and result in false
func GetSettingBool(key string) bool {
s, _ := GetSetting(key)
func GetSettingBool(ctx context.Context, key string) bool {
s, _ := GetSetting(ctx, key)
v, _ := strconv.ParseBool(s) v, _ := strconv.ParseBool(s)
return v return v
} }


// GetSettings returns specific settings // GetSettings returns specific settings
func GetSettings(keys []string) (map[string]*Setting, error) {
func GetSettings(ctx context.Context, keys []string) (map[string]*Setting, error) {
for i := 0; i < len(keys); i++ { for i := 0; i < len(keys); i++ {
keys[i] = strings.ToLower(keys[i]) keys[i] = strings.ToLower(keys[i])
} }
} }


// DeleteSetting deletes a specific setting for a user // DeleteSetting deletes a specific setting for a user
func DeleteSetting(setting *Setting) error {
func DeleteSetting(ctx context.Context, setting *Setting) error {
cache.RemoveContextData(ctx, contextCacheKey, setting.SettingKey)
cache.Remove(genSettingCacheKey(setting.SettingKey)) cache.Remove(genSettingCacheKey(setting.SettingKey))
_, err := db.GetEngine(db.DefaultContext).Delete(setting) _, err := db.GetEngine(db.DefaultContext).Delete(setting)
return err return err
} }


func SetSettingNoVersion(key, value string) error {
s, err := GetSettingNoCache(key)
func SetSettingNoVersion(ctx context.Context, key, value string) error {
s, err := GetSettingNoCache(ctx, key)
if IsErrSettingIsNotExist(err) { if IsErrSettingIsNotExist(err) {
return SetSetting(&Setting{
return SetSetting(ctx, &Setting{
SettingKey: key, SettingKey: key,
SettingValue: value, SettingValue: value,
}) })
return err return err
} }
s.SettingValue = value s.SettingValue = value
return SetSetting(s)
return SetSetting(ctx, s)
} }


// SetSetting updates a users' setting for a specific key // SetSetting updates a users' setting for a specific key
func SetSetting(setting *Setting) error {
func SetSetting(ctx context.Context, setting *Setting) error {
if err := upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version); err != nil { if err := upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version); err != nil {
return err return err
} }


cc := cache.GetCache() cc := cache.GetCache()
if cc != nil { if cc != nil {
return cc.Put(genSettingCacheKey(setting.SettingKey), setting.SettingValue, setting_module.CacheService.TTLSeconds())
if err := cc.Put(genSettingCacheKey(setting.SettingKey), setting.SettingValue, setting_module.CacheService.TTLSeconds()); err != nil {
return err
}
} }

cache.SetContextData(ctx, contextCacheKey, setting.SettingKey, setting.SettingValue)
return nil return nil
} }




func Init() error { func Init() error {
var disableGravatar bool var disableGravatar bool
disableGravatarSetting, err := GetSettingNoCache(KeyPictureDisableGravatar)
disableGravatarSetting, err := GetSettingNoCache(db.DefaultContext, KeyPictureDisableGravatar)
if IsErrSettingIsNotExist(err) { if IsErrSettingIsNotExist(err) {
disableGravatar = setting_module.GetDefaultDisableGravatar() disableGravatar = setting_module.GetDefaultDisableGravatar()
disableGravatarSetting = &Setting{SettingValue: strconv.FormatBool(disableGravatar)} disableGravatarSetting = &Setting{SettingValue: strconv.FormatBool(disableGravatar)}
} }


var enableFederatedAvatar bool var enableFederatedAvatar bool
enableFederatedAvatarSetting, err := GetSettingNoCache(KeyPictureEnableFederatedAvatar)
enableFederatedAvatarSetting, err := GetSettingNoCache(db.DefaultContext, KeyPictureEnableFederatedAvatar)
if IsErrSettingIsNotExist(err) { if IsErrSettingIsNotExist(err) {
enableFederatedAvatar = setting_module.GetDefaultEnableFederatedAvatar(disableGravatar) enableFederatedAvatar = setting_module.GetDefaultEnableFederatedAvatar(disableGravatar)
enableFederatedAvatarSetting = &Setting{SettingValue: strconv.FormatBool(enableFederatedAvatar)} enableFederatedAvatarSetting = &Setting{SettingValue: strconv.FormatBool(enableFederatedAvatar)}
if setting_module.OfflineMode { if setting_module.OfflineMode {
disableGravatar = true disableGravatar = true
enableFederatedAvatar = false enableFederatedAvatar = false
if !GetSettingBool(KeyPictureDisableGravatar) {
if err := SetSettingNoVersion(KeyPictureDisableGravatar, "true"); err != nil {
if !GetSettingBool(db.DefaultContext, KeyPictureDisableGravatar) {
if err := SetSettingNoVersion(db.DefaultContext, KeyPictureDisableGravatar, "true"); err != nil {
return fmt.Errorf("Failed to set setting %q: %w", KeyPictureDisableGravatar, err) return fmt.Errorf("Failed to set setting %q: %w", KeyPictureDisableGravatar, err)
} }
} }
if GetSettingBool(KeyPictureEnableFederatedAvatar) {
if err := SetSettingNoVersion(KeyPictureEnableFederatedAvatar, "false"); err != nil {
if GetSettingBool(db.DefaultContext, KeyPictureEnableFederatedAvatar) {
if err := SetSettingNoVersion(db.DefaultContext, KeyPictureEnableFederatedAvatar, "false"); err != nil {
return fmt.Errorf("Failed to set setting %q: %w", KeyPictureEnableFederatedAvatar, err) return fmt.Errorf("Failed to set setting %q: %w", KeyPictureEnableFederatedAvatar, err)
} }
} }

+ 7
- 6
models/system/setting_test.go Wyświetl plik

"strings" "strings"
"testing" "testing"


"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/system" "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"


newSetting := &system.Setting{SettingKey: keyName, SettingValue: "50"} newSetting := &system.Setting{SettingKey: keyName, SettingValue: "50"}


// create setting // create setting
err := system.SetSetting(newSetting)
err := system.SetSetting(db.DefaultContext, newSetting)
assert.NoError(t, err) assert.NoError(t, err)
// test about saving unchanged values // test about saving unchanged values
err = system.SetSetting(newSetting)
err = system.SetSetting(db.DefaultContext, newSetting)
assert.NoError(t, err) assert.NoError(t, err)


// get specific setting // get specific setting
settings, err := system.GetSettings([]string{keyName})
settings, err := system.GetSettings(db.DefaultContext, []string{keyName})
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, settings, 1) assert.Len(t, settings, 1)
assert.EqualValues(t, newSetting.SettingValue, settings[strings.ToLower(keyName)].SettingValue) assert.EqualValues(t, newSetting.SettingValue, settings[strings.ToLower(keyName)].SettingValue)


// updated setting // updated setting
updatedSetting := &system.Setting{SettingKey: keyName, SettingValue: "100", Version: settings[strings.ToLower(keyName)].Version} updatedSetting := &system.Setting{SettingKey: keyName, SettingValue: "100", Version: settings[strings.ToLower(keyName)].Version}
err = system.SetSetting(updatedSetting)
err = system.SetSetting(db.DefaultContext, updatedSetting)
assert.NoError(t, err) assert.NoError(t, err)


value, err := system.GetSetting(keyName)
value, err := system.GetSetting(db.DefaultContext, keyName)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, updatedSetting.SettingValue, value) assert.EqualValues(t, updatedSetting.SettingValue, value)


assert.EqualValues(t, updatedSetting.SettingValue, settings[strings.ToLower(updatedSetting.SettingKey)].SettingValue) assert.EqualValues(t, updatedSetting.SettingValue, settings[strings.ToLower(updatedSetting.SettingKey)].SettingValue)


// delete setting // delete setting
err = system.DeleteSetting(&system.Setting{SettingKey: strings.ToLower(keyName)})
err = system.DeleteSetting(db.DefaultContext, &system.Setting{SettingKey: strings.ToLower(keyName)})
assert.NoError(t, err) assert.NoError(t, err)
settings, err = system.GetAllSettings() settings, err = system.GetAllSettings()
assert.NoError(t, err) assert.NoError(t, err)

+ 6
- 6
models/user/avatar.go Wyświetl plik

} }


// AvatarLinkWithSize returns a link to the user's avatar with size. size <= 0 means default size // AvatarLinkWithSize returns a link to the user's avatar with size. size <= 0 means default size
func (u *User) AvatarLinkWithSize(size int) string {
func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
if u.ID == -1 { if u.ID == -1 {
// ghost user // ghost user
return avatars.DefaultAvatarLink() return avatars.DefaultAvatarLink()
useLocalAvatar := false useLocalAvatar := false
autoGenerateAvatar := false autoGenerateAvatar := false


disableGravatar := system_model.GetSettingBool(system_model.KeyPictureDisableGravatar)
disableGravatar := system_model.GetSettingBool(ctx, system_model.KeyPictureDisableGravatar)


switch { switch {
case u.UseCustomAvatar: case u.UseCustomAvatar:


if useLocalAvatar { if useLocalAvatar {
if u.Avatar == "" && autoGenerateAvatar { if u.Avatar == "" && autoGenerateAvatar {
if err := GenerateRandomAvatar(db.DefaultContext, u); err != nil {
if err := GenerateRandomAvatar(ctx, u); err != nil {
log.Error("GenerateRandomAvatar: %v", err) log.Error("GenerateRandomAvatar: %v", err)
} }
} }
} }
return avatars.GenerateUserAvatarImageLink(u.Avatar, size) return avatars.GenerateUserAvatarImageLink(u.Avatar, size)
} }
return avatars.GenerateEmailAvatarFastLink(u.AvatarEmail, size)
return avatars.GenerateEmailAvatarFastLink(ctx, u.AvatarEmail, size)
} }


// AvatarLink returns the full avatar link with http host // AvatarLink returns the full avatar link with http host
func (u *User) AvatarLink() string {
link := u.AvatarLinkWithSize(0)
func (u *User) AvatarLink(ctx context.Context) string {
link := u.AvatarLinkWithSize(ctx, 0)
if !strings.HasPrefix(link, "//") && !strings.Contains(link, "://") { if !strings.HasPrefix(link, "//") && !strings.Contains(link, "://") {
return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL+"/") return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL+"/")
} }

+ 5
- 10
models/user/user.go Wyświetl plik

} }


// ValidateCommitWithEmail check if author's e-mail of commit is corresponding to a user. // ValidateCommitWithEmail check if author's e-mail of commit is corresponding to a user.
func ValidateCommitWithEmail(c *git.Commit) *User {
func ValidateCommitWithEmail(ctx context.Context, c *git.Commit) *User {
if c.Author == nil { if c.Author == nil {
return nil return nil
} }
u, err := GetUserByEmail(c.Author.Email)
u, err := GetUserByEmail(ctx, c.Author.Email)
if err != nil { if err != nil {
return nil return nil
} }
} }


// ValidateCommitsWithEmails checks if authors' e-mails of commits are corresponding to users. // ValidateCommitsWithEmails checks if authors' e-mails of commits are corresponding to users.
func ValidateCommitsWithEmails(oldCommits []*git.Commit) []*UserCommit {
func ValidateCommitsWithEmails(ctx context.Context, oldCommits []*git.Commit) []*UserCommit {
var ( var (
emails = make(map[string]*User) emails = make(map[string]*User)
newCommits = make([]*UserCommit, 0, len(oldCommits)) newCommits = make([]*UserCommit, 0, len(oldCommits))
var u *User var u *User
if c.Author != nil { if c.Author != nil {
if v, ok := emails[c.Author.Email]; !ok { if v, ok := emails[c.Author.Email]; !ok {
u, _ = GetUserByEmail(c.Author.Email)
u, _ = GetUserByEmail(ctx, c.Author.Email)
emails[c.Author.Email] = u emails[c.Author.Email] = u
} else { } else {
u = v u = v
} }


// GetUserByEmail returns the user object by given e-mail if exists. // GetUserByEmail returns the user object by given e-mail if exists.
func GetUserByEmail(email string) (*User, error) {
return GetUserByEmailContext(db.DefaultContext, email)
}

// GetUserByEmailContext returns the user object by given e-mail if exists with db context
func GetUserByEmailContext(ctx context.Context, email string) (*User, error) {
func GetUserByEmail(ctx context.Context, email string) (*User, error) {
if len(email) == 0 { if len(email) == 0 {
return nil, ErrUserNotExist{0, email, 0} return nil, ErrUserNotExist{0, email, 0}
} }

+ 2
- 1
modules/auth/webauthn/webauthn.go Wyświetl plik

"encoding/gob" "encoding/gob"


"code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"




// WebAuthnIcon implements the webauthn.User interface // WebAuthnIcon implements the webauthn.User interface
func (u *User) WebAuthnIcon() string { func (u *User) WebAuthnIcon() string {
return (*user_model.User)(u).AvatarLink()
return (*user_model.User)(u).AvatarLink(db.DefaultContext)
} }


// WebAuthnCredentials implementns the webauthn.User interface // WebAuthnCredentials implementns the webauthn.User interface

+ 92
- 0
modules/cache/context.go Wyświetl plik

// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package cache

import (
"context"
"sync"

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

// cacheContext is a context that can be used to cache data in a request level context
// This is useful for caching data that is expensive to calculate and is likely to be
// used multiple times in a request.
type cacheContext struct {
ctx context.Context
data map[any]map[any]any
lock sync.RWMutex
}

func (cc *cacheContext) Get(tp, key any) any {
cc.lock.RLock()
defer cc.lock.RUnlock()
if cc.data[tp] == nil {
return nil
}
return cc.data[tp][key]
}

func (cc *cacheContext) Put(tp, key, value any) {
cc.lock.Lock()
defer cc.lock.Unlock()
if cc.data[tp] == nil {
cc.data[tp] = make(map[any]any)
}
cc.data[tp][key] = value
}

func (cc *cacheContext) Delete(tp, key any) {
cc.lock.Lock()
defer cc.lock.Unlock()
if cc.data[tp] == nil {
return
}
delete(cc.data[tp], key)
}

var cacheContextKey = struct{}{}

func WithCacheContext(ctx context.Context) context.Context {
return context.WithValue(ctx, cacheContextKey, &cacheContext{
ctx: ctx,
data: make(map[any]map[any]any),
})
}

func GetContextData(ctx context.Context, tp, key any) any {
if c, ok := ctx.Value(cacheContextKey).(*cacheContext); ok {
return c.Get(tp, key)
}
log.Warn("cannot get cache context when getting data: %v", ctx)
return nil
}

func SetContextData(ctx context.Context, tp, key, value any) {
if c, ok := ctx.Value(cacheContextKey).(*cacheContext); ok {
c.Put(tp, key, value)
return
}
log.Warn("cannot get cache context when setting data: %v", ctx)
}

func RemoveContextData(ctx context.Context, tp, key any) {
if c, ok := ctx.Value(cacheContextKey).(*cacheContext); ok {
c.Delete(tp, key)
}
}

// GetWithContextCache returns the cache value of the given key in the given context.
func GetWithContextCache[T any](ctx context.Context, cacheGroupKey string, cacheTargetID any, f func() (T, error)) (T, error) {
v := GetContextData(ctx, cacheGroupKey, cacheTargetID)
if vv, ok := v.(T); ok {
return vv, nil
}
t, err := f()
if err != nil {
return t, err
}
SetContextData(ctx, cacheGroupKey, cacheTargetID, t)
return t, nil
}

+ 41
- 0
modules/cache/context_test.go Wyświetl plik

// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package cache

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
)

func TestWithCacheContext(t *testing.T) {
ctx := WithCacheContext(context.Background())

v := GetContextData(ctx, "empty_field", "my_config1")
assert.Nil(t, v)

const field = "system_setting"
v = GetContextData(ctx, field, "my_config1")
assert.Nil(t, v)
SetContextData(ctx, field, "my_config1", 1)
v = GetContextData(ctx, field, "my_config1")
assert.NotNil(t, v)
assert.EqualValues(t, 1, v.(int))

RemoveContextData(ctx, field, "my_config1")
RemoveContextData(ctx, field, "my_config2") // remove an non-exist key

v = GetContextData(ctx, field, "my_config1")
assert.Nil(t, v)

vInt, err := GetWithContextCache(ctx, field, "my_config1", func() (int, error) {
return 1, nil
})
assert.NoError(t, err)
assert.EqualValues(t, 1, vInt)

v = GetContextData(ctx, field, "my_config1")
assert.EqualValues(t, 1, v)
}

+ 4
- 4
modules/gitgraph/graph_models.go Wyświetl plik



import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"strings" "strings"


// LoadAndProcessCommits will load the git.Commits for each commit in the graph, // LoadAndProcessCommits will load the git.Commits for each commit in the graph,
// the associate the commit with the user author, and check the commit verification // the associate the commit with the user author, and check the commit verification
// before finally retrieving the latest status // before finally retrieving the latest status
func (graph *Graph) LoadAndProcessCommits(repository *repo_model.Repository, gitRepo *git.Repository) error {
func (graph *Graph) LoadAndProcessCommits(ctx context.Context, repository *repo_model.Repository, gitRepo *git.Repository) error {
var err error var err error

var ok bool var ok bool


emails := map[string]*user_model.User{} emails := map[string]*user_model.User{}
if c.Commit.Author != nil { if c.Commit.Author != nil {
email := c.Commit.Author.Email email := c.Commit.Author.Email
if c.User, ok = emails[email]; !ok { if c.User, ok = emails[email]; !ok {
c.User, _ = user_model.GetUserByEmail(email)
c.User, _ = user_model.GetUserByEmail(ctx, email)
emails[email] = c.User emails[email] = c.User
} }
} }


c.Verification = asymkey_model.ParseCommitWithSignature(c.Commit)
c.Verification = asymkey_model.ParseCommitWithSignature(ctx, c.Commit)


_ = asymkey_model.CalculateTrustStatus(c.Verification, repository.GetTrustModel(), func(user *user_model.User) (bool, error) { _ = asymkey_model.CalculateTrustStatus(c.Verification, repository.GetTrustModel(), func(user *user_model.User) (bool, error) {
return repo_model.IsOwnerMemberCollaborator(repository, user.ID) return repo_model.IsOwnerMemberCollaborator(repository, user.ID)

+ 6
- 6
modules/repository/commits.go Wyświetl plik

authorUsername := "" authorUsername := ""
author, ok := pc.emailUsers[commit.AuthorEmail] author, ok := pc.emailUsers[commit.AuthorEmail]
if !ok { if !ok {
author, err = user_model.GetUserByEmail(commit.AuthorEmail)
author, err = user_model.GetUserByEmail(ctx, commit.AuthorEmail)
if err == nil { if err == nil {
authorUsername = author.Name authorUsername = author.Name
pc.emailUsers[commit.AuthorEmail] = author pc.emailUsers[commit.AuthorEmail] = author
committerUsername := "" committerUsername := ""
committer, ok := pc.emailUsers[commit.CommitterEmail] committer, ok := pc.emailUsers[commit.CommitterEmail]
if !ok { if !ok {
committer, err = user_model.GetUserByEmail(commit.CommitterEmail)
committer, err = user_model.GetUserByEmail(ctx, commit.CommitterEmail)
if err == nil { if err == nil {
// TODO: check errors other than email not found. // TODO: check errors other than email not found.
committerUsername = committer.Name committerUsername = committer.Name


// AvatarLink tries to match user in database with e-mail // AvatarLink tries to match user in database with e-mail
// in order to show custom avatar, and falls back to general avatar link. // in order to show custom avatar, and falls back to general avatar link.
func (pc *PushCommits) AvatarLink(email string) string {
func (pc *PushCommits) AvatarLink(ctx context.Context, email string) string {
if pc.avatars == nil { if pc.avatars == nil {
pc.avatars = make(map[string]string) pc.avatars = make(map[string]string)
} }
u, ok := pc.emailUsers[email] u, ok := pc.emailUsers[email]
if !ok { if !ok {
var err error var err error
u, err = user_model.GetUserByEmail(email)
u, err = user_model.GetUserByEmail(ctx, email)
if err != nil { if err != nil {
pc.avatars[email] = avatars.GenerateEmailAvatarFastLink(email, size)
pc.avatars[email] = avatars.GenerateEmailAvatarFastLink(ctx, email, size)
if !user_model.IsErrUserNotExist(err) { if !user_model.IsErrUserNotExist(err) {
log.Error("GetUserByEmail: %v", err) log.Error("GetUserByEmail: %v", err)
return "" return ""
} }
} }
if u != nil { if u != nil {
pc.avatars[email] = u.AvatarLinkWithSize(size)
pc.avatars[email] = u.AvatarLinkWithSize(ctx, size)
} }


return pc.avatars[email] return pc.avatars[email]

+ 4
- 3
modules/repository/commits_test.go Wyświetl plik

"testing" "testing"
"time" "time"


"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
system_model "code.gitea.io/gitea/models/system" system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
} }


func enableGravatar(t *testing.T) { func enableGravatar(t *testing.T) {
err := system_model.SetSettingNoVersion(system_model.KeyPictureDisableGravatar, "false")
err := system_model.SetSettingNoVersion(db.DefaultContext, system_model.KeyPictureDisableGravatar, "false")
assert.NoError(t, err) assert.NoError(t, err)
setting.GravatarSource = "https://secure.gravatar.com/avatar" setting.GravatarSource = "https://secure.gravatar.com/avatar"
err = system_model.Init() err = system_model.Init()


assert.Equal(t, assert.Equal(t,
"https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon&s=84", "https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon&s=84",
pushCommits.AvatarLink("user2@example.com"))
pushCommits.AvatarLink(db.DefaultContext, "user2@example.com"))


assert.Equal(t, assert.Equal(t,
"https://secure.gravatar.com/avatar/"+ "https://secure.gravatar.com/avatar/"+
fmt.Sprintf("%x", md5.Sum([]byte("nonexistent@example.com")))+ fmt.Sprintf("%x", md5.Sum([]byte("nonexistent@example.com")))+
"?d=identicon&s=84", "?d=identicon&s=84",
pushCommits.AvatarLink("nonexistent@example.com"))
pushCommits.AvatarLink(db.DefaultContext, "nonexistent@example.com"))
} }


func TestCommitToPushCommit(t *testing.T) { func TestCommitToPushCommit(t *testing.T) {

+ 3
- 3
modules/repository/repo.go Wyświetl plik

return nil return nil
} }


if err := PushUpdateAddTag(repo, gitRepo, tagName, sha1, refname); err != nil {
if err := PushUpdateAddTag(db.DefaultContext, repo, gitRepo, tagName, sha1, refname); err != nil {
return fmt.Errorf("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %w", tagName, repo.ID, repo.OwnerName, repo.Name, err) return fmt.Errorf("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %w", tagName, repo.ID, repo.OwnerName, repo.Name, err)
} }


} }


// PushUpdateAddTag must be called for any push actions to add tag // PushUpdateAddTag must be called for any push actions to add tag
func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagName, sha1, refname string) error {
func PushUpdateAddTag(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, tagName, sha1, refname string) error {
tag, err := gitRepo.GetTagWithID(sha1, tagName) tag, err := gitRepo.GetTagWithID(sha1, tagName)
if err != nil { if err != nil {
return fmt.Errorf("unable to GetTag: %w", err) return fmt.Errorf("unable to GetTag: %w", err)
createdAt := time.Unix(1, 0) createdAt := time.Unix(1, 0)


if sig != nil { if sig != nil {
author, err = user_model.GetUserByEmail(sig.Email)
author, err = user_model.GetUserByEmail(ctx, sig.Email)
if err != nil && !user_model.IsErrUserNotExist(err) { if err != nil && !user_model.IsErrUserNotExist(err) {
return fmt.Errorf("unable to GetUserByEmail for %q: %w", sig.Email, err) return fmt.Errorf("unable to GetUserByEmail for %q: %w", sig.Email, err)
} }

+ 11
- 12
modules/templates/helper.go Wyświetl plik



activities_model "code.gitea.io/gitea/models/activities" activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/avatars" "code.gitea.io/gitea/models/avatars"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"AssetVersion": func() string { "AssetVersion": func() string {
return setting.AssetVersion return setting.AssetVersion
}, },
"DisableGravatar": func() bool {
return system_model.GetSettingBool(system_model.KeyPictureDisableGravatar)
"DisableGravatar": func(ctx context.Context) bool {
return system_model.GetSettingBool(ctx, system_model.KeyPictureDisableGravatar)
}, },
"DefaultShowFullName": func() bool { "DefaultShowFullName": func() bool {
return setting.UI.DefaultShowFullName return setting.UI.DefaultShowFullName
} }


// Avatar renders user avatars. args: user, size (int), class (string) // Avatar renders user avatars. args: user, size (int), class (string)
func Avatar(item interface{}, others ...interface{}) template.HTML {
func Avatar(ctx context.Context, item interface{}, others ...interface{}) template.HTML {
size, class := gitea_html.ParseSizeAndClass(avatars.DefaultAvatarPixelSize, avatars.DefaultAvatarClass, others...) size, class := gitea_html.ParseSizeAndClass(avatars.DefaultAvatarPixelSize, avatars.DefaultAvatarClass, others...)


switch t := item.(type) { switch t := item.(type) {
case *user_model.User: case *user_model.User:
src := t.AvatarLinkWithSize(size * setting.Avatar.RenderedSizeFactor)
src := t.AvatarLinkWithSize(ctx, size*setting.Avatar.RenderedSizeFactor)
if src != "" { if src != "" {
return AvatarHTML(src, size, class, t.DisplayName()) return AvatarHTML(src, size, class, t.DisplayName())
} }
case *repo_model.Collaborator: case *repo_model.Collaborator:
src := t.AvatarLinkWithSize(size * setting.Avatar.RenderedSizeFactor)
src := t.AvatarLinkWithSize(ctx, size*setting.Avatar.RenderedSizeFactor)
if src != "" { if src != "" {
return AvatarHTML(src, size, class, t.DisplayName()) return AvatarHTML(src, size, class, t.DisplayName())
} }
case *organization.Organization: case *organization.Organization:
src := t.AsUser().AvatarLinkWithSize(size * setting.Avatar.RenderedSizeFactor)
src := t.AsUser().AvatarLinkWithSize(ctx, size*setting.Avatar.RenderedSizeFactor)
if src != "" { if src != "" {
return AvatarHTML(src, size, class, t.AsUser().DisplayName()) return AvatarHTML(src, size, class, t.AsUser().DisplayName())
} }
} }


// AvatarByAction renders user avatars from action. args: action, size (int), class (string) // AvatarByAction renders user avatars from action. args: action, size (int), class (string)
func AvatarByAction(action *activities_model.Action, others ...interface{}) template.HTML {
action.LoadActUser(db.DefaultContext)
return Avatar(action.ActUser, others...)
func AvatarByAction(ctx context.Context, action *activities_model.Action, others ...interface{}) template.HTML {
action.LoadActUser(ctx)
return Avatar(ctx, action.ActUser, others...)
} }


// RepoAvatar renders repo avatars. args: repo, size(int), class (string) // RepoAvatar renders repo avatars. args: repo, size(int), class (string)
} }


// AvatarByEmail renders avatars by email address. args: email, name, size (int), class (string) // AvatarByEmail renders avatars by email address. args: email, name, size (int), class (string)
func AvatarByEmail(email, name string, others ...interface{}) template.HTML {
func AvatarByEmail(ctx context.Context, email, name string, others ...interface{}) template.HTML {
size, class := gitea_html.ParseSizeAndClass(avatars.DefaultAvatarPixelSize, avatars.DefaultAvatarClass, others...) size, class := gitea_html.ParseSizeAndClass(avatars.DefaultAvatarPixelSize, avatars.DefaultAvatarClass, others...)
src := avatars.GenerateEmailAvatarFastLink(email, size*setting.Avatar.RenderedSizeFactor)
src := avatars.GenerateEmailAvatarFastLink(ctx, email, size*setting.Avatar.RenderedSizeFactor)


if src != "" { if src != "" {
return AvatarHTML(src, size, class, name) return AvatarHTML(src, size, class, name)

+ 1
- 1
routers/api/v1/activitypub/person.go Wyświetl plik

person.Icon = ap.Image{ person.Icon = ap.Image{
Type: ap.ImageType, Type: ap.ImageType,
MediaType: "image/png", MediaType: "image/png",
URL: ap.IRI(ctx.ContextUser.AvatarLink()),
URL: ap.IRI(ctx.ContextUser.AvatarLink(ctx)),
} }


person.Inbox = ap.IRI(link + "/inbox") person.Inbox = ap.IRI(link + "/inbox")

+ 2
- 2
routers/api/v1/admin/org.go Wyświetl plik

return return
} }


ctx.JSON(http.StatusCreated, convert.ToOrganization(org))
ctx.JSON(http.StatusCreated, convert.ToOrganization(ctx, org))
} }


// GetAllOrgs API for getting information of all the organizations // GetAllOrgs API for getting information of all the organizations
} }
orgs := make([]*api.Organization, len(users)) orgs := make([]*api.Organization, len(users))
for i := range users { for i := range users {
orgs[i] = convert.ToOrganization(organization.OrgFromUser(users[i]))
orgs[i] = convert.ToOrganization(ctx, organization.OrgFromUser(users[i]))
} }


ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) ctx.SetLinkHeader(int(maxResults), listOptions.PageSize)

+ 3
- 3
routers/api/v1/admin/user.go Wyświetl plik

if form.SendNotify { if form.SendNotify {
mailer.SendRegisterNotifyMail(u) mailer.SendRegisterNotifyMail(u)
} }
ctx.JSON(http.StatusCreated, convert.ToUser(u, ctx.Doer))
ctx.JSON(http.StatusCreated, convert.ToUser(ctx, u, ctx.Doer))
} }


// EditUser api for modifying a user's information // EditUser api for modifying a user's information
} }
log.Trace("Account profile updated by admin (%s): %s", ctx.Doer.Name, ctx.ContextUser.Name) log.Trace("Account profile updated by admin (%s): %s", ctx.Doer.Name, ctx.ContextUser.Name)


ctx.JSON(http.StatusOK, convert.ToUser(ctx.ContextUser, ctx.Doer))
ctx.JSON(http.StatusOK, convert.ToUser(ctx, ctx.ContextUser, ctx.Doer))
} }


// DeleteUser api for deleting a user // DeleteUser api for deleting a user


results := make([]*api.User, len(users)) results := make([]*api.User, len(users))
for i := range users { for i := range users {
results[i] = convert.ToUser(users[i], ctx.Doer)
results[i] = convert.ToUser(ctx, users[i], ctx.Doer)
} }


ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) ctx.SetLinkHeader(int(maxResults), listOptions.PageSize)

+ 1
- 1
routers/api/v1/org/member.go Wyświetl plik



apiMembers := make([]*api.User, len(members)) apiMembers := make([]*api.User, len(members))
for i, member := range members { for i, member := range members {
apiMembers[i] = convert.ToUser(member, ctx.Doer)
apiMembers[i] = convert.ToUser(ctx, member, ctx.Doer)
} }


ctx.SetTotalCountHeader(count) ctx.SetTotalCountHeader(count)

+ 5
- 5
routers/api/v1/org/org.go Wyświetl plik



apiOrgs := make([]*api.Organization, len(orgs)) apiOrgs := make([]*api.Organization, len(orgs))
for i := range orgs { for i := range orgs {
apiOrgs[i] = convert.ToOrganization(orgs[i])
apiOrgs[i] = convert.ToOrganization(ctx, orgs[i])
} }


ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) ctx.SetLinkHeader(int(maxResults), listOptions.PageSize)
} }
orgs := make([]*api.Organization, len(publicOrgs)) orgs := make([]*api.Organization, len(publicOrgs))
for i := range publicOrgs { for i := range publicOrgs {
orgs[i] = convert.ToOrganization(organization.OrgFromUser(publicOrgs[i]))
orgs[i] = convert.ToOrganization(ctx, organization.OrgFromUser(publicOrgs[i]))
} }


ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) ctx.SetLinkHeader(int(maxResults), listOptions.PageSize)
return return
} }


ctx.JSON(http.StatusCreated, convert.ToOrganization(org))
ctx.JSON(http.StatusCreated, convert.ToOrganization(ctx, org))
} }


// Get get an organization // Get get an organization
ctx.NotFound("HasOrgOrUserVisible", nil) ctx.NotFound("HasOrgOrUserVisible", nil)
return return
} }
ctx.JSON(http.StatusOK, convert.ToOrganization(ctx.Org.Organization))
ctx.JSON(http.StatusOK, convert.ToOrganization(ctx, ctx.Org.Organization))
} }


// Edit change an organization's information // Edit change an organization's information
return return
} }


ctx.JSON(http.StatusOK, convert.ToOrganization(org))
ctx.JSON(http.StatusOK, convert.ToOrganization(ctx, org))
} }


// Delete an organization // Delete an organization

+ 8
- 8
routers/api/v1/org/team.go Wyświetl plik

return return
} }


apiTeams, err := convert.ToTeams(teams, false)
apiTeams, err := convert.ToTeams(ctx, teams, false)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "ConvertToTeams", err) ctx.Error(http.StatusInternalServerError, "ConvertToTeams", err)
return return
return return
} }


apiTeams, err := convert.ToTeams(teams, true)
apiTeams, err := convert.ToTeams(ctx, teams, true)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "ConvertToTeams", err) ctx.Error(http.StatusInternalServerError, "ConvertToTeams", err)
return return
// "200": // "200":
// "$ref": "#/responses/Team" // "$ref": "#/responses/Team"


apiTeam, err := convert.ToTeam(ctx.Org.Team)
apiTeam, err := convert.ToTeam(ctx, ctx.Org.Team)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
return return
} }


apiTeam, err := convert.ToTeam(team)
apiTeam, err := convert.ToTeam(ctx, team)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
return return
} }


apiTeam, err := convert.ToTeam(team)
apiTeam, err := convert.ToTeam(ctx, team)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return


members := make([]*api.User, len(teamMembers)) members := make([]*api.User, len(teamMembers))
for i, member := range teamMembers { for i, member := range teamMembers {
members[i] = convert.ToUser(member, ctx.Doer)
members[i] = convert.ToUser(ctx, member, ctx.Doer)
} }


ctx.SetTotalCountHeader(int64(ctx.Org.Team.NumMembers)) ctx.SetTotalCountHeader(int64(ctx.Org.Team.NumMembers))
ctx.NotFound() ctx.NotFound()
return return
} }
ctx.JSON(http.StatusOK, convert.ToUser(u, ctx.Doer))
ctx.JSON(http.StatusOK, convert.ToUser(ctx, u, ctx.Doer))
} }


// AddTeamMember api for add a member to a team // AddTeamMember api for add a member to a team
return return
} }


apiTeams, err := convert.ToTeams(teams, false)
apiTeams, err := convert.ToTeams(ctx, teams, false)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return

+ 3
- 3
routers/api/v1/repo/branch.go Wyświetl plik

return return
} }


br, err := convert.ToBranch(ctx.Repo.Repository, branch, c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
br, err := convert.ToBranch(ctx, ctx.Repo.Repository, branch, c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err) ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err)
return return
return return
} }


br, err := convert.ToBranch(ctx.Repo.Repository, branch, commit, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
br, err := convert.ToBranch(ctx, ctx.Repo.Repository, branch, commit, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err) ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err)
return return
} }


branchProtection := rules.GetFirstMatched(branches[i].Name) branchProtection := rules.GetFirstMatched(branches[i].Name)
apiBranch, err := convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
apiBranch, err := convert.ToBranch(ctx, ctx.Repo.Repository, branches[i], c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err) ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err)
return return

+ 4
- 4
routers/api/v1/repo/collaborators.go Wyświetl plik



users := make([]*api.User, len(collaborators)) users := make([]*api.User, len(collaborators))
for i, collaborator := range collaborators { for i, collaborator := range collaborators {
users[i] = convert.ToUser(collaborator.User, ctx.Doer)
users[i] = convert.ToUser(ctx, collaborator.User, ctx.Doer)
} }


ctx.SetTotalCountHeader(count) ctx.SetTotalCountHeader(count)
return return
} }


ctx.JSON(http.StatusOK, convert.ToUserAndPermission(collaborator, ctx.ContextUser, permission.AccessMode))
ctx.JSON(http.StatusOK, convert.ToUserAndPermission(ctx, collaborator, ctx.ContextUser, permission.AccessMode))
} }


// GetReviewers return all users that can be requested to review in this repo // GetReviewers return all users that can be requested to review in this repo
ctx.Error(http.StatusInternalServerError, "ListCollaborators", err) ctx.Error(http.StatusInternalServerError, "ListCollaborators", err)
return return
} }
ctx.JSON(http.StatusOK, convert.ToUsers(ctx.Doer, reviewers))
ctx.JSON(http.StatusOK, convert.ToUsers(ctx, ctx.Doer, reviewers))
} }


// GetAssignees return all users that have write access and can be assigned to issues // GetAssignees return all users that have write access and can be assigned to issues
ctx.Error(http.StatusInternalServerError, "ListCollaborators", err) ctx.Error(http.StatusInternalServerError, "ListCollaborators", err)
return return
} }
ctx.JSON(http.StatusOK, convert.ToUsers(ctx.Doer, assignees))
ctx.JSON(http.StatusOK, convert.ToUsers(ctx, ctx.Doer, assignees))
} }

+ 2
- 2
routers/api/v1/repo/commits.go Wyświetl plik

return return
} }


json, err := convert.ToCommit(ctx.Repo.Repository, ctx.Repo.GitRepo, commit, nil, true)
json, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, commit, nil, true)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "toCommit", err) ctx.Error(http.StatusInternalServerError, "toCommit", err)
return return


for i, commit := range commits { for i, commit := range commits {
// Create json struct // Create json struct
apiCommits[i], err = convert.ToCommit(ctx.Repo.Repository, ctx.Repo.GitRepo, commit, userCache, stat)
apiCommits[i], err = convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, commit, userCache, stat)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "toCommit", err) ctx.Error(http.StatusInternalServerError, "toCommit", err)
return return

+ 3
- 3
routers/api/v1/repo/hook.go Wyświetl plik

return return
} }


commit := convert.ToPayloadCommit(ctx.Repo.Repository, ctx.Repo.Commit)
commit := convert.ToPayloadCommit(ctx, ctx.Repo.Repository, ctx.Repo.Commit)


commitID := ctx.Repo.Commit.ID.String() commitID := ctx.Repo.Commit.ID.String()
if err := webhook_service.PrepareWebhook(ctx, hook, webhook_module.HookEventPush, &api.PushPayload{ if err := webhook_service.PrepareWebhook(ctx, hook, webhook_module.HookEventPush, &api.PushPayload{
TotalCommits: 1, TotalCommits: 1,
HeadCommit: commit, HeadCommit: commit,
Repo: convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeNone), Repo: convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeNone),
Pusher: convert.ToUserWithAccessMode(ctx.Doer, perm.AccessModeNone),
Sender: convert.ToUserWithAccessMode(ctx.Doer, perm.AccessModeNone),
Pusher: convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone),
Sender: convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone),
}); err != nil { }); err != nil {
ctx.Error(http.StatusInternalServerError, "PrepareWebhook: ", err) ctx.Error(http.StatusInternalServerError, "PrepareWebhook: ", err)
return return

+ 5
- 5
routers/api/v1/repo/issue_comment.go Wyświetl plik

apiComments := make([]*api.Comment, len(comments)) apiComments := make([]*api.Comment, len(comments))
for i, comment := range comments { for i, comment := range comments {
comment.Issue = issue comment.Issue = issue
apiComments[i] = convert.ToComment(comments[i])
apiComments[i] = convert.ToComment(ctx, comments[i])
} }


ctx.SetTotalCountHeader(totalCount) ctx.SetTotalCountHeader(totalCount)
return return
} }
for i := range comments { for i := range comments {
apiComments[i] = convert.ToComment(comments[i])
apiComments[i] = convert.ToComment(ctx, comments[i])
} }


ctx.SetTotalCountHeader(totalCount) ctx.SetTotalCountHeader(totalCount)
return return
} }


ctx.JSON(http.StatusCreated, convert.ToComment(comment))
ctx.JSON(http.StatusCreated, convert.ToComment(ctx, comment))
} }


// GetIssueComment Get a comment by ID // GetIssueComment Get a comment by ID
return return
} }


ctx.JSON(http.StatusOK, convert.ToComment(comment))
ctx.JSON(http.StatusOK, convert.ToComment(ctx, comment))
} }


// EditIssueComment modify a comment of an issue // EditIssueComment modify a comment of an issue
return return
} }


ctx.JSON(http.StatusOK, convert.ToComment(comment))
ctx.JSON(http.StatusOK, convert.ToComment(ctx, comment))
} }


// DeleteIssueComment delete a comment from an issue // DeleteIssueComment delete a comment from an issue

+ 6
- 6
routers/api/v1/repo/issue_reaction.go Wyświetl plik

var result []api.Reaction var result []api.Reaction
for _, r := range reactions { for _, r := range reactions {
result = append(result, api.Reaction{ result = append(result, api.Reaction{
User: convert.ToUser(r.User, ctx.Doer),
User: convert.ToUser(ctx, r.User, ctx.Doer),
Reaction: r.Type, Reaction: r.Type,
Created: r.CreatedUnix.AsTime(), Created: r.CreatedUnix.AsTime(),
}) })
ctx.Error(http.StatusForbidden, err.Error(), err) ctx.Error(http.StatusForbidden, err.Error(), err)
} else if issues_model.IsErrReactionAlreadyExist(err) { } else if issues_model.IsErrReactionAlreadyExist(err) {
ctx.JSON(http.StatusOK, api.Reaction{ ctx.JSON(http.StatusOK, api.Reaction{
User: convert.ToUser(ctx.Doer, ctx.Doer),
User: convert.ToUser(ctx, ctx.Doer, ctx.Doer),
Reaction: reaction.Type, Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(), Created: reaction.CreatedUnix.AsTime(),
}) })
} }


ctx.JSON(http.StatusCreated, api.Reaction{ ctx.JSON(http.StatusCreated, api.Reaction{
User: convert.ToUser(ctx.Doer, ctx.Doer),
User: convert.ToUser(ctx, ctx.Doer, ctx.Doer),
Reaction: reaction.Type, Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(), Created: reaction.CreatedUnix.AsTime(),
}) })
var result []api.Reaction var result []api.Reaction
for _, r := range reactions { for _, r := range reactions {
result = append(result, api.Reaction{ result = append(result, api.Reaction{
User: convert.ToUser(r.User, ctx.Doer),
User: convert.ToUser(ctx, r.User, ctx.Doer),
Reaction: r.Type, Reaction: r.Type,
Created: r.CreatedUnix.AsTime(), Created: r.CreatedUnix.AsTime(),
}) })
ctx.Error(http.StatusForbidden, err.Error(), err) ctx.Error(http.StatusForbidden, err.Error(), err)
} else if issues_model.IsErrReactionAlreadyExist(err) { } else if issues_model.IsErrReactionAlreadyExist(err) {
ctx.JSON(http.StatusOK, api.Reaction{ ctx.JSON(http.StatusOK, api.Reaction{
User: convert.ToUser(ctx.Doer, ctx.Doer),
User: convert.ToUser(ctx, ctx.Doer, ctx.Doer),
Reaction: reaction.Type, Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(), Created: reaction.CreatedUnix.AsTime(),
}) })
} }


ctx.JSON(http.StatusCreated, api.Reaction{ ctx.JSON(http.StatusCreated, api.Reaction{
User: convert.ToUser(ctx.Doer, ctx.Doer),
User: convert.ToUser(ctx, ctx.Doer, ctx.Doer),
Reaction: reaction.Type, Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(), Created: reaction.CreatedUnix.AsTime(),
}) })

+ 1
- 1
routers/api/v1/repo/issue_subscription.go Wyświetl plik

} }
apiUsers := make([]*api.User, 0, len(users)) apiUsers := make([]*api.User, 0, len(users))
for _, v := range users { for _, v := range users {
apiUsers = append(apiUsers, convert.ToUser(v, ctx.Doer))
apiUsers = append(apiUsers, convert.ToUser(ctx, v, ctx.Doer))
} }


count, err := issues_model.CountIssueWatchers(ctx, issue.ID) count, err := issues_model.CountIssueWatchers(ctx, issue.ID)

+ 1
- 1
routers/api/v1/repo/notes.go Wyświetl plik

return return
} }


cmt, err := convert.ToCommit(ctx.Repo.Repository, ctx.Repo.GitRepo, note.Commit, nil, true)
cmt, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, note.Commit, nil, true)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "ToCommit", err) ctx.Error(http.StatusInternalServerError, "ToCommit", err)
return return

+ 1
- 1
routers/api/v1/repo/pull.go Wyświetl plik



apiCommits := make([]*api.Commit, 0, end-start) apiCommits := make([]*api.Commit, 0, end-start)
for i := start; i < end; i++ { for i := start; i < end; i++ {
apiCommit, err := convert.ToCommit(ctx.Repo.Repository, baseGitRepo, commits[i], userCache, true)
apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, baseGitRepo, commits[i], userCache, true)
if err != nil { if err != nil {
ctx.ServerError("toCommit", err) ctx.ServerError("toCommit", err)
return return

+ 1
- 1
routers/api/v1/repo/pull_review.go Wyświetl plik

for _, r := range opts.Reviewers { for _, r := range opts.Reviewers {
var reviewer *user_model.User var reviewer *user_model.User
if strings.Contains(r, "@") { if strings.Contains(r, "@") {
reviewer, err = user_model.GetUserByEmail(r)
reviewer, err = user_model.GetUserByEmail(ctx, r)
} else { } else {
reviewer, err = user_model.GetUserByName(ctx, r) reviewer, err = user_model.GetUserByName(ctx, r)
} }

+ 5
- 5
routers/api/v1/repo/release.go Wyświetl plik

ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return return
} }
ctx.JSON(http.StatusOK, convert.ToRelease(release))
ctx.JSON(http.StatusOK, convert.ToRelease(ctx, release))
} }


// GetLatestRelease gets the most recent non-prerelease, non-draft release of a repository, sorted by created_at // GetLatestRelease gets the most recent non-prerelease, non-draft release of a repository, sorted by created_at
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return return
} }
ctx.JSON(http.StatusOK, convert.ToRelease(release))
ctx.JSON(http.StatusOK, convert.ToRelease(ctx, release))
} }


// ListReleases list a repository's releases // ListReleases list a repository's releases
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return return
} }
rels[i] = convert.ToRelease(release)
rels[i] = convert.ToRelease(ctx, release)
} }


filteredCount, err := repo_model.CountReleasesByRepoID(ctx.Repo.Repository.ID, opts) filteredCount, err := repo_model.CountReleasesByRepoID(ctx.Repo.Repository.ID, opts)
return return
} }
} }
ctx.JSON(http.StatusCreated, convert.ToRelease(rel))
ctx.JSON(http.StatusCreated, convert.ToRelease(ctx, rel))
} }


// EditRelease edit a release // EditRelease edit a release
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return return
} }
ctx.JSON(http.StatusOK, convert.ToRelease(rel))
ctx.JSON(http.StatusOK, convert.ToRelease(ctx, rel))
} }


// DeleteRelease delete a release from a repository // DeleteRelease delete a release from a repository

+ 1
- 1
routers/api/v1/repo/release_attachment.go Wyświetl plik

ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return return
} }
ctx.JSON(http.StatusOK, convert.ToRelease(release).Attachments)
ctx.JSON(http.StatusOK, convert.ToRelease(ctx, release).Attachments)
} }


// CreateReleaseAttachment creates an attachment and saves the given file // CreateReleaseAttachment creates an attachment and saves the given file

+ 1
- 1
routers/api/v1/repo/release_tags.go Wyświetl plik

ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return return
} }
ctx.JSON(http.StatusOK, convert.ToRelease(release))
ctx.JSON(http.StatusOK, convert.ToRelease(ctx, release))
} }


// DeleteReleaseByTag delete a release from a repository by tag name // DeleteReleaseByTag delete a release from a repository by tag name

+ 1
- 1
routers/api/v1/repo/star.go Wyświetl plik

} }
users := make([]*api.User, len(stargazers)) users := make([]*api.User, len(stargazers))
for i, stargazer := range stargazers { for i, stargazer := range stargazers {
users[i] = convert.ToUser(stargazer, ctx.Doer)
users[i] = convert.ToUser(ctx, stargazer, ctx.Doer)
} }


ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumStars)) ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumStars))

+ 1
- 1
routers/api/v1/repo/subscriber.go Wyświetl plik

} }
users := make([]*api.User, len(subscribers)) users := make([]*api.User, len(subscribers))
for i, subscriber := range subscribers { for i, subscriber := range subscribers {
users[i] = convert.ToUser(subscriber, ctx.Doer)
users[i] = convert.ToUser(ctx, subscriber, ctx.Doer)
} }


ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumWatches)) ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumWatches))

+ 1
- 1
routers/api/v1/repo/tag.go Wyświetl plik

if err != nil { if err != nil {
ctx.Error(http.StatusBadRequest, "GetAnnotatedTag", err) ctx.Error(http.StatusBadRequest, "GetAnnotatedTag", err)
} }
ctx.JSON(http.StatusOK, convert.ToAnnotatedTag(ctx.Repo.Repository, tag, commit))
ctx.JSON(http.StatusOK, convert.ToAnnotatedTag(ctx, ctx.Repo.Repository, tag, commit))
} }
} }



+ 2
- 2
routers/api/v1/repo/teams.go Wyświetl plik

return return
} }


apiTeams, err := convert.ToTeams(teams, false)
apiTeams, err := convert.ToTeams(ctx, teams, false)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
} }


if models.HasRepository(team, ctx.Repo.Repository.ID) { if models.HasRepository(team, ctx.Repo.Repository.ID) {
apiTeam, err := convert.ToTeam(team)
apiTeam, err := convert.ToTeam(ctx, team)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return

+ 1
- 1
routers/api/v1/repo/transfer.go Wyświetl plik

return return
} }


org := convert.ToOrganization(organization.OrgFromUser(newOwner))
org := convert.ToOrganization(ctx, organization.OrgFromUser(newOwner))
for _, tID := range *opts.TeamIDs { for _, tID := range *opts.TeamIDs {
team, err := organization.GetTeamByID(ctx, tID) team, err := organization.GetTeamByID(ctx, tID)
if err != nil { if err != nil {

+ 1
- 1
routers/api/v1/user/follower.go Wyświetl plik

func responseAPIUsers(ctx *context.APIContext, users []*user_model.User) { func responseAPIUsers(ctx *context.APIContext, users []*user_model.User) {
apiUsers := make([]*api.User, len(users)) apiUsers := make([]*api.User, len(users))
for i := range users { for i := range users {
apiUsers[i] = convert.ToUser(users[i], ctx.Doer)
apiUsers[i] = convert.ToUser(ctx, users[i], ctx.Doer)
} }
ctx.JSON(http.StatusOK, &apiUsers) ctx.JSON(http.StatusOK, &apiUsers)
} }

+ 7
- 6
routers/api/v1/user/key.go Wyświetl plik

package user package user


import ( import (
std_ctx "context"
"net/http" "net/http"


asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
) )


// appendPrivateInformation appends the owner and key type information to api.PublicKey // appendPrivateInformation appends the owner and key type information to api.PublicKey
func appendPrivateInformation(apiKey *api.PublicKey, key *asymkey_model.PublicKey, defaultUser *user_model.User) (*api.PublicKey, error) {
func appendPrivateInformation(ctx std_ctx.Context, apiKey *api.PublicKey, key *asymkey_model.PublicKey, defaultUser *user_model.User) (*api.PublicKey, error) {
if key.Type == asymkey_model.KeyTypeDeploy { if key.Type == asymkey_model.KeyTypeDeploy {
apiKey.KeyType = "deploy" apiKey.KeyType = "deploy"
} else if key.Type == asymkey_model.KeyTypeUser { } else if key.Type == asymkey_model.KeyTypeUser {
apiKey.KeyType = "user" apiKey.KeyType = "user"


if defaultUser.ID == key.OwnerID { if defaultUser.ID == key.OwnerID {
apiKey.Owner = convert.ToUser(defaultUser, defaultUser)
apiKey.Owner = convert.ToUser(ctx, defaultUser, defaultUser)
} else { } else {
user, err := user_model.GetUserByID(db.DefaultContext, key.OwnerID) user, err := user_model.GetUserByID(db.DefaultContext, key.OwnerID)
if err != nil { if err != nil {
return apiKey, err return apiKey, err
} }
apiKey.Owner = convert.ToUser(user, user)
apiKey.Owner = convert.ToUser(ctx, user, user)
} }
} else { } else {
apiKey.KeyType = "unknown" apiKey.KeyType = "unknown"
for i := range keys { for i := range keys {
apiKeys[i] = convert.ToPublicKey(apiLink, keys[i]) apiKeys[i] = convert.ToPublicKey(apiLink, keys[i])
if ctx.Doer.IsAdmin || ctx.Doer.ID == keys[i].OwnerID { if ctx.Doer.IsAdmin || ctx.Doer.ID == keys[i].OwnerID {
apiKeys[i], _ = appendPrivateInformation(apiKeys[i], keys[i], user)
apiKeys[i], _ = appendPrivateInformation(ctx, apiKeys[i], keys[i], user)
} }
} }


apiLink := composePublicKeysAPILink() apiLink := composePublicKeysAPILink()
apiKey := convert.ToPublicKey(apiLink, key) apiKey := convert.ToPublicKey(apiLink, key)
if ctx.Doer.IsAdmin || ctx.Doer.ID == key.OwnerID { if ctx.Doer.IsAdmin || ctx.Doer.ID == key.OwnerID {
apiKey, _ = appendPrivateInformation(apiKey, key, ctx.Doer)
apiKey, _ = appendPrivateInformation(ctx, apiKey, key, ctx.Doer)
} }
ctx.JSON(http.StatusOK, apiKey) ctx.JSON(http.StatusOK, apiKey)
} }
apiLink := composePublicKeysAPILink() apiLink := composePublicKeysAPILink()
apiKey := convert.ToPublicKey(apiLink, key) apiKey := convert.ToPublicKey(apiLink, key)
if ctx.Doer.IsAdmin || ctx.Doer.ID == key.OwnerID { if ctx.Doer.IsAdmin || ctx.Doer.ID == key.OwnerID {
apiKey, _ = appendPrivateInformation(apiKey, key, ctx.Doer)
apiKey, _ = appendPrivateInformation(ctx, apiKey, key, ctx.Doer)
} }
ctx.JSON(http.StatusCreated, apiKey) ctx.JSON(http.StatusCreated, apiKey)
} }

+ 3
- 3
routers/api/v1/user/user.go Wyświetl plik



ctx.JSON(http.StatusOK, map[string]interface{}{ ctx.JSON(http.StatusOK, map[string]interface{}{
"ok": true, "ok": true,
"data": convert.ToUsers(ctx.Doer, users),
"data": convert.ToUsers(ctx, ctx.Doer, users),
}) })
} }


ctx.NotFound("GetUserByName", user_model.ErrUserNotExist{Name: ctx.Params(":username")}) ctx.NotFound("GetUserByName", user_model.ErrUserNotExist{Name: ctx.Params(":username")})
return return
} }
ctx.JSON(http.StatusOK, convert.ToUser(ctx.ContextUser, ctx.Doer))
ctx.JSON(http.StatusOK, convert.ToUser(ctx, ctx.ContextUser, ctx.Doer))
} }


// GetAuthenticatedUser get current user's information // GetAuthenticatedUser get current user's information
// "200": // "200":
// "$ref": "#/responses/User" // "$ref": "#/responses/User"


ctx.JSON(http.StatusOK, convert.ToUser(ctx.Doer, ctx.Doer))
ctx.JSON(http.StatusOK, convert.ToUser(ctx, ctx.Doer, ctx.Doer))
} }


// GetUserHeatmapData is the handler to get a users heatmap // GetUserHeatmapData is the handler to get a users heatmap

+ 2
- 1
routers/common/middleware.go Wyświetl plik

"net/http" "net/http"
"strings" "strings"


"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/process"


ctx, _, finished := process.GetManager().AddTypedContext(req.Context(), fmt.Sprintf("%s: %s", req.Method, req.RequestURI), process.RequestProcessType, true) ctx, _, finished := process.GetManager().AddTypedContext(req.Context(), fmt.Sprintf("%s: %s", req.Method, req.RequestURI), process.RequestProcessType, true)
defer finished() defer finished()
next.ServeHTTP(context.NewResponse(resp), req.WithContext(ctx))
next.ServeHTTP(context.NewResponse(resp), req.WithContext(cache.WithCacheContext(ctx)))
}) })
}, },
} }

+ 2
- 2
routers/install/install.go Wyświetl plik



cfg.Section("server").Key("OFFLINE_MODE").SetValue(fmt.Sprint(form.OfflineMode)) cfg.Section("server").Key("OFFLINE_MODE").SetValue(fmt.Sprint(form.OfflineMode))
// if you are reinstalling, this maybe not right because of missing version // if you are reinstalling, this maybe not right because of missing version
if err := system_model.SetSettingNoVersion(system_model.KeyPictureDisableGravatar, strconv.FormatBool(form.DisableGravatar)); err != nil {
if err := system_model.SetSettingNoVersion(ctx, system_model.KeyPictureDisableGravatar, strconv.FormatBool(form.DisableGravatar)); err != nil {
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form) ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
return return
} }
if err := system_model.SetSettingNoVersion(system_model.KeyPictureEnableFederatedAvatar, strconv.FormatBool(form.EnableFederatedAvatar)); err != nil {
if err := system_model.SetSettingNoVersion(ctx, system_model.KeyPictureEnableFederatedAvatar, strconv.FormatBool(form.EnableFederatedAvatar)); err != nil {
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form) ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
return return
} }

+ 1
- 1
routers/private/hook_verification.go Wyświetl plik

if err != nil { if err != nil {
return err return err
} }
verification := asymkey_model.ParseCommitWithSignature(commit)
verification := asymkey_model.ParseCommitWithSignature(ctx, commit)
if !verification.Verified { if !verification.Verified {
cancel() cancel()
return &errUnverifiedCommit{ return &errUnverifiedCommit{

+ 1
- 1
routers/web/admin/config.go Wyświetl plik

} }
} }


if err := system_model.SetSetting(&system_model.Setting{
if err := system_model.SetSetting(ctx, &system_model.Setting{
SettingKey: key, SettingKey: key,
SettingValue: value, SettingValue: value,
Version: version, Version: version,

+ 1
- 1
routers/web/auth/linkaccount.go Wyświetl plik

ctx.Data["email"] = email ctx.Data["email"] = email


if len(email) != 0 { if len(email) != 0 {
u, err := user_model.GetUserByEmail(email)
u, err := user_model.GetUserByEmail(ctx, email)
if err != nil && !user_model.IsErrUserNotExist(err) { if err != nil && !user_model.IsErrUserNotExist(err) {
ctx.ServerError("UserSignIn", err) ctx.ServerError("UserSignIn", err)
return return

+ 2
- 2
routers/web/auth/oauth.go Wyświetl plik

idToken.Name = user.GetDisplayName() idToken.Name = user.GetDisplayName()
idToken.PreferredUsername = user.Name idToken.PreferredUsername = user.Name
idToken.Profile = user.HTMLURL() idToken.Profile = user.HTMLURL()
idToken.Picture = user.AvatarLink()
idToken.Picture = user.AvatarLink(ctx)
idToken.Website = user.Website idToken.Website = user.Website
idToken.Locale = user.Language idToken.Locale = user.Language
idToken.UpdatedAt = user.UpdatedUnix idToken.UpdatedAt = user.UpdatedUnix
Name: ctx.Doer.FullName, Name: ctx.Doer.FullName,
Username: ctx.Doer.Name, Username: ctx.Doer.Name,
Email: ctx.Doer.Email, Email: ctx.Doer.Email,
Picture: ctx.Doer.AvatarLink(),
Picture: ctx.Doer.AvatarLink(ctx),
} }


groups, err := getOAuthGroupsForUser(ctx.Doer) groups, err := getOAuthGroupsForUser(ctx.Doer)

+ 2
- 2
routers/web/auth/oauth_test.go Wyświetl plik

assert.Equal(t, user.Name, oidcToken.Name) assert.Equal(t, user.Name, oidcToken.Name)
assert.Equal(t, user.Name, oidcToken.PreferredUsername) assert.Equal(t, user.Name, oidcToken.PreferredUsername)
assert.Equal(t, user.HTMLURL(), oidcToken.Profile) assert.Equal(t, user.HTMLURL(), oidcToken.Profile)
assert.Equal(t, user.AvatarLink(), oidcToken.Picture)
assert.Equal(t, user.AvatarLink(db.DefaultContext), oidcToken.Picture)
assert.Equal(t, user.Website, oidcToken.Website) assert.Equal(t, user.Website, oidcToken.Website)
assert.Equal(t, user.UpdatedUnix, oidcToken.UpdatedAt) assert.Equal(t, user.UpdatedUnix, oidcToken.UpdatedAt)
assert.Equal(t, user.Email, oidcToken.Email) assert.Equal(t, user.Email, oidcToken.Email)
assert.Equal(t, user.FullName, oidcToken.Name) assert.Equal(t, user.FullName, oidcToken.Name)
assert.Equal(t, user.Name, oidcToken.PreferredUsername) assert.Equal(t, user.Name, oidcToken.PreferredUsername)
assert.Equal(t, user.HTMLURL(), oidcToken.Profile) assert.Equal(t, user.HTMLURL(), oidcToken.Profile)
assert.Equal(t, user.AvatarLink(), oidcToken.Picture)
assert.Equal(t, user.AvatarLink(db.DefaultContext), oidcToken.Picture)
assert.Equal(t, user.Website, oidcToken.Website) assert.Equal(t, user.Website, oidcToken.Website)
assert.Equal(t, user.UpdatedUnix, oidcToken.UpdatedAt) assert.Equal(t, user.UpdatedUnix, oidcToken.UpdatedAt)
assert.Equal(t, user.Email, oidcToken.Email) assert.Equal(t, user.Email, oidcToken.Email)

+ 1
- 1
routers/web/auth/openid.go Wyświetl plik

log.Trace("User has email=%s and nickname=%s", email, nickname) log.Trace("User has email=%s and nickname=%s", email, nickname)


if email != "" { if email != "" {
u, err = user_model.GetUserByEmail(email)
u, err = user_model.GetUserByEmail(ctx, email)
if err != nil { if err != nil {
if !user_model.IsErrUserNotExist(err) { if !user_model.IsErrUserNotExist(err) {
ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{ ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{

+ 1
- 1
routers/web/auth/password.go Wyświetl plik

email := ctx.FormString("email") email := ctx.FormString("email")
ctx.Data["Email"] = email ctx.Data["Email"] = email


u, err := user_model.GetUserByEmail(email)
u, err := user_model.GetUserByEmail(ctx, email)
if err != nil { if err != nil {
if user_model.IsErrUserNotExist(err) { if user_model.IsErrUserNotExist(err) {
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale) ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale)

+ 1
- 1
routers/web/org/teams.go Wyświetl plik

return return
} }


apiTeams, err := convert.ToTeams(teams, false)
apiTeams, err := convert.ToTeams(ctx, teams, false)
if err != nil { if err != nil {
log.Error("convert ToTeams failed: %v", err) log.Error("convert ToTeams failed: %v", err)
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ ctx.JSON(http.StatusInternalServerError, map[string]interface{}{

+ 3
- 3
routers/web/repo/blame.go Wyświetl plik

} }


// populate commit email addresses to later look up avatars. // populate commit email addresses to later look up avatars.
for _, c := range user_model.ValidateCommitsWithEmails(commits) {
for _, c := range user_model.ValidateCommitsWithEmails(ctx, commits) {
commitNames[c.ID.String()] = c commitNames[c.ID.String()] = c
} }




var avatar string var avatar string
if commit.User != nil { if commit.User != nil {
avatar = string(templates.Avatar(commit.User, 18, "gt-mr-3"))
avatar = string(templates.Avatar(ctx, commit.User, 18, "gt-mr-3"))
} else { } else {
avatar = string(templates.AvatarByEmail(commit.Author.Email, commit.Author.Name, 18, "gt-mr-3"))
avatar = string(templates.AvatarByEmail(ctx, commit.Author.Email, commit.Author.Name, 18, "gt-mr-3"))
} }


br.Avatar = gotemplate.HTML(avatar) br.Avatar = gotemplate.HTML(avatar)

+ 4
- 4
routers/web/repo/commit.go Wyświetl plik

return return
} }


if err := graph.LoadAndProcessCommits(ctx.Repo.Repository, ctx.Repo.GitRepo); err != nil {
if err := graph.LoadAndProcessCommits(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo); err != nil {
ctx.ServerError("LoadAndProcessCommits", err) ctx.ServerError("LoadAndProcessCommits", err)
return return
} }
ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses) ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses)
ctx.Data["CommitStatuses"] = statuses ctx.Data["CommitStatuses"] = statuses


verification := asymkey_model.ParseCommitWithSignature(commit)
verification := asymkey_model.ParseCommitWithSignature(ctx, commit)
ctx.Data["Verification"] = verification ctx.Data["Verification"] = verification
ctx.Data["Author"] = user_model.ValidateCommitWithEmail(commit)
ctx.Data["Author"] = user_model.ValidateCommitWithEmail(ctx, commit)
ctx.Data["Parents"] = parents ctx.Data["Parents"] = parents
ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0 ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0


if err == nil { if err == nil {
ctx.Data["Note"] = string(charset.ToUTF8WithFallback(note.Message)) ctx.Data["Note"] = string(charset.ToUTF8WithFallback(note.Message))
ctx.Data["NoteCommit"] = note.Commit ctx.Data["NoteCommit"] = note.Commit
ctx.Data["NoteAuthor"] = user_model.ValidateCommitWithEmail(note.Commit)
ctx.Data["NoteAuthor"] = user_model.ValidateCommitWithEmail(ctx, note.Commit)
} }


ctx.Data["BranchName"], err = commit.GetBranchName() ctx.Data["BranchName"], err = commit.GetBranchName()

+ 1
- 1
routers/web/repo/issue.go Wyświetl plik



ctx.Data["MentionableTeams"] = teams ctx.Data["MentionableTeams"] = teams
ctx.Data["MentionableTeamsOrg"] = ctx.Repo.Owner.Name ctx.Data["MentionableTeamsOrg"] = ctx.Repo.Owner.Name
ctx.Data["MentionableTeamsOrgAvatar"] = ctx.Repo.Owner.AvatarLink()
ctx.Data["MentionableTeamsOrgAvatar"] = ctx.Repo.Owner.AvatarLink(ctx)
} }

+ 2
- 2
routers/web/repo/view.go Wyświetl plik

ctx.Data["LatestCommit"] = latestCommit ctx.Data["LatestCommit"] = latestCommit
if latestCommit != nil { if latestCommit != nil {


verification := asymkey_model.ParseCommitWithSignature(latestCommit)
verification := asymkey_model.ParseCommitWithSignature(ctx, latestCommit)


if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) { if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) {
return repo_model.IsOwnerMemberCollaborator(ctx.Repo.Repository, user.ID) return repo_model.IsOwnerMemberCollaborator(ctx.Repo.Repository, user.ID)
return nil return nil
} }
ctx.Data["LatestCommitVerification"] = verification ctx.Data["LatestCommitVerification"] = verification
ctx.Data["LatestCommitUser"] = user_model.ValidateCommitWithEmail(latestCommit)
ctx.Data["LatestCommitUser"] = user_model.ValidateCommitWithEmail(ctx, latestCommit)


statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, latestCommit.ID.String(), db.ListOptions{}) statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, latestCommit.ID.String(), db.ListOptions{})
if err != nil { if err != nil {

+ 1
- 1
routers/web/repo/webhook.go Wyświetl plik

} }
} }


apiUser := convert.ToUserWithAccessMode(ctx.Doer, perm.AccessModeNone)
apiUser := convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone)


apiCommit := &api.PayloadCommit{ apiCommit := &api.PayloadCommit{
ID: commit.ID.String(), ID: commit.ID.String(),

+ 2
- 2
routers/web/user/avatar.go Wyświetl plik

user = user_model.NewGhostUser() user = user_model.NewGhostUser()
} }


cacheableRedirect(ctx, user.AvatarLinkWithSize(size))
cacheableRedirect(ctx, user.AvatarLinkWithSize(ctx, size))
} }


// AvatarByEmailHash redirects the browser to the email avatar link // AvatarByEmailHash redirects the browser to the email avatar link
return return
} }
size := ctx.FormInt("size") size := ctx.FormInt("size")
cacheableRedirect(ctx, avatars.GenerateEmailAvatarFinalLink(email, size))
cacheableRedirect(ctx, avatars.GenerateEmailAvatarFinalLink(ctx, email, size))
} }

+ 1
- 1
routers/web/user/search.go Wyświetl plik



ctx.JSON(http.StatusOK, map[string]interface{}{ ctx.JSON(http.StatusOK, map[string]interface{}{
"ok": true, "ok": true,
"data": convert.ToUsers(ctx.Doer, users),
"data": convert.ToUsers(ctx, ctx.Doer, users),
}) })
} }

+ 2
- 2
routers/web/webfinger.go Wyświetl plik



u, err = user_model.GetUserByName(ctx, parts[0]) u, err = user_model.GetUserByName(ctx, parts[0])
case "mailto": case "mailto":
u, err = user_model.GetUserByEmailContext(ctx, resource.Opaque)
u, err = user_model.GetUserByEmail(ctx, resource.Opaque)
if u != nil && u.KeepEmailPrivate { if u != nil && u.KeepEmailPrivate {
err = user_model.ErrUserNotExist{} err = user_model.ErrUserNotExist{}
} }
}, },
{ {
Rel: "http://webfinger.net/rel/avatar", Rel: "http://webfinger.net/rel/avatar",
Href: u.AvatarLink(),
Href: u.AvatarLink(ctx),
}, },
{ {
Rel: "self", Rel: "self",

+ 23
- 23
services/actions/notifier.go Wyświetl plik

Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(issue.Poster, nil),
Sender: convert.ToUser(ctx, issue.Poster, nil),
}).Notify(withMethod(ctx, "NotifyNewIssue")) }).Notify(withMethod(ctx, "NotifyNewIssue"))
} }


Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(db.DefaultContext, issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(db.DefaultContext, issue.PullRequest, nil),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
CommitID: commitID, CommitID: commitID,
} }
if isClosed { if isClosed {
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
} }
if isClosed { if isClosed {
apiIssue.Action = api.HookIssueClosed apiIssue.Action = api.HookIssueClosed
Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(ctx, issue.Repo, perm_model.AccessModeNone), Repository: convert.ToRepo(ctx, issue.Repo, perm_model.AccessModeNone),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}). }).
Notify(ctx) Notify(ctx)
return return
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}). }).
Notify(ctx) Notify(ctx)
} }
WithPayload(&api.IssueCommentPayload{ WithPayload(&api.IssueCommentPayload{
Action: api.HookIssueCommentCreated, Action: api.HookIssueCommentCreated,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Comment: convert.ToComment(comment),
Comment: convert.ToComment(ctx, comment),
Repository: convert.ToRepo(ctx, repo, mode), Repository: convert.ToRepo(ctx, repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
IsPull: true, IsPull: true,
}). }).
Notify(ctx) Notify(ctx)
WithPayload(&api.IssueCommentPayload{ WithPayload(&api.IssueCommentPayload{
Action: api.HookIssueCommentCreated, Action: api.HookIssueCommentCreated,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Comment: convert.ToComment(comment),
Comment: convert.ToComment(ctx, comment),
Repository: convert.ToRepo(ctx, repo, mode), Repository: convert.ToRepo(ctx, repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
IsPull: false, IsPull: false,
}). }).
Notify(ctx) Notify(ctx)
Index: pull.Issue.Index, Index: pull.Issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, pull, nil), PullRequest: convert.ToAPIPullRequest(ctx, pull, nil),
Repository: convert.ToRepo(ctx, pull.Issue.Repo, mode), Repository: convert.ToRepo(ctx, pull.Issue.Repo, mode),
Sender: convert.ToUser(pull.Issue.Poster, nil),
Sender: convert.ToUser(ctx, pull.Issue.Poster, nil),
}). }).
WithPullRequest(pull). WithPullRequest(pull).
Notify(ctx) Notify(ctx)
newNotifyInput(repo, doer, webhook_module.HookEventRepository).WithPayload(&api.RepositoryPayload{ newNotifyInput(repo, doer, webhook_module.HookEventRepository).WithPayload(&api.RepositoryPayload{
Action: api.HookRepoCreated, Action: api.HookRepoCreated,
Repository: convert.ToRepo(ctx, repo, perm_model.AccessModeOwner), Repository: convert.ToRepo(ctx, repo, perm_model.AccessModeOwner),
Organization: convert.ToUser(u, nil),
Sender: convert.ToUser(doer, nil),
Organization: convert.ToUser(ctx, u, nil),
Sender: convert.ToUser(ctx, doer, nil),
}).Notify(ctx) }).Notify(ctx)
} }


newNotifyInput(oldRepo, doer, webhook_module.HookEventFork).WithPayload(&api.ForkPayload{ newNotifyInput(oldRepo, doer, webhook_module.HookEventFork).WithPayload(&api.ForkPayload{
Forkee: convert.ToRepo(ctx, oldRepo, oldMode), Forkee: convert.ToRepo(ctx, oldRepo, oldMode),
Repo: convert.ToRepo(ctx, repo, mode), Repo: convert.ToRepo(ctx, repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}).Notify(ctx) }).Notify(ctx)


u := repo.MustOwner(ctx) u := repo.MustOwner(ctx)
WithPayload(&api.RepositoryPayload{ WithPayload(&api.RepositoryPayload{
Action: api.HookRepoCreated, Action: api.HookRepoCreated,
Repository: convert.ToRepo(ctx, repo, perm_model.AccessModeOwner), Repository: convert.ToRepo(ctx, repo, perm_model.AccessModeOwner),
Organization: convert.ToUser(u, nil),
Sender: convert.ToUser(doer, nil),
Organization: convert.ToUser(ctx, u, nil),
Sender: convert.ToUser(ctx, doer, nil),
}).Notify(ctx) }).Notify(ctx)
} }
} }
Index: review.Issue.Index, Index: review.Issue.Index,
PullRequest: convert.ToAPIPullRequest(db.DefaultContext, pr, nil), PullRequest: convert.ToAPIPullRequest(db.DefaultContext, pr, nil),
Repository: convert.ToRepo(ctx, review.Issue.Repo, mode), Repository: convert.ToRepo(ctx, review.Issue.Repo, mode),
Sender: convert.ToUser(review.Reviewer, nil),
Sender: convert.ToUser(ctx, review.Reviewer, nil),
Review: &api.ReviewPayload{ Review: &api.ReviewPayload{
Type: string(reviewHookType), Type: string(reviewHookType),
Content: review.Content, Content: review.Content,
Index: pr.Issue.Index, Index: pr.Issue.Index,
PullRequest: convert.ToAPIPullRequest(db.DefaultContext, pr, nil), PullRequest: convert.ToAPIPullRequest(db.DefaultContext, pr, nil),
Repository: convert.ToRepo(ctx, pr.Issue.Repo, mode), Repository: convert.ToRepo(ctx, pr.Issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
Action: api.HookIssueClosed, Action: api.HookIssueClosed,
} }


func (n *actionsNotifier) NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { func (n *actionsNotifier) NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
ctx = withMethod(ctx, "NotifyPushCommits") ctx = withMethod(ctx, "NotifyPushCommits")


apiPusher := convert.ToUser(pusher, nil)
apiPusher := convert.ToUser(ctx, pusher, nil)
apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL()) apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL())
if err != nil { if err != nil {
log.Error("commits.ToAPIPayloadCommits failed: %v", err) log.Error("commits.ToAPIPayloadCommits failed: %v", err)
func (n *actionsNotifier) NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { func (n *actionsNotifier) NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
ctx = withMethod(ctx, "NotifyCreateRef") ctx = withMethod(ctx, "NotifyCreateRef")


apiPusher := convert.ToUser(pusher, nil)
apiPusher := convert.ToUser(ctx, pusher, nil)
apiRepo := convert.ToRepo(ctx, repo, perm_model.AccessModeNone) apiRepo := convert.ToRepo(ctx, repo, perm_model.AccessModeNone)
refName := git.RefEndName(refFullName) refName := git.RefEndName(refFullName)


func (n *actionsNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { func (n *actionsNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) {
ctx = withMethod(ctx, "NotifyDeleteRef") ctx = withMethod(ctx, "NotifyDeleteRef")


apiPusher := convert.ToUser(pusher, nil)
apiPusher := convert.ToUser(ctx, pusher, nil)
apiRepo := convert.ToRepo(ctx, repo, perm_model.AccessModeNone) apiRepo := convert.ToRepo(ctx, repo, perm_model.AccessModeNone)
refName := git.RefEndName(refFullName) refName := git.RefEndName(refFullName)


func (n *actionsNotifier) NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { func (n *actionsNotifier) NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
ctx = withMethod(ctx, "NotifySyncPushCommits") ctx = withMethod(ctx, "NotifySyncPushCommits")


apiPusher := convert.ToUser(pusher, nil)
apiPusher := convert.ToUser(ctx, pusher, nil)
apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(db.DefaultContext, repo.RepoPath(), repo.HTMLURL()) apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(db.DefaultContext, repo.RepoPath(), repo.HTMLURL())
if err != nil { if err != nil {
log.Error("commits.ToAPIPayloadCommits failed: %v", err) log.Error("commits.ToAPIPayloadCommits failed: %v", err)
Index: pr.Issue.Index, Index: pr.Issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
Repository: convert.ToRepo(ctx, pr.Issue.Repo, perm_model.AccessModeNone), Repository: convert.ToRepo(ctx, pr.Issue.Repo, perm_model.AccessModeNone),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}). }).
WithPullRequest(pr). WithPullRequest(pr).
Notify(ctx) Notify(ctx)
}, },
PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
Repository: convert.ToRepo(ctx, pr.Issue.Repo, mode), Repository: convert.ToRepo(ctx, pr.Issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}). }).
WithPullRequest(pr). WithPullRequest(pr).
Notify(ctx) Notify(ctx)

+ 3
- 3
services/actions/notifier_helper.go Wyświetl plik

WithRef(ref). WithRef(ref).
WithPayload(&api.ReleasePayload{ WithPayload(&api.ReleasePayload{
Action: action, Action: action,
Release: convert.ToRelease(rel),
Release: convert.ToRelease(ctx, rel),
Repository: convert.ToRepo(ctx, rel.Repo, mode), Repository: convert.ToRepo(ctx, rel.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}). }).
Notify(ctx) Notify(ctx)
} }
WithPayload(&api.PackagePayload{ WithPayload(&api.PackagePayload{
Action: action, Action: action,
Package: apiPackage, Package: apiPackage,
Sender: convert.ToUser(sender, nil),
Sender: convert.ToUser(ctx, sender, nil),
}). }).
Notify(ctx) Notify(ctx)
} }

+ 6
- 6
services/asymkey/sign.go Wyświetl plik

if commit.Signature == nil { if commit.Signature == nil {
return false, "", nil, &ErrWontSign{parentSigned} return false, "", nil, &ErrWontSign{parentSigned}
} }
verification := asymkey_model.ParseCommitWithSignature(commit)
verification := asymkey_model.ParseCommitWithSignature(ctx, commit)
if !verification.Verified { if !verification.Verified {
return false, "", nil, &ErrWontSign{parentSigned} return false, "", nil, &ErrWontSign{parentSigned}
} }
if commit.Signature == nil { if commit.Signature == nil {
return false, "", nil, &ErrWontSign{parentSigned} return false, "", nil, &ErrWontSign{parentSigned}
} }
verification := asymkey_model.ParseCommitWithSignature(commit)
verification := asymkey_model.ParseCommitWithSignature(ctx, commit)
if !verification.Verified { if !verification.Verified {
return false, "", nil, &ErrWontSign{parentSigned} return false, "", nil, &ErrWontSign{parentSigned}
} }
if err != nil { if err != nil {
return false, "", nil, err return false, "", nil, err
} }
verification := asymkey_model.ParseCommitWithSignature(commit)
verification := asymkey_model.ParseCommitWithSignature(ctx, commit)
if !verification.Verified { if !verification.Verified {
return false, "", nil, &ErrWontSign{baseSigned} return false, "", nil, &ErrWontSign{baseSigned}
} }
if err != nil { if err != nil {
return false, "", nil, err return false, "", nil, err
} }
verification := asymkey_model.ParseCommitWithSignature(commit)
verification := asymkey_model.ParseCommitWithSignature(ctx, commit)
if !verification.Verified { if !verification.Verified {
return false, "", nil, &ErrWontSign{headSigned} return false, "", nil, &ErrWontSign{headSigned}
} }
if err != nil { if err != nil {
return false, "", nil, err return false, "", nil, err
} }
verification := asymkey_model.ParseCommitWithSignature(commit)
verification := asymkey_model.ParseCommitWithSignature(ctx, commit)
if !verification.Verified { if !verification.Verified {
return false, "", nil, &ErrWontSign{commitsSigned} return false, "", nil, &ErrWontSign{commitsSigned}
} }
return false, "", nil, err return false, "", nil, err
} }
for _, commit := range commitList { for _, commit := range commitList {
verification := asymkey_model.ParseCommitWithSignature(commit)
verification := asymkey_model.ParseCommitWithSignature(ctx, commit)
if !verification.Verified { if !verification.Verified {
return false, "", nil, &ErrWontSign{commitsSigned} return false, "", nil, &ErrWontSign{commitsSigned}
} }

+ 1
- 1
services/auth/reverseproxy.go Wyświetl plik

} }
log.Trace("ReverseProxy Authorization: Found email: %s", email) log.Trace("ReverseProxy Authorization: Found email: %s", email)


user, err := user_model.GetUserByEmail(email)
user, err := user_model.GetUserByEmail(req.Context(), email)
if err != nil { if err != nil {
// Do not allow auto-registration, we don't have a username here // Do not allow auto-registration, we don't have a username here
if !user_model.IsErrUserNotExist(err) { if !user_model.IsErrUserNotExist(err) {

+ 13
- 13
services/convert/convert.go Wyświetl plik

} }


// ToBranch convert a git.Commit and git.Branch to an api.Branch // ToBranch convert a git.Commit and git.Branch to an api.Branch
func ToBranch(repo *repo_model.Repository, b *git.Branch, c *git.Commit, bp *git_model.ProtectedBranch, user *user_model.User, isRepoAdmin bool) (*api.Branch, error) {
func ToBranch(ctx context.Context, repo *repo_model.Repository, b *git.Branch, c *git.Commit, bp *git_model.ProtectedBranch, user *user_model.User, isRepoAdmin bool) (*api.Branch, error) {
if bp == nil { if bp == nil {
var hasPerm bool var hasPerm bool
var canPush bool var canPush bool


return &api.Branch{ return &api.Branch{
Name: b.Name, Name: b.Name,
Commit: ToPayloadCommit(repo, c),
Commit: ToPayloadCommit(ctx, repo, c),
Protected: false, Protected: false,
RequiredApprovals: 0, RequiredApprovals: 0,
EnableStatusCheck: false, EnableStatusCheck: false,


branch := &api.Branch{ branch := &api.Branch{
Name: b.Name, Name: b.Name,
Commit: ToPayloadCommit(repo, c),
Commit: ToPayloadCommit(ctx, repo, c),
Protected: true, Protected: true,
RequiredApprovals: bp.RequiredApprovals, RequiredApprovals: bp.RequiredApprovals,
EnableStatusCheck: bp.EnableStatusCheck, EnableStatusCheck: bp.EnableStatusCheck,
} }


// ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification // ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification
func ToVerification(c *git.Commit) *api.PayloadCommitVerification {
verif := asymkey_model.ParseCommitWithSignature(c)
func ToVerification(ctx context.Context, c *git.Commit) *api.PayloadCommitVerification {
verif := asymkey_model.ParseCommitWithSignature(ctx, c)
commitVerification := &api.PayloadCommitVerification{ commitVerification := &api.PayloadCommitVerification{
Verified: verif.Verified, Verified: verif.Verified,
Reason: verif.Reason, Reason: verif.Reason,
} }


// ToOrganization convert user_model.User to api.Organization // ToOrganization convert user_model.User to api.Organization
func ToOrganization(org *organization.Organization) *api.Organization {
func ToOrganization(ctx context.Context, org *organization.Organization) *api.Organization {
return &api.Organization{ return &api.Organization{
ID: org.ID, ID: org.ID,
AvatarURL: org.AsUser().AvatarLink(),
AvatarURL: org.AsUser().AvatarLink(ctx),
Name: org.Name, Name: org.Name,
UserName: org.Name, UserName: org.Name,
FullName: org.FullName, FullName: org.FullName,
} }


// ToTeam convert models.Team to api.Team // ToTeam convert models.Team to api.Team
func ToTeam(team *organization.Team, loadOrg ...bool) (*api.Team, error) {
teams, err := ToTeams([]*organization.Team{team}, len(loadOrg) != 0 && loadOrg[0])
func ToTeam(ctx context.Context, team *organization.Team, loadOrg ...bool) (*api.Team, error) {
teams, err := ToTeams(ctx, []*organization.Team{team}, len(loadOrg) != 0 && loadOrg[0])
if err != nil || len(teams) == 0 { if err != nil || len(teams) == 0 {
return nil, err return nil, err
} }
} }


// ToTeams convert models.Team list to api.Team list // ToTeams convert models.Team list to api.Team list
func ToTeams(teams []*organization.Team, loadOrgs bool) ([]*api.Team, error) {
func ToTeams(ctx context.Context, teams []*organization.Team, loadOrgs bool) ([]*api.Team, error) {
if len(teams) == 0 || teams[0] == nil { if len(teams) == 0 || teams[0] == nil {
return nil, nil return nil, nil
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
apiOrg = ToOrganization(org)
apiOrg = ToOrganization(ctx, org)
cache[teams[i].OrgID] = apiOrg cache[teams[i].OrgID] = apiOrg
} }
apiTeams[i].Organization = apiOrg apiTeams[i].Organization = apiOrg
} }


// ToAnnotatedTag convert git.Tag to api.AnnotatedTag // ToAnnotatedTag convert git.Tag to api.AnnotatedTag
func ToAnnotatedTag(repo *repo_model.Repository, t *git.Tag, c *git.Commit) *api.AnnotatedTag {
func ToAnnotatedTag(ctx context.Context, repo *repo_model.Repository, t *git.Tag, c *git.Commit) *api.AnnotatedTag {
return &api.AnnotatedTag{ return &api.AnnotatedTag{
Tag: t.Name, Tag: t.Name,
SHA: t.ID.String(), SHA: t.ID.String(),
Message: t.Message, Message: t.Message,
URL: util.URLJoin(repo.APIURL(), "git/tags", t.ID.String()), URL: util.URLJoin(repo.APIURL(), "git/tags", t.ID.String()),
Tagger: ToCommitUser(t.Tagger), Tagger: ToCommitUser(t.Tagger),
Verification: ToVerification(c),
Verification: ToVerification(ctx, c),
} }
} }



+ 13
- 12
services/convert/git_commit.go Wyświetl plik

package convert package convert


import ( import (
"context"
"net/url" "net/url"
"time" "time"


} }


// ToPayloadCommit convert a git.Commit to api.PayloadCommit // ToPayloadCommit convert a git.Commit to api.PayloadCommit
func ToPayloadCommit(repo *repo_model.Repository, c *git.Commit) *api.PayloadCommit {
func ToPayloadCommit(ctx context.Context, repo *repo_model.Repository, c *git.Commit) *api.PayloadCommit {
authorUsername := "" authorUsername := ""
if author, err := user_model.GetUserByEmail(c.Author.Email); err == nil {
if author, err := user_model.GetUserByEmail(ctx, c.Author.Email); err == nil {
authorUsername = author.Name authorUsername = author.Name
} else if !user_model.IsErrUserNotExist(err) { } else if !user_model.IsErrUserNotExist(err) {
log.Error("GetUserByEmail: %v", err) log.Error("GetUserByEmail: %v", err)
} }


committerUsername := "" committerUsername := ""
if committer, err := user_model.GetUserByEmail(c.Committer.Email); err == nil {
if committer, err := user_model.GetUserByEmail(ctx, c.Committer.Email); err == nil {
committerUsername = committer.Name committerUsername = committer.Name
} else if !user_model.IsErrUserNotExist(err) { } else if !user_model.IsErrUserNotExist(err) {
log.Error("GetUserByEmail: %v", err) log.Error("GetUserByEmail: %v", err)
UserName: committerUsername, UserName: committerUsername,
}, },
Timestamp: c.Author.When, Timestamp: c.Author.When,
Verification: ToVerification(c),
Verification: ToVerification(ctx, c),
} }
} }


// ToCommit convert a git.Commit to api.Commit // ToCommit convert a git.Commit to api.Commit
func ToCommit(repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, userCache map[string]*user_model.User, stat bool) (*api.Commit, error) {
func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, userCache map[string]*user_model.User, stat bool) (*api.Commit, error) {
var apiAuthor, apiCommitter *api.User var apiAuthor, apiCommitter *api.User


// Retrieve author and committer information // Retrieve author and committer information
} }


if ok { if ok {
apiAuthor = ToUser(cacheAuthor, nil)
apiAuthor = ToUser(ctx, cacheAuthor, nil)
} else { } else {
author, err := user_model.GetUserByEmail(commit.Author.Email)
author, err := user_model.GetUserByEmail(ctx, commit.Author.Email)
if err != nil && !user_model.IsErrUserNotExist(err) { if err != nil && !user_model.IsErrUserNotExist(err) {
return nil, err return nil, err
} else if err == nil { } else if err == nil {
apiAuthor = ToUser(author, nil)
apiAuthor = ToUser(ctx, author, nil)
if userCache != nil { if userCache != nil {
userCache[commit.Author.Email] = author userCache[commit.Author.Email] = author
} }
} }


if ok { if ok {
apiCommitter = ToUser(cacheCommitter, nil)
apiCommitter = ToUser(ctx, cacheCommitter, nil)
} else { } else {
committer, err := user_model.GetUserByEmail(commit.Committer.Email)
committer, err := user_model.GetUserByEmail(ctx, commit.Committer.Email)
if err != nil && !user_model.IsErrUserNotExist(err) { if err != nil && !user_model.IsErrUserNotExist(err) {
return nil, err return nil, err
} else if err == nil { } else if err == nil {
apiCommitter = ToUser(committer, nil)
apiCommitter = ToUser(ctx, committer, nil)
if userCache != nil { if userCache != nil {
userCache[commit.Committer.Email] = committer userCache[commit.Committer.Email] = committer
} }
SHA: commit.ID.String(), SHA: commit.ID.String(),
Created: commit.Committer.When, Created: commit.Committer.When,
}, },
Verification: ToVerification(commit),
Verification: ToVerification(ctx, commit),
}, },
Author: apiAuthor, Author: apiAuthor,
Committer: apiCommitter, Committer: apiCommitter,

+ 3
- 3
services/convert/issue.go Wyświetl plik

URL: issue.APIURL(), URL: issue.APIURL(),
HTMLURL: issue.HTMLURL(), HTMLURL: issue.HTMLURL(),
Index: issue.Index, Index: issue.Index,
Poster: ToUser(issue.Poster, nil),
Poster: ToUser(ctx, issue.Poster, nil),
Title: issue.Title, Title: issue.Title,
Body: issue.Content, Body: issue.Content,
Attachments: ToAttachments(issue.Attachments), Attachments: ToAttachments(issue.Attachments),
} }
if len(issue.Assignees) > 0 { if len(issue.Assignees) > 0 {
for _, assignee := range issue.Assignees { for _, assignee := range issue.Assignees {
apiIssue.Assignees = append(apiIssue.Assignees, ToUser(assignee, nil))
apiIssue.Assignees = append(apiIssue.Assignees, ToUser(ctx, assignee, nil))
} }
apiIssue.Assignee = ToUser(issue.Assignees[0], nil) // For compatibility, we're keeping the first assignee as `apiIssue.Assignee`
apiIssue.Assignee = ToUser(ctx, issue.Assignees[0], nil) // For compatibility, we're keeping the first assignee as `apiIssue.Assignee`
} }
if issue.IsPull { if issue.IsPull {
if err := issue.LoadPullRequest(ctx); err != nil { if err := issue.LoadPullRequest(ctx); err != nil {

+ 7
- 7
services/convert/issue_comment.go Wyświetl plik

) )


// ToComment converts a issues_model.Comment to the api.Comment format // ToComment converts a issues_model.Comment to the api.Comment format
func ToComment(c *issues_model.Comment) *api.Comment {
func ToComment(ctx context.Context, c *issues_model.Comment) *api.Comment {
return &api.Comment{ return &api.Comment{
ID: c.ID, ID: c.ID,
Poster: ToUser(c.Poster, nil),
Poster: ToUser(ctx, c.Poster, nil),
HTMLURL: c.HTMLURL(), HTMLURL: c.HTMLURL(),
IssueURL: c.IssueURL(), IssueURL: c.IssueURL(),
PRURL: c.PRURL(), PRURL: c.PRURL(),
comment := &api.TimelineComment{ comment := &api.TimelineComment{
ID: c.ID, ID: c.ID,
Type: c.Type.String(), Type: c.Type.String(),
Poster: ToUser(c.Poster, nil),
Poster: ToUser(ctx, c.Poster, nil),
HTMLURL: c.HTMLURL(), HTMLURL: c.HTMLURL(),
IssueURL: c.IssueURL(), IssueURL: c.IssueURL(),
PRURL: c.PRURL(), PRURL: c.PRURL(),
log.Error("LoadPoster: %v", err) log.Error("LoadPoster: %v", err)
return nil return nil
} }
comment.RefComment = ToComment(com)
comment.RefComment = ToComment(ctx, com)
} }


if c.Label != nil { if c.Label != nil {
} }


if c.Assignee != nil { if c.Assignee != nil {
comment.Assignee = ToUser(c.Assignee, nil)
comment.Assignee = ToUser(ctx, c.Assignee, nil)
} }
if c.AssigneeTeam != nil { if c.AssigneeTeam != nil {
comment.AssigneeTeam, _ = ToTeam(c.AssigneeTeam)
comment.AssigneeTeam, _ = ToTeam(ctx, c.AssigneeTeam)
} }


if c.ResolveDoer != nil { if c.ResolveDoer != nil {
comment.ResolveDoer = ToUser(c.ResolveDoer, nil)
comment.ResolveDoer = ToUser(ctx, c.ResolveDoer, nil)
} }


if c.DependentIssue != nil { if c.DependentIssue != nil {

+ 2
- 2
services/convert/package.go Wyświetl plik



return &api.Package{ return &api.Package{
ID: pd.Version.ID, ID: pd.Version.ID,
Owner: ToUser(pd.Owner, doer),
Owner: ToUser(ctx, pd.Owner, doer),
Repository: repo, Repository: repo,
Creator: ToUser(pd.Creator, doer),
Creator: ToUser(ctx, pd.Creator, doer),
Type: string(pd.Package.Type), Type: string(pd.Package.Type),
Name: pd.Package.Name, Name: pd.Package.Name,
Version: pd.Version.Version, Version: pd.Version.Version,

+ 1
- 1
services/convert/pull.go Wyświetl plik

if pr.HasMerged { if pr.HasMerged {
apiPullRequest.Merged = pr.MergedUnix.AsTimePtr() apiPullRequest.Merged = pr.MergedUnix.AsTimePtr()
apiPullRequest.MergedCommitID = &pr.MergedCommitID apiPullRequest.MergedCommitID = &pr.MergedCommitID
apiPullRequest.MergedBy = ToUser(pr.Merger, nil)
apiPullRequest.MergedBy = ToUser(ctx, pr.Merger, nil)
} }


return apiPullRequest return apiPullRequest

+ 4
- 4
services/convert/pull_review.go Wyświetl plik

r.Reviewer = user_model.NewGhostUser() r.Reviewer = user_model.NewGhostUser()
} }


apiTeam, err := ToTeam(r.ReviewerTeam)
apiTeam, err := ToTeam(ctx, r.ReviewerTeam)
if err != nil { if err != nil {
return nil, err return nil, err
} }


result := &api.PullReview{ result := &api.PullReview{
ID: r.ID, ID: r.ID,
Reviewer: ToUser(r.Reviewer, doer),
Reviewer: ToUser(ctx, r.Reviewer, doer),
ReviewerTeam: apiTeam, ReviewerTeam: apiTeam,
State: api.ReviewStateUnknown, State: api.ReviewStateUnknown,
Body: r.Content, Body: r.Content,
apiComment := &api.PullReviewComment{ apiComment := &api.PullReviewComment{
ID: comment.ID, ID: comment.ID,
Body: comment.Content, Body: comment.Content,
Poster: ToUser(comment.Poster, doer),
Resolver: ToUser(comment.ResolveDoer, doer),
Poster: ToUser(ctx, comment.Poster, doer),
Resolver: ToUser(ctx, comment.ResolveDoer, doer),
ReviewID: review.ID, ReviewID: review.ID,
Created: comment.CreatedUnix.AsTime(), Created: comment.CreatedUnix.AsTime(),
Updated: comment.UpdatedUnix.AsTime(), Updated: comment.UpdatedUnix.AsTime(),

+ 4
- 2
services/convert/release.go Wyświetl plik

package convert package convert


import ( import (
"context"

repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
) )


// ToRelease convert a repo_model.Release to api.Release // ToRelease convert a repo_model.Release to api.Release
func ToRelease(r *repo_model.Release) *api.Release {
func ToRelease(ctx context.Context, r *repo_model.Release) *api.Release {
return &api.Release{ return &api.Release{
ID: r.ID, ID: r.ID,
TagName: r.TagName, TagName: r.TagName,
IsPrerelease: r.IsPrerelease, IsPrerelease: r.IsPrerelease,
CreatedAt: r.CreatedUnix.AsTime(), CreatedAt: r.CreatedUnix.AsTime(),
PublishedAt: r.CreatedUnix.AsTime(), PublishedAt: r.CreatedUnix.AsTime(),
Publisher: ToUser(r.Publisher, nil),
Publisher: ToUser(ctx, r.Publisher, nil),
Attachments: ToAttachments(r.Attachments), Attachments: ToAttachments(r.Attachments),
} }
} }

+ 7
- 7
services/convert/repository.go Wyświetl plik

if err := t.LoadAttributes(ctx); err != nil { if err := t.LoadAttributes(ctx); err != nil {
log.Warn("LoadAttributes of RepoTransfer: %v", err) log.Warn("LoadAttributes of RepoTransfer: %v", err)
} else { } else {
transfer = ToRepoTransfer(t)
transfer = ToRepoTransfer(ctx, t)
} }
} }
} }


return &api.Repository{ return &api.Repository{
ID: repo.ID, ID: repo.ID,
Owner: ToUserWithAccessMode(repo.Owner, mode),
Owner: ToUserWithAccessMode(ctx, repo.Owner, mode),
Name: repo.Name, Name: repo.Name,
FullName: repo.FullName(), FullName: repo.FullName(),
Description: repo.Description, Description: repo.Description,
DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge, DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge,
DefaultMergeStyle: string(defaultMergeStyle), DefaultMergeStyle: string(defaultMergeStyle),
DefaultAllowMaintainerEdit: defaultAllowMaintainerEdit, DefaultAllowMaintainerEdit: defaultAllowMaintainerEdit,
AvatarURL: repo.AvatarLink(),
AvatarURL: repo.AvatarLink(ctx),
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate, Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
MirrorInterval: mirrorInterval, MirrorInterval: mirrorInterval,
MirrorUpdated: mirrorUpdated, MirrorUpdated: mirrorUpdated,
} }


// ToRepoTransfer convert a models.RepoTransfer to a structs.RepeTransfer // ToRepoTransfer convert a models.RepoTransfer to a structs.RepeTransfer
func ToRepoTransfer(t *models.RepoTransfer) *api.RepoTransfer {
teams, _ := ToTeams(t.Teams, false)
func ToRepoTransfer(ctx context.Context, t *models.RepoTransfer) *api.RepoTransfer {
teams, _ := ToTeams(ctx, t.Teams, false)


return &api.RepoTransfer{ return &api.RepoTransfer{
Doer: ToUser(t.Doer, nil),
Recipient: ToUser(t.Recipient, nil),
Doer: ToUser(ctx, t.Doer, nil),
Recipient: ToUser(ctx, t.Recipient, nil),
Teams: teams, Teams: teams,
} }
} }

+ 1
- 1
services/convert/status.go Wyświetl plik



if status.CreatorID != 0 { if status.CreatorID != 0 {
creator, _ := user_model.GetUserByID(ctx, status.CreatorID) creator, _ := user_model.GetUserByID(ctx, status.CreatorID)
apiStatus.Creator = ToUser(creator, nil)
apiStatus.Creator = ToUser(ctx, creator, nil)
} }


return apiStatus return apiStatus

+ 12
- 10
services/convert/user.go Wyświetl plik

package convert package convert


import ( import (
"context"

"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"


// ToUser convert user_model.User to api.User // ToUser convert user_model.User to api.User
// if doer is set, private information is added if the doer has the permission to see it // if doer is set, private information is added if the doer has the permission to see it
func ToUser(user, doer *user_model.User) *api.User {
func ToUser(ctx context.Context, user, doer *user_model.User) *api.User {
if user == nil { if user == nil {
return nil return nil
} }
signed = true signed = true
authed = doer.ID == user.ID || doer.IsAdmin authed = doer.ID == user.ID || doer.IsAdmin
} }
return toUser(user, signed, authed)
return toUser(ctx, user, signed, authed)
} }


// ToUsers convert list of user_model.User to list of api.User // ToUsers convert list of user_model.User to list of api.User
func ToUsers(doer *user_model.User, users []*user_model.User) []*api.User {
func ToUsers(ctx context.Context, doer *user_model.User, users []*user_model.User) []*api.User {
result := make([]*api.User, len(users)) result := make([]*api.User, len(users))
for i := range users { for i := range users {
result[i] = ToUser(users[i], doer)
result[i] = ToUser(ctx, users[i], doer)
} }
return result return result
} }


// ToUserWithAccessMode convert user_model.User to api.User // ToUserWithAccessMode convert user_model.User to api.User
// AccessMode is not none show add some more information // AccessMode is not none show add some more information
func ToUserWithAccessMode(user *user_model.User, accessMode perm.AccessMode) *api.User {
func ToUserWithAccessMode(ctx context.Context, user *user_model.User, accessMode perm.AccessMode) *api.User {
if user == nil { if user == nil {
return nil return nil
} }
return toUser(user, accessMode != perm.AccessModeNone, false)
return toUser(ctx, user, accessMode != perm.AccessModeNone, false)
} }


// toUser convert user_model.User to api.User // toUser convert user_model.User to api.User
// signed shall only be set if requester is logged in. authed shall only be set if user is site admin or user himself // signed shall only be set if requester is logged in. authed shall only be set if user is site admin or user himself
func toUser(user *user_model.User, signed, authed bool) *api.User {
func toUser(ctx context.Context, user *user_model.User, signed, authed bool) *api.User {
result := &api.User{ result := &api.User{
ID: user.ID, ID: user.ID,
UserName: user.Name, UserName: user.Name,
FullName: user.FullName, FullName: user.FullName,
Email: user.GetEmail(), Email: user.GetEmail(),
AvatarURL: user.AvatarLink(),
AvatarURL: user.AvatarLink(ctx),
Created: user.CreatedUnix.AsTime(), Created: user.CreatedUnix.AsTime(),
Restricted: user.IsRestricted, Restricted: user.IsRestricted,
Location: user.Location, Location: user.Location,
} }


// ToUserAndPermission return User and its collaboration permission for a repository // ToUserAndPermission return User and its collaboration permission for a repository
func ToUserAndPermission(user, doer *user_model.User, accessMode perm.AccessMode) api.RepoCollaboratorPermission {
func ToUserAndPermission(ctx context.Context, user, doer *user_model.User, accessMode perm.AccessMode) api.RepoCollaboratorPermission {
return api.RepoCollaboratorPermission{ return api.RepoCollaboratorPermission{
User: ToUser(user, doer),
User: ToUser(ctx, user, doer),
Permission: accessMode.String(), Permission: accessMode.String(),
RoleName: accessMode.String(), RoleName: accessMode.String(),
} }

+ 5
- 4
services/convert/user_test.go Wyświetl plik

import ( import (
"testing" "testing"


"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"


user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1, IsAdmin: true}) user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1, IsAdmin: true})


apiUser := toUser(user1, true, true)
apiUser := toUser(db.DefaultContext, user1, true, true)
assert.True(t, apiUser.IsAdmin) assert.True(t, apiUser.IsAdmin)
assert.Contains(t, apiUser.AvatarURL, "://") assert.Contains(t, apiUser.AvatarURL, "://")


user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2, IsAdmin: false}) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2, IsAdmin: false})


apiUser = toUser(user2, true, true)
apiUser = toUser(db.DefaultContext, user2, true, true)
assert.False(t, apiUser.IsAdmin) assert.False(t, apiUser.IsAdmin)


apiUser = toUser(user1, false, false)
apiUser = toUser(db.DefaultContext, user1, false, false)
assert.False(t, apiUser.IsAdmin) assert.False(t, apiUser.IsAdmin)
assert.EqualValues(t, api.VisibleTypePublic.String(), apiUser.Visibility) assert.EqualValues(t, api.VisibleTypePublic.String(), apiUser.Visibility)


user31 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31, IsAdmin: false, Visibility: api.VisibleTypePrivate}) user31 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31, IsAdmin: false, Visibility: api.VisibleTypePrivate})


apiUser = toUser(user31, true, true)
apiUser = toUser(db.DefaultContext, user31, true, true)
assert.False(t, apiUser.IsAdmin) assert.False(t, apiUser.IsAdmin)
assert.EqualValues(t, api.VisibleTypePrivate.String(), apiUser.Visibility) assert.EqualValues(t, api.VisibleTypePrivate.String(), apiUser.Visibility)
} }

+ 1
- 1
services/pull/check.go Wyświetl plik

pr.MergedCommitID = commit.ID.String() pr.MergedCommitID = commit.ID.String()
pr.MergedUnix = timeutil.TimeStamp(commit.Author.When.Unix()) pr.MergedUnix = timeutil.TimeStamp(commit.Author.When.Unix())
pr.Status = issues_model.PullRequestStatusManuallyMerged pr.Status = issues_model.PullRequestStatusManuallyMerged
merger, _ := user_model.GetUserByEmail(commit.Author.Email)
merger, _ := user_model.GetUserByEmail(ctx, commit.Author.Email)


// When the commit author is unknown set the BaseRepo owner as merger // When the commit author is unknown set the BaseRepo owner as merger
if merger == nil { if merger == nil {

+ 1
- 1
services/release/release.go Wyświetl plik

} }


if rel.PublisherID <= 0 { if rel.PublisherID <= 0 {
u, err := user_model.GetUserByEmailContext(ctx, commit.Author.Email)
u, err := user_model.GetUserByEmail(ctx, commit.Author.Email)
if err == nil { if err == nil {
rel.PublisherID = u.ID rel.PublisherID = u.ID
} }

+ 1
- 1
services/repository/files/cherry_pick.go Wyświetl plik

} }


fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil
verification := GetPayloadCommitVerification(commit)
verification := GetPayloadCommitVerification(ctx, commit)
fileResponse := &structs.FileResponse{ fileResponse := &structs.FileResponse{
Commit: fileCommitResponse, Commit: fileCommitResponse,
Verification: verification, Verification: verification,

+ 2
- 2
services/repository/files/commit.go Wyświetl plik

} }


// GetPayloadCommitVerification returns the verification information of a commit // GetPayloadCommitVerification returns the verification information of a commit
func GetPayloadCommitVerification(commit *git.Commit) *structs.PayloadCommitVerification {
func GetPayloadCommitVerification(ctx context.Context, commit *git.Commit) *structs.PayloadCommitVerification {
verification := &structs.PayloadCommitVerification{} verification := &structs.PayloadCommitVerification{}
commitVerification := asymkey_model.ParseCommitWithSignature(commit)
commitVerification := asymkey_model.ParseCommitWithSignature(ctx, commit)
if commit.Signature != nil { if commit.Signature != nil {
verification.Signature = commit.Signature.Signature verification.Signature = commit.Signature.Signature
verification.Payload = commit.Signature.Payload verification.Payload = commit.Signature.Payload

+ 1
- 1
services/repository/files/file.go Wyświetl plik

func GetFileResponseFromCommit(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, branch, treeName string) (*api.FileResponse, error) { func GetFileResponseFromCommit(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, branch, treeName string) (*api.FileResponse, error) {
fileContents, _ := GetContents(ctx, repo, treeName, branch, false) // ok if fails, then will be nil fileContents, _ := GetContents(ctx, repo, treeName, branch, false) // ok if fails, then will be nil
fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil
verification := GetPayloadCommitVerification(commit)
verification := GetPayloadCommitVerification(ctx, commit)
fileResponse := &api.FileResponse{ fileResponse := &api.FileResponse{
Content: fileContents, Content: fileContents,
Commit: fileCommitResponse, Commit: fileCommitResponse,

+ 1
- 1
services/repository/files/patch.go Wyświetl plik

} }


fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil
verification := GetPayloadCommitVerification(commit)
verification := GetPayloadCommitVerification(ctx, commit)
fileResponse := &structs.FileResponse{ fileResponse := &structs.FileResponse{
Commit: fileCommitResponse, Commit: fileCommitResponse,
Verification: verification, Verification: verification,

+ 1
- 1
services/repository/push.go Wyświetl plik

var ok bool var ok bool
author, ok = emailToUser[sig.Email] author, ok = emailToUser[sig.Email]
if !ok { if !ok {
author, err = user_model.GetUserByEmailContext(ctx, sig.Email)
author, err = user_model.GetUserByEmail(ctx, sig.Email)
if err != nil && !user_model.IsErrUserNotExist(err) { if err != nil && !user_model.IsErrUserNotExist(err) {
return fmt.Errorf("GetUserByEmail: %w", err) return fmt.Errorf("GetUserByEmail: %w", err)
} }

+ 1
- 1
services/user/user_test.go Wyświetl plik



assert.NoError(t, user_model.CreateUser(v.user)) assert.NoError(t, user_model.CreateUser(v.user))


u, err := user_model.GetUserByEmail(v.user.Email)
u, err := user_model.GetUserByEmail(db.DefaultContext, v.user.Email)
assert.NoError(t, err) assert.NoError(t, err)


assert.Equal(t, !u.AllowCreateOrganization, v.disableOrgCreation) assert.Equal(t, !u.AllowCreateOrganization, v.disableOrgCreation)

+ 45
- 45
services/webhook/notifier.go Wyświetl plik

Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}) })
} else { } else {
err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}) })
} }
if err != nil { if err != nil {
if err := PrepareWebhooks(ctx, EventSource{Repository: oldRepo}, webhook_module.HookEventFork, &api.ForkPayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: oldRepo}, webhook_module.HookEventFork, &api.ForkPayload{
Forkee: convert.ToRepo(ctx, oldRepo, oldMode), Forkee: convert.ToRepo(ctx, oldRepo, oldMode),
Repo: convert.ToRepo(ctx, repo, mode), Repo: convert.ToRepo(ctx, repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err) log.Error("PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err)
} }
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoCreated, Action: api.HookRepoCreated,
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
Organization: convert.ToUser(u, nil),
Sender: convert.ToUser(doer, nil),
Organization: convert.ToUser(ctx, u, nil),
Sender: convert.ToUser(ctx, doer, nil),
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
} }
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoCreated, Action: api.HookRepoCreated,
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
Organization: convert.ToUser(u, nil),
Sender: convert.ToUser(doer, nil),
Organization: convert.ToUser(ctx, u, nil),
Sender: convert.ToUser(ctx, doer, nil),
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
} }
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoDeleted, Action: api.HookRepoDeleted,
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
Organization: convert.ToUser(repo.MustOwner(ctx), nil),
Sender: convert.ToUser(doer, nil),
Organization: convert.ToUser(ctx, repo.MustOwner(ctx), nil),
Sender: convert.ToUser(ctx, doer, nil),
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
} }
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoCreated, Action: api.HookRepoCreated,
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
Organization: convert.ToUser(u, nil),
Sender: convert.ToUser(doer, nil),
Organization: convert.ToUser(ctx, u, nil),
Sender: convert.ToUser(ctx, doer, nil),
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
} }
Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
} }
if removed { if removed {
apiPullRequest.Action = api.HookIssueUnassigned apiPullRequest.Action = api.HookIssueUnassigned
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
} }
if removed { if removed {
apiIssue.Action = api.HookIssueUnassigned apiIssue.Action = api.HookIssueUnassigned
}, },
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}) })
} else { } else {
err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{ err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{
}, },
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}) })
} }


Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
CommitID: commitID, CommitID: commitID,
} }
if isClosed { if isClosed {
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
CommitID: commitID, CommitID: commitID,
} }
if isClosed { if isClosed {
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(issue.Poster, nil),
Sender: convert.ToUser(ctx, issue.Poster, nil),
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks: %v", err) log.Error("PrepareWebhooks: %v", err)
} }
Index: pull.Issue.Index, Index: pull.Issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, pull, nil), PullRequest: convert.ToAPIPullRequest(ctx, pull, nil),
Repository: convert.ToRepo(ctx, pull.Issue.Repo, mode), Repository: convert.ToRepo(ctx, pull.Issue.Repo, mode),
Sender: convert.ToUser(pull.Issue.Poster, nil),
Sender: convert.ToUser(ctx, pull.Issue.Poster, nil),
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks: %v", err) log.Error("PrepareWebhooks: %v", err)
} }
}, },
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}) })
} else { } else {
err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{ err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{
}, },
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}) })
} }
if err != nil { if err != nil {
if err := PrepareWebhooks(ctx, EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{
Action: api.HookIssueCommentEdited, Action: api.HookIssueCommentEdited,
Issue: convert.ToAPIIssue(ctx, c.Issue), Issue: convert.ToAPIIssue(ctx, c.Issue),
Comment: convert.ToComment(c),
Comment: convert.ToComment(ctx, c),
Changes: &api.ChangesPayload{ Changes: &api.ChangesPayload{
Body: &api.ChangesFromPayload{ Body: &api.ChangesFromPayload{
From: oldContent, From: oldContent,
}, },
}, },
Repository: convert.ToRepo(ctx, c.Issue.Repo, mode), Repository: convert.ToRepo(ctx, c.Issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
IsPull: c.Issue.IsPull, IsPull: c.Issue.IsPull,
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks [comment_id: %d]: %v", c.ID, err) log.Error("PrepareWebhooks [comment_id: %d]: %v", c.ID, err)
if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{
Action: api.HookIssueCommentCreated, Action: api.HookIssueCommentCreated,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Comment: convert.ToComment(comment),
Comment: convert.ToComment(ctx, comment),
Repository: convert.ToRepo(ctx, repo, mode), Repository: convert.ToRepo(ctx, repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
IsPull: issue.IsPull, IsPull: issue.IsPull,
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err) log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
if err := PrepareWebhooks(ctx, EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{
Action: api.HookIssueCommentDeleted, Action: api.HookIssueCommentDeleted,
Issue: convert.ToAPIIssue(ctx, comment.Issue), Issue: convert.ToAPIIssue(ctx, comment.Issue),
Comment: convert.ToComment(comment),
Comment: convert.ToComment(ctx, comment),
Repository: convert.ToRepo(ctx, comment.Issue.Repo, mode), Repository: convert.ToRepo(ctx, comment.Issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
IsPull: comment.Issue.IsPull, IsPull: comment.Issue.IsPull,
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err) log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{
Action: api.HookWikiCreated, Action: api.HookWikiCreated,
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
Page: page, Page: page,
Comment: comment, Comment: comment,
}); err != nil { }); err != nil {
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{
Action: api.HookWikiEdited, Action: api.HookWikiEdited,
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
Page: page, Page: page,
Comment: comment, Comment: comment,
}); err != nil { }); err != nil {
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{
Action: api.HookWikiDeleted, Action: api.HookWikiDeleted,
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
Page: page, Page: page,
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(ctx, issue.Repo, perm.AccessModeNone), Repository: convert.ToRepo(ctx, issue.Repo, perm.AccessModeNone),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}) })
} else { } else {
err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}) })
} }
if err != nil { if err != nil {
Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}) })
} else { } else {
err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueMilestone, &api.IssuePayload{ err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueMilestone, &api.IssuePayload{
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}) })
} }
if err != nil { if err != nil {
} }


func (m *webhookNotifier) NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { 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)
apiPusher := convert.ToUser(ctx, pusher, nil)
apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL()) apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL())
if err != nil { if err != nil {
log.Error("commits.ToAPIPayloadCommits failed: %v", err) log.Error("commits.ToAPIPayloadCommits failed: %v", err)
Index: pr.Issue.Index, Index: pr.Issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
Repository: convert.ToRepo(ctx, pr.Issue.Repo, mode), Repository: convert.ToRepo(ctx, pr.Issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
Action: api.HookIssueClosed, Action: api.HookIssueClosed,
} }


}, },
PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks [pr: %d]: %v", pr.ID, err) log.Error("PrepareWebhooks [pr: %d]: %v", pr.ID, err)
} }
Index: review.Issue.Index, Index: review.Issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
Repository: convert.ToRepo(ctx, review.Issue.Repo, mode), Repository: convert.ToRepo(ctx, review.Issue.Repo, mode),
Sender: convert.ToUser(review.Reviewer, nil),
Sender: convert.ToUser(ctx, review.Reviewer, nil),
Review: &api.ReviewPayload{ Review: &api.ReviewPayload{
Type: string(reviewHookType), Type: string(reviewHookType),
Content: review.Content, Content: review.Content,
} }


func (m *webhookNotifier) NotifyCreateRef(ctx context.Context, 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)
apiPusher := convert.ToUser(ctx, pusher, nil)
apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone) apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone)
refName := git.RefEndName(refFullName) refName := git.RefEndName(refFullName)


Index: pr.Issue.Index, Index: pr.Issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
Repository: convert.ToRepo(ctx, pr.Issue.Repo, perm.AccessModeNone), Repository: convert.ToRepo(ctx, pr.Issue.Repo, perm.AccessModeNone),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err) log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
} }
} }


func (m *webhookNotifier) NotifyDeleteRef(ctx context.Context, 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)
apiPusher := convert.ToUser(ctx, pusher, nil)
apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone) apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone)
refName := git.RefEndName(refFullName) refName := git.RefEndName(refFullName)


mode, _ := access_model.AccessLevel(ctx, doer, rel.Repo) mode, _ := access_model.AccessLevel(ctx, doer, rel.Repo)
if err := PrepareWebhooks(ctx, EventSource{Repository: rel.Repo}, webhook_module.HookEventRelease, &api.ReleasePayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: rel.Repo}, webhook_module.HookEventRelease, &api.ReleasePayload{
Action: action, Action: action,
Release: convert.ToRelease(rel),
Release: convert.ToRelease(ctx, rel),
Repository: convert.ToRepo(ctx, rel.Repo, mode), Repository: convert.ToRepo(ctx, rel.Repo, mode),
Sender: convert.ToUser(doer, nil),
Sender: convert.ToUser(ctx, doer, nil),
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks: %v", err) log.Error("PrepareWebhooks: %v", err)
} }
} }


func (m *webhookNotifier) NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { 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)
apiPusher := convert.ToUser(ctx, pusher, nil)
apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL()) apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL())
if err != nil { if err != nil {
log.Error("commits.ToAPIPayloadCommits failed: %v", err) log.Error("commits.ToAPIPayloadCommits failed: %v", err)
if err := PrepareWebhooks(ctx, source, webhook_module.HookEventPackage, &api.PackagePayload{ if err := PrepareWebhooks(ctx, source, webhook_module.HookEventPackage, &api.PackagePayload{
Action: action, Action: action,
Package: apiPackage, Package: apiPackage,
Sender: convert.ToUser(sender, nil),
Sender: convert.ToUser(ctx, sender, nil),
}); err != nil { }); err != nil {
log.Error("PrepareWebhooks: %v", err) log.Error("PrepareWebhooks: %v", err)
} }

+ 1
- 1
templates/admin/user/edit.tmpl Wyświetl plik

<div class="ui attached segment"> <div class="ui attached segment">
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data"> <form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
{{if not DisableGravatar}}
{{if not (DisableGravatar $.Context)}}
<div class="inline field"> <div class="inline field">
<div class="ui radio checkbox"> <div class="ui radio checkbox">
<input name="source" value="lookup" type="radio" {{if not .User.UseCustomAvatar}}checked{{end}}> <input name="source" value="lookup" type="radio" {{if not .User.UseCustomAvatar}}checked{{end}}>

+ 4
- 4
templates/base/head.tmpl Wyświetl plik

{{if .PageIsUserProfile}} {{if .PageIsUserProfile}}
<meta property="og:title" content="{{.Owner.DisplayName}}"> <meta property="og:title" content="{{.Owner.DisplayName}}">
<meta property="og:type" content="profile"> <meta property="og:type" content="profile">
<meta property="og:image" content="{{.Owner.AvatarLink}}">
<meta property="og:image" content="{{.Owner.AvatarLink $.Context}}">
<meta property="og:url" content="{{.Owner.HTMLURL}}"> <meta property="og:url" content="{{.Owner.HTMLURL}}">
{{if .Owner.Description}} {{if .Owner.Description}}
<meta property="og:description" content="{{.Owner.Description}}"> <meta property="og:description" content="{{.Owner.Description}}">
{{end}} {{end}}
{{end}} {{end}}
<meta property="og:type" content="object"> <meta property="og:type" content="object">
{{if .Repository.AvatarLink}}
<meta property="og:image" content="{{.Repository.AvatarLink}}">
{{if (.Repository.AvatarLink $.Context)}}
<meta property="og:image" content="{{.Repository.AvatarLink $.Context}}">
{{else}} {{else}}
<meta property="og:image" content="{{.Repository.Owner.AvatarLink}}">
<meta property="og:image" content="{{.Repository.Owner.AvatarLink $.Context}}">
{{end}} {{end}}
{{else}} {{else}}
<meta property="og:title" content="{{AppName}}"> <meta property="og:title" content="{{AppName}}">

+ 2
- 2
templates/base/head_navbar.tmpl Wyświetl plik

<div class="right stackable menu"> <div class="right stackable menu">
<div class="ui dropdown jump item tooltip" tabindex="-1" data-content="{{.locale.Tr "user_profile_and_more"}}"> <div class="ui dropdown jump item tooltip" tabindex="-1" data-content="{{.locale.Tr "user_profile_and_more"}}">
<span class="text"> <span class="text">
{{avatar .SignedUser 24 "tiny"}}
{{avatar $.Context .SignedUser 24 "tiny"}}
<span class="sr-only">{{.locale.Tr "user_profile_and_more"}}</span> <span class="sr-only">{{.locale.Tr "user_profile_and_more"}}</span>
<span class="mobile-only">{{.SignedUser.Name}}</span> <span class="mobile-only">{{.SignedUser.Name}}</span>
<span class="fitted not-mobile" tabindex="-1">{{svg "octicon-triangle-down"}}</span> <span class="fitted not-mobile" tabindex="-1">{{svg "octicon-triangle-down"}}</span>


<div class="ui dropdown jump item tooltip gt-mx-0" tabindex="-1" data-content="{{.locale.Tr "user_profile_and_more"}}"> <div class="ui dropdown jump item tooltip gt-mx-0" tabindex="-1" data-content="{{.locale.Tr "user_profile_and_more"}}">
<span class="text"> <span class="text">
{{avatar .SignedUser 24 "tiny"}}
{{avatar $.Context .SignedUser 24 "tiny"}}
<span class="sr-only">{{.locale.Tr "user_profile_and_more"}}</span> <span class="sr-only">{{.locale.Tr "user_profile_and_more"}}</span>
<span class="mobile-only">{{.SignedUser.Name}}</span> <span class="mobile-only">{{.SignedUser.Name}}</span>
<span class="fitted not-mobile" tabindex="-1">{{svg "octicon-triangle-down"}}</span> <span class="fitted not-mobile" tabindex="-1">{{svg "octicon-triangle-down"}}</span>

+ 2
- 2
templates/base/head_script.tmpl Wyświetl plik

tributeValues: Array.from(new Map([ tributeValues: Array.from(new Map([
{{range .Participants}} {{range .Participants}}
['{{.Name}}', {key: '{{.Name}} {{.FullName}}', value: '{{.Name}}', ['{{.Name}}', {key: '{{.Name}} {{.FullName}}', value: '{{.Name}}',
name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.AvatarLink}}'}],
name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.AvatarLink $.Context}}'}],
{{end}} {{end}}
{{range .Assignees}} {{range .Assignees}}
['{{.Name}}', {key: '{{.Name}} {{.FullName}}', value: '{{.Name}}', ['{{.Name}}', {key: '{{.Name}} {{.FullName}}', value: '{{.Name}}',
name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.AvatarLink}}'}],
name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.AvatarLink $.Context}}'}],
{{end}} {{end}}
{{range .MentionableTeams}} {{range .MentionableTeams}}
['{{$.MentionableTeamsOrg}}/{{.Name}}', {key: '{{$.MentionableTeamsOrg}}/{{.Name}}', value: '{{$.MentionableTeamsOrg}}/{{.Name}}', ['{{$.MentionableTeamsOrg}}/{{.Name}}', {key: '{{$.MentionableTeamsOrg}}/{{.Name}}', value: '{{$.MentionableTeamsOrg}}/{{.Name}}',

+ 1
- 1
templates/explore/organizations.tmpl Wyświetl plik

<div class="ui user list"> <div class="ui user list">
{{range .Users}} {{range .Users}}
<div class="item"> <div class="item">
{{avatar .}}
{{avatar $.Context .}}
<div class="content"> <div class="content">
<span class="header"> <span class="header">
<a href="{{.HomeLink}}">{{.Name}}</a> {{.FullName}} <a href="{{.HomeLink}}">{{.Name}}</a> {{.FullName}}

+ 1
- 1
templates/explore/users.tmpl Wyświetl plik

<div class="ui user list"> <div class="ui user list">
{{range .Users}} {{range .Users}}
<div class="item"> <div class="item">
{{avatar .}}
{{avatar $.Context .}}
<div class="content"> <div class="content">
<span class="header"><a href="{{.HomeLink}}">{{.Name}}</a> {{.FullName}}</span> <span class="header"><a href="{{.HomeLink}}">{{.Name}}</a> {{.FullName}}</span>
<div class="description"> <div class="description">

+ 1
- 1
templates/org/header.tmpl Wyświetl plik

<div class="ui vertically grid head"> <div class="ui vertically grid head">
<div class="column"> <div class="column">
<div class="ui header"> <div class="ui header">
{{avatar . 100}}
{{avatar $.Context . 100}}
<span class="text thin grey"><a href="{{.HomeLink}}">{{.DisplayName}}</a></span> <span class="text thin grey"><a href="{{.HomeLink}}">{{.DisplayName}}</a></span>
<span class="org-visibility"> <span class="org-visibility">
{{if .Visibility.IsLimited}}<div class="ui medium basic horizontal label">{{$.locale.Tr "org.settings.visibility.limited_shortname"}}</div>{{end}} {{if .Visibility.IsLimited}}<div class="ui medium basic horizontal label">{{$.locale.Tr "org.settings.visibility.limited_shortname"}}</div>{{end}}

+ 2
- 2
templates/org/home.tmpl Wyświetl plik

{{template "base/head" .}} {{template "base/head" .}}
<div role="main" aria-label="{{.Title}}" class="page-content organization profile"> <div role="main" aria-label="{{.Title}}" class="page-content organization profile">
<div class="ui container gt-df"> <div class="ui container gt-df">
{{avatar .Org 140 "org-avatar"}}
{{avatar $.Context .Org 140 "org-avatar"}}
<div id="org-info"> <div id="org-info">
<div class="ui header"> <div class="ui header">
{{.Org.DisplayName}} {{.Org.DisplayName}}
{{range .Members}} {{range .Members}}
{{if or $isMember (call $.IsPublicMember .ID)}} {{if or $isMember (call $.IsPublicMember .ID)}}
<a href="{{.HomeLink}}" title="{{.Name}}{{if .FullName}} ({{.FullName}}){{end}}"> <a href="{{.HomeLink}}" title="{{.Name}}{{if .FullName}} ({{.FullName}}){{end}}">
{{avatar .}}
{{avatar $.Context .}}
</a> </a>
{{end}} {{end}}
{{end}} {{end}}

+ 1
- 1
templates/org/member/members.tmpl Wyświetl plik

{{range .Members}} {{range .Members}}
<div class="item ui grid"> <div class="item ui grid">
<div class="ui four wide column" style="display: flex;"> <div class="ui four wide column" style="display: flex;">
{{avatar . 48}}
{{avatar $.Context . 48}}
<div> <div>
<div class="meta"><a href="{{.HomeLink}}">{{.Name}}</a></div> <div class="meta"><a href="{{.HomeLink}}">{{.Name}}</a></div>
<div class="meta">{{.FullName}}</div> <div class="meta">{{.FullName}}</div>

+ 0
- 0
templates/org/team/invite.tmpl Wyświetl plik


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików

Ładowanie…
Anuluj
Zapisz