Skip to content

Commit

Permalink
feat: add CRUD organizations support
Browse files Browse the repository at this point in the history
  • Loading branch information
hperl committed Sep 28, 2023
1 parent 33a62bb commit d6be6da
Show file tree
Hide file tree
Showing 22 changed files with 484 additions and 46 deletions.
94 changes: 90 additions & 4 deletions cmd/cloudx/client/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"golang.org/x/term"

cloud "github.com/ory/client-go"
newCloud "github.com/ory/client-go/1.2"
"github.com/ory/x/cmdx"
"github.com/ory/x/flagx"
"github.com/ory/x/jsonx"
Expand Down Expand Up @@ -299,10 +300,11 @@ retryRegistration:
return nil, err
}

signup, _, err := c.FrontendApi.UpdateRegistrationFlow(h.Ctx).
Flow(flow.Id).UpdateRegistrationFlowBody(cloud.UpdateRegistrationFlowBody{
UpdateRegistrationFlowWithPasswordMethod: &form,
}).Execute()
signup, _, err := c.FrontendApi.
UpdateRegistrationFlow(h.Ctx).
Flow(flow.Id).
UpdateRegistrationFlowBody(cloud.UpdateRegistrationFlowBody{UpdateRegistrationFlowWithPasswordMethod: &form}).
Execute()
if err != nil {
if e, ok := err.(*cloud.GenericOpenAPIError); ok {
switch m := e.Model().(type) {
Expand Down Expand Up @@ -518,6 +520,90 @@ func (h *CommandHelper) ListProjects() ([]cloud.ProjectMetadata, error) {
return projects, nil
}

func (h *CommandHelper) ListOrganizations(projectID string) (*newCloud.ListOrganizationsResponse, error) {
ac, err := h.EnsureContext()
if err != nil {
return nil, err
}

c, err := newNewCloudClient(ac.SessionToken)
if err != nil {
return nil, err
}

organizations, res, err := c.ProjectApi.ListOrganizations(h.Ctx, projectID).Execute()
if err != nil {
return nil, handleError("unable to list organizations", res, err)
}

return organizations, nil
}

func (h *CommandHelper) CreateOrganization(projectID string, body newCloud.OrganizationBody) (*newCloud.Organization, error) {
ac, err := h.EnsureContext()
if err != nil {
return nil, err
}

c, err := newNewCloudClient(ac.SessionToken)
if err != nil {
return nil, err
}

organization, res, err := c.ProjectApi.
CreateOrganization(h.Ctx, projectID).
OrganizationBody(body).
Execute()
if err != nil {
return nil, handleError("unable to create organization", res, err)
}

return organization, nil
}

func (h *CommandHelper) UpdateOrganization(projectID, orgID string, body newCloud.OrganizationBody) (*newCloud.Organization, error) {
ac, err := h.EnsureContext()
if err != nil {
return nil, err
}

c, err := newNewCloudClient(ac.SessionToken)
if err != nil {
return nil, err
}

organization, res, err := c.ProjectApi.
UpdateOrganization(h.Ctx, projectID, orgID).
OrganizationBody(body).
Execute()
if err != nil {
return nil, handleError("unable to update organization", res, err)
}

return organization, nil
}

func (h *CommandHelper) DeleteOrganization(projectID, orgID string) error {
ac, err := h.EnsureContext()
if err != nil {
return err
}

c, err := newNewCloudClient(ac.SessionToken)
if err != nil {
return err
}

res, err := c.ProjectApi.
DeleteOrganization(h.Ctx, projectID, orgID).
Execute()
if err != nil {
return handleError("unable to create organization", res, err)
}

return nil
}

func (h *CommandHelper) GetProject(projectOrSlug string) (*cloud.Project, error) {
if projectOrSlug == "" {
return nil, errors.Errorf("No project selected! Please see the help message on how to set one.")
Expand Down
14 changes: 14 additions & 0 deletions cmd/cloudx/client/sdks.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

cloud "github.com/ory/client-go"
newCloud "github.com/ory/client-go/1.2"
"github.com/ory/x/stringsx"
)

Expand Down Expand Up @@ -76,3 +77,16 @@ func newCloudClient(token string) (*cloud.APIClient, error) {

return cloud.NewAPIClient(conf), nil
}

func newNewCloudClient(token string) (*newCloud.APIClient, error) {
u := makeCloudConsoleURL("api")

conf := newCloud.NewConfiguration()
conf.Servers = newCloud.ServerConfigurations{{URL: u}}
conf.HTTPClient = newBearerTokenClient(token)
if RateLimitHeader != "" {
conf.AddDefaultHeader("Ory-RateLimit-Action", RateLimitHeader)
}

return newCloud.NewAPIClient(conf), nil
}
2 changes: 2 additions & 0 deletions cmd/cloudx/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra"

"github.com/ory/cli/cmd/cloudx/oauth2"
"github.com/ory/cli/cmd/cloudx/organizations"
"github.com/ory/cli/cmd/cloudx/relationtuples"

"github.com/ory/cli/cmd/cloudx/client"
Expand All @@ -24,6 +25,7 @@ func NewCreateCmd() *cobra.Command {
oauth2.NewCreateOAuth2Client(),
relationtuples.NewCreateCmd(),
oauth2.NewCreateJWK(),
organizations.NewCreateOrganizationCmd(),
)

client.RegisterConfigFlag(cmd.PersistentFlags())
Expand Down
2 changes: 2 additions & 0 deletions cmd/cloudx/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra"

"github.com/ory/cli/cmd/cloudx/oauth2"
"github.com/ory/cli/cmd/cloudx/organizations"
"github.com/ory/cli/cmd/cloudx/relationtuples"

"github.com/ory/cli/cmd/cloudx/client"
Expand All @@ -26,6 +27,7 @@ func NewDeleteCmd() *cobra.Command {
oauth2.NewDeleteJWKs(),
oauth2.NewDeleteAccessTokens(),
relationtuples.NewDeleteCmd(),
organizations.NewDeleteOrganizationCmd(),
)

client.RegisterConfigFlag(cmd.PersistentFlags())
Expand Down
2 changes: 2 additions & 0 deletions cmd/cloudx/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/ory/cli/cmd/cloudx/identity"
"github.com/ory/cli/cmd/cloudx/oauth2"
"github.com/ory/cli/cmd/cloudx/organizations"
"github.com/ory/cli/cmd/cloudx/relationtuples"

"github.com/ory/cli/cmd/cloudx/client"
Expand All @@ -24,6 +25,7 @@ func NewListCmd() *cobra.Command {

cmd.AddCommand(
project.NewListProjectsCmd(),
organizations.NewListOrganizationsCmd(),
identity.NewListIdentityCmd(),
oauth2.NewListOAuth2Clients(),
relationtuples.NewListCmd(),
Expand Down
55 changes: 55 additions & 0 deletions cmd/cloudx/organizations/create_organization.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0

package organizations

import (
"fmt"

"github.com/spf13/cobra"

"github.com/ory/cli/cmd/cloudx/client"
cloud "github.com/ory/client-go/1.2"

"github.com/ory/x/cmdx"
"github.com/ory/x/flagx"
)

func NewCreateOrganizationCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "organization label [--project=PROJECT_ID] [--domains=a.example.com,b.example.com]",
Args: cobra.ExactArgs(1),
Short: "Create a new Ory Network organization",
RunE: func(cmd *cobra.Command, args []string) error {
h, err := client.NewCommandHelper(cmd)
if err != nil {
return err
}

projectID, err := client.ProjectOrDefault(cmd, h)
if err != nil {
return cmdx.PrintOpenAPIError(cmd, err)
}
label := args[0]
domains := flagx.MustGetStringSlice(cmd, "domains")

organization, err := h.CreateOrganization(projectID, cloud.OrganizationBody{
Label: &label,
Domains: domains,
})
if err != nil {
return cmdx.PrintOpenAPIError(cmd, err)
}

_, _ = fmt.Fprintln(h.VerboseErrWriter, "Organization created successfully!")
cmdx.PrintRow(cmd, output(*organization))
return nil
},
}

client.RegisterProjectFlag(cmd.Flags())
cmdx.RegisterFormatFlags(cmd.Flags())
cmd.Flags().StringSliceP("domains", "d", []string{}, "A list of domains that will be used for this organization.")

return cmd
}
44 changes: 44 additions & 0 deletions cmd/cloudx/organizations/delete_organization.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0

package organizations

import (
"fmt"

"github.com/spf13/cobra"

"github.com/ory/cli/cmd/cloudx/client"
"github.com/ory/x/cmdx"
)

func NewDeleteOrganizationCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "organization id [--project=PROJECT_ID]",
Args: cobra.ExactArgs(1),
Short: "Delete the organization with the given ID",
RunE: func(cmd *cobra.Command, args []string) error {
h, err := client.NewCommandHelper(cmd)
if err != nil {
return err
}

projectID, err := client.ProjectOrDefault(cmd, h)
if err != nil {
return cmdx.PrintOpenAPIError(cmd, err)
}
orgID := args[0]

err = h.DeleteOrganization(projectID, orgID)
if err != nil {
return cmdx.PrintOpenAPIError(cmd, err)
}

_, _ = fmt.Fprintln(h.VerboseErrWriter, "Organization deleted successfully!")
return nil
},
}

client.RegisterProjectFlag(cmd.Flags())
return cmd
}
42 changes: 42 additions & 0 deletions cmd/cloudx/organizations/list_organizations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0

package organizations

import (
"github.com/spf13/cobra"

"github.com/ory/cli/cmd/cloudx/client"
"github.com/ory/x/cmdx"
)

func NewListOrganizationsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "organizations",
Args: cobra.NoArgs,
Short: "List your Ory Network organizations",
RunE: func(cmd *cobra.Command, args []string) error {
h, err := client.NewCommandHelper(cmd)
if err != nil {
return err
}

id, err := client.ProjectOrDefault(cmd, h)
if err != nil {
return cmdx.PrintOpenAPIError(cmd, err)
}

organizations, err := h.ListOrganizations(id)
if err != nil {
return cmdx.PrintOpenAPIError(cmd, err)
}

cmdx.PrintTable(cmd, &outputOrganizations{organizations})
return nil
},
}

client.RegisterProjectFlag(cmd.Flags())
cmdx.RegisterFormatFlags(cmd.Flags())
return cmd
}
62 changes: 62 additions & 0 deletions cmd/cloudx/organizations/organizations_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0

