Add user.refreshAvatar()

This commit is contained in:
Yang Luo
2023-04-16 00:29:56 +08:00
parent 47dc3715f9
commit 336f3f7a7b
7 changed files with 255 additions and 1 deletions

View File

@ -80,3 +80,21 @@ func DownloadAndUpload(url string, fullFilePath string, lang string) {
panic(err)
}
}
func getPermanentAvatarUrlFromBuffer(organization string, username string, fileBuffer *bytes.Buffer, ext string, upload bool) string {
if defaultStorageProvider == nil {
return ""
}
fullFilePath := fmt.Sprintf("/avatar/%s/%s%s", organization, username, ext)
uploadedFileUrl, _ := GetUploadFileUrl(defaultStorageProvider, fullFilePath, false)
if upload {
_, _, err := UploadFileSafe(defaultStorageProvider, fullFilePath, fileBuffer, "en")
if err != nil {
panic(err)
}
}
return uploadedFileUrl
}

View File

@ -16,6 +16,7 @@ package object
import (
"fmt"
"strings"
"testing"
"github.com/casdoor/casdoor/proxy"
@ -37,3 +38,22 @@ func TestSyncPermanentAvatars(t *testing.T) {
fmt.Printf("[%d/%d]: Update user: [%s]'s permanent avatar: %s\n", i, len(users), user.GetId(), user.PermanentAvatar)
}
}
func TestUpdateAvatars(t *testing.T) {
InitConfig()
InitDefaultStorageProvider()
proxy.InitHttpClient()
users := GetUsers("casdoor")
for _, user := range users {
if strings.HasPrefix(user.Avatar, "http") {
continue
}
updated := user.refreshAvatar()
if updated {
user.PermanentAvatar = "*"
UpdateUser(user.GetId(), user, []string{"avatar"}, true)
}
}
}

167
object/avatar_util.go Normal file
View File

@ -0,0 +1,167 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"bytes"
"crypto/md5"
"fmt"
"image"
"image/color"
"image/png"
"io"
"net/http"
"strings"
"github.com/fogleman/gg"
)
func hasGravatar(client *http.Client, email string) (bool, error) {
// Clean and lowercase the email
email = strings.TrimSpace(strings.ToLower(email))
// Generate MD5 hash of the email
hash := md5.New()
io.WriteString(hash, email)
hashedEmail := fmt.Sprintf("%x", hash.Sum(nil))
// Create Gravatar URL with d=404 parameter
gravatarURL := fmt.Sprintf("https://www.gravatar.com/avatar/%s?d=404", hashedEmail)
// Send a request to Gravatar
req, err := http.NewRequest("GET", gravatarURL, nil)
if err != nil {
return false, err
}
resp, err := client.Do(req)
if err != nil {
return false, err
}
defer resp.Body.Close()
// Check if the user has a custom Gravatar image
if resp.StatusCode == http.StatusOK {
return true, nil
} else if resp.StatusCode == http.StatusNotFound {
return false, nil
} else {
return false, fmt.Errorf("failed to fetch gravatar image: %s", resp.Status)
}
}
func getGravatarFileBuffer(client *http.Client, email string) (*bytes.Buffer, string, error) {
// Clean and lowercase the email
email = strings.TrimSpace(strings.ToLower(email))
// Generate MD5 hash of the email
hash := md5.New()
io.WriteString(hash, email)
hashedEmail := fmt.Sprintf("%x", hash.Sum(nil))
// Create Gravatar URL
gravatarURL := fmt.Sprintf("https://www.gravatar.com/avatar/%s", hashedEmail)
// Download the image
req, err := http.NewRequest("GET", gravatarURL, nil)
if err != nil {
return nil, "", err
}
resp, err := client.Do(req)
if err != nil {
return nil, "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, "", fmt.Errorf("failed to download gravatar image: %s", resp.Status)
}
// Get the content type and determine the file extension
contentType := resp.Header.Get("Content-Type")
fileExtension := ""
switch contentType {
case "image/jpeg":
fileExtension = ".jpg"
case "image/png":
fileExtension = ".png"
case "image/gif":
fileExtension = ".gif"
default:
return nil, "", fmt.Errorf("unsupported content type: %s", contentType)
}
// Save the image to a bytes.Buffer
buffer := &bytes.Buffer{}
_, err = io.Copy(buffer, resp.Body)
if err != nil {
return nil, "", err
}
return buffer, fileExtension, nil
}
func getColor(data []byte) color.RGBA {
r := int(data[0]) % 256
g := int(data[1]) % 256
b := int(data[2]) % 256
return color.RGBA{uint8(r), uint8(g), uint8(b), 255}
}
func getIdenticonFileBuffer(username string) (*bytes.Buffer, string, error) {
username = strings.TrimSpace(strings.ToLower(username))
hash := md5.New()
io.WriteString(hash, username)
hashedUsername := hash.Sum(nil)
// Define the size of the image
const imageSize = 420
const cellSize = imageSize / 7
// Create a new image
img := image.NewRGBA(image.Rect(0, 0, imageSize, imageSize))
// Create a context
dc := gg.NewContextForRGBA(img)
// Set a background color
dc.SetColor(color.RGBA{240, 240, 240, 255})
dc.Clear()
// Get avatar color
avatarColor := getColor(hashedUsername)
// Draw cells
for i := 0; i < 7; i++ {
for j := 0; j < 7; j++ {
if (hashedUsername[i] >> uint(j) & 1) == 1 {
dc.SetColor(avatarColor)
dc.DrawRectangle(float64(j*cellSize), float64(i*cellSize), float64(cellSize), float64(cellSize))
dc.Fill()
}
}
}
// Save image to a bytes.Buffer
buffer := &bytes.Buffer{}
err := png.Encode(buffer, img)
if err != nil {
return nil, "", fmt.Errorf("failed to save image: %w", err)
}
return buffer, ".png", nil
}

View File

@ -30,7 +30,10 @@ func TestProduct(t *testing.T) {
product := GetProduct("admin/product_123")
provider := getProvider(product.Owner, "provider_pay_alipay")
cert := getCert(product.Owner, "cert-pay-alipay")
pProvider := pp.GetPaymentProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey, provider.ClientId2)
pProvider, err := pp.GetPaymentProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey, provider.ClientId2)
if err != nil {
panic(err)
}
paymentName := util.GenerateTimeId()
returnUrl := ""

View File

@ -15,10 +15,12 @@
package object
import (
"bytes"
"fmt"
"strings"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/proxy"
"github.com/casdoor/casdoor/util"
"github.com/go-webauthn/webauthn/webauthn"
"github.com/xorm-io/core"
@ -693,3 +695,40 @@ func userChangeTrigger(oldName string, newName string) error {
return session.Commit()
}
func (user *User) refreshAvatar() bool {
var err error
var fileBuffer *bytes.Buffer
var ext string
// Gravatar + Identicon
if strings.Contains(user.Avatar, "Gravatar") && user.Email != "" {
client := proxy.ProxyHttpClient
has, err := hasGravatar(client, user.Email)
if err != nil {
panic(err)
}
if has {
fileBuffer, ext, err = getGravatarFileBuffer(client, user.Email)
if err != nil {
panic(err)
}
}
}
if fileBuffer == nil && strings.Contains(user.Avatar, "Identicon") {
fileBuffer, ext, err = getIdenticonFileBuffer(user.Name)
if err != nil {
panic(err)
}
}
if fileBuffer != nil {
avatarUrl := getPermanentAvatarUrlFromBuffer(user.Owner, user.Name, fileBuffer, ext, true)
user.Avatar = avatarUrl
return true
}
return false
}