Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/java/com/streamx/cli/commands/StreamxCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.streamx.cli.commands.auth.AuthCommand;
import com.streamx.cli.commands.completion.CompleteClusterIdsCommand;
import com.streamx.cli.commands.completion.CompleteContextNamesCommand;
import com.streamx.cli.commands.completion.CompleteInvitedEmailsCommand;
import com.streamx.cli.commands.completion.CompleteNonDefaultTemplateIdsCommand;
import com.streamx.cli.commands.completion.CompleteOrgIdsCommand;
import com.streamx.cli.commands.completion.CompleteOrgMemberIdsCommand;
import com.streamx.cli.commands.completion.CompleteRegisteredTemplateIdsCommand;
import com.streamx.cli.commands.completion.CompleteSettingsKeysCommand;
import com.streamx.cli.commands.completion.CompleteSettingsSetKeysCommand;
Expand Down Expand Up @@ -38,6 +40,8 @@
CompleteSettingsSetKeysCommand.class,
CompleteContextNamesCommand.class,
CompleteOrgIdsCommand.class,
CompleteOrgMemberIdsCommand.class,
CompleteInvitedEmailsCommand.class,
CompleteClusterIdsCommand.class
}
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.streamx.cli.commands.completion;

import com.streamx.cli.framework.AbstractCommand;
import com.streamx.cli.framework.CommandResult;
import com.streamx.cli.platform.OrganizationInvitationsApi;
import com.streamx.cli.platform.PlatformClients;
import com.streamx.cli.platform.PlatformContext;
import com.streamx.cli.platform.generated.model.Invitation;
import java.util.List;
import java.util.Objects;
import picocli.CommandLine;

