refactor(db): move some methods off `user.go` (#7199)

pull/7200/head
Joe Chen 2022-10-22 20:01:38 +08:00 committed by GitHub
parent 7cbd84d5b3
commit ce25881c88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 274 additions and 197 deletions

View File

@ -99,7 +99,7 @@ func newMacaron() *macaron.Macaron {
conf.Picture.AvatarUploadPath,
macaron.StaticOptions{
ETag: true,
Prefix: conf.UsersAvatarURLPath,
Prefix: conf.UsersAvatarPathPrefix,
SkipLogging: conf.Server.DisableRouterLog,
},
))

View File

@ -55,3 +55,11 @@ func SetMockUI(t *testing.T, opts UIOpts) {
UI = before
})
}
func SetMockPicture(t *testing.T, opts PictureOpts) {
before := Picture
Picture = opts
t.Cleanup(func() {
Picture = before
})
}

View File

@ -12,12 +12,6 @@ import (
"github.com/gogs/go-libravatar"
)
const (
// UsersAvatarURLPath is used to identify whether a URL is to access user
// avatars.
UsersAvatarURLPath = "avatars"
)
// README: This file contains static values that should only be set at initialization time.
//
// ⚠️ WARNING: After changing any options, do not forget to update template of
@ -132,18 +126,6 @@ var (
FormatLayout string `ini:"-"` // Actual layout of the Format.
}
// Picture settings
Picture struct {
AvatarUploadPath string
RepositoryAvatarUploadPath string
GravatarSource string
DisableGravatar bool
EnableFederatedAvatar bool
// Derived from other static values
LibravatarService *libravatar.Libravatar `ini:"-"` // Initialized client for federated avatar.
}
// Mirror settings
Mirror struct {
DefaultInterval int
@ -408,6 +390,20 @@ type UIOpts struct {
// UI settings
var UI UIOpts
type PictureOpts struct {
AvatarUploadPath string
RepositoryAvatarUploadPath string
GravatarSource string
DisableGravatar bool
EnableFederatedAvatar bool
// Derived from other static values
LibravatarService *libravatar.Libravatar `ini:"-"` // Initialized client for federated avatar.
}
// Picture settings
var Picture PictureOpts
type i18nConf struct {
Langs []string `delim:","`
Names []string `delim:","`
@ -448,3 +444,11 @@ var (
UsePostgreSQL bool
UseMSSQL bool
)
// UsersAvatarPathPrefix is the path prefix to user avatars.
const UsersAvatarPathPrefix = "avatars"
// UserDefaultAvatarURLPath returns the URL path of the default user avatar.
func UserDefaultAvatarURLPath() string {
return Server.Subpath + "/img/avatar_default.png"
}

View File

@ -954,7 +954,7 @@ func (pcs *PushCommits) AvatarLink(email string) string {
log.Error("Failed to get user [email: %s]: %v", email, err)
}
} else {
pcs.avatars[email] = u.RelAvatarLink()
pcs.avatars[email] = u.AvatarURLPath()
}
}

View File

@ -14,6 +14,7 @@ import (
"xorm.io/xorm"
"gogs.io/gogs/internal/errutil"
"gogs.io/gogs/internal/userutil"
)
var ErrOrgNotExist = errors.New("Organization does not exist")
@ -131,7 +132,7 @@ func CreateOrganization(org, owner *User) (err error) {
if _, err = sess.Insert(org); err != nil {
return fmt.Errorf("insert organization: %v", err)
}
_ = org.GenerateRandomAvatar()
_ = userutil.GenerateRandomAvatar(org.ID, org.Name, org.Email)
// Add initial creator to organization and owner team.
if _, err = sess.Insert(&OrgUser{

View File

@ -34,6 +34,7 @@ import (
"gogs.io/gogs/internal/errutil"
"gogs.io/gogs/internal/strutil"
"gogs.io/gogs/internal/tool"
"gogs.io/gogs/internal/userutil"
)
// TODO(unknwon): Delete me once refactoring is done.
@ -60,75 +61,6 @@ func (u *User) AfterSet(colName string, _ xorm.Cell) {
}
}
// CustomAvatarPath returns user custom avatar file path.
func (u *User) CustomAvatarPath() string {
return filepath.Join(conf.Picture.AvatarUploadPath, com.ToStr(u.ID))
}
// GenerateRandomAvatar generates a random avatar for user.
func (u *User) GenerateRandomAvatar() error {
seed := u.Email
if seed == "" {
seed = u.Name
}
img, err := avatar.RandomImage([]byte(seed))
if err != nil {
return fmt.Errorf("RandomImage: %v", err)
}
if err = os.MkdirAll(filepath.Dir(u.CustomAvatarPath()), os.ModePerm); err != nil {
return fmt.Errorf("MkdirAll: %v", err)
}
fw, err := os.Create(u.CustomAvatarPath())
if err != nil {
return fmt.Errorf("Create: %v", err)
}
defer fw.Close()
if err = png.Encode(fw, img); err != nil {
return fmt.Errorf("Encode: %v", err)
}
log.Info("New random avatar created: %d", u.ID)
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 {
defaultImgUrl := conf.Server.Subpath + "/img/avatar_default.png"
if u.ID == -1 {
return defaultImgUrl
}
switch {
case u.UseCustomAvatar:
if !com.IsExist(u.CustomAvatarPath()) {
return defaultImgUrl
}
return fmt.Sprintf("%s/%s/%d", conf.Server.Subpath, conf.UsersAvatarURLPath, u.ID)
case conf.Picture.DisableGravatar:
if !com.IsExist(u.CustomAvatarPath()) {
if err := u.GenerateRandomAvatar(); err != nil {
log.Error("GenerateRandomAvatar: %v", err)
}
}
return fmt.Sprintf("%s/%s/%d", conf.Server.Subpath, conf.UsersAvatarURLPath, u.ID)
}
return tool.AvatarLink(u.AvatarEmail)
}
// AvatarLink returns user avatar absolute link.
func (u *User) AvatarLink() string {
link := u.RelAvatarLink()
if link[0] == '/' && link[1] != '/' {
return conf.Server.ExternalURL + strings.TrimPrefix(link, conf.Server.Subpath)[1:]
}
return link
}
// User.GetFollowers returns range of user's followers.
func (u *User) GetFollowers(page int) ([]*User, error) {
users := make([]*User, 0, ItemsPerPage)
@ -188,7 +120,7 @@ func (u *User) UploadAvatar(data []byte) error {
}
_ = os.MkdirAll(conf.Picture.AvatarUploadPath, os.ModePerm)
fw, err := os.Create(u.CustomAvatarPath())
fw, err := os.Create(userutil.CustomAvatarPath(u.ID))
if err != nil {
return fmt.Errorf("create custom avatar directory: %v", err)
}
@ -204,8 +136,9 @@ func (u *User) UploadAvatar(data []byte) error {
// DeleteAvatar deletes the user's custom avatar.
func (u *User) DeleteAvatar() error {
log.Trace("DeleteAvatar [%d]: %s", u.ID, u.CustomAvatarPath())
if err := os.Remove(u.CustomAvatarPath()); err != nil {
avatarPath := userutil.CustomAvatarPath(u.ID)
log.Trace("DeleteAvatar [%d]: %s", u.ID, avatarPath)
if err := os.Remove(avatarPath); err != nil {
return err
}
@ -705,7 +638,7 @@ func deleteUser(e *xorm.Session, u *User) error {
// so just keep error logs of those operations.
_ = os.RemoveAll(UserPath(u.Name))
_ = os.Remove(u.CustomAvatarPath())
_ = os.Remove(userutil.CustomAvatarPath(u.ID))
return nil
}

View File

@ -14,11 +14,15 @@ import (
api "github.com/gogs/go-gogs-client"
"github.com/pkg/errors"
"gorm.io/gorm"
log "unknwon.dev/clog/v2"
"gogs.io/gogs/internal/auth"
"gogs.io/gogs/internal/conf"
"gogs.io/gogs/internal/cryptoutil"
"gogs.io/gogs/internal/errutil"
"gogs.io/gogs/internal/osutil"
"gogs.io/gogs/internal/tool"
"gogs.io/gogs/internal/userutil"
)
// UsersStore is the persistent interface for users.
@ -432,7 +436,7 @@ func (u *User) APIFormat() *api.User {
Login: u.Name,
FullName: u.FullName,
Email: u.Email,
AvatarUrl: u.AvatarLink(),
AvatarUrl: u.AvatarURL(),
}
}
@ -474,7 +478,7 @@ func (u *User) HomeURLPath() string {
return conf.Server.Subpath + "/" + u.Name
}
// HTMLURL returns the HTML URL to the user or organization home page.
// HTMLURL returns the full URL to the user or organization home page.
//
// TODO(unknwon): This is also used in templates, which should be fixed by
// having a dedicated type `template.User` and move this to the "userutil"
@ -482,3 +486,47 @@ func (u *User) HomeURLPath() string {
func (u *User) HTMLURL() string {
return conf.Server.ExternalURL + u.Name
}
// AvatarURLPath returns the URL path to the user or organization avatar. If the
// user enables Gravatar-like service, then an external URL will be returned.
//
// TODO(unknwon): This is also used in templates, which should be fixed by
// having a dedicated type `template.User` and move this to the "userutil"
// package.
func (u *User) AvatarURLPath() string {
defaultURLPath := conf.UserDefaultAvatarURLPath()
if u.ID <= 0 {
return defaultURLPath
}
hasCustomAvatar := osutil.IsFile(userutil.CustomAvatarPath(u.ID))
switch {
case u.UseCustomAvatar:
if !hasCustomAvatar {
return defaultURLPath
}
return fmt.Sprintf("%s/%s/%d", conf.Server.Subpath, conf.UsersAvatarPathPrefix, u.ID)
case conf.Picture.DisableGravatar:
if !hasCustomAvatar {
if err := userutil.GenerateRandomAvatar(u.ID, u.Name, u.Email); err != nil {
log.Error("Failed to generate random avatar [user_id: %d]: %v", u.ID, err)
}
}
return fmt.Sprintf("%s/%s/%d", conf.Server.Subpath, conf.UsersAvatarPathPrefix, u.ID)
}
return tool.AvatarLink(u.AvatarEmail)
}
// AvatarURL returns the full URL to the user or organization avatar. If the
// user enables Gravatar-like service, then an external URL will be returned.
//
// TODO(unknwon): This is also used in templates, which should be fixed by
// having a dedicated type `template.User` and move this to the "userutil"
// package.
func (u *User) AvatarURL() string {
link := u.AvatarURLPath()
if link[0] == '/' && link[1] != '/' {
return conf.Server.ExternalURL + strings.TrimPrefix(link, conf.Server.Subpath)[1:]
}
return link
}

View File

@ -120,7 +120,7 @@ func ToDeployKey(apiLink string, key *db.DeployKey) *api.DeployKey {
func ToOrganization(org *db.User) *api.Organization {
return &api.Organization{
ID: org.ID,
AvatarUrl: org.AvatarLink(),
AvatarUrl: org.AvatarURL(),
UserName: org.Name,
FullName: org.FullName,
Description: org.Description,

View File

@ -40,7 +40,7 @@ func Search(c *context.APIContext) {
results[i] = &api.User{
ID: users[i].ID,
UserName: users[i].Name,
AvatarUrl: users[i].AvatarLink(),
AvatarUrl: users[i].AvatarURL(),
FullName: markup.Sanitize(users[i].FullName),
}
if c.IsLogged {

View File

@ -82,7 +82,7 @@ func retrieveFeeds(c *context.Context, ctxUser *db.User, userID int64, isProfile
c.Error(err, "get user by name")
return
}
unameAvatars[act.ActUserName] = u.RelAvatarLink()
unameAvatars[act.ActUserName] = u.AvatarURLPath()
}
act.ActAvatar = unameAvatars[act.ActUserName]

View File

@ -27,6 +27,7 @@ import (
"gogs.io/gogs/internal/email"
"gogs.io/gogs/internal/form"
"gogs.io/gogs/internal/tool"
"gogs.io/gogs/internal/userutil"
)
const (
@ -144,8 +145,8 @@ func UpdateAvatarSetting(c *context.Context, f form.Avatar, ctxUser *db.User) er
} else {
// No avatar is uploaded but setting has been changed to enable,
// generate a random one when needed.
if ctxUser.UseCustomAvatar && !com.IsFile(ctxUser.CustomAvatarPath()) {
if err := ctxUser.GenerateRandomAvatar(); err != nil {
if ctxUser.UseCustomAvatar && !com.IsFile(userutil.CustomAvatarPath(ctxUser.ID)) {
if err := userutil.GenerateRandomAvatar(ctxUser.ID, ctxUser.Name, ctxUser.Email); err != nil {
log.Error("generate random avatar [%d]: %v", ctxUser.ID, err)
}
}

View File

@ -7,8 +7,15 @@ package userutil
import (
"encoding/hex"
"fmt"
"image/png"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/pkg/errors"
"gogs.io/gogs/internal/avatar"
"gogs.io/gogs/internal/conf"
"gogs.io/gogs/internal/tool"
)
@ -23,9 +30,9 @@ func DashboardURLPath(name string, isOrganization bool) string {
// GenerateActivateCode generates an activate code based on user information and
// the given email.
func GenerateActivateCode(id int64, email, name, password, rands string) string {
func GenerateActivateCode(userID int64, email, name, password, rands string) string {
code := tool.CreateTimeLimitCode(
fmt.Sprintf("%d%s%s%s%s", id, email, strings.ToLower(name), password, rands),
fmt.Sprintf("%d%s%s%s%s", userID, email, strings.ToLower(name), password, rands),
conf.Auth.ActivateCodeLives,
nil,
)
@ -34,3 +41,39 @@ func GenerateActivateCode(id int64, email, name, password, rands string) string
code += hex.EncodeToString([]byte(strings.ToLower(name)))
return code
}
// CustomAvatarPath returns the absolute path of the user custom avatar file.
func CustomAvatarPath(userID int64) string {
return filepath.Join(conf.Picture.AvatarUploadPath, strconv.FormatInt(userID, 10))
}
// GenerateRandomAvatar generates a random avatar and stores to local file
// system using given user information.
func GenerateRandomAvatar(userID int64, name, email string) error {
seed := email
if seed == "" {
seed = name
}
img, err := avatar.RandomImage([]byte(seed))
if err != nil {
return errors.Wrap(err, "generate random image")
}
avatarPath := CustomAvatarPath(userID)
err = os.MkdirAll(filepath.Dir(avatarPath), os.ModePerm)
if err != nil {
return errors.Wrap(err, "create avatar directory")
}
f, err := os.Create(avatarPath)
if err != nil {
return errors.Wrap(err, "create avatar file")
}
defer func() { _ = f.Close() }()
if err = png.Encode(f, img); err != nil {
return errors.Wrap(err, "encode avatar image to file")
}
return nil
}

View File

@ -5,11 +5,15 @@
package userutil
import (
"os"
"runtime"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gogs.io/gogs/internal/conf"
"gogs.io/gogs/internal/osutil"
"gogs.io/gogs/internal/tool"
)
@ -38,3 +42,38 @@ func TestGenerateActivateCode(t *testing.T) {
got := tool.VerifyTimeLimitCode("1alice@example.comalice123456rands", conf.Auth.ActivateCodeLives, code[:tool.TIME_LIMIT_CODE_LENGTH])
assert.True(t, got)
}
func TestCustomAvatarPath(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping testing on Windows")
return
}
conf.SetMockPicture(t,
conf.PictureOpts{
AvatarUploadPath: "data/avatars",
},
)
got := CustomAvatarPath(1)
want := "data/avatars/1"
assert.Equal(t, want, got)
}
func TestGenerateRandomAvatar(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping testing on Windows")
return
}
conf.SetMockPicture(t,
conf.PictureOpts{
AvatarUploadPath: os.TempDir(),
},
)
err := GenerateRandomAvatar(1, "alice", "alice@example.com")
require.NoError(t, err)
got := osutil.IsFile(CustomAvatarPath(1))
assert.True(t, got)
}

View File

@ -28,7 +28,7 @@
{{range .Users}}
<tr>
<td>{{.ID}}</td>
<td><a href="{{.HomeLink}}">{{.Name}}</a></td>
<td><a href="{{.HomeURLPath}}">{{.Name}}</a></td>
<td>{{.NumTeams}}</td>
<td>{{.NumMembers}}</td>
<td>{{.NumRepos}}</td>

View File

@ -19,13 +19,13 @@
<meta property="og:type" content="profile" />
<meta property="og:title" content="{{.Owner.Name}}{{if .Owner.FullName}} ({{.Owner.FullName}}){{end}}">
<meta property="og:description" content="{{.Owner.Name}} has {{.Owner.NumFollowers}} followers and is following {{.Owner.NumFollowing}} people.">
<meta property="og:image" content="{{.Owner.AvatarLink}}" />
<meta property="og:image" content="{{.Owner.AvatarURL}}" />
{{else if .Repository}}
<meta property="og:url" content="{{.Repository.HTMLURL}}" />
<meta property="og:type" content="object" />
<meta property="og:title" content="{{.Repository.FullName}}">
<meta property="og:description" content="{{.Repository.Description}}">
<meta property="og:image" content="{{.Repository.Owner.AvatarLink}}" />
<meta property="og:image" content="{{.Repository.Owner.AvatarURL}}" />
{{else}}
<meta property="og:url" content="{{AppURL}}" />
<meta property="og:type" content="website" />
@ -132,7 +132,7 @@
<div class="ui dropdown head link jump item poping up" tabindex="-1" data-content="{{.i18n.Tr "user_profile_and_more"}}" data-variation="tiny inverted">
<span class="text avatar">
<img class="ui small rounded image" src="{{.LoggedUser.RelAvatarLink}}">
<img class="ui small rounded image" src="{{.LoggedUser.AvatarURLPath}}">
<span class="sr-only">{{.i18n.Tr "user_profile_and_more"}}</span>
<i class="octicon octicon-triangle-down" tabindex="-1"></i>
</span>

View File

@ -9,9 +9,9 @@
<div class="ui user list">
{{range .Users}}
<div class="item">
<img class="ui avatar image" src="{{.RelAvatarLink}}">
<img class="ui avatar image" src="{{.AvatarURLPath}}">
<div class="content">
<span class="header"><a href="{{.HomeLink}}">{{.Name}}</a> {{.FullName}}</span>
<span class="header"><a href="{{.HomeURLPath}}">{{.Name}}</a> {{.FullName}}</span>
<div class="description">
{{if .Location}}
<i class="octicon octicon-location"></i> {{.Location}}

View File

@ -9,9 +9,9 @@
<div class="ui user list">
{{range .Users}}
<div class="item">
<img class="ui avatar image" src="{{.RelAvatarLink}}">
<img class="ui avatar image" src="{{.AvatarURLPath}}">
<div class="content">
<span class="header"><a href="{{.HomeLink}}">{{.Name}}</a> {{.FullName}}</span>
<span class="header"><a href="{{.HomeURLPath}}">{{.Name}}</a> {{.FullName}}</span>
<div class="description">
{{if .Location}}
<i class="octicon octicon-location"></i> {{.Location}}

View File

@ -3,8 +3,8 @@
<div class="ui vertically grid head">
<div class="column">
<div class="ui header">
<img class="ui image" src="{{.RelAvatarLink}}?s=100">
<span class="text thin grey"><a href="{{.HomeLink}}">{{.DisplayName}}</a></span>
<img class="ui image" src="{{.AvatarURLPath}}?s=100">
<span class="text thin grey"><a href="{{.HomeURLPath}}">{{.DisplayName}}</a></span>
<div class="ui right">
<div class="ui menu">

View File

@ -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.AvatarURLPath}}?s=140"/>
<div id="org-info">
<div class="ui header">
{{.Org.DisplayName}}
@ -48,7 +48,7 @@
{{$isMember := .IsOrganizationMember}}
{{range .Members}}
{{if or $isMember (.IsPublicMember $.Org.ID)}}
<a href="{{.HomeLink}}" title="{{.Name}}{{if .FullName}} ({{.FullName}}){{end}}"><img class="ui avatar" src="{{.RelAvatarLink}}"></a>
<a href="{{.HomeURLPath}}" title="{{.Name}}{{if .FullName}} ({{.FullName}}){{end}}"><img class="ui avatar" src="{{.AvatarURLPath}}"></a>
{{end}}
{{end}}
</div>

View File

@ -14,10 +14,10 @@
{{range .Members}}
<div class="item ui grid">
<div class="ui one wide column">
<img class="ui avatar" src="{{AppendAvatarSize .RelAvatarLink 48}}">
<img class="ui avatar" src="{{AppendAvatarSize .AvatarURLPath 48}}">
</div>
<div class="ui three wide column">
<div class="meta"><a href="{{.HomeLink}}">{{.Name}}</a></div>
<div class="meta"><a href="{{.HomeURLPath}}">{{.Name}}</a></div>
<div class="meta">{{.FullName}}</div>
</div>
<div class="ui five wide column center">

View File

@ -15,8 +15,8 @@
{{if $.IsOrganizationOwner}}
<a class="ui red small button right" href="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/remove?uid={{.ID}}">{{$.i18n.Tr "org.members.remove"}}</a>
{{end}}
<a href="{{.HomeLink}}">
<img class="ui avatar image" src="{{.RelAvatarLink}}">
<a href="{{.HomeURLPath}}">
<img class="ui avatar image" src="{{.AvatarURLPath}}">
{{.DisplayName}}
</a>
</div>

View File

@ -25,8 +25,8 @@
</div>
<div class="ui attached segment members">
{{range .Members}}
<a href="{{.HomeLink}}" title="{{.Name}}">
<img class="ui avatar image" src="{{.RelAvatarLink}}">
<a href="{{.HomeURLPath}}" title="{{.Name}}">
<img class="ui avatar image" src="{{.AvatarURLPath}}">
</a>
{{end}}
</div>

View File

@ -33,7 +33,7 @@
<tr>
<td class="author">
{{if .User}}
<img class="ui avatar image" src="{{.User.RelAvatarLink}}" alt=""/>&nbsp;&nbsp;<a href="{{AppSubURL}}/{{.User.Name}}">{{.Author.Name}}</a>
<img class="ui avatar image" src="{{.User.AvatarURLPath}}" alt=""/>&nbsp;&nbsp;<a href="{{AppSubURL}}/{{.User.Name}}">{{.Author.Name}}</a>
{{else}}
<img class="ui avatar image" src="{{AvatarLink .Author.Email}}" alt=""/>&nbsp;&nbsp;{{.Author.Name}}
{{end}}

View File

@ -14,18 +14,18 @@
<div class="ui selection owner dropdown">
<input type="hidden" id="user_id" name="user_id" value="{{.ContextUser.ID}}" required>
<span class="text">
<img class="ui mini image" src="{{.ContextUser.RelAvatarLink}}">
<img class="ui mini image" src="{{.ContextUser.AvatarURLPath}}">
{{.ContextUser.ShortName 20}}
</span>
<i class="dropdown icon"></i>
<div class="menu">
<div class="item" data-value="{{.LoggedUser.ID}}">
<img class="ui mini image" src="{{.LoggedUser.RelAvatarLink}}">
<img class="ui mini image" src="{{.LoggedUser.AvatarURLPath}}">
{{.LoggedUser.ShortName 20}}
</div>
{{range .Orgs}}
<div class="item" data-value="{{.ID}}">
<img class="ui mini image" src="{{.RelAvatarLink}}">
<img class="ui mini image" src="{{.AvatarURLPath}}">
{{.ShortName 20}}
</div>
{{end}}

View File

@ -15,8 +15,8 @@
</div>
<div class="ui attached info segment">
{{if .Author}}
<img class="ui avatar image" src="{{.Author.RelAvatarLink}}" />
<a href="{{.Author.HomeLink}}"><strong>{{.Commit.Author.Name}}</strong></a> {{if .IsLogged}}<{{.Commit.Author.Email}}>{{end}}
<img class="ui avatar image" src="{{.Author.AvatarURLPath}}" />
<a href="{{.Author.HomeURLPath}}"><strong>{{.Commit.Author.Name}}</strong></a> {{if .IsLogged}}<{{.Commit.Author.Email}}>{{end}}
{{else}}
<img class="ui avatar image" src="{{AvatarLink .Commit.Author.Email}}" />
<strong>{{.Commit.Author.Name}}</strong>

View File

@ -1,5 +1,5 @@
<div class="commit-form-wrapper">
<img width="48" height="48" class="ui image commit-avatar" src="{{.LoggedUser.RelAvatarLink}}">
<img width="48" height="48" class="ui image commit-avatar" src="{{.LoggedUser.AvatarURLPath}}">
<div class="commit-form">
<h3>{{.i18n.Tr "repo.editor.commit_changes"}}</h3>
<div class="field">
@ -41,4 +41,4 @@
{{.i18n.Tr "repo.editor.commit_changes"}}
</button>
<a class="ui button red" href="{{EscapePound $.BranchLink}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.editor.cancel"}}</a>
</div>
</div>

View File

@ -8,7 +8,7 @@
<div class="ui list">
{{range .Forks}}
<div class="item">
<img class="ui avatar image" src="{{.Owner.RelAvatarLink}}">
<img class="ui avatar image" src="{{.Owner.AvatarURLPath}}">
<div class="link">
<a href="{{AppSubURL}}/{{.Owner.Name}}">{{.Owner.Name}}</a>
/

View File

@ -61,7 +61,7 @@
<div class="menu">
<a class="item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}">{{.i18n.Tr "repo.issues.filter_assginee_no_select"}}</a>
{{range .Assignees}}
<a class="{{if eq $.AssigneeID .ID}}active selected{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{.ID}}"><img src="{{.RelAvatarLink}}"> {{.DisplayName}}</a>
<a class="{{if eq $.AssigneeID .ID}}active selected{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{.ID}}"><img src="{{.AvatarURLPath}}"> {{.DisplayName}}</a>
{{end}}
</div>
</div>
@ -113,15 +113,15 @@
{{end}}
<p class="desc">
{{$.i18n.Tr "repo.issues.opened_by" $timeStr .Poster.HomeLink .Poster.DisplayName | Sanitize | Safe}}
{{$.i18n.Tr "repo.issues.opened_by" $timeStr .Poster.HomeURLPath .Poster.DisplayName | Sanitize | Safe}}
{{if .Milestone}}
<a class="milestone" href="{{$.Link}}?type={{$.ViewType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.Milestone.ID}}&assignee={{$.AssigneeID}}">
<span class="octicon octicon-milestone"></span> {{.Milestone.Name | Sanitize}}
</a>
{{end}}
{{if .Assignee}}
<a class="ui right assignee poping up" href="{{.Assignee.HomeLink}}" data-content="{{.Assignee.DisplayName}}" data-variation="inverted" data-position="left center">
<img class="ui avatar image" src="{{.Assignee.RelAvatarLink}}">
<a class="ui right assignee poping up" href="{{.Assignee.HomeURLPath}}" data-content="{{.Assignee.DisplayName}}" data-variation="inverted" data-position="left center">
<img class="ui avatar image" src="{{.Assignee.AvatarURLPath}}">
</a>
{{end}}
</p>

View File

@ -8,8 +8,8 @@
<div class="twelve wide column">
<div class="ui comments">
<div class="comment">
<a class="avatar" href="{{.LoggedUser.HomeLink}}">
<img src="{{.LoggedUser.RelAvatarLink}}">
<a class="avatar" href="{{.LoggedUser.HomeURLPath}}">
<img src="{{.LoggedUser.AvatarURLPath}}">
</a>
<div class="ui segment content">
<div class="field">
@ -104,7 +104,7 @@
<div class="menu">
<div class="no-select item">{{.i18n.Tr "repo.issues.new.clear_assignee"}}</div>
{{range .Assignees}}
<div class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?assignee={{.ID}}" data-avatar="{{.RelAvatarLink}}"><img src="{{.RelAvatarLink}}"> {{.Name}}</div>
<div class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?assignee={{.ID}}" data-avatar="{{.AvatarURLPath}}"><img src="{{.AvatarURLPath}}"> {{.Name}}</div>
{{end}}
</div>
</div>
@ -112,7 +112,7 @@
<span class="no-select item {{if .Assignee}}hide{{end}}">{{.i18n.Tr "repo.issues.new.no_assignee"}}</span>
<div class="selected">
{{if .Assignee}}
<a class="item" href="{{.RepoLink}}/issues?assignee={{.Assignee.ID}}"><img class="ui avatar image" src="{{.Assignee.RelAvatarLink}}"> {{.Assignee.Name}}</a>
<a class="item" href="{{.RepoLink}}/issues?assignee={{.Assignee.ID}}"><img class="ui avatar image" src="{{.Assignee.AvatarURLPath}}"> {{.Assignee.Name}}</a>
{{end}}
</div>
</div>

View File

@ -12,12 +12,12 @@
<div class="twelve wide column comment-list">
<ui class="ui comments">
<div class="comment">
<a class="avatar" {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>
<img src="{{.Issue.Poster.RelAvatarLink}}">
<a class="avatar" {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeURLPath}}"{{end}}>
<img src="{{.Issue.Poster.AvatarURLPath}}">
</a>
<div class="content">
<div class="ui top attached header">
<span class="text grey"><a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.DisplayName}}</a> {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}}</span>
<span class="text grey"><a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeURLPath}}"{{end}}>{{.Issue.Poster.DisplayName}}</a> {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}}</span>
<div class="ui right actions">
{{if .IsIssueOwner}}
<div class="item action">
@ -61,12 +61,12 @@
<!-- 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE_REF, 4 = COMMIT_REF, 5 = COMMENT_REF, 6 = PULL_REF -->
{{if eq .Type 0}}
<div class="comment" id="{{.HashTag}}">
<a class="avatar" {{if gt .Poster.ID 0}}href="{{.Poster.HomeLink}}"{{end}}>
<img src="{{.Poster.RelAvatarLink}}">
<a class="avatar" {{if gt .Poster.ID 0}}href="{{.Poster.HomeURLPath}}"{{end}}>
<img src="{{.Poster.AvatarURLPath}}">
</a>
<div class="content">
<div class="ui top attached header">
<span class="text grey"><a {{if gt .Poster.ID 0}}href="{{.Poster.HomeLink}}"{{end}}>{{.Poster.DisplayName}}</a> {{$.i18n.Tr "repo.issues.commented_at" .HashTag $createdStr | Safe}}</span>
<span class="text grey"><a {{if gt .Poster.ID 0}}href="{{.Poster.HomeURLPath}}"{{end}}>{{.Poster.DisplayName}}</a> {{$.i18n.Tr "repo.issues.commented_at" .HashTag $createdStr | Safe}}</span>
<div class="ui right actions">
{{if gt .ShowTag 0}}
<div class="item tag">
@ -118,26 +118,26 @@
{{else if eq .Type 1}}
<div class="event">
<span class="octicon octicon-primitive-dot"></span>
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
<img src="{{.Poster.RelAvatarLink}}">
<a class="ui avatar image" href="{{.Poster.HomeURLPath}}">
<img src="{{.Poster.AvatarURLPath}}">
</a>
<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a> {{$.i18n.Tr "repo.issues.reopened_at" .EventTag $createdStr | Safe}}</span>
<span class="text grey"><a href="{{.Poster.HomeURLPath}}">{{.Poster.Name}}</a> {{$.i18n.Tr "repo.issues.reopened_at" .EventTag $createdStr | Safe}}</span>
</div>
{{else if eq .Type 2}}
<div class="event">
<span class="octicon octicon-circle-slash"></span>
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
<img src="{{.Poster.RelAvatarLink}}">
<a class="ui avatar image" href="{{.Poster.HomeURLPath}}">
<img src="{{.Poster.AvatarURLPath}}">
</a>
<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a> {{$.i18n.Tr "repo.issues.closed_at" .EventTag $createdStr | Safe}}</span>
<span class="text grey"><a href="{{.Poster.HomeURLPath}}">{{.Poster.Name}}</a> {{$.i18n.Tr "repo.issues.closed_at" .EventTag $createdStr | Safe}}</span>
</div>
{{else if eq .Type 4}}
<div class="event">
<span class="octicon octicon-bookmark"></span>
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
<img src="{{.Poster.RelAvatarLink}}">
<a class="ui avatar image" href="{{.Poster.HomeURLPath}}">
<img src="{{.Poster.AvatarURLPath}}">
</a>
<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.DisplayName}}</a> {{$.i18n.Tr "repo.issues.commit_ref_at" .EventTag $createdStr | Safe}}</span>
<span class="text grey"><a href="{{.Poster.HomeURLPath}}">{{.Poster.DisplayName}}</a> {{$.i18n.Tr "repo.issues.commit_ref_at" .EventTag $createdStr | Safe}}</span>
<div class="detail">
<span class="octicon octicon-git-commit"></span>
<span class="text grey">{{.Content | Str2HTML}}</span>
@ -237,8 +237,8 @@
{{if .IsLogged}}
<div class="comment form">
<a class="avatar" href="{{.LoggedUser.HomeLink}}">
<img src="{{.LoggedUser.RelAvatarLink}}">
<a class="avatar" href="{{.LoggedUser.HomeURLPath}}">
<img src="{{.LoggedUser.AvatarURLPath}}">
</a>
<div class="content">
<form class="ui segment form" id="comment-form" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/comments" method="post">
@ -347,7 +347,7 @@
<div class="menu" data-action="update" data-update-url="{{$.RepoLink}}/issues/{{$.Issue.Index}}/assignee">
<div class="no-select item">{{.i18n.Tr "repo.issues.new.clear_assignee"}}</div>
{{range .Assignees}}
<div class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?assignee={{.ID}}" data-avatar="{{.RelAvatarLink}}"><img src="{{.RelAvatarLink}}"> {{.DisplayName}}</div>
<div class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?assignee={{.ID}}" data-avatar="{{.AvatarURLPath}}"><img src="{{.AvatarURLPath}}"> {{.DisplayName}}</div>
{{end}}
</div>
</div>
@ -355,7 +355,7 @@
<span class="no-select item {{if .Issue.Assignee}}hide{{end}}">{{.i18n.Tr "repo.issues.new.no_assignee"}}</span>
<div class="selected">
{{if .Issue.Assignee}}
<a class="item" href="{{$.RepoLink}}/issues?assignee={{.Issue.Assignee.ID}}"><img class="ui avatar image" src="{{.Issue.Assignee.RelAvatarLink}}"> {{.Issue.Assignee.DisplayName}}</a>
<a class="item" href="{{$.RepoLink}}/issues?assignee={{.Issue.Assignee.ID}}"><img class="ui avatar image" src="{{.Issue.Assignee.AvatarURLPath}}"> {{.Issue.Assignee.DisplayName}}</a>
{{end}}
</div>
</div>
@ -366,8 +366,8 @@
<span class="text"><strong>{{.i18n.Tr "repo.issues.num_participants" .NumParticipants}}</strong></span>
<div>
{{range .Participants}}
<a href="{{.HomeLink}}">
<img class="ui avatar image poping up" src="{{.RelAvatarLink}}" data-content="{{.DisplayName}}" data-position="top center" data-variation="small inverted">
<a href="{{.HomeURLPath}}">
<img class="ui avatar image poping up" src="{{.AvatarURLPath}}" data-content="{{.DisplayName}}" data-position="top center" data-variation="small inverted">
</a>
{{end}}
</div>

View File

@ -27,17 +27,17 @@
{{if .Issue.IsPull}}
{{if .Issue.PullRequest.HasMerged}}
{{ $mergedStr:= TimeSince .Issue.PullRequest.Merged $.Lang }}
<a {{if gt .Issue.PullRequest.Merger.ID 0}}href="{{.Issue.PullRequest.Merger.HomeLink}}"{{end}}>{{.Issue.PullRequest.Merger.Name}}</a>
<a {{if gt .Issue.PullRequest.Merger.ID 0}}href="{{.Issue.PullRequest.Merger.HomeURLPath}}"{{end}}>{{.Issue.PullRequest.Merger.Name}}</a>
<span class="pull-desc">{{$.i18n.Tr "repo.pulls.merged_title_desc" .NumCommits .HeadTarget .BaseTarget $mergedStr | Str2HTML}}</span>
{{else}}
<a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.Name}}</a>
<a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeURLPath}}"{{end}}>{{.Issue.Poster.Name}}</a>
<span class="pull-desc">{{$.i18n.Tr "repo.pulls.title_desc" .NumCommits .HeadTarget .BaseTarget | Str2HTML}}</span>
{{end}}
{{else}}
{{ $createdStr:= TimeSince .Issue.Created $.Lang }}
<span class="time-desc">
{{if gt .Issue.Poster.ID 0}}
{{$.i18n.Tr "repo.issues.opened_by" $createdStr .Issue.Poster.HomeLink .Issue.Poster.Name | Safe}}
{{$.i18n.Tr "repo.issues.opened_by" $createdStr .Issue.Poster.HomeURLPath .Issue.Poster.Name | Safe}}
{{else}}
{{$.i18n.Tr "repo.issues.opened_by_fake" $createdStr .Issue.Poster.Name | Safe}}
{{end}}

