Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
[985][2647] Manage Secure and Non-Secure Template Sources (#137)
Browse files Browse the repository at this point in the history
Signed-off-by: Keith Chong <[email protected]>
  • Loading branch information
keithchong authored Jun 24, 2020
1 parent d4d6a25 commit 1aaeadd
Show file tree
Hide file tree
Showing 43 changed files with 3,271 additions and 101 deletions.
35 changes: 17 additions & 18 deletions dev/src/main/java/org/eclipse/codewind/intellij/core/HttpUtil.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2018, 2019 IBM Corporation and others.
* Copyright (c) 2018, 2020 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand All @@ -12,7 +12,6 @@
package org.eclipse.codewind.intellij.core;

import okhttp3.*;
import org.eclipse.codewind.intellij.core.cli.AuthToken;
import org.json.JSONArray;
import org.json.JSONObject;

Expand Down Expand Up @@ -130,55 +129,55 @@ public static HttpResult get(URI uri) throws IOException {
return get(uri, null);
}

public static HttpResult get(URI uri, AuthToken auth) throws IOException {
public static HttpResult get(URI uri, IAuthInfo auth) throws IOException {
return sendRequest("GET", uri, auth, null);
}

public static HttpResult get(URI uri, AuthToken auth, int connectTimeoutMS, int readTimeoutMS) throws IOException {
public static HttpResult get(URI uri, IAuthInfo auth, int connectTimeoutMS, int readTimeoutMS) throws IOException {
return sendRequest("GET", uri, auth, null, connectTimeoutMS, readTimeoutMS);
}

public static HttpResult post(URI uri, AuthToken auth, JSONObject payload) throws IOException {
public static HttpResult post(URI uri, IAuthInfo auth, JSONObject payload) throws IOException {
return sendRequest("POST", uri, auth, payload, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS);
}

public static HttpResult post(URI uri, AuthToken auth, JSONObject payload, int readTimeoutSeconds) throws IOException {
public static HttpResult post(URI uri, IAuthInfo auth, JSONObject payload, int readTimeoutSeconds) throws IOException {
return sendRequest("POST", uri, auth, payload, DEFAULT_CONNECT_TIMEOUT_MS, readTimeoutSeconds * 1000);
}

public static HttpResult post(URI uri, AuthToken auth) throws IOException {
public static HttpResult post(URI uri, IAuthInfo auth) throws IOException {
return sendRequest("POST", uri, auth, null);
}

public static HttpResult put(URI uri, AuthToken auth) throws IOException {
public static HttpResult put(URI uri, IAuthInfo auth) throws IOException {
return sendRequest("PUT", uri, auth, null);
}

public static HttpResult put(URI uri, AuthToken auth, JSONObject payload) throws IOException {
public static HttpResult put(URI uri, IAuthInfo auth, JSONObject payload) throws IOException {
return sendRequest("PUT", uri, auth, payload, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS);
}

public static HttpResult put(URI uri, AuthToken auth, JSONObject payload, int readTimoutSeconds) throws IOException {
public static HttpResult put(URI uri, IAuthInfo auth, JSONObject payload, int readTimoutSeconds) throws IOException {
return sendRequest("PUT", uri, auth, payload, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS);
}

public static HttpResult head(URI uri, AuthToken auth) throws IOException {
public static HttpResult head(URI uri, IAuthInfo auth) throws IOException {
return sendRequest("HEAD", uri, auth, null);
}

public static HttpResult delete(URI uri, AuthToken auth) throws IOException {
public static HttpResult delete(URI uri, IAuthInfo auth) throws IOException {
return delete(uri, auth, null);
}

public static HttpResult delete(URI uri, AuthToken auth, JSONObject payload) throws IOException {
public static HttpResult delete(URI uri, IAuthInfo auth, JSONObject payload) throws IOException {
return sendRequest("DELETE", uri, auth, payload);
}

public static HttpResult sendRequest(String method, URI uri, AuthToken auth, JSONObject payload) throws IOException {
public static HttpResult sendRequest(String method, URI uri, IAuthInfo auth, JSONObject payload) throws IOException {
return sendRequest(method, uri, auth, payload, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS);
}

public static HttpResult sendRequest(String method, URI uri, AuthToken auth, JSONObject payload, int connectTimeoutMS, int readTimeoutMS) throws IOException {
public static HttpResult sendRequest(String method, URI uri, IAuthInfo auth, JSONObject payload, int connectTimeoutMS, int readTimeoutMS) throws IOException {
HttpURLConnection connection = null;
if (payload != null) {
Logger.log("Making a " + method + " request on " + uri + " with payload: " + payload.toString());
Expand Down Expand Up @@ -210,11 +209,11 @@ public static HttpResult sendRequest(String method, URI uri, AuthToken auth, JSO
}
}

private static void addAuthorization(HttpURLConnection connection, AuthToken auth) {
if (sslContext == null || auth == null || auth.getToken() == null || auth.getTokenType() == null || !(connection instanceof HttpsURLConnection)) {
private static void addAuthorization(HttpURLConnection connection, IAuthInfo auth) {
if (sslContext == null || auth == null || !auth.isValid() || !(connection instanceof HttpsURLConnection)) {
return;
}
connection.setRequestProperty("Authorization", auth.getTokenType() + " " + auth.getToken());
connection.setRequestProperty("Authorization", auth.getHttpAuthorization());
((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.getSocketFactory());
((HttpsURLConnection)connection).setHostnameVerifier(hostnameVerifier);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*******************************************************************************
* Copyright (c) 2020 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.codewind.intellij.core;

public interface IAuthInfo {
public boolean isValid();
public String getHttpAuthorization();
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@

package org.eclipse.codewind.intellij.core.cli;

import org.eclipse.codewind.intellij.core.IAuthInfo;
import org.eclipse.codewind.intellij.core.connection.JSONObjectResult;
import org.json.JSONObject;

public class AuthToken extends JSONObjectResult {
public class AuthToken extends JSONObjectResult implements IAuthInfo {

private static final String ACCESS_TOKEN_KEY = "access_token";
private static final String TOKEN_TYPE_KEY = "token_type";
Expand All @@ -31,4 +32,15 @@ public String getTokenType() {
return getString(TOKEN_TYPE_KEY);
}

@Override
public boolean isValid() {
return getToken() != null && getTokenType() != null;
}

@Override
public String getHttpAuthorization() {
return getTokenType() + " " + getToken();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public static ProcessBuilder createCWCTLProcess(String[] globalOptions, String[]
addOptions(cmdList, cmd);
addOptions(cmdList, options);
addOptions(cmdList, args);
Logger.log(cmdList.stream().collect(Collectors.joining(" ")));
// Logger.log(cmdList.stream().collect(Collectors.joining(" ")));
String[] command = cmdList.toArray(new String[cmdList.size()]);
ProcessBuilder builder = new ProcessBuilder(command);
if (PlatformUtil.getOS() == PlatformUtil.OperatingSystem.MAC) {
Expand Down Expand Up @@ -182,13 +182,13 @@ public static void checkResult(String[] command, ProcessResult result, boolean c
// system output.
// Expected format:
// {"error":"con_not_found","error_description":"Connection AGALJKAFD not found"}
String commandName = command.length > 0 ? command[0] : ""; // cwctl with no parameter;
try {
if (result.getOutput() != null && !result.getOutput().isEmpty()) {
JSONObject obj = new JSONObject(result.getOutput());
if (obj.has(ERROR_KEY) && obj.has(ERROR_DESCRIPTION_KEY)) {
String msg = String.format("The cwctl '%s' command failed with error: %s", CoreUtil.formatString(command, " "), obj.getString(ERROR_DESCRIPTION_KEY)); //$NON-NLS-1$
Logger.logWarning(msg);
throw new IOException(obj.getString(ERROR_DESCRIPTION_KEY));
String msg = String.format("The cwctl '%s' command failed with error: %s", commandName, obj.getString(ERROR_DESCRIPTION_KEY)); //$NON-NLS-1$
throw new CLIException(obj.getString(ERROR_KEY), obj.getString(ERROR_DESCRIPTION_KEY));
}
}
} catch (JSONException e) {
Expand All @@ -199,19 +199,27 @@ public static void checkResult(String[] command, ProcessResult result, boolean c
String msg;
String error = result.getError() != null && !result.getError().isEmpty() ? result.getError() : result.getOutput();
if (error == null || error.isEmpty()) {
msg = String.format("The cwctl '%s' command exited with return code %d", CoreUtil.formatString(command, " "), result.getExitValue()); //$NON-NLS-1$
msg = String.format("The cwctl '%s' command exited with return code %d", commandName, result.getExitValue());
} else {
msg = String.format("The cwctl '%s' command exited with return code %d and error: %s", CoreUtil.formatString(command, " "), result.getExitValue(), error); //$NON-NLS-1$
msg = String.format("The cwctl '%s' command exited with return code %d and error: %s", commandName, result.getExitValue(), error);
}
Logger.logWarning(msg);
throw new IOException(msg);
} else if (checkOutput && (result.getOutput() == null || result.getOutput().isEmpty())) {
String msg = String.format("The cwctl '%s' command exited with return code 0 but the output was empty", CoreUtil.formatString(command, " ")); //$NON-NLS-1$
Logger.logWarning(msg);
String msg = String.format("The cwctl '%s' command exited with return code 0 but the output was empty", commandName); //$NON-NLS-1$
throw new IOException(msg);
}

Logger.log(String.format("Result of the cwctl '%s' command: \n%s", CoreUtil.formatString(command, " "), Optional.ofNullable(result.getOutput()).orElse("<empty>")));
}

@SuppressWarnings("serial")
public static class CLIException extends IOException {

public final String errorId;
public final String errorMsg;

public CLIException(String errorId, String errorMsg) {
super(errorMsg);
this.errorId = errorId;
this.errorMsg = errorMsg;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ public class TemplateUtil {
private static final String URL_OPTION = "--url";
private static final String NAME_OPTION = "--name";
private static final String DESCRIPTION_OPTION = "--description";
private static final String USERNAME_OPTION = "--username";
private static final String PASSWORD_OPTION = "--password";
private static final String PERSONAL_ACCESS_TOKEN_OPTION = "--personalAccessToken";


public static List<ProjectTemplateInfo> listTemplates(boolean enabledOnly, String conid, ProgressIndicator monitor) throws IOException, JSONException, TimeoutException {
monitor.setIndeterminate(true);
Expand Down Expand Up @@ -84,7 +88,29 @@ public static List<RepositoryInfo> listTemplateSources(String conid, ProgressInd
}
}
}


public static void addTemplateSource(String url, String username, String password, String accessToken, String name, String description, String conid, ProgressIndicator monitor) throws IOException, JSONException, TimeoutException {
List<String> options = new ArrayList<String>();
options.add(URL_OPTION);
options.add(url);
if (username != null && password != null) {
options.add(USERNAME_OPTION);
options.add(username);
options.add(PASSWORD_OPTION);
options.add(password);
} else if (accessToken != null) {
options.add(PERSONAL_ACCESS_TOKEN_OPTION);
options.add(accessToken);
}
options.add(NAME_OPTION);
options.add(name);
options.add(DESCRIPTION_OPTION);
options.add(description);
options.add(CLIUtil.CON_ID_OPTION);
options.add(conid);
runTemplateSourceCmd(REPO_ADD_CMD, options.toArray(new String[options.size()]), null, monitor);
}

public static void addTemplateSource(String url, String name, String description, String conid, ProgressIndicator monitor) throws IOException, JSONException, TimeoutException {
runTemplateSourceCmd(REPO_ADD_CMD, new String[] {URL_OPTION, url, NAME_OPTION, name, DESCRIPTION_OPTION, description, CLIUtil.CON_ID_OPTION, conid}, null, monitor);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import org.json.JSONException;
import org.json.JSONObject;

public abstract class JSONObjectResult {
public class JSONObjectResult {

protected final JSONObject result;
protected final String type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class CodewindToolWindow extends JBPanel<CodewindToolWindow> {
private final AnAction restartDebugModeAction;
private final AnAction attachDebuggerAction;
private final AnAction openShellAction;
private final AnAction manageReposAction;

private final AnAction newProjectAction;

Expand Down Expand Up @@ -113,6 +114,7 @@ public CodewindToolWindow() {
restartDebugModeAction = new RestartDebugModeAction();
attachDebuggerAction = new AttachDebuggerAction();
openShellAction = new OpenContainerShellAction();
manageReposAction = new ManageReposAction();

newProjectAction = new NewCodewindProjectAction();

Expand Down Expand Up @@ -275,6 +277,8 @@ private void handleLocalConnectionPopup(LocalConnection connection, Component co
actions.add(newProjectAction);
actions.add(addExistingProjectAction);
actions.addSeparator();
actions.add(manageReposAction);
actions.addSeparator();
InstallStatus status = CodewindManager.getManager().getInstallStatus();
if (status.isInstalled()) {
// a supported version of Codewind is installed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class IconCache {
public static final String ICONS_THEMELESS_PROJECT_TYPES_SPRING_SVG = "/icons/themeless/project-types/spring.svg";
public static final String ICONS_THEMELESS_PROJECT_TYPES_SWIFT_SVG = "/icons/themeless/project-types/swift.svg";
public static final String ICONS_CODEWIND_13PX_SVG = "/META-INF/pluginIcon13x13.svg";
public static final String ICONS_CODEWIND_BANNER_PNG = "/icons/codewindBanner.png";

private static final Map<String, Icon> iconCache = new HashMap<>();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*******************************************************************************
* Copyright (c) 2020 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.codewind.intellij.ui.actions;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.ui.treeStructure.Tree;
import org.eclipse.codewind.intellij.core.CoreUtil;
import org.eclipse.codewind.intellij.core.Logger;
import org.eclipse.codewind.intellij.core.cli.TemplateUtil;
import org.eclipse.codewind.intellij.core.connection.CodewindConnection;
import org.eclipse.codewind.intellij.core.connection.RepositoryInfo;
import org.eclipse.codewind.intellij.ui.templates.RepositoryManagementDialog;
import org.jetbrains.annotations.NotNull;

import javax.swing.tree.TreePath;
import java.util.List;

import static com.intellij.openapi.actionSystem.PlatformDataKeys.CONTEXT_COMPONENT;
import static org.eclipse.codewind.intellij.ui.messages.CodewindUIBundle.message;


public class ManageReposAction extends AnAction {

public ManageReposAction() {
super(message("RepoMgmtActionLabel"));
}

@Override
public void update(@NotNull AnActionEvent e) {
super.update(e);
CodewindConnection connection = getSelection(e);
e.getPresentation().setEnabled(connection != null && connection.isConnected());
}

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
CodewindConnection connection = getSelection(e);
final List<RepositoryInfo>[] repoListArray = new List[1];
try {
ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
try {
ProgressIndicator mon = new EmptyProgressIndicator();
repoListArray[0] = TemplateUtil.listTemplateSources(connection.getConid(), mon);
} catch (Exception e1) {
Logger.logWarning("An error occurred trying to get the template sources for: " + connection.getName() + ": " + e1.getMessage());
}
}, message("RepoListTask", "connection"), false, e.getProject());
RepositoryManagementDialog dialog = new RepositoryManagementDialog(e.getProject(), connection, repoListArray[0]);
// Init must be done after
dialog.initForm();
boolean rc = dialog.showAndGet();
if (rc) {
dialog.updateRepos();
}
} catch (Exception ex) {
CoreUtil.openDialog(true, message("RepoListErrorTitle"), message("RepoListErrorMsg", ex));
}
}

private CodewindConnection getSelection(@NotNull AnActionEvent e) {
Object data = e.getData(CONTEXT_COMPONENT);
if (!(data instanceof Tree)) {
Logger.logDebug("Unrecognized component for : " + data);
return null;
}
Tree tree = (Tree) data;
TreePath treePath = tree.getSelectionPath();
if (treePath == null) {
Logger.logDebug("No selection path for ManageReposAction: " + tree);
return null;
}
Object node = treePath.getLastPathComponent();
if (!(node instanceof CodewindConnection)) {
return null;
}
return (CodewindConnection) node;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,15 @@ public abstract class AbstractCodewindDialogWrapper extends DialogWrapper {

private String helpUrl;

/**
* Note: init() should be called after the dialog wrapper has been instantiated
*
* @param project
* @param title
* @param helpUrl
*/
public AbstractCodewindDialogWrapper(Project project, String title, String helpUrl) {
super(project,true); // Can use current dialog window as parent for other child dialogs
init();
setTitle(title);
this.helpUrl = helpUrl;
}
Expand Down
Loading

0 comments on commit 1aaeadd

Please sign in to comment.