Noah Petherbridge
a663462e27
Adds initial code for basically functional forums: * Forums landing page shows hard-coded list of Categories along with any forums in the DB that use those categories. * Admin: Create, Edit forums and view forums you own or have admin rights to modify. * Landing page forums list shows the title/description and dynamic count of number of Topics and total number of Posts in each forum. TODO: distinct count of Users who posted in each forum. * Board Index page shows list of Threads (posts) with a Replies count and Views count on each thread. * Thread view is basically an array of Comments. Users can post, edit and delete (their own) comments. Deleting the first comment removes the entire Thread - the thread points to a first Comment to provide its body. * Reply and Quote-Reply options working.
157 lines
3.3 KiB
Go
157 lines
3.3 KiB
Go
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
|
|
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
|
|
}
|
|
|
|
// 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
|
|
*/
|
|
func PaginateForums(userID uint64, categories []string, pager *Pagination) ([]*Forum, error) {
|
|
var (
|
|
fs = []*Forum{}
|
|
query = (&Forum{}).Preload()
|
|
wheres = []string{}
|
|
placeholders = []interface{}{}
|
|
)
|
|
|
|
if categories != nil && len(categories) > 0 {
|
|
wheres = append(wheres, "category IN ?")
|
|
placeholders = append(placeholders, categories)
|
|
}
|
|
|
|
// 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).
|
|
func PaginateOwnedForums(userID uint64, isAdmin bool, pager *Pagination) ([]*Forum, error) {
|
|
var (
|
|
fs = []*Forum{}
|
|
query = (&Forum{}).Preload()
|
|
)
|
|
|
|
if !isAdmin {
|
|
query = query.Where(
|
|
"owner_id = ?",
|
|
userID,
|
|
)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
return result
|
|
}
|