This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
modelUser "github.com/perfect-panel/server/internal/model/user"
|
||||
"github.com/perfect-panel/server/pkg/xerr"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
EntitlementSourceSelf = "self"
|
||||
EntitlementSourceFamilyOwner = "family_owner"
|
||||
)
|
||||
|
||||
type EntitlementContext struct {
|
||||
EffectiveUserID int64
|
||||
Source string
|
||||
OwnerUserID int64
|
||||
ReadOnly bool
|
||||
}
|
||||
|
||||
type familyEntitlementRelation struct {
|
||||
Role uint8 `gorm:"column:role"`
|
||||
FamilyStatus uint8 `gorm:"column:family_status"`
|
||||
OwnerUserID int64 `gorm:"column:owner_user_id"`
|
||||
}
|
||||
|
||||
func ResolveEntitlementUser(ctx context.Context, db *gorm.DB, currentUserID int64) (*EntitlementContext, error) {
|
||||
entitlement := buildEntitlementContext(currentUserID, nil)
|
||||
if currentUserID <= 0 {
|
||||
return entitlement, nil
|
||||
}
|
||||
|
||||
var relation familyEntitlementRelation
|
||||
err := db.WithContext(ctx).
|
||||
Table("user_family_member").
|
||||
Select("user_family_member.role, user_family.status AS family_status, user_family.owner_user_id").
|
||||
Joins("JOIN user_family ON user_family.id = user_family_member.family_id AND user_family.deleted_at IS NULL").
|
||||
Where("user_family_member.user_id = ? AND user_family_member.deleted_at IS NULL AND user_family_member.status = ?", currentUserID, modelUser.FamilyMemberActive).
|
||||
First(&relation).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entitlement, nil
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query family entitlement relation failed")
|
||||
}
|
||||
|
||||
return buildEntitlementContext(currentUserID, &relation), nil
|
||||
}
|
||||
|
||||
func DenyIfFamilyMemberReadonly(ctx context.Context, db *gorm.DB, currentUserID int64) error {
|
||||
entitlement, err := ResolveEntitlementUser(ctx, db, currentUserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return denyReadonlyEntitlement(entitlement)
|
||||
}
|
||||
|
||||
func buildEntitlementContext(currentUserID int64, relation *familyEntitlementRelation) *EntitlementContext {
|
||||
entitlement := &EntitlementContext{
|
||||
EffectiveUserID: currentUserID,
|
||||
Source: EntitlementSourceSelf,
|
||||
}
|
||||
if relation == nil {
|
||||
return entitlement
|
||||
}
|
||||
if relation.Role == modelUser.FamilyRoleMember &&
|
||||
relation.FamilyStatus == modelUser.FamilyStatusActive &&
|
||||
relation.OwnerUserID > 0 &&
|
||||
relation.OwnerUserID != currentUserID {
|
||||
return &EntitlementContext{
|
||||
EffectiveUserID: relation.OwnerUserID,
|
||||
Source: EntitlementSourceFamilyOwner,
|
||||
OwnerUserID: relation.OwnerUserID,
|
||||
ReadOnly: true,
|
||||
}
|
||||
}
|
||||
return entitlement
|
||||
}
|
||||
|
||||
func denyReadonlyEntitlement(entitlement *EntitlementContext) error {
|
||||
if entitlement != nil && entitlement.ReadOnly {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyOwnerOperationForbidden), "family member operation is forbidden")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user