summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMario Lubenka <mario.lubenka@googlemail.com>2019-06-02 08:40:12 +0200
committerLunny Xiao <xiaolunwen@gmail.com>2019-06-02 14:40:12 +0800
commit8eba27c79257c6bc68cefbdffbb36d3596e6d3ee (patch)
tree3a79fd7a5beb49d212d82bf61df7d8cd9bf1a613
parent356854fc5f8d7d1a7e4d68c9e00929e9ce8aa867 (diff)
downloadgitea-8eba27c79257c6bc68cefbdffbb36d3596e6d3ee.tar.gz
gitea-8eba27c79257c6bc68cefbdffbb36d3596e6d3ee.zip
Repository avatar fallback configuration (#7087)
* Only show repository avatar in list when one was selected Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adds fallback configuration option for repository avatar Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Implements repository avatar fallback Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adds admin task for deleting generated repository avatars Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Solve linting issues Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Save avatar before updating database * Linting * Update models/repo.go Co-Authored-By: zeripath <art27@cantab.net>
-rw-r--r--custom/conf/app.ini.sample4
-rw-r--r--docs/content/doc/advanced/config-cheat-sheet.en-us.md5
-rw-r--r--models/repo.go77
-rw-r--r--modules/setting/setting.go24
-rw-r--r--options/locale/locale_en-US.ini2
-rw-r--r--public/img/repo_default.pngbin0 -> 2464 bytes
-rw-r--r--routers/admin/admin.go4
-rw-r--r--templates/admin/dashboard.tmpl4
-rw-r--r--templates/explore/repo_list.tmpl4
9 files changed, 105 insertions, 19 deletions
diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample
index e8e3ffada6..a674984a25 100644
--- a/custom/conf/app.ini.sample
+++ b/custom/conf/app.ini.sample
@@ -505,6 +505,10 @@ SESSION_LIFE_TIME = 86400
[picture]
AVATAR_UPLOAD_PATH = data/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = data/repo-avatars
+; How Gitea deals with missing repository avatars
+; none = no avatar will be displayed; random = random avatar will be displayed; image = default image will be used
+REPOSITORY_AVATAR_FALLBACK = none
+REPOSITORY_AVATAR_FALLBACK_IMAGE = /img/repo_default.png
; Max Width and Height of uploaded avatars.
; This is to limit the amount of RAM used when resizing the image.
AVATAR_MAX_WIDTH = 4096
diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
index 052ced6e2a..ecc196c86e 100644
--- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md
+++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
@@ -292,6 +292,11 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
[http://www.libravatar.org](http://www.libravatar.org)).
- `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store user avatar image files.
- `REPOSITORY_AVATAR_UPLOAD_PATH`: **data/repo-avatars**: Path to store repository avatar image files.
+- `REPOSITORY_AVATAR_FALLBACK`: **none**: How Gitea deals with missing repository avatars
+ - none = no avatar will be displayed
+ - random = random avatar will be generated
+ - image = default image will be used (which is set in `REPOSITORY_AVATAR_DEFAULT_IMAGE`)
+- `REPOSITORY_AVATAR_FALLBACK_IMAGE`: **/img/repo_default.png**: Image used as default repository avatar (if `REPOSITORY_AVATAR_FALLBACK` is set to image and none was uploaded)
- `AVATAR_MAX_WIDTH`: **4096**: Maximum avatar image width in pixels.
- `AVATAR_MAX_HEIGHT`: **3072**: Maximum avatar image height in pixels.
- `AVATAR_MAX_FILE_SIZE`: **1048576** (1Mb): Maximum avatar image file size in bytes.
diff --git a/models/repo.go b/models/repo.go
index 16684bdeef..d5eca3d225 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -2528,17 +2528,78 @@ func (repo *Repository) CustomAvatarPath() string {
return filepath.Join(setting.RepositoryAvatarUploadPath, repo.Avatar)
}
-// RelAvatarLink returns a relative link to the user's avatar.
-// The link a sub-URL to this site
-// Since Gravatar support not needed here - just check for image path.
+// GenerateRandomAvatar generates a random avatar for repository.
+func (repo *Repository) GenerateRandomAvatar() error {
+ return repo.generateRandomAvatar(x)
+}
+
+func (repo *Repository) generateRandomAvatar(e Engine) error {
+ idToString := fmt.Sprintf("%d", repo.ID)
+
+ seed := idToString
+ img, err := avatar.RandomImage([]byte(seed))
+ if err != nil {
+ return fmt.Errorf("RandomImage: %v", err)
+ }
+
+ repo.Avatar = idToString
+ if err = os.MkdirAll(filepath.Dir(repo.CustomAvatarPath()), os.ModePerm); err != nil {
+ return fmt.Errorf("MkdirAll: %v", err)
+ }
+ fw, err := os.Create(repo.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 for repository: %d", repo.ID)
+
+ if _, err := e.ID(repo.ID).Cols("avatar").NoAutoTime().Update(repo); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// RemoveRandomAvatars removes the randomly generated avatars that were created for repositories
+func RemoveRandomAvatars() error {
+ var (
+ err error
+ )
+ err = x.
+ Where("id > 0").BufferSize(setting.IterateBufferSize).
+ Iterate(new(Repository),
+ func(idx int, bean interface{}) error {
+ repository := bean.(*Repository)
+ stringifiedID := strconv.FormatInt(repository.ID, 10)
+ if repository.Avatar == stringifiedID {
+ return repository.DeleteAvatar()
+ }
+ return nil
+ })
+ return err
+}
+
+// RelAvatarLink returns a relative link to the repository's avatar.
func (repo *Repository) RelAvatarLink() string {
+
// If no avatar - path is empty
avatarPath := repo.CustomAvatarPath()
- if len(avatarPath) <= 0 {
- return ""
- }
- if !com.IsFile(avatarPath) {
- return ""
+ if len(avatarPath) <= 0 || !com.IsFile(avatarPath) {
+ switch mode := setting.RepositoryAvatarFallback; mode {
+ case "image":
+ return setting.RepositoryAvatarFallbackImage
+ case "random":
+ if err := repo.GenerateRandomAvatar(); err != nil {
+ log.Error("GenerateRandomAvatar: %v", err)
+ }
+ default:
+ // default behaviour: do not display avatar
+ return ""
+ }
}
return setting.AppSubURL + "/repo-avatars/" + repo.Avatar
}
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 9e96105788..ff53e9a375 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -250,16 +250,18 @@ var (
}
// Picture settings
- AvatarUploadPath string
- AvatarMaxWidth int
- AvatarMaxHeight int
- GravatarSource string
- GravatarSourceURL *url.URL
- DisableGravatar bool
- EnableFederatedAvatar bool
- LibravatarService *libravatar.Libravatar
- AvatarMaxFileSize int64
- RepositoryAvatarUploadPath string
+ AvatarUploadPath string
+ AvatarMaxWidth int
+ AvatarMaxHeight int
+ GravatarSource string
+ GravatarSourceURL *url.URL
+ DisableGravatar bool
+ EnableFederatedAvatar bool
+ LibravatarService *libravatar.Libravatar
+ AvatarMaxFileSize int64
+ RepositoryAvatarUploadPath string
+ RepositoryAvatarFallback string
+ RepositoryAvatarFallbackImage string
// Log settings
LogLevel string
@@ -842,6 +844,8 @@ func NewContext() {
if !filepath.IsAbs(RepositoryAvatarUploadPath) {
RepositoryAvatarUploadPath = path.Join(AppWorkPath, RepositoryAvatarUploadPath)
}
+ RepositoryAvatarFallback = sec.Key("REPOSITORY_AVATAR_FALLBACK").MustString("none")
+ RepositoryAvatarFallbackImage = sec.Key("REPOSITORY_AVATAR_FALLBACK_IMAGE").MustString("/img/repo_default.png")
AvatarMaxWidth = sec.Key("AVATAR_MAX_WIDTH").MustInt(4096)
AvatarMaxHeight = sec.Key("AVATAR_MAX_HEIGHT").MustInt(3072)
AvatarMaxFileSize = sec.Key("AVATAR_MAX_FILE_SIZE").MustInt64(1048576)
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 645c9770a4..ebc6ca31ce 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1522,6 +1522,8 @@ dashboard.delete_repo_archives = Delete all repository archives
dashboard.delete_repo_archives_success = All repository archives have been deleted.
dashboard.delete_missing_repos = Delete all repositories missing their Git files
dashboard.delete_missing_repos_success = All repositories missing their Git files have been deleted.
+dashboard.delete_generated_repository_avatars = Delete generated repository avatars
+dashboard.delete_generated_repository_avatars_success = Generated repository avatars were deleted.
dashboard.git_gc_repos = Garbage collect all repositories
dashboard.git_gc_repos_success = All repositories have finished garbage collection.
dashboard.resync_all_sshkeys = Update the '.ssh/authorized_keys' file with Gitea SSH keys. (Not needed for the built-in SSH server.)
diff --git a/public/img/repo_default.png b/public/img/repo_default.png
new file mode 100644
index 0000000000..dbfa843723
--- /dev/null
+++ b/public/img/repo_default.png
Binary files differ
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index 0e6fa2c242..5107e18b7d 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -125,6 +125,7 @@ const (
reinitMissingRepository
syncExternalUsers
gitFsck
+ deleteGeneratedRepositoryAvatars
)
// Dashboard show admin panel dashboard
@@ -167,6 +168,9 @@ func Dashboard(ctx *context.Context) {
case gitFsck:
success = ctx.Tr("admin.dashboard.git_fsck_started")
go models.GitFsck()
+ case deleteGeneratedRepositoryAvatars:
+ success = ctx.Tr("admin.dashboard.delete_generated_repository_avatars_success")
+ err = models.RemoveRandomAvatars()
}
if err != nil {
diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl
index 13c06334a5..262db04b90 100644
--- a/templates/admin/dashboard.tmpl
+++ b/templates/admin/dashboard.tmpl
@@ -53,6 +53,10 @@
<td>{{.i18n.Tr "admin.dashboard.git_fsck"}}</td>
<td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=9">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td>
</tr>
+ <tr>
+ <td>{{.i18n.Tr "admin.dashboard.delete_generated_repository_avatars"}}</td>
+ <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=10">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td>
+ </tr>
</tbody>
</table>
</div>
diff --git a/templates/explore/repo_list.tmpl b/templates/explore/repo_list.tmpl
index 34aab6477a..8c7ba51a54 100644
--- a/templates/explore/repo_list.tmpl
+++ b/templates/explore/repo_list.tmpl
@@ -2,7 +2,9 @@
{{range .Repos}}
<div class="item">
<div class="ui header">
- <img class="ui avatar image" src="{{.RelAvatarLink}}">
+ {{if .RelAvatarLink}}
+ <img class="ui avatar image" src="{{.RelAvatarLink}}">
+ {{end}}
<a class="name" href="{{.Link}}">
{{if or $.PageIsExplore $.PageIsProfileStarList }}{{if .Owner}}{{.Owner.Name}} / {{end}}{{end}}{{.Name}}
{{if .IsArchived}}<i class="archive icon archived-icon"></i>{{end}}