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),
|
||
|
})
|
||
|
})
|
||
|
}
|