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 query := 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). Order("user_family_member.role"). Limit(1). Find(&relation) if query.Error != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query family entitlement relation failed") } if query.RowsAffected == 0 { return entitlement, nil } 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 }