This repository has been archived on 2022-08-26. You can view files and clone it, but cannot push or open issues or pull requests.
gosocial/pkg/models/forum.go
Noah Petherbridge bb08ec56ce Finish Forums + Likes & Notifications
Finish implementing the basic forum features:
* Pinned threads (admin or board owner only)
* Edit Thread settings when you edit the top-most comment.
* NoReply threads remove all the reply buttons.
* Explicit forums and threads are filtered out unless opted-in (admins
  always see them).
* Count the unique members who participated in each forum.
* Get the most recently updated thread to show on forum list page.
* Contact/Report page: handle receiving a comment ID to report on.

Implement Likes & Notifications
* Like buttons added to Photos and Profile Pages. Implemented via simple
  vanilla JS (likes.js) to make ajax requests to back-end to like/unlike.
* Notifications: for your photo or profile being liked. If you unlike,
  the existing notifications about the like are revoked.
* The notifications appear as an alert number in the nav bar and are read
  on the User Dashboard. Click to mark a notification as "read" or click
  the "mark all as read" button.

Update DeleteUser to scrub likes, notifications, threads, and comments.
2022-08-24 21:17:34 -07:00

162 lines
3.4 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(user *User, 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)
}
// Hide explicit forum if user hasn't opted into it.
if !user.Explicit && !user.IsAdmin {
wheres = append(wheres, "explicit = false")
}
// 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
}