Ctrl K
ComunidadGuías…

cli/organizationsettings.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package cli

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"

	"github.com/google/uuid"
	"golang.org/x/xerrors"

	"github.com/coder/coder/v2/codersdk"
	"github.com/coder/serpent"
)

func (r *RootCmd) organizationSettings(orgContext *OrganizationContext) *serpent.Command {
	settings := []organizationSetting{
		{
			Name:    "group-sync",
			Aliases: []string{"groupsync"},
			Short:   "Group sync settings to sync groups from an IdP.",
			Patch: func(ctx context.Context, cli *codersdk.Client, org uuid.UUID, input json.RawMessage) (any, error) {
				var req codersdk.GroupSyncSettings
				err := json.Unmarshal(input, &req)
				if err != nil {
					return nil, xerrors.Errorf("unmarshalling group sync settings: %w", err)
				}
				return cli.PatchGroupIDPSyncSettings(ctx, org.String(), req)
			},
			Fetch: func(ctx context.Context, cli *codersdk.Client, org uuid.UUID) (any, error) {
				return cli.GroupIDPSyncSettings(ctx, org.String())
			},
		},
		{
			Name:    "role-sync",
			Aliases: []string{"rolesync"},
			Short:   "Role sync settings to sync organization roles from an IdP.",
			Patch: func(ctx context.Context, cli *codersdk.Client, org uuid.UUID, input json.RawMessage) (any, error) {
				var req codersdk.RoleSyncSettings
				err := json.Unmarshal(input, &req)
				if err != nil {
					return nil, xerrors.Errorf("unmarshalling role sync settings: %w", err)
				}
				return cli.PatchRoleIDPSyncSettings(ctx, org.String(), req)
			},
			Fetch: func(ctx context.Context, cli *codersdk.Client, org uuid.UUID) (any, error) {
				return cli.RoleIDPSyncSettings(ctx, org.String())
			},
		},
		{
			Name:              "organization-sync",
			Aliases:           []string{"organizationsync", "org-sync", "orgsync"},
			Short:             "Organization sync settings to sync organization memberships from an IdP.",
			DisableOrgContext: true,
			Patch: func(ctx context.Context, cli *codersdk.Client, _ uuid.UUID, input json.RawMessage) (any, error) {
				var req codersdk.OrganizationSyncSettings
				err := json.Unmarshal(input, &req)
				if err != nil {
					return nil, xerrors.Errorf("unmarshalling organization sync settings: %w", err)
				}
				return cli.PatchOrganizationIDPSyncSettings(ctx, req)
			},
			Fetch: func(ctx context.Context, cli *codersdk.Client, _ uuid.UUID) (any, error) {
				return cli.OrganizationIDPSyncSettings(ctx)
			},
		},
		{
			Name:    "workspace-sharing",
			Aliases: []string{"workspacesharing"},
			Short:   "Workspace sharing settings for the organization.",
			Patch: func(ctx context.Context, cli *codersdk.Client, org uuid.UUID, input json.RawMessage) (any, error) {
				var req codersdk.UpdateWorkspaceSharingSettingsRequest
				err := json.Unmarshal(input, &req)
				if err != nil {
					return nil, xerrors.Errorf("unmarshalling workspace sharing settings: %w", err)
				}
				return cli.PatchWorkspaceSharingSettings(ctx, org.String(), req)
			},
			Fetch: func(ctx context.Context, cli *codersdk.Client, org uuid.UUID) (any, error) {
				return cli.WorkspaceSharingSettings(ctx, org.String())
			},
		},
	}
	cmd := &serpent.Command{
		Use:     "settings",
		Short:   "Manage organization settings.",
		Aliases: []string{"setting"},
		Handler: func(inv *serpent.Invocation) error {
			return inv.Command.HelpHandler(inv)
		},
		Children: []*serpent.Command{
			r.printOrganizationSetting(orgContext, settings),
			r.setOrganizationSettings(orgContext, settings),
		},
	}
	return cmd
}

type organizationSetting struct {
	Name    string
	Aliases []string
	Short   string
	// DisableOrgContext is kinda a kludge. It tells the command constructor
	// to not require an organization context. This is used for the organization
	// sync settings which are not tied to a specific organization.
	// It feels excessive to build a more elaborate solution for this one-off.
	DisableOrgContext bool
	Patch             func(ctx context.Context, cli *codersdk.Client, org uuid.UUID, input json.RawMessage) (any, error)
	Fetch             func(ctx context.Context, cli *codersdk.Client, org uuid.UUID) (any, error)
}

