Able to subscribe to realm

This commit is contained in:
LittleSheep 2024-10-14 21:40:28 +08:00
parent 6f26a44838
commit 4d602220d2
6 changed files with 181 additions and 19 deletions

View File

@ -13,4 +13,6 @@ type Subscription struct {
Tag Tag `json:"tag,omitempty"` Tag Tag `json:"tag,omitempty"`
CategoryID *uint `json:"category_id,omitempty"` CategoryID *uint `json:"category_id,omitempty"`
Category Category `json:"category,omitempty"` Category Category `json:"category,omitempty"`
RealmID *uint `json:"realm_id,omitempty"`
Realm Realm `json:"realm,omitempty"`
} }

View File

@ -51,12 +51,15 @@ func MapAPIs(app *fiber.App, baseURL string) {
subscriptions.Get("/users/:userId", getSubscriptionOnUser) subscriptions.Get("/users/:userId", getSubscriptionOnUser)
subscriptions.Get("/tags/:tagId", getSubscriptionOnTag) subscriptions.Get("/tags/:tagId", getSubscriptionOnTag)
subscriptions.Get("/categories/:categoryId", getSubscriptionOnCategory) subscriptions.Get("/categories/:categoryId", getSubscriptionOnCategory)
subscriptions.Get("/realms/:realmId", getSubscriptionOnRealm)
subscriptions.Post("/users/:userId", subscribeToUser) subscriptions.Post("/users/:userId", subscribeToUser)
subscriptions.Post("/tags/:tagId", subscribeToTag) subscriptions.Post("/tags/:tagId", subscribeToTag)
subscriptions.Post("/categories/:categoryId", subscribeToCategory) subscriptions.Post("/categories/:categoryId", subscribeToCategory)
subscriptions.Post("/realms/:realmId", subscribeToRealm)
subscriptions.Delete("/users/:userId", unsubscribeFromUser) subscriptions.Delete("/users/:userId", unsubscribeFromUser)
subscriptions.Delete("/tags/:tagId", unsubscribeFromTag) subscriptions.Delete("/tags/:tagId", unsubscribeFromTag)
subscriptions.Delete("/categories/:categoryId", unsubscribeFromCategory) subscriptions.Delete("/categories/:categoryId", unsubscribeFromCategory)
subscriptions.Delete("/realms/:realmId", unsubscribeFromRealm)
} }
api.Get("/categories", listCategories) api.Get("/categories", listCategories)

View File

@ -76,6 +76,28 @@ func getSubscriptionOnCategory(c *fiber.Ctx) error {
return c.JSON(subscription) return c.JSON(subscription)
} }
func getSubscriptionOnRealm(c *fiber.Ctx) error {
if err := gap.H.EnsureAuthenticated(c); err != nil {
return err
}
user := c.Locals("user").(models.Account)
realmId, err := c.ParamsInt("realmId", 0)
realm, err := services.GetRealmWithID(uint(realmId))
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get realm: %v", err))
}
subscription, err := services.GetSubscriptionOnRealm(user, realm)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get subscription: %v", err))
} else if subscription == nil {
return fiber.NewError(fiber.StatusNotFound, "subscription does not exist")
}
return c.JSON(subscription)
}
func subscribeToUser(c *fiber.Ctx) error { func subscribeToUser(c *fiber.Ctx) error {
if err := gap.H.EnsureAuthenticated(c); err != nil { if err := gap.H.EnsureAuthenticated(c); err != nil {
return err return err
@ -160,6 +182,34 @@ func subscribeToCategory(c *fiber.Ctx) error {
return c.JSON(subscription) return c.JSON(subscription)
} }
func subscribeToRealm(c *fiber.Ctx) error {
if err := gap.H.EnsureAuthenticated(c); err != nil {
return err
}
user := c.Locals("user").(models.Account)
realmId, err := c.ParamsInt("realmId", 0)
realm, err := services.GetRealmWithID(uint(realmId))
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get realm: %v", err))
}
subscription, err := services.SubscribeToRealm(user, realm)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to subscribe to realm: %v", err))
}
_ = gap.H.RecordAuditLog(
user.ID,
"posts.subscribe.realms",
strconv.Itoa(int(realm.ID)),
c.IP(),
c.Get(fiber.HeaderUserAgent),
)
return c.JSON(subscription)
}
func unsubscribeFromUser(c *fiber.Ctx) error { func unsubscribeFromUser(c *fiber.Ctx) error {
if err := gap.H.EnsureAuthenticated(c); err != nil { if err := gap.H.EnsureAuthenticated(c); err != nil {
return err return err
@ -243,3 +293,31 @@ func unsubscribeFromCategory(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusOK) return c.SendStatus(fiber.StatusOK)
} }
func unsubscribeFromRealm(c *fiber.Ctx) error {
if err := gap.H.EnsureAuthenticated(c); err != nil {
return err
}
user := c.Locals("user").(models.Account)
realmId, err := c.ParamsInt("realmId", 0)
realm, err := services.GetRealmWithID(uint(realmId))
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get realm: %v", err))
}
err = services.UnsubscribeFromRealm(user, realm)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to unsubscribe from realm: %v", err))
}
_ = gap.H.RecordAuditLog(
user.ID,
"posts.unsubscribe.realms",
strconv.Itoa(int(realm.ID)),
c.IP(),
c.Get(fiber.HeaderUserAgent),
)
return c.SendStatus(fiber.StatusOK)
}

View File

@ -491,3 +491,14 @@ func TruncatePostContent(post models.Post) models.Post {
return post return post
} }
const TruncatePostContentShortThreshold = 80
func TruncatePostContentShort(content string) string {
length := TruncatePostContentShortThreshold
if len([]rune(content)) >= length {
return string([]rune(content)[:length]) + "..."
} else {
return content
}
}

