2022-08-24 05:55:19 +00:00
|
|
|
package models
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Forum table.
|
|
|
|
type Forum struct {
|
|
|
|
ID uint64 `gorm:"primaryKey"`
|
|
|
|
OwnerID uint64 `gorm:"index"`
|
|
|
|
Owner User `gorm:"foreignKey:owner_id"`
|
|
|
|
Category string `gorm:"index"`
|
|
|
|
Fragment string `gorm:"uniqueIndex"`
|
|
|
|
Title string
|
|
|
|
Description string
|
|
|
|
Explicit bool `gorm:"index"`
|
|
|
|
Privileged bool
|
|
|
|
PermitPhotos bool
|
2024-05-11 19:23:06 +00:00
|
|
|
Private bool `gorm:"index"`
|
2022-08-24 05:55:19 +00:00
|
|
|
CreatedAt time.Time
|
|
|
|
UpdatedAt time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
// Preload related tables for the forum (classmethod).
|
|
|
|
func (f *Forum) Preload() *gorm.DB {
|
|
|
|
return DB.Preload("Owner")
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetForum by ID.
|
|
|
|
func GetForum(id uint64) (*Forum, error) {
|
|
|
|
forum := &Forum{}
|
|
|
|
result := forum.Preload().First(&forum, id)
|
|
|
|
return forum, result.Error
|
|
|
|
}
|
|
|
|
|
2022-08-31 05:13:57 +00:00
|
|
|
// GetForums queries a set of thread IDs and returns them mapped.
|
|
|
|
func GetForums(IDs []uint64) (map[uint64]*Forum, error) {
|
|
|
|
var (
|
|
|
|
mt = map[uint64]*Forum{}
|
|
|
|
fs = []*Forum{}
|
|
|
|
)
|
|
|
|
|
|
|
|
result := (&Forum{}).Preload().Where("id IN ?", IDs).Find(&fs)
|
|
|
|
for _, row := range fs {
|
|
|
|
mt[row.ID] = row
|
|
|
|
}
|
|
|
|
|
|
|
|
return mt, result.Error
|
|
|
|
}
|
|
|
|
|
2022-08-24 05:55:19 +00:00
|
|
|
// ForumByFragment looks up a forum by its URL fragment.
|
|
|
|
func ForumByFragment(fragment string) (*Forum, error) {
|
|
|
|
if fragment == "" {
|
|
|
|
return nil, errors.New("the URL fragment is required")
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
f = &Forum{}
|
|
|
|
result = f.Preload().Where(
|
|
|
|
"fragment = ?",
|
|
|
|
fragment,
|
|
|
|
).First(&f)
|
|
|
|
)
|
|
|
|
|
|
|
|
return f, result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
PaginateForums scans over the available forums for a user.
|
|
|
|
|
|
|
|
Parameters:
|
|
|
|
|
|
|
|
- userID: of who is looking
|
|
|
|
- categories: optional, filter within categories
|
|
|
|
- pager
|
|
|
|
*/
|
2022-08-25 04:17:34 +00:00
|
|
|
func PaginateForums(user *User, categories []string, pager *Pagination) ([]*Forum, error) {
|
2022-08-24 05:55:19 +00:00
|
|
|
var (
|
|
|
|
fs = []*Forum{}
|
|
|
|
query = (&Forum{}).Preload()
|
|
|
|
wheres = []string{}
|
|
|
|
placeholders = []interface{}{}
|
|
|
|
)
|
|
|
|
|
2023-05-25 01:40:27 +00:00
|
|
|
if len(categories) > 0 {
|
2022-08-24 05:55:19 +00:00
|
|
|
wheres = append(wheres, "category IN ?")
|
|
|
|
placeholders = append(placeholders, categories)
|
|
|
|
}
|
|
|
|
|
2022-08-25 04:17:34 +00:00
|
|
|
// Hide explicit forum if user hasn't opted into it.
|
|
|
|
if !user.Explicit && !user.IsAdmin {
|
|
|
|
wheres = append(wheres, "explicit = false")
|
|
|
|
}
|
|
|
|
|
2024-05-11 19:23:06 +00:00
|
|
|
// Hide private forums except for admins.
|
|
|
|
if !user.IsAdmin {
|
|
|
|
wheres = append(wheres, "private is not true")
|
|
|
|
}
|
|
|
|
|
2022-08-24 05:55:19 +00:00
|
|
|
// Filters?
|
|
|
|
if len(wheres) > 0 {
|
|
|
|
query = query.Where(
|
|
|
|
strings.Join(wheres, " AND "),
|
|
|
|
placeholders...,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
query = query.Order(pager.Sort)
|
|
|
|
query.Model(&Forum{}).Count(&pager.Total)
|
|
|
|
result := query.Offset(pager.GetOffset()).Limit(pager.PerPage).Find(&fs)
|
|
|
|
return fs, result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
// PaginateOwnedForums returns forums the user owns (or all forums to admins).
|
2024-08-21 02:31:56 +00:00
|
|
|
func PaginateOwnedForums(userID uint64, isAdmin bool, search *Search, pager *Pagination) ([]*Forum, error) {
|
2022-08-24 05:55:19 +00:00
|
|
|
var (
|
2024-08-21 02:31:56 +00:00
|
|
|
fs = []*Forum{}
|
|
|
|
query = (&Forum{}).Preload()
|
|
|
|
wheres = []string{}
|
|
|
|
placeholders = []interface{}{}
|
2022-08-24 05:55:19 +00:00
|
|
|
)
|
|
|
|
|
2024-08-21 02:31:56 +00:00
|
|
|
// Users see only their owned forums.
|
2022-08-24 05:55:19 +00:00
|
|
|
if !isAdmin {
|
2024-08-21 02:31:56 +00:00
|
|
|
wheres = append(wheres, "owner_id = ?")
|
|
|
|
placeholders = append(placeholders, userID)
|
2022-08-24 05:55:19 +00:00
|
|
|
}
|
|
|
|
|
2024-08-21 02:31:56 +00:00
|
|
|
// Apply their search terms.
|
|
|
|
if search != nil {
|
|
|
|
for _, term := range search.Includes {
|
|
|
|
var ilike = "%" + strings.ToLower(term) + "%"
|
|
|
|
wheres = append(wheres, "(fragment ILIKE ? OR title ILIKE ? OR description ILIKE ?)")
|
|
|
|
placeholders = append(placeholders, ilike, ilike, ilike)
|
|
|
|
}
|
|
|
|
for _, term := range search.Excludes {
|
|
|
|
var ilike = "%" + strings.ToLower(term) + "%"
|
|
|
|
wheres = append(wheres, "(fragment NOT ILIKE ? AND title NOT ILIKE ? AND description NOT ILIKE ?)")
|
|
|
|
placeholders = append(placeholders, ilike, ilike, ilike)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
query = query.Where(
|
|
|
|
strings.Join(wheres, " AND "),
|
|
|
|
placeholders...,
|
|
|
|
).Order(pager.Sort)
|
|
|
|
|
2022-08-24 05:55:19 +00:00
|
|
|
query.Model(&Forum{}).Count(&pager.Total)
|
|
|
|
result := query.Offset(pager.GetOffset()).Limit(pager.PerPage).Find(&fs)
|
|
|
|
return fs, result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateForum.
|
|
|
|
func CreateForum(f *Forum) error {
|
|
|
|
result := DB.Create(f)
|
|
|
|
return result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save a forum.
|
|
|
|
func (f *Forum) Save() error {
|
|
|
|
return DB.Save(f).Error
|
|
|
|
}
|
|
|
|
|
|
|
|
// CategorizedForum supports the main index page with custom categories.
|
|
|
|
type CategorizedForum struct {
|
|
|
|
Category string
|
|
|
|
Forums []*Forum
|
|
|
|
}
|
|
|
|
|
|
|
|
// CategorizeForums buckets forums into categories for front-end.
|
|
|
|
func CategorizeForums(fs []*Forum, categories []string) []*CategorizedForum {
|
|
|
|
var (
|
|
|
|
result = []*CategorizedForum{}
|
|
|
|
idxMap = map[string]int{}
|
|
|
|
)
|
|
|
|
|
|
|
|
// Initialize the result set.
|
|
|
|
for i, category := range categories {
|
|
|
|
result = append(result, &CategorizedForum{
|
|
|
|
Category: category,
|
|
|
|
Forums: []*Forum{},
|
|
|
|
})
|
|
|
|
idxMap[category] = i
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bucket the forums into their categories.
|
|
|
|
for _, forum := range fs {
|
|
|
|
category := forum.Category
|
|
|
|
if category == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
idx := idxMap[category]
|
|
|
|
result[idx].Forums = append(result[idx].Forums, forum)
|
|
|
|
}
|
|
|
|
|
2023-05-24 03:04:17 +00:00
|
|
|
// Remove any blank categories with no boards.
|
|
|
|
var filtered = []*CategorizedForum{}
|
|
|
|
for _, forum := range result {
|
|
|
|
if len(forum.Forums) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
filtered = append(filtered, forum)
|
|
|
|
}
|
|
|
|
|
|
|
|
return filtered
|
2022-08-24 05:55:19 +00:00
|
|
|
}
|