Use Discord avatars as HMN avatars

This commit is contained in:
Ben Visness 2023-05-04 23:46:31 -05:00
parent 2ba2fa4d7d
commit a826f1918e
2 changed files with 47 additions and 7 deletions

View File

@ -431,7 +431,7 @@ var discordDownloadClient = &http.Client{
type DiscordResourceBadStatusCode error
func downloadDiscordResource(ctx context.Context, url string) ([]byte, string, error) {
func DownloadDiscordResource(ctx context.Context, url string) ([]byte, string, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, "", oops.New(err, "failed to make Discord download request")
@ -491,7 +491,7 @@ func saveAttachment(
height = *attachment.Height
}
content, _, err := downloadDiscordResource(ctx, attachment.Url)
content, _, err := DownloadDiscordResource(ctx, attachment.Url)
if err != nil {
return nil, oops.New(err, "failed to download Discord attachment")
}
@ -561,7 +561,7 @@ func saveEmbed(
}
maybeSaveImageish := func(i EmbedImageish, contentTypeCheck func(string) bool) (*uuid.UUID, error) {
content, contentType, err := downloadDiscordResource(ctx, *i.Url)
content, contentType, err := DownloadDiscordResource(ctx, *i.Url)
if err != nil {
var statusError DiscordResourceBadStatusCode
if errors.As(err, &statusError) {
@ -838,7 +838,8 @@ func HandleSnippetForInternedMessage(ctx context.Context, dbConn db.ConnOrTx, in
}
// TODO(asaf): I believe this will also match https://example.com?hello=1&whatever=5
// Probably need to add word boundaries.
//
// Probably need to add word boundaries.
var REDiscordTag = regexp.MustCompile(`&([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)`)
func getDiscordTags(content string) []string {

View File

@ -1,12 +1,14 @@
package website
import (
"context"
"errors"
"fmt"
"net/http"
"strings"
"time"
"git.handmade.network/hmn/hmn/src/assets"
"git.handmade.network/hmn/hmn/src/config"
"git.handmade.network/hmn/hmn/src/db"
"git.handmade.network/hmn/hmn/src/discord"
@ -14,6 +16,7 @@ import (
"git.handmade.network/hmn/hmn/src/models"
"git.handmade.network/hmn/hmn/src/oops"
"git.handmade.network/hmn/hmn/src/utils"
"github.com/google/uuid"
)
// This callback handles Discord account linking whether the user is signed in
@ -194,16 +197,26 @@ func DiscordOAuthCallback(c *RequestContext) ResponseData {
return c.RejectRequest(fmt.Sprintf("There is already a Handmade Network account with the username \"%s\".", user.Username))
}
var avatarAssetID *uuid.UUID
if user.Avatar != nil {
// Note! Not using the transaction here. Don't want to fail the login due to avatars.
if avatarAsset, err := saveDiscordAvatar(c, c.Conn, user.ID, *user.Avatar); err == nil {
avatarAssetID = &avatarAsset.ID
} else {
c.Logger.Warn().Err(err).Msg("failed to save Discord avatar")
}
}
newHMNUser, err := db.QueryOne[models.User](c, tx,
`
INSERT INTO hmn_user (
username, email, password, date_joined, registration_ip
username, email, password, avatar_asset_id, date_joined, registration_ip
) VALUES (
$1, $2, '', $3, $4
$1, $2, '', $3, $4, $5
)
RETURNING $columns
`,
user.Username, strings.ToLower(user.Email), time.Now(), c.GetIP(),
user.Username, strings.ToLower(user.Email), avatarAssetID, time.Now(), c.GetIP(),
)
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new HMN user for Discord login"))
@ -366,3 +379,29 @@ func DiscordShowcaseBacklog(c *RequestContext) ResponseData {
return c.Redirect(hmnurl.BuildUserProfile(c.CurrentUser.Username), http.StatusSeeOther)
}
func saveDiscordAvatar(ctx context.Context, conn db.ConnOrTx, userID, avatarHash string) (*models.Asset, error) {
const size = 256
filename := fmt.Sprintf("%s.png", avatarHash)
url := fmt.Sprintf("https://cdn.discordapp.com/avatars/%s/%s?size=%d", userID, filename, size)
content, _, err := discord.DownloadDiscordResource(ctx, url)
if err != nil {
return nil, oops.New(err, "failed to download Discord avatar")
}
asset, err := assets.Create(ctx, conn, assets.CreateInput{
Content: content,
Filename: filename,
ContentType: "image/png",
Width: size,
Height: size,
})
if err != nil {
return nil, oops.New(err, "failed to save asset for Discord attachment")
}
return asset, nil
}