website/pkg/models/like.go
2022-08-25 21:21:46 -07:00

146 lines
3.2 KiB
Go

package models
import (
"time"
"code.nonshy.com/nonshy/website/pkg/log"
)
// Like table.
type Like struct {
ID uint64 `gorm:"primaryKey"`
UserID uint64 `gorm:"index"` // who it belongs to
TableName string
TableID uint64
CreatedAt time.Time
UpdatedAt time.Time
}
// LikeableTables are the set of table names that allow likes (used by the JSON API).
var LikeableTables = map[string]interface{}{
"photos": nil,
"users": nil,
}
// AddLike to something.
func AddLike(user *User, tableName string, tableID uint64) error {
// Already has a like?
var like = &Like{}
exist := DB.Model(like).Where(
"user_id = ? AND table_name = ? AND table_id = ?",
user.ID, tableName, tableID,
).First(&like)
if exist.Error == nil {
return nil
}
// Create it.
like = &Like{
UserID: user.ID,
TableName: tableName,
TableID: tableID,
}
return DB.Create(like).Error
}
// Unlike something.
func Unlike(user *User, tableName string, tableID uint64) error {
result := DB.Where(
"user_id = ? AND table_name = ? AND table_id = ?",
user.ID, tableName, tableID,
).Delete(&Like{})
return result.Error
}
// CountLikes on something.
func CountLikes(tableName string, tableID uint64) int64 {
var count int64
DB.Model(&Like{}).Where(
"table_name = ? AND table_id = ?",
tableName, tableID,
).Count(&count)
return count
}
// LikedIDs filters a set of table IDs to ones the user likes.
func LikedIDs(user *User, tableName string, tableIDs []uint64) ([]uint64, error) {
var result = []uint64{}
if r := DB.Table(
"likes",
).Select(
"table_id",
).Where(
"user_id = ? AND table_name = ? AND table_id IN ?",
user.ID, tableName, tableIDs,
).Scan(&result); r.Error != nil {
return result, r.Error
}
return result, nil
}
// LikeMap maps table IDs to Likes metadata.
type LikeMap map[uint64]*LikeStats
// Get like stats from the map.
func (lm LikeMap) Get(id uint64) *LikeStats {
if stats, ok := lm[id]; ok {
return stats
}
return &LikeStats{}
}
// LikeStats holds mapped statistics about liked objects.
type LikeStats struct {
Count int64 // how many total
UserLikes bool // current user likes it
}
// MapLikes over a set of table IDs.
func MapLikes(user *User, tableName string, tableIDs []uint64) LikeMap {
var result = LikeMap{}
// Initialize the result set.
for _, id := range tableIDs {
result[id] = &LikeStats{}
}
// Hold the result of the grouped count query.
type group struct {
ID uint64
Likes int64
}
var groups = []group{}
// Map the counts of likes to each of these IDs.
if res := DB.Table(
"likes",
).Select(
"table_id AS id, count(id) AS likes",
).Where(
"table_name = ? AND table_id IN ?",
tableName, tableIDs,
).Group("table_id").Scan(&groups); res.Error != nil {
log.Error("MapLikes: count query: %s", res.Error)
}
// Map the counts back in.
for _, row := range groups {
if stats, ok := result[row.ID]; ok {
stats.Count = row.Likes
}
}
// Does the CURRENT USER like any of these IDs?
if likedIDs, err := LikedIDs(user, tableName, tableIDs); err == nil {
log.Error("USER LIKES IDS: %+v", likedIDs)
for _, id := range likedIDs {
if stats, ok := result[id]; ok {
stats.UserLikes = true
}
}
}
return result
}