View File

@ -45,18 +45,18 @@
<div class="ui selection owner dropdown">
<input type="hidden" id="uid" name="uid" value="{{.ContextUser.ID}}" required>
<span class="text">
<img class="ui mini image" src="{{.ContextUser.RelAvatarLink}}">
<img class="ui mini image" src="{{.ContextUser.AvatarURLPath}}">
{{.ContextUser.ShortName 20}}
</span>
<i class="dropdown icon"></i>
<div class="menu">
<div class="item" data-value="{{.LoggedUser.ID}}">
<img class="ui mini image" src="{{.LoggedUser.RelAvatarLink}}">
<img class="ui mini image" src="{{.LoggedUser.AvatarURLPath}}">
{{.LoggedUser.ShortName 20}}
</div>
{{range .Orgs}}
<div class="item" data-value="{{.ID}}">
<img class="ui mini image" src="{{.RelAvatarLink}}">
<img class="ui mini image" src="{{.AvatarURLPath}}">
{{.ShortName 20}}
</div>
{{end}}

View File

@ -14,19 +14,19 @@
<div class="ui selection owner dropdown">
<input type="hidden" id="user_id" name="user_id" value="{{.ContextUser.ID}}" required>
<span class="text">
<img class="ui mini image" src="{{.ContextUser.RelAvatarLink}}">
<img class="ui mini image" src="{{.ContextUser.AvatarURLPath}}">
{{.ContextUser.ShortName 20}}
</span>
<i class="dropdown icon"></i>
<div class="menu">
<div class="item" data-value="{{.LoggedUser.ID}}">
<img class="ui mini image" src="{{.LoggedUser.RelAvatarLink}}">
<img class="ui mini image" src="{{.LoggedUser.AvatarURLPath}}">
{{.LoggedUser.ShortName 20}}
</div>
{{range .Orgs}}
{{if .IsOwnedBy $.LoggedUser.ID}}
<div class="item" data-value="{{.ID}}">
<img class="ui mini image" src="{{.RelAvatarLink}}">
<img class="ui mini image" src="{{.AvatarURLPath}}">
{{.ShortName 20}}
</div>
{{end}}

