Files
Tomas Dvorak d27cf14110 first test
2026-02-08 14:14:55 +01:00

247 lines
9.2 KiB
Go

package models
import (
"regexp"
"strings"
"time"
"gorm.io/gorm"
)
// WikiPage represents a page in the knowledge base/wiki
type WikiPage struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
UserID uint `json:"user_id" gorm:"not null;index"`
User User `json:"user,omitempty" gorm:"foreignKey:UserID"`
// Basic page information
Title string `json:"title" gorm:"not null"`
Slug string `json:"slug" gorm:"not null;uniqueIndex"`
Content string `json:"content" gorm:"type:text"`
Summary string `json:"summary" gorm:"type:text"`
Status string `json:"status" gorm:"default:draft"` // draft, published, archived
// Organization
CategoryID *uint `json:"category_id,omitempty"`
Category *Category `json:"category,omitempty" gorm:"foreignKey:CategoryID"`
ParentID *uint `json:"parent_id,omitempty"`
Parent *WikiPage `json:"parent,omitempty" gorm:"foreignKey:ParentID"`
Children []WikiPage `json:"children,omitempty" gorm:"foreignKey:ParentID"`
// Metadata
Tags []Tag `json:"tags,omitempty" gorm:"many2many:wiki_page_tags;"`
Keywords []string `json:"keywords" gorm:"serializer:json"`
ReadingTime int `json:"reading_time"` // estimated minutes
WordCount int `json:"word_count"`
ViewCount int `json:"view_count" gorm:"default:0"`
LastViewedAt *time.Time `json:"last_viewed_at,omitempty"`
IsPublic bool `json:"is_public" gorm:"default:false"`
IsTemplate bool `json:"is_template" gorm:"default:false"`
TemplateID *uint `json:"template_id,omitempty"`
Template *WikiPage `json:"template,omitempty" gorm:"foreignKey:TemplateID"`
// Collaboration
IsCollaborative bool `json:"is_collaborative" gorm:"default:false"`
Collaborators []User `json:"collaborators,omitempty" gorm:"many2many:wiki_collaborators;"`
LastEditedBy *uint `json:"last_edited_by,omitempty"`
LastEditedUser *User `json:"last_edited_user,omitempty" gorm:"foreignKey:LastEditedBy"`
EditCount int `json:"edit_count" gorm:"default:0"`
// Relationships
Versions []WikiVersion `json:"versions,omitempty" gorm:"foreignKey:WikiPageID"`
Backlinks []WikiBacklink `json:"backlinks,omitempty" gorm:"foreignKey:TargetPageID"`
Attachments []WikiAttachment `json:"attachments,omitempty" gorm:"foreignKey:WikiPageID"`
Bookmarks []Bookmark `json:"bookmarks,omitempty" gorm:"foreignKey:WikiPageID"`
Notes []Note `json:"notes,omitempty" gorm:"foreignKey:WikiPageID"`
}
// Category represents a category for organizing wiki pages
type Category struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
UserID uint `json:"user_id" gorm:"not null;index"`
User User `json:"user,omitempty" gorm:"foreignKey:UserID"`
Name string `json:"name" gorm:"not null"`
Slug string `json:"slug" gorm:"not null;uniqueIndex"`
Description string `json:"description"`
Color string `json:"color" gorm:"default:#6366f1"`
Icon string `json:"icon"`
ParentID *uint `json:"parent_id,omitempty"`
Parent *Category `json:"parent,omitempty" gorm:"foreignKey:ParentID"`
Children []Category `json:"children,omitempty" gorm:"foreignKey:ParentID"`
IsPublic bool `json:"is_public" gorm:"default:false"`
SortOrder int `json:"sort_order" gorm:"default:0"`
// Relationships
Pages []WikiPage `json:"pages,omitempty" gorm:"foreignKey:CategoryID"`
}
// WikiVersion represents a version history of a wiki page
type WikiVersion struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
WikiPageID uint `json:"wiki_page_id" gorm:"not null;index"`
WikiPage WikiPage `json:"wiki_page,omitempty" gorm:"foreignKey:WikiPageID"`
VersionNumber int `json:"version_number" gorm:"not null"`
Title string `json:"title" gorm:"not null"`
Content string `json:"content" gorm:"type:text"`
Summary string `json:"summary" gorm:"type:text"`
ChangeLog string `json:"change_log" gorm:"type:text"`
// Author information
AuthorID uint `json:"author_id" gorm:"not null"`
Author User `json:"author,omitempty" gorm:"foreignKey:AuthorID"`
// Version metadata
WordCount int `json:"word_count"`
CharactersAdded int `json:"characters_added"`
CharactersRemoved int `json:"characters_removed"`
IsMinorChange bool `json:"is_minor_change" gorm:"default:false"`
}
// WikiBacklink represents a link between wiki pages
type WikiBacklink struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
SourcePageID uint `json:"source_page_id" gorm:"not null;index"`
SourcePage WikiPage `json:"source_page,omitempty" gorm:"foreignKey:SourcePageID"`
TargetPageID uint `json:"target_page_id" gorm:"not null;index"`
TargetPage WikiPage `json:"target_page,omitempty" gorm:"foreignKey:TargetPageID"`
LinkText string `json:"link_text"`
Context string `json:"context" gorm:"type:text"` // Surrounding text where the link appears
}
// WikiAttachment represents files attached to wiki pages
type WikiAttachment struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
WikiPageID uint `json:"wiki_page_id" gorm:"not null;index"`
WikiPage WikiPage `json:"wiki_page,omitempty" gorm:"foreignKey:WikiPageID"`
FileName string `json:"file_name" gorm:"not null"`
OriginalName string `json:"original_name" gorm:"not null"`
FilePath string `json:"file_path" gorm:"not null"`
FileSize int64 `json:"file_size"`
MimeType string `json:"mime_type"`
Width int `json:"width"` // For images
Height int `json:"height"` // For images
Thumbnail string `json:"thumbnail"`
Description string `json:"description"`
IsPublic bool `json:"is_public" gorm:"default:false"`
}
// Template represents reusable page templates
type Template struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
UserID uint `json:"user_id" gorm:"not null;index"`
User User `json:"user,omitempty" gorm:"foreignKey:UserID"`
Name string `json:"name" gorm:"not null"`
Slug string `json:"slug" gorm:"not null;uniqueIndex"`
Description string `json:"description"`
Content string `json:"content" gorm:"type:text"`
Category string `json:"category"` // meeting, project, documentation, etc.
IsPublic bool `json:"is_public" gorm:"default:false"`
UsageCount int `json:"usage_count" gorm:"default:0"`
// Template variables
Variables []TemplateVariable `json:"variables,omitempty" gorm:"foreignKey:TemplateID"`
}
// TemplateVariable represents variables in templates
type TemplateVariable struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
TemplateID uint `json:"template_id" gorm:"not null;index"`
Template Template `json:"template,omitempty" gorm:"foreignKey:TemplateID"`
Name string `json:"name" gorm:"not null"`
Type string `json:"type" gorm:"not null"` // text, number, date, select
DefaultValue string `json:"default_value"`
Required bool `json:"required" gorm:"default:false"`
Description string `json:"description"`
Options string `json:"options" gorm:"serializer:json"` // For select type
}
// BeforeCreate hooks
func (w *WikiPage) BeforeCreate(tx *gorm.DB) error {
if w.Status == "" {
w.Status = "draft"
}
if w.Slug == "" && w.Title != "" {
w.Slug = generateSlug(w.Title)
}
return nil
}
func (c *Category) BeforeCreate(tx *gorm.DB) error {
if c.Slug == "" && c.Name != "" {
c.Slug = generateSlug(c.Name)
}
return nil
}
func (t *Template) BeforeCreate(tx *gorm.DB) error {
if t.Slug == "" && t.Name != "" {
t.Slug = generateSlug(t.Name)
}
return nil
}
// BeforeUpdate hooks
func (w *WikiPage) BeforeUpdate(tx *gorm.DB) error {
if w.Title != "" {
w.Slug = generateSlug(w.Title)
}
if w.Content != "" {
w.WordCount = len(strings.Fields(w.Content))
w.ReadingTime = estimateReadingTime(w.WordCount)
}
return nil
}
// Helper functions
func generateSlug(title string) string {
// Simple slug generation - in production, you'd want more sophisticated handling
slug := strings.ToLower(title)
slug = strings.ReplaceAll(slug, " ", "-")
slug = regexp.MustCompile(`[^a-z0-9-]`).ReplaceAllString(slug, "")
slug = regexp.MustCompile(`-+`).ReplaceAllString(slug, "-")
slug = strings.Trim(slug, "-")
return slug
}
func estimateReadingTime(wordCount int) int {
readingSpeed := 225 // words per minute
readingTime := wordCount / readingSpeed
if readingTime < 1 {
readingTime = 1
}
return readingTime
}