pkg/connector/connector.go
108 linesgo
package connector

import (
	"context"
	"fmt"

	"example/baton-junction/pkg/client"
	cfg "example/baton-junction/pkg/config"

	config "github.com/conductorone/baton-sdk/pb/c1/config/v1"
	v2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2"
	"github.com/conductorone/baton-sdk/pkg/actions"
	"github.com/conductorone/baton-sdk/pkg/annotations"
	"github.com/conductorone/baton-sdk/pkg/cli"
	"github.com/conductorone/baton-sdk/pkg/connectorbuilder"
	"github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap"
	"go.uber.org/zap"
)

type Connector struct {
	client *client.Client
}

func New(ctx context.Context, cc *cfg.App, opts *cli.ConnectorOpts) (connectorbuilder.ConnectorBuilderV2, []connectorbuilder.Opt, error) {
	c, err := client.New(ctx, cc.AppClientId, cc.AppClientSecret, cc.BaseUrl)
	if err != nil {
		return nil, nil, fmt.Errorf("baton-junction: failed to create client: %w", err)
	}
	return &Connector{client: c}, nil, nil
}

func (m *Connector) Metadata(_ context.Context) (*v2.ConnectorMetadata, error) {
	var annos annotations.Annotations
	annos.Update(&v2.ExternalLink{Url: "https://example.com"})

	return &v2.ConnectorMetadata{
		DisplayName: "Baton App",
		Description: "Syncs users, roles, and groups from the target app",
		Annotations: annos,
	}, nil
}

func (m *Connector) Validate(ctx context.Context) (annotations.Annotations, error) {
	l := ctxzap.Extract(ctx)

	_, err := m.client.GetCurrentUser(ctx)
	if err != nil {
		return nil, fmt.Errorf("baton-junction: validation failed — check credentials: %w", err)
	}

	l.Debug("validation passed")
	return nil, nil
}

func (m *Connector) ResourceSyncers(_ context.Context) []connectorbuilder.ResourceSyncerV2 {
	return []connectorbuilder.ResourceSyncerV2{
		newUserBuilder(m.client),
		newGroupBuilder(m.client),
		newRoleBuilder(m.client),
	}
}

func (m *Connector) GlobalActions(ctx context.Context, registry actions.ActionRegistry) error {
	l := ctxzap.Extract(ctx)

	enableSchema := &v2.BatonActionSchema{
		Name:        "enable_user",
		DisplayName: "Enable User",
		Description: "Enable a user account in the target app",
		Arguments: []*config.Field{
			{Name: "resource_id", DisplayName: "User Resource ID", Field: &config.Field_StringField{}, IsRequired: true},
		},
		ReturnTypes: []*config.Field{
			{Name: "success", DisplayName: "Success", Field: &config.Field_BoolField{}},
		},
		ActionType: []v2.ActionType{
			v2.ActionType_ACTION_TYPE_ACCOUNT,
			v2.ActionType_ACTION_TYPE_ACCOUNT_ENABLE,
		},
	}
	if err := registry.Register(ctx, enableSchema, m.enableUser); err != nil {
		l.Error("failed to register action", zap.Error(err), zap.String("action", enableSchema.GetName()))
		return fmt.Errorf("baton-junction: failed to register enable_user action: %w", err)
	}

	disableSchema := &v2.BatonActionSchema{
		Name:        "disable_user",
		DisplayName: "Disable User",
		Description: "Disable a user account in the target app",
		Arguments: []*config.Field{
			{Name: "resource_id", DisplayName: "User Resource ID", Field: &config.Field_StringField{}, IsRequired: true},
		},
		ReturnTypes: []*config.Field{
			{Name: "success", DisplayName: "Success", Field: &config.Field_BoolField{}},
		},
		ActionType: []v2.ActionType{
			v2.ActionType_ACTION_TYPE_ACCOUNT,
			v2.ActionType_ACTION_TYPE_ACCOUNT_DISABLE,
		},
	}
	if err := registry.Register(ctx, disableSchema, m.disableUser); err != nil {
		l.Error("failed to register action", zap.Error(err), zap.String("action", disableSchema.GetName()))
		return fmt.Errorf("baton-junction: failed to register disable_user action: %w", err)
	}

	return nil
}