diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HookEventFacade.java b/scm-core/src/main/java/sonia/scm/repository/spi/HookEventFacade.java index 27cafd1a16..fd785e2138 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/HookEventFacade.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/HookEventFacade.java @@ -77,7 +77,7 @@ public final class HookEventFacade Repository repository = repositoryManagerProvider.get().get(id); if (repository == null) { - throw notFound(entity("repository", id)); + throw notFound(entity("Repository", id)); } return handle(repository); } diff --git a/scm-plugins/scm-git-plugin/package.json b/scm-plugins/scm-git-plugin/package.json index 8d5ac3165b..3b66c4f2c1 100644 --- a/scm-plugins/scm-git-plugin/package.json +++ b/scm-plugins/scm-git-plugin/package.json @@ -12,6 +12,6 @@ "@scm-manager/ui-extensions": "^0.1.2" }, "devDependencies": { - "@scm-manager/ui-bundler": "^0.0.25" + "@scm-manager/ui-bundler": "^0.0.26" } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java index f490b7ea4f..7aacdb256a 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java @@ -205,7 +205,7 @@ public final class GitUtil } catch (GitAPIException ex) { - throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity("remote", directory.toString()).in(remoteRepository), "could not fetch", ex); + throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity("Remote", directory.toString()).in(remoteRepository), "could not fetch", ex); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBlameCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBlameCommand.java index 2ad38648da..5787842b9a 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBlameCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBlameCommand.java @@ -110,7 +110,7 @@ public class GitBlameCommand extends AbstractGitCommand implements BlameCommand if (gitBlameResult == null) { - throw new InternalRepositoryException(entity("path", request.getPath()).in(repository), + throw new InternalRepositoryException(entity("Path", request.getPath()).in(repository), "could not create blame result for path"); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java index 9186572858..93fb01176b 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java @@ -65,6 +65,9 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import static sonia.scm.ContextEntry.ContextBuilder.entity; +import static sonia.scm.NotFoundException.notFound; + //~--- JDK imports ------------------------------------------------------------ /** @@ -128,10 +131,11 @@ public class GitBrowseCommand extends AbstractGitCommand if (Util.isNotEmpty(request.getRevision())) { logger.error("could not find revision {}", request.getRevision()); + throw notFound(entity("Revision", request.getRevision()).in(this.repository)); } else if (logger.isWarnEnabled()) { - logger.warn("coul not find head of repository, empty?"); + logger.warn("could not find head of repository, empty?"); } result = new BrowserResult(Constants.HEAD, createEmtpyRoot()); @@ -354,7 +358,7 @@ public class GitBrowseCommand extends AbstractGitCommand } } - throw new NotFoundException("file", request.getPath()); + throw notFound(entity("File", request.getPath()).in("Revision", revId.getName()).in(this.repository)); } @SuppressWarnings("unchecked") diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLogCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLogCommand.java index bdbb87f2aa..a42abca5f0 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLogCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLogCommand.java @@ -43,7 +43,6 @@ import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.treewalk.filter.AndTreeFilter; import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.treewalk.filter.TreeFilter; @@ -79,6 +78,7 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand */ private static final Logger logger = LoggerFactory.getLogger(GitLogCommand.class); + public static final String REVISION = "Revision"; //~--- constructors --------------------------------------------------------- @@ -143,6 +143,10 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand { logger.error("could not open repository", ex); } + catch (NullPointerException e) + { + throw notFound(entity(REVISION, revision).in(this.repository)); + } finally { IOUtil.close(converter); @@ -208,7 +212,7 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand if (!Strings.isNullOrEmpty(request.getAncestorChangeset())) { ancestorId = repository.resolve(request.getAncestorChangeset()); if (ancestorId == null) { - throw notFound(entity("Revision", request.getAncestorChangeset()).in(this.repository)); + throw notFound(entity(REVISION, request.getAncestorChangeset()).in(this.repository)); } } @@ -250,7 +254,7 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand } } } else if (ancestorId != null) { - throw notFound(entity("Revision", request.getBranch()).in(this.repository)); + throw notFound(entity(REVISION, request.getBranch()).in(this.repository)); } if (branch != null) { @@ -267,7 +271,7 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand } catch (MissingObjectException e) { - throw notFound(entity("Revision", e.getObjectId().getName()).in(repository)); + throw notFound(entity(REVISION, e.getObjectId().getName()).in(repository)); } catch (NotFoundException e) { @@ -285,17 +289,4 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand return changesets; } - - private ObjectId computeCommonAncestor(LogCommandRequest request, Repository repository, ObjectId startId, Ref branch) throws IOException { - try (RevWalk mergeBaseWalk = new RevWalk(repository)) { - mergeBaseWalk.setRevFilter(RevFilter.MERGE_BASE); - if (startId != null) { - mergeBaseWalk.markStart(mergeBaseWalk.lookupCommit(startId)); - } else { - mergeBaseWalk.markStart(mergeBaseWalk.lookupCommit(branch.getObjectId())); - } - mergeBaseWalk.markStart(mergeBaseWalk.parseCommit(repository.resolve(request.getAncestorChangeset()))); - return mergeBaseWalk.next().getId(); - } - } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java index 64fbadd5a2..f328011815 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java @@ -74,7 +74,7 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand private ObjectId resolveRevisionOrThrowNotFound(Repository repository, String revision) throws IOException { ObjectId resolved = repository.resolve(revision); if (resolved == null) { - throw notFound(entity("revision", revision).in(context.getRepository())); + throw notFound(entity("Revision", revision).in(context.getRepository())); } else { return resolved; } @@ -125,7 +125,7 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand clone.checkout().setStartPoint(targetRevision.getName()).setName(target).setCreateBranch(true).call(); } catch (RefNotFoundException e) { logger.debug("could not checkout target branch {} for merge as local branch", target, e); - throw notFound(entity("revision", target).in(context.getRepository())); + throw notFound(entity("Revision", target).in(context.getRepository())); } catch (GitAPIException e) { throw new InternalRepositoryException(context.getRepository(), "could not checkout target branch for merge as local branch: " + target, e); } diff --git a/scm-plugins/scm-git-plugin/yarn.lock b/scm-plugins/scm-git-plugin/yarn.lock index 6438262437..a45145d157 100644 --- a/scm-plugins/scm-git-plugin/yarn.lock +++ b/scm-plugins/scm-git-plugin/yarn.lock @@ -707,9 +707,9 @@ version "0.0.2" resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85" -"@scm-manager/ui-bundler@^0.0.25": - version "0.0.25" - resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.25.tgz#1f65b3ff0ae81559a114c6a8d8cf43856cc6e166" +"@scm-manager/ui-bundler@^0.0.26": + version "0.0.26" + resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.26.tgz#4676a7079b781b33fa1989c6643205c3559b1f66" dependencies: "@babel/core" "^7.0.0" "@babel/plugin-proposal-class-properties" "^7.0.0" diff --git a/scm-plugins/scm-hg-plugin/package.json b/scm-plugins/scm-hg-plugin/package.json index 8d3926f0dd..d723751912 100644 --- a/scm-plugins/scm-hg-plugin/package.json +++ b/scm-plugins/scm-hg-plugin/package.json @@ -9,6 +9,6 @@ "@scm-manager/ui-extensions": "^0.1.2" }, "devDependencies": { - "@scm-manager/ui-bundler": "^0.0.25" + "@scm-manager/ui-bundler": "^0.0.26" } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java index 7db9a8becb..d2da936c48 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java @@ -349,7 +349,7 @@ public class HgRepositoryHandler try { return new INIConfigurationReader().read(new File(directory, PATH_HGRC)).getSection(CONFIG_SECTION_SCMM).getParameter(CONFIG_KEY_REPOSITORY_ID); } catch (IOException e) { - throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity("directory", directory.toString()), "could not read scm configuration file", e); + throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity("Directory", directory.toString()), "could not read scm configuration file", e); } } diff --git a/scm-plugins/scm-hg-plugin/yarn.lock b/scm-plugins/scm-hg-plugin/yarn.lock index 47334b6e36..c1e19efede 100644 --- a/scm-plugins/scm-hg-plugin/yarn.lock +++ b/scm-plugins/scm-hg-plugin/yarn.lock @@ -641,9 +641,9 @@ version "0.0.2" resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85" -"@scm-manager/ui-bundler@^0.0.25": - version "0.0.25" - resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.25.tgz#1f65b3ff0ae81559a114c6a8d8cf43856cc6e166" +"@scm-manager/ui-bundler@^0.0.26": + version "0.0.26" + resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.26.tgz#4676a7079b781b33fa1989c6643205c3559b1f66" dependencies: "@babel/core" "^7.0.0" "@babel/plugin-proposal-class-properties" "^7.0.0" diff --git a/scm-plugins/scm-svn-plugin/package.json b/scm-plugins/scm-svn-plugin/package.json index 8bbf204e2f..10439dba66 100644 --- a/scm-plugins/scm-svn-plugin/package.json +++ b/scm-plugins/scm-svn-plugin/package.json @@ -9,6 +9,6 @@ "@scm-manager/ui-extensions": "^0.1.2" }, "devDependencies": { - "@scm-manager/ui-bundler": "^0.0.25" + "@scm-manager/ui-bundler": "^0.0.26" } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryHandler.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryHandler.java index 639a16968c..c32310e7e7 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryHandler.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnRepositoryHandler.java @@ -234,7 +234,7 @@ public class SvnRepositoryHandler try { return new INIConfigurationReader().read(new File(directory, CONFIG_FILE_NAME)).getSection(CONFIG_SECTION_SCMM).getParameter(CONFIG_KEY_REPOSITORY_ID); } catch (IOException e) { - throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity("directory", directory.toString()), "could not read scm configuration file", e); + throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity("Directory", directory.toString()), "could not read scm configuration file", e); } } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnBrowseCommand.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnBrowseCommand.java index df266a11af..99dae0e77b 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnBrowseCommand.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnBrowseCommand.java @@ -53,6 +53,10 @@ import sonia.scm.util.Util; import java.util.Collection; +import static org.tmatesoft.svn.core.SVNErrorCode.FS_NO_SUCH_REVISION; +import static sonia.scm.ContextEntry.ContextBuilder.entity; +import static sonia.scm.NotFoundException.notFound; + //~--- JDK imports ------------------------------------------------------------ /** @@ -107,6 +111,9 @@ public class SvnBrowseCommand extends AbstractSvnCommand } catch (SVNException ex) { + if (FS_NO_SUCH_REVISION.equals(ex.getErrorMessage().getErrorCode())) { + throw notFound(entity("Revision", Long.toString(revisionNumber)).in(this.repository)); + } logger.error("could not open repository", ex); } @@ -153,6 +160,9 @@ public class SvnBrowseCommand extends AbstractSvnCommand private FileObject createFileObject(BrowseCommandRequest request, SVNRepository repository, long revision, SVNDirEntry entry, String path) { + if (entry == null) { + throw notFound(entity("Path", path).in("Revision", Long.toString(revision)).in(this.repository)); + } FileObject fileObject = new FileObject(); fileObject.setName(entry.getName()); diff --git a/scm-plugins/scm-svn-plugin/yarn.lock b/scm-plugins/scm-svn-plugin/yarn.lock index 47334b6e36..c1e19efede 100644 --- a/scm-plugins/scm-svn-plugin/yarn.lock +++ b/scm-plugins/scm-svn-plugin/yarn.lock @@ -641,9 +641,9 @@ version "0.0.2" resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85" -"@scm-manager/ui-bundler@^0.0.25": - version "0.0.25" - resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.25.tgz#1f65b3ff0ae81559a114c6a8d8cf43856cc6e166" +"@scm-manager/ui-bundler@^0.0.26": + version "0.0.26" + resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.26.tgz#4676a7079b781b33fa1989c6643205c3559b1f66" dependencies: "@babel/core" "^7.0.0" "@babel/plugin-proposal-class-properties" "^7.0.0" diff --git a/scm-ui-components/packages/ui-components/package.json b/scm-ui-components/packages/ui-components/package.json index 80b83b0265..8eaebe3632 100644 --- a/scm-ui-components/packages/ui-components/package.json +++ b/scm-ui-components/packages/ui-components/package.json @@ -14,7 +14,7 @@ "eslint-fix": "eslint src --fix" }, "devDependencies": { - "@scm-manager/ui-bundler": "^0.0.25", + "@scm-manager/ui-bundler": "^0.0.26", "create-index": "^2.3.0", "enzyme": "^3.5.0", "enzyme-adapter-react-16": "^1.3.1", diff --git a/scm-ui-components/packages/ui-components/src/DateFromNow.js b/scm-ui-components/packages/ui-components/src/DateFromNow.js index be15bcdad2..3c14f02d0c 100644 --- a/scm-ui-components/packages/ui-components/src/DateFromNow.js +++ b/scm-ui-components/packages/ui-components/src/DateFromNow.js @@ -4,6 +4,10 @@ import moment from "moment"; import { translate } from "react-i18next"; import injectSheet from "react-jss"; +// fix german locale +// https://momentjscom.readthedocs.io/en/latest/moment/00-use-it/07-browserify/ +import "moment/locale/de"; + const styles = { date: { borderBottom: "1px dotted rgba(219, 219, 219)", diff --git a/scm-ui-components/packages/ui-components/src/apiclient.js b/scm-ui-components/packages/ui-components/src/apiclient.js index 77ebe8cf4e..551bb3e2eb 100644 --- a/scm-ui-components/packages/ui-components/src/apiclient.js +++ b/scm-ui-components/packages/ui-components/src/apiclient.js @@ -6,7 +6,9 @@ import type { BackendErrorContent } from "./errors"; const fetchOptions: RequestOptions = { credentials: "same-origin", headers: { - Cache: "no-cache" + Cache: "no-cache", + // identify the request as ajax request + "X-Requested-With": "XMLHttpRequest" } }; diff --git a/scm-ui-components/packages/ui-components/yarn.lock b/scm-ui-components/packages/ui-components/yarn.lock index 1a4c28c9c2..9736de8a78 100644 --- a/scm-ui-components/packages/ui-components/yarn.lock +++ b/scm-ui-components/packages/ui-components/yarn.lock @@ -687,9 +687,9 @@ version "0.0.2" resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85" -"@scm-manager/ui-bundler@^0.0.25": - version "0.0.25" - resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.25.tgz#1f65b3ff0ae81559a114c6a8d8cf43856cc6e166" +"@scm-manager/ui-bundler@^0.0.26": + version "0.0.26" + resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.26.tgz#4676a7079b781b33fa1989c6643205c3559b1f66" dependencies: "@babel/core" "^7.0.0" "@babel/plugin-proposal-class-properties" "^7.0.0" diff --git a/scm-ui-components/packages/ui-types/package.json b/scm-ui-components/packages/ui-types/package.json index 11029490bb..c6a7c880dc 100644 --- a/scm-ui-components/packages/ui-types/package.json +++ b/scm-ui-components/packages/ui-types/package.json @@ -14,7 +14,7 @@ "check": "flow check" }, "devDependencies": { - "@scm-manager/ui-bundler": "^0.0.25" + "@scm-manager/ui-bundler": "^0.0.26" }, "browserify": { "transform": [ diff --git a/scm-ui-components/packages/ui-types/yarn.lock b/scm-ui-components/packages/ui-types/yarn.lock index d0ef9f7a86..2d47639005 100644 --- a/scm-ui-components/packages/ui-types/yarn.lock +++ b/scm-ui-components/packages/ui-types/yarn.lock @@ -707,9 +707,9 @@ version "0.0.2" resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85" -"@scm-manager/ui-bundler@^0.0.25": - version "0.0.25" - resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.25.tgz#1f65b3ff0ae81559a114c6a8d8cf43856cc6e166" +"@scm-manager/ui-bundler@^0.0.26": + version "0.0.26" + resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.26.tgz#4676a7079b781b33fa1989c6643205c3559b1f66" dependencies: "@babel/core" "^7.0.0" "@babel/plugin-proposal-class-properties" "^7.0.0" diff --git a/scm-ui/package.json b/scm-ui/package.json index 531b3400a9..6844ea3ec7 100644 --- a/scm-ui/package.json +++ b/scm-ui/package.json @@ -52,7 +52,7 @@ "pre-commit": "jest && flow && eslint src" }, "devDependencies": { - "@scm-manager/ui-bundler": "^0.0.25", + "@scm-manager/ui-bundler": "^0.0.26", "concat": "^1.0.3", "copyfiles": "^2.0.0", "enzyme": "^3.3.0", diff --git a/scm-ui/yarn.lock b/scm-ui/yarn.lock index 5c38cb2dba..5b6ec89ef3 100644 --- a/scm-ui/yarn.lock +++ b/scm-ui/yarn.lock @@ -698,9 +698,9 @@ version "0.0.2" resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85" -"@scm-manager/ui-bundler@^0.0.25": - version "0.0.25" - resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.25.tgz#1f65b3ff0ae81559a114c6a8d8cf43856cc6e166" +"@scm-manager/ui-bundler@^0.0.26": + version "0.0.26" + resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.26.tgz#4676a7079b781b33fa1989c6643205c3559b1f66" dependencies: "@babel/core" "^7.0.0" "@babel/plugin-proposal-class-properties" "^7.0.0" diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileHistoryRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileHistoryRootResource.java index 017568b613..5e087dc7ca 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileHistoryRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileHistoryRootResource.java @@ -85,7 +85,7 @@ public class FileHistoryRootResource { } else { String message = String.format("for the revision %s and the file %s there are no changesets", revision, path); log.error(message); - throw notFound(entity("path", path).in("revision", revision).in(namespaceAndName)); + throw notFound(entity("Path", path).in("revision", revision).in(namespaceAndName)); } } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java index d149f55401..b87a4911a5 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResource.java @@ -258,7 +258,7 @@ public class RepositoryPermissionRootResource { */ private void checkPermissionAlreadyExists(RepositoryPermissionDto permission, Repository repository) { if (isPermissionExist(permission, repository)) { - throw alreadyExists(entity("permission", permission.getName()).in(repository)); + throw alreadyExists(entity("Permission", permission.getName()).in(repository)); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java index d507a59f14..b5c7e205be 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java @@ -15,6 +15,9 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Response; import java.io.IOException; +import static sonia.scm.ContextEntry.ContextBuilder.entity; +import static sonia.scm.NotFoundException.notFound; + public class SourceRootResource { private final RepositoryServiceFactory serviceFactory; @@ -62,7 +65,7 @@ public class SourceRootResource { if (browserResult != null) { return Response.ok(browserResultToFileObjectDtoMapper.map(browserResult, namespaceAndName)).build(); } else { - return Response.status(Response.Status.NOT_FOUND).build(); + throw notFound(entity("Source", path).in("Revision", revision).in(namespaceAndName)); } } } diff --git a/scm-webapp/src/main/java/sonia/scm/security/PermissionAssigner.java b/scm-webapp/src/main/java/sonia/scm/security/PermissionAssigner.java index faa25d7817..cc0428071a 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/PermissionAssigner.java +++ b/scm-webapp/src/main/java/sonia/scm/security/PermissionAssigner.java @@ -77,7 +77,7 @@ public class PermissionAssigner { private Predicate permissionExists(Collection availablePermissions, Collection existingPermissions) { return p -> { if (!availablePermissions.contains(p) && existingPermissions.stream().map(AssignedPermission::getPermission).noneMatch(e -> e.equals(p))) { - throw NotFoundException.notFound(ContextEntry.ContextBuilder.entity("permission", p.getValue())); + throw NotFoundException.notFound(ContextEntry.ContextBuilder.entity("Permission", p.getValue())); } return true; }; diff --git a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java index 33762a5941..709987fb1b 100644 --- a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java +++ b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java @@ -403,7 +403,7 @@ public class DefaultUserManager extends AbstractUserManager User user = get((String) SecurityUtils.getSubject().getPrincipals().getPrimaryPrincipal()); if (!user.getPassword().equals(oldPassword)) { - throw new InvalidPasswordException(ContextEntry.ContextBuilder.entity("passwordChange", "-").in(User.class, user.getName())); + throw new InvalidPasswordException(ContextEntry.ContextBuilder.entity("PasswordChange", "-").in(User.class, user.getName())); } user.setPassword(newPassword); @@ -422,7 +422,7 @@ public class DefaultUserManager extends AbstractUserManager throw new NotFoundException(User.class, userId); } if (!isTypeDefault(user)) { - throw new ChangePasswordNotAllowedException(ContextEntry.ContextBuilder.entity("passwordChange", "-").in(User.class, user.getName()), user.getType()); + throw new ChangePasswordNotAllowedException(ContextEntry.ContextBuilder.entity("PasswordChange", "-").in(User.class, user.getName()), user.getType()); } user.setPassword(newPassword); this.modify(user); diff --git a/scm-webapp/src/main/java/sonia/scm/web/filter/HttpProtocolServletAuthenticationFilter.java b/scm-webapp/src/main/java/sonia/scm/web/filter/HttpProtocolServletAuthenticationFilter.java index e58945a346..973b3af4cb 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/filter/HttpProtocolServletAuthenticationFilter.java +++ b/scm-webapp/src/main/java/sonia/scm/web/filter/HttpProtocolServletAuthenticationFilter.java @@ -1,7 +1,6 @@ package sonia.scm.web.filter; import sonia.scm.Priority; -import sonia.scm.PushStateDispatcher; import sonia.scm.config.ScmConfiguration; import sonia.scm.filter.Filters; import sonia.scm.filter.WebElement; @@ -12,6 +11,8 @@ import sonia.scm.web.WebTokenGenerator; import sonia.scm.web.protocol.HttpProtocolServlet; import javax.inject.Inject; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -21,25 +22,23 @@ import java.util.Set; @WebElement(value = HttpProtocolServlet.PATTERN) public class HttpProtocolServletAuthenticationFilter extends AuthenticationFilter { - private final PushStateDispatcher dispatcher; private final UserAgentParser userAgentParser; @Inject public HttpProtocolServletAuthenticationFilter( ScmConfiguration configuration, Set tokenGenerators, - PushStateDispatcher dispatcher, UserAgentParser userAgentParser) { super(configuration, tokenGenerators); - this.dispatcher = dispatcher; this.userAgentParser = userAgentParser; } @Override - protected void sendUnauthorizedError(HttpServletRequest request, HttpServletResponse response) throws IOException { + protected void handleUnauthorized(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { UserAgent userAgent = userAgentParser.parse(request); if (userAgent.isBrowser()) { - dispatcher.dispatch(request, response, request.getRequestURI()); + // we can proceed the filter chain because the HttpProtocolServlet will render the ui if the client is a browser + chain.doFilter(request, response); } else { HttpUtil.sendUnauthorized(request, response); } diff --git a/scm-webapp/src/test/java/sonia/scm/web/filter/HttpProtocolServletAuthenticationFilterTest.java b/scm-webapp/src/test/java/sonia/scm/web/filter/HttpProtocolServletAuthenticationFilterTest.java new file mode 100644 index 0000000000..ff493e2b84 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/web/filter/HttpProtocolServletAuthenticationFilterTest.java @@ -0,0 +1,72 @@ +package sonia.scm.web.filter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.config.ScmConfiguration; +import sonia.scm.util.HttpUtil; +import sonia.scm.web.UserAgent; +import sonia.scm.web.UserAgentParser; +import sonia.scm.web.WebTokenGenerator; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Collections; +import java.util.Set; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class HttpProtocolServletAuthenticationFilterTest { + + private ScmConfiguration configuration = new ScmConfiguration(); + + private Set tokenGenerators = Collections.emptySet(); + + @Mock + private UserAgentParser userAgentParser; + + private HttpProtocolServletAuthenticationFilter authenticationFilter; + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + @Mock + private FilterChain filterChain; + + private UserAgent nonBrowser = UserAgent.builder("i'm not a browser").browser(false).build(); + private UserAgent browser = UserAgent.builder("i am a browser").browser(true).build(); + + @BeforeEach + void setUpObjectUnderTest() { + authenticationFilter = new HttpProtocolServletAuthenticationFilter(configuration, tokenGenerators, userAgentParser); + } + + @Test + void shouldSendUnauthorized() throws IOException, ServletException { + when(userAgentParser.parse(request)).thenReturn(nonBrowser); + + authenticationFilter.handleUnauthorized(request, response, filterChain); + + verify(response).sendError(HttpServletResponse.SC_UNAUTHORIZED, HttpUtil.STATUS_UNAUTHORIZED_MESSAGE); + } + + @Test + void shouldCallFilterChain() throws IOException, ServletException { + when(userAgentParser.parse(request)).thenReturn(browser); + + authenticationFilter.handleUnauthorized(request, response, filterChain); + + verify(filterChain).doFilter(request, response); + } + +}