138 lines
4.8 KiB
Go

package models
import (
"database/sql"
"encoding/json"
"fmt"
"time"
)
// Bot represents a Nostr posting bot
type Bot struct {
ID int64 `db:"id" json:"id"`
Pubkey string `db:"pubkey" json:"pubkey"`
EncryptedPrivkey string `db:"encrypted_privkey" json:"encrypted_privkey,omitempty"`
Name string `db:"name" json:"name"`
DisplayName string `db:"display_name" json:"display_name"`
Bio string `db:"bio" json:"bio"`
Nip05 string `db:"nip05" json:"nip05"`
ZapAddress string `db:"zap_address" json:"zap_address"`
ProfilePicture string `db:"profile_picture" json:"profile_picture"`
Banner string `db:"banner" json:"banner"`
Website sql.NullString `db:"website" json:"website,omitempty"` // Changed to sql.NullString to handle NULL values
// Custom JSON marshaling is handled in MarshalJSON/UnmarshalJSON methods
CreatedAt time.Time `db:"created_at" json:"created_at"`
OwnerPubkey string `db:"owner_pubkey" json:"owner_pubkey"`
// The following are not stored in the database
PostConfig *PostConfig `json:"post_config,omitempty"`
MediaConfig *MediaConfig `json:"media_config,omitempty"`
Relays []*Relay `json:"relays,omitempty"`
}
// PostConfig represents the posting configuration for a bot
type PostConfig struct {
ID int64 `db:"id" json:"id"`
BotID int64 `db:"bot_id" json:"-"`
Hashtags string `db:"hashtags" json:"hashtags"` // JSON array stored as string
IntervalMinutes int `db:"interval_minutes" json:"interval_minutes"`
PostTemplate string `db:"post_template" json:"post_template"`
Enabled bool `db:"enabled" json:"enabled"`
}
// MediaConfig represents the media upload configuration for a bot
type MediaConfig struct {
ID int64 `db:"id" json:"id"`
BotID int64 `db:"bot_id" json:"-"`
PrimaryService string `db:"primary_service" json:"primary_service"` // "nip94" or "blossom"
FallbackService string `db:"fallback_service" json:"fallback_service"`
Nip94ServerURL string `db:"nip94_server_url" json:"nip94_server_url"`
BlossomServerURL string `db:"blossom_server_url" json:"blossom_server_url"`
}
// Relay represents a Nostr relay configuration
type Relay struct {
ID int64 `db:"id" json:"id"`
BotID int64 `db:"bot_id" json:"-"`
URL string `db:"url" json:"url"`
Read bool `db:"read" json:"read"`
Write bool `db:"write" json:"write"`
OwnerPubkey string `db:"owner_pubkey" json:"owner_pubkey,omitempty"` // Add this field
}
// Post represents a post made by the bot
type Post struct {
ID int64 `db:"id" json:"id"`
BotID int64 `db:"bot_id" json:"bot_id"`
ContentFilename string `db:"content_filename" json:"content_filename"`
MediaURL string `db:"media_url" json:"media_url"`
EventID string `db:"event_id" json:"event_id"`
Status string `db:"status" json:"status"` // "pending", "posted", "failed"
CreatedAt time.Time `db:"created_at" json:"created_at"`
Error string `db:"error" json:"error,omitempty"`
}
// MarshalJSON handles custom JSON marshaling for Bot, especially for sql.NullString fields
func (b Bot) MarshalJSON() ([]byte, error) {
type Alias Bot // Create an alias to avoid infinite recursion
// Create a copy of the bot to modify for JSON
bot := &struct {
Website interface{} `json:"website,omitempty"`
*Alias
}{
Alias: (*Alias)(&b),
}
// Handle the sql.NullString field specifically
if b.Website.Valid {
bot.Website = b.Website.String
} else {
bot.Website = nil
}
return json.Marshal(bot)
}
// UnmarshalJSON handles custom JSON unmarshaling for Bot, especially for sql.NullString fields
func (b *Bot) UnmarshalJSON(data []byte) error {
type Alias Bot // Create an alias to avoid infinite recursion
// Create a proxy structure with website as interface{}
aux := &struct {
Website interface{} `json:"website,omitempty"`
*Alias
}{
Alias: (*Alias)(b),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
// Handle possible types for the website field
if aux.Website == nil {
b.Website = sql.NullString{Valid: false}
} else {
switch v := aux.Website.(type) {
case string:
b.Website = sql.NullString{String: v, Valid: true}
case map[string]interface{}:
// Handle specific JSON format for sql.NullString
if str, ok := v["String"].(string); ok {
valid := true
if v, ok := v["Valid"].(bool); ok {
valid = v
}
b.Website = sql.NullString{String: str, Valid: valid}
}
case nil:
b.Website = sql.NullString{Valid: false}
default:
return fmt.Errorf("unsupported type for Website: %T", v)
}
}
return nil
}