GoToSocial/internal/typeutils/defaulticons.go
Daenney 5e2bf0bdca
[chore] Improve copyright header handling (#1608)
* [chore] Remove years from all license headers

Years or year ranges aren't required in license headers. Many projects
have removed them in recent years and it avoids a bit of yearly toil.

In many cases our copyright claim was also a bit dodgy since we added
the 2021-2023 header to files created after 2021 but you can't claim
copyright into the past that way.

* [chore] Add license header check

This ensures a license header is always added to any new file. This
avoids maintainers/reviewers needing to remember to check for and ask
for it in case a contribution doesn't include it.

* [chore] Add missing license headers

* [chore] Further updates to license header

* Use the more common // indentend comment format
* Remove the hack we had for the linter now that we use the // format
* Add SPDX license identifier
2023-03-12 16:00:57 +01:00

138 lines
4.3 KiB
Go

// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package typeutils
import (
"math/rand"
"os"
"path/filepath"
"strings"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/log"
)
const defaultHeaderPath = "/assets/default_header.png"
// populateDefaultAvatars returns a slice of standard avatars found
// in the path [web-assets-base-dir]/default_avatars. The slice
// entries correspond to the relative url via which they can be
// retrieved from the server.
//
// So for example, an avatar called default.jpeg would be returned
// in the slice as "/assets/default_avatars/default.jpeg".
func populateDefaultAvatars() (defaultAvatars []string) {
webAssetsAbsFilePath, err := filepath.Abs(config.GetWebAssetBaseDir())
if err != nil {
log.Panicf(nil, "error getting abs path for web assets: %s", err)
}
defaultAvatarsAbsFilePath := filepath.Join(webAssetsAbsFilePath, "default_avatars")
defaultAvatarFiles, err := os.ReadDir(defaultAvatarsAbsFilePath)
if err != nil {
log.Warnf(nil, "error reading default avatars at %s: %s", defaultAvatarsAbsFilePath, err)
return
}
for _, f := range defaultAvatarFiles {
// ignore directories
if f.IsDir() {
continue
}
// ignore files bigger than 50kb
if i, err := f.Info(); err != nil || i.Size() > 50000 {
continue
}
// get the name of the file, eg avatar.jpeg
fileName := f.Name()
// get just the .jpeg, for example, from avatar.jpeg
extensionWithDot := filepath.Ext(fileName)
// remove the leading . to just get, eg, jpeg
extension := strings.TrimPrefix(extensionWithDot, ".")
// take only files with simple extensions
// that we know will work OK as avatars
switch strings.ToLower(extension) {
case "jpeg", "jpg", "gif", "png":
avatarURL := config.GetProtocol() + "://" + config.GetHost() + "/assets/default_avatars/" + fileName
defaultAvatars = append(defaultAvatars, avatarURL)
default:
continue
}
}
return
}
// ensureAvatar ensures that the given account has a value set
// for the avatar URL.
//
// If no value is set, an avatar will be selected at random from
// the available default avatars. This selection is 'sticky', so
// the same account will get the same result on subsequent calls.
//
// If a value for the avatar URL is already set, this function is
// a no-op.
//
// If there are no default avatars available, this function is a
// no-op.
func (c *converter) ensureAvatar(account *apimodel.Account) {
if (account.Avatar != "" && account.AvatarStatic != "") || len(c.defaultAvatars) == 0 {
return
}
var avatar string
if avatarI, ok := c.randAvatars.Load(account.ID); ok {
// we already have a default avatar stored for this account
avatar, ok = avatarI.(string)
if !ok {
panic("avatarI was not a string")
}
} else {
// select + store a default avatar for this account at random
randomIndex := rand.Intn(len(c.defaultAvatars)) //nolint:gosec
avatar = c.defaultAvatars[randomIndex]
c.randAvatars.Store(account.ID, avatar)
}
account.Avatar = avatar
account.AvatarStatic = avatar
}
// EnsureAvatar ensures that the given account has a value set
// for the header URL.
//
// If no value is set, the default header will be set.
//
// If a value for the header URL is already set, this function is
// a no-op.
func (c *converter) ensureHeader(account *apimodel.Account) {
if account.Header != "" && account.HeaderStatic != "" {
return
}
h := config.GetProtocol() + "://" + config.GetHost() + defaultHeaderPath
account.Header = h
account.HeaderStatic = h
}