| @@ -14,6 +14,7 @@ github.com/go-xorm/core = | |||||
| github.com/go-xorm/xorm = | github.com/go-xorm/xorm = | ||||
| github.com/gogits/chardet = commit:2404f77725 | github.com/gogits/chardet = commit:2404f77725 | ||||
| github.com/gogits/go-gogs-client = commit:92e76d616a | github.com/gogits/go-gogs-client = commit:92e76d616a | ||||
| github.com/issue9/identicon = | |||||
| github.com/lib/pq = commit:0dad96c0b9 | github.com/lib/pq = commit:0dad96c0b9 | ||||
| github.com/macaron-contrib/binding = commit:de6ed78668 | github.com/macaron-contrib/binding = commit:de6ed78668 | ||||
| github.com/macaron-contrib/cache = commit:cd824f6f2d | github.com/macaron-contrib/cache = commit:cd824f6f2d | ||||
| @@ -13,7 +13,9 @@ import ( | |||||
| "fmt" | "fmt" | ||||
| "image" | "image" | ||||
| "image/jpeg" | "image/jpeg" | ||||
| _ "image/jpeg" | |||||
| "os" | "os" | ||||
| "path" | |||||
| "path/filepath" | "path/filepath" | ||||
| "strings" | "strings" | ||||
| "time" | "time" | ||||
| @@ -116,11 +118,39 @@ func (u *User) HomeLink() string { | |||||
| // AvatarLink returns user gravatar link. | // AvatarLink returns user gravatar link. | ||||
| func (u *User) AvatarLink() string { | func (u *User) AvatarLink() string { | ||||
| defaultImgUrl := setting.AppSubUrl + "/img/avatar_default.jpg" | |||||
| imgPath := path.Join(setting.AvatarUploadPath, com.ToStr(u.Id)) | |||||
| switch { | switch { | ||||
| case u.UseCustomAvatar: | case u.UseCustomAvatar: | ||||
| if !com.IsExist(imgPath) { | |||||
| return defaultImgUrl | |||||
| } | |||||
| return setting.AppSubUrl + "/avatars/" + com.ToStr(u.Id) | return setting.AppSubUrl + "/avatars/" + com.ToStr(u.Id) | ||||
| case setting.DisableGravatar, setting.OfflineMode: | case setting.DisableGravatar, setting.OfflineMode: | ||||
| return setting.AppSubUrl + "/img/avatar_default.jpg" | |||||
| if !com.IsExist(imgPath) { | |||||
| img, err := avatar.RandomImage([]byte(u.Email)) | |||||
| if err != nil { | |||||
| log.Error(3, "RandomImage: %v", err) | |||||
| return defaultImgUrl | |||||
| } | |||||
| if err = os.MkdirAll(path.Dir(imgPath), os.ModePerm); err != nil { | |||||
| log.Error(3, "Create: %v", err) | |||||
| return defaultImgUrl | |||||
| } | |||||
| fw, err := os.Create(imgPath) | |||||
| if err != nil { | |||||
| log.Error(3, "Create: %v", err) | |||||
| return defaultImgUrl | |||||
| } | |||||
| defer fw.Close() | |||||
| if err = jpeg.Encode(fw, img, nil); err != nil { | |||||
| log.Error(3, "Encode: %v", err) | |||||
| return defaultImgUrl | |||||
| } | |||||
| } | |||||
| return setting.AppSubUrl + "/avatars/" + com.ToStr(u.Id) | |||||
| case setting.Service.EnableCacheAvatar: | case setting.Service.EnableCacheAvatar: | ||||
| return setting.AppSubUrl + "/avatar/" + u.Avatar | return setting.AppSubUrl + "/avatar/" + u.Avatar | ||||
| } | } | ||||
| @@ -19,9 +19,11 @@ import ( | |||||
| "errors" | "errors" | ||||
| "fmt" | "fmt" | ||||
| "image" | "image" | ||||
| "image/color/palette" | |||||
| "image/jpeg" | "image/jpeg" | ||||
| "image/png" | "image/png" | ||||
| "io" | "io" | ||||
| "math/rand" | |||||
| "net/http" | "net/http" | ||||
| "net/url" | "net/url" | ||||
| "os" | "os" | ||||
| @@ -30,6 +32,7 @@ import ( | |||||
| "sync" | "sync" | ||||
| "time" | "time" | ||||
| "github.com/issue9/identicon" | |||||
| "github.com/nfnt/resize" | "github.com/nfnt/resize" | ||||
| "github.com/gogits/gogs/modules/log" | "github.com/gogits/gogs/modules/log" | ||||
| @@ -59,6 +62,27 @@ func HashEmail(email string) string { | |||||
| return hex.EncodeToString(h.Sum(nil)) | return hex.EncodeToString(h.Sum(nil)) | ||||
| } | } | ||||
| const _RANDOM_AVATAR_SIZE = 200 | |||||
| // RandomImage generates and returns a random avatar image. | |||||
| func RandomImage(data []byte) (image.Image, error) { | |||||
| randExtent := len(palette.WebSafe) - 32 | |||||
| rand.Seed(time.Now().UnixNano()) | |||||
| colorIndex := rand.Intn(randExtent) | |||||
| backColorIndex := colorIndex - 1 | |||||
| if backColorIndex < 0 { | |||||
| backColorIndex = randExtent - 1 | |||||
| } | |||||
| // Size, background, forecolor | |||||
| imgMaker, err := identicon.New(_RANDOM_AVATAR_SIZE, | |||||
| palette.WebSafe[backColorIndex], palette.WebSafe[colorIndex:colorIndex+32]...) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return imgMaker.Make(data), nil | |||||
| } | |||||
| // Avatar represents the avatar object. | // Avatar represents the avatar object. | ||||
| type Avatar struct { | type Avatar struct { | ||||
| Hash string | Hash string | ||||
| @@ -14,19 +14,19 @@ | |||||
| <div class="ui selection dropdown"> | <div class="ui selection dropdown"> | ||||
| <input type="hidden" id="uid" name="uid" value="{{.ContextUser.Id}}" required> | <input type="hidden" id="uid" name="uid" value="{{.ContextUser.Id}}" required> | ||||
| <span class="text"> | <span class="text"> | ||||
| <img class="ui mini avatar image" src="{{.ContextUser.AvatarLink}}"> | |||||
| <img class="ui mini image" src="{{.ContextUser.AvatarLink}}"> | |||||
| {{.ContextUser.Name}} | {{.ContextUser.Name}} | ||||
| </span> | </span> | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <div class="item" data-value="{{.SignedUser.Id}}"> | <div class="item" data-value="{{.SignedUser.Id}}"> | ||||
| <img class="ui mini avatar image" src="{{.SignedUser.AvatarLink}}"> | |||||
| <img class="ui mini image" src="{{.SignedUser.AvatarLink}}"> | |||||
| {{.SignedUser.Name}} | {{.SignedUser.Name}} | ||||
| </div> | </div> | ||||
| {{range .Orgs}} | {{range .Orgs}} | ||||
| {{if .IsOwnedBy $.SignedUser.Id}} | {{if .IsOwnedBy $.SignedUser.Id}} | ||||
| <div class="item" data-value="{{.Id}}"> | <div class="item" data-value="{{.Id}}"> | ||||
| <img class="ui mini avatar image" src="{{.AvatarLink}}"> | |||||
| <img class="ui mini image" src="{{.AvatarLink}}"> | |||||
| {{.Name}} | {{.Name}} | ||||
| </div> | </div> | ||||
| {{end}} | {{end}} | ||||