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.
125 lines
3.2 KiB
Go
125 lines
3.2 KiB
Go
package api
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"git.kirsle.net/apps/gosocial/pkg/log"
|
|
"git.kirsle.net/apps/gosocial/pkg/models"
|
|
"git.kirsle.net/apps/gosocial/pkg/session"
|
|
)
|
|
|
|
// Likes API.
|
|
func Likes() http.HandlerFunc {
|
|
// Request JSON schema.
|
|
type Request struct {
|
|
TableName string `json:"name"`
|
|
TableID uint64 `json:"id"`
|
|
Unlike bool `json:"unlike,omitempty"`
|
|
}
|
|
|
|
// Response JSON schema.
|
|
type Response struct {
|
|
OK bool `json:"OK"`
|
|
Error string `json:"error,omitempty"`
|
|
Likes int64 `json:"likes"`
|
|
}
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
SendJSON(w, http.StatusNotAcceptable, Response{
|
|
Error: "POST method only",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Get the current user.
|
|
currentUser, err := session.CurrentUser(r)
|
|
if err != nil {
|
|
SendJSON(w, http.StatusBadRequest, Response{
|
|
Error: "Couldn't get current user!",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Parse request payload.
|
|
var req Request
|
|
if err := ParseJSON(r, &req); err != nil {
|
|
SendJSON(w, http.StatusBadRequest, Response{
|
|
Error: fmt.Sprintf("Error with request payload: %s", err),
|
|
})
|
|
return
|
|
}
|
|
|
|
// Who do we notify about this like?
|
|
var targetUser *models.User
|
|
switch req.TableName {
|
|
case "photos":
|
|
if photo, err := models.GetPhoto(req.TableID); err == nil {
|
|
if user, err := models.GetUser(photo.UserID); err == nil {
|
|
targetUser = user
|
|
}
|
|
} else {
|
|
log.Error("For like on photos table: didn't find photo %d: %s", req.TableID, err)
|
|
}
|
|
case "users":
|
|
log.Error("subject is users, find %d", req.TableID)
|
|
if user, err := models.GetUser(req.TableID); err == nil {
|
|
targetUser = user
|
|
log.Warn("found user %s", targetUser.Username)
|
|
} else {
|
|
log.Error("For like on users table: didn't find user %d: %s", req.TableID, err)
|
|
}
|
|
}
|
|
|
|
// Is the table likeable?
|
|
if _, ok := models.LikeableTables[req.TableName]; !ok {
|
|
SendJSON(w, http.StatusBadRequest, Response{
|
|
Error: fmt.Sprintf("Can't like table %s: not allowed.", req.TableName),
|
|
})
|
|
return
|
|
}
|
|
|
|
// Put in a like.
|
|
if req.Unlike {
|
|
if err := models.Unlike(currentUser, req.TableName, req.TableID); err != nil {
|
|
SendJSON(w, http.StatusBadRequest, Response{
|
|
Error: fmt.Sprintf("Error unliking: %s", err),
|
|
})
|
|
return
|
|
}
|
|
|
|
// Remove the target's notification about this like.
|
|
models.RemoveNotification(req.TableName, req.TableID)
|
|
} else {
|
|
if err := models.AddLike(currentUser, req.TableName, req.TableID); err != nil {
|
|
SendJSON(w, http.StatusBadRequest, Response{
|
|
Error: fmt.Sprintf("Error liking: %s", err),
|
|
})
|
|
return
|
|
}
|
|
|
|
// Notify the recipient of the like.
|
|
log.Info("Added like on %s:%d, notifying owner %+v", req.TableName, req.TableID, targetUser)
|
|
if targetUser != nil {
|
|
notif := &models.Notification{
|
|
UserID: targetUser.ID,
|
|
User: *currentUser,
|
|
Type: models.NotificationLike,
|
|
TableName: req.TableName,
|
|
TableID: req.TableID,
|
|
}
|
|
if err := models.CreateNotification(notif); err != nil {
|
|
log.Error("Couldn't create Likes notification: %s", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Send success response.
|
|
SendJSON(w, http.StatusOK, Response{
|
|
OK: true,
|
|
Likes: models.CountLikes(req.TableName, req.TableID),
|
|
})
|
|
})
|
|
}
|