Noah Petherbridge
bb08ec56ce
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.
175 lines
4.9 KiB
Go
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
|
|
}
|
|
})
|
|
}
|