Noah Petherbridge
96e5b1abfa
Implement block lists. They work like friend lists but are unidirectional, but take effect in both directions (blocker and blockee can not see one another on the site -- except admin users can always see all users). * Profile page says 404 * User gallery says 404 * User search page filters out blocked users * Compose endpoint blocks sending messages to blocked users (except admin) * Site Gallery filters photos by blocked (and uncertified) users * Inbox page hides chat list for blocked users (can still read the chat history if you have a link to the old thread)
173 lines
4.1 KiB
Go
173 lines
4.1 KiB
Go
package models
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"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
|
|
)
|
|
|
|
var PhotoVisibilityAll = []PhotoVisibility{
|
|
PhotoPublic,
|
|
PhotoFriends,
|
|
PhotoPrivate,
|
|
}
|
|
|
|
// 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,
|
|
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
|
|
}
|
|
|
|
/*
|
|
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
|
|
}
|
|
|
|
// 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(userID uint64, adminView bool, explicitOK bool, pager *Pagination) ([]*Photo, error) {
|
|
var (
|
|
p = []*Photo{}
|
|
query *gorm.DB
|
|
blocklist = BlockedUserIDs(userID)
|
|
wheres = []string{}
|
|
placeholders = []interface{}{}
|
|
)
|
|
|
|
// Universal filters: public + gallery photos only.
|
|
wheres = append(wheres, "visibility = ?", "gallery = ?")
|
|
placeholders = append(placeholders, PhotoPublic, 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.
|
|
if !explicitOK {
|
|
wheres = append(wheres, "explicit = ?")
|
|
placeholders = append(placeholders, false)
|
|
}
|
|
|
|
// Only certified user photos.
|
|
wheres = append(wheres,
|
|
"EXISTS (SELECT 1 FROM users WHERE id = photos.user_id AND certified = true)",
|
|
)
|
|
|
|
// Admin view: get ALL PHOTOS on the site, period.
|
|
if adminView {
|
|
query = DB
|
|
} 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
|
|
}
|