@CommandLine.Command(
name = "__complete-invited-emails",
hidden = true,
header = "Internal: list invited email addresses of an organization for shell completion"
)
public class CompleteInvitedEmailsCommand extends AbstractCommand<List<String>> {

@CommandLine.Parameters(index = "0", arity = "0..1", description = "Organization ID")
public String orgId;

@Override
public CommandResult<List<String>> runCommand() {
String org = orgId == null || orgId.isBlank() || orgId.startsWith("-")
? PlatformContext.effectiveOrg()
: orgId;
if (org == null) {
return new CommandResult<>(List.of());
}
try (PlatformClients client = PlatformClients.completion()) {
return new CommandResult<>(new OrganizationInvitationsApi(client).list(org).stream()
.map(Invitation::getEmail)
.filter(Objects::nonNull)
.sorted()
.toList());
} catch (RuntimeException anyFailure) {
return new CommandResult<>(List.of());
}
}

@Override
public String getTextOutput(CommandResult<List<String>> result) {
return String.join("\n", result.getData());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.streamx.cli.commands.completion;

import com.streamx.cli.framework.AbstractCommand;
import com.streamx.cli.framework.CommandResult;
import com.streamx.cli.platform.OrganizationUsersApi;
import com.streamx.cli.platform.PlatformClients;
import com.streamx.cli.platform.PlatformContext;
import com.streamx.cli.platform.generated.model.User;
import java.util.List;
import java.util.Objects;
import picocli.CommandLine;

@CommandLine.Command(
name = "__complete-org-member-ids",
hidden = true,
header = "Internal: list ACTIVE member IDs of an organization for shell completion"
)
public class CompleteOrgMemberIdsCommand extends AbstractCommand<List<String>> {

@CommandLine.Parameters(index = "0", arity = "0..1", description = "Organization ID")
public String orgId;

@Override
public CommandResult<List<String>> runCommand() {
String org = orgId == null || orgId.isBlank() || orgId.startsWith("-")
? PlatformContext.effectiveOrg()
: orgId;
if (org == null) {
return new CommandResult<>(List.of());
}
try (PlatformClients client = PlatformClients.completion()) {
return new CommandResult<>(new OrganizationUsersApi(client).list(org).stream()
.filter(user -> user.getStatus() == User.StatusEnum.ACTIVE)
.map(User::getId)
.filter(Objects::nonNull)
.sorted()
.toList());
} catch (RuntimeException anyFailure) {
return new CommandResult<>(List.of());
}
}

@Override
public String getTextOutput(CommandResult<List<String>> result) {
return String.join("\n", result.getData());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import com.streamx.cli.commands.settings.eventtemplates.TemplateIdCompletionCandidates;
import com.streamx.cli.config.ContextNameCompletionCandidates;
import com.streamx.cli.platform.ClusterIdCompletionCandidates;
import com.streamx.cli.platform.InvitedEmailCompletionCandidates;
import com.streamx.cli.platform.OrgIdCompletionCandidates;
import com.streamx.cli.platform.OrgMemberIdCompletionCandidates;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
Expand Down Expand Up @@ -221,6 +223,12 @@ private static String getCompletionAction(
if (completionCandidates instanceof OrgIdCompletionCandidates) {
return "($(streamx __complete-org-ids 2>/dev/null))";
}
if (completionCandidates instanceof OrgMemberIdCompletionCandidates) {
return "($(streamx __complete-org-member-ids " + ORG_FROM_WORDS + " 2>/dev/null))";
}
if (completionCandidates instanceof InvitedEmailCompletionCandidates) {
return "($(streamx __complete-invited-emails " + ORG_FROM_WORDS + " 2>/dev/null))";
}
if (completionCandidates instanceof ClusterIdCompletionCandidates) {
return "($(streamx __complete-cluster-ids " + ORG_FROM_WORDS + " 2>/dev/null))";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import com.streamx.cli.commands.org.create.CreateCommand;
import com.streamx.cli.commands.org.delete.DeleteCommand;
import com.streamx.cli.commands.org.get.GetCommand;
import com.streamx.cli.commands.org.invitations.InvitationsCommand;
import com.streamx.cli.commands.org.list.ListCommand;
import com.streamx.cli.commands.org.members.MembersCommand;
import com.streamx.cli.framework.AbstractCommandGroup;
import picocli.CommandLine;

Expand All @@ -16,7 +18,9 @@
CreateCommand.class,
DeleteCommand.class,
GetCommand.class,
ListCommand.class
InvitationsCommand.class,
ListCommand.class,
MembersCommand.class
}
)
public class OrgCommand extends AbstractCommandGroup {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.streamx.cli.commands.org.invitations;

import com.streamx.cli.commands.org.invitations.accept.AcceptCommand;
import com.streamx.cli.commands.org.invitations.cancel.CancelCommand;
import com.streamx.cli.commands.org.invitations.create.CreateCommand;
import com.streamx.cli.commands.org.invitations.list.ListCommand;
import com.streamx.cli.framework.AbstractCommandGroup;
import picocli.CommandLine;

@CommandLine.Command(
name = "invitations",
header = "Manage organization invitations",
subcommands = {
AcceptCommand.class,
CancelCommand.class,
CreateCommand.class,
ListCommand.class
}
)
public class InvitationsCommand extends AbstractCommandGroup {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.streamx.cli.commands.org.invitations.accept;

import static com.streamx.cli.i18n.MessageProvider.msg;

import com.streamx.cli.framework.AbstractSilentCommand;
import com.streamx.cli.framework.CliException;
import com.streamx.cli.framework.CommandResult;
import com.streamx.cli.platform.OrgIdCompletionCandidates;
import com.streamx.cli.platform.OrganizationInvitationsApi;
import com.streamx.cli.platform.PlatformClients;
import com.streamx.cli.platform.PlatformContext;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import picocli.CommandLine;

@CommandLine.Command(
name = "accept",
header = "Accept an invitation to an organization",
description = {
"The invitation token is read from standard input, or from --token-file.",
"It is not taken as an argument: that would leave a credential in the shell",
"history and expose it to anyone listing processes.",
"",
" streamx org invitations accept --org <orgId> --token-file ./token.txt",
" pbpaste | streamx org invitations accept --org <orgId>"
}
)
public class AcceptCommand extends AbstractSilentCommand {

@CommandLine.Option(
names = "--org",
paramLabel = "<orgId>",
description = "Organization ID (defaults to the current organization)",
completionCandidates = OrgIdCompletionCandidates.class
)
public String orgId;

@CommandLine.Option(
names = "--token-file",
description = "File holding the invitation token; defaults to reading standard input"
)
public Path tokenFile;

@Override
public CommandResult<Void> runCommand() {
orgId = PlatformContext.requireOrg(orgId);
String token = readToken();

try (PlatformClients client = PlatformClients.fromConfig()) {
new OrganizationInvitationsApi(client).accept(orgId, token);
}
System.out.println(msg.orgInvitationAccepted());
return new CommandResult<>(null);
}

private String readToken() {
String token;
try {
token = tokenFile != null
? Files.readString(tokenFile, StandardCharsets.UTF_8)
: new String(System.in.readAllBytes(), StandardCharsets.UTF_8);
} catch (IOException e) {
throw new CliException(msg.orgInvitationTokenRequired(), e);
}

token = token.strip();
if (token.isEmpty()) {
throw new CliException(msg.orgInvitationTokenRequired());
}
return token;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.streamx.cli.commands.org.invitations.cancel;

import static com.streamx.cli.i18n.MessageProvider.msg;

import com.streamx.cli.framework.AbstractSilentCommand;
import com.streamx.cli.framework.CommandResult;
import com.streamx.cli.platform.InvitedEmailCompletionCandidates;
import com.streamx.cli.platform.OrgIdCompletionCandidates;
import com.streamx.cli.platform.OrganizationInvitationsApi;
import com.streamx.cli.platform.PlatformClients;
import com.streamx.cli.platform.PlatformContext;
import picocli.CommandLine;

@CommandLine.Command(
name = "cancel",
header = "Cancel a pending organization invitation"
)
public class CancelCommand extends AbstractSilentCommand {

@CommandLine.Option(
names = "--org",
paramLabel = "<orgId>",
description = "Organization ID (defaults to the current organization)",
completionCandidates = OrgIdCompletionCandidates.class
)
public String orgId;

@CommandLine.Parameters(
index = "0",
description = "Invited email address",
completionCandidates = InvitedEmailCompletionCandidates.class
)
public String email;

@Override
public CommandResult<Void> runCommand() {
orgId = PlatformContext.requireOrg(orgId);
try (PlatformClients client = PlatformClients.fromConfig()) {
new OrganizationInvitationsApi(client).cancel(orgId, email);
}
System.out.println(msg.orgInvitationCancelled(email));
return new CommandResult<>(null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.streamx.cli.commands.org.invitations.create;

import static com.streamx.cli.i18n.MessageProvider.msg;

import com.streamx.cli.framework.AbstractSilentCommand;
import com.streamx.cli.framework.CommandResult;
import com.streamx.cli.platform.OrgIdCompletionCandidates;
import com.streamx.cli.platform.OrganizationInvitationsApi;
import com.streamx.cli.platform.PlatformClients;
import com.streamx.cli.platform.PlatformContext;
import com.streamx.cli.platform.Roles;
import picocli.CommandLine;

@CommandLine.Command(
name = "create",
header = "Invite a user to an organization"
)
public class CreateCommand extends AbstractSilentCommand {

@CommandLine.Option(
names = "--org",
paramLabel = "<orgId>",
description = "Organization ID (defaults to the current organization)",
completionCandidates = OrgIdCompletionCandidates.class
)
public String orgId;

@CommandLine.Parameters(
index = "0",
description = "Email address to invite"
)
public String email;

@CommandLine.Option(
names = {"-r", "--role"},
required = true,
description = "Role to grant: ${COMPLETION-CANDIDATES}",
completionCandidates = Roles.class
)
public String role;

@Override
public CommandResult<Void> runCommand() {
orgId = PlatformContext.requireOrg(orgId);
try (PlatformClients client = PlatformClients.fromConfig()) {
new OrganizationInvitationsApi(client).create(orgId, email, role);
}
System.out.println(msg.orgInvitationCreated(email, role));
return new CommandResult<>(null);
}
}
Loading
Loading