Use Discord avatars as HMN avatars
This commit is contained in:
parent
2ba2fa4d7d
commit
a826f1918e
|
@ -431,7 +431,7 @@ var discordDownloadClient = &http.Client{
|
||||||
|
|
||||||
type DiscordResourceBadStatusCode error
|
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)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", oops.New(err, "failed to make Discord download request")
|
return nil, "", oops.New(err, "failed to make Discord download request")
|
||||||
|
@ -491,7 +491,7 @@ func saveAttachment(
|
||||||
height = *attachment.Height
|
height = *attachment.Height
|
||||||
}
|
}
|
||||||
|
|
||||||
content, _, err := downloadDiscordResource(ctx, attachment.Url)
|
content, _, err := DownloadDiscordResource(ctx, attachment.Url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, oops.New(err, "failed to download Discord attachment")
|
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) {
|
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 {
|
if err != nil {
|
||||||
var statusError DiscordResourceBadStatusCode
|
var statusError DiscordResourceBadStatusCode
|
||||||
if errors.As(err, &statusError) {
|
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
|
// 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]+)*)`)
|
var REDiscordTag = regexp.MustCompile(`&([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)`)
|
||||||
|
|
||||||
func getDiscordTags(content string) []string {
|
func getDiscordTags(content string) []string {
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package website
|
package website
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.handmade.network/hmn/hmn/src/assets"
|
||||||
"git.handmade.network/hmn/hmn/src/config"
|
"git.handmade.network/hmn/hmn/src/config"
|
||||||
"git.handmade.network/hmn/hmn/src/db"
|
"git.handmade.network/hmn/hmn/src/db"
|
||||||
"git.handmade.network/hmn/hmn/src/discord"
|
"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/models"
|
||||||
"git.handmade.network/hmn/hmn/src/oops"
|
"git.handmade.network/hmn/hmn/src/oops"
|
||||||
"git.handmade.network/hmn/hmn/src/utils"
|
"git.handmade.network/hmn/hmn/src/utils"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This callback handles Discord account linking whether the user is signed in
|
// 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))
|
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,
|
newHMNUser, err := db.QueryOne[models.User](c, tx,
|
||||||
`
|
`
|
||||||
INSERT INTO hmn_user (
|
INSERT INTO hmn_user (
|
||||||
username, email, password, date_joined, registration_ip
|
username, email, password, avatar_asset_id, date_joined, registration_ip
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2, '', $3, $4
|
$1, $2, '', $3, $4, $5
|
||||||
)
|
)
|
||||||
RETURNING $columns
|
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 {
|
if err != nil {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new HMN user for Discord login"))
|
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)
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue