♻️ Refactored relation system
⬆️ Support new realm & relation api
This commit is contained in:
@ -209,7 +209,7 @@ func DeleteAccount(id uint) error {
|
||||
&models.MagicToken{},
|
||||
&models.ThirdClient{},
|
||||
&models.NotificationSubscriber{},
|
||||
&models.AccountFriendship{},
|
||||
&models.AccountRelationship{},
|
||||
} {
|
||||
if err := tx.Delete(model, "account_id = ?", id).Error; err != nil {
|
||||
tx.Rollback()
|
||||
|
@ -1,125 +0,0 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func ListAllFriend(anyside models.Account) ([]models.AccountFriendship, error) {
|
||||
var relationships []models.AccountFriendship
|
||||
if err := database.C.
|
||||
Where("account_id = ? OR related_id = ?", anyside.ID, anyside.ID).
|
||||
Preload("Account").
|
||||
Preload("Related").
|
||||
Find(&relationships).Error; err != nil {
|
||||
return relationships, err
|
||||
}
|
||||
|
||||
return relationships, nil
|
||||
}
|
||||
|
||||
func ListFriend(anyside models.Account, status models.FriendshipStatus) ([]models.AccountFriendship, error) {
|
||||
var relationships []models.AccountFriendship
|
||||
if err := database.C.
|
||||
Where("(account_id = ? OR related_id = ?) AND status = ?", anyside.ID, anyside.ID, status).
|
||||
Preload("Account").
|
||||
Preload("Related").
|
||||
Find(&relationships).Error; err != nil {
|
||||
return relationships, err
|
||||
}
|
||||
|
||||
return relationships, nil
|
||||
}
|
||||
|
||||
func GetFriend(anysideId uint) (models.AccountFriendship, error) {
|
||||
var relationship models.AccountFriendship
|
||||
if err := database.C.
|
||||
Where(&models.AccountFriendship{AccountID: anysideId}).
|
||||
Or(&models.AccountFriendship{RelatedID: anysideId}).
|
||||
Preload("Account").
|
||||
Preload("Related").
|
||||
First(&relationship).Error; err != nil {
|
||||
return relationship, err
|
||||
}
|
||||
|
||||
return relationship, nil
|
||||
}
|
||||
|
||||
func GetFriendWithTwoSides(userId, relatedId uint, noPreload ...bool) (models.AccountFriendship, error) {
|
||||
var tx *gorm.DB
|
||||
if len(noPreload) > 0 && noPreload[0] {
|
||||
tx = database.C
|
||||
} else {
|
||||
tx = database.C.Preload("Account").Preload("Related")
|
||||
}
|
||||
|
||||
var relationship models.AccountFriendship
|
||||
if err := tx.
|
||||
Where(&models.AccountFriendship{AccountID: userId, RelatedID: relatedId}).
|
||||
Or(&models.AccountFriendship{RelatedID: userId, AccountID: relatedId}).
|
||||
First(&relationship).Error; err != nil {
|
||||
return relationship, err
|
||||
}
|
||||
|
||||
return relationship, nil
|
||||
}
|
||||
|
||||
func NewFriend(user models.Account, related models.Account, status models.FriendshipStatus) (models.AccountFriendship, error) {
|
||||
relationship := models.AccountFriendship{
|
||||
AccountID: user.ID,
|
||||
RelatedID: related.ID,
|
||||
Status: status,
|
||||
}
|
||||
|
||||
if user.ID == related.ID {
|
||||
return relationship, fmt.Errorf("you cannot make friendship with yourself")
|
||||
} else if _, err := GetFriendWithTwoSides(user.ID, related.ID, true); err == nil || !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return relationship, fmt.Errorf("you already have a friendship with him or her")
|
||||
}
|
||||
|
||||
if err := database.C.Save(&relationship).Error; err != nil {
|
||||
return relationship, err
|
||||
} else {
|
||||
_ = NewNotification(models.Notification{
|
||||
Subject: fmt.Sprintf("New friend request from %s", user.Name),
|
||||
Content: fmt.Sprintf("You got a new friend request from %s. Go to your settings and decide how to deal it.", user.Nick),
|
||||
RecipientID: related.ID,
|
||||
})
|
||||
}
|
||||
|
||||
return relationship, nil
|
||||
}
|
||||
|
||||
func EditFriendWithCheck(relationship models.AccountFriendship, user models.Account, originalStatus models.FriendshipStatus) (models.AccountFriendship, error) {
|
||||
if relationship.Status != originalStatus {
|
||||
if originalStatus == models.FriendshipBlocked && relationship.BlockedBy != nil && user.ID != *relationship.BlockedBy {
|
||||
return relationship, fmt.Errorf("the friendship has been blocked by the otherside, you cannot modify it status")
|
||||
}
|
||||
if relationship.Status == models.FriendshipPending && relationship.RelatedID != user.ID {
|
||||
return relationship, fmt.Errorf("only related person can accept friendship")
|
||||
}
|
||||
}
|
||||
if originalStatus != models.FriendshipBlocked && relationship.Status == models.FriendshipBlocked {
|
||||
relationship.BlockedBy = &user.ID
|
||||
}
|
||||
|
||||
return EditFriend(relationship)
|
||||
}
|
||||
|
||||
func EditFriend(relationship models.AccountFriendship) (models.AccountFriendship, error) {
|
||||
if err := database.C.Save(&relationship).Error; err != nil {
|
||||
return relationship, err
|
||||
}
|
||||
return relationship, nil
|
||||
}
|
||||
|
||||
func DeleteFriend(relationship models.AccountFriendship) error {
|
||||
if err := database.C.Delete(&relationship).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@ -61,15 +61,15 @@ func NewNotification(notification models.Notification) error {
|
||||
}
|
||||
|
||||
// PushNotification will push the notification whatever it exists record in the
|
||||
// database Recommend push another goroutine when you need to push a lot of
|
||||
// database Recommend pushing another goroutine when you need to push a lot of
|
||||
// notifications And just use a block statement when you just push one
|
||||
// notification, the time of create a new subprocess is much more than push
|
||||
// notification
|
||||
// notification.
|
||||
// The time of creating a new subprocess is much more than push notification.
|
||||
func PushNotification(notification models.Notification) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
_, err := proto.NewStreamControllerClient(gap.H.GetDealerGrpcConn()).PushStream(ctx, &proto.PushStreamRequest{
|
||||
UserId: uint64(notification.RecipientID),
|
||||
UserId: uint64(notification.UserID),
|
||||
Body: models.UnifiedCommand{
|
||||
Action: "notifications.new",
|
||||
Payload: notification,
|
||||
@ -80,13 +80,13 @@ func PushNotification(notification models.Notification) error {
|
||||
}
|
||||
|
||||
// Skip push notification
|
||||
if GetStatusDisturbable(notification.RecipientID) != nil {
|
||||
if GetStatusDisturbable(notification.UserID) != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var subscribers []models.NotificationSubscriber
|
||||
if err := database.C.Where(&models.NotificationSubscriber{
|
||||
AccountID: notification.RecipientID,
|
||||
AccountID: notification.UserID,
|
||||
}).Find(&subscribers).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
@ -104,8 +104,8 @@ func PushNotification(notification models.Notification) error {
|
||||
|
||||
message := &messaging.Message{
|
||||
Notification: &messaging.Notification{
|
||||
Title: notification.Subject,
|
||||
Body: notification.Content,
|
||||
Title: notification.Title,
|
||||
Body: notification.Body,
|
||||
},
|
||||
Token: subscriber.DeviceToken,
|
||||
}
|
||||
@ -123,10 +123,10 @@ func PushNotification(notification models.Notification) error {
|
||||
if ExtAPNS != nil {
|
||||
data, err := payload2.
|
||||
NewPayload().
|
||||
AlertTitle(notification.Subject).
|
||||
AlertBody(notification.Content).
|
||||
AlertTitle(notification.Title).
|
||||
AlertBody(notification.Body).
|
||||
Sound("default").
|
||||
Category(notification.Type).
|
||||
Category(notification.Topic).
|
||||
MarshalJSON()
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("An error occurred when preparing to notify subscriber via APNs...")
|
||||
|
@ -14,6 +14,13 @@ func HasPermNode(perms map[string]any, requiredKey string, requiredValue any) bo
|
||||
return false
|
||||
}
|
||||
|
||||
func HasPermNodeWithDefault(perms map[string]any, requiredKey string, requiredValue any, defaultValue any) bool {
|
||||
if heldValue, ok := perms[requiredKey]; ok {
|
||||
return ComparePermNode(heldValue, requiredValue)
|
||||
}
|
||||
return ComparePermNode(defaultValue, requiredValue)
|
||||
}
|
||||
|
||||
func ComparePermNode(held any, required any) bool {
|
||||
heldValue := reflect.ValueOf(held)
|
||||
requiredValue := reflect.ValueOf(required)
|
||||
|
@ -97,9 +97,14 @@ func AddRealmMember(user models.Account, affected models.Account, target models.
|
||||
} else if member.PowerLevel < 50 {
|
||||
return fmt.Errorf("only realm moderator can add people")
|
||||
}
|
||||
friendship, err := GetFriendWithTwoSides(affected.ID, user.ID)
|
||||
if err != nil || friendship.Status != models.FriendshipActive {
|
||||
return fmt.Errorf("you only can add your friends to your realm")
|
||||
rel, err := GetRelationWithTwoNode(affected.ID, user.ID)
|
||||
if err != nil || HasPermNodeWithDefault(
|
||||
rel.PermNodes,
|
||||
"RealmAdd",
|
||||
true,
|
||||
rel.Status == models.RelationshipFriend,
|
||||
) {
|
||||
return fmt.Errorf("you unable to add this user to your realm")
|
||||
}
|
||||
}
|
||||
|
||||
|
118
pkg/internal/services/relationships.go
Normal file
118
pkg/internal/services/relationships.go
Normal file
@ -0,0 +1,118 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func ListAllRelationship(user models.Account) ([]models.AccountRelationship, error) {
|
||||
var relationships []models.AccountRelationship
|
||||
if err := database.C.
|
||||
Where("account_id = ?", user.ID).
|
||||
Preload("Account").
|
||||
Preload("Related").
|
||||
Find(&relationships).Error; err != nil {
|
||||
return relationships, err
|
||||
}
|
||||
|
||||
return relationships, nil
|
||||
}
|
||||
|
||||
func ListRelationshipWithFilter(user models.Account, status models.RelationshipStatus) ([]models.AccountRelationship, error) {
|
||||
var relationships []models.AccountRelationship
|
||||
if err := database.C.
|
||||
Where("account_id = ? AND status = ?", user.ID, status).
|
||||
Preload("Account").
|
||||
Preload("Related").
|
||||
Find(&relationships).Error; err != nil {
|
||||
return relationships, err
|
||||
}
|
||||
|
||||
return relationships, nil
|
||||
}
|
||||
|
||||
func GetRelationship(otherId uint) (models.AccountRelationship, error) {
|
||||
var relationship models.AccountRelationship
|
||||
if err := database.C.
|
||||
Where(&models.AccountRelationship{AccountID: otherId}).
|
||||
Preload("Account").
|
||||
Preload("Related").
|
||||
First(&relationship).Error; err != nil {
|
||||
return relationship, err
|
||||
}
|
||||
|
||||
return relationship, nil
|
||||
}
|
||||
|
||||
func GetRelationWithTwoNode(userId, relatedId uint, noPreload ...bool) (models.AccountRelationship, error) {
|
||||
var tx *gorm.DB
|
||||
if len(noPreload) > 0 && noPreload[0] {
|
||||
tx = database.C
|
||||
} else {
|
||||
tx = database.C.Preload("Account").Preload("Related")
|
||||
}
|
||||
|
||||
var relationship models.AccountRelationship
|
||||
if err := tx.
|
||||
Where(&models.AccountRelationship{AccountID: userId, RelatedID: relatedId}).
|
||||
First(&relationship).Error; err != nil {
|
||||
return relationship, err
|
||||
}
|
||||
|
||||
return relationship, nil
|
||||
}
|
||||
|
||||
func NewFriend(userA models.Account, userB models.Account, skipPending ...bool) (models.AccountRelationship, error) {
|
||||
relA := models.AccountRelationship{
|
||||
AccountID: userA.ID,
|
||||
RelatedID: userB.ID,
|
||||
Status: models.RelationshipFriend,
|
||||
}
|
||||
relB := models.AccountRelationship{
|
||||
AccountID: userB.ID,
|
||||
RelatedID: userA.ID,
|
||||
Status: models.RelationshipPending,
|
||||
}
|
||||
|
||||
if len(skipPending) > 0 && skipPending[0] {
|
||||
relB.Status = models.RelationshipFriend
|
||||
}
|
||||
|
||||
if userA.ID == userB.ID {
|
||||
return relA, fmt.Errorf("you cannot make friendship with yourself")
|
||||
} else if _, err := GetRelationWithTwoNode(userA.ID, userB.ID, true); err == nil || !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return relA, fmt.Errorf("you already have a friendship with him or her")
|
||||
}
|
||||
|
||||
if err := database.C.Save(&relA).Error; err != nil {
|
||||
return relA, err
|
||||
} else if err = database.C.Save(&relB).Error; err != nil {
|
||||
return relA, err
|
||||
} else {
|
||||
_ = NewNotification(models.Notification{
|
||||
Title: fmt.Sprintf("New friend request from %s", userA.Name),
|
||||
Body: fmt.Sprintf("You got a new friend request from %s. Go to your settings and decide how to deal it.", userA.Nick),
|
||||
UserID: userB.ID,
|
||||
})
|
||||
}
|
||||
|
||||
return relA, nil
|
||||
}
|
||||
|
||||
func EditRelationship(relationship models.AccountRelationship) (models.AccountRelationship, error) {
|
||||
if err := database.C.Save(&relationship).Error; err != nil {
|
||||
return relationship, err
|
||||
}
|
||||
return relationship, nil
|
||||
}
|
||||
|
||||
func DeleteRelationship(relationship models.AccountRelationship) error {
|
||||
if err := database.C.Delete(&relationship).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user