Mute Users from the Site Gallery
This commit is contained in:
parent
3416d647fc
commit
9db4dbd1e7
|
@ -12,6 +12,7 @@ var (
|
|||
PageSizeMemberSearch = 60
|
||||
PageSizeFriends = 12
|
||||
PageSizeBlockList = 12
|
||||
PageSizeMuteList = PageSizeBlockList
|
||||
PageSizePrivatePhotoGrantees = 12
|
||||
PageSizeAdminCertification = 20
|
||||
PageSizeAdminFeedback = 20
|
||||
|
|
166
pkg/controller/mutelist/mute.go
Normal file
166
pkg/controller/mutelist/mute.go
Normal file
|
@ -0,0 +1,166 @@
|
|||
package mutelist
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"code.nonshy.com/nonshy/website/pkg/config"
|
||||
"code.nonshy.com/nonshy/website/pkg/models"
|
||||
"code.nonshy.com/nonshy/website/pkg/session"
|
||||
"code.nonshy.com/nonshy/website/pkg/templates"
|
||||
)
|
||||
|
||||
// Muted User list: view the list of muted accounts.
|
||||
func MuteList() http.HandlerFunc {
|
||||
tmpl := templates.Must("account/mute_list.html")
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
currentUser, err := session.CurrentUser(r)
|
||||
if err != nil {
|
||||
session.FlashError(w, r, "Unexpected error: could not get currentUser.")
|
||||
templates.Redirect(w, "/")
|
||||
return
|
||||
}
|
||||
|
||||
// Get our mutelist.
|
||||
pager := &models.Pagination{
|
||||
PerPage: config.PageSizeMuteList,
|
||||
Sort: "updated_at desc",
|
||||
}
|
||||
pager.ParsePage(r)
|
||||
muted, err := models.PaginateMuteList(currentUser, pager)
|
||||
if err != nil {
|
||||
session.FlashError(w, r, "Couldn't paginate mute list: %s", err)
|
||||
templates.Redirect(w, "/")
|
||||
return
|
||||
}
|
||||
|
||||
var vars = map[string]interface{}{
|
||||
"MutedUsers": muted,
|
||||
"Pager": pager,
|
||||
}
|
||||
if err := tmpl.Execute(w, r, vars); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AddUser to manually add someone to your mute list.
|
||||
func AddUser() http.HandlerFunc {
|
||||
tmpl := templates.Must("account/mute_list_add.html")
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Query parameters.
|
||||
var (
|
||||
username = strings.ToLower(r.FormValue("username"))
|
||||
next = r.FormValue("next")
|
||||
context = models.MutedUserContext(r.FormValue("context"))
|
||||
listName = "Site Gallery" // TODO: more as contexts are added
|
||||
)
|
||||
|
||||
// Validate the Next URL.
|
||||
if !strings.HasPrefix(next, "/") {
|
||||
next = "/users/muted"
|
||||
}
|
||||
|
||||
// Validate acceptable contexts.
|
||||
if !models.IsValidMuteUserContext(context) {
|
||||
session.FlashError(w, r, "Unsupported mute context.")
|
||||
templates.Redirect(w, next)
|
||||
return
|
||||
}
|
||||
|
||||
// Get the target user.
|
||||
user, err := models.FindUser(username)
|
||||
if err != nil {
|
||||
session.FlashError(w, r, "User Not Found")
|
||||
templates.Redirect(w, next)
|
||||
return
|
||||
}
|
||||
|
||||
vars := map[string]interface{}{
|
||||
"User": user,
|
||||
"Next": next,
|
||||
"Context": context,
|
||||
"MuteListName": listName,
|
||||
}
|
||||
if err := tmpl.Execute(w, r, vars); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// MuteUser controller: POST endpoint to add a mute.
|
||||
func MuteUser() http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Form fields
|
||||
var (
|
||||
username = strings.ToLower(r.PostFormValue("username"))
|
||||
next = r.PostFormValue("next")
|
||||
context = models.MutedUserContext(r.PostFormValue("context"))
|
||||
listName = "Site Gallery" // TODO: more as contexts are added
|
||||
unmute = r.PostFormValue("unmute") == "true"
|
||||
)
|
||||
|
||||
// Validate the Next URL.
|
||||
if !strings.HasPrefix(next, "/") {
|
||||
next = "/users/muted"
|
||||
}
|
||||
|
||||
// Validate acceptable contexts.
|
||||
if !models.IsValidMuteUserContext(context) {
|
||||
session.FlashError(w, r, "Unsupported mute context.")
|
||||
templates.Redirect(w, "/")
|
||||
return
|
||||
}
|
||||
|
||||
// Get the current user.
|
||||
currentUser, err := session.CurrentUser(r)
|
||||
if err != nil {
|
||||
session.FlashError(w, r, "Couldn't get CurrentUser: %s", err)
|
||||
templates.Redirect(w, "/")
|
||||
return
|
||||
}
|
||||
|
||||
// Get the target user.
|
||||
user, err := models.FindUser(username)
|
||||
if err != nil {
|
||||
session.FlashError(w, r, "User Not Found")
|
||||
templates.Redirect(w, next)
|
||||
return
|
||||
}
|
||||
|
||||
// Unmuting?
|
||||
if unmute {
|
||||
if err := models.RemoveMutedUser(currentUser.ID, user.ID, context); err != nil {
|
||||
session.FlashError(w, r, "Couldn't unmute this user: %s.", err)
|
||||
} else {
|
||||
session.Flash(w, r, "You have removed %s from your %s mute list.", user.Username, listName)
|
||||
|
||||
// Log the change.
|
||||
models.LogDeleted(currentUser, nil, "muted_users", user.ID, "Unmuted user "+user.Username+" from "+listName+".", nil)
|
||||
}
|
||||
templates.Redirect(w, next)
|
||||
return
|
||||
}
|
||||
|
||||
// Can't mute yourself.
|
||||
if currentUser.ID == user.ID {
|
||||
session.FlashError(w, r, "You can't mute yourself!")
|
||||
templates.Redirect(w, next)
|
||||
return
|
||||
}
|
||||
|
||||
// Mute the target user.
|
||||
if err := models.AddMutedUser(currentUser.ID, user.ID, context); err != nil {
|
||||
session.FlashError(w, r, "Couldn't mute this user: %s.", err)
|
||||
} else {
|
||||
session.Flash(w, r, "You have added %s to your %s mute list.", user.Username, listName)
|
||||
|
||||
// Log the change.
|
||||
models.LogCreated(currentUser, "muted_users", user.ID, "Mutes user "+user.Username+" on list "+listName+".")
|
||||
}
|
||||
|
||||
templates.Redirect(w, next)
|
||||
})
|
||||
}
|
|
@ -51,6 +51,7 @@ func DeleteUser(user *models.User) error {
|
|||
{"Messages", DeleteUserMessages},
|
||||
{"Friends", DeleteFriends},
|
||||
{"Blocks", DeleteBlocks},
|
||||
{"MutedUsers", DeleteMutedUsers},
|
||||
{"Feedbacks", DeleteFeedbacks},
|
||||
{"Two Factor", DeleteTwoFactor},
|
||||
{"Profile Fields", DeleteProfile},
|
||||
|
@ -227,6 +228,16 @@ func DeleteBlocks(userID uint64) error {
|
|||
return result.Error
|
||||
}
|
||||
|
||||
// DeleteMutedUsers scrubs data for deleting a user.
|
||||
func DeleteMutedUsers(userID uint64) error {
|
||||
log.Error("DeleteUser: DeleteMutedUsers(%d)", userID)
|
||||
result := models.DB.Where(
|
||||
"source_user_id = ? OR target_user_id = ?",
|
||||
userID, userID,
|
||||
).Delete(&models.MutedUser{})
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// DeleteFeedbacks scrubs data for deleting a user.
|
||||
func DeleteFeedbacks(userID uint64) error {
|
||||
log.Error("DeleteUser: DeleteFeedbacks(%d)", userID)
|
||||
|
|
|
@ -32,6 +32,7 @@ func ExportModels(zw *zip.Writer, user *models.User) error {
|
|||
{"IPAddress", ExportIPAddressTable},
|
||||
{"Like", ExportLikeTable},
|
||||
{"Message", ExportMessageTable},
|
||||
{"MutedUser", ExportMutedUserTable},
|
||||
{"Notification", ExportNotificationTable},
|
||||
{"ProfileField", ExportProfileFieldTable},
|
||||
{"Photo", ExportPhotoTable},
|
||||
|
@ -189,6 +190,21 @@ func ExportBlockTable(zw *zip.Writer, user *models.User) error {
|
|||
return ZipJson(zw, "blocks.json", items)
|
||||
}
|
||||
|
||||
func ExportMutedUserTable(zw *zip.Writer, user *models.User) error {
|
||||
var (
|
||||
items = []*models.MutedUser{}
|
||||
query = models.DB.Model(&models.MutedUser{}).Where(
|
||||
"source_user_id = ?",
|
||||
user.ID,
|
||||
).Find(&items)
|
||||
)
|
||||
if query.Error != nil {
|
||||
return query.Error
|
||||
}
|
||||
|
||||
return ZipJson(zw, "muted_users.json", items)
|
||||
}
|
||||
|
||||
func ExportFeedbackTable(zw *zip.Writer, user *models.User) error {
|
||||
var (
|
||||
items = []*models.Feedback{}
|
||||
|
|
|
@ -24,6 +24,7 @@ func AutoMigrate() {
|
|||
&IPAddress{}, // ✔
|
||||
&Like{}, // ✔
|
||||
&Message{}, // ✔
|
||||
&MutedUser{}, // ✔
|
||||
&Notification{}, // ✔
|
||||
&ProfileField{}, // ✔
|
||||
&Photo{}, // ✔
|
||||
|
|
109
pkg/models/muted_users.go
Normal file
109
pkg/models/muted_users.go
Normal file
|
@ -0,0 +1,109 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// MutedUser table, for users to mute one another's Site Gallery photos and similar.
|
||||
type MutedUser struct {
|
||||
ID uint64 `gorm:"primaryKey"`
|
||||
SourceUserID uint64 `gorm:"uniqueIndex:idx_muted_user"`
|
||||
TargetUserID uint64 `gorm:"uniqueIndex:idx_muted_user"`
|
||||
Context MutedUserContext `gorm:"uniqueIndex:idx_muted_user"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type MutedUserContext string
|
||||
|
||||
// Context options for MutedUser to specify what is being muted.
|
||||
const (
|
||||
MutedUserContextSiteGallery MutedUserContext = "site_gallery" // hide a user's photos from the Site Gallery.
|
||||
)
|
||||
|
||||
// IsValidMuteUserContext validates acceptable options for muting users.
|
||||
func IsValidMuteUserContext(ctx MutedUserContext) bool {
|
||||
return ctx == MutedUserContextSiteGallery
|
||||
}
|
||||
|
||||
// AddMutedUser is sourceUserId adding targetUserId to their mute list under the given context.
|
||||
func AddMutedUser(sourceUserID, targetUserID uint64, ctx MutedUserContext) error {
|
||||
m := &MutedUser{
|
||||
SourceUserID: sourceUserID,
|
||||
TargetUserID: targetUserID,
|
||||
Context: ctx,
|
||||
}
|
||||
|
||||
// Upsert the mute.
|
||||
res := DB.Model(&MutedUser{}).Clauses(
|
||||
clause.OnConflict{
|
||||
Columns: []clause.Column{
|
||||
{Name: "source_user_id"},
|
||||
{Name: "target_user_id"},
|
||||
{Name: "context"},
|
||||
},
|
||||
DoNothing: true,
|
||||
},
|
||||
).Create(m)
|
||||
return res.Error
|
||||
}
|
||||
|
||||
// MutedUserIDs returns all user IDs Muted by the user.
|
||||
func MutedUserIDs(user *User, context MutedUserContext) []uint64 {
|
||||
var (
|
||||
ms = []*MutedUser{}
|
||||
userIDs = []uint64{}
|
||||
)
|
||||
DB.Where("source_user_id = ? AND context = ?", user.ID, context).Find(&ms)
|
||||
for _, row := range ms {
|
||||
userIDs = append(userIDs, row.TargetUserID)
|
||||
}
|
||||
return userIDs
|
||||
}
|
||||
|
||||
// PaginateMuteList views a user's mute lists.
|
||||
func PaginateMuteList(user *User, pager *Pagination) ([]*User, error) {
|
||||
// We paginate over the MutedUser table.
|
||||
var (
|
||||
ms = []*MutedUser{}
|
||||
userIDs = []uint64{}
|
||||
query *gorm.DB
|
||||
)
|
||||
|
||||
query = DB.Where(
|
||||
"source_user_id = ?",
|
||||
user.ID,
|
||||
)
|
||||
|
||||
query = query.Order(pager.Sort)
|
||||
query.Model(&MutedUser{}).Count(&pager.Total)
|
||||
result := query.Offset(pager.GetOffset()).Limit(pager.PerPage).Find(&ms)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
// Now of these friends get their User objects.
|
||||
for _, b := range ms {
|
||||
userIDs = append(userIDs, b.TargetUserID)
|
||||
}
|
||||
|
||||
return GetUsers(user, userIDs)
|
||||
}
|
||||
|
||||
// RemoveMutedUser clears the muted user row.
|
||||
func RemoveMutedUser(sourceUserID, targetUserID uint64, ctx MutedUserContext) error {
|
||||
result := DB.Where(
|
||||
"source_user_id = ? AND target_user_id = ? AND context = ?",
|
||||
sourceUserID, targetUserID, ctx,
|
||||
).Delete(&MutedUser{})
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Save photo.
|
||||
func (m *MutedUser) Save() error {
|
||||
result := DB.Save(m)
|
||||
return result.Error
|
||||
}
|
|
@ -682,6 +682,7 @@ func PaginateGalleryPhotos(user *User, conf Gallery, pager *Pagination) ([]*Phot
|
|||
explicitOK = user.Explicit // User opted-in for explicit content
|
||||
|
||||
blocklist = BlockedUserIDs(user)
|
||||
mutelist = MutedUserIDs(user, MutedUserContextSiteGallery)
|
||||
privateUserIDs = PrivateGrantedUserIDs(userID)
|
||||
privateUserIDsAreFriends = PrivateGrantedUserIDsAreFriends(user)
|
||||
wheres = []string{}
|
||||
|
@ -790,6 +791,12 @@ func PaginateGalleryPhotos(user *User, conf Gallery, pager *Pagination) ([]*Phot
|
|||
placeholders = append(placeholders, blocklist)
|
||||
}
|
||||
|
||||
// Filter Site Gallery muted users.
|
||||
if len(mutelist) > 0 {
|
||||
wheres = append(wheres, "photos.user_id NOT IN ?")
|
||||
placeholders = append(placeholders, mutelist)
|
||||
}
|
||||
|
||||
// Non-explicit pics unless the user opted in. Allow explicit filter setting to override.
|
||||
if filterExplicit != "" {
|
||||
wheres = append(wheres, "photos.explicit = ?")
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"code.nonshy.com/nonshy/website/pkg/controller/htmx"
|
||||
"code.nonshy.com/nonshy/website/pkg/controller/inbox"
|
||||
"code.nonshy.com/nonshy/website/pkg/controller/index"
|
||||
"code.nonshy.com/nonshy/website/pkg/controller/mutelist"
|
||||
"code.nonshy.com/nonshy/website/pkg/controller/photo"
|
||||
"code.nonshy.com/nonshy/website/pkg/controller/poll"
|
||||
"code.nonshy.com/nonshy/website/pkg/middleware"
|
||||
|
@ -78,6 +79,9 @@ func New() http.Handler {
|
|||
mux.Handle("POST /users/block", middleware.LoginRequired(block.BlockUser()))
|
||||
mux.Handle("GET /users/blocked", middleware.LoginRequired(block.Blocked()))
|
||||
mux.Handle("GET /users/blocklist/add", middleware.LoginRequired(block.AddUser()))
|
||||
mux.Handle("GET /users/muted", middleware.LoginRequired(mutelist.MuteList()))
|
||||
mux.Handle("GET /users/mutelist/add", middleware.LoginRequired(mutelist.AddUser()))
|
||||
mux.Handle("POST /users/mutelist/add", middleware.LoginRequired(mutelist.MuteUser()))
|
||||
mux.Handle("/comments", middleware.LoginRequired(comment.PostComment()))
|
||||
mux.Handle("GET /comments/subscription", middleware.LoginRequired(comment.Subscription()))
|
||||
mux.Handle("GET /admin/unimpersonate", middleware.LoginRequired(admin.Unimpersonate()))
|
||||
|
|
|
@ -35,6 +35,7 @@ func TemplateFuncs(r *http.Request) template.FuncMap {
|
|||
"FormatNumberCommas": FormatNumberCommas(),
|
||||
"ComputeAge": utility.Age,
|
||||
"Split": strings.Split,
|
||||
"NewHashMap": NewHashMap,
|
||||
"ToMarkdown": ToMarkdown,
|
||||
"DeMarkify": markdown.DeMarkify,
|
||||
"ToJSON": ToJSON,
|
||||
|
@ -264,6 +265,30 @@ func SubtractInt64(a, b int64) int64 {
|
|||
return a - b
|
||||
}
|
||||
|
||||
// NewHashMap creates a key/value dict on the fly for Go templates.
|
||||
//
|
||||
// Use it like: {{$Vars := NewHashMap "username" .CurrentUser.Username "photoID" .Photo.ID}}
|
||||
//
|
||||
// It is useful for calling Go subtemplates that need custom parameters, e.g. a
|
||||
// mixin from current scope with other variables.
|
||||
func NewHashMap(upsert ...interface{}) map[string]interface{} {
|
||||
// Map the positional arguments into a dictionary.
|
||||
var params = map[string]interface{}{}
|
||||
for i := 0; i < len(upsert); i += 2 {
|
||||
var (
|
||||
key = fmt.Sprintf("%v", upsert[i])
|
||||
value interface{}
|
||||
)
|
||||
if len(upsert) > i {
|
||||
value = upsert[i+1]
|
||||
}
|
||||
|
||||
params[key] = value
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
// UrlEncode escapes a series of values (joined with no delimiter)
|
||||
func UrlEncode(values ...interface{}) string {
|
||||
var result string
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
<section class="hero is-link is-bold">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title">Blocked Users</h1>
|
||||
<h1 class="title">
|
||||
<i class="fa fa-hand mr-2"></i>
|
||||
Blocked Users
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -234,6 +234,12 @@
|
|||
Blocked Users
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/users/muted">
|
||||
<span class="icon"><i class="fa fa-eye-slash"></i></span>
|
||||
Muted Users
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/logout">
|
||||
<span class="icon"><i class="fa fa-arrow-right-from-bracket"></i></span>
|
||||
|
|
74
web/templates/account/mute_list.html
Normal file
74
web/templates/account/mute_list.html
Normal file
|
@ -0,0 +1,74 @@
|
|||
{{define "title"}}Muted Users{{end}}
|
||||
{{define "content"}}
|
||||
<div class="container">
|
||||
{{$Root := .}}
|
||||
<section class="hero is-link is-bold">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title">
|
||||
<i class="fa fa-eye-slash mr-2"></i>
|
||||
Muted Users
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="p-4">
|
||||
|
||||
<div class="block">
|
||||
This page lists members of {{PrettyTitle}} who you have "muted" so that their content
|
||||
will not appear to you in certain areas of the site. Currently, only <strong>Site Gallery</strong>
|
||||
mutes exist: so you can hide somebody's pictures from ever appearing to you on the Site Gallery.
|
||||
In the future, more kinds of mute lists may be available to manage from this page.
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
You have muted {{.Pager.Total}} user{{Pluralize64 .Pager.Total}}
|
||||
(page {{.Pager.Page}} of {{.Pager.Pages}}).
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
{{SimplePager .Pager}}
|
||||
</div>
|
||||
|
||||
<div class="columns is-multiline">
|
||||
|
||||
{{range .MutedUsers}}
|
||||
<div class="column is-half-tablet is-one-third-desktop">
|
||||
|
||||
<form action="/users/mutelist/add" method="POST">
|
||||
{{InputCSRF}}
|
||||
<input type="hidden" name="username" value="{{.Username}}">
|
||||
<input type="hidden" name="context" value="site_gallery">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="media block">
|
||||
<div class="media-left">
|
||||
{{template "avatar-64x64" .}}
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<p class="title is-4">{{.NameOrUsername}}</p>
|
||||
<p class="subtitle is-6">
|
||||
<span class="icon"><i class="fa fa-user"></i></span>
|
||||
<a href="/u/{{.Username}}">{{.Username}}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<button type="submit" name="unmute" value="true" class="card-footer-item button is-danger">
|
||||
<span class="icon"><i class="fa fa-xmark"></i></span>
|
||||
<span>Unmute User</span>
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
{{end}}<!-- range .MutedUsers -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
77
web/templates/account/mute_list_add.html
Normal file
77
web/templates/account/mute_list_add.html
Normal file
|
@ -0,0 +1,77 @@
|
|||
{{define "title"}}Add to {{.MuteListName}} Mute List{{end}}
|
||||
{{define "content"}}
|
||||
<div class="container">
|
||||
<section class="hero is-link is-bold">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title">
|
||||
<i class="fa fa-eye-slash mr-2"></i>
|
||||
Add to {{.MuteListName}} Mute List
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="block p-4">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-half">
|
||||
|
||||
<div class="card" style="width: 100%; max-width: 640px">
|
||||
<header class="card-header has-background-link">
|
||||
<p class="card-header-title has-text-light">
|
||||
<span class="icon mr-2"><i class="fa fa-eye-slash"></i></span>
|
||||
<span>Add to {{.MuteListName}} Mute List</span>
|
||||
</p>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
|
||||
<div class="block">
|
||||
Confirm that you wish to add <strong>{{.User.Username}}</strong>
|
||||
to your <strong>{{.MuteListName}}</strong> mute list by clicking the button below.
|
||||
</div>
|
||||
<div class="media block">
|
||||
<div class="media-left">
|
||||
{{template "avatar-64x64" .User}}
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<p class="title is-4">{{.User.NameOrUsername}}</p>
|
||||
<p class="subtitle is-6">
|
||||
<span class="icon"><i class="fa fa-user"></i></span>
|
||||
<a href="/u/{{.User.Username}}" target="_blank">{{.User.Username}}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form action="/users/mutelist/add" method="POST">
|
||||
{{InputCSRF}}
|
||||
<input type="hidden" name="username" value="{{.User.Username}}">
|
||||
<input type="hidden" name="context" value="{{.Context}}">
|
||||
<input type="hidden" name="next" value="{{.Next}}">
|
||||
|
||||
<!-- Explain what will happen -->
|
||||
{{if eq .Context "site_gallery"}}
|
||||
<div class="block">
|
||||
By continuing, <strong>you will no longer see <a href="/u/{{.User.Username}}">{{.User.Username}}</a>'s photos appear on the site-wide Photo Gallery.</strong>
|
||||
You may still see their photos when looking at their own Photo Gallery directly, from their profile page.
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div class="field has-text-centered">
|
||||
<button type="submit" class="button is-success">
|
||||
Continue
|
||||
</button>
|
||||
<a href="{{.Next}}" class="button">
|
||||
Cancel
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{{end}}
|
|
@ -131,6 +131,15 @@
|
|||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/users/muted">
|
||||
<strong><i class="fa fa-eye-slash mr-1"></i> Muted Users</strong>
|
||||
<p class="help">
|
||||
View and manage your mute lists.
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/notes/me">
|
||||
<strong><i class="fa fa-pen-to-square mr-1"></i> My User Notes</strong>
|
||||
|
|
|
@ -88,6 +88,19 @@
|
|||
</a>
|
||||
{{end}}
|
||||
|
||||
<!-- Reusable "mute site gallery" component -->
|
||||
<!-- Parameter: the photo owner User object -->
|
||||
{{define "mute-site-gallery"}}
|
||||
<div class="columns is-centered is-mobile">
|
||||
<div class="column is-narrow">
|
||||
<a href="/users/mutelist/add?username={{.User.Username}}&context=site_gallery&next={{.Request.URL.String}}" class="has-text-grey is-size-7">
|
||||
<i class="fa fa-eye-slash"></i>
|
||||
Don't show {{.User.Username}}'s photos
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- Main content template -->
|
||||
{{define "content"}}
|
||||
{{if not .IsSiteGallery}}
|
||||
|
@ -615,6 +628,13 @@
|
|||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- Mute this user from Site Gallery -->
|
||||
{{if and $Root.IsSiteGallery (ne $Root.CurrentUser.ID .UserID) ($Root.UserMap.Has .UserID)}}
|
||||
{{$Owner := $Root.UserMap.Get .UserID}}
|
||||
{{$SubVariables := NewHashMap "User" $Owner "Request" $Root.Request}}
|
||||
{{template "mute-site-gallery" $SubVariables}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<footer class="card-footer">
|
||||
|
@ -740,6 +760,13 @@
|
|||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- Mute this user from Site Gallery -->
|
||||
{{if and $Root.IsSiteGallery (ne $Root.CurrentUser.ID .UserID) ($Root.UserMap.Has .UserID)}}
|
||||
{{$Owner := $Root.UserMap.Get .UserID}}
|
||||
{{$SubVariables := NewHashMap "User" $Owner "Request" $Root.Request}}
|
||||
{{template "mute-site-gallery" $SubVariables}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<footer class="card-footer">
|
||||
|
|
Loading…
Reference in New Issue
Block a user