View File

@ -39,7 +39,7 @@
</h3>
<p class="text grey">
<span class="author">
<img class="img-10" src="{{.Publisher.RelAvatarLink}}">
<img class="img-10" src="{{.Publisher.AvatarURLPath}}">
<a href="{{AppSubURL}}/{{.Publisher.Name}}">{{.Publisher.DisplayName}}</a>
</span>
{{if .Created}}<span class="time">{{TimeSince .Created $.Lang}}</span>{{end}}

View File

@ -14,7 +14,7 @@
<div class="item ui grid">
<div class="ui five wide column">
<a href="{{AppSubURL}}/{{.Name}}">
<img class="ui avatar image" src="{{.RelAvatarLink}}">
<img class="ui avatar image" src="{{.AvatarURLPath}}">
{{.DisplayName}}
</a>
</div>

View File

@ -45,7 +45,7 @@
<div class="menu">
{{range .Users}}
<div class="item" data-value="{{.ID}}">
<img class="ui mini image" src="{{.RelAvatarLink}}">
<img class="ui mini image" src="{{.AvatarURLPath}}">
{{.Name}}
</div>
{{end}}

View File

@ -5,10 +5,10 @@
<ul class="list">
{{range .Cards}}
<li class="item ui segment">
<a href="{{.HomeLink}}">
<img class="avatar" src="{{.RelAvatarLink}}"/>
<a href="{{.HomeURLPath}}">
<img class="avatar" src="{{.AvatarURLPath}}"/>
</a>
<h3 class="name"><a href="{{.HomeLink}}">{{.DisplayName}}</a></h3>
<h3 class="name"><a href="{{.HomeURLPath}}">{{.DisplayName}}</a></h3>
<div class="meta">
{{if .Website}}

