All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 8m16s
91 lines
2.7 KiB
Go
91 lines
2.7 KiB
Go
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
|
|
}
|