Ability to delete DMs and minor spit & polish
This commit is contained in:
parent
96a90c059e
commit
72a7f57f03
|
@ -18,7 +18,7 @@ var (
|
|||
PageSizeSiteGallery = 16
|
||||
PageSizeUserGallery = 16
|
||||
PageSizeInboxList = 20 // sidebar list
|
||||
PageSizeInboxThread = 20 // conversation view
|
||||
PageSizeInboxThread = 10 // conversation view
|
||||
PageSizeForums = 100 // TODO: for main category index view
|
||||
PageSizeThreadList = 20 // 20 threads per board, 20 posts per thread
|
||||
PageSizeForumAdmin = 20
|
||||
|
|
84
pkg/controller/inbox/delete.go
Normal file
84
pkg/controller/inbox/delete.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
package inbox
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"code.nonshy.com/nonshy/website/pkg/models"
|
||||
"code.nonshy.com/nonshy/website/pkg/session"
|
||||
"code.nonshy.com/nonshy/website/pkg/templates"
|
||||
)
|
||||
|
||||
// Delete a new chat coming from a user's profile page.
|
||||
func Delete() http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
session.FlashError(w, r, "Invalid method.")
|
||||
templates.Redirect(w, "/")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse parameters.
|
||||
var (
|
||||
id uint64
|
||||
idStr = r.FormValue("id")
|
||||
deleteAll = r.FormValue("intent") == "delete-thread"
|
||||
next = r.FormValue("next")
|
||||
)
|
||||
|
||||
if value, err := strconv.Atoi(idStr); err == nil {
|
||||
id = uint64(value)
|
||||
} else {
|
||||
session.FlashError(w, r, "Request error.")
|
||||
templates.Redirect(w, "/")
|
||||
return
|
||||
}
|
||||
|
||||
// The redirect URL must be local.
|
||||
if len(next) == 0 || next[0] != '/' {
|
||||
next = "/"
|
||||
}
|
||||
|
||||
// Get the current user.
|
||||
currentUser, err := session.CurrentUser(r)
|
||||
if err != nil {
|
||||
session.FlashError(w, r, "Error getting the current user: %s", err)
|
||||
templates.Redirect(w, next)
|
||||
return
|
||||
}
|
||||
|
||||
// Lookup the message.
|
||||
message, err := models.GetMessage(id)
|
||||
if err != nil {
|
||||
session.FlashError(w, r, err.Error())
|
||||
templates.Redirect(w, next)
|
||||
}
|
||||
|
||||
// Delete whole thread?
|
||||
if deleteAll {
|
||||
if err := models.DeleteMessageThread(message); err != nil {
|
||||
session.FlashError(w, r, "Error removing thread: %s", err)
|
||||
} else {
|
||||
session.Flash(w, r, "Message thread has been removed.")
|
||||
}
|
||||
templates.Redirect(w, next)
|
||||
return
|
||||
}
|
||||
|
||||
// We should be a party on this message.
|
||||
if message.SourceUserID != currentUser.ID {
|
||||
session.FlashError(w, r, "You did not create that message so you can't delete it.")
|
||||
templates.Redirect(w, next)
|
||||
return
|
||||
}
|
||||
|
||||
// Do the needful.
|
||||
if err := message.Delete(); err != nil {
|
||||
session.FlashError(w, r, "Error deleting the message: %s", err)
|
||||
} else {
|
||||
session.Flash(w, r, "Message deleted!")
|
||||
}
|
||||
|
||||
templates.Redirect(w, next)
|
||||
})
|
||||
}
|
|
@ -75,6 +75,15 @@ func GetMessageThread(sourceUserID, targetUserID uint64, pager *Pagination) ([]*
|
|||
return m, result.Error
|
||||
}
|
||||
|
||||
// DeleteMessageThread removes all message history between two people.
|
||||
func DeleteMessageThread(message *Message) error {
|
||||
return DB.Where(
|
||||
"(source_user_id = ? AND target_user_id = ?) OR (source_user_id = ? AND target_user_id = ?)",
|
||||
message.SourceUserID, message.TargetUserID,
|
||||
message.TargetUserID, message.SourceUserID,
|
||||
).Delete(&Message{}).Error
|
||||
}
|
||||
|
||||
// CountUnreadMessages gets the count of unread messages for a user.
|
||||
func CountUnreadMessages(userID uint64) (int64, error) {
|
||||
query := DB.Where(
|
||||
|
@ -106,3 +115,8 @@ func (m *Message) Save() error {
|
|||
result := DB.Save(m)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
// Delete a message.
|
||||
func (m *Message) Delete() error {
|
||||
return DB.Delete(m).Error
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ func New() http.Handler {
|
|||
mux.Handle("/messages", middleware.LoginRequired(inbox.Inbox()))
|
||||
mux.Handle("/messages/read/", middleware.LoginRequired(inbox.Inbox()))
|
||||
mux.Handle("/messages/compose", middleware.LoginRequired(inbox.Compose()))
|
||||
mux.Handle("/messages/delete", middleware.LoginRequired(inbox.Delete()))
|
||||
mux.Handle("/friends", middleware.LoginRequired(friend.Friends()))
|
||||
mux.Handle("/friends/add", middleware.LoginRequired(friend.AddFriend()))
|
||||
mux.Handle("/users/block", middleware.LoginRequired(block.BlockUser()))
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
/* Custom CSS styles */
|
||||
|
||||
abbr {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* Container for large profile pic on user pages */
|
||||
.profile-photo {
|
||||
width: 150px;
|
||||
|
@ -10,10 +14,12 @@
|
|||
padding: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.profile-photo img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.profile-photo .corner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -36,14 +42,17 @@
|
|||
.has-text-private {
|
||||
color: #CC00CC;
|
||||
}
|
||||
|
||||
.has-text-private-light {
|
||||
color: #FF99FF;
|
||||
}
|
||||
|
||||
.hero.is-private {
|
||||
background-color: #b748c7;
|
||||
}
|
||||
|
||||
.hero.is-private.is-bold {
|
||||
background-image: linear-gradient(141deg,#b329b1 0,#9948c7 71%,#7156d2 100%);
|
||||
background-image: linear-gradient(141deg, #b329b1 0, #9948c7 71%, #7156d2 100%);
|
||||
}
|
||||
|
||||
/* Mobile: notification badge near the hamburger menu */
|
||||
|
@ -53,6 +62,7 @@
|
|||
right: 50px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
.nonshy-mobile-notification {
|
||||
display: none;
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
<section class="hero is-link is-bold">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title">People</h1>
|
||||
<h2 class="subtitle">Explore</h2>
|
||||
<h1 class="title">
|
||||
<i class="fa fa-people-group mr-2"></i>
|
||||
People
|
||||
</h1>
|
||||
<h2 class="subtitle">Member Directory</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -20,11 +20,19 @@
|
|||
<ul>
|
||||
<li><a href="#certification">What does <strong>certification</strong> mean, and what is a <strong>"verification selfie"</strong>?</a></li>
|
||||
<li><a href="#need-certification">Do I <strong>need</strong> to send a "verification selfie"?</a></li>
|
||||
<li><a href="#why-certify">Why the hard requirement to certify?</a> <strong class="tag is-success is-light">NEW Sept. 9 2022</strong></li>
|
||||
<li><a href="#cannot-certify">Are there <strong>alternative options</strong> to becoming Certified?</a> <strong><span class="tag is-success is-light">NEW Sept. 8 2022</span></strong></li>
|
||||
<li><a href="#private-avatar">Can my <strong>Profile Picture be kept private?</strong></a> <strong><span class="tag is-success is-light">NEW Sept. 8 2022</span></strong></li>
|
||||
<li><a href="#why-certify">Why the hard requirement to certify?</a></li>
|
||||
<li><a href="#cannot-certify">Are there <strong>alternative options</strong> to becoming Certified?</a></li>
|
||||
|
||||
<li><a href="#uncertified">What can non-certified members do?</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#privacy-faqs">Privacy FAQs</a>
|
||||
<ul>
|
||||
<li><a href="#private-avatar">Can my <strong>Profile Picture be kept private?</strong></a></li>
|
||||
<li><a href="#profile-visibility">What are the <strong>visibility options</strong> for my profile page?</a></li>
|
||||
<li><a href="#delete-messages">How do I delete direct messages (DMs)?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
|
@ -91,7 +99,7 @@
|
|||
<h3 id="why-certify">Why the hard requirement to certify?</h3>
|
||||
|
||||
<p>
|
||||
<strong class="tag is-success is-light">NEW Sept. 9 2022</strong>
|
||||
|
||||
I didn't set out to build "just another social network" that allows for random, faceless, anonymous
|
||||
people to sign up - you can do that literally anywhere else. This website was designed
|
||||
<em>specifically</em> to get ahead of what happened with Tumblr, Pornhub and other sites
|
||||
|
@ -155,7 +163,6 @@
|
|||
<h3 id="cannot-certify">Are there alternative options to becoming Certified?</h3>
|
||||
|
||||
<p>
|
||||
<strong><span class="tag is-success is-light">NEW Sept. 8 2022</span></strong>
|
||||
I understand that some nudists need to exercise a degree of discretion and will
|
||||
not want to take a face pic with {{PrettyTitle}}'s name and upload that <em>anywhere at all</em> onto the Internet. For
|
||||
example if you are a teacher or work in law enforcement or the clergy and you need to keep
|
||||
|
@ -180,10 +187,31 @@
|
|||
picture can be marked private or "friends only" if you like; see below.
|
||||
</p>
|
||||
|
||||
<h3 id="uncertified">What can non-certified members do?</h3>
|
||||
|
||||
<p>
|
||||
Before you have an approved certification photo, you can mainly only access and edit your
|
||||
own profile page, and upload a few pictures while you await approval. Your pictures won't
|
||||
be shown to members on the Site Gallery until you're certified, and most of the website's
|
||||
features (namely, the Forums, Site Gallery and Member Search Directory) are gated behind
|
||||
certification.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Certified members may, at their own discretion, be able to find your profile page by
|
||||
browsing the Member Directory. They may send you a friend request or reach out to you.
|
||||
Or, if you happen to know a member's profile URL on this site, you (the non-certified
|
||||
member) can view their profile page and photo gallery (depending on their privacy
|
||||
settings), send them a friend request or direct message. But basically, it will be
|
||||
difficult to discover users to interact with until after you are certified - and
|
||||
this is intentional to help guard against spam bots and creepy people.
|
||||
</p>
|
||||
|
||||
<h2 id="privacy-faqs">Privacy FAQs</h2>
|
||||
|
||||
<h3 id="private-avatar">Can my Profile Picture be kept private?</h3>
|
||||
|
||||
<p>
|
||||
<strong><span class="tag is-success is-light">NEW Sept. 8 2022</span></strong>
|
||||
You <em>may</em> set your Profile Picture to be "Friends only" or "Private" visibility
|
||||
if you wish to be more discreet about your face pictures.
|
||||
</p>
|
||||
|
@ -207,26 +235,6 @@
|
|||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="uncertified">What can non-certified members do?</h3>
|
||||
|
||||
<p>
|
||||
Before you have an approved certification photo, you can mainly only access and edit your
|
||||
own profile page, and upload a few pictures while you await approval. Your pictures won't
|
||||
be shown to members on the Site Gallery until you're certified, and most of the website's
|
||||
features (namely, the Forums, Site Gallery and Member Search Directory) are gated behind
|
||||
certification.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Certified members may, at their own discretion, be able to find your profile page by
|
||||
browsing the Member Directory. They may send you a friend request or reach out to you.
|
||||
Or, if you happen to know a member's profile URL on this site, you (the non-certified
|
||||
member) can view their profile page and photo gallery (depending on their privacy
|
||||
settings), send them a friend request or direct message. But basically, it will be
|
||||
difficult to discover users to interact with until after you are certified - and
|
||||
this is intentional to help guard against spam bots and creepy people.
|
||||
</p>
|
||||
|
||||
<h3 id="profile-visibility">What are the visibility options for my profile page?</h3>
|
||||
|
||||
<p>
|
||||
|
@ -258,6 +266,26 @@
|
|||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="delete-messages">How do I delete direct messages (DMs)?</h3>
|
||||
|
||||
<p>
|
||||
You have two options for deleting your private one-on-one chat messages.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can delete <strong>your own</strong> messages by clicking on the "Delete"
|
||||
button that appears below them. This deletes your message from <em>both</em> of
|
||||
your threads, and (if unread), will not notify them that they had an unread
|
||||
message.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can delete <strong>the whole thread</strong> by using the "Delete whole thread"
|
||||
button at the bottom of the conversation. This will remove <em>both</em> of your
|
||||
chat history with one another and make it like you never exchanged a DM before
|
||||
at all.
|
||||
</p>
|
||||
|
||||
<h1 id="photo-faqs">Photo FAQs</h1>
|
||||
|
||||
<h3 id="nudes-required">Do I have to post my nudes here?</h3>
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
<section class="hero is-link is-bold">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title">Friends</h1>
|
||||
<h1 class="title">
|
||||
<i class="fa fa-user-group mr-2"></i>
|
||||
Friends
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -4,12 +4,16 @@
|
|||
<section class="hero is-info is-bold">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title">Messages</h1>
|
||||
<h1 class="title">
|
||||
<i class="fa fa-envelope mr-2"></i>
|
||||
Messages
|
||||
</h1>
|
||||
<h2 class="subtitle">{{if .IsSentBox}}Sent{{else}}Inbox{{end}}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{$Root := .}}
|
||||
{{$UserMap := .UserMap}}
|
||||
{{$Request := .Request}}
|
||||
|
||||
|
@ -58,7 +62,16 @@
|
|||
{{template "avatar-64x64" $SourceUser}}
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<p class="title is-4">{{$SourceUser.NameOrUsername}}</p>
|
||||
<p class="title is-4">
|
||||
{{$SourceUser.NameOrUsername}}
|
||||
|
||||
{{if $SourceUser.IsAdmin}}
|
||||
<span class="tag is-danger is-light ml-2 p-1" style="font-size: x-small">
|
||||
<i class="fa fa-gavel mr-1"></i>
|
||||
Admin
|
||||
</span>
|
||||
{{end}}
|
||||
</p>
|
||||
<p class="subtitle is-6">
|
||||
<span class="icon"><i class="fa fa-user"></i></span>
|
||||
<a href="/u/{{$SourceUser.Username}}">{{$SourceUser.Username}}</a>
|
||||
|
@ -68,13 +81,6 @@
|
|||
<span>Not Certified!</span>
|
||||
</span>
|
||||
{{end}}
|
||||
|
||||
{{if $SourceUser.IsAdmin}}
|
||||
<span class="has-text-danger">
|
||||
<span class="icon"><i class="fa fa-gavel"></i></span>
|
||||
<span>Admin</span>
|
||||
</span>
|
||||
{{end}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -83,8 +89,23 @@
|
|||
{{ToMarkdown .Message}}
|
||||
</div>
|
||||
<div class="block">
|
||||
<em>Sent on {{.CreatedAt.Format "2006-01-02 15:04:05"}}</em>
|
||||
<em>Sent <abbr title="{{.CreatedAt.Format "2006-01-02 15:04:05"}}">
|
||||
{{SincePrettyCoarse .CreatedAt}} ago
|
||||
</em>
|
||||
{{if not .Read}}<span class="tag is-success ml-2">UNREAD</span>{{end}}
|
||||
|
||||
<!-- Our message? We can delete it. -->
|
||||
{{if eq $Root.CurrentUser.ID $SourceUser.ID}}
|
||||
<form action="/messages/delete" method="POST" class="is-inline" onsubmit="return confirm('Delete this message?')">
|
||||
{{InputCSRF}}
|
||||
<input type="hidden" name="id" value="{{.ID}}">
|
||||
<input type="hidden" name="next" value="{{$Root.Request.URL.Path}}">
|
||||
<button class="button has-text-danger is-outline is-small p-1 ml-4">
|
||||
<i class="fa fa-trash mr-2"></i>
|
||||
Delete
|
||||
</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<hr class="block">
|
||||
|
@ -98,6 +119,20 @@
|
|||
Found <strong>{{.ThreadPager.Total}}</strong> message{{Pluralize64 .ThreadPager.Total}} in this thread
|
||||
(page {{.ThreadPager.Page}} of {{.ThreadPager.Pages}}).
|
||||
</div>
|
||||
|
||||
<!-- "Delete ALL" Form -->
|
||||
<form action="/messages/delete" method="POST"
|
||||
class="is-inline"
|
||||
onsubmit="return confirm('Are you sure you want to delete this whole entire thread for both of you? It will be like you two had never chatted before at all.')">
|
||||
{{InputCSRF}}
|
||||
<input type="hidden" name="intent" value="delete-thread">
|
||||
<input type="hidden" name="id" value="{{$Root.MessageID}}">
|
||||
<input type="hidden" name="next" value="/messages">
|
||||
<button class="button has-text-danger is-outline is-small p-1 ml-4">
|
||||
<i class="fa fa-trash mr-2"></i>
|
||||
Delete whole thread
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
{{if .ThreadPager.HasPrevious}}
|
||||
|
@ -128,7 +163,7 @@
|
|||
</header>
|
||||
|
||||
<div class="card-content">
|
||||
<div class="tabs is-toggle">
|
||||
<div class="tabs is-toggle is-fullwidth">
|
||||
<ul>
|
||||
<li{{if not .IsSentBox}} class="is-active"{{end}}>
|
||||
<a href="/messages">Inbox</a>
|
||||
|
|
|
@ -97,29 +97,26 @@
|
|||
<div class="container">
|
||||
<section class="hero is-info is-bold">
|
||||
<div class="hero-body">
|
||||
{{if .IsSiteGallery}}
|
||||
<h1 class="title">
|
||||
{{template "title" .}}
|
||||
</h1>
|
||||
{{else}}
|
||||
<div class="container">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<h1 class="title">
|
||||
{{template "title" .}}
|
||||
<span class="icon mr-4"><i class="fa fa-image"></i></span>
|
||||
<span>{{template "title" .}}</span>
|
||||
</h1>
|
||||
</div>
|
||||
{{if .IsOwnPhotos}}
|
||||
{{if or .IsOwnPhotos .IsSiteGallery}}
|
||||
<div class="level-right">
|
||||
<div>
|
||||
<a href="/photo/upload" class="button">
|
||||
<span class="icon"><i class="fa fa-upload"></i></span>
|
||||
<span>Upload Photos</span>
|
||||
<span>Upload Photo</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user