Files
rsspipe/internal/models/models.go
T

177 lines
6.9 KiB
Go

package models
import (
"time"
)
// User represents the single admin user
type User struct {
ID string `json:"id"`
Username string `json:"username"`
PasswordHash string `json:"-"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// SearchHistoryItem tracks user search history for autocomplete
type SearchHistoryItem struct {
Keyword string `json:"keyword"`
LastSearchedAt time.Time `json:"last_searched_at"`
SearchCount int `json:"search_count"`
}
// Category represents a folder/tag grouping for feeds
type Category struct {
ID string `json:"id"`
Title string `json:"title"`
ParentID *string `json:"parent_id,omitempty"`
SortOrder int `json:"sort_order"`
FeedCount int `json:"feed_count,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
// Feed represents a subscribed RSS/Atom/JSON feed
type Feed struct {
ID string `json:"id"`
Title string `json:"title"`
FeedURL string `json:"feed_url"`
SiteURL string `json:"site_url"`
IconURL string `json:"icon_url,omitempty"`
CategoryID *string `json:"category_id,omitempty"`
CategoryTitle string `json:"category_title,omitempty"`
IsVirtualDigest bool `json:"is_virtual_digest"`
RefreshIntervalMinutes int `json:"refresh_interval_minutes"`
TimeoutSeconds int `json:"timeout_seconds"`
ETag string `json:"etag,omitempty"`
LastModified string `json:"last_modified,omitempty"`
LastFetchedAt *time.Time `json:"last_fetched_at,omitempty"`
FetchError string `json:"fetch_error,omitempty"`
UnreadCount int `json:"unread_count"`
TotalCount int `json:"total_count"`
CreatedAt time.Time `json:"created_at"`
}
// FeedEntry represents an individual article or digest entry
type FeedEntry struct {
ID string `json:"id"`
FeedID string `json:"feed_id"`
FeedTitle string `json:"feed_title"`
FeedSiteURL string `json:"feed_site_url,omitempty"`
GUID string `json:"guid"`
URL string `json:"url"`
Title string `json:"title"`
Author string `json:"author,omitempty"`
Content string `json:"content"` // Immutable original RSS content
RawContent string `json:"raw_content,omitempty"`
PublishedAt time.Time `json:"published_at"`
IsRead bool `json:"is_read"`
IsStarred bool `json:"is_starred"`
ShareUUID *string `json:"share_uuid,omitempty"`
Variants map[string]EntryVariant `json:"variants,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
// EntryVariant represents an extensible enrichment result (readability, keywords, ai_summary, tts)
type EntryVariant struct {
EntryID string `json:"entry_id"`
VariantKey string `json:"variant_key"`
ContentType string `json:"content_type"` // 'text', 'html', 'json', 'yaml', 'audio/mp3', 'binary'
TextValue string `json:"text_value,omitempty"`
BlobPath string `json:"blob_path,omitempty"`
StreamURL string `json:"stream_url,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// Rule represents a filter/automation hook rule
type Rule struct {
ID string `json:"id"`
Name string `json:"name"`
Trigger string `json:"trigger"` // 'on_post_created', 'on_post_updated', 'on_variant_updated', 'manual'
Conditions []RuleCondition `json:"conditions"`
MatchMode string `json:"match_mode"` // 'all' (AND) or 'any' (OR)
Actions []RuleAction `json:"actions"`
IsActive bool `json:"is_active"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// RuleCondition represents a single condition predicate
type RuleCondition struct {
Field string `json:"field"` // 'feed_id', 'title', 'author', 'variants.keywords', 'variants.readability_full_text'
Operator string `json:"operator"` // 'eq', 'neq', 'in', 'contains', 'matches'
Value interface{} `json:"value"`
}
// RuleAction represents an action triggered by a rule
type RuleAction struct {
Type string `json:"type"` // 'readability_scrape', 'mark_read', 'mark_starred', 'extract_keywords', 'ai_summary', 'tts'
Params map[string]interface{} `json:"params,omitempty"`
}
// Stats represents dashboard aggregate counts
type Stats struct {
TotalFeeds int `json:"total_feeds"`
TotalUnread int `json:"total_unread"`
TotalStarred int `json:"total_starred"`
TotalShared int `json:"total_shared"`
TotalCategories int `json:"total_categories"`
TotalRules int `json:"total_rules"`
}
// LoginRequest is the body for POST /api/auth/login
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
// LoginResponse is the response returned on successful auth
type LoginResponse struct {
Token string `json:"token"`
User User `json:"user"`
}
// CreateFeedRequest is the body for POST /api/feeds
type CreateFeedRequest struct {
FeedURL string `json:"feed_url"`
CategoryID *string `json:"category_id,omitempty"`
Title *string `json:"title,omitempty"`
IconURL *string `json:"icon_url,omitempty"`
RefreshIntervalMinutes *int `json:"refresh_interval_minutes,omitempty"`
TimeoutSeconds *int `json:"timeout_seconds,omitempty"`
}
// UpdateFeedRequest is the body for PUT /api/feeds/{id}
type UpdateFeedRequest struct {
Title *string `json:"title,omitempty"`
CategoryID *string `json:"category_id,omitempty"`
IconURL *string `json:"icon_url,omitempty"`
RefreshIntervalMinutes *int `json:"refresh_interval_minutes,omitempty"`
TimeoutSeconds *int `json:"timeout_seconds,omitempty"`
}
// UpdateEntryReadRequest
type UpdateEntryReadRequest struct {
IsRead bool `json:"is_read"`
}
// UpdateEntryStarRequest
type UpdateEntryStarRequest struct {
IsStarred bool `json:"is_starred"`
}
// MarkAllReadRequest
type MarkAllReadRequest struct {
FeedID *string `json:"feed_id,omitempty"`
CategoryID *string `json:"category_id,omitempty"`
Before *string `json:"before,omitempty"`
}
// ChangePasswordRequest is the body for PUT /api/auth/password
type ChangePasswordRequest struct {
OldPassword string `json:"old_password"`
NewPassword string `json:"new_password"`
}