package main import ( "errors" "strings" "github.com/glebarez/sqlite" "gorm.io/gorm" ) type ormUser struct { ID int64 `gorm:"column:id;primaryKey;autoIncrement"` Email string `gorm:"column:email"` PasswordHash string `gorm:"column:password_hash"` Theme string `gorm:"column:theme"` ColorMode string `gorm:"column:color_mode"` Archive string `gorm:"column:archive_format"` GoogleSub *string `gorm:"column:google_sub"` } func (ormUser) TableName() string { return "users" } type ormRepo struct { db *gorm.DB } func newORMRepo(dbPath string) (*ormRepo, error) { db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{}) if err != nil { return nil, err } return &ormRepo{db: db}, nil } func (o *ormRepo) listUsers() ([]User, error) { var rows []ormUser if err := o.db.Order("id asc").Find(&rows).Error; err != nil { return nil, err } users := make([]User, 0, len(rows)) for _, row := range rows { users = append(users, row.toPublicUser()) } return users, nil } func (o *ormRepo) createUser(email, passwordHash, theme, colorMode, archive string, googleSub *string) (int64, error) { row := ormUser{ Email: strings.ToLower(strings.TrimSpace(email)), PasswordHash: passwordHash, Theme: normalizeTheme(theme), ColorMode: normalizeColorMode(colorMode), Archive: archive, GoogleSub: googleSub, } if err := o.db.Create(&row).Error; err != nil { return 0, err } return row.ID, nil } func (o *ormRepo) findUserWithHashByEmail(email string) (User, string, error) { var row ormUser err := o.db.Where("email = ?", strings.ToLower(strings.TrimSpace(email))).First(&row).Error if err != nil { return User{}, "", err } user := row.toPublicUser() return user, row.PasswordHash, nil } func (o *ormRepo) findUserByID(id int64) (User, error) { var row ormUser err := o.db.Where("id = ?", id).First(&row).Error if err != nil { return User{}, err } return row.toPublicUser(), nil } func (o *ormRepo) findUserByEmail(email string) (User, error) { var row ormUser err := o.db.Where("email = ?", strings.ToLower(strings.TrimSpace(email))).First(&row).Error if err != nil { return User{}, err } return row.toPublicUser(), nil } func (o *ormRepo) findUserByGoogleSub(googleSub string) (User, error) { var row ormUser err := o.db.Where("google_sub = ?", strings.TrimSpace(googleSub)).First(&row).Error if err != nil { return User{}, err } return row.toPublicUser(), nil } func (o *ormRepo) updateGoogleSub(userID int64, googleSub string) error { return o.db.Model(&ormUser{}).Where("id = ?", userID).Update("google_sub", strings.TrimSpace(googleSub)).Error } func (u ormUser) toPublicUser() User { archive := normalizeArchiveFormat(u.Archive) if archive == "" { archive = "zip" } return User{ ID: u.ID, Username: strings.ToLower(strings.TrimSpace(u.Email)), Theme: normalizeTheme(u.Theme), ColorMode: normalizeColorMode(u.ColorMode), Archive: archive, } } func isORMNotFound(err error) bool { return errors.Is(err, gorm.ErrRecordNotFound) }