2021-12-12 18:48:20 +03:00
// Copyright 2021 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2020-10-14 16:07:51 +03:00
2021-12-12 18:48:20 +03:00
package repository
2020-10-14 16:07:51 +03:00
import (
"context"
"fmt"
"io"
"strconv"
2021-12-12 18:48:20 +03:00
"strings"
2020-10-14 16:07:51 +03:00
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2021-12-10 04:27:50 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2020-10-14 16:07:51 +03:00
"code.gitea.io/gitea/modules/avatar"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/storage"
)
2021-12-12 18:48:20 +03:00
// UploadAvatar saves custom avatar for repository.
2020-10-14 16:07:51 +03:00
// FIXME: split uploads to different subdirs in case we have massive number of repos.
2023-03-01 01:17:51 +03:00
func UploadAvatar ( ctx context . Context , repo * repo_model . Repository , data [ ] byte ) error {
2023-05-13 21:59:11 +03:00
avatarData , err := avatar . ProcessAvatarImage ( data )
2020-10-14 16:07:51 +03:00
if err != nil {
return err
}
2023-01-03 00:46:39 +03:00
newAvatar := avatar . HashAvatar ( repo . ID , data )
2020-10-14 16:07:51 +03:00
if repo . Avatar == newAvatar { // upload the same picture
return nil
}
2023-03-01 01:17:51 +03:00
ctx , committer , err := db . TxContext ( ctx )
2021-11-21 18:41:00 +03:00
if err != nil {
2020-10-14 16:07:51 +03:00
return err
}
2021-11-21 18:41:00 +03:00
defer committer . Close ( )
2020-10-14 16:07:51 +03:00
oldAvatarPath := repo . CustomAvatarRelativePath ( )
// Users can upload the same image to other repo - prefix it with ID
// Then repo will be removed - only it avatar file will be removed
repo . Avatar = newAvatar
2022-05-20 17:08:52 +03:00
if err := repo_model . UpdateRepositoryCols ( ctx , repo , "avatar" ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "UploadAvatar: Update repository avatar: %w" , err )
2020-10-14 16:07:51 +03:00
}
if err := storage . SaveFrom ( storage . RepoAvatars , repo . CustomAvatarRelativePath ( ) , func ( w io . Writer ) error {
2023-05-13 21:59:11 +03:00
_ , err := w . Write ( avatarData )
2020-10-14 16:07:51 +03:00
return err
} ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "UploadAvatar %s failed: Failed to remove old repo avatar %s: %w" , repo . RepoPath ( ) , newAvatar , err )
2020-10-14 16:07:51 +03:00
}
if len ( oldAvatarPath ) > 0 {
if err := storage . RepoAvatars . Delete ( oldAvatarPath ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "UploadAvatar: Failed to remove old repo avatar %s: %w" , oldAvatarPath , err )
2020-10-14 16:07:51 +03:00
}
}
2021-11-21 18:41:00 +03:00
return committer . Commit ( )
2020-10-14 16:07:51 +03:00
}
2021-12-12 18:48:20 +03:00
// DeleteAvatar deletes the repos's custom avatar.
2023-03-01 01:17:51 +03:00
func DeleteAvatar ( ctx context . Context , repo * repo_model . Repository ) error {
2020-10-14 16:07:51 +03:00
// Avatar not exists
if len ( repo . Avatar ) == 0 {
return nil
}
avatarPath := repo . CustomAvatarRelativePath ( )
log . Trace ( "DeleteAvatar[%d]: %s" , repo . ID , avatarPath )
2023-03-01 01:17:51 +03:00
ctx , committer , err := db . TxContext ( ctx )
2021-11-21 18:41:00 +03:00
if err != nil {
2020-10-14 16:07:51 +03:00
return err
}
2021-11-21 18:41:00 +03:00
defer committer . Close ( )
2020-10-14 16:07:51 +03:00
repo . Avatar = ""
2022-05-20 17:08:52 +03:00
if err := repo_model . UpdateRepositoryCols ( ctx , repo , "avatar" ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "DeleteAvatar: Update repository avatar: %w" , err )
2020-10-14 16:07:51 +03:00
}
if err := storage . RepoAvatars . Delete ( avatarPath ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "DeleteAvatar: Failed to remove %s: %w" , avatarPath , err )
2020-10-14 16:07:51 +03:00
}
2021-11-21 18:41:00 +03:00
return committer . Commit ( )
2020-10-14 16:07:51 +03:00
}
2021-12-12 18:48:20 +03:00
// RemoveRandomAvatars removes the randomly generated avatars that were created for repositories
func RemoveRandomAvatars ( ctx context . Context ) error {
2022-10-31 18:51:14 +03:00
return db . Iterate ( ctx , nil , func ( ctx context . Context , repository * repo_model . Repository ) error {
2021-12-12 18:48:20 +03:00
select {
case <- ctx . Done ( ) :
return db . ErrCancelledf ( "before random avatars removed for %s" , repository . FullName ( ) )
default :
}
stringifiedID := strconv . FormatInt ( repository . ID , 10 )
if repository . Avatar == stringifiedID {
2023-03-01 01:17:51 +03:00
return DeleteAvatar ( ctx , repository )
2021-12-12 18:48:20 +03:00
}
return nil
} )
}
// generateAvatar generates the avatar from a template repository
func generateAvatar ( ctx context . Context , templateRepo , generateRepo * repo_model . Repository ) error {
generateRepo . Avatar = strings . Replace ( templateRepo . Avatar , strconv . FormatInt ( templateRepo . ID , 10 ) , strconv . FormatInt ( generateRepo . ID , 10 ) , 1 )
if _ , err := storage . Copy ( storage . RepoAvatars , generateRepo . CustomAvatarRelativePath ( ) , storage . RepoAvatars , templateRepo . CustomAvatarRelativePath ( ) ) ; err != nil {
return err
}
2022-05-20 17:08:52 +03:00
return repo_model . UpdateRepositoryCols ( ctx , generateRepo , "avatar" )
2021-12-12 18:48:20 +03:00
}