View File

@ -3,7 +3,7 @@
<tr>
<th class="four wide">
{{if .LatestCommitUser}}
<img class="ui avatar image img-12" src="{{.LatestCommitUser.RelAvatarLink}}" />
<img class="ui avatar image img-12" src="{{.LatestCommitUser.AvatarURLPath}}" />
<a href="{{AppSubURL}}/{{.LatestCommitUser.Name}}"><strong>{{.LatestCommit.Author.Name}}</strong></a>
{{else}}
<img class="ui avatar image img-12" src="{{AvatarLink .LatestCommit.Author.Email}}" />

View File

@ -42,7 +42,7 @@
{{end}}
{{if gt .ContextUser.NumRepos .MaxShowRepoNum}}
<li>
<a href="{{.ContextUser.HomeLink}}">{{.i18n.Tr "home.show_more_repos"}}</a>
<a href="{{.ContextUser.HomeURLPath}}">{{.i18n.Tr "home.show_more_repos"}}</a>
</li>
{{end}}
</ul>

View File

@ -73,7 +73,7 @@
{{if .NumComments}}
<span class="comment ui right"><i class="octicon octicon-comment"></i> {{.NumComments}}</span>
{{end}}
<div>
<span class="ui right">
{{range .Labels}}
@ -83,10 +83,10 @@
</div>
<p class="desc">
{{$.i18n.Tr "repo.issues.opened_by" $timeStr .Poster.HomeLink .Poster.Name | Safe}}
{{$.i18n.Tr "repo.issues.opened_by" $timeStr .Poster.HomeURLPath .Poster.Name | Safe}}
{{if .Assignee}}
<a class="ui right assignee poping up" href="{{.Assignee.HomeLink}}" data-content="{{.Assignee.Name}}" data-variation="inverted" data-position="left center">
<img class="ui avatar image" src="{{.Assignee.RelAvatarLink}}">
<a class="ui right assignee poping up" href="{{.Assignee.HomeURLPath}}" data-content="{{.Assignee.Name}}" data-variation="inverted" data-position="left center">
<img class="ui avatar image" src="{{.Assignee.AvatarURLPath}}">
</a>
{{end}}
</p>

