github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/cloudery/service.go (about)

     1  package cloudery
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/url"
     7  
     8  	"github.com/cozy/cozy-stack/model/instance"
     9  	"github.com/cozy/cozy-stack/pkg/config/config"
    10  	"github.com/cozy/cozy-stack/pkg/manager"
    11  )
    12  
    13  var (
    14  	ErrInvalidContext = errors.New("missing or invalid context")
    15  )
    16  
    17  // ClouderyService handle all the Cloudery actions.
    18  type ClouderyService struct {
    19  	contexts map[string]config.ClouderyConfig
    20  }
    21  
    22  // NewService instantiate a new [ClouderyService].
    23  //
    24  // If contexts arg is nil, nil will be returned.
    25  func NewService(contexts map[string]config.ClouderyConfig) *ClouderyService {
    26  	if contexts == nil {
    27  		return nil
    28  	}
    29  
    30  	return &ClouderyService{contexts}
    31  }
    32  
    33  type SaveCmd struct {
    34  	Locale     string
    35  	Email      string
    36  	PublicName string
    37  }
    38  
    39  // SaveInstance data into the cloudery matching the instance context.
    40  func (s *ClouderyService) SaveInstance(inst *instance.Instance, cmd *SaveCmd) error {
    41  	client, err := s.getClient(inst)
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	url := fmt.Sprintf("/api/v1/instances/%s?source=stack", url.PathEscape(inst.UUID))
    47  	if err := client.Put(url, map[string]interface{}{
    48  		"locale":      cmd.Locale,
    49  		"email":       cmd.Email,
    50  		"public_name": cmd.PublicName,
    51  	}); err != nil {
    52  		return fmt.Errorf("request failed: %w", err)
    53  	}
    54  
    55  	return nil
    56  }
    57  
    58  type BlockingSubscription struct {
    59  	Vendor string `json:"vendor,omitempty"`
    60  }
    61  
    62  func (s *ClouderyService) BlockingSubscription(inst *instance.Instance) (*BlockingSubscription, error) {
    63  	client, err := s.getClient(inst)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	url := fmt.Sprintf("/api/v1/instances/%s", url.PathEscape(inst.UUID))
    69  	res, err := client.Get(url)
    70  	if err != nil {
    71  		return nil, fmt.Errorf("request failed: %w", err)
    72  	}
    73  
    74  	if hasBlockingSubscription(res) {
    75  		vendor, err := blockingSubscriptionVendor(res)
    76  		if err != nil {
    77  			return nil, err
    78  		}
    79  
    80  		return &BlockingSubscription{
    81  			Vendor: vendor,
    82  		}, nil
    83  	}
    84  
    85  	return nil, nil
    86  }
    87  
    88  func hasBlockingSubscription(clouderyInstance map[string]interface{}) bool {
    89  	return clouderyInstance["has_blocking_subscription"] == true
    90  }
    91  
    92  func blockingSubscriptionVendor(clouderyInstance map[string]interface{}) (string, error) {
    93  	if vendor, ok := clouderyInstance["blocking_subscription_vendor"].(string); ok {
    94  		return vendor, nil
    95  	}
    96  
    97  	return "", fmt.Errorf("invalid blocking subscription vendor")
    98  }
    99  
   100  func (s *ClouderyService) getClient(inst *instance.Instance) (*manager.APIClient, error) {
   101  	cfg, ok := s.contexts[inst.ContextName]
   102  	if !ok {
   103  		cfg, ok = s.contexts[config.DefaultInstanceContext]
   104  	}
   105  
   106  	if !ok {
   107  		return nil, fmt.Errorf("%w: tried %q and %q", ErrInvalidContext, inst.ContextName, config.DefaultInstanceContext)
   108  	}
   109  
   110  	client := manager.NewAPIClient(cfg.API.URL, cfg.API.Token)
   111  
   112  	return client, nil
   113  }