opcotech/elemo

View on GitHub
internal/transport/http/system.go

Summary

Maintainability
A
1 hr
Test Coverage
F
0%
package http

import (
    "context"
    "errors"
    "time"

    oapiTypes "github.com/oapi-codegen/runtime/types"

    "github.com/opcotech/elemo/internal/license"
    "github.com/opcotech/elemo/internal/model"
    "github.com/opcotech/elemo/internal/service"
    "github.com/opcotech/elemo/internal/transport/http/api"
)

// SystemController is a controller for system endpoints.
type SystemController interface {
    V1SystemHealth(ctx context.Context, request api.V1SystemHealthRequestObject) (api.V1SystemHealthResponseObject, error)
    V1SystemHeartbeat(ctx context.Context, request api.V1SystemHeartbeatRequestObject) (api.V1SystemHeartbeatResponseObject, error)
    V1SystemVersion(ctx context.Context, request api.V1SystemVersionRequestObject) (api.V1SystemVersionResponseObject, error)
    V1SystemLicense(ctx context.Context, request api.V1SystemLicenseRequestObject) (api.V1SystemLicenseResponseObject, error)
}

// systemController is the concrete implementation of SystemController.
type systemController struct {
    *baseController
}

func (c *systemController) V1SystemHealth(ctx context.Context, _ api.V1SystemHealthRequestObject) (api.V1SystemHealthResponseObject, error) {
    ctx, span := c.tracer.Start(ctx, "transport.http.handler/GetSystemHealth")
    defer span.End()

    ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
    defer cancel()

    health, _ := c.systemService.GetHealth(ctx)
    return api.V1SystemHealth200JSONResponse(*healthStatusToDTO(health)), nil
}

func (c *systemController) V1SystemHeartbeat(ctx context.Context, _ api.V1SystemHeartbeatRequestObject) (api.V1SystemHeartbeatResponseObject, error) {
    _, span := c.tracer.Start(ctx, "transport.http.handler/GetSystemHeartbeat")
    defer span.End()

    return api.V1SystemHeartbeat200TextResponse("OK"), nil
}

func (c *systemController) V1SystemVersion(ctx context.Context, _ api.V1SystemVersionRequestObject) (api.V1SystemVersionResponseObject, error) {
    ctx, span := c.tracer.Start(ctx, "transport.http.handler/GetSystemVersion")
    defer span.End()

    versionInfo := c.systemService.GetVersion(ctx)

    return api.V1SystemVersion200JSONResponse(*versionInfoToDTO(versionInfo)), nil
}

func (c *systemController) V1SystemLicense(ctx context.Context, _ api.V1SystemLicenseRequestObject) (api.V1SystemLicenseResponseObject, error) {
    ctx, span := c.tracer.Start(ctx, "transport.http.handler/GetSystemLicense")
    defer span.End()

    l, err := c.licenseService.GetLicense(ctx)
    if err != nil {
        if errors.Is(err, service.ErrNoPermission) {
            return api.V1SystemLicense403JSONResponse{N403JSONResponse: permissionDenied}, nil
        }
        return api.V1SystemLicenseResponseObject(nil), err
    }

    return api.V1SystemLicense200JSONResponse(*licenseToDTO(&l)), nil
}

// NewSystemController creates a new SystemController.
func NewSystemController(opts ...ControllerOption) (SystemController, error) {
    c, err := newController(opts...)
    if err != nil {
        return nil, err
    }

    controller := &systemController{
        baseController: c,
    }

    if controller.systemService == nil {
        return nil, ErrNoSystemService
    }

    return controller, nil
}

func healthStatusToDTO(status map[model.HealthCheckComponent]model.HealthStatus) *api.SystemHealth {
    return &api.SystemHealth{
        CacheDatabase:      api.SystemHealthCacheDatabase(status[model.HealthCheckComponentCacheDB].String()),
        GraphDatabase:      api.SystemHealthGraphDatabase(status[model.HealthCheckComponentGraphDB].String()),
        RelationalDatabase: api.SystemHealthRelationalDatabase(status[model.HealthCheckComponentRelationalDB].String()),
        License:            api.SystemHealthLicense(status[model.HealthCheckComponentLicense].String()),
        MessageQueue:       api.SystemHealthMessageQueue(status[model.HealthCheckComponentMessageQueue].String()),
    }
}

func versionInfoToDTO(version *model.VersionInfo) *api.SystemVersion {
    // The date is set by ldflags, so it's always in the same format.
    date, _ := time.Parse(time.RFC3339, version.Date)

    return &api.SystemVersion{
        Version:   version.Version,
        Commit:    version.Commit,
        Date:      date,
        GoVersion: version.GoVersion,
    }
}

func licenseToDTO(l *license.License) *api.SystemLicense {
    type licenseQuota = struct {
        Documents     int `json:"documents"`
        Namespaces    int `json:"namespaces"`
        Organizations int `json:"organizations"`
        Projects      int `json:"projects"`
        Roles         int `json:"roles"`
        Users         int `json:"users"`
    }

    systemLicense := &api.SystemLicense{
        Id:           l.ID.String(),
        Organization: l.Organization,
        Email:        oapiTypes.Email(l.Email),
        Quotas: licenseQuota{
            Documents:     int(l.Quotas[license.QuotaDocuments]),
            Namespaces:    int(l.Quotas[license.QuotaNamespaces]),
            Organizations: int(l.Quotas[license.QuotaOrganizations]),
            Projects:      int(l.Quotas[license.QuotaProjects]),
            Roles:         int(l.Quotas[license.QuotaRoles]),
            Users:         int(l.Quotas[license.QuotaUsers]),
        },
        ExpiresAt: l.ExpiresAt,
    }

    for _, feature := range l.Features {
        systemLicense.Features = append(systemLicense.Features, api.SystemLicenseFeatures(feature))
    }

    return systemLicense
}