sojorn/go-backend/internal/models/user.go
Patrick Britton 4eebd27e69 feat: implement Cloudflare Turnstile, terms acceptance, and email preferences
- Add Cloudflare Turnstile verification to registration flow
- Require terms of service and privacy policy acceptance
- Add email newsletter and contact preference options
- Update User model with email preference fields
- Create database migration for email preferences
- Add Turnstile service with Cloudflare API integration
- Update registration request structure with new required fields
- Add Turnstile secret key configuration
- Include development bypass for testing

Registration now requires:
- Turnstile token verification
- Terms of service acceptance
- Privacy policy acceptance
- Optional email newsletter/contact preferences
2026-02-05 08:59:05 -06:00

108 lines
4.7 KiB
Go

package models
import (
"time"
"github.com/google/uuid"
)
type UserStatus string
const (
UserStatusPending UserStatus = "pending"
UserStatusActive UserStatus = "active"
UserStatusDeactivated UserStatus = "deactivated"
)
type User struct {
ID uuid.UUID `json:"id" db:"id"`
Email string `json:"email" db:"email"`
PasswordHash string `json:"-" db:"encrypted_password"`
Status UserStatus `json:"status" db:"status"`
MFAEnabled bool `json:"mfa_enabled" db:"mfa_enabled"`
LastLogin *time.Time `json:"last_login" db:"last_login"`
EmailNewsletter bool `json:"email_newsletter" db:"email_newsletter"`
EmailContact bool `json:"email_contact" db:"email_contact"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
DeletedAt *time.Time `json:"deleted_at,omitempty" db:"deleted_at"`
}
type Profile struct {
ID uuid.UUID `json:"id" db:"id"`
Handle *string `json:"handle" db:"handle"`
DisplayName *string `json:"display_name" db:"display_name"`
Bio *string `json:"bio" db:"bio"`
AvatarURL *string `json:"avatar_url" db:"avatar_url"`
CoverURL *string `json:"cover_url" db:"cover_url"`
IsOfficial *bool `json:"is_official" db:"is_official"`
IsPrivate *bool `json:"is_private" db:"is_private"`
IsVerified *bool `json:"is_verified" db:"is_verified"`
BeaconEnabled bool `json:"beacon_enabled" db:"beacon_enabled"`
Location *string `json:"location" db:"location"`
Website *string `json:"website" db:"website"`
Interests []string `json:"interests" db:"interests"`
OriginCountry *string `json:"origin_country" db:"origin_country"`
Strikes int `json:"strikes" db:"strikes"`
IdentityKey *string `json:"identity_key" db:"identity_key"`
RegistrationID *int `json:"registration_id" db:"registration_id"`
EncryptedPrivateKey *string `json:"encrypted_private_key" db:"encrypted_private_key"`
HasCompletedOnboarding bool `json:"has_completed_onboarding" db:"has_completed_onboarding"`
Role string `json:"role" db:"role"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
// Computed fields (not stored in DB)
FollowerCount *int `json:"follower_count,omitempty" db:"-"`
FollowingCount *int `json:"following_count,omitempty" db:"-"`
}
type Follow struct {
FollowerID uuid.UUID `json:"follower_id" db:"follower_id"`
FollowingID uuid.UUID `json:"following_id" db:"following_id"`
Status string `json:"status" db:"status"` // pending, accepted
CreatedAt time.Time `json:"created_at" db:"created_at"`
}
type TrustState struct {
UserID uuid.UUID `json:"user_id" db:"user_id"`
HarmonyScore int `json:"harmony_score" db:"harmony_score"`
Tier string `json:"tier" db:"tier"` // new, trusted, established
PostsToday int `json:"posts_today" db:"posts_today"`
LastPostAt *time.Time `json:"last_post_at" db:"last_post_at"`
LastHarmonyCalcAt *time.Time `json:"last_harmony_calc_at" db:"last_harmony_calc_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
type AuthToken struct {
Token string `json:"token" db:"token"`
UserID uuid.UUID `json:"user_id" db:"user_id"`
Type string `json:"type" db:"type"`
ExpiresAt time.Time `json:"expires_at" db:"expires_at"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
}
type MFASecret struct {
UserID uuid.UUID `json:"user_id" db:"user_id"`
Secret string `json:"-" db:"secret"`
RecoveryCodes []string `json:"-" db:"recovery_codes"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
type WebAuthnCredential struct {
ID []byte `json:"id" db:"id"`
UserID uuid.UUID `json:"user_id" db:"user_id"`
PublicKey []byte `json:"public_key" db:"public_key"`
AttestationType string `json:"attestation_type" db:"attestation_type"`
AAGUID *uuid.UUID `json:"aaguid,omitempty" db:"aaguid"`
SignCount uint32 `json:"sign_count" db:"sign_count"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
LastUsedAt time.Time `json:"last_used_at" db:"last_used_at"`
}
type OneTimePrekey struct {
KeyID int `json:"key_id" db:"key_id"`
PublicKey string `json:"public_key" db:"public_key"`
}