231 lines
7.2 KiB
Go
231 lines
7.2 KiB
Go
package models
|
|
|
|
import "time"
|
|
|
|
// --- Enums (matches DB types) ---
|
|
type QuestionType string
|
|
const (
|
|
Single QuestionType = "single"
|
|
Multiple QuestionType = "multiple"
|
|
)
|
|
|
|
type DeliveryType string
|
|
const (
|
|
Physical DeliveryType = "physical"
|
|
Digital DeliveryType = "digital"
|
|
)
|
|
|
|
type PurchaseStatus string
|
|
const (
|
|
Pending PurchaseStatus = "pending"
|
|
Delivered PurchaseStatus = "delivered"
|
|
Cancelled PurchaseStatus = "cancelled"
|
|
)
|
|
|
|
type QRScanType string
|
|
const (
|
|
QRReward QRScanType = "reward"
|
|
QRQuiz QRScanType = "quiz"
|
|
QRShop QRScanType = "shop"
|
|
)
|
|
|
|
type QRScanSource string
|
|
const (
|
|
InApp QRScanSource = "in_app"
|
|
External QRScanSource = "external"
|
|
)
|
|
|
|
type AdminRole string
|
|
const (
|
|
RoleAdmin AdminRole = "admin"
|
|
RoleOperator AdminRole = "operator"
|
|
)
|
|
|
|
// --- Model Structs ---
|
|
|
|
type User struct {
|
|
TelegramID int64 `json:"telegram_id"`
|
|
Username *string `json:"username,omitempty"`
|
|
FirstName *string `json:"first_name,omitempty"`
|
|
LastName *string `json:"last_name,omitempty"`
|
|
PhotoURL *string `json:"photo_url,omitempty"`
|
|
StarsBalance int `json:"stars_balance"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type Quiz struct {
|
|
ID int `json:"id"`
|
|
Title string `json:"title"`
|
|
Description *string `json:"description,omitempty"`
|
|
ImageURL *string `json:"image_url,omitempty"`
|
|
RewardStars int `json:"reward_stars"`
|
|
HasTimer bool `json:"has_timer"`
|
|
TimerPerQuestion *int `json:"timer_per_question,omitempty"`
|
|
CanRepeat bool `json:"can_repeat"`
|
|
RepeatCooldownHours *int `json:"repeat_cooldown_hours,omitempty"`
|
|
IsActive bool `json:"is_active"`
|
|
CreatedBy *int64 `json:"created_by,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
Questions []Question `json:"questions,omitempty"` // This field is for API responses, not DB storage
|
|
}
|
|
|
|
type Question struct {
|
|
ID int `json:"id"`
|
|
QuizID int `json:"quiz_id"`
|
|
Text string `json:"text"`
|
|
Type QuestionType `json:"type"`
|
|
Options []Option `json:"options"` // Stored as JSONB
|
|
OrderIndex int `json:"order_index"`
|
|
}
|
|
|
|
type Option struct {
|
|
ID int `json:"id"`
|
|
Text string `json:"text"`
|
|
IsCorrect bool `json:"is_correct"`
|
|
}
|
|
|
|
type QuizAttempt struct {
|
|
ID int `json:"id"`
|
|
UserID int64 `json:"user_id"`
|
|
QuizID int `json:"quiz_id"`
|
|
Score int `json:"score"`
|
|
StarsEarned int `json:"stars_earned"`
|
|
CompletedAt time.Time `json:"completed_at"`
|
|
Answers []UserAnswer `json:"answers"` // Stored as JSONB
|
|
// Additional fields for response
|
|
CorrectAnswers int `json:"correct_answers"`
|
|
TotalQuestions int `json:"total_questions"`
|
|
}
|
|
|
|
type Reward struct {
|
|
ID int `json:"id"`
|
|
Title string `json:"title"`
|
|
Description *string `json:"description,omitempty"`
|
|
ImageURL *string `json:"image_url,omitempty"`
|
|
PriceStars int `json:"price_stars"`
|
|
DeliveryType DeliveryType `json:"delivery_type"`
|
|
Instructions *string `json:"instructions,omitempty"`
|
|
Stock int `json:"stock"`
|
|
IsActive bool `json:"is_active"`
|
|
CreatedBy *int64 `json:"created_by,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type Purchase struct {
|
|
ID int `json:"id"`
|
|
UserID int64 `json:"user_id"`
|
|
RewardID int `json:"reward_id"`
|
|
StarsSpent int `json:"stars_spent"`
|
|
PurchasedAt time.Time `json:"purchased_at"`
|
|
Status PurchaseStatus `json:"status"`
|
|
}
|
|
|
|
type QRScan struct {
|
|
ID int `json:"id"`
|
|
UserID int64 `json:"user_id"`
|
|
Type QRScanType `json:"type"`
|
|
Value *string `json:"value,omitempty"`
|
|
ScannedAt time.Time `json:"scanned_at"`
|
|
Source QRScanSource `json:"source"`
|
|
}
|
|
|
|
type Admin struct {
|
|
TelegramID int64 `json:"telegram_id"`
|
|
Role AdminRole `json:"role"`
|
|
Name *string `json:"name,omitempty"`
|
|
AddedBy *int64 `json:"added_by,omitempty"`
|
|
AddedAt time.Time `json:"added_at"`
|
|
}
|
|
|
|
|
|
// --- API Request/Response Structs ---
|
|
|
|
// TransactionType defines whether stars were earned or spent.
|
|
type TransactionType string
|
|
|
|
const (
|
|
TransactionEarned TransactionType = "earned"
|
|
TransactionSpent TransactionType = "spent"
|
|
)
|
|
|
|
// Transaction represents a single entry in the user's balance history.
|
|
type Transaction struct {
|
|
Type TransactionType `json:"type"`
|
|
Amount int `json:"amount"`
|
|
Description string `json:"description"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// SubmissionRequest defines the structure for a user submitting quiz answers.
|
|
type SubmissionRequest struct {
|
|
Answers []UserAnswer `json:"answers"`
|
|
}
|
|
|
|
// UserAnswer defines a single answer provided by the user.
|
|
type UserAnswer struct {
|
|
QuestionID int `json:"question_id"`
|
|
OptionIDs []int `json:"option_ids"`
|
|
}
|
|
|
|
// GrantStarsRequest defines the structure for an admin to grant stars to a user.
|
|
type GrantStarsRequest struct {
|
|
UserID int64 `json:"user_id"`
|
|
Amount int `json:"amount"`
|
|
}
|
|
|
|
// CanRepeatResponse defines the response for the can-repeat check.
|
|
type CanRepeatResponse struct {
|
|
CanRepeat bool `json:"can_repeat"`
|
|
NextAvailableAt *time.Time `json:"next_available_at,omitempty"`
|
|
}
|
|
|
|
// QRValidateRequest defines the structure for a QR validation request.
|
|
type QRValidateRequest struct {
|
|
Payload string `json:"payload"`
|
|
}
|
|
|
|
// QRValidateResponse defines the structure for a QR validation response.
|
|
type QRValidateResponse struct {
|
|
Type string `json:"type"` // e.g., "REWARD", "OPEN_QUIZ"
|
|
Data interface{} `json:"data"`
|
|
}
|
|
|
|
// GenerateQRCodesRequest defines the structure for generating unique QR codes.
|
|
type GenerateQRCodesRequest struct {
|
|
Type string `json:"type"` // e.g., "reward", "quiz"
|
|
Value string `json:"value"` // e.g., "50" for reward, "1" for quiz
|
|
Count int `json:"count"` // Number of codes to generate
|
|
}
|
|
|
|
// QRTokenData represents the data stored for a unique QR token
|
|
type QRTokenData struct {
|
|
Type string `json:"type"` // "reward", "quiz", "shop"
|
|
Value string `json:"value"` // e.g., "50", "123"
|
|
Used bool `json:"used"` // Whether the token has been used
|
|
}
|
|
|
|
// GenerateQRCodesResponse defines the response for generating QR codes
|
|
type GenerateQRCodesResponse struct {
|
|
Tokens []string `json:"tokens"` // List of generated unique tokens
|
|
}
|
|
|
|
// CreateOperatorRequest defines the structure for creating a new operator
|
|
type CreateOperatorRequest struct {
|
|
TelegramID int64 `json:"telegram_id"`
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
// Analytics represents various statistics and metrics for the admin dashboard
|
|
type Analytics struct {
|
|
TotalUsers int `json:"total_users"`
|
|
TotalQuizzes int `json:"total_quizzes"`
|
|
ActiveQuizzes int `json:"active_quizzes"`
|
|
TotalRewards int `json:"total_rewards"`
|
|
ActiveRewards int `json:"active_rewards"`
|
|
TotalAttempts int `json:"total_attempts"`
|
|
TotalPurchases int `json:"total_purchases"`
|
|
TotalQRScans int `json:"total_qr_scans"`
|
|
StarsDistributed int `json:"stars_distributed"`
|
|
StarsSpent int `json:"stars_spent"`
|
|
}
|