Refactor character to types

This commit is contained in:
2025-10-10 22:24:10 +02:00
parent ef02bb810e
commit d7d3a6e888
4 changed files with 39 additions and 43 deletions

View File

@@ -3,6 +3,7 @@ package db
import ( import (
"go-eve-pi/esi" "go-eve-pi/esi"
"go-eve-pi/options" "go-eve-pi/options"
"go-eve-pi/types"
"path/filepath" "path/filepath"
"gorm.io/driver/sqlite" "gorm.io/driver/sqlite"
@@ -14,8 +15,8 @@ import (
type DB interface { type DB interface {
DB() *gorm.DB DB() *gorm.DB
Raw(sql string, args ...any) *gorm.DB Raw(sql string, args ...any) *gorm.DB
GetCharacterByName(characterName string) (*esi.Character, error) GetCharacterByName(characterName string) (*types.Character, error)
SaveCharacter(character *esi.Character) error SaveCharacter(character *types.Character) error
AutoMigrate(dst ...interface{}) error AutoMigrate(dst ...interface{}) error
GetCacheEntry(urlHash string) (*esi.CacheEntry, error) GetCacheEntry(urlHash string) (*esi.CacheEntry, error)
SaveCacheEntry(entry *esi.CacheEntry) error SaveCacheEntry(entry *esi.CacheEntry) error
@@ -59,9 +60,9 @@ func (db *DBWrapper) DB() *gorm.DB {
return db.db return db.db
} }
func (db *DBWrapper) GetCharacterByName(characterName string) (*esi.Character, error) { func (db *DBWrapper) GetCharacterByName(characterName string) (*types.Character, error) {
logger.Debug("Fetching token for character %s from database", characterName) logger.Debug("Fetching token for character %s from database", characterName)
var char esi.Character var char types.Character
err := db.db.Where("character_name = ?", characterName).First(&char).Error err := db.db.Where("character_name = ?", characterName).First(&char).Error
if err != nil { if err != nil {
logger.Debug("No token found for character %s: %v", characterName, err) logger.Debug("No token found for character %s: %v", characterName, err)
@@ -71,7 +72,7 @@ func (db *DBWrapper) GetCharacterByName(characterName string) (*esi.Character, e
return &char, nil return &char, nil
} }
func (db *DBWrapper) SaveCharacter(character *esi.Character) error { func (db *DBWrapper) SaveCharacter(character *types.Character) error {
logger.Debug("Saving token for character %s to database", character.CharacterName) logger.Debug("Saving token for character %s to database", character.CharacterName)
err := db.db.Save(character).Error err := db.db.Save(character).Error
if err != nil { if err != nil {

View File

@@ -16,6 +16,7 @@ import (
"sync" "sync"
"time" "time"
"go-eve-pi/types"
"gorm.io/gorm" "gorm.io/gorm"
logger "git.site.quack-lab.dev/dave/cylogger" logger "git.site.quack-lab.dev/dave/cylogger"
@@ -28,14 +29,11 @@ const (
issuerTokenURL = "https://login.eveonline.com/v2/oauth/token" issuerTokenURL = "https://login.eveonline.com/v2/oauth/token"
) )
type Character struct { // DB interface for database operations
ID int64 `gorm:"primaryKey"` // EVE character ID from JWT token type DB interface {
CharacterName string `gorm:"uniqueIndex"` GetCharacterByName(characterName string) (*types.Character, error)
AccessToken string SaveCharacter(character *types.Character) error
RefreshToken string AutoMigrate(dst ...interface{}) error
ExpiresAt time.Time
UpdatedAt time.Time
CreatedAt time.Time
} }
type SSO struct { type SSO struct {
@@ -54,15 +52,9 @@ type SSO struct {
} }
// NewSSO creates a new SSO instance // NewSSO creates a new SSO instance
func NewSSO(clientID, redirectURI string, scopes []string) (*SSO, error) { func NewSSO(clientID, redirectURI string, scopes []string, db DB) (*SSO, error) {
logger.Info("Creating new SSO instance for clientID %s with redirectURI %s and scopes %v", clientID, redirectURI, scopes) logger.Info("Creating new SSO instance for clientID %s with redirectURI %s and scopes %v", clientID, redirectURI, scopes)
db, err := GetDB()
if err != nil {
logger.Error("Failed to get database connection %v", err)
return nil, err
}
s := &SSO{ s := &SSO{
clientID: clientID, clientID: clientID,
redirectURI: redirectURI, redirectURI: redirectURI,
@@ -88,7 +80,7 @@ func (s *SSO) SetRouter(r *router.Router) {
func (s *SSO) initDB() error { func (s *SSO) initDB() error {
logger.Debug("Initializing SSO database schema") logger.Debug("Initializing SSO database schema")
err := s.db.AutoMigrate(&Character{}) err := s.db.AutoMigrate(&types.Character{})
if err != nil { if err != nil {
logger.Error("Failed to migrate Token table %v", err) logger.Error("Failed to migrate Token table %v", err)
return err return err
@@ -100,7 +92,7 @@ func (s *SSO) initDB() error {
// GetCharacter returns a valid character object for the given character name // GetCharacter returns a valid character object for the given character name
// If no token exists, it will start the OAuth flow // If no token exists, it will start the OAuth flow
// If token is expired, it will refresh it automatically // If token is expired, it will refresh it automatically
func (s *SSO) GetCharacter(ctx context.Context, characterName string) (Character, error) { func (s *SSO) GetCharacter(ctx context.Context, characterName string) (types.Character, error) {
logger.Debug("Getting token for character %s", characterName) logger.Debug("Getting token for character %s", characterName)
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
@@ -112,16 +104,16 @@ func (s *SSO) GetCharacter(ctx context.Context, characterName string) (Character
logger.Info("No existing token found for character %s, starting authentication flow", characterName) logger.Info("No existing token found for character %s, starting authentication flow", characterName)
// No token exists, need to authenticate // No token exists, need to authenticate
if err := s.startAuthFlow(ctx, characterName); err != nil { if err := s.startAuthFlow(ctx, characterName); err != nil {
return Character{}, err return types.Character{}, err
} }
// After authentication, fetch the token from DB // After authentication, fetch the token from DB
char, err = s.db.GetCharacterByName(characterName) char, err = s.db.GetCharacterByName(characterName)
if err != nil { if err != nil {
return Character{}, err return types.Character{}, err
} }
logger.Info("Successfully authenticated character %s", characterName) logger.Info("Successfully authenticated character %s", characterName)
} else { } else {
return Character{}, err return types.Character{}, err
} }
} else { } else {
logger.Debug("Found existing token for character %s, expires at %v", characterName, char.ExpiresAt) logger.Debug("Found existing token for character %s, expires at %v", characterName, char.ExpiresAt)
@@ -148,12 +140,12 @@ func (s *SSO) GetCharacter(ctx context.Context, characterName string) (Character
logger.Warning("Token refresh failed for character %s, re-authenticating: %v", characterName, err) logger.Warning("Token refresh failed for character %s, re-authenticating: %v", characterName, err)
// Refresh failed, need to re-authenticate // Refresh failed, need to re-authenticate
if err := s.startAuthFlow(ctx, characterName); err != nil { if err := s.startAuthFlow(ctx, characterName); err != nil {
return Character{}, err return types.Character{}, err
} }
// After re-authentication, fetch the token from DB // After re-authentication, fetch the token from DB
char, err = s.db.GetCharacterByName(characterName) char, err = s.db.GetCharacterByName(characterName)
if err != nil { if err != nil {
return Character{}, err return types.Character{}, err
} }
logger.Info("Successfully re-authenticated character %s", characterName) logger.Info("Successfully re-authenticated character %s", characterName)
} else { } else {
@@ -320,7 +312,7 @@ func (s *SSO) waitForCallback() (code, state string, err error) {
} }
} }
func (s *SSO) exchangeCodeForToken(ctx context.Context, code, verifier string) (*Character, error) { func (s *SSO) exchangeCodeForToken(ctx context.Context, code, verifier string) (*types.Character, error) {
logger.Debug("Exchanging authorization code for access token") logger.Debug("Exchanging authorization code for access token")
form := url.Values{} form := url.Values{}
form.Set("grant_type", "authorization_code") form.Set("grant_type", "authorization_code")
@@ -356,7 +348,7 @@ func (s *SSO) exchangeCodeForToken(ctx context.Context, code, verifier string) (
name, _ := parseTokenCharacter(tr.AccessToken) name, _ := parseTokenCharacter(tr.AccessToken)
logger.Info("Successfully exchanged code for token, character: %s", name) logger.Info("Successfully exchanged code for token, character: %s", name)
return &Character{ return &types.Character{
CharacterName: name, CharacterName: name,
AccessToken: tr.AccessToken, AccessToken: tr.AccessToken,
RefreshToken: tr.RefreshToken, RefreshToken: tr.RefreshToken,
@@ -364,7 +356,7 @@ func (s *SSO) exchangeCodeForToken(ctx context.Context, code, verifier string) (
}, nil }, nil
} }
func (s *SSO) refreshToken(ctx context.Context, char *Character) error { func (s *SSO) refreshToken(ctx context.Context, char *types.Character) error {
logger.Debug("Refreshing token for character %s", char.CharacterName) logger.Debug("Refreshing token for character %s", char.CharacterName)
form := url.Values{} form := url.Values{}
form.Set("grant_type", "refresh_token") form.Set("grant_type", "refresh_token")

View File

@@ -4,9 +4,9 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"strconv" "strconv"
"time"
"go-eve-pi/esi" "go-eve-pi/esi"
"go-eve-pi/types"
wh "go-eve-pi/webhook" wh "go-eve-pi/webhook"
logger "git.site.quack-lab.dev/dave/cylogger" logger "git.site.quack-lab.dev/dave/cylogger"
@@ -23,18 +23,7 @@ type RouteHandler struct {
// SSOInterface defines the interface for SSO operations // SSOInterface defines the interface for SSO operations
type SSOInterface interface { type SSOInterface interface {
GetCharacter(ctx context.Context, characterName string) (Character, error) GetCharacter(ctx context.Context, characterName string) (types.Character, error)
}
// Character represents a character with authentication info
type Character struct {
ID int64 `gorm:"primaryKey"`
CharacterName string `gorm:"uniqueIndex"`
AccessToken string
RefreshToken string
ExpiresAt time.Time
UpdatedAt time.Time
CreatedAt time.Time
} }
// NewRouteHandler creates a new route handler with dependencies // NewRouteHandler creates a new route handler with dependencies

14
types/character.go Normal file
View File

@@ -0,0 +1,14 @@
package types
import "time"
// Character represents a character with authentication info
type Character struct {
ID int64 `gorm:"primaryKey"` // EVE character ID from JWT token
CharacterName string `gorm:"uniqueIndex"`
AccessToken string
RefreshToken string
ExpiresAt time.Time
UpdatedAt time.Time
CreatedAt time.Time
}