✨ CRUD of subscriptions
This commit is contained in:
parent
45698db199
commit
c01714b3fc
@ -12,6 +12,7 @@ var AutoMaintainRange = []any{
|
|||||||
&models.Tag{},
|
&models.Tag{},
|
||||||
&models.Post{},
|
&models.Post{},
|
||||||
&models.Reaction{},
|
&models.Reaction{},
|
||||||
|
&models.Subscription{},
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunMigration(source *gorm.DB) error {
|
func RunMigration(source *gorm.DB) error {
|
||||||
|
@ -5,8 +5,9 @@ import "git.solsynth.dev/hydrogen/dealer/pkg/hyper"
|
|||||||
type Account struct {
|
type Account struct {
|
||||||
hyper.BaseUser
|
hyper.BaseUser
|
||||||
|
|
||||||
Posts []Post `json:"posts" gorm:"foreignKey:AuthorID"`
|
Posts []Post `json:"posts" gorm:"foreignKey:AuthorID"`
|
||||||
Reactions []Reaction `json:"reactions"`
|
Reactions []Reaction `json:"reactions"`
|
||||||
|
Subscriptions []Subscription `json:"subscriptions" gorm:"foreginKey:FollowerID"`
|
||||||
|
|
||||||
TotalUpvote int `json:"total_upvote"`
|
TotalUpvote int `json:"total_upvote"`
|
||||||
TotalDownvote int `json:"total_downvote"`
|
TotalDownvote int `json:"total_downvote"`
|
||||||
|
16
pkg/internal/models/subscriptions.go
Normal file
16
pkg/internal/models/subscriptions.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "git.solsynth.dev/hydrogen/dealer/pkg/hyper"
|
||||||
|
|
||||||
|
type Subscription struct {
|
||||||
|
hyper.BaseModel
|
||||||
|
|
||||||
|
FollowerID uint `json:"follower_id"`
|
||||||
|
Follower Account `json:"follower"`
|
||||||
|
AccountID *uint `json:"account_id,omitempty"`
|
||||||
|
Account *Account `json:"account,omitempty"`
|
||||||
|
TagID *uint `json:"tag_id,omitempty"`
|
||||||
|
Tag Tag `json:"tag,omitempty"`
|
||||||
|
CategoryID *uint `json:"category_id,omitempty"`
|
||||||
|
Category Category `json:"category,omitempty"`
|
||||||
|
}
|
@ -45,6 +45,19 @@ func MapAPIs(app *fiber.App, baseURL string) {
|
|||||||
posts.Get("/:postId/replies/featured", listPostFeaturedReply)
|
posts.Get("/:postId/replies/featured", listPostFeaturedReply)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subscriptions := api.Group("/subscriptions").Name("Subscriptions API")
|
||||||
|
{
|
||||||
|
subscriptions.Get("/users/:userId", getSubscriptionOnUser)
|
||||||
|
subscriptions.Get("/tags/:tagId", getSubscriptionOnTag)
|
||||||
|
subscriptions.Get("/categories/:categoryId", getSubscriptionOnCategory)
|
||||||
|
subscriptions.Post("/users/:userId", subscribeToUser)
|
||||||
|
subscriptions.Post("/tags/:tagId", subscribeToTag)
|
||||||
|
subscriptions.Post("/categories/:categoryId", subscribeToCategory)
|
||||||
|
subscriptions.Delete("/users/:userId", unsubscribeFromUser)
|
||||||
|
subscriptions.Delete("/tags/:tagId", unsubscribeFromTag)
|
||||||
|
subscriptions.Delete("/categories/:categoryId", unsubscribeFromCategory)
|
||||||
|
}
|
||||||
|
|
||||||
api.Get("/categories", listCategories)
|
api.Get("/categories", listCategories)
|
||||||
api.Get("/categories/:category", getCategory)
|
api.Get("/categories/:category", getCategory)
|
||||||
api.Post("/categories", newCategory)
|
api.Post("/categories", newCategory)
|
||||||
|
190
pkg/internal/server/api/subscriptions_api.go
Normal file
190
pkg/internal/server/api/subscriptions_api.go
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.solsynth.dev/hydrogen/interactive/pkg/internal/gap"
|
||||||
|
"git.solsynth.dev/hydrogen/interactive/pkg/internal/models"
|
||||||
|
"git.solsynth.dev/hydrogen/interactive/pkg/internal/services"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getSubscriptionOnUser(c *fiber.Ctx) error {
|
||||||
|
if err := gap.H.EnsureAuthenticated(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user := c.Locals("user").(models.Account)
|
||||||
|
|
||||||
|
otherUserId, err := c.ParamsInt("userId", 0)
|
||||||
|
otherUser, err := services.GetAccountWithID(uint(otherUserId))
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("unable to get user: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription, err := services.GetSubscriptionOnUser(user, otherUser)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get subscription: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSubscriptionOnTag(c *fiber.Ctx) error {
|
||||||
|
if err := gap.H.EnsureAuthenticated(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user := c.Locals("user").(models.Account)
|
||||||
|
|
||||||
|
tagId, err := c.ParamsInt("tagId", 0)
|
||||||
|
tag, err := services.GetTagWithID(uint(tagId))
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("unable to get tag: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription, err := services.GetSubscriptionOnTag(user, tag)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get subscription: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSubscriptionOnCategory(c *fiber.Ctx) error {
|
||||||
|
if err := gap.H.EnsureAuthenticated(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user := c.Locals("user").(models.Account)
|
||||||
|
|
||||||
|
categoryId, err := c.ParamsInt("categoryId", 0)
|
||||||
|
category, err := services.GetCategoryWithID(uint(categoryId))
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("unable to get category: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription, err := services.GetSubscriptionOnCategory(user, category)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get subscription: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
func subscribeToUser(c *fiber.Ctx) error {
|
||||||
|
if err := gap.H.EnsureAuthenticated(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user := c.Locals("user").(models.Account)
|
||||||
|
|
||||||
|
otherUserId, err := c.ParamsInt("userId", 0)
|
||||||
|
otherUser, err := services.GetAccountWithID(uint(otherUserId))
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("unable to get user: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription, err := services.SubscribeToUser(user, otherUser)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to subscribe to user: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
func subscribeToTag(c *fiber.Ctx) error {
|
||||||
|
if err := gap.H.EnsureAuthenticated(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user := c.Locals("user").(models.Account)
|
||||||
|
|
||||||
|
tagId, err := c.ParamsInt("tagId", 0)
|
||||||
|
tag, err := services.GetTagWithID(uint(tagId))
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("unable to get tag: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription, err := services.SubscribeToTag(user, tag)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to subscribe to tag: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
func subscribeToCategory(c *fiber.Ctx) error {
|
||||||
|
if err := gap.H.EnsureAuthenticated(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user := c.Locals("user").(models.Account)
|
||||||
|
|
||||||
|
categoryId, err := c.ParamsInt("categoryId", 0)
|
||||||
|
category, err := services.GetCategoryWithID(uint(categoryId))
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("unable to get category: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription, err := services.SubscribeToCategory(user, category)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to subscribe to category: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unsubscribeFromUser(c *fiber.Ctx) error {
|
||||||
|
if err := gap.H.EnsureAuthenticated(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user := c.Locals("user").(models.Account)
|
||||||
|
|
||||||
|
otherUserId, err := c.ParamsInt("userId", 0)
|
||||||
|
otherUser, err := services.GetAccountWithID(uint(otherUserId))
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("unable to get user: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = services.UnsubscribeFromUser(user, otherUser)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to unsubscribe from user: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unsubscribeFromTag(c *fiber.Ctx) error {
|
||||||
|
if err := gap.H.EnsureAuthenticated(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user := c.Locals("user").(models.Account)
|
||||||
|
|
||||||
|
tagId, err := c.ParamsInt("tagId", 0)
|
||||||
|
tag, err := services.GetTagWithID(uint(tagId))
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("unable to get tag: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = services.UnsubscribeFromTag(user, tag)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to unsubscribe from tag: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unsubscribeFromCategory(c *fiber.Ctx) error {
|
||||||
|
if err := gap.H.EnsureAuthenticated(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user := c.Locals("user").(models.Account)
|
||||||
|
|
||||||
|
categoryId, err := c.ParamsInt("categoryId", 0)
|
||||||
|
category, err := services.GetCategoryWithID(uint(categoryId))
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("unable to get category: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = services.UnsubscribeFromCategory(user, category)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to unsubscribe from category: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
}
|
@ -3,6 +3,8 @@ package services
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/dealer/pkg/hyper"
|
"git.solsynth.dev/hydrogen/dealer/pkg/hyper"
|
||||||
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
|
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
|
||||||
"git.solsynth.dev/hydrogen/interactive/pkg/internal/database"
|
"git.solsynth.dev/hydrogen/interactive/pkg/internal/database"
|
||||||
@ -10,9 +12,16 @@ import (
|
|||||||
"git.solsynth.dev/hydrogen/interactive/pkg/internal/models"
|
"git.solsynth.dev/hydrogen/interactive/pkg/internal/models"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func GetAccountWithID(id uint) (models.Account, error) {
|
||||||
|
var account models.Account
|
||||||
|
if err := database.C.Where("id = ?", id).First(&account).Error; err != nil {
|
||||||
|
return account, fmt.Errorf("unable to get account by id: %v", err)
|
||||||
|
}
|
||||||
|
return account, nil
|
||||||
|
}
|
||||||
|
|
||||||
func ListAccountFriends(user models.Account) ([]models.Account, error) {
|
func ListAccountFriends(user models.Account) ([]models.Account, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -61,6 +61,16 @@ func DeleteCategory(category models.Category) error {
|
|||||||
return database.C.Delete(category).Error
|
return database.C.Delete(category).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetTagWithID(id uint) (models.Tag, error) {
|
||||||
|
var tag models.Tag
|
||||||
|
if err := database.C.Where(models.Tag{
|
||||||
|
BaseModel: hyper.BaseModel{ID: id},
|
||||||
|
}).First(&tag).Error; err != nil {
|
||||||
|
return tag, err
|
||||||
|
}
|
||||||
|
return tag, nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetTagOrCreate(alias, name string) (models.Tag, error) {
|
func GetTagOrCreate(alias, name string) (models.Tag, error) {
|
||||||
alias = strings.ToLower(alias)
|
alias = strings.ToLower(alias)
|
||||||
var tag models.Tag
|
var tag models.Tag
|
||||||
|
136
pkg/internal/services/subscriptions.go
Normal file
136
pkg/internal/services/subscriptions.go
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.solsynth.dev/hydrogen/interactive/pkg/internal/database"
|
||||||
|
"git.solsynth.dev/hydrogen/interactive/pkg/internal/models"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetSubscriptionOnUser(user models.Account, target models.Account) (*models.Subscription, error) {
|
||||||
|
var subscription models.Subscription
|
||||||
|
if err := database.C.Where("follower_id = ? AND account_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unable to get subscription: %v", err)
|
||||||
|
}
|
||||||
|
return &subscription, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSubscriptionOnTag(user models.Account, target models.Tag) (*models.Subscription, error) {
|
||||||
|
var subscription models.Subscription
|
||||||
|
if err := database.C.Where("follower_id = ? AND tag_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unable to get subscription: %v", err)
|
||||||
|
}
|
||||||
|
return &subscription, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSubscriptionOnCategory(user models.Account, target models.Category) (*models.Subscription, error) {
|
||||||
|
var subscription models.Subscription
|
||||||
|
if err := database.C.Where("follower_id = ? AND category_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unable to get subscription: %v", err)
|
||||||
|
}
|
||||||
|
return &subscription, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubscribeToUser(user models.Account, target models.Account) (models.Subscription, error) {
|
||||||
|
var subscription models.Subscription
|
||||||
|
if err := database.C.Where("follower_id = ? AND account_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return subscription, fmt.Errorf("subscription already exists")
|
||||||
|
}
|
||||||
|
return subscription, fmt.Errorf("unable to check subscription is exists or not: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription = models.Subscription{
|
||||||
|
FollowerID: user.ID,
|
||||||
|
AccountID: &target.ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := database.C.Save(&subscription).Error
|
||||||
|
return subscription, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubscribeToTag(user models.Account, target models.Tag) (models.Subscription, error) {
|
||||||
|
var subscription models.Subscription
|
||||||
|
if err := database.C.Where("follower_id = ? AND tag_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return subscription, fmt.Errorf("subscription already exists")
|
||||||
|
}
|
||||||
|
return subscription, fmt.Errorf("unable to check subscription is exists or not: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription = models.Subscription{
|
||||||
|
FollowerID: user.ID,
|
||||||
|
TagID: &target.ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := database.C.Save(&subscription).Error
|
||||||
|
return subscription, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubscribeToCategory(user models.Account, target models.Category) (models.Subscription, error) {
|
||||||
|
var subscription models.Subscription
|
||||||
|
if err := database.C.Where("follower_id = ? AND category_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return subscription, fmt.Errorf("subscription already exists")
|
||||||
|
}
|
||||||
|
return subscription, fmt.Errorf("unable to check subscription is exists or not: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription = models.Subscription{
|
||||||
|
FollowerID: user.ID,
|
||||||
|
CategoryID: &target.ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := database.C.Save(&subscription).Error
|
||||||
|
return subscription, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnsubscribeFromUser(user models.Account, target models.Account) error {
|
||||||
|
var subscription models.Subscription
|
||||||
|
if err := database.C.Where("follower_id = ? AND account_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return fmt.Errorf("subscription does not exist")
|
||||||
|
}
|
||||||
|
return fmt.Errorf("unable to check subscription is exists or not: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := database.C.Delete(&subscription).Error
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnsubscribeFromTag(user models.Account, target models.Tag) error {
|
||||||
|
var subscription models.Subscription
|
||||||
|
if err := database.C.Where("follower_id = ? AND tag_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return fmt.Errorf("subscription does not exist")
|
||||||
|
}
|
||||||
|
return fmt.Errorf("unable to check subscription is exists or not: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := database.C.Delete(&subscription).Error
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnsubscribeFromCategory(user models.Account, target models.Category) error {
|
||||||
|
var subscription models.Subscription
|
||||||
|
if err := database.C.Where("follower_id = ? AND category_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return fmt.Errorf("subscription does not exist")
|
||||||
|
}
|
||||||
|
return fmt.Errorf("unable to check subscription is exists or not: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := database.C.Delete(&subscription).Error
|
||||||
|
return err
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user