Skip to content

Commit

Permalink
GH-2200 Display directory index for Ivy (Resolve #2176)
Browse files Browse the repository at this point in the history
* dir index

* filter files
  • Loading branch information
dzikoysk committed Aug 18, 2024
1 parent 647bb7f commit 0b0fc2b
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class FrontendFacade internal constructor(
) : Facade {

private val resources = HashMap<String, ResourceSupplier>(0)
private val formattedBasePath = basePath.computed { BasePathFormatter.formatBasePath(it) }
val formattedBasePath = basePath.computed { BasePathFormatter.formatBasePath(it) }

init {
computed(basePath, formattedBasePath, frontendSettings) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import com.reposilite.storage.api.FileDetails
import com.reposilite.storage.api.Location
import com.reposilite.token.AccessTokenIdentifier
import panda.std.Result
import java.io.InputStream

class MavenFacade internal constructor(
private val journalist: Journalist,
Expand All @@ -54,6 +55,9 @@ class MavenFacade internal constructor(
fun findFile(lookupRequest: LookupRequest): Result<ResolvedDocument, ErrorResponse> =
repositoryService.findFile(lookupRequest)

fun findData(lookupRequest: LookupRequest): Result<InputStream, ErrorResponse> =
repositoryService.findInputStream(lookupRequest)

fun deployFile(deployRequest: DeployRequest): Result<Unit, ErrorResponse> =
repositoryService.deployFile(deployRequest)

Expand Down Expand Up @@ -84,10 +88,24 @@ class MavenFacade internal constructor(
handler = handler
)

fun getAvailableFiles(request: LookupRequest, directoryInfo: DirectoryInfo): List<FileDetails> =
getRepository(request.repository)!!.let { repository ->
directoryInfo.files.filter {
repositorySecurityProvider.canBrowseResource(
accessToken = request.accessToken,
repository = repository,
gav = request.gav.resolve(it.name)
).isOk
}
}

fun createLatestBadge(lookupRequest: LatestBadgeRequest): Result<String, ErrorResponse> =
findLatestVersion(lookupRequest.toVersionLookupRequest())
.flatMap { latestService.createLatestBadge(lookupRequest, it.version) }

fun acceptsCachingOf(request: LookupRequest): Boolean =
getRepository(request.repository)?.acceptsCachingOf(request.gav) ?: false

fun canAccessResource(accessToken: AccessTokenIdentifier?, repository: Repository, gav: Location): Result<Unit, ErrorResponse> =
repositorySecurityProvider.canAccessResource(accessToken, repository, gav)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import com.reposilite.maven.api.ResolvedDocument
import com.reposilite.maven.api.ResolvedFileEvent
import com.reposilite.plugin.Extensions
import com.reposilite.shared.ErrorResponse
import com.reposilite.shared.badRequestError
import com.reposilite.shared.errorResponse
import com.reposilite.shared.notFound
import com.reposilite.shared.notFoundError
Expand Down Expand Up @@ -114,8 +113,7 @@ internal class RepositoryService(

fun findFile(lookupRequest: LookupRequest): Result<ResolvedDocument, ErrorResponse> =
resolve(lookupRequest) { repository, gav ->
findFile(lookupRequest.accessToken, repository, gav).map {
val (details, stream) = it
findFile(lookupRequest.accessToken, repository, gav).map { (details, stream) ->
ResolvedDocument(
document = details,
cachable = repository.acceptsCachingOf(gav),
Expand Down Expand Up @@ -144,6 +142,9 @@ internal class RepositoryService(
.flatMap { details -> findInputStream(repository, gav).map { details to it } }
.let { extensions.emitEvent(ResolvedFileEvent(accessToken, repository, gav, it)).result }

fun findInputStream(lookupRequest: LookupRequest): Result<InputStream, ErrorResponse> =
resolve(lookupRequest) { repository, gav -> findInputStream(repository, gav) }

private fun findInputStream(repository: Repository, gav: Location): Result<InputStream, ErrorResponse> =
when {
mirrorService.shouldPrioritizeMirrorRepository(repository, gav) -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.reposilite.maven.infrastructure

import com.reposilite.storage.api.FileDetails
import com.reposilite.storage.api.FileType

internal fun createDirectoryIndexPage(basePath: String, uri: String, authenticatedFiles: List<FileDetails>): String {
val formattedUri = basePath + uri.removePrefix("/")

// language=html
return """
<!DOCTYPE html>
<html lang='en'>
<head>
<title>Index of $formattedUri</title>
<meta charset='utf-8'>
<style>
li {
padding: 2px 10px;
}
.back::marker {
content: '🔙';
}
.directory::marker {
content: '📁';
}
.file::marker {
content: '📄';
}
</style>
</head>
<body>
<h1>Index of $formattedUri</h1>
<ul>
<li class='back'>
<a href='${formattedUri.substringBeforeLast("/")}'>Parent Directory</a>
</li>
${authenticatedFiles.flatMap {
listOf(
"<li class='${it.type.name.lowercase()}'>",
"<a href='$formattedUri/${it.name}'>${it.name}${if (it.type == FileType.DIRECTORY) "/" else ""}</a>",
"</li>"
)
}.joinToString(separator = "")}
</ul>
</body>
</html>
""".trimIndent()
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ import com.reposilite.maven.MavenFacade
import com.reposilite.maven.api.DeleteRequest
import com.reposilite.maven.api.DeployRequest
import com.reposilite.maven.api.LookupRequest
import com.reposilite.shared.ErrorResponse
import com.reposilite.shared.extensions.resultAttachment
import com.reposilite.shared.extensions.uri
import com.reposilite.storage.api.DirectoryInfo
import com.reposilite.storage.api.DocumentInfo
import com.reposilite.storage.api.FileType
import com.reposilite.storage.api.Location
import com.reposilite.token.AccessTokenIdentifier
import com.reposilite.web.api.ReposiliteRoute
Expand All @@ -31,13 +35,15 @@ import io.javalin.community.routing.Route.GET
import io.javalin.community.routing.Route.HEAD
import io.javalin.community.routing.Route.POST
import io.javalin.community.routing.Route.PUT
import io.javalin.http.ContentType
import io.javalin.http.Context
import io.javalin.openapi.ContentType.FORM_DATA_MULTIPART
import io.javalin.openapi.HttpMethod
import io.javalin.openapi.OpenApi
import io.javalin.openapi.OpenApiContent
import io.javalin.openapi.OpenApiParam
import io.javalin.openapi.OpenApiResponse
import panda.std.Result

const val X_GENERATE_CHECKSUMS = "X-Generate-Checksums"

Expand Down Expand Up @@ -70,25 +76,43 @@ internal class MavenEndpoints(
}
}

fun findFile(ctx: Context, identifier: AccessTokenIdentifier?, repository: String, gav: Location) {
LookupRequest(identifier, repository, gav)
.let { request -> mavenFacade.findFile(request) }
.peek {
ctx.resultAttachment(
name = it.document.name,
contentType = it.document.contentType,
contentLength = it.document.contentLength,
lastTimeModified = it.document.lastModifiedTime,
compressionStrategy = compressionStrategy,
cache = it.cachable,
data = it.content
)
}
.onError {
ctx.status(it.status).html(frontendFacade.createNotFoundPage(ctx.uri(), it.message))
mavenFacade.logger.debug("FIND | Could not find file due to $it")
}
}
fun findFile(ctx: Context, identifier: AccessTokenIdentifier?, repository: String, gav: Location): Result<Any, ErrorResponse> =
LookupRequest(accessToken = identifier, repository = repository, gav = gav).let { request ->
mavenFacade
.findDetails(request)
.map { details ->
when (details) {
is DocumentInfo ->
mavenFacade
.findData(request)
.peek {
ctx.resultAttachment(
name = details.name,
contentType = details.contentType,
contentLength = details.contentLength,
lastTimeModified = details.lastModifiedTime,
compressionStrategy = compressionStrategy,
cache = mavenFacade.acceptsCachingOf(request),
data = it,
)
}
is DirectoryInfo ->
ctx.html(
createDirectoryIndexPage(
basePath = frontendFacade.formattedBasePath.get(),
uri = ctx.uri(),
authenticatedFiles = mavenFacade.getAvailableFiles(request, details),
)
)
else ->
throw IllegalStateException("Expected file details, but got $details")
}
}
.onError {
ctx.status(it.status).html(frontendFacade.createNotFoundPage(ctx.uri(), it.message))
mavenFacade.logger.debug("FIND | Could not find file due to $it")
}
}

@OpenApi(
tags = [ "Maven" ],
Expand Down

0 comments on commit 0b0fc2b

Please sign in to comment.