186 lines
4.6 KiB
Go
186 lines
4.6 KiB
Go
package models
|
|
|
|
import (
|
|
"strings"
|
|
"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()
|
|
blockedUserIDs = BlockedUserIDs(user.ID)
|
|
wheres = []string{}
|
|
placeholders = []interface{}{}
|
|
)
|
|
|
|
wheres = append(wheres, "table_name = ? AND table_id = ?")
|
|
placeholders = append(placeholders, tableName, tableID)
|
|
|
|
if len(blockedUserIDs) > 0 {
|
|
wheres = append(wheres, "user_id NOT IN ?")
|
|
placeholders = append(placeholders, blockedUserIDs)
|
|
}
|
|
|
|
query = query.Where(
|
|
strings.Join(wheres, " AND "),
|
|
placeholders...,
|
|
).Order(pager.Sort)
|
|
|
|
query.Model(&Comment{}).Count(&pager.Total)
|
|
result := query.Offset(pager.GetOffset()).Limit(pager.PerPage).Find(&cs)
|
|
|
|
// Inject user relationships into these comments' authors.
|
|
SetUserRelationshipsInComments(user, cs)
|
|
|
|
return cs, result.Error
|
|
}
|
|
|
|
// ListComments returns a complete set of comments without paging.
|
|
func ListComments(user *User, tableName string, tableID uint64) ([]*Comment, error) {
|
|
var (
|
|
cs []*Comment
|
|
blockedUserIDs = BlockedUserIDs(user.ID)
|
|
wheres = []string{}
|
|
placeholders = []interface{}{}
|
|
)
|
|
|
|
wheres = append(wheres, "table_name = ? AND table_id = ?")
|
|
placeholders = append(placeholders, tableName, tableID)
|
|
|
|
if len(blockedUserIDs) > 0 {
|
|
wheres = append(wheres, "user_id NOT IN ?")
|
|
placeholders = append(placeholders, blockedUserIDs)
|
|
}
|
|
|
|
result := (&Comment{}).Preload().Where(
|
|
strings.Join(wheres, " AND "),
|
|
placeholders...,
|
|
).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
|
|
}
|
|
|
|
// IsEdited returns if a comment was reasonably edited after it was created.
|
|
func (c *Comment) IsEdited() bool {
|
|
return c.UpdatedAt.Sub(c.CreatedAt) > 5*time.Second
|
|
}
|
|
|
|
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
|
|
}
|