mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
187 lines
6.0 KiB
Go
187 lines
6.0 KiB
Go
package domain
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"gorm.io/datatypes"
|
|
)
|
|
|
|
// TimelineCategory defines the category of a timeline event
|
|
type TimelineCategory string
|
|
|
|
const (
|
|
TimelineCategoryPolitical TimelineCategory = "political"
|
|
TimelineCategoryMilitary TimelineCategory = "military"
|
|
TimelineCategoryEconomic TimelineCategory = "economic"
|
|
TimelineCategoryCultural TimelineCategory = "cultural"
|
|
TimelineCategorySocial TimelineCategory = "social"
|
|
TimelineCategoryNatural TimelineCategory = "natural"
|
|
TimelineCategoryInfrastructure TimelineCategory = "infrastructure"
|
|
TimelineCategoryCriminal TimelineCategory = "criminal"
|
|
)
|
|
|
|
// TimelineKind defines the kind/type of timeline event
|
|
type TimelineKind string
|
|
|
|
const (
|
|
TimelineKindHistorical TimelineKind = "historical"
|
|
TimelineKindLegend TimelineKind = "legend"
|
|
TimelineKindMixed TimelineKind = "mixed"
|
|
)
|
|
|
|
// IsValidTimelineCategory checks if a category value is valid
|
|
func IsValidTimelineCategory(category TimelineCategory) bool {
|
|
validCategories := map[TimelineCategory]bool{
|
|
TimelineCategoryPolitical: true,
|
|
TimelineCategoryMilitary: true,
|
|
TimelineCategoryEconomic: true,
|
|
TimelineCategoryCultural: true,
|
|
TimelineCategorySocial: true,
|
|
TimelineCategoryNatural: true,
|
|
TimelineCategoryInfrastructure: true,
|
|
TimelineCategoryCriminal: true,
|
|
}
|
|
return validCategories[category]
|
|
}
|
|
|
|
// IsValidTimelineKind checks if a kind value is valid
|
|
func IsValidTimelineKind(kind TimelineKind) bool {
|
|
validKinds := map[TimelineKind]bool{
|
|
TimelineKindHistorical: true,
|
|
TimelineKindLegend: true,
|
|
TimelineKindMixed: true,
|
|
}
|
|
return validKinds[kind]
|
|
}
|
|
|
|
// TimelineItem represents a historical event or period that can be displayed in various contexts
|
|
type TimelineItem struct {
|
|
ID string `gorm:"primaryKey;type:varchar(50)" json:"id"`
|
|
Title string `gorm:"type:varchar(255);not null" json:"title"`
|
|
Content string `gorm:"type:text;not null" json:"content"`
|
|
Summary string `gorm:"type:text" json:"summary"` // Short 1-2 sentence description
|
|
ImageURL string `gorm:"type:text" json:"image_url"`
|
|
IconName string `gorm:"type:varchar(50);not null" json:"icon_name"`
|
|
Order int `gorm:"not null" json:"order"`
|
|
Heritage sql.NullBool `json:"heritage"` // Whether this item is for heritage page display (nullable to allow false)
|
|
|
|
// Time range
|
|
TimeFrom *time.Time `gorm:"type:timestamp" json:"time_from"` // Start date/time
|
|
TimeTo *time.Time `gorm:"type:timestamp" json:"time_to"` // End date/time
|
|
|
|
// Categorization
|
|
Category TimelineCategory `gorm:"type:varchar(50)" json:"category"` // political | military | economic | cultural | social | natural | infrastructure | criminal
|
|
Kind TimelineKind `gorm:"type:varchar(20)" json:"kind"` // historical | legend | mixed
|
|
IsHistorical sql.NullBool `json:"is_historical"` // Whether this is a verified historical event (nullable to allow false)
|
|
|
|
// Importance level (1-10, higher = more important)
|
|
Importance int `gorm:"default:1" json:"importance"`
|
|
|
|
// Related data as JSON arrays
|
|
// Store arrays as JSONB in Postgres. Use datatypes.JSON so GORM will
|
|
// correctly write/read JSONB columns. MarshalJSON will decode these
|
|
// into native []string when producing API responses.
|
|
Locations datatypes.JSON `gorm:"type:jsonb;default:'[]'::jsonb" json:"locations"`
|
|
Actors datatypes.JSON `gorm:"type:jsonb;default:'[]'::jsonb" json:"actors"`
|
|
Related datatypes.JSON `gorm:"type:jsonb;default:'[]'::jsonb" json:"related"`
|
|
Tags datatypes.JSON `gorm:"type:jsonb;default:'[]'::jsonb" json:"tags"`
|
|
|
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
|
}
|
|
|
|
// TableName specifies the table name for TimelineItem
|
|
func (TimelineItem) TableName() string {
|
|
return "timeline_items"
|
|
}
|
|
|
|
// GetEntityType implements Localizable interface
|
|
func (t *TimelineItem) GetEntityType() string {
|
|
return "timeline_item"
|
|
}
|
|
|
|
// GetEntityID implements Localizable interface
|
|
func (t *TimelineItem) GetEntityID() string {
|
|
return t.ID
|
|
}
|
|
|
|
// MarshalJSON implements custom JSON marshaling for TimelineItem
|
|
func (t TimelineItem) MarshalJSON() ([]byte, error) {
|
|
// Create a map for JSON serialization
|
|
result := map[string]interface{}{
|
|
"id": t.ID,
|
|
"title": t.Title,
|
|
"content": t.Content,
|
|
"summary": t.Summary,
|
|
"image_url": t.ImageURL,
|
|
"icon_name": t.IconName,
|
|
"order": t.Order,
|
|
"time_from": t.TimeFrom,
|
|
"time_to": t.TimeTo,
|
|
"category": t.Category,
|
|
"kind": t.Kind,
|
|
"importance": t.Importance,
|
|
"locations": t.Locations,
|
|
"actors": t.Actors,
|
|
"related": t.Related,
|
|
"tags": t.Tags,
|
|
"created_at": t.CreatedAt,
|
|
"updated_at": t.UpdatedAt,
|
|
}
|
|
|
|
// Handle nullable boolean fields
|
|
if t.Heritage.Valid {
|
|
result["heritage"] = t.Heritage.Bool
|
|
} else {
|
|
result["heritage"] = nil
|
|
}
|
|
|
|
if t.IsHistorical.Valid {
|
|
result["is_historical"] = t.IsHistorical.Bool
|
|
} else {
|
|
result["is_historical"] = nil
|
|
}
|
|
|
|
// Ensure stored JSON fields are valid JSON arrays. When using datatypes.JSON
|
|
// we should decode the raw bytes into Go slices for consistent API output.
|
|
// Attempt to decode locations/actors/related/tags into []string and set
|
|
// the result to the decoded slice; on failure fall back to raw JSON value.
|
|
var list []string
|
|
|
|
if len(t.Locations) > 0 {
|
|
if err := json.Unmarshal(t.Locations, &list); err == nil {
|
|
result["locations"] = list
|
|
} else {
|
|
result["locations"] = t.Locations
|
|
}
|
|
}
|
|
|
|
if len(t.Actors) > 0 {
|
|
if err := json.Unmarshal(t.Actors, &list); err == nil {
|
|
result["actors"] = list
|
|
} else {
|
|
result["actors"] = t.Actors
|
|
}
|
|
}
|
|
|
|
if len(t.Related) > 0 {
|
|
if err := json.Unmarshal(t.Related, &list); err == nil {
|
|
result["related"] = list
|
|
} else {
|
|
result["related"] = t.Related
|
|
}
|
|
}
|
|
|
|
if len(t.Tags) > 0 {
|
|
if err := json.Unmarshal(t.Tags, &list); err == nil {
|
|
result["tags"] = list
|
|
} else {
|
|
result["tags"] = t.Tags
|
|
}
|
|
}
|
|
|
|
return json.Marshal(result)
|
|
}
|