mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-22 02:18:26 +00:00
Add attachment preview url based on ViewerJS
The viewerJS library can display PDF files easily using pdfjs. Another attachment route redirects to the viewerjs application to display the current attachment. The attachment responses have been improved in that now the response headers are added to all responses. Additional a HEAD route has been added to support the viewerJS application.
This commit is contained in:
@ -3,17 +3,18 @@ package docspell.restserver.routes
|
||||
import cats.data.NonEmptyList
|
||||
import cats.effect._
|
||||
import cats.implicits._
|
||||
import org.http4s._
|
||||
import org.http4s.dsl.Http4sDsl
|
||||
import org.http4s.headers._
|
||||
import org.http4s.headers.ETag.EntityTag
|
||||
import org.http4s.circe.CirceEntityEncoder._
|
||||
import docspell.backend.BackendApp
|
||||
import docspell.backend.auth.AuthToken
|
||||
import docspell.backend.ops.OItem
|
||||
import docspell.common.Ident
|
||||
import org.http4s.{Header, HttpRoutes, MediaType, Response}
|
||||
import org.http4s.dsl.Http4sDsl
|
||||
import org.http4s.headers._
|
||||
import org.http4s.circe.CirceEntityEncoder._
|
||||
import docspell.restapi.model._
|
||||
import docspell.restserver.conv.Conversions
|
||||
import org.http4s.headers.ETag.EntityTag
|
||||
import docspell.restserver.webapp.Webjars
|
||||
|
||||
object AttachmentRoutes {
|
||||
|
||||
@ -21,28 +22,52 @@ object AttachmentRoutes {
|
||||
val dsl = new Http4sDsl[F] {}
|
||||
import dsl._
|
||||
|
||||
def makeByteResp(data: OItem.AttachmentData[F]): F[Response[F]] = {
|
||||
def withResponseHeaders(resp: F[Response[F]])(data: OItem.AttachmentData[F]): F[Response[F]] = {
|
||||
val mt = MediaType.unsafeParse(data.meta.mimetype.asString)
|
||||
val ctype = `Content-Type`(mt)
|
||||
val cntLen: Header = `Content-Length`.unsafeFromLong(data.meta.length)
|
||||
val eTag: Header = ETag(data.meta.checksum)
|
||||
val disp: Header =
|
||||
`Content-Disposition`("inline", Map("filename" -> data.ra.name.getOrElse("")))
|
||||
Ok(data.data.take(data.meta.length)).map(r =>
|
||||
r.withContentType(`Content-Type`(mt)).withHeaders(cntLen, eTag, disp)
|
||||
|
||||
resp.map(r =>
|
||||
if (r.status == NotModified) r.withHeaders(ctype, eTag, disp)
|
||||
else r.withHeaders(ctype, cntLen, eTag, disp)
|
||||
)
|
||||
}
|
||||
|
||||
def makeByteResp(data: OItem.AttachmentData[F]): F[Response[F]] =
|
||||
withResponseHeaders(Ok(data.data.take(data.meta.length)))(data)
|
||||
|
||||
HttpRoutes.of {
|
||||
case HEAD -> Root / Ident(id) =>
|
||||
for {
|
||||
fileData <- backend.item.findAttachment(id, user.account.collective)
|
||||
resp <- fileData
|
||||
.map(data => withResponseHeaders(Ok())(data))
|
||||
.getOrElse(NotFound(BasicResult(false, "Not found")))
|
||||
} yield resp
|
||||
|
||||
case req @ GET -> Root / Ident(id) =>
|
||||
for {
|
||||
fileData <- backend.item.findAttachment(id, user.account.collective)
|
||||
inm = req.headers.get(`If-None-Match`).flatMap(_.tags)
|
||||
matches = matchETag(fileData, inm)
|
||||
resp <- if (matches) NotModified()
|
||||
else
|
||||
fileData.map(makeByteResp).getOrElse(NotFound(BasicResult(false, "Not found")))
|
||||
resp <- fileData
|
||||
.map({ data =>
|
||||
if (matches) withResponseHeaders(NotModified())(data)
|
||||
else makeByteResp(data)
|
||||
})
|
||||
.getOrElse(NotFound(BasicResult(false, "Not found")))
|
||||
} yield resp
|
||||
|
||||
case GET -> Root / Ident(id) / "view" =>
|
||||
// this route exists to provide a stable url
|
||||
// it redirects currently to viewerjs
|
||||
val attachUrl = s"/api/v1/sec/attachment/${id.id}"
|
||||
val path = s"/app/assets${Webjars.viewerjs}/ViewerJS/index.html#$attachUrl"
|
||||
SeeOther(Location(Uri(path = path)))
|
||||
|
||||
case GET -> Root / Ident(id) / "meta" =>
|
||||
for {
|
||||
rm <- backend.item.findAttachmentMeta(id, user.account.collective)
|
||||
|
Reference in New Issue
Block a user