website/pkg/models/comment.go
Noah 6c91c67c97 More Private User Avatars
* Users who set their Profile Picture to "friends only" or "private" can have
  their avatar be private all over the website to users who are not their
  friends or not granted access.
* Users who are not your friends see a yellow placeholder avatar, and users
  not granted access to a private Profile Pic sees a purple avatar.
* Admin users see these same placeholder avatars most places too (on search,
  forums, comments, etc.) if the user did not friend or grant the admin. But
  admins ALWAYS see it on their Profile Page directly, for ability to moderate.
* Fix marking Notifications as read: clicking the link in an unread notification
  now will wait on the ajax request to finish before allowing the redirect.
* Update the FAQ
2022-09-08 21:42:20 -07:00

160 lines
3.8 KiB
Go

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)
// 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(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
}
// 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
}