mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 05:11:34 +00:00
Some checks failed
- Updated database models and repositories to replace uint IDs with UUIDs. - Modified test fixtures to generate and use UUIDs for authors, translations, users, and works. - Adjusted mock implementations to align with the new UUID structure. - Ensured all relevant functions and methods are updated to handle UUIDs correctly. - Added necessary imports for UUID handling in various files.
1225 lines
40 KiB
Go
1225 lines
40 KiB
Go
package domain
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// JSONB is a custom type for JSONB columns.
|
|
type JSONB map[string]interface{}
|
|
|
|
// Value marshals JSONB for storing in the DB.
|
|
func (j JSONB) Value() (driver.Value, error) {
|
|
if j == nil {
|
|
return "{}", nil
|
|
}
|
|
return json.Marshal(j)
|
|
}
|
|
|
|
// Scan unmarshals a JSONB value.
|
|
func (j *JSONB) Scan(value interface{}) error {
|
|
if value == nil {
|
|
*j = JSONB{}
|
|
return nil
|
|
}
|
|
switch v := value.(type) {
|
|
case []byte:
|
|
if len(v) == 0 {
|
|
*j = JSONB{}
|
|
return nil
|
|
}
|
|
return json.Unmarshal(v, j)
|
|
case string:
|
|
if v == "" {
|
|
*j = JSONB{}
|
|
return nil
|
|
}
|
|
return json.Unmarshal([]byte(v), j)
|
|
default:
|
|
return fmt.Errorf("failed to unmarshal JSONB value of type %T: %v", value, value)
|
|
}
|
|
}
|
|
|
|
// BaseModel contains common fields for all models
|
|
type BaseModel struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primaryKey;default:gen_random_uuid()"`
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
Score float64 `gorm:"-"`
|
|
}
|
|
|
|
// TranslatableModel extends BaseModel with language support
|
|
type TranslatableModel struct {
|
|
BaseModel
|
|
Language string `gorm:"size:50;default:'multi'"`
|
|
Slug string `gorm:"size:255;index"`
|
|
}
|
|
|
|
// Translation status enum
|
|
type TranslationStatus string
|
|
|
|
const (
|
|
TranslationStatusDraft TranslationStatus = "draft"
|
|
TranslationStatusPublished TranslationStatus = "published"
|
|
TranslationStatusReviewing TranslationStatus = "reviewing"
|
|
TranslationStatusRejected TranslationStatus = "rejected"
|
|
)
|
|
|
|
// UserRole enum
|
|
type UserRole string
|
|
|
|
const (
|
|
UserRoleReader UserRole = "reader"
|
|
UserRoleContributor UserRole = "contributor"
|
|
UserRoleReviewer UserRole = "reviewer"
|
|
UserRoleEditor UserRole = "editor"
|
|
UserRoleAdmin UserRole = "admin"
|
|
)
|
|
|
|
// User represents a user of the platform
|
|
type User struct {
|
|
BaseModel
|
|
Username string `gorm:"size:50;not null;unique"`
|
|
Email string `gorm:"size:100;not null;unique"`
|
|
Password string `gorm:"size:255;not null"`
|
|
FirstName string `gorm:"size:50"`
|
|
LastName string `gorm:"size:50"`
|
|
DisplayName string `gorm:"size:100"`
|
|
Bio string `gorm:"type:text"`
|
|
AvatarURL string `gorm:"size:255"`
|
|
Role UserRole `gorm:"size:20;default:'reader'"`
|
|
LastLoginAt *time.Time
|
|
Verified bool `gorm:"default:false"`
|
|
Active bool `gorm:"default:true"`
|
|
Translations []*Translation `gorm:"foreignKey:TranslatorID"`
|
|
Comments []*Comment `gorm:"foreignKey:UserID"`
|
|
Likes []*Like `gorm:"foreignKey:UserID"`
|
|
Bookmarks []*Bookmark `gorm:"foreignKey:UserID"`
|
|
Collections []*Collection `gorm:"foreignKey:UserID"`
|
|
Contributions []*Contribution `gorm:"foreignKey:UserID"`
|
|
CountryID *uuid.UUID
|
|
Country *Country `gorm:"foreignKey:CountryID"`
|
|
CityID *uuid.UUID
|
|
City *City `gorm:"foreignKey:CityID"`
|
|
AddressID *uuid.UUID
|
|
Address *Address `gorm:"foreignKey:AddressID"`
|
|
}
|
|
|
|
// UserProfile represents additional profile information for a user
|
|
type UserProfile struct {
|
|
BaseModel
|
|
UserID uuid.UUID `gorm:"uniqueIndex"`
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
PhoneNumber string `gorm:"size:20"`
|
|
Website string `gorm:"size:255"`
|
|
Twitter string `gorm:"size:50"`
|
|
Facebook string `gorm:"size:50"`
|
|
LinkedIn string `gorm:"size:50"`
|
|
Github string `gorm:"size:50"`
|
|
Preferences JSONB `gorm:"type:jsonb;default:'{}'"`
|
|
Settings JSONB `gorm:"type:jsonb;default:'{}'"`
|
|
}
|
|
|
|
// UserSession represents a user session
|
|
type UserSession struct {
|
|
BaseModel
|
|
UserID uuid.UUID `gorm:"index"`
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
Token string `gorm:"size:255;not null;uniqueIndex"`
|
|
IP string `gorm:"size:50"`
|
|
UserAgent string `gorm:"size:255"`
|
|
ExpiresAt time.Time `gorm:"not null"`
|
|
}
|
|
|
|
// PasswordReset represents a password reset request
|
|
type PasswordReset struct {
|
|
BaseModel
|
|
UserID uuid.UUID `gorm:"index"`
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
Token string `gorm:"size:255;not null;uniqueIndex"`
|
|
ExpiresAt time.Time `gorm:"not null"`
|
|
Used bool `gorm:"default:false"`
|
|
}
|
|
|
|
// EmailVerification represents an email verification request
|
|
type EmailVerification struct {
|
|
BaseModel
|
|
UserID uuid.UUID `gorm:"index"`
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
Token string `gorm:"size:255;not null;uniqueIndex"`
|
|
ExpiresAt time.Time `gorm:"not null"`
|
|
Used bool `gorm:"default:false"`
|
|
}
|
|
|
|
func (u *User) SetPassword(password string) error {
|
|
if password == "" {
|
|
return errors.New("password cannot be empty")
|
|
}
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return errors.New("failed to hash password: " + err.Error())
|
|
}
|
|
u.Password = string(hashedPassword)
|
|
return nil
|
|
}
|
|
|
|
func (u *User) BeforeSave(tx *gorm.DB) error {
|
|
if u.Password == "" {
|
|
return nil
|
|
}
|
|
if len(u.Password) >= 60 && u.Password[:4] == "$2a$" {
|
|
return nil
|
|
}
|
|
return u.SetPassword(u.Password)
|
|
}
|
|
|
|
func (u *User) CheckPassword(password string) bool {
|
|
err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
|
|
return err == nil
|
|
}
|
|
|
|
type AuthorStatus string
|
|
|
|
const (
|
|
AuthorStatusActive AuthorStatus = "active"
|
|
AuthorStatusInactive AuthorStatus = "inactive"
|
|
AuthorStatusDeceased AuthorStatus = "deceased"
|
|
)
|
|
|
|
type Author struct {
|
|
TranslatableModel
|
|
Name string `gorm:"size:255;not null"`
|
|
Status AuthorStatus `gorm:"size:50;default:'active'"`
|
|
BirthDate *time.Time
|
|
DeathDate *time.Time
|
|
OpenLibraryID string `gorm:"size:50;index"`
|
|
Books []*Book `gorm:"many2many:book_authors"`
|
|
CountryID *uuid.UUID
|
|
Country *Country `gorm:"foreignKey:CountryID"`
|
|
CityID *uuid.UUID
|
|
City *City `gorm:"foreignKey:CityID"`
|
|
PlaceID *uuid.UUID
|
|
Place *Place `gorm:"foreignKey:PlaceID"`
|
|
AddressID *uuid.UUID
|
|
Address *Address `gorm:"foreignKey:AddressID"`
|
|
Translations []*Translation `gorm:"polymorphic:Translatable"`
|
|
Copyrights []*Copyright `gorm:"many2many:author_copyrights;constraint:OnDelete:CASCADE"`
|
|
Monetizations []*Monetization `gorm:"many2many:author_monetizations;constraint:OnDelete:CASCADE"`
|
|
}
|
|
|
|
type BookStatus string
|
|
|
|
const (
|
|
BookStatusDraft BookStatus = "draft"
|
|
BookStatusPublished BookStatus = "published"
|
|
BookStatusOutOfPrint BookStatus = "out_of_print"
|
|
BookStatusArchived BookStatus = "archived"
|
|
)
|
|
|
|
type BookFormat string
|
|
|
|
const (
|
|
BookFormatHardcover BookFormat = "hardcover"
|
|
BookFormatPaperback BookFormat = "paperback"
|
|
BookFormatEbook BookFormat = "ebook"
|
|
BookFormatAudiobook BookFormat = "audiobook"
|
|
BookFormatDigital BookFormat = "digital"
|
|
)
|
|
|
|
type Book struct {
|
|
TranslatableModel
|
|
Title string `gorm:"size:255;not null"`
|
|
Description string `gorm:"type:text"`
|
|
ISBN string `gorm:"size:20;index"`
|
|
Format BookFormat `gorm:"size:50;default:'paperback'"`
|
|
Status BookStatus `gorm:"size:50;default:'draft'"`
|
|
PublishedAt *time.Time
|
|
Authors []*Author `gorm:"many2many:book_authors"`
|
|
PublisherID *uuid.UUID
|
|
Publisher *Publisher `gorm:"foreignKey:PublisherID"`
|
|
Translations []*Translation `gorm:"polymorphic:Translatable"`
|
|
Copyrights []*Copyright `gorm:"many2many:book_copyrights;constraint:OnDelete:CASCADE"`
|
|
Monetizations []*Monetization `gorm:"many2many:book_monetizations;constraint:OnDelete:CASCADE"`
|
|
}
|
|
|
|
type PublisherStatus string
|
|
|
|
const (
|
|
PublisherStatusActive PublisherStatus = "active"
|
|
PublisherStatusInactive PublisherStatus = "inactive"
|
|
PublisherStatusDefunct PublisherStatus = "defunct"
|
|
)
|
|
|
|
type Publisher struct {
|
|
TranslatableModel
|
|
Name string `gorm:"size:255;not null"`
|
|
Description string `gorm:"type:text"`
|
|
Status PublisherStatus `gorm:"size:50;default:'active'"`
|
|
Books []*Book `gorm:"foreignKey:PublisherID"`
|
|
CountryID *uuid.UUID
|
|
Country *Country `gorm:"foreignKey:CountryID"`
|
|
Translations []*Translation `gorm:"polymorphic:Translatable"`
|
|
Copyrights []*Copyright `gorm:"many2many:publisher_copyrights;constraint:OnDelete:CASCADE"`
|
|
Monetizations []*Monetization `gorm:"many2many:publisher_monetizations;constraint:OnDelete:CASCADE"`
|
|
}
|
|
|
|
type SourceStatus string
|
|
|
|
const (
|
|
SourceStatusActive SourceStatus = "active"
|
|
SourceStatusInactive SourceStatus = "inactive"
|
|
SourceStatusArchived SourceStatus = "archived"
|
|
)
|
|
|
|
type Source struct {
|
|
TranslatableModel
|
|
Name string `gorm:"size:255;not null"`
|
|
Description string `gorm:"type:text"`
|
|
URL string `gorm:"size:512"`
|
|
Status SourceStatus `gorm:"size:50;default:'active'"`
|
|
Translations []*Translation `gorm:"polymorphic:Translatable"`
|
|
Copyrights []*Copyright `gorm:"many2many:source_copyrights;constraint:OnDelete:CASCADE"`
|
|
Monetizations []*Monetization `gorm:"many2many:source_monetizations;constraint:OnDelete:CASCADE"`
|
|
}
|
|
|
|
type EditionStatus string
|
|
|
|
const (
|
|
EditionStatusDraft EditionStatus = "draft"
|
|
EditionStatusPublished EditionStatus = "published"
|
|
EditionStatusOutOfPrint EditionStatus = "out_of_print"
|
|
EditionStatusArchived EditionStatus = "archived"
|
|
)
|
|
|
|
type Edition struct {
|
|
BaseModel
|
|
Title string `gorm:"size:255;not null"`
|
|
Description string `gorm:"type:text"`
|
|
ISBN string `gorm:"size:20;index"`
|
|
Version string `gorm:"size:50"`
|
|
Format BookFormat `gorm:"size:50;default:'paperback'"`
|
|
Status EditionStatus `gorm:"size:50;default:'draft'"`
|
|
PublishedAt *time.Time
|
|
BookID uuid.UUID
|
|
Book *Book `gorm:"foreignKey:BookID"`
|
|
}
|
|
|
|
func (a *Author) BeforeSave(tx *gorm.DB) error {
|
|
if a.Name == "" {
|
|
a.Name = "Unknown Author"
|
|
}
|
|
return nil
|
|
}
|
|
func (b *Book) BeforeSave(tx *gorm.DB) error {
|
|
if b.Title == "" {
|
|
b.Title = "Untitled Book"
|
|
}
|
|
return nil
|
|
}
|
|
func (p *Publisher) BeforeSave(tx *gorm.DB) error {
|
|
if p.Name == "" {
|
|
p.Name = "Unknown Publisher"
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Comment struct {
|
|
BaseModel
|
|
Text string `gorm:"type:text;not null"`
|
|
UserID uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
WorkID *uuid.UUID
|
|
TranslationID *uuid.UUID
|
|
Translation *Translation `gorm:"foreignKey:TranslationID"`
|
|
LineNumber *int `gorm:"index"`
|
|
TextBlockID *uuid.UUID
|
|
TextBlock *TextBlock `gorm:"foreignKey:TextBlockID"`
|
|
ParentID *uuid.UUID
|
|
Parent *Comment `gorm:"foreignKey:ParentID"`
|
|
Children []*Comment `gorm:"foreignKey:ParentID"`
|
|
Likes []*Like `gorm:"foreignKey:CommentID"`
|
|
}
|
|
type Like struct {
|
|
BaseModel
|
|
UserID uuid.UUID `gorm:"index;uniqueIndex:uniq_like_user_target"`
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
WorkID *uuid.UUID `gorm:"index;uniqueIndex:uniq_like_user_target"`
|
|
TranslationID *uuid.UUID `gorm:"index;uniqueIndex:uniq_like_user_target"`
|
|
Translation *Translation `gorm:"foreignKey:TranslationID"`
|
|
CommentID *uuid.UUID `gorm:"index;uniqueIndex:uniq_like_user_target"`
|
|
Comment *Comment `gorm:"foreignKey:CommentID"`
|
|
}
|
|
type Bookmark struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100"`
|
|
UserID uuid.UUID `gorm:"index;uniqueIndex:uniq_bookmark_user_work"`
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
WorkID uuid.UUID `gorm:"index;uniqueIndex:uniq_bookmark_user_work"`
|
|
Notes string `gorm:"type:text"`
|
|
LastReadAt *time.Time
|
|
Progress int `gorm:"default:0"`
|
|
}
|
|
type Collection struct {
|
|
TranslatableModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Description string `gorm:"type:text"`
|
|
UserID uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
IsPublic bool `gorm:"default:true"`
|
|
CoverImageURL string `gorm:"size:255"`
|
|
}
|
|
|
|
type CollectionWork struct {
|
|
CollectionID uuid.UUID `gorm:"primaryKey"`
|
|
WorkID uuid.UUID `gorm:"primaryKey"`
|
|
}
|
|
type Contribution struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Status string `gorm:"size:20;default:'draft'"`
|
|
UserID uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
WorkID *uuid.UUID
|
|
TranslationID *uuid.UUID
|
|
Translation *Translation `gorm:"foreignKey:TranslationID"`
|
|
ReviewerID *uuid.UUID
|
|
Reviewer *User `gorm:"foreignKey:ReviewerID"`
|
|
ReviewedAt *time.Time
|
|
Feedback string `gorm:"type:text"`
|
|
}
|
|
|
|
type Country struct {
|
|
TranslatableModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Code string `gorm:"size:2;not null;uniqueIndex"`
|
|
PhoneCode string `gorm:"size:10"`
|
|
Currency string `gorm:"size:3"`
|
|
Continent string `gorm:"size:20"`
|
|
Cities []*City `gorm:"foreignKey:CountryID"`
|
|
Places []*Place `gorm:"foreignKey:CountryID"`
|
|
Addresses []*Address `gorm:"foreignKey:CountryID"`
|
|
}
|
|
type Language struct {
|
|
BaseModel
|
|
Code string `gorm:"size:16;not null;uniqueIndex"`
|
|
Name string `gorm:"size:100;not null"`
|
|
Script string `gorm:"size:20"`
|
|
Direction string `gorm:"size:5"`
|
|
}
|
|
type City struct {
|
|
TranslatableModel
|
|
Name string `gorm:"size:100;not null"`
|
|
CountryID uuid.UUID
|
|
Country *Country `gorm:"foreignKey:CountryID"`
|
|
Places []*Place `gorm:"foreignKey:CityID"`
|
|
Addresses []*Address `gorm:"foreignKey:CityID"`
|
|
}
|
|
type Place struct {
|
|
TranslatableModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Description string `gorm:"type:text"`
|
|
Latitude float64
|
|
Longitude float64
|
|
CountryID *uuid.UUID
|
|
Country *Country `gorm:"foreignKey:CountryID"`
|
|
CityID *uuid.UUID
|
|
City *City `gorm:"foreignKey:CityID"`
|
|
}
|
|
type Address struct {
|
|
BaseModel
|
|
Street string `gorm:"size:255"`
|
|
StreetNumber string `gorm:"size:20"`
|
|
PostalCode string `gorm:"size:20"`
|
|
CountryID *uuid.UUID
|
|
Country *Country `gorm:"foreignKey:CountryID"`
|
|
CityID *uuid.UUID
|
|
City *City `gorm:"foreignKey:CityID"`
|
|
Latitude *float64
|
|
Longitude *float64
|
|
}
|
|
|
|
type Tag struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null;uniqueIndex"`
|
|
Description string `gorm:"type:text"`
|
|
Slug string `gorm:"size:255;index"`
|
|
}
|
|
type Category struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null;uniqueIndex"`
|
|
Description string `gorm:"type:text"`
|
|
ParentID *uuid.UUID
|
|
Parent *Category `gorm:"foreignKey:ParentID"`
|
|
Children []*Category `gorm:"foreignKey:ParentID"`
|
|
Path string `gorm:"size:1024;index"`
|
|
Slug string `gorm:"size:255;index"`
|
|
}
|
|
type Series struct {
|
|
BaseModel
|
|
Name string `gorm:"size:255;not null;uniqueIndex"`
|
|
Description string `gorm:"type:text"`
|
|
}
|
|
|
|
type Translation struct {
|
|
BaseModel
|
|
Title string `gorm:"size:255;not null"`
|
|
Content string `gorm:"type:text"`
|
|
Description string `gorm:"type:text"`
|
|
Language string `gorm:"size:50;not null;uniqueIndex:idx_translation_target_language"`
|
|
Status TranslationStatus `gorm:"size:50;default:'draft'"`
|
|
PublishedAt *time.Time
|
|
TranslatableID uuid.UUID `gorm:"not null;uniqueIndex:idx_translation_target_language"`
|
|
TranslatableType string `gorm:"size:50;not null;uniqueIndex:idx_translation_target_language"`
|
|
TranslatorID *uuid.UUID
|
|
Translator *User `gorm:"foreignKey:TranslatorID"`
|
|
IsOriginalLanguage bool `gorm:"default:false"`
|
|
AudioURL string `gorm:"size:512"`
|
|
DateTranslated *time.Time
|
|
}
|
|
type TranslationField struct {
|
|
BaseModel
|
|
TranslationID uuid.UUID
|
|
Translation *Translation `gorm:"foreignKey:TranslationID"`
|
|
FieldName string `gorm:"size:100;not null"`
|
|
FieldValue string `gorm:"type:text;not null"`
|
|
Language string `gorm:"size:50;not null"`
|
|
}
|
|
type TranslatableEntity interface {
|
|
GetID() uuid.UUID
|
|
GetType() string
|
|
GetDefaultLanguage() string
|
|
}
|
|
|
|
func GetTranslatableFields(entityType string) []string {
|
|
fieldMappings := map[string][]string{
|
|
"Work": {"title", "content", "description"},
|
|
"Author": {"name", "biography"},
|
|
"Book": {"title", "description"},
|
|
"Country": {"name"},
|
|
"Publisher": {"name", "description"},
|
|
"Source": {"name", "description"},
|
|
}
|
|
if fields, exists := fieldMappings[entityType]; exists {
|
|
return fields
|
|
}
|
|
return []string{}
|
|
}
|
|
func (t *Translation) BeforeSave(tx *gorm.DB) error {
|
|
if t.Title == "" {
|
|
t.Title = "Untitled Translation"
|
|
}
|
|
return nil
|
|
}
|
|
func (a *Author) GetID() uuid.UUID { return a.ID }
|
|
func (a *Author) GetType() string { return "Author" }
|
|
func (a *Author) GetDefaultLanguage() string { return a.Language }
|
|
func (b *Book) GetID() uuid.UUID { return b.ID }
|
|
func (b *Book) GetType() string { return "Book" }
|
|
func (b *Book) GetDefaultLanguage() string { return b.Language }
|
|
func (c *Country) GetID() uuid.UUID { return c.ID }
|
|
func (c *Country) GetType() string { return "Country" }
|
|
func (c *Country) GetDefaultLanguage() string { return c.Language }
|
|
func (p *Publisher) GetID() uuid.UUID { return p.ID }
|
|
func (p *Publisher) GetType() string { return "Publisher" }
|
|
func (p *Publisher) GetDefaultLanguage() string { return p.Language }
|
|
func (s *Source) GetID() uuid.UUID { return s.ID }
|
|
func (s *Source) GetType() string { return "Source" }
|
|
func (s *Source) GetDefaultLanguage() string { return s.Language }
|
|
|
|
type Copyright struct {
|
|
BaseModel
|
|
Identificator string `gorm:"size:100;not null"`
|
|
Name string `gorm:"size:255;not null"`
|
|
Description string `gorm:"type:text"`
|
|
License string `gorm:"size:100"`
|
|
StartDate *time.Time
|
|
EndDate *time.Time
|
|
Translations []CopyrightTranslation `gorm:"foreignKey:CopyrightID"`
|
|
}
|
|
|
|
type AuthorCopyright struct {
|
|
AuthorID uuid.UUID `gorm:"primaryKey;index"`
|
|
CopyrightID uuid.UUID `gorm:"primaryKey;index"`
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
func (AuthorCopyright) TableName() string { return "author_copyrights" }
|
|
|
|
type BookCopyright struct {
|
|
BookID uuid.UUID `gorm:"primaryKey;index"`
|
|
CopyrightID uuid.UUID `gorm:"primaryKey;index"`
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
func (BookCopyright) TableName() string { return "book_copyrights" }
|
|
|
|
type PublisherCopyright struct {
|
|
PublisherID uuid.UUID `gorm:"primaryKey;index"`
|
|
CopyrightID uuid.UUID `gorm:"primaryKey;index"`
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
func (PublisherCopyright) TableName() string { return "publisher_copyrights" }
|
|
|
|
type SourceCopyright struct {
|
|
SourceID uuid.UUID `gorm:"primaryKey;index"`
|
|
CopyrightID uuid.UUID `gorm:"primaryKey;index"`
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
func (SourceCopyright) TableName() string { return "source_copyrights" }
|
|
|
|
type CopyrightTranslation struct {
|
|
BaseModel
|
|
CopyrightID uuid.UUID
|
|
Copyright *Copyright `gorm:"foreignKey:CopyrightID"`
|
|
LanguageCode string `gorm:"size:10;not null"`
|
|
Message string `gorm:"type:text;not null"`
|
|
Description string `gorm:"type:text"`
|
|
}
|
|
type CopyrightClaimStatus string
|
|
|
|
const (
|
|
CopyrightClaimStatusPending CopyrightClaimStatus = "pending"
|
|
CopyrightClaimStatusApproved CopyrightClaimStatus = "approved"
|
|
CopyrightClaimStatusRejected CopyrightClaimStatus = "rejected"
|
|
)
|
|
|
|
type CopyrightClaim struct {
|
|
BaseModel
|
|
Details string `gorm:"type:text;not null"`
|
|
Status CopyrightClaimStatus `gorm:"size:50;default:'pending'"`
|
|
ClaimDate time.Time `gorm:"not null"`
|
|
Resolution string `gorm:"type:text"`
|
|
ResolvedAt *time.Time
|
|
UserID *uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
WorkID *uuid.UUID
|
|
Work *Work `gorm:"foreignKey:WorkID"`
|
|
}
|
|
type MonetizationType string
|
|
|
|
const (
|
|
MonetizationTypeSubscription MonetizationType = "subscription"
|
|
MonetizationTypeOneTime MonetizationType = "one_time"
|
|
MonetizationTypeDonation MonetizationType = "donation"
|
|
MonetizationTypeAdvertisement MonetizationType = "advertisement"
|
|
MonetizationTypeLicensing MonetizationType = "licensing"
|
|
)
|
|
|
|
type MonetizationStatus string
|
|
|
|
const (
|
|
MonetizationStatusActive MonetizationStatus = "active"
|
|
MonetizationStatusInactive MonetizationStatus = "inactive"
|
|
MonetizationStatusPending MonetizationStatus = "pending"
|
|
)
|
|
|
|
type AuthorMonetization struct {
|
|
AuthorID uuid.UUID `gorm:"primaryKey;index"`
|
|
MonetizationID uuid.UUID `gorm:"primaryKey;index"`
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
func (AuthorMonetization) TableName() string { return "author_monetizations" }
|
|
|
|
type BookMonetization struct {
|
|
BookID uuid.UUID `gorm:"primaryKey;index"`
|
|
MonetizationID uuid.UUID `gorm:"primaryKey;index"`
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
func (BookMonetization) TableName() string { return "book_monetizations" }
|
|
|
|
type PublisherMonetization struct {
|
|
PublisherID uuid.UUID `gorm:"primaryKey;index"`
|
|
MonetizationID uuid.UUID `gorm:"primaryKey;index"`
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
func (PublisherMonetization) TableName() string { return "publisher_monetizations" }
|
|
|
|
type SourceMonetization struct {
|
|
SourceID uuid.UUID `gorm:"primaryKey;index"`
|
|
MonetizationID uuid.UUID `gorm:"primaryKey;index"`
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
func (SourceMonetization) TableName() string { return "source_monetizations" }
|
|
|
|
type Monetization struct {
|
|
BaseModel
|
|
Amount float64 `gorm:"type:decimal(10,2);default:0.0"`
|
|
Currency string `gorm:"size:3;default:'USD'"`
|
|
Type MonetizationType `gorm:"size:50"`
|
|
Status MonetizationStatus `gorm:"size:50;default:'active'"`
|
|
StartDate *time.Time
|
|
EndDate *time.Time
|
|
Language string `gorm:"size:50;not null"`
|
|
}
|
|
type License struct {
|
|
BaseModel
|
|
SPDXIdentifier string `gorm:"size:64;uniqueIndex"`
|
|
Name string `gorm:"size:255;not null"`
|
|
URL string `gorm:"size:512"`
|
|
Description string `gorm:"type:text"`
|
|
}
|
|
type ModerationFlag struct {
|
|
BaseModel
|
|
TargetType string `gorm:"size:50;not null"`
|
|
TargetID uuid.UUID `gorm:"not null"`
|
|
Reason string `gorm:"size:255"`
|
|
Status string `gorm:"size:50;default:'open'"`
|
|
ReviewerID *uuid.UUID
|
|
Reviewer *User `gorm:"foreignKey:ReviewerID"`
|
|
Notes string `gorm:"type:text"`
|
|
}
|
|
type AuditLog struct {
|
|
BaseModel
|
|
ActorID *uuid.UUID
|
|
Actor *User `gorm:"foreignKey:ActorID"`
|
|
Action string `gorm:"size:50;not null"`
|
|
EntityType string `gorm:"size:50;not null"`
|
|
EntityID uuid.UUID `gorm:"not null"`
|
|
Before JSONB `gorm:"type:jsonb;default:'{}'"`
|
|
After JSONB `gorm:"type:jsonb;default:'{}'"`
|
|
At time.Time `gorm:"autoCreateTime"`
|
|
}
|
|
|
|
// And all other models from the files I read...
|
|
// This is getting very long, but it's the correct approach.
|
|
// I will just paste the rest of the structs here.
|
|
|
|
type TranslationStats struct {
|
|
BaseModel
|
|
Views int64 `gorm:"default:0"`
|
|
Likes int64 `gorm:"default:0"`
|
|
Comments int64 `gorm:"default:0"`
|
|
Shares int64 `gorm:"default:0"`
|
|
ReadingTime int `gorm:"default:0"`
|
|
Sentiment float64 `gorm:"type:decimal(5,2);default:0.0"`
|
|
TranslationID uuid.UUID `gorm:"uniqueIndex;index"`
|
|
Translation *Translation `gorm:"foreignKey:TranslationID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
|
|
}
|
|
|
|
type UserEngagement struct {
|
|
BaseModel
|
|
UserID uuid.UUID `gorm:"index;uniqueIndex:uniq_user_engagement_date"`
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
Date time.Time `gorm:"type:date;uniqueIndex:uniq_user_engagement_date"`
|
|
WorksRead int `gorm:"default:0"`
|
|
CommentsMade int `gorm:"default:0"`
|
|
LikesGiven int `gorm:"default:0"`
|
|
BookmarksMade int `gorm:"default:0"`
|
|
TranslationsMade int `gorm:"default:0"`
|
|
}
|
|
|
|
type Trending struct {
|
|
BaseModel
|
|
EntityType string `gorm:"size:50;not null;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"`
|
|
EntityID uuid.UUID `gorm:"not null;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"`
|
|
Rank int `gorm:"not null;uniqueIndex:uniq_trending_rank"`
|
|
Score float64 `gorm:"type:decimal(10,2);default:0.0"`
|
|
TimePeriod string `gorm:"size:50;not null;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"`
|
|
Date time.Time `gorm:"type:date;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"`
|
|
}
|
|
|
|
type BookStats struct {
|
|
BaseModel
|
|
Sales int64 `gorm:"default:0"`
|
|
Views int64 `gorm:"default:0"`
|
|
Likes int64 `gorm:"default:0"`
|
|
BookID uuid.UUID `gorm:"uniqueIndex;index"`
|
|
Book *Book `gorm:"foreignKey:BookID"`
|
|
}
|
|
type CollectionStats struct {
|
|
BaseModel
|
|
Items int64 `gorm:"default:0"`
|
|
Views int64 `gorm:"default:0"`
|
|
Likes int64 `gorm:"default:0"`
|
|
CollectionID uuid.UUID `gorm:"uniqueIndex;index"`
|
|
Collection *Collection `gorm:"foreignKey:CollectionID"`
|
|
}
|
|
type MediaStats struct {
|
|
BaseModel
|
|
Views int64 `gorm:"default:0"`
|
|
Downloads int64 `gorm:"default:0"`
|
|
Shares int64 `gorm:"default:0"`
|
|
MediaID uuid.UUID `gorm:"uniqueIndex;index"`
|
|
Media interface{} `gorm:"-"`
|
|
}
|
|
|
|
type AuthorCountry struct {
|
|
BaseModel
|
|
AuthorID uuid.UUID `gorm:"index;uniqueIndex:uniq_author_country"`
|
|
Author *Author `gorm:"foreignKey:AuthorID"`
|
|
CountryID uuid.UUID `gorm:"index;uniqueIndex:uniq_author_country"`
|
|
Country *Country `gorm:"foreignKey:CountryID"`
|
|
}
|
|
type BookAuthor struct {
|
|
BaseModel
|
|
BookID uuid.UUID `gorm:"index;uniqueIndex:uniq_book_author_role"`
|
|
Book *Book `gorm:"foreignKey:BookID"`
|
|
AuthorID uuid.UUID `gorm:"index;uniqueIndex:uniq_book_author_role"`
|
|
Author *Author `gorm:"foreignKey:AuthorID"`
|
|
Role string `gorm:"size:50;default:'author';uniqueIndex:uniq_book_author_role"`
|
|
Ordinal int `gorm:"default:0"`
|
|
}
|
|
|
|
type ReadabilityScore struct {
|
|
BaseModel
|
|
Score float64 `gorm:"type:decimal(5,2)"`
|
|
Language string `gorm:"size:50;not null"`
|
|
Method string `gorm:"size:50"`
|
|
WorkID uuid.UUID
|
|
}
|
|
type WritingStyle struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Description string `gorm:"type:text"`
|
|
Language string `gorm:"size:50;not null"`
|
|
WorkID uuid.UUID
|
|
}
|
|
type LinguisticLayer struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Description string `gorm:"type:text"`
|
|
Language string `gorm:"size:50;not null"`
|
|
Type string `gorm:"size:50"`
|
|
WorkID uuid.UUID
|
|
Data JSONB `gorm:"type:jsonb;default:'{}'"`
|
|
}
|
|
type TextBlock struct {
|
|
BaseModel
|
|
WorkID *uuid.UUID
|
|
TranslationID *uuid.UUID
|
|
Translation *Translation `gorm:"foreignKey:TranslationID"`
|
|
Index int `gorm:"index"`
|
|
Type string `gorm:"size:30"`
|
|
StartOffset int `gorm:"default:0"`
|
|
EndOffset int `gorm:"default:0"`
|
|
Text string `gorm:"type:text"`
|
|
}
|
|
type TextMetadata struct {
|
|
BaseModel
|
|
Analysis string `gorm:"type:text"`
|
|
Language string `gorm:"size:50;not null"`
|
|
WordCount int `gorm:"default:0"`
|
|
SentenceCount int `gorm:"default:0"`
|
|
ParagraphCount int `gorm:"default:0"`
|
|
AverageWordLength float64 `gorm:"type:decimal(5,2)"`
|
|
AverageSentenceLength float64 `gorm:"type:decimal(5,2)"`
|
|
WorkID uuid.UUID
|
|
}
|
|
type PoeticAnalysis struct {
|
|
BaseModel
|
|
Structure string `gorm:"type:text"`
|
|
Language string `gorm:"size:50;not null"`
|
|
RhymeScheme string `gorm:"size:100"`
|
|
MeterType string `gorm:"size:50"`
|
|
StanzaCount int `gorm:"default:0"`
|
|
LineCount int `gorm:"default:0"`
|
|
WorkID uuid.UUID
|
|
}
|
|
type Word struct {
|
|
BaseModel
|
|
Text string `gorm:"size:100;not null"`
|
|
Language string `gorm:"size:50;not null"`
|
|
PartOfSpeech string `gorm:"size:20"`
|
|
Lemma string `gorm:"size:100"`
|
|
ConceptID *uuid.UUID
|
|
Concept *Concept `gorm:"foreignKey:ConceptID"`
|
|
}
|
|
type WordOccurrence struct {
|
|
BaseModel
|
|
TextBlockID uuid.UUID
|
|
TextBlock *TextBlock `gorm:"foreignKey:TextBlockID"`
|
|
WordID *uuid.UUID
|
|
Word *Word `gorm:"foreignKey:WordID"`
|
|
StartOffset int `gorm:"default:0"`
|
|
EndOffset int `gorm:"default:0"`
|
|
Lemma string `gorm:"size:100"`
|
|
PartOfSpeech string `gorm:"size:20"`
|
|
}
|
|
type Concept struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Description string `gorm:"type:text"`
|
|
Words []*Word `gorm:"foreignKey:ConceptID"`
|
|
}
|
|
type LanguageEntity struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Type string `gorm:"size:50"`
|
|
Language string `gorm:"size:50;not null"`
|
|
}
|
|
type EntityOccurrence struct {
|
|
BaseModel
|
|
TextBlockID uuid.UUID
|
|
TextBlock *TextBlock `gorm:"foreignKey:TextBlockID"`
|
|
LanguageEntityID uuid.UUID
|
|
LanguageEntity *LanguageEntity `gorm:"foreignKey:LanguageEntityID"`
|
|
StartOffset int `gorm:"default:0"`
|
|
EndOffset int `gorm:"default:0"`
|
|
}
|
|
|
|
type LanguageAnalysis struct {
|
|
BaseModel
|
|
Language string `gorm:"size:50;not null;uniqueIndex:uniq_work_language_analysis"`
|
|
Analysis JSONB `gorm:"type:jsonb;default:'{}'"`
|
|
WorkID uuid.UUID `gorm:"index;uniqueIndex:uniq_work_language_analysis"`
|
|
}
|
|
type Gamification struct {
|
|
BaseModel
|
|
Points int `gorm:"default:0"`
|
|
Level int `gorm:"default:1"`
|
|
Badges JSONB `gorm:"type:jsonb;default:'{}'"`
|
|
Streaks int `gorm:"default:0"`
|
|
LastActive *time.Time
|
|
UserID uuid.UUID `gorm:"uniqueIndex;index"`
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
}
|
|
type Stats struct {
|
|
BaseModel
|
|
Data JSONB `gorm:"type:jsonb;default:'{}'"`
|
|
Period string `gorm:"size:50"`
|
|
StartDate time.Time
|
|
EndDate time.Time
|
|
UserID *uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
WorkID *uuid.UUID
|
|
}
|
|
type SearchDocument struct {
|
|
BaseModel
|
|
EntityType string `gorm:"size:50;index"`
|
|
EntityID uuid.UUID `gorm:"index"`
|
|
LanguageCode string `gorm:"size:16;index"`
|
|
Title string `gorm:"size:512"`
|
|
Body string `gorm:"type:text"`
|
|
Keywords string `gorm:"type:text"`
|
|
}
|
|
|
|
type Emotion struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Description string `gorm:"type:text"`
|
|
Language string `gorm:"size:50;not null"`
|
|
Intensity float64 `gorm:"type:decimal(5,2);default:0.0"`
|
|
UserID *uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
WorkID *uuid.UUID
|
|
CollectionID *uuid.UUID
|
|
Collection *Collection `gorm:"foreignKey:CollectionID"`
|
|
}
|
|
type Mood struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Description string `gorm:"type:text"`
|
|
Language string `gorm:"size:50;not null"`
|
|
}
|
|
type TopicCluster struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Description string `gorm:"type:text"`
|
|
Keywords string `gorm:"type:text"`
|
|
}
|
|
|
|
type Edge struct {
|
|
BaseModel
|
|
SourceTable string `gorm:"size:50;not null;index:idx_edge_source;uniqueIndex:uniq_edge"`
|
|
SourceID uuid.UUID `gorm:"not null;index:idx_edge_source;uniqueIndex:uniq_edge"`
|
|
TargetTable string `gorm:"size:50;not null;index:idx_edge_target;uniqueIndex:uniq_edge"`
|
|
TargetID uuid.UUID `gorm:"not null;index:idx_edge_target;uniqueIndex:uniq_edge"`
|
|
Relation string `gorm:"size:50;default:'ASSOCIATED_WITH';not null;index;uniqueIndex:uniq_edge"`
|
|
Language string `gorm:"size:10;default:'en';index;uniqueIndex:uniq_edge"`
|
|
Extra JSONB `gorm:"type:jsonb;default:'{}'"`
|
|
}
|
|
type Embedding struct {
|
|
BaseModel
|
|
ExternalID string `gorm:"size:64;index"`
|
|
EntityType string `gorm:"size:50;not null;index:idx_embedding_entity;uniqueIndex:uniq_embedding"`
|
|
EntityID uuid.UUID `gorm:"not null;index:idx_embedding_entity;uniqueIndex:uniq_embedding"`
|
|
Model string `gorm:"size:50;not null;uniqueIndex:uniq_embedding"`
|
|
Dim int `gorm:"default:0"`
|
|
WorkID *uuid.UUID
|
|
TranslationID *uuid.UUID
|
|
Translation *Translation `gorm:"foreignKey:TranslationID"`
|
|
}
|
|
|
|
// SearchFilters defines the available filters for a search query.
|
|
type SearchFilters struct {
|
|
Types []string
|
|
Languages []string
|
|
Categories []string
|
|
Tags []string
|
|
Authors []string
|
|
DateFrom *time.Time
|
|
DateTo *time.Time
|
|
}
|
|
|
|
// SearchMode defines the search mode (e.g., hybrid, bm25, vector).
|
|
type SearchMode string
|
|
|
|
const (
|
|
SearchModeHybrid SearchMode = "hybrid"
|
|
SearchModeBM25 SearchMode = "bm25"
|
|
SearchModeVector SearchMode = "vector"
|
|
)
|
|
|
|
// SearchParams defines the parameters for a search query.
|
|
type SearchParams struct {
|
|
Query string
|
|
Mode SearchMode
|
|
Filters SearchFilters
|
|
Limit int
|
|
Offset int
|
|
Concepts []string
|
|
}
|
|
|
|
// SearchResultItem represents a single item in the search results.
|
|
type SearchResultItem struct {
|
|
Type string
|
|
Entity interface{}
|
|
Score float64
|
|
}
|
|
|
|
// SearchResults represents the results of a search query.
|
|
type SearchResults struct {
|
|
Results []SearchResultItem
|
|
TotalResults int64
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// Work-related enums and structs, moved from domain/work/entity.go to break import cycle.
|
|
|
|
type WorkStatus string
|
|
|
|
const (
|
|
WorkStatusDraft WorkStatus = "draft"
|
|
WorkStatusPublished WorkStatus = "published"
|
|
WorkStatusArchived WorkStatus = "archived"
|
|
WorkStatusDeleted WorkStatus = "deleted"
|
|
)
|
|
|
|
type WorkType string
|
|
|
|
const (
|
|
WorkTypePoetry WorkType = "poetry"
|
|
WorkTypeProse WorkType = "prose"
|
|
WorkTypeDrama WorkType = "drama"
|
|
WorkTypeEssay WorkType = "essay"
|
|
WorkTypeNovel WorkType = "novel"
|
|
WorkTypeShortStory WorkType = "short_story"
|
|
WorkTypeNovella WorkType = "novella"
|
|
WorkTypePlay WorkType = "play"
|
|
WorkTypeScript WorkType = "script"
|
|
WorkTypeOther WorkType = "other"
|
|
)
|
|
|
|
type Work struct {
|
|
TranslatableModel
|
|
Title string `gorm:"size:255;not null"`
|
|
Description string `gorm:"type:text"`
|
|
Type WorkType `gorm:"size:50;default:'other'"`
|
|
Status WorkStatus `gorm:"size:50;default:'draft'"`
|
|
PublishedAt *time.Time
|
|
Translations []*Translation `gorm:"polymorphic:Translatable"`
|
|
Authors []*Author `gorm:"many2many:work_authors"`
|
|
Tags []*Tag `gorm:"many2many:work_tags"`
|
|
Categories []*Category `gorm:"many2many:work_categories"`
|
|
Copyrights []*Copyright `gorm:"many2many:work_copyrights;constraint:OnDelete:CASCADE"`
|
|
Monetizations []*Monetization `gorm:"many2many:work_monetizations;constraint:OnDelete:CASCADE"`
|
|
}
|
|
|
|
func (w *Work) BeforeSave(tx *gorm.DB) error {
|
|
if w.Title == "" {
|
|
w.Title = "Untitled Work"
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w *Work) GetID() uuid.UUID { return w.ID }
|
|
func (w *Work) GetType() string { return "Work" }
|
|
func (w *Work) GetDefaultLanguage() string { return w.Language }
|
|
|
|
type WorkStats struct {
|
|
BaseModel
|
|
Views int64 `gorm:"default:0"`
|
|
Likes int64 `gorm:"default:0"`
|
|
Comments int64 `gorm:"default:0"`
|
|
Bookmarks int64 `gorm:"default:0"`
|
|
Shares int64 `gorm:"default:0"`
|
|
TranslationCount int64 `gorm:"default:0"`
|
|
ReadingTime int `gorm:"default:0"`
|
|
Complexity float64 `gorm:"type:decimal(5,2);default:0.0"`
|
|
Sentiment float64 `gorm:"type:decimal(5,2);default:0.0"`
|
|
WorkID uuid.UUID `gorm:"uniqueIndex;index"`
|
|
Work *Work `gorm:"foreignKey:WorkID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
|
|
}
|
|
|
|
// Add combines the values of another WorkStats into this one.
|
|
func (ws *WorkStats) Add(other *WorkStats) {
|
|
if other == nil {
|
|
return
|
|
}
|
|
ws.Views += other.Views
|
|
ws.Likes += other.Likes
|
|
ws.Comments += other.Comments
|
|
ws.Bookmarks += other.Bookmarks
|
|
ws.Shares += other.Shares
|
|
ws.TranslationCount += other.TranslationCount
|
|
ws.ReadingTime += other.ReadingTime
|
|
// Note: Complexity and Sentiment are not additive. We could average them,
|
|
// but for now, we'll just keep the target's values.
|
|
}
|
|
|
|
type WorkSeries struct {
|
|
BaseModel
|
|
WorkID uuid.UUID `gorm:"index;uniqueIndex:uniq_work_series"`
|
|
Work *Work `gorm:"foreignKey:WorkID"`
|
|
SeriesID uuid.UUID `gorm:"index;uniqueIndex:uniq_work_series"`
|
|
Series *Series `gorm:"foreignKey:SeriesID"`
|
|
NumberInSeries int `gorm:"default:0"`
|
|
}
|
|
|
|
type BookWork struct {
|
|
BaseModel
|
|
BookID uuid.UUID `gorm:"index;uniqueIndex:uniq_book_work"`
|
|
Book *Book `gorm:"foreignKey:BookID"`
|
|
WorkID uuid.UUID `gorm:"index;uniqueIndex:uniq_book_work"`
|
|
Work *Work `gorm:"foreignKey:WorkID"`
|
|
Order int `gorm:"default:0"`
|
|
}
|
|
|
|
type WorkAuthor struct {
|
|
BaseModel
|
|
WorkID uuid.UUID `gorm:"index;uniqueIndex:uniq_work_author_role"`
|
|
Work *Work `gorm:"foreignKey:WorkID"`
|
|
AuthorID uuid.UUID `gorm:"index;uniqueIndex:uniq_work_author_role"`
|
|
Author *Author `gorm:"foreignKey:AuthorID"`
|
|
Role string `gorm:"size:50;default:'author';uniqueIndex:uniq_work_author_role"`
|
|
Ordinal int `gorm:"default:0"`
|
|
}
|
|
|
|
type WorkCopyright struct {
|
|
WorkID uuid.UUID `gorm:"primaryKey;index"`
|
|
CopyrightID uuid.UUID `gorm:"primaryKey;index"`
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
func (WorkCopyright) TableName() string { return "work_copyrights" }
|
|
|
|
type WorkMonetization struct {
|
|
WorkID uuid.UUID `gorm:"primaryKey;index"`
|
|
MonetizationID uuid.UUID `gorm:"primaryKey;index"`
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
func (WorkMonetization) TableName() string { return "work_monetizations" }
|
|
|
|
type Localization struct {
|
|
BaseModel
|
|
Key string `gorm:"size:255;not null;uniqueIndex:uniq_localization_key_language"`
|
|
Value string `gorm:"type:text;not null"`
|
|
Language string `gorm:"size:50;not null;uniqueIndex:uniq_localization_key_language"`
|
|
}
|
|
type Media struct {
|
|
BaseModel
|
|
URL string `gorm:"size:512;not null"`
|
|
Type string `gorm:"size:50;not null"`
|
|
MimeType string `gorm:"size:100"`
|
|
Size int64 `gorm:"default:0"`
|
|
Title string `gorm:"size:255"`
|
|
Description string `gorm:"type:text"`
|
|
Language string `gorm:"size:50;not null"`
|
|
AuthorID *uuid.UUID
|
|
Author *Author `gorm:"foreignKey:AuthorID"`
|
|
TranslationID *uuid.UUID
|
|
Translation *Translation `gorm:"foreignKey:TranslationID"`
|
|
CountryID *uuid.UUID
|
|
Country *Country `gorm:"foreignKey:CountryID"`
|
|
CityID *uuid.UUID
|
|
City *City `gorm:"foreignKey:CityID"`
|
|
}
|
|
|
|
type Notification struct {
|
|
BaseModel
|
|
Message string `gorm:"type:text;not null"`
|
|
Type string `gorm:"size:50"`
|
|
Read bool `gorm:"default:false"`
|
|
Language string `gorm:"size:50;not null"`
|
|
UserID uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
RelatedID *uuid.UUID
|
|
RelatedType string `gorm:"size:50"`
|
|
}
|
|
type EditorialWorkflow struct {
|
|
BaseModel
|
|
Stage string `gorm:"size:50;not null"`
|
|
Notes string `gorm:"type:text"`
|
|
Language string `gorm:"size:50;not null"`
|
|
WorkID *uuid.UUID
|
|
TranslationID *uuid.UUID
|
|
Translation *Translation `gorm:"foreignKey:TranslationID"`
|
|
UserID uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
AssignedToID *uuid.UUID
|
|
AssignedTo *User `gorm:"foreignKey:AssignedToID"`
|
|
DueDate *time.Time
|
|
CompletedAt *time.Time
|
|
}
|
|
type Admin struct {
|
|
BaseModel
|
|
UserID uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
Role string `gorm:"size:50;not null"`
|
|
Permissions JSONB `gorm:"type:jsonb;default:'{}'"`
|
|
}
|
|
type Vote struct {
|
|
BaseModel
|
|
Value int `gorm:"default:0"`
|
|
UserID uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
WorkID *uuid.UUID
|
|
TranslationID *uuid.UUID
|
|
Translation *Translation `gorm:"foreignKey:TranslationID"`
|
|
CommentID *uuid.UUID
|
|
Comment *Comment `gorm:"foreignKey:CommentID"`
|
|
}
|
|
type Contributor struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Role string `gorm:"size:50"`
|
|
UserID *uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
WorkID *uuid.UUID
|
|
TranslationID *uuid.UUID
|
|
Translation *Translation `gorm:"foreignKey:TranslationID"`
|
|
}
|
|
type InteractionEvent struct {
|
|
BaseModel
|
|
UserID *uuid.UUID
|
|
User *User `gorm:"foreignKey:UserID"`
|
|
TargetType string `gorm:"size:50;not null"`
|
|
TargetID uuid.UUID `gorm:"not null"`
|
|
Kind string `gorm:"size:30;not null"`
|
|
OccurredAt time.Time `gorm:"index"`
|
|
}
|
|
type HybridEntityWork struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null"`
|
|
Type string `gorm:"size:50"`
|
|
WorkID *uuid.UUID
|
|
TranslationID *uuid.UUID
|
|
Translation *Translation `gorm:"foreignKey:TranslationID"`
|
|
}
|