package connector
import (
"context"
"fmt"
"github.com/conductorone/baton-sdk/pkg/actions"
"github.com/conductorone/baton-sdk/pkg/annotations"
"github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap"
"go.uber.org/zap"
"google.golang.org/protobuf/types/known/structpb"
)
// attrsLookup maps ConductorOne standard attribute names to the target app's
// API field names. Used by updateUserProfile to translate attribute update masks.
var attrsLookup = map[string]string{
"first_name": "first_name",
"last_name": "last_name",
"email": "email",
"department": "department",
}
func (m *Connector) enableUser(ctx context.Context, args *structpb.Struct) (*structpb.Struct, annotations.Annotations, error) {
return m.setUserStatus(ctx, args, "active", "enable-user")
}
func (m *Connector) disableUser(ctx context.Context, args *structpb.Struct) (*structpb.Struct, annotations.Annotations, error) {
return m.setUserStatus(ctx, args, "inactive", "disable-user")
}
func (m *Connector) setUserStatus(
ctx context.Context,
args *structpb.Struct,
status string,
actionName string,
) (*structpb.Struct, annotations.Annotations, error) {
l := ctxzap.Extract(ctx)
userID, ok := actions.GetStringArg(args, "resource_id")
if !ok || userID == "" {
return nil, nil, fmt.Errorf("baton-junction: %s: missing resource_id", actionName)
}
updated, err := m.client.UpdateUser(ctx, userID, map[string]string{"status": status})
if err != nil {
l.Error(fmt.Sprintf("baton-junction: %s: failed to update user status", actionName),
zap.Error(err), zap.String("user_id", userID))
return nil, nil, fmt.Errorf("baton-junction: %s: %w", actionName, err)
}
l.Info(fmt.Sprintf("baton-junction: %s: success", actionName),
zap.String("user_id", userID), zap.String("new_status", updated.Status))
result := &structpb.Struct{
Fields: map[string]*structpb.Value{
"success": {Kind: &structpb.Value_BoolValue{BoolValue: true}},
},
}
return result, nil, nil
}
func (o *userBuilder) updateUserProfile(ctx context.Context, args *structpb.Struct) (*structpb.Struct, annotations.Annotations, error) {
l := ctxzap.Extract(ctx)
userResourceID, ok := actions.GetResourceIDArg(args, "user_id")
if !ok {
return nil, nil, fmt.Errorf("baton-junction: update-user-profile: missing required argument user_id")
}
userID := userResourceID.GetResource()
if userID == "" {
return nil, nil, fmt.Errorf("baton-junction: update-user-profile: empty user_id provided")
}
attrs := make(map[string]string)
for c1Name, apiName := range attrsLookup {
val, found := actions.GetStringArg(args, c1Name)
if found && val != "" {
attrs[apiName] = val
}
}
if len(attrs) == 0 {
return nil, nil, fmt.Errorf("baton-junction: update-user-profile: no attributes provided to update")
}
updated, err := o.client.UpdateUser(ctx, userID, attrs)
if err != nil {
l.Error("baton-junction: update-user-profile: failed to update user",
zap.Error(err), zap.String("user_id", userID))
return nil, nil, fmt.Errorf("baton-junction: update-user-profile: %w", err)
}
l.Info("baton-junction: update-user-profile: success",
zap.String("user_id", userID), zap.Int("attrs_updated", len(attrs)))
result := &structpb.Struct{
Fields: map[string]*structpb.Value{
"success": {Kind: &structpb.Value_BoolValue{BoolValue: true}},
"user_id": {Kind: &structpb.Value_StringValue{StringValue: updated.ID}},
"first_name": {Kind: &structpb.Value_StringValue{StringValue: updated.FirstName}},
"last_name": {Kind: &structpb.Value_StringValue{StringValue: updated.LastName}},
"email": {Kind: &structpb.Value_StringValue{StringValue: updated.Email}},
"department": {Kind: &structpb.Value_StringValue{StringValue: updated.Department}},
},
}
return result, nil, nil
}