From 72a7f57f03e7a7aedc16352eb5dd796b7116f40e Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Tue, 20 Dec 2022 21:11:43 -0800 Subject: [PATCH] Ability to delete DMs and minor spit & polish --- pkg/config/page_sizes.go | 2 +- pkg/controller/inbox/delete.go | 84 +++++++++++++++++++++++++++++++ pkg/models/message.go | 14 ++++++ pkg/router/router.go | 1 + web/static/css/theme.css | 12 ++++- web/templates/account/search.html | 7 ++- web/templates/faq.html | 80 +++++++++++++++++++---------- web/templates/friend/friends.html | 5 +- web/templates/inbox/inbox.html | 57 +++++++++++++++++---- web/templates/photo/gallery.html | 37 +++++++------- 10 files changed, 237 insertions(+), 62 deletions(-) create mode 100644 pkg/controller/inbox/delete.go diff --git a/pkg/config/page_sizes.go b/pkg/config/page_sizes.go index 236f17f..b1306db 100644 --- a/pkg/config/page_sizes.go +++ b/pkg/config/page_sizes.go @@ -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 diff --git a/pkg/controller/inbox/delete.go b/pkg/controller/inbox/delete.go new file mode 100644 index 0000000..ae2da76 --- /dev/null +++ b/pkg/controller/inbox/delete.go @@ -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) + }) +} diff --git a/pkg/models/message.go b/pkg/models/message.go index 1a6dfee..25e7507 100644 --- a/pkg/models/message.go +++ b/pkg/models/message.go @@ -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 +} diff --git a/pkg/router/router.go b/pkg/router/router.go index 50998e7..a2f9242 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -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())) diff --git a/web/static/css/theme.css b/web/static/css/theme.css index d1f5ca7..b13db08 100644 --- a/web/static/css/theme.css +++ b/web/static/css/theme.css @@ -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; diff --git a/web/templates/account/search.html b/web/templates/account/search.html index 91ce193..17ace16 100644 --- a/web/templates/account/search.html +++ b/web/templates/account/search.html @@ -5,8 +5,11 @@ diff --git a/web/templates/faq.html b/web/templates/faq.html index 0751453..f3bd7e6 100644 --- a/web/templates/faq.html +++ b/web/templates/faq.html @@ -20,11 +20,19 @@ + +
  • + Privacy FAQs +
  • @@ -91,7 +99,7 @@

    Why the hard requirement to certify?

    - NEW Sept. 9 2022 + 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 specifically to get ahead of what happened with Tumblr, Pornhub and other sites @@ -155,7 +163,6 @@

    Are there alternative options to becoming Certified?

    - NEW Sept. 8 2022 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 anywhere at all 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.

    +

    What can non-certified members do?

    + +

    + 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. +

    + +

    + 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. +

    + +

    Privacy FAQs

    +

    Can my Profile Picture be kept private?

    - NEW Sept. 8 2022 You may set your Profile Picture to be "Friends only" or "Private" visibility if you wish to be more discreet about your face pictures.

    @@ -207,26 +235,6 @@
  • -

    What can non-certified members do?

    - -

    - 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. -

    - -

    - 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. -

    -

    What are the visibility options for my profile page?

    @@ -258,6 +266,26 @@ +

    How do I delete direct messages (DMs)?

    + +

    + You have two options for deleting your private one-on-one chat messages. +

    + +

    + You can delete your own messages by clicking on the "Delete" + button that appears below them. This deletes your message from both of + your threads, and (if unread), will not notify them that they had an unread + message. +

    + +

    + You can delete the whole thread by using the "Delete whole thread" + button at the bottom of the conversation. This will remove both of your + chat history with one another and make it like you never exchanged a DM before + at all. +

    +

    Photo FAQs

    Do I have to post my nudes here?

    diff --git a/web/templates/friend/friends.html b/web/templates/friend/friends.html index 5f7c2ac..bf2e36c 100644 --- a/web/templates/friend/friends.html +++ b/web/templates/friend/friends.html @@ -5,7 +5,10 @@ diff --git a/web/templates/inbox/inbox.html b/web/templates/inbox/inbox.html index 25580c4..ca90a1d 100644 --- a/web/templates/inbox/inbox.html +++ b/web/templates/inbox/inbox.html @@ -4,12 +4,16 @@
    -

    Messages

    +

    + + Messages +

    {{if .IsSentBox}}Sent{{else}}Inbox{{end}}

    + {{$Root := .}} {{$UserMap := .UserMap}} {{$Request := .Request}} @@ -58,7 +62,16 @@ {{template "avatar-64x64" $SourceUser}}
    -

    {{$SourceUser.NameOrUsername}}

    +

    + {{$SourceUser.NameOrUsername}} + + {{if $SourceUser.IsAdmin}} + + + Admin + + {{end}} +

    {{$SourceUser.Username}} @@ -68,13 +81,6 @@ Not Certified! {{end}} - - {{if $SourceUser.IsAdmin}} - - - Admin - - {{end}}

    @@ -83,8 +89,23 @@ {{ToMarkdown .Message}}
    - Sent on {{.CreatedAt.Format "2006-01-02 15:04:05"}} + Sent + {{SincePrettyCoarse .CreatedAt}} ago + {{if not .Read}}UNREAD{{end}} + + + {{if eq $Root.CurrentUser.ID $SourceUser.ID}} +
    + {{InputCSRF}} + + + +
    + {{end}}

    @@ -98,6 +119,20 @@ Found {{.ThreadPager.Total}} message{{Pluralize64 .ThreadPager.Total}} in this thread (page {{.ThreadPager.Page}} of {{.ThreadPager.Pages}}). + + +
    + {{InputCSRF}} + + + + +
    {{if .ThreadPager.HasPrevious}} @@ -128,7 +163,7 @@
    -
    +
      Inbox diff --git a/web/templates/photo/gallery.html b/web/templates/photo/gallery.html index dd01333..5519d0d 100644 --- a/web/templates/photo/gallery.html +++ b/web/templates/photo/gallery.html @@ -97,29 +97,26 @@
      - {{if .IsSiteGallery}} -

      - {{template "title" .}} -

      - {{else}} -
      -
      -

      - {{template "title" .}} -

      -
      - {{if .IsOwnPhotos}} -
      -
      - - - Upload Photos - +
      +
      +
      +

      + + {{template "title" .}} +

      + {{if or .IsOwnPhotos .IsSiteGallery}} + + {{end}}
      - {{end}}
      - {{end}}