8e4bb85934
The photo upload limit for user profiles is raised from 24 to 100. The bug about Filesize not saving to the database for Photos and CommentPhotos (storing zeroes in the DB) has been fixed. Run the `nonshy backfill filesizes` to populate your existing database.
263 lines
6.6 KiB
Go
263 lines
6.6 KiB
Go
package models
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.nonshy.com/nonshy/website/pkg/log"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// Photo table.
|
|
type Photo struct {
|
|
ID uint64 `gorm:"primaryKey"`
|
|
UserID uint64 `gorm:"index"`
|
|
Filename string
|
|
CroppedFilename string // if cropped, e.g. for profile photo
|
|
Filesize int64
|
|
Caption string
|
|
Flagged bool // photo has been reported by the community
|
|
Visibility PhotoVisibility
|
|
Gallery bool // photo appears in the public gallery (if public)
|
|
Explicit bool // is an explicit photo
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
// PhotoVisibility settings.
|
|
type PhotoVisibility string
|
|
|
|
const (
|
|
PhotoPublic PhotoVisibility = "public" // on profile page and/or public gallery
|
|
PhotoFriends = "friends" // only friends can see it
|
|
PhotoPrivate = "private" // private
|
|
)
|
|
|
|
// PhotoVisibility preset settings.
|
|
var (
|
|
PhotoVisibilityAll = []PhotoVisibility{
|
|
PhotoPublic,
|
|
PhotoFriends,
|
|
PhotoPrivate,
|
|
}
|
|
|
|
// Site Gallery visibility for when your friends show up in the gallery.
|
|
// Or: "Friends + Gallery" photos can appear to your friends in the Site Gallery.
|
|
PhotoVisibilityFriends = []string{
|
|
string(PhotoPublic),
|
|
string(PhotoFriends),
|
|
}
|
|
)
|
|
|
|
// CreatePhoto with most of the settings you want (not ID or timestamps) in the database.
|
|
func CreatePhoto(tmpl Photo) (*Photo, error) {
|
|
if tmpl.UserID == 0 {
|
|
return nil, errors.New("UserID required")
|
|
}
|
|
|
|
p := &Photo{
|
|
UserID: tmpl.UserID,
|
|
Filename: tmpl.Filename,
|
|
CroppedFilename: tmpl.CroppedFilename,
|
|
Filesize: tmpl.Filesize,
|
|
Caption: tmpl.Caption,
|
|
Visibility: tmpl.Visibility,
|
|
Gallery: tmpl.Gallery,
|
|
Explicit: tmpl.Explicit,
|
|
}
|
|
|
|
result := DB.Create(p)
|
|
return p, result.Error
|
|
}
|
|
|
|
// GetPhoto by ID.
|
|
func GetPhoto(id uint64) (*Photo, error) {
|
|
p := &Photo{}
|
|
result := DB.First(&p, id)
|
|
return p, result.Error
|
|
}
|
|
|
|
// GetPhotos by an array of IDs, mapped to their IDs.
|
|
func GetPhotos(IDs []uint64) (map[uint64]*Photo, error) {
|
|
var (
|
|
mp = map[uint64]*Photo{}
|
|
ps = []*Photo{}
|
|
)
|
|
|
|
result := DB.Model(&Photo{}).Where("id IN ?", IDs).Find(&ps)
|
|
for _, row := range ps {
|
|
mp[row.ID] = row
|
|
}
|
|
|
|
return mp, result.Error
|
|
}
|
|
|
|
/*
|
|
PaginateUserPhotos gets a page of photos belonging to a user ID.
|
|
*/
|
|
func PaginateUserPhotos(userID uint64, visibility []PhotoVisibility, explicitOK bool, pager *Pagination) ([]*Photo, error) {
|
|
var p = []*Photo{}
|
|
|
|
var explicit = []bool{false}
|
|
if explicitOK {
|
|
explicit = []bool{true, false}
|
|
}
|
|
|
|
query := DB.Where(
|
|
"user_id = ? AND visibility IN ? AND explicit IN ?",
|
|
userID,
|
|
visibility,
|
|
explicit,
|
|
).Order(
|
|
pager.Sort,
|
|
)
|
|
|
|
// Get the total count.
|
|
query.Model(&Photo{}).Count(&pager.Total)
|
|
|
|
result := query.Offset(
|
|
pager.GetOffset(),
|
|
).Limit(pager.PerPage).Find(&p)
|
|
|
|
return p, result.Error
|
|
}
|
|
|
|
// CountPhotos returns the total number of photos on a user's account.
|
|
func CountPhotos(userID uint64) int64 {
|
|
var count int64
|
|
result := DB.Where(
|
|
"user_id = ?",
|
|
userID,
|
|
).Model(&Photo{}).Count(&count)
|
|
if result.Error != nil {
|
|
log.Error("CountPhotos(%d): %s", userID, result.Error)
|
|
}
|
|
return count
|
|
}
|
|
|
|
// CountExplicitPhotos returns the number of explicit photos a user has (so non-explicit viewers can see some do exist)
|
|
func CountExplicitPhotos(userID uint64, visibility []PhotoVisibility) (int64, error) {
|
|
query := DB.Where(
|
|
"user_id = ? AND visibility IN ? AND explicit = ?",
|
|
userID,
|
|
visibility,
|
|
true,
|
|
)
|
|
|
|
var count int64
|
|
result := query.Model(&Photo{}).Count(&count)
|
|
return count, result.Error
|
|
}
|
|
|
|
/*
|
|
PaginateGalleryPhotos gets a page of all public user photos for the site gallery.
|
|
|
|
Admin view returns ALL photos regardless of Gallery status.
|
|
*/
|
|
func PaginateGalleryPhotos(user *User, filterExplicit, filterVisibility string, adminView bool, pager *Pagination) ([]*Photo, error) {
|
|
var (
|
|
p = []*Photo{}
|
|
query *gorm.DB
|
|
|
|
// Get the user ID and their preferences.
|
|
userID = user.ID
|
|
explicitOK = user.Explicit // User opted-in for explicit content
|
|
|
|
blocklist = BlockedUserIDs(userID)
|
|
friendIDs = FriendIDs(userID)
|
|
privateUserIDs = PrivateGrantedUserIDs(userID)
|
|
wheres = []string{}
|
|
placeholders = []interface{}{}
|
|
)
|
|
|
|
// Admins see everything on the site (only an admin user can get an admin view).
|
|
adminView = user.IsAdmin && adminView
|
|
|
|
// Include ourself in our friend IDs.
|
|
friendIDs = append(friendIDs, userID)
|
|
|
|
// You can see friends' Friend photos but only public for non-friends.
|
|
wheres = append(wheres,
|
|
"((user_id IN ? AND visibility IN ?) OR "+
|
|
"(user_id IN ? AND visibility IN ?) OR "+
|
|
"(user_id NOT IN ? AND visibility = ?))",
|
|
)
|
|
placeholders = append(placeholders,
|
|
friendIDs, PhotoVisibilityFriends,
|
|
privateUserIDs, PhotoVisibilityAll,
|
|
friendIDs, PhotoPublic,
|
|
)
|
|
|
|
// Gallery photos only.
|
|
wheres = append(wheres, "gallery = ?")
|
|
placeholders = append(placeholders, true)
|
|
|
|
// Filter blocked users.
|
|
if len(blocklist) > 0 {
|
|
wheres = append(wheres, "user_id NOT IN ?")
|
|
placeholders = append(placeholders, blocklist)
|
|
}
|
|
|
|
// Non-explicit pics unless the user opted in. Allow explicit filter setting to override.
|
|
if filterExplicit != "" {
|
|
wheres = append(wheres, "explicit = ?")
|
|
placeholders = append(placeholders, filterExplicit == "true")
|
|
} else if !explicitOK {
|
|
wheres = append(wheres, "explicit = ?")
|
|
placeholders = append(placeholders, false)
|
|
}
|
|
|
|
// Is the user furthermore clamping the visibility filter?
|
|
if filterVisibility != "" {
|
|
wheres = append(wheres, "visibility = ?")
|
|
placeholders = append(placeholders, filterVisibility)
|
|
}
|
|
|
|
// Only certified user photos.
|
|
wheres = append(wheres,
|
|
"EXISTS (SELECT 1 FROM users WHERE id = photos.user_id AND certified = true)",
|
|
)
|
|
|
|
// Exclude private users' photos.
|
|
wheres = append(wheres,
|
|
"NOT EXISTS (SELECT 1 FROM users WHERE id = photos.user_id AND visibility = 'private')",
|
|
)
|
|
|
|
// Admin view: get ALL PHOTOS on the site, period.
|
|
if adminView {
|
|
query = DB
|
|
|
|
// Admin may filter too.
|
|
if filterVisibility != "" {
|
|
query = query.Where("visibility = ?", filterVisibility)
|
|
}
|
|
if filterExplicit != "" {
|
|
query = query.Where("explicit = ?", filterExplicit == "true")
|
|
}
|
|
} else {
|
|
query = DB.Where(
|
|
strings.Join(wheres, " AND "),
|
|
placeholders...,
|
|
)
|
|
}
|
|
|
|
query = query.Order(pager.Sort)
|
|
|
|
query.Model(&Photo{}).Count(&pager.Total)
|
|
result := query.Offset(pager.GetOffset()).Limit(pager.PerPage).Find(&p)
|
|
return p, result.Error
|
|
}
|
|
|
|
// Save photo.
|
|
func (p *Photo) Save() error {
|
|
result := DB.Save(p)
|
|
return result.Error
|
|
}
|
|
|
|
// Delete photo.
|
|
func (p *Photo) Delete() error {
|
|
result := DB.Delete(p)
|
|
return result.Error
|
|
}
|