146 lines
3.2 KiB
Go
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
|
|
}
|