This repository has been archived on 2022-08-26. You can view files and clone it, but cannot push or open issues or pull requests.
gosocial/pkg/controller/index/contact.go
Noah Petherbridge bb08ec56ce Finish Forums + Likes & Notifications
Finish implementing the basic forum features:
* Pinned threads (admin or board owner only)
* Edit Thread settings when you edit the top-most comment.
* NoReply threads remove all the reply buttons.
* Explicit forums and threads are filtered out unless opted-in (admins
  always see them).
* Count the unique members who participated in each forum.
* Get the most recently updated thread to show on forum list page.
* Contact/Report page: handle receiving a comment ID to report on.

Implement Likes & Notifications
* Like buttons added to Photos and Profile Pages. Implemented via simple
  vanilla JS (likes.js) to make ajax requests to back-end to like/unlike.
* Notifications: for your photo or profile being liked. If you unlike,
  the existing notifications about the like are revoked.
* The notifications appear as an alert number in the nav bar and are read
  on the User Dashboard. Click to mark a notification as "read" or click
  the "mark all as read" button.

Update DeleteUser to scrub likes, notifications, threads, and comments.
2022-08-24 21:17:34 -07:00

175 lines
4.9 KiB
Go

package index
import (
"fmt"
"html/template"
"net/http"
"strconv"
"git.kirsle.net/apps/gosocial/pkg/config"
"git.kirsle.net/apps/gosocial/pkg/log"
"git.kirsle.net/apps/gosocial/pkg/mail"
"git.kirsle.net/apps/gosocial/pkg/markdown"
"git.kirsle.net/apps/gosocial/pkg/models"
"git.kirsle.net/apps/gosocial/pkg/session"
"git.kirsle.net/apps/gosocial/pkg/templates"
)
// Contact or report a problem.
func Contact() http.HandlerFunc {
tmpl := templates.Must("contact.html")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Query and form POST parameters.
var (
intent = r.FormValue("intent")
subject = r.FormValue("subject")
title = "Contact Us"
message = r.FormValue("message")
replyTo = r.FormValue("email")
tableID int
tableName string
tableLabel string // front-end user feedback about selected report item
messageRequired = true // unless we have a table ID to work with
success = "Thank you for your feedback! Your message has been delivered to the website administrators."
)
// For report intents: ID of the user, photo, message, etc.
tableID, _ = strconv.Atoi(r.FormValue("id"))
if tableID > 0 {
messageRequired = false
}
// In what context is the ID given?
if subject != "" && tableID > 0 {
switch subject {
case "report.user":
tableName = "users"
if user, err := models.GetUser(uint64(tableID)); err == nil {
tableLabel = fmt.Sprintf(`User account "%s"`, user.Username)
} else {
log.Error("/contact: couldn't produce table label for user %d: %s", tableID, err)
}
case "report.photo":
tableName = "photos"
// Find this photo and the user associated.
if pic, err := models.GetPhoto(uint64(tableID)); err == nil {
if user, err := models.GetUser(pic.UserID); err == nil {
tableLabel = fmt.Sprintf(`A profile photo of user account "%s"`, user.Username)
} else {
log.Error("/contact: couldn't produce table label for user %d: %s", tableID, err)
}
} else {
log.Error("/contact: couldn't produce table label for photo %d: %s", tableID, err)
}
case "report.message":
tableName = "messages"
tableLabel = "Direct Message conversation"
case "report.comment":
tableName = "comments"
// Find this comment.
if comment, err := models.GetComment(uint64(tableID)); err == nil {
tableLabel = fmt.Sprintf(`A comment written by "%s"`, comment.User.Username)
} else {
log.Error("/contact: couldn't produce table label for comment %d: %s", tableID, err)
}
}
}
// On POST: take what we have now and email the admins.
if r.Method == http.MethodPost {
// Look up the current user, in case logged in.
currentUser, err := session.CurrentUser(r)
if err == nil {
replyTo = currentUser.Email
}
// Store feedback in the database.
fb := &models.Feedback{
Intent: intent,
Subject: subject,
Message: message,
TableName: tableName,
TableID: uint64(tableID),
}
if currentUser != nil && currentUser.ID > 0 {
fb.UserID = currentUser.ID
} else if replyTo != "" {
fb.ReplyTo = replyTo
}
if err := models.CreateFeedback(fb); err != nil {
session.FlashError(w, r, "Couldn't save feedback: %s", err)
templates.Redirect(w, r.URL.Path)
return
}
// Email the admins.
if err := mail.Send(mail.Message{
To: config.Current.AdminEmail,
Subject: "User Feedback: " + title,
Template: "email/contact_admin.html",
Data: map[string]interface{}{
"Title": title,
"Intent": intent,
"Subject": subject,
"Message": template.HTML(markdown.Render(message)),
"TableName": tableName,
"TableID": tableID,
"CurrentUser": currentUser,
"ReplyTo": replyTo,
"BaseURL": config.Current.BaseURL,
"AdminURL": config.Current.BaseURL + "/admin/feedback",
},
}); err != nil {
log.Error("/contact page: couldn't send email: %s", err)
}
session.Flash(w, r, success)
templates.Redirect(w, r.URL.Path)
return
}
// Default intent = contact
if intent == "report" {
title = "Report a Problem"
} else {
intent = "contact"
}
// Validate the subject.
if subject != "" {
var found bool
for _, group := range config.ContactUsChoices {
for _, opt := range group.Options {
if opt.Value == subject {
found = true
break
}
}
}
if !found {
subject = ""
}
}
var vars = map[string]interface{}{
"Intent": intent,
"TableID": tableID,
"TableLabel": tableLabel,
"Subject": subject,
"PageTitle": title,
"Subjects": config.ContactUsChoices,
"Message": message,
"MessageRequired": messageRequired,
}
if err := tmpl.Execute(w, r, vars); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})
}