diff --git a/gradle/changelog/colon_in_filenames.yaml b/gradle/changelog/colon_in_filenames.yaml new file mode 100644 index 0000000000..89f8e6235f --- /dev/null +++ b/gradle/changelog/colon_in_filenames.yaml @@ -0,0 +1,2 @@ +- type: fixed + description: Source view for files with colons ([#1881](https://github.com/scm-manager/scm-manager/pull/1881)) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java index 55f54aaf49..61a019d881 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java @@ -44,7 +44,7 @@ class ResourceLinks { // we have to add the file path using URI, so that path separators (aka '/') will not be encoded as '%2F' private static String addPath(String sourceWithPath, String path) { try { - return new URI(sourceWithPath).resolve(new URI(null, null, path, null)).toASCIIString(); + return new URI(sourceWithPath).resolve(new URI(null, null, "./" + path, null)).toASCIIString(); } catch (URISyntaxException e) { throw new RuntimeException(e); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToFileObjectDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToFileObjectDtoMapperTest.java index c38aad6021..f2f420a12c 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToFileObjectDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToFileObjectDtoMapperTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.api.v2.resources; import org.apache.shiro.subject.Subject; @@ -52,10 +52,8 @@ public class BrowserResultToFileObjectDtoMapperTest { private final Subject subject = mock(Subject.class); private final ThreadState subjectThreadState = new SubjectThreadState(subject); - private FileObject fileObject1 = new FileObject(); - private FileObject fileObject2 = new FileObject(); - private FileObject partialFileObject = new FileObject(); - + private final FileObject fileObject1 = new FileObject(); + private final FileObject fileObject2 = new FileObject(); @Before public void init() { @@ -115,18 +113,36 @@ public class BrowserResultToFileObjectDtoMapperTest { assertThat(dto.getLinks().getLinkBy("self").get().getHref()).contains("path"); } - private BrowserResult createBrowserResult() { - return new BrowserResult("Revision", createFileObject()); + @Test + public void shouldEncodeFileLinks() { + BrowserResult browserResult = new BrowserResult("Revision", createFileObject("c:file")); + NamespaceAndName namespaceAndName = new NamespaceAndName("foo", "bar"); + + FileObjectDto dto = mapper.map(browserResult, namespaceAndName, 0); + + assertThat(dto.getLinks().getLinkBy("self").get().getHref()).isEqualTo("http://example.com/base/v2/repositories/foo/bar/content/Revision/c:file"); } - private FileObject createFileObject() { - FileObject file = new FileObject(); - file.setName(""); - file.setPath("/path"); - file.setDirectory(true); + private BrowserResult createBrowserResult() { + return new BrowserResult("Revision", createDirectoryObject()); + } - file.addChild(fileObject1); - file.addChild(fileObject2); + private FileObject createDirectoryObject() { + FileObject directory = new FileObject(); + directory.setName(""); + directory.setPath("/path"); + directory.setDirectory(true); + + directory.addChild(fileObject1); + directory.addChild(fileObject2); + return directory; + } + + private FileObject createFileObject(String name) { + FileObject file = new FileObject(); + file.setName(name); + file.setPath(name); + file.setDirectory(false); return file; } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java index 98f01f864a..8fad950a27 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java @@ -26,66 +26,16 @@ package sonia.scm.api.v2.resources; import java.net.URI; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.spy; public class ResourceLinksMock { public static ResourceLinks createMock(URI baseUri) { - ResourceLinks resourceLinks = mock(ResourceLinks.class); + ScmPathInfo pathInfo = () -> baseUri; - ScmPathInfo pathInfo = mock(ScmPathInfo.class); - when(pathInfo.getApiRestUri()).thenReturn(baseUri); + ScmPathInfoStore scmPathInfoStore = new ScmPathInfoStore(); + scmPathInfoStore.set(pathInfo); - ResourceLinks.UserLinks userLinks = new ResourceLinks.UserLinks(pathInfo); - lenient().when(resourceLinks.user()).thenReturn(userLinks); - lenient().when(resourceLinks.me()).thenReturn(new ResourceLinks.MeLinks(pathInfo,userLinks)); - lenient().when(resourceLinks.userCollection()).thenReturn(new ResourceLinks.UserCollectionLinks(pathInfo)); - lenient().when(resourceLinks.userPermissions()).thenReturn(new ResourceLinks.UserPermissionLinks(pathInfo)); - lenient().when(resourceLinks.autoComplete()).thenReturn(new ResourceLinks.AutoCompleteLinks(pathInfo)); - lenient().when(resourceLinks.group()).thenReturn(new ResourceLinks.GroupLinks(pathInfo)); - lenient().when(resourceLinks.groupCollection()).thenReturn(new ResourceLinks.GroupCollectionLinks(pathInfo)); - lenient().when(resourceLinks.groupPermissions()).thenReturn(new ResourceLinks.GroupPermissionLinks(pathInfo)); - lenient().when(resourceLinks.repository()).thenReturn(new ResourceLinks.RepositoryLinks(pathInfo)); - lenient().when(resourceLinks.incoming()).thenReturn(new ResourceLinks.IncomingLinks(pathInfo)); - lenient().when(resourceLinks.repositoryCollection()).thenReturn(new ResourceLinks.RepositoryCollectionLinks(pathInfo)); - lenient().when(resourceLinks.tag()).thenReturn(new ResourceLinks.TagCollectionLinks(pathInfo)); - lenient().when(resourceLinks.branchCollection()).thenReturn(new ResourceLinks.BranchCollectionLinks(pathInfo)); - lenient().when(resourceLinks.changeset()).thenReturn(new ResourceLinks.ChangesetLinks(pathInfo)); - lenient().when(resourceLinks.fileHistory()).thenReturn(new ResourceLinks.FileHistoryLinks(pathInfo)); - lenient().when(resourceLinks.source()).thenReturn(new ResourceLinks.SourceLinks(pathInfo)); - lenient().when(resourceLinks.repositoryPermission()).thenReturn(new ResourceLinks.RepositoryPermissionLinks(pathInfo)); - lenient().when(resourceLinks.config()).thenReturn(new ResourceLinks.ConfigLinks(pathInfo)); - lenient().when(resourceLinks.branch()).thenReturn(new ResourceLinks.BranchLinks(pathInfo)); - lenient().when(resourceLinks.diff()).thenReturn(new ResourceLinks.DiffLinks(pathInfo)); - lenient().when(resourceLinks.modifications()).thenReturn(new ResourceLinks.ModificationsLinks(pathInfo)); - lenient().when(resourceLinks.repositoryType()).thenReturn(new ResourceLinks.RepositoryTypeLinks(pathInfo)); - lenient().when(resourceLinks.repositoryTypeCollection()).thenReturn(new ResourceLinks.RepositoryTypeCollectionLinks(pathInfo)); - lenient().when(resourceLinks.installedPluginCollection()).thenReturn(new ResourceLinks.InstalledPluginCollectionLinks(pathInfo)); - lenient().when(resourceLinks.availablePluginCollection()).thenReturn(new ResourceLinks.AvailablePluginCollectionLinks(pathInfo)); - lenient().when(resourceLinks.pendingPluginCollection()).thenReturn(new ResourceLinks.PendingPluginCollectionLinks(pathInfo)); - lenient().when(resourceLinks.installedPlugin()).thenReturn(new ResourceLinks.InstalledPluginLinks(pathInfo)); - lenient().when(resourceLinks.availablePlugin()).thenReturn(new ResourceLinks.AvailablePluginLinks(pathInfo)); - lenient().when(resourceLinks.uiPluginCollection()).thenReturn(new ResourceLinks.UIPluginCollectionLinks(pathInfo)); - lenient().when(resourceLinks.uiPlugin()).thenReturn(new ResourceLinks.UIPluginLinks(pathInfo)); - lenient().when(resourceLinks.authentication()).thenReturn(new ResourceLinks.AuthenticationLinks(pathInfo)); - lenient().when(resourceLinks.index()).thenReturn(new ResourceLinks.IndexLinks(pathInfo)); - lenient().when(resourceLinks.permissions()).thenReturn(new ResourceLinks.PermissionsLinks(pathInfo)); - lenient().when(resourceLinks.repositoryVerbs()).thenReturn(new ResourceLinks.RepositoryVerbLinks(pathInfo)); - lenient().when(resourceLinks.repositoryRole()).thenReturn(new ResourceLinks.RepositoryRoleLinks(pathInfo)); - lenient().when(resourceLinks.repositoryRoleCollection()).thenReturn(new ResourceLinks.RepositoryRoleCollectionLinks(pathInfo)); - lenient().when(resourceLinks.namespaceStrategies()).thenReturn(new ResourceLinks.NamespaceStrategiesLinks(pathInfo)); - lenient().when(resourceLinks.annotate()).thenReturn(new ResourceLinks.AnnotateLinks(pathInfo)); - lenient().when(resourceLinks.namespace()).thenReturn(new ResourceLinks.NamespaceLinks(pathInfo)); - lenient().when(resourceLinks.namespaceCollection()).thenReturn(new ResourceLinks.NamespaceCollectionLinks(pathInfo)); - lenient().when(resourceLinks.namespacePermission()).thenReturn(new ResourceLinks.NamespacePermissionLinks(pathInfo)); - lenient().when(resourceLinks.adminInfo()).thenReturn(new ResourceLinks.AdminInfoLinks(pathInfo)); - lenient().when(resourceLinks.apiKeyCollection()).thenReturn(new ResourceLinks.ApiKeyCollectionLinks(pathInfo)); - lenient().when(resourceLinks.apiKey()).thenReturn(new ResourceLinks.ApiKeyLinks(pathInfo)); - lenient().when(resourceLinks.search()).thenReturn(new ResourceLinks.SearchLinks(pathInfo)); - lenient().when(resourceLinks.branchDetails()).thenReturn(new ResourceLinks.BranchDetailsLinks(pathInfo)); - lenient().when(resourceLinks.branchDetailsCollection()).thenReturn(new ResourceLinks.BranchDetailsCollectionLinks(pathInfo)); - - return resourceLinks; + ResourceLinks resourceLinks = new ResourceLinks(scmPathInfoStore); + return spy(resourceLinks); } }