website/pkg/models/comment.go

151 lines
3.6 KiB
Go
Raw Normal View History

package models
import (
"time"
"code.nonshy.com/nonshy/website/pkg/log"
"gorm.io/gorm"
)
// Comment table - in forum threads, on profiles or photos, etc.
type Comment struct {
ID uint64 `gorm:"primaryKey"`
TableName string `gorm:"index"`
TableID uint64 `gorm:"index"`
UserID uint64 `gorm:"index"`
User User
Message string
CreatedAt time.Time
UpdatedAt time.Time
}
// CommentableTables are the set of table names that allow comments (via the
// generic "/comments" URI which accepts a table_name param)
var CommentableTables = map[string]interface{}{
"photos": nil,
"threads": nil,
}
// Preload related tables for the forum (classmethod).
func (c *Comment) Preload() *gorm.DB {
return DB.Preload("User.ProfilePhoto")
}
// GetComment by ID.
func GetComment(id uint64) (*Comment, error) {
c := &Comment{}
result := c.Preload().First(&c, id)
return c, result.Error
}
// GetComments queries a set of comment IDs and returns them mapped.
func GetComments(IDs []uint64) (map[uint64]*Comment, error) {
var (
mt = map[uint64]*Comment{}
ts = []*Comment{}
)
result := (&Comment{}).Preload().Where("id IN ?", IDs).Find(&ts)
for _, row := range ts {
mt[row.ID] = row
}
return mt, result.Error
}
// AddComment about anything.
func AddComment(user *User, tableName string, tableID uint64, message string) (*Comment, error) {
c := &Comment{
TableName: tableName,
TableID: tableID,
User: *user,
Message: message,
}
result := DB.Create(c)
return c, result.Error
}
// PaginateComments provides a page of comments on something.
func PaginateComments(user *User, tableName string, tableID uint64, pager *Pagination) ([]*Comment, error) {
var (
cs = []*Comment{}
query = (&Comment{}).Preload()
)
query = query.Where(
"table_name = ? AND table_id = ?",
tableName, tableID,
).Order(pager.Sort)
query.Model(&Comment{}).Count(&pager.Total)
result := query.Offset(pager.GetOffset()).Limit(pager.PerPage).Find(&cs)
return cs, result.Error
}
// ListComments returns a complete set of comments without paging.
func ListComments(tableName string, tableID uint64) ([]*Comment, error) {
var cs []*Comment
result := (&Comment{}).Preload().Where(
"table_name = ? AND table_id = ?",
tableName, tableID,
).Order("created_at asc").Find(&cs)
return cs, result.Error
}
// Save a comment.
func (c *Comment) Save() error {
return DB.Save(c).Error
}
// Delete a comment.
func (c *Comment) Delete() error {
return DB.Delete(c).Error
}
type CommentCountMap map[uint64]int64
// MapCommentCounts collects total numbers of comments over a set of table IDs. Returns a
// map of table ID (uint64) to comment counts for each (int64).
func MapCommentCounts(tableName string, tableIDs []uint64) CommentCountMap {
var result = CommentCountMap{}
// Initialize the result set.
for _, id := range tableIDs {
result[id] = 0
}
// Hold the result of the grouped count query.
type group struct {
ID uint64
Comments int64
}
var groups = []group{}
// Map the counts of comments to each of these IDs.
if res := DB.Table(
"comments",
).Select(
"table_id AS id, count(id) AS comments",
).Where(
"table_name = ? AND table_id IN ?",
tableName, tableIDs,
).Group("table_id").Scan(&groups); res.Error != nil {
log.Error("MapCommentCounts: count query: %s", res.Error)
}
// Map the counts back in.
for _, row := range groups {
result[row.ID] = row.Comments
}
return result
}
// Get a comment count for the given table ID from the map.
func (cc CommentCountMap) Get(id uint64) int64 {
if value, ok := cc[id]; ok {
return value
}
return 0
}