defaulticons.go (4403B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package typeutils 19 20 import ( 21 "math/rand" 22 "os" 23 "path/filepath" 24 "strings" 25 26 apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" 27 "github.com/superseriousbusiness/gotosocial/internal/config" 28 "github.com/superseriousbusiness/gotosocial/internal/log" 29 ) 30 31 const defaultHeaderPath = "/assets/default_header.png" 32 33 // populateDefaultAvatars returns a slice of standard avatars found 34 // in the path [web-assets-base-dir]/default_avatars. The slice 35 // entries correspond to the relative url via which they can be 36 // retrieved from the server. 37 // 38 // So for example, an avatar called default.jpeg would be returned 39 // in the slice as "/assets/default_avatars/default.jpeg". 40 func populateDefaultAvatars() (defaultAvatars []string) { 41 webAssetsAbsFilePath, err := filepath.Abs(config.GetWebAssetBaseDir()) 42 if err != nil { 43 log.Panicf(nil, "error getting abs path for web assets: %s", err) 44 } 45 46 defaultAvatarsAbsFilePath := filepath.Join(webAssetsAbsFilePath, "default_avatars") 47 defaultAvatarFiles, err := os.ReadDir(defaultAvatarsAbsFilePath) 48 if err != nil { 49 log.Warnf(nil, "error reading default avatars at %s: %s", defaultAvatarsAbsFilePath, err) 50 return 51 } 52 53 for _, f := range defaultAvatarFiles { 54 // ignore directories 55 if f.IsDir() { 56 continue 57 } 58 59 // ignore files bigger than 50kb 60 if i, err := f.Info(); err != nil || i.Size() > 50000 { 61 continue 62 } 63 64 // get the name of the file, eg avatar.jpeg 65 fileName := f.Name() 66 67 // get just the .jpeg, for example, from avatar.jpeg 68 extensionWithDot := filepath.Ext(fileName) 69 70 // remove the leading . to just get, eg, jpeg 71 extension := strings.TrimPrefix(extensionWithDot, ".") 72 73 // take only files with simple extensions 74 // that we know will work OK as avatars 75 switch strings.ToLower(extension) { 76 case "jpeg", "jpg", "gif", "png": 77 avatarURL := config.GetProtocol() + "://" + config.GetHost() + "/assets/default_avatars/" + fileName 78 defaultAvatars = append(defaultAvatars, avatarURL) 79 default: 80 continue 81 } 82 } 83 84 return 85 } 86 87 // ensureAvatar ensures that the given account has a value set 88 // for the avatar URL. 89 // 90 // If no value is set, an avatar will be selected at random from 91 // the available default avatars. This selection is 'sticky', so 92 // the same account will get the same result on subsequent calls. 93 // 94 // If a value for the avatar URL is already set, this function is 95 // a no-op. 96 // 97 // If there are no default avatars available, this function is a 98 // no-op. 99 func (c *converter) ensureAvatar(account *apimodel.Account) { 100 if (account.Avatar != "" && account.AvatarStatic != "") || len(c.defaultAvatars) == 0 { 101 return 102 } 103 104 var avatar string 105 if avatarI, ok := c.randAvatars.Load(account.ID); ok { 106 // we already have a default avatar stored for this account 107 avatar, ok = avatarI.(string) 108 if !ok { 109 panic("avatarI was not a string") 110 } 111 } else { 112 // select + store a default avatar for this account at random 113 randomIndex := rand.Intn(len(c.defaultAvatars)) //nolint:gosec 114 avatar = c.defaultAvatars[randomIndex] 115 c.randAvatars.Store(account.ID, avatar) 116 } 117 118 account.Avatar = avatar 119 account.AvatarStatic = avatar 120 } 121 122 // EnsureAvatar ensures that the given account has a value set 123 // for the header URL. 124 // 125 // If no value is set, the default header will be set. 126 // 127 // If a value for the header URL is already set, this function is 128 // a no-op. 129 func (c *converter) ensureHeader(account *apimodel.Account) { 130 if account.Header != "" && account.HeaderStatic != "" { 131 return 132 } 133 134 h := config.GetProtocol() + "://" + config.GetHost() + defaultHeaderPath 135 account.Header = h 136 account.HeaderStatic = h 137 }