parent
7bab3d2fb1
commit
ab62da283a
8 changed files with 111 additions and 37 deletions
|
@ -315,10 +315,9 @@ func (u *User) generateRandomAvatar(e Engine) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RelAvatarLink returns relative avatar link to the site domain,
|
||||
// which includes app sub-url as prefix. However, it is possible
|
||||
// to return full URL if user enables Gravatar-like service.
|
||||
func (u *User) RelAvatarLink() string {
|
||||
// SizedRelAvatarLink returns a relative link to the user's avatar. When
|
||||
// applicable, the link is for an avatar of the indicated size (in pixels).
|
||||
func (u *User) SizedRelAvatarLink(size int) string {
|
||||
if u.ID == -1 {
|
||||
return base.DefaultAvatarLink()
|
||||
}
|
||||
|
@ -338,7 +337,14 @@ func (u *User) RelAvatarLink() string {
|
|||
|
||||
return setting.AppSubURL + "/avatars/" + u.Avatar
|
||||
}
|
||||
return base.AvatarLink(u.AvatarEmail)
|
||||
return base.SizedAvatarLink(u.AvatarEmail, size)
|
||||
}
|
||||
|
||||
// RelAvatarLink returns a relative link to the user's avatar. The link
|
||||
// may either be a sub-URL to this site, or a full URL to an external avatar
|
||||
// service.
|
||||
func (u *User) RelAvatarLink() string {
|
||||
return u.SizedRelAvatarLink(base.DefaultAvatarSize)
|
||||
}
|
||||
|
||||
// AvatarLink returns user avatar absolute link.
|
||||
|
|
|
@ -16,6 +16,8 @@ import (
|
|||
"math"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -197,24 +199,59 @@ func DefaultAvatarLink() string {
|
|||
return setting.AppSubURL + "/img/avatar_default.png"
|
||||
}
|
||||
|
||||
// DefaultAvatarSize is a sentinel value for the default avatar size, as
|
||||
// determined by the avatar-hosting service.
|
||||
const DefaultAvatarSize = -1
|
||||
|
||||
// libravatarURL returns the URL for the given email. This function should only
|
||||
// be called if a federated avatar service is enabled.
|
||||
func libravatarURL(email string) (*url.URL, error) {
|
||||
urlStr, err := setting.LibravatarService.FromEmail(email)
|
||||
if err != nil {
|
||||
log.Error(4, "LibravatarService.FromEmail(email=%s): error %v", email, err)
|
||||
return nil, err
|
||||
}
|
||||
u, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
log.Error(4, "Failed to parse libravatar url(%s): error %v", urlStr, err)
|
||||
return nil, err
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// SizedAvatarLink returns a sized link to the avatar for the given email
|
||||
// address.
|
||||
func SizedAvatarLink(email string, size int) string {
|
||||
var avatarURL *url.URL
|
||||
if setting.EnableFederatedAvatar && setting.LibravatarService != nil {
|
||||
var err error
|
||||
avatarURL, err = libravatarURL(email)
|
||||
if err != nil {
|
||||
return DefaultAvatarLink()
|
||||
}
|
||||
} else if !setting.DisableGravatar {
|
||||
// copy GravatarSourceURL, because we will modify its Path.
|
||||
copyOfGravatarSourceURL := *setting.GravatarSourceURL
|
||||
avatarURL = ©OfGravatarSourceURL
|
||||
avatarURL.Path = path.Join(avatarURL.Path, HashEmail(email))
|
||||
} else {
|
||||
return DefaultAvatarLink()
|
||||
}
|
||||
|
||||
vals := avatarURL.Query()
|
||||
vals.Set("d", "identicon")
|
||||
if size != DefaultAvatarSize {
|
||||
vals.Set("s", strconv.Itoa(size))
|
||||
}
|
||||
avatarURL.RawQuery = vals.Encode()
|
||||
return avatarURL.String()
|
||||
}
|
||||
|
||||
// AvatarLink returns relative avatar link to the site domain by given email,
|
||||
// which includes app sub-url as prefix. However, it is possible
|
||||
// to return full URL if user enables Gravatar-like service.
|
||||
func AvatarLink(email string) string {
|
||||
if setting.EnableFederatedAvatar && setting.LibravatarService != nil {
|
||||
url, err := setting.LibravatarService.FromEmail(email)
|
||||
if err != nil {
|
||||
log.Error(4, "LibravatarService.FromEmail(email=%s): error %v", email, err)
|
||||
return DefaultAvatarLink()
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
if !setting.DisableGravatar {
|
||||
return setting.GravatarSource + HashEmail(email) + "?d=identicon"
|
||||
}
|
||||
|
||||
return DefaultAvatarLink()
|
||||
return SizedAvatarLink(email, DefaultAvatarSize)
|
||||
}
|
||||
|
||||
// Seconds-based time units
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package base
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/Unknwon/i18n"
|
||||
macaroni18n "github.com/go-macaron/i18n"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -126,16 +128,40 @@ func TestHashEmail(t *testing.T) {
|
|||
)
|
||||
}
|
||||
|
||||
func TestAvatarLink(t *testing.T) {
|
||||
const gravatarSource = "https://secure.gravatar.com/avatar/"
|
||||
|
||||
func disableGravatar() {
|
||||
setting.EnableFederatedAvatar = false
|
||||
setting.LibravatarService = nil
|
||||
setting.DisableGravatar = true
|
||||
}
|
||||
|
||||
assert.Equal(t, "/img/avatar_default.png", AvatarLink(""))
|
||||
|
||||
func enableGravatar(t *testing.T) {
|
||||
setting.DisableGravatar = false
|
||||
var err error
|
||||
setting.GravatarSourceURL, err = url.Parse(gravatarSource)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSizedAvatarLink(t *testing.T) {
|
||||
disableGravatar()
|
||||
assert.Equal(t, "/img/avatar_default.png",
|
||||
SizedAvatarLink("gitea@example.com", 100))
|
||||
|
||||
enableGravatar(t)
|
||||
assert.Equal(t,
|
||||
"353cbad9b58e69c96154ad99f92bedc7?d=identicon",
|
||||
"https://secure.gravatar.com/avatar/353cbad9b58e69c96154ad99f92bedc7?d=identicon&s=100",
|
||||
SizedAvatarLink("gitea@example.com", 100),
|
||||
)
|
||||
}
|
||||
|
||||
func TestAvatarLink(t *testing.T) {
|
||||
disableGravatar()
|
||||
assert.Equal(t, "/img/avatar_default.png", AvatarLink("gitea@example.com"))
|
||||
|
||||
enableGravatar(t)
|
||||
assert.Equal(t,
|
||||
"https://secure.gravatar.com/avatar/353cbad9b58e69c96154ad99f92bedc7?d=identicon",
|
||||
AvatarLink("gitea@example.com"),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -326,6 +326,7 @@ var (
|
|||
// Picture settings
|
||||
AvatarUploadPath string
|
||||
GravatarSource string
|
||||
GravatarSourceURL *url.URL
|
||||
DisableGravatar bool
|
||||
EnableFederatedAvatar bool
|
||||
LibravatarService *libravatar.Libravatar
|
||||
|
@ -1027,18 +1028,22 @@ func NewContext() {
|
|||
if DisableGravatar {
|
||||
EnableFederatedAvatar = false
|
||||
}
|
||||
if EnableFederatedAvatar || !DisableGravatar {
|
||||
GravatarSourceURL, err = url.Parse(GravatarSource)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to parse Gravatar URL(%s): %v",
|
||||
GravatarSource, err)
|
||||
}
|
||||
}
|
||||
|
||||
if EnableFederatedAvatar {
|
||||
LibravatarService = libravatar.New()
|
||||
parts := strings.Split(GravatarSource, "/")
|
||||
if len(parts) >= 3 {
|
||||
if parts[0] == "https:" {
|
||||
if GravatarSourceURL.Scheme == "https" {
|
||||
LibravatarService.SetUseHTTPS(true)
|
||||
LibravatarService.SetSecureFallbackHost(parts[2])
|
||||
LibravatarService.SetSecureFallbackHost(GravatarSourceURL.Host)
|
||||
} else {
|
||||
LibravatarService.SetUseHTTPS(false)
|
||||
LibravatarService.SetFallbackHost(parts[2])
|
||||
}
|
||||
LibravatarService.SetFallbackHost(GravatarSourceURL.Host)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="ui vertically grid head">
|
||||
<div class="column">
|
||||
<div class="ui header">
|
||||
<img class="ui image" src="{{.RelAvatarLink}}?s=100">
|
||||
<img class="ui image" src="{{.SizedRelAvatarLink 100}}">
|
||||
<span class="text thin grey"><a href="{{.HomeLink}}">{{.DisplayName}}</a></span>
|
||||
|
||||
<div class="ui right">
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="ui container">
|
||||
<div class="ui grid">
|
||||
<div class="ui sixteen wide column">
|
||||
<img class="ui left" id="org-avatar" src="{{.Org.RelAvatarLink}}?s=140"/>
|
||||
<img class="ui left" id="org-avatar" src="{{.Org.SizedRelAvatarLink 140}}"/>
|
||||
<div id="org-info">
|
||||
<div class="ui header">
|
||||
{{.Org.DisplayName}}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
{{range .Members}}
|
||||
<div class="item ui grid">
|
||||
<div class="ui one wide column">
|
||||
<img class="ui avatar" src="{{.RelAvatarLink}}?s=48">
|
||||
<img class="ui avatar" src="{{.SizedRelAvatarLink 48}}">
|
||||
</div>
|
||||
<div class="ui three wide column">
|
||||
<div class="meta"><a href="{{.HomeLink}}">{{.Name}}</a></div>
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
<div class="ui card">
|
||||
{{if eq .SignedUserName .Owner.Name}}
|
||||
<a class="image poping up" href="{{AppSubUrl}}/user/settings/avatar" id="profile-avatar" data-content="{{.i18n.Tr "user.change_avatar"}}" data-variation="inverted tiny" data-position="bottom center">
|
||||
<img src="{{.Owner.RelAvatarLink}}?s=290" title="{{.Owner.Name}}"/>
|
||||
<img src="{{.Owner.SizedRelAvatarLink 290}}" title="{{.Owner.Name}}"/>
|
||||
</a>
|
||||
{{else}}
|
||||
<span class="image">
|
||||
<img src="{{.Owner.RelAvatarLink}}?s=290" title="{{.Owner.Name}}"/>
|
||||
<img src="{{.Owner.SizedRelAvatarLink 290}}" title="{{.Owner.Name}}"/>
|
||||
</span>
|
||||
{{end}}
|
||||
<div class="content">
|
||||
|
|
Reference in a new issue