mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-13 08:55:44 +01:00
merge with default branch
This commit is contained in:
@@ -8,7 +8,6 @@ public abstract class RepositoryDtoToRepositoryMapper extends BaseDtoMapper {
|
||||
|
||||
@Mapping(target = "creationDate", ignore = true)
|
||||
@Mapping(target = "id", ignore = true)
|
||||
@Mapping(target = "publicReadable", ignore = true)
|
||||
@Mapping(target = "healthCheckFailures", ignore = true)
|
||||
public abstract Repository map(RepositoryDto repositoryDto, @Context String id);
|
||||
|
||||
|
||||
@@ -88,14 +88,16 @@ public class BootstrapContextListener extends GuiceServletContextListener {
|
||||
protected Injector getInjector() {
|
||||
Throwable startupError = SCMContext.getContext().getStartupError();
|
||||
if (startupError != null) {
|
||||
LOG.error("received unrecoverable error during startup", startupError);
|
||||
return createStageOneInjector(SingleView.error(startupError));
|
||||
} else if (Versions.isTooOld()) {
|
||||
LOG.error("Existing version is too old and cannot be migrated to new version. Please update to version {} first", Versions.MIN_VERSION);
|
||||
LOG.error("existing version is too old and cannot be migrated to new version. Please update to version {} first", Versions.MIN_VERSION);
|
||||
return createStageOneInjector(SingleView.view("/templates/too-old.mustache", HttpServletResponse.SC_CONFLICT));
|
||||
} else {
|
||||
try {
|
||||
return createStageTwoInjector();
|
||||
} catch (Exception ex) {
|
||||
LOG.error("failed to create stage two injector", ex);
|
||||
return createStageOneInjector(SingleView.error(ex));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class SetupContextListener implements ServletContextListener {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (isFirstStart()) {
|
||||
if (shouldCreateAdminAccount()) {
|
||||
createAdminAccount();
|
||||
}
|
||||
if (anonymousUserRequiredButNotExists()) {
|
||||
@@ -73,8 +73,12 @@ public class SetupContextListener implements ServletContextListener {
|
||||
return scmConfiguration.isAnonymousAccessEnabled() && !userManager.contains(SCMContext.USER_ANONYMOUS);
|
||||
}
|
||||
|
||||
private boolean isFirstStart() {
|
||||
return userManager.getAll().isEmpty();
|
||||
private boolean shouldCreateAdminAccount() {
|
||||
return userManager.getAll().isEmpty() || onlyAnonymousUserExists();
|
||||
}
|
||||
|
||||
private boolean onlyAnonymousUserExists() {
|
||||
return userManager.getAll().size() == 1 && userManager.contains(SCMContext.USER_ANONYMOUS);
|
||||
}
|
||||
|
||||
private void createAdminAccount() {
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
|
||||
import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
|
||||
import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventorFactory;
|
||||
import se.jiderhamn.classloader.leak.prevention.cleanup.MBeanCleanUp;
|
||||
import se.jiderhamn.classloader.leak.prevention.cleanup.StopThreadsCleanUp;
|
||||
import se.jiderhamn.classloader.leak.prevention.preinit.SunAwtAppContextInitiator;
|
||||
import sonia.scm.lifecycle.LifeCycle;
|
||||
import sonia.scm.plugin.ChildFirstPluginClassLoader;
|
||||
@@ -43,6 +44,9 @@ public final class ClassLoaderLifeCycle implements LifeCycle {
|
||||
classLoaderLeakPreventorFactory.removePreInitiator(SunAwtAppContextInitiator.class);
|
||||
// the MBeanCleanUp causes a Exception and we use no mbeans
|
||||
classLoaderLeakPreventorFactory.removeCleanUp(MBeanCleanUp.class);
|
||||
// the StopThreadsCleanUp leads to timeouts on shutdown - we try to stop our threads on our own
|
||||
classLoaderLeakPreventorFactory.removeCleanUp(StopThreadsCleanUp.class);
|
||||
|
||||
return new ClassLoaderLifeCycle(Thread.currentThread().getContextClassLoader(), classLoaderLeakPreventorFactory);
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ public final class SingleView {
|
||||
MustacheTemplateEngine.class);
|
||||
bind(TemplateEngineFactory.class);
|
||||
|
||||
serve("/images/*", "/styles/*", "/favicon.ico").with(StaticResourceServlet.class);
|
||||
serve("/images/*", "/assets/*", "/favicon.ico").with(StaticResourceServlet.class);
|
||||
serve("/*").with(SingleViewServlet.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,39 +38,27 @@ import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.apache.shiro.codec.Base64;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.net.Proxies;
|
||||
import sonia.scm.net.TrustAllHostnameVerifier;
|
||||
import sonia.scm.net.TrustAllTrustManager;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.Proxy;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URL;
|
||||
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import java.util.Set;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.*;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Set;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link AdvancedHttpClient}. The default
|
||||
@@ -324,11 +312,7 @@ public class DefaultAdvancedHttpClient extends AdvancedHttpClient
|
||||
sc.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||
connection.setSSLSocketFactory(sc.getSocketFactory());
|
||||
}
|
||||
catch (KeyManagementException ex)
|
||||
{
|
||||
logger.error("could not disable certificate validation", ex);
|
||||
}
|
||||
catch (NoSuchAlgorithmException ex)
|
||||
catch (KeyManagementException | NoSuchAlgorithmException ex)
|
||||
{
|
||||
logger.error("could not disable certificate validation", ex);
|
||||
}
|
||||
|
||||
@@ -34,20 +34,17 @@ package sonia.scm.net.ahc;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.io.ByteSource;
|
||||
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.util.IOUtil;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.xml.bind.DataBindingException;
|
||||
import javax.xml.bind.JAXB;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import javax.xml.bind.DataBindingException;
|
||||
import javax.xml.bind.JAXB;
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* {@link ContentTransformer} for xml. The {@link XmlContentTransformer} uses
|
||||
@@ -96,15 +93,10 @@ public class XmlContentTransformer implements ContentTransformer
|
||||
stream = content.openBufferedStream();
|
||||
object = JAXB.unmarshal(stream, type);
|
||||
}
|
||||
catch (IOException ex)
|
||||
catch (IOException | DataBindingException ex)
|
||||
{
|
||||
throw new ContentTransformerException("could not unmarshall content", ex);
|
||||
}
|
||||
catch (DataBindingException ex)
|
||||
{
|
||||
throw new ContentTransformerException("could not unmarshall content", ex);
|
||||
}
|
||||
finally
|
||||
} finally
|
||||
{
|
||||
IOUtil.close(stream);
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ public class DefaultPluginManager implements PluginManager {
|
||||
|
||||
if (!pendingInstallations.isEmpty()) {
|
||||
if (restartAfterInstallation) {
|
||||
restart("plugin installation");
|
||||
triggerRestart("plugin installation");
|
||||
} else {
|
||||
pendingInstallQueue.addAll(pendingInstallations);
|
||||
updateMayUninstallFlag();
|
||||
@@ -205,7 +205,7 @@ public class DefaultPluginManager implements PluginManager {
|
||||
markForUninstall(installed);
|
||||
|
||||
if (restartAfterInstallation) {
|
||||
restart("plugin installation");
|
||||
triggerRestart("plugin installation");
|
||||
} else {
|
||||
updateMayUninstallFlag();
|
||||
}
|
||||
@@ -238,12 +238,20 @@ public class DefaultPluginManager implements PluginManager {
|
||||
public void executePendingAndRestart() {
|
||||
PluginPermissions.manage().check();
|
||||
if (!pendingInstallQueue.isEmpty() || getInstalled().stream().anyMatch(InstalledPlugin::isMarkedForUninstall)) {
|
||||
restart("execute pending plugin changes");
|
||||
triggerRestart("execute pending plugin changes");
|
||||
}
|
||||
}
|
||||
|
||||
private void restart(String cause) {
|
||||
eventBus.post(new RestartEvent(PluginManager.class, cause));
|
||||
@VisibleForTesting
|
||||
void triggerRestart(String cause) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
eventBus.post(new RestartEvent(PluginManager.class, cause));
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void cancelPending(List<PendingPluginInstallation> pendingInstallations) {
|
||||
|
||||
@@ -74,7 +74,7 @@ public class MultiParentClassLoader extends ClassLoader
|
||||
public MultiParentClassLoader(Collection<? extends ClassLoader> parents)
|
||||
{
|
||||
super(null);
|
||||
this.parents = new CopyOnWriteArrayList<ClassLoader>(parents);
|
||||
this.parents = new CopyOnWriteArrayList<>(parents);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@@ -53,7 +53,7 @@ public final class PluginCenterDto implements Serializable {
|
||||
private String category;
|
||||
private String author;
|
||||
private String avatarUrl;
|
||||
private String sha256;
|
||||
private String sha256sum;
|
||||
|
||||
@XmlElement(name = "conditions")
|
||||
private Condition conditions;
|
||||
|
||||
@@ -19,7 +19,7 @@ public abstract class PluginCenterDtoMapper {
|
||||
for (PluginCenterDto.Plugin plugin : pluginCenterDto.getEmbedded().getPlugins()) {
|
||||
String url = plugin.getLinks().get("download").getHref();
|
||||
AvailablePluginDescriptor descriptor = new AvailablePluginDescriptor(
|
||||
map(plugin), map(plugin.getConditions()), plugin.getDependencies(), url, plugin.getSha256()
|
||||
map(plugin), map(plugin.getConditions()), plugin.getDependencies(), url, plugin.getSha256sum()
|
||||
);
|
||||
plugins.add(new AvailablePlugin(descriptor));
|
||||
}
|
||||
|
||||
@@ -128,15 +128,7 @@ public class HealthCheckContextListener implements ServletContextListener
|
||||
{
|
||||
|
||||
// excute health checks for all repsitories asynchronous
|
||||
SecurityUtils.getSubject().execute(new Runnable()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
healthChecker.checkAll();
|
||||
}
|
||||
});
|
||||
SecurityUtils.getSubject().execute(healthChecker::checkAll);
|
||||
}
|
||||
|
||||
//~--- fields -------------------------------------------------------------
|
||||
|
||||
@@ -168,8 +168,7 @@ public class AuthorizationChangedEventProducer {
|
||||
}
|
||||
|
||||
private boolean isAuthorizationDataModified(Repository repository, Repository beforeModification) {
|
||||
return repository.isPublicReadable() != beforeModification.isPublicReadable()
|
||||
|| !(repository.getPermissions().containsAll(beforeModification.getPermissions()) && beforeModification.getPermissions().containsAll(repository.getPermissions()));
|
||||
return !(repository.getPermissions().containsAll(beforeModification.getPermissions()) && beforeModification.getPermissions().containsAll(repository.getPermissions()));
|
||||
}
|
||||
|
||||
private void fireEventForEveryUser() {
|
||||
|
||||
@@ -18,7 +18,7 @@ class MigrationWizardModule extends ServletModule {
|
||||
LOG.info("= Open SCM-Manager in a browser to start the wizard. =");
|
||||
LOG.info("= =");
|
||||
LOG.info("==========================================================");
|
||||
serve("/images/*", "/styles/*", "/favicon.ico").with(StaticResourceServlet.class);
|
||||
serve("/images/*", "/assets/*", "/favicon.ico").with(StaticResourceServlet.class);
|
||||
serve("/*").with(MigrationWizardServlet.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,6 @@ public class MigrateVerbsToPermissionRoles implements UpdateStep {
|
||||
repository.setCreationDate(oldRepository.creationDate);
|
||||
repository.setHealthCheckFailures(oldRepository.healthCheckFailures);
|
||||
repository.setLastModified(oldRepository.lastModified);
|
||||
repository.setPublicReadable(oldRepository.publicReadable);
|
||||
return repository;
|
||||
}
|
||||
|
||||
@@ -149,8 +148,6 @@ public class MigrateVerbsToPermissionRoles implements UpdateStep {
|
||||
private String name;
|
||||
@XmlElement(name = "permission")
|
||||
private final Set<RepositoryPermission> permissions = new HashSet<>();
|
||||
@XmlElement(name = "public")
|
||||
private boolean publicReadable = false;
|
||||
private boolean archived = false;
|
||||
private String type;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package sonia.scm.update.repository;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.SCMContext;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.migration.UpdateStep;
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryPermission;
|
||||
import sonia.scm.repository.xml.XmlRepositoryDAO;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.xml.XmlUserDAO;
|
||||
import sonia.scm.version.Version;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
import static sonia.scm.version.Version.parse;
|
||||
|
||||
@Extension
|
||||
public class PublicFlagUpdateStep implements UpdateStep {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PublicFlagUpdateStep.class);
|
||||
|
||||
private static final String V1_REPOSITORY_BACKUP_FILENAME = "repositories.xml.v1.backup";
|
||||
|
||||
private final SCMContextProvider contextProvider;
|
||||
private final XmlUserDAO userDAO;
|
||||
private final XmlRepositoryDAO repositoryDAO;
|
||||
|
||||
@Inject
|
||||
public PublicFlagUpdateStep(SCMContextProvider contextProvider, XmlUserDAO userDAO, XmlRepositoryDAO repositoryDAO) {
|
||||
this.contextProvider = contextProvider;
|
||||
this.userDAO = userDAO;
|
||||
this.repositoryDAO = repositoryDAO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUpdate() throws JAXBException {
|
||||
LOG.info("Migrating public flags of repositories as RepositoryRolePermission 'READ' for user '_anonymous'");
|
||||
V1RepositoryHelper.readV1Database(contextProvider, V1_REPOSITORY_BACKUP_FILENAME).ifPresent(
|
||||
v1RepositoryDatabase -> {
|
||||
createNewAnonymousUserIfNotExists();
|
||||
deleteOldAnonymousUserIfAvailable();
|
||||
addRepositoryReadPermissionForAnonymousUser(v1RepositoryDatabase);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version getTargetVersion() {
|
||||
return parse("2.0.3");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAffectedDataType() {
|
||||
return "sonia.scm.repository.xml";
|
||||
}
|
||||
|
||||
private void addRepositoryReadPermissionForAnonymousUser(V1RepositoryHelper.V1RepositoryDatabase v1RepositoryDatabase) {
|
||||
User v2AnonymousUser = userDAO.get(SCMContext.USER_ANONYMOUS);
|
||||
v1RepositoryDatabase.repositoryList.repositories
|
||||
.stream()
|
||||
.filter(V1Repository::isPublic)
|
||||
.forEach(v1Repository -> {
|
||||
Repository v2Repository = repositoryDAO.get(v1Repository.getId());
|
||||
LOG.info(String.format("Add RepositoryRole 'READ' to _anonymous user for repository: %s - %s/%s", v2Repository.getId(), v2Repository.getNamespace(), v2Repository.getName()));
|
||||
v2Repository.addPermission(new RepositoryPermission(v2AnonymousUser.getId(), "READ", false));
|
||||
repositoryDAO.modify(v2Repository);
|
||||
});
|
||||
}
|
||||
|
||||
private void createNewAnonymousUserIfNotExists() {
|
||||
if (!userExists(SCMContext.USER_ANONYMOUS)) {
|
||||
LOG.info("Create new _anonymous user");
|
||||
userDAO.add(SCMContext.ANONYMOUS);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteOldAnonymousUserIfAvailable() {
|
||||
String oldAnonymous = "anonymous";
|
||||
if (userExists(oldAnonymous)) {
|
||||
User anonymousUser = userDAO.get(oldAnonymous);
|
||||
LOG.info("Delete obsolete anonymous user");
|
||||
userDAO.delete(anonymousUser);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean userExists(String username) {
|
||||
return userDAO
|
||||
.getAll()
|
||||
.stream()
|
||||
.anyMatch(user -> user.getName().equals(username));
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import sonia.scm.update.V1Properties;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.util.List;
|
||||
|
||||
@@ -16,6 +17,7 @@ public class V1Repository {
|
||||
private String description;
|
||||
private String id;
|
||||
private String name;
|
||||
@XmlElement(name="public")
|
||||
private boolean isPublic;
|
||||
private boolean archived;
|
||||
private String type;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package sonia.scm.update.repository;
|
||||
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.store.StoreConstants;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.util.Optional.empty;
|
||||
import static java.util.Optional.of;
|
||||
|
||||
class V1RepositoryHelper {
|
||||
|
||||
static Optional<File> resolveV1File(SCMContextProvider contextProvider, String filename) {
|
||||
File v1XmlFile = contextProvider.resolve(Paths.get(StoreConstants.CONFIG_DIRECTORY_NAME).resolve(filename)).toFile();
|
||||
if (v1XmlFile.exists()) {
|
||||
return Optional.of(v1XmlFile);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
static Optional<V1RepositoryDatabase> readV1Database(SCMContextProvider contextProvider, String filename) throws JAXBException {
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance(V1RepositoryDatabase.class);
|
||||
Optional<File> file = resolveV1File(contextProvider, filename);
|
||||
if (file.isPresent()) {
|
||||
Object unmarshal = jaxbContext.createUnmarshaller().unmarshal(file.get());
|
||||
if (unmarshal instanceof V1RepositoryDatabase) {
|
||||
return of((V1RepositoryDatabase) unmarshal);
|
||||
} else {
|
||||
return empty();
|
||||
}
|
||||
}
|
||||
return empty();
|
||||
}
|
||||
|
||||
static class RepositoryList {
|
||||
@XmlElement(name = "repository")
|
||||
List<V1Repository> repositories;
|
||||
}
|
||||
|
||||
@XmlRootElement(name = "repository-db")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
static class V1RepositoryDatabase {
|
||||
long creationTime;
|
||||
Long lastModified;
|
||||
@XmlElement(name = "repositories")
|
||||
RepositoryList repositoryList;
|
||||
}
|
||||
}
|
||||
@@ -17,26 +17,18 @@ import sonia.scm.update.V1Properties;
|
||||
import sonia.scm.version.Version;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Optional.empty;
|
||||
import static java.util.Optional.of;
|
||||
import static sonia.scm.update.V1PropertyReader.REPOSITORY_PROPERTY_READER;
|
||||
import static sonia.scm.update.repository.V1RepositoryHelper.resolveV1File;
|
||||
import static sonia.scm.version.Version.parse;
|
||||
|
||||
/**
|
||||
@@ -59,6 +51,8 @@ import static sonia.scm.version.Version.parse;
|
||||
@Extension
|
||||
public class XmlRepositoryV1UpdateStep implements CoreUpdateStep {
|
||||
|
||||
private final String V1_REPOSITORY_FILENAME = "repositories" + StoreConstants.FILE_EXTENSION;
|
||||
|
||||
private static Logger LOG = LoggerFactory.getLogger(XmlRepositoryV1UpdateStep.class);
|
||||
|
||||
private final SCMContextProvider contextProvider;
|
||||
@@ -97,12 +91,11 @@ public class XmlRepositoryV1UpdateStep implements CoreUpdateStep {
|
||||
|
||||
@Override
|
||||
public void doUpdate() throws JAXBException {
|
||||
if (!resolveV1File().exists()) {
|
||||
if (!resolveV1File(contextProvider, V1_REPOSITORY_FILENAME).isPresent()) {
|
||||
LOG.info("no v1 repositories database file found");
|
||||
return;
|
||||
}
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance(V1RepositoryDatabase.class);
|
||||
readV1Database(jaxbContext).ifPresent(
|
||||
V1RepositoryHelper.readV1Database(contextProvider, V1_REPOSITORY_FILENAME).ifPresent(
|
||||
v1Database -> {
|
||||
v1Database.repositoryList.repositories.forEach(this::readMigrationEntry);
|
||||
v1Database.repositoryList.repositories.forEach(this::update);
|
||||
@@ -112,13 +105,12 @@ public class XmlRepositoryV1UpdateStep implements CoreUpdateStep {
|
||||
}
|
||||
|
||||
public List<V1Repository> getRepositoriesWithoutMigrationStrategies() {
|
||||
if (!resolveV1File().exists()) {
|
||||
if (!resolveV1File(contextProvider, V1_REPOSITORY_FILENAME).isPresent()) {
|
||||
LOG.info("no v1 repositories database file found");
|
||||
return emptyList();
|
||||
}
|
||||
try {
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance(XmlRepositoryV1UpdateStep.V1RepositoryDatabase.class);
|
||||
return readV1Database(jaxbContext)
|
||||
return V1RepositoryHelper.readV1Database(contextProvider, V1_REPOSITORY_FILENAME)
|
||||
.map(v1Database -> v1Database.repositoryList.repositories.stream())
|
||||
.orElse(Stream.empty())
|
||||
.filter(v1Repository -> !this.findMigrationStrategy(v1Repository).isPresent())
|
||||
@@ -196,33 +188,4 @@ public class XmlRepositoryV1UpdateStep implements CoreUpdateStep {
|
||||
return new RepositoryPermission(v1Permission.getName(), v1Permission.getType(), v1Permission.isGroupPermission());
|
||||
}
|
||||
|
||||
private Optional<V1RepositoryDatabase> readV1Database(JAXBContext jaxbContext) throws JAXBException {
|
||||
Object unmarshal = jaxbContext.createUnmarshaller().unmarshal(resolveV1File());
|
||||
if (unmarshal instanceof V1RepositoryDatabase) {
|
||||
return of((V1RepositoryDatabase) unmarshal);
|
||||
} else {
|
||||
return empty();
|
||||
}
|
||||
}
|
||||
|
||||
private File resolveV1File() {
|
||||
return contextProvider
|
||||
.resolve(
|
||||
Paths.get(StoreConstants.CONFIG_DIRECTORY_NAME).resolve("repositories" + StoreConstants.FILE_EXTENSION)
|
||||
).toFile();
|
||||
}
|
||||
|
||||
private static class RepositoryList {
|
||||
@XmlElement(name = "repository")
|
||||
private List<V1Repository> repositories;
|
||||
}
|
||||
|
||||
@XmlRootElement(name = "repository-db")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
private static class V1RepositoryDatabase {
|
||||
private long creationTime;
|
||||
private Long lastModified;
|
||||
@XmlElement(name = "repositories")
|
||||
private RepositoryList repositoryList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package sonia.scm.user;
|
||||
|
||||
import com.github.legman.Subscribe;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.EagerSingleton;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.SCMContext;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.plugin.Extension;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@EagerSingleton
|
||||
@Extension
|
||||
public class AnonymousUserDeletionEventHandler {
|
||||
|
||||
private ScmConfiguration scmConfiguration;
|
||||
|
||||
@Inject
|
||||
public AnonymousUserDeletionEventHandler(ScmConfiguration scmConfiguration) {
|
||||
this.scmConfiguration = scmConfiguration;
|
||||
}
|
||||
|
||||
@Subscribe(async = false)
|
||||
public void onEvent(UserEvent event) {
|
||||
if (isAnonymousUserDeletionNotAllowed(event)) {
|
||||
throw new AnonymousUserDeletionException(ContextEntry.ContextBuilder.entity(User.class, event.getItem().getId()));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAnonymousUserDeletionNotAllowed(UserEvent event) {
|
||||
return event.getEventType() == HandlerEventType.BEFORE_DELETE
|
||||
&& event.getItem().getName().equals(SCMContext.USER_ANONYMOUS)
|
||||
&& scmConfiguration.isAnonymousAccessEnabled();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package sonia.scm.user;
|
||||
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.ExceptionWithContext;
|
||||
|
||||
public class AnonymousUserDeletionException extends ExceptionWithContext {
|
||||
|
||||
private static final String CODE = "1yRiASshD1";
|
||||
|
||||
public AnonymousUserDeletionException(ContextEntry.ContextBuilder context) {
|
||||
super(context.build(), "_anonymous user can not be deleted if anonymous access is enabled");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return CODE;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user