- Comment model with nested replies (ParentID), dual authorship (logged-in UserID / anonymous GuestToken cookie), email hash for Gravatar, private flag, and moderation status - CommentConfig singleton (enabled / allow guest / guest-require-approval / use Gravatar) cached like the other platform config - Markdown comments with built-in emoji picker, preview, and markdown help; rendered client-side via marked + DOMPurify, with server-side HTML/dangerous-scheme stripping as a first XSS defense - Private comments visible only to admin and the author; pending comments visible only to admin and the author - Admin moderation list (pending/approved/rejected/all tabs) with approve/reject/delete and a pending-count badge - Comment settings page with the four toggles - One-time session flash notice (auto-dismissed after 4s) so the "comment posted" banner no longer persists across refreshes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
99 lines
3.9 KiB
Go
99 lines
3.9 KiB
Go
package models
|
|
|
|
import (
|
|
"log"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// seedSiteSettings inserts the singleton site_settings row (id=1) if absent.
|
|
// Text fields are left empty so templates fall back to i18n defaults until an
|
|
// admin configures them.
|
|
func seedSiteSettings(db *gorm.DB) {
|
|
var count int64
|
|
db.Model(&SiteSetting{}).Count(&count)
|
|
if count > 0 {
|
|
return
|
|
}
|
|
s := &SiteSetting{ID: 1}
|
|
if err := db.Create(s).Error; err != nil {
|
|
log.Printf("Warning: failed to seed site_settings: %v", err)
|
|
}
|
|
}
|
|
|
|
// seedUploadConfig inserts the singleton upload_configs row (id=1) if absent.
|
|
func seedUploadConfig(db *gorm.DB) {
|
|
var count int64
|
|
db.Model(&UploadConfig{}).Count(&count)
|
|
if count > 0 {
|
|
return
|
|
}
|
|
c := &UploadConfig{
|
|
ID: 1,
|
|
Enabled: true,
|
|
DefaultMaxSize: DefaultUploadMaxSize,
|
|
StorageDir: "attachments",
|
|
}
|
|
if err := db.Create(c).Error; err != nil {
|
|
log.Printf("Warning: failed to seed upload_configs: %v", err)
|
|
}
|
|
}
|
|
|
|
// seedCommentConfig inserts the singleton comment_configs row (id=1) if absent.
|
|
func seedCommentConfig(db *gorm.DB) {
|
|
var count int64
|
|
db.Model(&CommentConfig{}).Count(&count)
|
|
if count > 0 {
|
|
return
|
|
}
|
|
c := &CommentConfig{
|
|
ID: 1,
|
|
Enabled: true,
|
|
AllowGuest: true,
|
|
GuestRequireApproval: false,
|
|
UseGravatar: true,
|
|
}
|
|
if err := db.Create(c).Error; err != nil {
|
|
log.Printf("Warning: failed to seed comment_configs: %v", err)
|
|
}
|
|
}
|
|
|
|
// defaultUploadFileTypes is the set of commonly permitted attachment types
|
|
// seeded on first run.
|
|
var defaultUploadFileTypes = []UploadFileType{
|
|
// Images
|
|
{Extension: ".jpg", MimeType: "image/jpeg", Category: CategoryImage, Enabled: true, Sort: 1},
|
|
{Extension: ".jpeg", MimeType: "image/jpeg", Category: CategoryImage, Enabled: true, Sort: 2},
|
|
{Extension: ".png", MimeType: "image/png", Category: CategoryImage, Enabled: true, Sort: 3},
|
|
{Extension: ".gif", MimeType: "image/gif", Category: CategoryImage, Enabled: true, Sort: 4},
|
|
{Extension: ".webp", MimeType: "image/webp", Category: CategoryImage, Enabled: true, Sort: 5},
|
|
// Documents
|
|
{Extension: ".pdf", MimeType: "application/pdf", Category: CategoryDocument, Enabled: true, Sort: 10},
|
|
{Extension: ".doc", MimeType: "application/msword", Category: CategoryDocument, Enabled: true, Sort: 11},
|
|
{Extension: ".docx", MimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", Category: CategoryDocument, Enabled: true, Sort: 12},
|
|
{Extension: ".xls", MimeType: "application/vnd.ms-excel", Category: CategoryDocument, Enabled: true, Sort: 13},
|
|
{Extension: ".xlsx", MimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", Category: CategoryDocument, Enabled: true, Sort: 14},
|
|
{Extension: ".ppt", MimeType: "application/vnd.ms-powerpoint", Category: CategoryDocument, Enabled: true, Sort: 15},
|
|
{Extension: ".pptx", MimeType: "application/vnd.openxmlformats-officedocument.presentationml.presentation", Category: CategoryDocument, Enabled: true, Sort: 16},
|
|
{Extension: ".txt", MimeType: "text/plain", Category: CategoryDocument, Enabled: true, Sort: 17},
|
|
// Archives
|
|
{Extension: ".zip", MimeType: "application/zip", Category: CategoryArchive, Enabled: true, Sort: 20},
|
|
{Extension: ".rar", MimeType: "application/vnd.rar", Category: CategoryArchive, Enabled: true, Sort: 21},
|
|
{Extension: ".7z", MimeType: "application/x-7z-compressed", Category: CategoryArchive, Enabled: true, Sort: 22},
|
|
// Video
|
|
{Extension: ".mp4", MimeType: "video/mp4", Category: CategoryVideo, Enabled: true, Sort: 30},
|
|
{Extension: ".avi", MimeType: "video/x-msvideo", Category: CategoryVideo, Enabled: true, Sort: 31},
|
|
}
|
|
|
|
// seedUploadFileTypes seeds the permitted file-type rows if the table is empty.
|
|
func seedUploadFileTypes(db *gorm.DB) {
|
|
var count int64
|
|
db.Model(&UploadFileType{}).Count(&count)
|
|
if count > 0 {
|
|
return
|
|
}
|
|
if err := db.Create(&defaultUploadFileTypes).Error; err != nil {
|
|
log.Printf("Warning: failed to seed upload_file_types: %v", err)
|
|
}
|
|
}
|