✨ Able to subscribe to realm
This commit is contained in:
		| @@ -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"` | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
| @@ -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) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -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 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -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 { | ||||||
|   | |||||||
| @@ -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) | ||||||
| 	} | 	} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user