Merge with 2.0.0-m3

This commit is contained in:
Rene Pfeuffer
2019-11-25 14:35:47 +01:00
39 changed files with 499 additions and 197 deletions

View File

@@ -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);

View File

@@ -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() {

View File

@@ -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,19 @@ 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) {
}
eventBus.post(new RestartEvent(PluginManager.class, cause));
}).start();
}
private void cancelPending(List<PendingPluginInstallation> pendingInstallations) {

View File

@@ -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() {

View File

@@ -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;
}

View File

@@ -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));
}
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;
}
}