Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: list server stores #13

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
29 changes: 0 additions & 29 deletions src/main/java/dev/openfga/intellijplugin/Notifier.java

This file was deleted.

2 changes: 2 additions & 0 deletions src/main/java/dev/openfga/intellijplugin/OpenFGAIcons.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
public interface OpenFGAIcons {

Icon FILE = IconLoader.getIcon("/icons/openfga-color-transparent-16x16.svg", OpenFGAIcons.class);
Icon SERVER_NODE = IconLoader.getIcon("/icons/openfga-color-transparent-16x16.svg", OpenFGAIcons.class);
Icon STORE_NODE = IconLoader.getIcon("/icons/openfga-store.svg", OpenFGAIcons.class);
Icon TOOL_WINDOW = IconLoader.getIcon("/icons/tool-window.svg", OpenFGAIcons.class);

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
package dev.openfga.intellijplugin.cli.tasks;

import dev.openfga.intellijplugin.Notifier;
import dev.openfga.intellijplugin.cli.CliProcess;
import dev.openfga.intellijplugin.cli.CliProcessTask;
import dev.openfga.intellijplugin.cli.CliTaskException;
import dev.openfga.intellijplugin.settings.OpenFGASettingsState;
import com.intellij.codeInsight.actions.ReformatCodeProcessor;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
Expand All @@ -17,6 +12,12 @@
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import dev.openfga.intellijplugin.cli.CliProcess;
import dev.openfga.intellijplugin.cli.CliProcessTask;
import dev.openfga.intellijplugin.cli.CliTaskException;
import dev.openfga.intellijplugin.settings.OpenFGASettingsState;
import dev.openfga.intellijplugin.util.notifications.Notifier;
import dev.openfga.intellijplugin.util.notifications.ProjectNotifier;
import org.jetbrains.annotations.NotNull;

import java.io.File;
Expand All @@ -32,6 +33,7 @@ public class DslToJsonTask extends Task.Backgroundable implements CliProcessTask
private final PsiFile dslFile;
private final Path targetPath;
private final CliProcess process;
private final Notifier notifier;

public static Optional<DslToJsonTask> create(@NotNull PsiFile dslFile, @NotNull Path dslFilePath) {
var targetName = computeJsonGeneratedFileName(dslFile);
Expand All @@ -52,6 +54,7 @@ private DslToJsonTask(@NotNull PsiFile dslFile, @NotNull Path dslFilePath, @NotN
super(dslFile.getProject(), "Generating json model for " + dslFile.getName(), true);
this.dslFile = dslFile;
this.targetPath = targetPath;
notifier = new ProjectNotifier(dslFile.getProject());

process = new CliProcess(
OpenFGASettingsState.getInstance().requireCli(),
Expand All @@ -74,7 +77,7 @@ public void run(@NotNull ProgressIndicator indicator) {
try {
process.start(indicator, this);
} catch (CliTaskException e) {
notifyError(dslFile, e.getMessage());
notifier.notifyError("Error generating json authorization model", e);
}
}

Expand All @@ -84,11 +87,11 @@ public void onCancel() {
}

@Override
public Void onSuccess(File stdOutFile, File stdErrFile) throws IOException, CliTaskException {
public Void onSuccess(File stdOutFile, File stdErrFile) throws IOException {
Files.copy(stdOutFile.toPath(), targetPath, StandardCopyOption.REPLACE_EXISTING);
ApplicationManager.getApplication().invokeLater(
() -> show(new GeneratedFile(dslFile.getProject(), targetPath)),
ModalityState.NON_MODAL);
ModalityState.nonModal());
return null;
}

Expand All @@ -102,10 +105,6 @@ public CliTaskException onFailure(File stdOutFile, File stdErrFile) {
}
}

private static void notifyError(PsiFile psiFile, String message) {
Notifier.notifyError(psiFile.getProject(), "Error generating json authorization model", message);
}

private void show(GeneratedFile generatedFile) {
generatedFile.refreshInTreeView();
generatedFile.openInEditor();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package dev.openfga.intellijplugin.sdk;

import dev.openfga.intellijplugin.servers.model.Server;
import dev.openfga.intellijplugin.servers.util.ServersUtil;
import dev.openfga.sdk.api.model.Store;
import dev.openfga.sdk.errors.FgaInvalidParameterException;

import java.util.List;
import java.util.concurrent.CompletableFuture;

public interface OpenFgaApiClient {

CompletableFuture<List<Store>> listStores();

static OpenFgaApiClient ForServer(Server server) {
try {
var openFgaClient = ServersUtil.createClient(server);
return new SdkClient(openFgaClient);
} catch (FgaInvalidParameterException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
52 changes: 52 additions & 0 deletions src/main/java/dev/openfga/intellijplugin/sdk/SdkClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package dev.openfga.intellijplugin.sdk;

import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.client.model.ClientListStoresResponse;
import dev.openfga.sdk.api.configuration.ClientListStoresOptions;
import dev.openfga.sdk.api.model.Store;
import dev.openfga.sdk.errors.FgaInvalidParameterException;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;

class SdkClient implements OpenFgaApiClient {

private static final int STORES_PAGE_SIZE = 50;

private final OpenFgaClient fgaClient;

public SdkClient(OpenFgaClient fgaClient) {
this.fgaClient = fgaClient;
}

@Override
public CompletableFuture<List<Store>> listStores() {
return listStores(new ClientListStoresOptions().pageSize(STORES_PAGE_SIZE));
}

private CompletableFuture<List<Store>> listStores(ClientListStoresOptions options) {
try {
return fgaClient.listStores(options).thenCompose(this::listNextStores);
} catch (FgaInvalidParameterException e) {
throw new RuntimeException(e.getMessage(), e);
}
}

private CompletableFuture<List<Store>> listNextStores(ClientListStoresResponse response) {
var continuationToken = response.getContinuationToken();
if (continuationToken == null || continuationToken.isBlank()) {
return CompletableFuture.completedFuture(response.getStores());
}

try {
return fgaClient
.listStores(new ClientListStoresOptions().pageSize(STORES_PAGE_SIZE).continuationToken(continuationToken))
.thenCompose((ClientListStoresResponse nextResponse) ->
listNextStores(nextResponse).thenApply(nextStores -> Stream.concat(response.getStores().stream(), nextStores.stream()).toList()));
} catch (FgaInvalidParameterException e) {
throw new RuntimeException(e.getMessage(), e);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ public record Oidc(
String clientSecret,
String scope
) {
public static final Oidc EMPTY = new Oidc("", "", "", "");
}
114 changes: 44 additions & 70 deletions src/main/java/dev/openfga/intellijplugin/servers/model/Server.java
Original file line number Diff line number Diff line change
@@ -1,62 +1,28 @@
package dev.openfga.intellijplugin.servers.model;

import com.intellij.credentialStore.CredentialAttributes;
import com.intellij.credentialStore.CredentialAttributesKt;
import com.intellij.credentialStore.Credentials;
import com.intellij.ide.passwordSafe.PasswordSafe;
import org.jetbrains.annotations.NotNull;

import java.util.Objects;
import java.util.UUID;

public class Server {
public final class Server {

private String id;
private String name;
private String url;
private AuthenticationMethod authenticationMethod = AuthenticationMethod.NONE;
private String apiToken;
private Oidc oidc = Oidc.EMPTY;

public Server() {
this("new server");
}

public Server(String name) {
this.id = UUID.randomUUID().toString();
this.name = name;
}

public String loadUrl() {
var credentials = getCredentials(CredentialKey.URL);
if (credentials == null) {
return "";
}
return credentials.getPasswordAsString();
}

public void storeUrl(String url) {
var attributes = getCredentialAttributes(CredentialKey.URL);
PasswordSafe.getInstance().set(attributes, new Credentials(id, url));
}

public String loadApiToken() {
var credentials = getCredentials(CredentialKey.API_TOKEN);
if (credentials == null) {
return "";
}
return credentials.getPasswordAsString();
}

public void storeApiToken(String token) {
var attributes = getCredentialAttributes(CredentialKey.API_TOKEN);
PasswordSafe.getInstance().set(attributes, new Credentials(id, token));
}

public Credentials getCredentials(String keySuffix) {
CredentialAttributes attributes = getCredentialAttributes(keySuffix);
return PasswordSafe.getInstance().get(attributes);
}

@NotNull
private CredentialAttributes getCredentialAttributes(String keySuffix) {
var key = id + "_" + keySuffix;
return new CredentialAttributes(CredentialAttributesKt.generateServiceName("OpenFGAServer", key));
public Server(String id, String name, String url, AuthenticationMethod authenticationMethod, String apiToken, Oidc oidc) {
this.id = id;
this.name = name;
this.url = url;
this.authenticationMethod = authenticationMethod;
this.apiToken = apiToken;
this.oidc = oidc;
}

public String getId() {
Expand All @@ -75,48 +41,56 @@ public void setName(String name) {
this.name = name;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

public AuthenticationMethod getAuthenticationMethod() {
return authenticationMethod;
}

public void setAuthenticationMethod(AuthenticationMethod authenticationMethod) {
if (authenticationMethod == null) {
authenticationMethod = AuthenticationMethod.NONE;
}
this.authenticationMethod = authenticationMethod;
}

public Oidc loadOidc() {
var credentials = getCredentials(CredentialKey.OIDC_CLIENT);
var clientId = credentials != null ? credentials.getUserName() : "";
var clientSecret = credentials != null ? credentials.getPasswordAsString() : "";

credentials = getCredentials(CredentialKey.OIDC_TOKEN_ENDPOINT);
var tokenEndpoint = credentials != null ? credentials.getPasswordAsString() : "";
public String getApiToken() {
return apiToken;
}

credentials = getCredentials(CredentialKey.OIDC_SCOPE);
var audience = credentials != null ? credentials.getPasswordAsString() : "";
public void setApiToken(String apiToken) {
this.apiToken = apiToken;
}

return new Oidc(tokenEndpoint, clientId, clientSecret, audience);
public Oidc getOidc() {
return oidc;
}

public void storeOidc(Oidc oidc) {
var attributes = getCredentialAttributes(CredentialKey.OIDC_CLIENT);
PasswordSafe.getInstance().set(attributes, new Credentials(oidc.clientId(), oidc.clientSecret()));
attributes = getCredentialAttributes(CredentialKey.OIDC_TOKEN_ENDPOINT);
PasswordSafe.getInstance().set(attributes, new Credentials(id, oidc.tokenEndpoint()));
attributes = getCredentialAttributes(CredentialKey.OIDC_SCOPE);
PasswordSafe.getInstance().set(attributes, new Credentials(id, oidc.scope()));
public void setOidc(Oidc oidc) {
this.oidc = oidc;
}

@Override
public String toString() {
return name;
}

private interface CredentialKey {
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
Server that = (Server) object;
return Objects.equals(id, that.id);
}

String URL = "url";
String API_TOKEN = "apiToken";
String OIDC_CLIENT = "oidc_client";
String OIDC_TOKEN_ENDPOINT = "oidc_token_endpoint";
String OIDC_SCOPE = "oidc_scope";
@Override
public int hashCode() {
return Objects.hash(id);
}
}

This file was deleted.

This file was deleted.

Loading