View File

@ -1,7 +1,7 @@
<div class="ui container">
<div class="ui floating dropdown link jump">
<span class="text">
<img class="ui avatar image" src="{{.ContextUser.RelAvatarLink}}">
<img class="ui avatar image" src="{{.ContextUser.AvatarURLPath}}">
{{.ContextUser.ShortName 20}}
<i class="dropdown icon"></i>
</span>
@ -11,12 +11,12 @@
</div>
<div class="items">
<a class="{{if eq .ContextUser.ID .LoggedUser.ID}}active selected{{end}} item" href="{{AppSubURL}}/{{if .PageIsIssues}}issues{{else if .PageIsPulls}}pulls{{end}}">
<img class="ui avatar image" src="{{.LoggedUser.RelAvatarLink}}">
<img class="ui avatar image" src="{{.LoggedUser.AvatarURLPath}}">
{{.LoggedUser.Name}}
</a>
{{range .Orgs}}
<a class="{{if eq $.ContextUser.ID .ID}}active selected{{end}} item" href="{{AppSubURL}}/org/{{.Name}}/{{if $.PageIsIssues}}issues{{else if $.PageIsPulls}}pulls{{else}}dashboard{{end}}">
<img class="ui avatar image" src="{{.RelAvatarLink}}">
<img class="ui avatar image" src="{{.AvatarURLPath}}">
{{.ShortName 20}}
</a>
{{end}}
@ -41,7 +41,7 @@
</a>
<div class="right menu">
<div class="item">
<a class="ui blue basic button" href="{{.ContextUser.HomeLink}}">
<a class="ui blue basic button" href="{{.ContextUser.HomeURLPath}}">
{{.i18n.Tr "home.view_home" (.ContextUser.ShortName 10)}}
</a>
</div>