package organizations_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/ory/cli/cmd/cloudx/client"
"github.com/ory/cli/cmd/cloudx/testhelpers"
"github.com/ory/x/cmdx"
)

var (
project, defaultEmail, defaultPassword string
defaultCmd *cmdx.CommandExecuter
)

func TestMain(m *testing.M) {
_, defaultEmail, defaultPassword, _, project, defaultCmd = testhelpers.CreateDefaultAssets()
testhelpers.RunAgainstStaging(m)
}

func TestNoUnauthenticated(t *testing.T) {
t.Parallel()
cases := []struct {
verb string
noun string
arg string
}{
{verb: "create", noun: "organization", arg: "my-org"},
{verb: "ls", noun: "organizations"},
{verb: "list", noun: "organizations"},
{verb: "delete", noun: "organization", arg: "some-uuid"},
}

for _, tc := range cases {
t.Run("verb="+tc.verb, func(t *testing.T) {
configDir := testhelpers.NewConfigDir(t)
cmd := testhelpers.ConfigAwareCmd(configDir)
args := []string{tc.verb, tc.noun, "--quiet", "--project", project}
if tc.arg != "" {
args = append(args, tc.arg)
}
_, _, err := cmd.Exec(nil, args...)
require.ErrorIsf(t, err, client.ErrNoConfigQuiet, "got error: %v", err)
})
}
}

func TestCRUD(t *testing.T) {
t.Parallel()

defaultCmd.ExecNoErr(t, "use", project)

// List organizations: Empty
out := defaultCmd.ExecNoErr(t, "list", "organizations", "--format=json")
assert.Equal(t, "[]\n", out)
}
Loading

0 comments on commit d6be6da

Please sign in to comment.