瀏覽代碼

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

Joe Chen 2 年之前
父節點
當前提交
ce25881c88
共有 44 個文件被更改,包括 274 次插入197 次删除
  1. 1 1
      internal/cmd/web.go
  2. 8 0
      internal/conf/mocks.go
  3. 22 18
      internal/conf/static.go
  4. 1 1
      internal/db/actions.go
  5. 2 1
      internal/db/org.go
  6. 6 73
      internal/db/user.go
  7. 50 2
      internal/db/users.go
  8. 1 1
      internal/route/api/v1/convert/convert.go
  9. 1 1
      internal/route/api/v1/user/user.go
  10. 1 1
      internal/route/user/home.go
  11. 3 2
      internal/route/user/setting.go
  12. 45 2
      internal/userutil/userutil.go
  13. 39 0
      internal/userutil/userutil_test.go
  14. 1 1
      templates/admin/org/list.tmpl
  15. 3 3
      templates/base/head.tmpl
  16. 2 2
      templates/explore/organizations.tmpl
  17. 2 2
      templates/explore/users.tmpl
  18. 2 2
      templates/org/header.tmpl
  19. 2 2
      templates/org/home.tmpl
  20. 2 2
      templates/org/member/members.tmpl
  21. 2 2
      templates/org/team/members.tmpl
  22. 2 2
      templates/org/team/teams.tmpl
  23. 1 1
      templates/repo/commits_table.tmpl
  24. 3 3
      templates/repo/create.tmpl
  25. 2 2
      templates/repo/diff/page.tmpl
  26. 2 2
      templates/repo/editor/commit_form.tmpl
  27. 1 1
      templates/repo/forks.tmpl
  28. 4 4
      templates/repo/issue/list.tmpl
  29. 4 4
      templates/repo/issue/new_form.tmpl
  30. 21 21
      templates/repo/issue/view_content.tmpl
  31. 3 3
      templates/repo/issue/view_title.tmpl
  32. 3 3
      templates/repo/migrate.tmpl
  33. 3 3
      templates/repo/pulls/fork.tmpl
  34. 1 1
      templates/repo/release/list.tmpl
  35. 1 1
      templates/repo/settings/collaboration.tmpl
  36. 1 1
      templates/repo/settings/protected_branch.tmpl
  37. 3 3
      templates/repo/user_cards.tmpl
  38. 1 1
      templates/repo/view_list.tmpl
  39. 1 1
      templates/user/dashboard/dashboard.tmpl
  40. 4 4
      templates/user/dashboard/issues.tmpl
  41. 4 4
      templates/user/dashboard/navbar.tmpl
  42. 4 4
      templates/user/meta/header.tmpl
  43. 7 7
      templates/user/profile.tmpl
  44. 2 2
      templates/user/settings/organizations.tmpl

+ 1 - 1
internal/cmd/web.go

@@ -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,
 		},
 	))

+ 8 - 0
internal/conf/mocks.go

@@ -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
+	})
+}

+ 22 - 18
internal/conf/static.go

@@ -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"
+}

+ 1 - 1
internal/db/actions.go

@@ -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()
 		}
 	}
 

+ 2 - 1
internal/db/org.go

@@ -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{

+ 6 - 73
internal/db/user.go

@@ -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
 }

+ 50 - 2
internal/db/users.go

@@ -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
+}

+ 1 - 1
internal/route/api/v1/convert/convert.go

@@ -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,

+ 1 - 1
internal/route/api/v1/user/user.go

@@ -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 {

+ 1 - 1
internal/route/user/home.go

@@ -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]

+ 3 - 2
internal/route/user/setting.go

@@ -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)
 			}
 		}

+ 45 - 2
internal/userutil/userutil.go

@@ -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
+}

+ 39 - 0
internal/userutil/userutil_test.go

@@ -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)
+}

+ 1 - 1
templates/admin/org/list.tmpl

@@ -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>

+ 3 - 3
templates/base/head.tmpl

@@ -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>

+ 2 - 2
templates/explore/organizations.tmpl

@@ -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}}

+ 2 - 2
templates/explore/users.tmpl

@@ -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}}

+ 2 - 2
templates/org/header.tmpl

@@ -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">

+ 2 - 2
templates/org/home.tmpl

@@ -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>

+ 2 - 2
templates/org/member/members.tmpl

@@ -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">

+ 2 - 2
templates/org/team/members.tmpl

@@ -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>

+ 2 - 2
templates/org/team/teams.tmpl

@@ -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>

+ 1 - 1
templates/repo/commits_table.tmpl

@@ -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}}

+ 3 - 3
templates/repo/create.tmpl

@@ -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}}

+ 2 - 2
templates/repo/diff/page.tmpl

@@ -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>

+ 2 - 2
templates/repo/editor/commit_form.tmpl

@@ -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>

+ 1 - 1
templates/repo/forks.tmpl

@@ -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>
 						/

+ 4 - 4
templates/repo/issue/list.tmpl

@@ -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>

+ 4 - 4
templates/repo/issue/new_form.tmpl

@@ -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>

+ 21 - 21
templates/repo/issue/view_content.tmpl

@@ -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>

+ 3 - 3
templates/repo/issue/view_title.tmpl

@@ -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}}

+ 3 - 3
templates/repo/migrate.tmpl

@@ -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}}

+ 3 - 3
templates/repo/pulls/fork.tmpl

@@ -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}}

+ 1 - 1
templates/repo/release/list.tmpl

@@ -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}}

+ 1 - 1
templates/repo/settings/collaboration.tmpl

@@ -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>

+ 1 - 1
templates/repo/settings/protected_branch.tmpl

@@ -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}}

+ 3 - 3
templates/repo/user_cards.tmpl

@@ -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}}

+ 1 - 1
templates/repo/view_list.tmpl

@@ -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}}" />

+ 1 - 1
templates/user/dashboard/dashboard.tmpl

@@ -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>

+ 4 - 4
templates/user/dashboard/issues.tmpl

@@ -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>

+ 4 - 4
templates/user/dashboard/navbar.tmpl

@@ -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>

+ 4 - 4
templates/user/meta/header.tmpl

@@ -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}}

+ 7 - 7
templates/user/profile.tmpl

@@ -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>

+ 2 - 2
templates/user/settings/organizations.tmpl

@@ -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}}