opcotech/elemo

View on GitHub
internal/model/role.go

Summary

Maintainability
A
1 hr
Test Coverage
package model

import (
    "errors"
    "time"

    "github.com/opcotech/elemo/internal/pkg/validate"
)

const (
    SystemRoleOwner   SystemRole = iota + 1 // the owner them of the instance
    SystemRoleAdmin                         // the administrator team of the instance
    SystemRoleSupport                       // the support team of the instance
)

var (
    systemRoleValues = map[SystemRole]string{
        SystemRoleOwner:   "Owner",
        SystemRoleAdmin:   "Admin",
        SystemRoleSupport: "Support",
    }
    systemRoleKeys = map[string]SystemRole{
        "Owner":   SystemRoleOwner,
        "Admin":   SystemRoleAdmin,
        "Support": SystemRoleSupport,
    }
)

// SystemRole is a special role that is created by the system.
type SystemRole uint8

// String returns the string representation of the SystemRole.
func (r SystemRole) String() string {
    return systemRoleValues[r]
}

// MarshalText implements the encoding.TextMarshaler interface.
func (r SystemRole) MarshalText() (text []byte, err error) {
    if r < 1 || r > 3 {
        return nil, ErrInvalidSystemRole
    }
    return []byte(r.String()), nil
}

// UnmarshalText implements the encoding.TextUnmarshaler interface.
func (r *SystemRole) UnmarshalText(text []byte) error {
    if v, ok := systemRoleKeys[string(text)]; ok {
        *r = v
        return nil
    }
    return ErrInvalidSystemRole
}

// Role is a group of users. However, permissions are attached to roles
// separately to avoid infinitely nested permissions.
type Role struct {
    ID          ID         `json:"id" validate:"required"`
    Name        string     `json:"name" validate:"required,min=3,max=120"`
    Description string     `json:"description" validate:"omitempty,min=5,max=500"`
    Members     []ID       `json:"members" validate:"omitempty,dive"`
    Permissions []ID       `json:"permissions" validate:"omitempty,dive"`
    CreatedAt   *time.Time `json:"created_at" validate:"omitempty"`
    UpdatedAt   *time.Time `json:"updated_at" validate:"omitempty"`
}

func (r *Role) Validate() error {
    if err := validate.Struct(r); err != nil {
        return errors.Join(ErrInvalidRoleDetails, err)
    }
    if err := r.ID.Validate(); err != nil {
        return errors.Join(ErrInvalidRoleDetails, err)
    }
    for _, member := range r.Members {
        if err := member.Validate(); err != nil {
            return errors.Join(ErrInvalidRoleDetails, err)
        }
    }
    for _, permission := range r.Permissions {
        if err := permission.Validate(); err != nil {
            return errors.Join(ErrInvalidRoleDetails, err)
        }
    }
    return nil
}

// NewRole creates a new Role.
func NewRole(name string) (*Role, error) {
    role := &Role{
        ID:          MustNewNilID(ResourceTypeRole),
        Name:        name,
        Members:     make([]ID, 0),
        Permissions: make([]ID, 0),
    }

    if err := role.Validate(); err != nil {
        return nil, err
    }

    return role, nil
}