View File

@ -1,8 +1,8 @@
{{with .Owner}}
<div class="ui container">
<img class="ui avatar image" src="{{.RelAvatarLink}}">
<img class="ui avatar image" src="{{.AvatarURLPath}}">
<span class="header name">
<a href="{{.HomeLink}}">{{.Name}}</a>
<a href="{{.HomeURLPath}}">{{.Name}}</a>
{{with .FullName}}({{.}}){{end}}
</span>
@ -11,9 +11,9 @@
{{if and $.IsLogged (ne $.LoggedUserName .Name)}}
<div class="follow">
{{if $.LoggedUser.IsFollowing .ID}}
<a class="ui small basic red button" href="{{.HomeLink}}/action/unfollow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{$.i18n.Tr "user.unfollow"}}</a>
<a class="ui small basic red button" href="{{.HomeURLPath}}/action/unfollow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{$.i18n.Tr "user.unfollow"}}</a>
{{else}}
<a class="ui small basic green button" href="{{.HomeLink}}/action/follow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{$.i18n.Tr "user.follow"}}</a>
<a class="ui small basic green button" href="{{.HomeURLPath}}/action/follow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{$.i18n.Tr "user.follow"}}</a>
{{end}}
</div>
{{end}}

View File

@ -6,11 +6,11 @@
<div class="ui card">
{{if eq .LoggedUserName .Owner.Name}}
<a class="profile-avatar 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="{{AppendAvatarSize .Owner.RelAvatarLink 287}}" title="{{.Owner.Name}}"/>
<img src="{{AppendAvatarSize .Owner.AvatarURLPath 287}}" title="{{.Owner.Name}}"/>
</a>
{{else}}
<span class="profile-avatar image">
<img src="{{AppendAvatarSize .Owner.RelAvatarLink 287}}" title="{{.Owner.Name}}"/>
<img src="{{AppendAvatarSize .Owner.AvatarURLPath 287}}" title="{{.Owner.Name}}"/>
</span>
{{end}}
<div class="content">
@ -37,11 +37,11 @@
<li><i class="octicon octicon-clock"></i> {{.i18n.Tr "user.join_on"}} {{DateFmtShort .Owner.Created}}</li>
<li>
<i class="octicon octicon-person"></i>
<a href="{{.Owner.HomeLink}}/followers">
<a href="{{.Owner.HomeURLPath}}/followers">
{{.Owner.NumFollowers}} {{.i18n.Tr "user.followers"}}
</a>
-
<a href="{{.Owner.HomeLink}}/following">
<a href="{{.Owner.HomeURLPath}}/following">
{{.Owner.NumFollowing}} {{.i18n.Tr "user.following"}}
</a>
</li>
@ -56,7 +56,7 @@
{{if .Orgs}}
<li>
{{range .Orgs}}
<a href="{{.HomeURLPath}}"><img class="ui mini image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a>
<a href="{{.HomeURLPath}}"><img class="ui mini image poping up" src="{{.AvatarURLPath}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a>
{{end}}
</li>
{{end}}
@ -85,11 +85,11 @@
</div>
<div class="ui eleven wide column">
<div class="ui secondary pointing menu">
<a class="{{if ne .TabName "activity"}}active{{end}} item" href="{{.Owner.HomeLink}}">
<a class="{{if ne .TabName "activity"}}active{{end}} item" href="{{.Owner.HomeURLPath}}">
<i class="octicon octicon-repo"></i> {{.i18n.Tr "user.repositories"}}
</a>
<a class="item">
<a class="{{if eq .TabName "activity"}}active{{end}} item" href="{{.Owner.HomeLink}}?tab=activity">
<a class="{{if eq .TabName "activity"}}active{{end}} item" href="{{.Owner.HomeURLPath}}?tab=activity">
<i class="octicon octicon-rss"></i> {{.i18n.Tr "user.activity"}}
</a>
</a>

View File

@ -21,9 +21,9 @@
{{$.i18n.Tr "org.members.leave"}}
</button>
</div>
<img class="ui mini image" src="{{.RelAvatarLink}}">
<img class="ui mini image" src="{{.AvatarURLPath}}">
<div class="content">
<a href="{{.HomeLink}}">{{.Name}}</a>
<a href="{{.HomeURLPath}}">{{.Name}}</a>
</div>
</div>
{{end}}