2020-01-10 12:34:21 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repository
import (
2022-01-20 02:26:57 +03:00
"context"
2020-01-10 12:34:21 +03:00
"fmt"
2021-11-16 21:18:25 +03:00
"net/url"
2020-01-10 12:34:21 +03:00
"time"
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
"code.gitea.io/gitea/models/avatars"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2020-01-10 12:34:21 +03:00
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
2021-12-16 05:18:38 +03:00
"code.gitea.io/gitea/modules/setting"
2020-01-10 12:34:21 +03:00
api "code.gitea.io/gitea/modules/structs"
)
// PushCommit represents a commit in a push operation.
type PushCommit struct {
Sha1 string
Message string
AuthorEmail string
AuthorName string
CommitterEmail string
CommitterName string
Timestamp time . Time
}
// PushCommits represents list of commits in a push operation.
type PushCommits struct {
Commits [ ] * PushCommit
2021-06-29 16:34:03 +03:00
HeadCommit * PushCommit
2020-01-10 12:34:21 +03:00
CompareURL string
2021-08-26 02:04:58 +03:00
Len int
2020-01-10 12:34:21 +03:00
avatars map [ string ] string
2021-11-24 12:49:20 +03:00
emailUsers map [ string ] * user_model . User
2020-01-10 12:34:21 +03:00
}
// NewPushCommits creates a new PushCommits object.
func NewPushCommits ( ) * PushCommits {
return & PushCommits {
avatars : make ( map [ string ] string ) ,
2021-11-24 12:49:20 +03:00
emailUsers : make ( map [ string ] * user_model . User ) ,
2020-01-10 12:34:21 +03:00
}
}
2021-06-29 16:34:03 +03:00
// toAPIPayloadCommit converts a single PushCommit to an api.PayloadCommit object.
2022-01-20 02:26:57 +03:00
func ( pc * PushCommits ) toAPIPayloadCommit ( ctx context . Context , repoPath , repoLink string , commit * PushCommit ) ( * api . PayloadCommit , error ) {
2020-01-10 12:34:21 +03:00
var err error
2021-06-29 16:34:03 +03:00
authorUsername := ""
author , ok := pc . emailUsers [ commit . AuthorEmail ]
if ! ok {
2021-11-24 12:49:20 +03:00
author , err = user_model . GetUserByEmail ( commit . AuthorEmail )
2021-06-29 16:34:03 +03:00
if err == nil {
2020-01-10 12:34:21 +03:00
authorUsername = author . Name
2021-06-29 16:34:03 +03:00
pc . emailUsers [ commit . AuthorEmail ] = author
2020-01-10 12:34:21 +03:00
}
2021-06-29 16:34:03 +03:00
} else {
authorUsername = author . Name
}
2020-01-10 12:34:21 +03:00
2021-06-29 16:34:03 +03:00
committerUsername := ""
committer , ok := pc . emailUsers [ commit . CommitterEmail ]
if ! ok {
2021-11-24 12:49:20 +03:00
committer , err = user_model . GetUserByEmail ( commit . CommitterEmail )
2021-06-29 16:34:03 +03:00
if err == nil {
// TODO: check errors other than email not found.
2020-01-10 12:34:21 +03:00
committerUsername = committer . Name
2021-06-29 16:34:03 +03:00
pc . emailUsers [ commit . CommitterEmail ] = committer
2020-01-10 12:34:21 +03:00
}
2021-06-29 16:34:03 +03:00
} else {
committerUsername = committer . Name
}
2020-01-10 12:34:21 +03:00
2022-01-20 02:26:57 +03:00
fileStatus , err := git . GetCommitFileStatus ( ctx , repoPath , commit . Sha1 )
2021-06-29 16:34:03 +03:00
if err != nil {
2022-10-24 22:29:17 +03:00
return nil , fmt . Errorf ( "FileStatus [commit_sha1: %s]: %w" , commit . Sha1 , err )
2021-06-29 16:34:03 +03:00
}
return & api . PayloadCommit {
ID : commit . Sha1 ,
Message : commit . Message ,
2021-11-16 21:18:25 +03:00
URL : fmt . Sprintf ( "%s/commit/%s" , repoLink , url . PathEscape ( commit . Sha1 ) ) ,
2021-06-29 16:34:03 +03:00
Author : & api . PayloadUser {
Name : commit . AuthorName ,
Email : commit . AuthorEmail ,
UserName : authorUsername ,
} ,
Committer : & api . PayloadUser {
Name : commit . CommitterName ,
Email : commit . CommitterEmail ,
UserName : committerUsername ,
} ,
Added : fileStatus . Added ,
Removed : fileStatus . Removed ,
Modified : fileStatus . Modified ,
Timestamp : commit . Timestamp ,
} , nil
}
// ToAPIPayloadCommits converts a PushCommits object to api.PayloadCommit format.
// It returns all converted commits and, if provided, the head commit or an error otherwise.
2022-01-20 02:26:57 +03:00
func ( pc * PushCommits ) ToAPIPayloadCommits ( ctx context . Context , repoPath , repoLink string ) ( [ ] * api . PayloadCommit , * api . PayloadCommit , error ) {
2021-06-29 16:34:03 +03:00
commits := make ( [ ] * api . PayloadCommit , len ( pc . Commits ) )
var headCommit * api . PayloadCommit
if pc . emailUsers == nil {
2021-11-24 12:49:20 +03:00
pc . emailUsers = make ( map [ string ] * user_model . User )
2021-06-29 16:34:03 +03:00
}
for i , commit := range pc . Commits {
2022-01-20 02:26:57 +03:00
apiCommit , err := pc . toAPIPayloadCommit ( ctx , repoPath , repoLink , commit )
2020-01-10 12:34:21 +03:00
if err != nil {
2021-06-29 16:34:03 +03:00
return nil , nil , err
2020-01-10 12:34:21 +03:00
}
2021-06-29 16:34:03 +03:00
commits [ i ] = apiCommit
if pc . HeadCommit != nil && pc . HeadCommit . Sha1 == commits [ i ] . ID {
headCommit = apiCommit
2020-01-10 12:34:21 +03:00
}
}
2021-06-29 16:34:03 +03:00
if pc . HeadCommit != nil && headCommit == nil {
var err error
2022-01-20 02:26:57 +03:00
headCommit , err = pc . toAPIPayloadCommit ( ctx , repoPath , repoLink , pc . HeadCommit )
2021-06-29 16:34:03 +03:00
if err != nil {
return nil , nil , err
}
}
return commits , headCommit , nil
2020-01-10 12:34:21 +03:00
}
// AvatarLink tries to match user in database with e-mail
// in order to show custom avatar, and falls back to general avatar link.
func ( pc * PushCommits ) AvatarLink ( email string ) string {
if pc . avatars == nil {
pc . avatars = make ( map [ string ] string )
}
avatar , ok := pc . avatars [ email ]
if ok {
return avatar
}
2021-12-16 05:18:38 +03:00
size := avatars . DefaultAvatarPixelSize * setting . Avatar . RenderedSizeFactor
2020-12-09 03:12:15 +03:00
2020-01-10 12:34:21 +03:00
u , ok := pc . emailUsers [ email ]
if ! ok {
var err error
2021-11-24 12:49:20 +03:00
u , err = user_model . GetUserByEmail ( email )
2020-01-10 12:34:21 +03:00
if err != nil {
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
pc . avatars [ email ] = avatars . GenerateEmailAvatarFastLink ( email , size )
2021-11-24 12:49:20 +03:00
if ! user_model . IsErrUserNotExist ( err ) {
2020-01-10 12:34:21 +03:00
log . Error ( "GetUserByEmail: %v" , err )
return ""
}
} else {
pc . emailUsers [ email ] = u
}
}
if u != nil {
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
pc . avatars [ email ] = u . AvatarLinkWithSize ( size )
2020-01-10 12:34:21 +03:00
}
return pc . avatars [ email ]
}
// CommitToPushCommit transforms a git.Commit to PushCommit type.
func CommitToPushCommit ( commit * git . Commit ) * PushCommit {
return & PushCommit {
Sha1 : commit . ID . String ( ) ,
Message : commit . Message ( ) ,
AuthorEmail : commit . Author . Email ,
AuthorName : commit . Author . Name ,
CommitterEmail : commit . Committer . Email ,
CommitterName : commit . Committer . Name ,
Timestamp : commit . Author . When ,
}
}
2021-08-09 21:08:51 +03:00
// GitToPushCommits transforms a list of git.Commits to PushCommits type.
func GitToPushCommits ( gitCommits [ ] * git . Commit ) * PushCommits {
commits := make ( [ ] * PushCommit , 0 , len ( gitCommits ) )
for _ , commit := range gitCommits {
commits = append ( commits , CommitToPushCommit ( commit ) )
2020-01-10 12:34:21 +03:00
}
2021-08-26 02:04:58 +03:00
return & PushCommits {
Commits : commits ,
HeadCommit : nil ,
CompareURL : "" ,
Len : len ( commits ) ,
avatars : make ( map [ string ] string ) ,
2021-11-24 12:49:20 +03:00
emailUsers : make ( map [ string ] * user_model . User ) ,
2021-08-26 02:04:58 +03:00
}
2020-01-10 12:34:21 +03:00
}