152 lines
5.0 KiB
Go
152 lines
5.0 KiB
Go
package models
|
|
|
|
import (
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// Item represents a found item
|
|
type Item struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
Name string `gorm:"type:varchar(100);not null" json:"name"`
|
|
CategoryID uint `gorm:"not null" json:"category_id"`
|
|
Category Category `gorm:"foreignKey:CategoryID" json:"category,omitempty"`
|
|
PhotoURL string `gorm:"type:varchar(255)" json:"photo_url"`
|
|
Location string `gorm:"type:varchar(200);not null" json:"location"`
|
|
Description string `gorm:"type:text;not null" json:"description"` // Keunikan (rahasia)
|
|
DateFound time.Time `gorm:"not null" json:"date_found"`
|
|
Status string `gorm:"type:varchar(50);default:'unclaimed'" json:"status"` // unclaimed, pending_claim, verified, case_closed, expired
|
|
ReporterID uint `gorm:"not null" json:"reporter_id"`
|
|
Reporter User `gorm:"foreignKey:ReporterID" json:"reporter,omitempty"`
|
|
ReporterName string `gorm:"type:varchar(100);not null" json:"reporter_name"`
|
|
ReporterContact string `gorm:"type:varchar(50);not null" json:"reporter_contact"`
|
|
ExpiresAt *time.Time `json:"expires_at"` // Auto-expire after 90 days
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
|
|
|
// Relationships
|
|
Claims []Claim `gorm:"foreignKey:ItemID" json:"claims,omitempty"`
|
|
MatchResults []MatchResult `gorm:"foreignKey:ItemID" json:"match_results,omitempty"`
|
|
RevisionLogs []RevisionLog `gorm:"foreignKey:ItemID" json:"revision_logs,omitempty"`
|
|
}
|
|
|
|
// TableName specifies the table name for Item model
|
|
func (Item) TableName() string {
|
|
return "items"
|
|
}
|
|
|
|
// Status constants
|
|
const (
|
|
ItemStatusUnclaimed = "unclaimed"
|
|
ItemStatusPendingClaim = "pending_claim"
|
|
ItemStatusVerified = "verified"
|
|
ItemStatusCaseClosed = "case_closed"
|
|
ItemStatusExpired = "expired"
|
|
)
|
|
|
|
// BeforeCreate hook to set expiration date
|
|
func (i *Item) BeforeCreate(tx *gorm.DB) error {
|
|
// Set default status
|
|
if i.Status == "" {
|
|
i.Status = ItemStatusUnclaimed
|
|
}
|
|
|
|
// Set expiration date (90 days from date found)
|
|
if i.ExpiresAt == nil {
|
|
expiresAt := i.DateFound.AddDate(0, 0, 90) // Add 90 days
|
|
i.ExpiresAt = &expiresAt
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// IsExpired checks if item has expired
|
|
func (i *Item) IsExpired() bool {
|
|
if i.ExpiresAt == nil {
|
|
return false
|
|
}
|
|
return time.Now().After(*i.ExpiresAt)
|
|
}
|
|
|
|
// CanBeClaimed checks if item can be claimed
|
|
func (i *Item) CanBeClaimed() bool {
|
|
return i.Status == ItemStatusUnclaimed && !i.IsExpired()
|
|
}
|
|
|
|
// CanBeEdited checks if item can be edited
|
|
func (i *Item) CanBeEdited() bool {
|
|
// Cannot edit if case is closed or expired
|
|
return i.Status != ItemStatusCaseClosed && i.Status != ItemStatusExpired
|
|
}
|
|
|
|
// ItemPublicResponse represents item data for public view (without sensitive info)
|
|
type ItemPublicResponse struct {
|
|
ID uint `json:"id"`
|
|
Name string `json:"name"`
|
|
Category string `json:"category"`
|
|
PhotoURL string `json:"photo_url"`
|
|
Location string `json:"location"`
|
|
DateFound time.Time `json:"date_found"`
|
|
Status string `json:"status"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// ToPublicResponse converts Item to ItemPublicResponse (hides description, reporter details)
|
|
func (i *Item) ToPublicResponse() ItemPublicResponse {
|
|
categoryName := ""
|
|
if i.Category.ID != 0 {
|
|
categoryName = i.Category.Name
|
|
}
|
|
|
|
return ItemPublicResponse{
|
|
ID: i.ID,
|
|
Name: i.Name,
|
|
Category: categoryName,
|
|
PhotoURL: i.PhotoURL,
|
|
Location: i.Location,
|
|
DateFound: i.DateFound,
|
|
Status: i.Status,
|
|
CreatedAt: i.CreatedAt,
|
|
}
|
|
}
|
|
|
|
// ItemDetailResponse represents full item data for authorized users
|
|
type ItemDetailResponse struct {
|
|
ID uint `json:"id"`
|
|
Name string `json:"name"`
|
|
Category string `json:"category"`
|
|
PhotoURL string `json:"photo_url"`
|
|
Location string `json:"location"`
|
|
Description string `json:"description"`
|
|
DateFound time.Time `json:"date_found"`
|
|
Status string `json:"status"`
|
|
ReporterName string `json:"reporter_name"`
|
|
ReporterContact string `json:"reporter_contact"`
|
|
ExpiresAt *time.Time `json:"expires_at"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// ToDetailResponse converts Item to ItemDetailResponse (includes all info)
|
|
func (i *Item) ToDetailResponse() ItemDetailResponse {
|
|
categoryName := ""
|
|
if i.Category.ID != 0 {
|
|
categoryName = i.Category.Name
|
|
}
|
|
|
|
return ItemDetailResponse{
|
|
ID: i.ID,
|
|
Name: i.Name,
|
|
Category: categoryName,
|
|
PhotoURL: i.PhotoURL,
|
|
Location: i.Location,
|
|
Description: i.Description,
|
|
DateFound: i.DateFound,
|
|
Status: i.Status,
|
|
ReporterName: i.ReporterName,
|
|
ReporterContact: i.ReporterContact,
|
|
ExpiresAt: i.ExpiresAt,
|
|
CreatedAt: i.CreatedAt,
|
|
}
|
|
} |