Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Build and Push Docker Image to GHCR
on:
push:
branches:
- main
- master
paths:
- 'apps/api/**'

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
45 changes: 38 additions & 7 deletions apps/api/internal/oauth/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ var (
)

type DiscordUser struct {
ID string `json:"id"`
Username string `json:"username"`
Avatar string `json:"avatar"`
Discriminator string `json:"discriminator"`
Email string `json:"email"`
ID string `json:"id"`
Username string `json:"username"`
Avatar *string `json:"avatar"`
Discriminator string `json:"discriminator"`
Email string `json:"email"`
}

type DiscordUserWithAvatarURL struct {
DiscordUser
AvatarURL *string
}

// Note: expiresIn is in seconds
Expand Down Expand Up @@ -71,7 +76,7 @@ func ExchangeDiscordCode(ctx context.Context, client *http.Client, oauthCfg *con

}

func GetDiscordUserInfo(ctx context.Context, client *http.Client, accessToken string) (*DiscordUser, error) {
func GetDiscordUserInfo(ctx context.Context, client *http.Client, accessToken string) (*DiscordUserWithAvatarURL, error) {
req, err := http.NewRequestWithContext(ctx, "GET", "https://discord.com/api/users/@me", nil)
if err != nil {
return nil, err
Expand All @@ -96,7 +101,33 @@ func GetDiscordUserInfo(ctx context.Context, client *http.Client, accessToken st
return nil, err
}

return &user, nil
// Parse real avatar URL or make nil
userWithAvatar := DiscordUserWithAvatarURL{
DiscordUser: user,
AvatarURL: user.AvatarURL(),
}

return &userWithAvatar, nil
}

func (u *DiscordUser) AvatarURL() *string {
// Only proceed if Avatar is non-nil *and* not the empty string
if u.Avatar != nil && *u.Avatar != "" {
hash := *u.Avatar

ext := "png"
if strings.HasPrefix(hash, "a_") {
ext = "gif"
}

url := fmt.Sprintf(
"https://cdn.discordapp.com/avatars/%s/%s.%s",
u.ID, hash, ext,
)
return &url
}

return nil
}

// TODO: Refactor more cleanly
Expand Down
12 changes: 10 additions & 2 deletions apps/api/internal/services/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"time"

"github.com/google/uuid"
Expand Down Expand Up @@ -109,18 +110,25 @@ func (s *AuthService) authenticateWithDiscord(ctx context.Context, code string,
return s.createSessionForExistingUser(ctx, account.UserID, ipAddress, userAgent)
}

func (s *AuthService) registerNewDiscordUser(ctx context.Context, userInfo *oauth.DiscordUser, oauthResp *oauth.DiscordExchangeResponse, ipAddress, userAgent *string) (*sqlc.AuthSession, error) {
func (s *AuthService) registerNewDiscordUser(ctx context.Context, userInfo *oauth.DiscordUserWithAvatarURL, oauthResp *oauth.DiscordExchangeResponse, ipAddress, userAgent *string) (*sqlc.AuthSession, error) {
var session *sqlc.AuthSession

err := s.txm.WithTx(ctx, func(tx pgx.Tx) error {
txUserRepo := s.userRepo.NewTx(tx)
txAccountRepo := s.accountRepo.NewTx(tx)
txSessionRepo := s.sessionRepo.NewTx(tx)

// Default avatar if no discord avatar
avatar := userInfo.AvatarURL
if avatar == nil {
custom := fmt.Sprintf("https://api.dicebear.com/9.x/initials/png?seed=%s", url.QueryEscape(userInfo.Username))
avatar = &custom
}

user, err := txUserRepo.Create(ctx, sqlc.CreateUserParams{
Name: userInfo.Username,
Email: &userInfo.Email,
Image: &userInfo.Avatar,
Image: avatar,
})
if err != nil {
return err
Expand Down