func (r *RootCmd) setOrganizationSettings(orgContext *OrganizationContext, settings []organizationSetting) *serpent.Command {
	cmd := &serpent.Command{
		Use:   "set",
		Short: "Update specified organization setting.",
		Long: FormatExamples(
			Example{
				Description: "Update group sync settings.",
				Command:     "coder organization settings set groupsync < input.json",
			},
		),
		Options: []serpent.Option{},
		Middleware: serpent.Chain(
			serpent.RequireNArgs(0),
		),
		Handler: func(inv *serpent.Invocation) error {
			return inv.Command.HelpHandler(inv)
		},
	}

	for _, set := range settings {
		patch := set.Patch
		cmd.Children = append(cmd.Children, &serpent.Command{
			Use:     set.Name,
			Aliases: set.Aliases,
			Short:   set.Short,
			Options: []serpent.Option{},
			Middleware: serpent.Chain(
				serpent.RequireNArgs(0),
			),
			Handler: func(inv *serpent.Invocation) error {
				client, err := r.InitClient(inv)
				if err != nil {
					return err
				}

				ctx := inv.Context()
				var org codersdk.Organization

				if !set.DisableOrgContext {
					org, err = orgContext.Selected(inv, client)
					if err != nil {
						return err
					}
				}

				// Read in the json
				inputData, err := io.ReadAll(inv.Stdin)
				if err != nil {
					return xerrors.Errorf("reading stdin: %w", err)
				}

				output, err := patch(ctx, client, org.ID, inputData)
				if err != nil {
					return xerrors.Errorf("patching %q: %w", set.Name, err)
				}

				settingJSON, err := json.Marshal(output)
				if err != nil {
					return xerrors.Errorf("failed to marshal organization setting %s: %w", inv.Args[0], err)
				}

				var dst bytes.Buffer
				err = json.Indent(&dst, settingJSON, "", "\t")
				if err != nil {
					return xerrors.Errorf("failed to indent organization setting as json %s: %w", inv.Args[0], err)
				}

				_, err = fmt.Fprintln(inv.Stdout, dst.String())
				return err
			},
		})
	}

	return cmd
}

func (r *RootCmd) printOrganizationSetting(orgContext *OrganizationContext, settings []organizationSetting) *serpent.Command {
	cmd := &serpent.Command{
		Use:   "show",
		Short: "Outputs specified organization setting.",
		Long: FormatExamples(
			Example{
				Description: "Output group sync settings.",
				Command:     "coder organization settings show groupsync",
			},
		),
		Options: []serpent.Option{},
		Middleware: serpent.Chain(
			serpent.RequireNArgs(0),
		),
		Handler: func(inv *serpent.Invocation) error {
			return inv.Command.HelpHandler(inv)
		},
	}

	for _, set := range settings {
		fetch := set.Fetch
		cmd.Children = append(cmd.Children, &serpent.Command{
			Use:     set.Name,
			Aliases: set.Aliases,
			Short:   set.Short,
			Options: []serpent.Option{},
			Middleware: serpent.Chain(
				serpent.RequireNArgs(0),
			),
			Handler: func(inv *serpent.Invocation) error {
				client, err := r.InitClient(inv)
				if err != nil {
					return err
				}

				ctx := inv.Context()
				var org codersdk.Organization
				if !set.DisableOrgContext {
					org, err = orgContext.Selected(inv, client)
					if err != nil {
						return err
					}
				}

				output, err := fetch(ctx, client, org.ID)
				if err != nil {
					return xerrors.Errorf("patching %q: %w", set.Name, err)
				}

				settingJSON, err := json.Marshal(output)
				if err != nil {
					return xerrors.Errorf("failed to marshal organization setting %s: %w", inv.Args[0], err)
				}

				var dst bytes.Buffer
				err = json.Indent(&dst, settingJSON, "", "\t")
				if err != nil {
					return xerrors.Errorf("failed to indent organization setting as json %s: %w", inv.Args[0], err)
				}

				_, err = fmt.Fprintln(inv.Stdout, dst.String())
				return err
			},
		})
	}

	return cmd
}