mylyn-gitea/io.gitea.mylyn.core/src/io/gitea/mylyn/core/ConnectionManager.java

201 lines
7.4 KiB
Java

// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.mylyn.commons.net.AuthenticationType;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import io.gitea.*;
import io.gitea.auth.*;
import io.gitea.model.*;
import io.gitea.api.UserApi;
import io.gitea.mylyn.core.exceptions.GiteaException;
import io.gitea.mylyn.core.exceptions.GiteaExceptionHandler;
import io.gitea.mylyn.core.exceptions.UnknownRepositoryException;
/**
* The ConnectionManager is a singleton that handles all GiteaConnection
* instances in a HashMap. The key in this HashMap is the URL to the Gitea
* instance constructed using a TaskRepository class.
*/
public class ConnectionManager {
/**
* The HashMap used to store all GiteaConnections
*/
private static HashMap<String, GiteaConnection> connections = new HashMap<String, GiteaConnection>();
/**
* The pattern is used to verify a ULR to a valid Gitea repository URL. group 1
* -> server including protocol (without trailing '/') group 2 ->
* repository/project path excluding potential ".git"
*
* trick: for server we are locking for any character which is not / which is
* same as looking not greedy to all character until /
*
* example: https://forge.chapril.org/gitea/mylyn-gitea.git group 1 =>
* https//forge.chapril.org group 2 => gitea/mylyn-gitea
*/
private static Pattern URLPattern = Pattern.compile("(https?://(?:[^\\/]*))/((?:.*?)/(?:[^\\/]*?))(?:\\.git)?$");
/**
* Returns the GiteaConnection for the given task repository
*
* @param repository
* @return
* @throws GiteaException
*/
static public GiteaConnection get(TaskRepository repository) throws GiteaException {
return get(repository, false);
}
/**
* Returns the GiteaConnection for the given task repository. If it fails for
* whatever reason, it returns null.
*
* @param repository
* @return
*/
static public GiteaConnection getSafe(TaskRepository repository) {
try {
return get(repository);
} catch (GiteaException e) {
return null;
}
}
/**
* Gitea connection configuration.
*/
static public ApiClient getConfiguration() {
return Configuration.getDefaultApiClient();
}
/**
* Constructs a "pseudo" URL string for the given task repository.
*
* @param repository
* @return
*/
private static String constructHash(TaskRepository repository) {
String username = repository.getCredentials(AuthenticationType.REPOSITORY).getUserName();
String password = repository.getCredentials(AuthenticationType.REPOSITORY).getPassword();
return repository.getUrl() + "?username=" + username + "&password=" + password.hashCode();
}
/**
* Validates the given task repository and returns a GiteaConnection if the task
* repository is a valid repository.
*
* @param repository
* @return
* @throws GiteaException
*/
// FIXME: redesign to limit this function to validation but not configuration
static GiteaConnection validate(TaskRepository repository) throws GiteaException {
try {
String projectPath = null;
String host = null;
// Extract host&project path from valid url
if (repository.getProperty("giteaBaseUrl").trim().length() > 0) {
host = repository.getProperty("giteaBaseUrl").trim();
if (!repository.getUrl().startsWith(host)) {
throw new GiteaException("Invalid repository URL!");
}
projectPath = repository.getUrl().replaceFirst(Matcher.quoteReplacement(host), "");
if (projectPath.startsWith("/")) {
projectPath = projectPath.substring(1);
}
} else {
Matcher matcher = URLPattern.matcher(repository.getUrl());
if (!matcher.find()) {
throw new GiteaException("Invalid Project-URL!");
}
projectPath = matcher.group(2);
host = matcher.group(1);
}
// Configure credentials
String username = repository.getCredentials(AuthenticationType.REPOSITORY).getUserName();
String password = repository.getCredentials(AuthenticationType.REPOSITORY).getPassword();
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath(GiteaConnection.apiVersion.getBasePath(host));
if (repository.getProperty("usePrivateToken") != null
&& repository.getProperty("usePrivateToken").equals("true")) {
ApiKeyAuth accessToken = (ApiKeyAuth) defaultClient.getAuthentication("AccessToken");
accessToken.setApiKey(password); // token is stored in the password field.
} else {
HttpBasicAuth basicAuth = (HttpBasicAuth) defaultClient.getAuthentication("BasicAuth");
basicAuth.setUsername(username);
basicAuth.setPassword(password);
}
// Get user related repository list
UserApi userApi = new UserApi();
List<Repository> repositories = userApi.userCurrentListRepos(0, 0);
for (Repository p : repositories) {
if (p.getFullName().equals(projectPath)) {
GiteaConnection connection = new GiteaConnection(host, p, new GiteaAttributeMapper(repository));
return connection;
}
}
// At this point the authentication was successful, but the corresponding
// repository
// could not be found! which not not occurs with Gitea.
throw new UnknownRepositoryException(projectPath);
} catch (GiteaException e) {
throw e;
} catch (Exception e) {
throw GiteaExceptionHandler.handle(e);
} catch (Error e) {
throw GiteaExceptionHandler.handle(e);
}
}
/**
* Returns a *valid* GiteaConnection, otherwise this method throws an exception.
*
* @param repository
* @param forceUpdate if true, a new GiteaConnection instance will be created,
* even if a Gitea Connection already exists for the given
* task repository
* @return connection
* @throws GiteaException
*/
static GiteaConnection get(TaskRepository repository, boolean forceUpdate) throws GiteaException {
try {
String hash = constructHash(repository);
if (connections.containsKey(hash) && !forceUpdate) {
return connections.get(hash);
} else {
GiteaConnection connection = validate(repository);
connections.put(hash, connection);
connection.update();
return connection;
}
} catch (GiteaException e) {
throw e;
} catch (Exception e) {
throw GiteaExceptionHandler.handle(e);
} catch (Error e) {
throw GiteaExceptionHandler.handle(e);
}
}
}