View File

@ -12,7 +12,7 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
) )
func GetRealmWithExtID(id uint) (models.Realm, error) { func GetRealmWithID(id uint) (models.Realm, error) {
var realm models.Realm var realm models.Realm
pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider) pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider)
if err != nil { if err != nil {

View File

@ -47,6 +47,17 @@ func GetSubscriptionOnCategory(user models.Account, target models.Category) (*mo
return &subscription, nil return &subscription, nil
} }
func GetSubscriptionOnRealm(user models.Account, target models.Realm) (*models.Subscription, error) {
var subscription models.Subscription
if err := database.C.Where("follower_id = ? AND realm_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) { func SubscribeToUser(user models.Account, target models.Account) (models.Subscription, error) {
var subscription models.Subscription var subscription models.Subscription
if err := database.C.Where("follower_id = ? AND account_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { if err := database.C.Where("follower_id = ? AND account_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
@ -98,6 +109,23 @@ func SubscribeToCategory(user models.Account, target models.Category) (models.Su
return subscription, err return subscription, err
} }
func SubscribeToRealm(user models.Account, target models.Realm) (models.Subscription, error) {
var subscription models.Subscription
if err := database.C.Where("follower_id = ? AND realm_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return subscription, fmt.Errorf("subscription already exists")
}
}
subscription = models.Subscription{
FollowerID: user.ID,
RealmID: &target.ID,
}
err := database.C.Save(&subscription).Error
return subscription, err
}
func UnsubscribeFromUser(user models.Account, target models.Account) error { func UnsubscribeFromUser(user models.Account, target models.Account) error {
var subscription models.Subscription var subscription models.Subscription
if err := database.C.Where("follower_id = ? AND account_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { if err := database.C.Where("follower_id = ? AND account_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil {
@ -137,6 +165,19 @@ func UnsubscribeFromCategory(user models.Account, target models.Category) error
return err return err
} }
func UnsubscribeFromRealm(user models.Account, target models.Realm) error {
var subscription models.Subscription
if err := database.C.Where("follower_id = ? AND realm_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 NotifyUserSubscription(poster models.Account, content string, title *string) error { func NotifyUserSubscription(poster models.Account, content string, title *string) error {
var subscriptions []models.Subscription var subscriptions []models.Subscription
if err := database.C.Where("account_id = ?", poster.ID).Preload("Follower").Find(&subscriptions).Error; err != nil { if err := database.C.Where("account_id = ?", poster.ID).Preload("Follower").Find(&subscriptions).Error; err != nil {
@ -146,12 +187,7 @@ func NotifyUserSubscription(poster models.Account, content string, title *string
nTitle := fmt.Sprintf("New post from %s (%s)", poster.Nick, poster.Name) nTitle := fmt.Sprintf("New post from %s (%s)", poster.Nick, poster.Name)
nSubtitle := "From your subscription" nSubtitle := "From your subscription"
var body string body := TruncatePostContentShort(content)
if len(content) > 80 {
body = content[:80]
} else {
body = content
}
if title != nil { if title != nil {
body = fmt.Sprintf("%s\n%s", *title, body) body = fmt.Sprintf("%s\n%s", *title, body)
} }
@ -193,12 +229,7 @@ func NotifyTagSubscription(poster models.Tag, og models.Account, content string,
nTitle := fmt.Sprintf("New post in %s by %s (%s)", poster.Name, og.Nick, og.Name) nTitle := fmt.Sprintf("New post in %s by %s (%s)", poster.Name, og.Nick, og.Name)
nSubtitle := "From your subscription" nSubtitle := "From your subscription"
var body string body := TruncatePostContentShort(content)
if len(content) > 80 {
body = content[:80]
} else {
body = content
}
if title != nil { if title != nil {
body = fmt.Sprintf("%s\n%s", *title, body) body = fmt.Sprintf("%s\n%s", *title, body)
} }
@ -240,12 +271,49 @@ func NotifyCategorySubscription(poster models.Category, og models.Account, conte
nTitle := fmt.Sprintf("New post in %s by %s (%s)", poster.Name, og.Nick, og.Name) nTitle := fmt.Sprintf("New post in %s by %s (%s)", poster.Name, og.Nick, og.Name)
nSubtitle := "From your subscription" nSubtitle := "From your subscription"
var body string body := TruncatePostContentShort(content)
if len(content) > 80 { if title != nil {
body = content[:80] body = fmt.Sprintf("%s\n%s", *title, body)
} else { }
body = content
} userIDs := make([]uint64, 0, len(subscriptions))
for _, subscription := range subscriptions {
userIDs = append(userIDs, uint64(subscription.Follower.ID))
}
pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
_, err = proto.NewNotifierClient(pc).NotifyUserBatch(ctx, &proto.NotifyUserBatchRequest{
UserId: userIDs,
Notify: &proto.NotifyRequest{
Topic: "interactive.subscription",
Title: nTitle,
Subtitle: &nSubtitle,
Body: body,
IsRealtime: false,
IsForcePush: true,
},
})
return err
}
func NotifyRealmSubscription(poster models.Realm, og models.Account, content string, title *string) error {
var subscriptions []models.Subscription
if err := database.C.Where("realm_id = ?", poster.ID).Preload("Follower").Find(&subscriptions).Error; err != nil {
return fmt.Errorf("unable to get subscriptions: %v", err)
}
nTitle := fmt.Sprintf("New post in %s by %s (%s)", poster.Name, og.Nick, og.Name)
nSubtitle := "From your subscription"
body := TruncatePostContentShort(content)
if title != nil { if title != nil {
body = fmt.Sprintf("%s\n%s", *title, body) body = fmt.Sprintf("%s\n%s", *title, body)
} }