mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 19:38:23 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			116 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2019 The Gitea Authors. All rights reserved.
 | |
| // Use of this source code is governed by a MIT-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| package migrations
 | |
| 
 | |
| import (
 | |
| 	"crypto/md5"
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 
 | |
| 	"code.gitea.io/gitea/modules/log"
 | |
| 	"code.gitea.io/gitea/modules/setting"
 | |
| 
 | |
| 	"xorm.io/xorm"
 | |
| )
 | |
| 
 | |
| func renameExistingUserAvatarName(x *xorm.Engine) error {
 | |
| 	sess := x.NewSession()
 | |
| 	defer sess.Close()
 | |
| 
 | |
| 	type User struct {
 | |
| 		ID        int64  `xorm:"pk autoincr"`
 | |
| 		LowerName string `xorm:"UNIQUE NOT NULL"`
 | |
| 		Avatar    string
 | |
| 	}
 | |
| 	deleteList := make(map[string]struct{})
 | |
| 	start := 0
 | |
| 	for {
 | |
| 		if err := sess.Begin(); err != nil {
 | |
| 			return fmt.Errorf("session.Begin: %v", err)
 | |
| 		}
 | |
| 		users := make([]*User, 0, 50)
 | |
| 		if err := sess.Table("user").Asc("id").Limit(50, start).Find(&users); err != nil {
 | |
| 			return fmt.Errorf("select users from id [%d]: %v", start, err)
 | |
| 		}
 | |
| 		if len(users) == 0 {
 | |
| 			_ = sess.Rollback()
 | |
| 			break
 | |
| 		}
 | |
| 
 | |
| 		log.Info("select users [%d - %d]", start, start+len(users))
 | |
| 		start += 50
 | |
| 
 | |
| 		for _, user := range users {
 | |
| 			oldAvatar := user.Avatar
 | |
| 
 | |
| 			if stat, err := os.Stat(filepath.Join(setting.AvatarUploadPath, oldAvatar)); err != nil || !stat.Mode().IsRegular() {
 | |
| 				if err == nil {
 | |
| 					err = fmt.Errorf("Error: \"%s\" is not a regular file", oldAvatar)
 | |
| 				}
 | |
| 				log.Warn("[user: %s] os.Stat: %v", user.LowerName, err)
 | |
| 				// avatar doesn't exist in the storage
 | |
| 				// no need to move avatar and update database
 | |
| 				// we can just skip this
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 			newAvatar, err := copyOldAvatarToNewLocation(user.ID, oldAvatar)
 | |
| 			if err != nil {
 | |
| 				_ = sess.Rollback()
 | |
| 				return fmt.Errorf("[user: %s] %v", user.LowerName, err)
 | |
| 			} else if newAvatar == oldAvatar {
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 			user.Avatar = newAvatar
 | |
| 			if _, err := sess.ID(user.ID).Cols("avatar").Update(user); err != nil {
 | |
| 				_ = sess.Rollback()
 | |
| 				return fmt.Errorf("[user: %s] user table update: %v", user.LowerName, err)
 | |
| 			}
 | |
| 
 | |
| 			deleteList[filepath.Join(setting.AvatarUploadPath, oldAvatar)] = struct{}{}
 | |
| 		}
 | |
| 		if err := sess.Commit(); err != nil {
 | |
| 			_ = sess.Rollback()
 | |
| 			return fmt.Errorf("commit session: %v", err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for file := range deleteList {
 | |
| 		if err := os.Remove(file); err != nil {
 | |
| 			log.Warn("os.Remove: %v", err)
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // copyOldAvatarToNewLocation copies oldAvatar to newAvatarLocation
 | |
| // and returns newAvatar location
 | |
| func copyOldAvatarToNewLocation(userID int64, oldAvatar string) (string, error) {
 | |
| 	fr, err := os.Open(filepath.Join(setting.AvatarUploadPath, oldAvatar))
 | |
| 	if err != nil {
 | |
| 		return "", fmt.Errorf("os.Open: %v", err)
 | |
| 	}
 | |
| 	defer fr.Close()
 | |
| 
 | |
| 	data, err := ioutil.ReadAll(fr)
 | |
| 	if err != nil {
 | |
| 		return "", fmt.Errorf("ioutil.ReadAll: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	newAvatar := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", userID, md5.Sum(data)))))
 | |
| 	if newAvatar == oldAvatar {
 | |
| 		return newAvatar, nil
 | |
| 	}
 | |
| 
 | |
| 	if err := ioutil.WriteFile(filepath.Join(setting.AvatarUploadPath, newAvatar), data, 0666); err != nil {
 | |
| 		return "", fmt.Errorf("ioutil.WriteFile: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	return newAvatar, nil
 | |
| }
 |