jove.notebook.services.Contents.scala Maven / Gradle / Ivy
The newest version!
package jove
package notebook
package services
import java.io.{PrintWriter, File}
import java.nio.file.Files
import jove.helpers.Kernels
import jove.notebook.Protocol.CheckPoint
import jove.notebook.components.Content
import org.http4s.dsl._
import org.joda.time.DateTime
import org.http4s.argonaut._
import argonaut._, Argonaut._, Shapeless._
import scalaz._, Scalaz._
object Contents extends LazyLogging {
def apply(content: Content, kernel: Kernels): Plan = {
object Content extends PrefixedDecodedPath(Root / "api" / "contents");
def get(path: List[String]) =
if (path.lastOption == Some("checkpoints"))
for {
f <- content.fileFor(path dropRight 1)
cp = content.checkpointFile(f, content.checkpointId)
lastModifiedOpt <- \/.fromTryCatchNonFatal {
if (cp.exists())
Some(new DateTime(cp.lastModified()))
else
None
} .leftMap(_.toString)
} yield {
lastModifiedOpt match {
case Some(lm) =>
List(CheckPoint(content.checkpointId, lm.toString))
case None =>
Nil
}
} .asJson
else
// FIXME Set Location & Last-Modified in response
content.model(path, withContent = true).map(_.asJson)
def post(path: List[String], reqJsonOpt: Option[Json]) =
if (path.lastOption == Some("checkpoints"))
for {
f <- content.fileFor(path dropRight 1)
cp = content.checkpointFile(f, content.checkpointId)
_ <- \/.fromTryCatchNonFatal {
val par = cp.getParentFile
if (!par.exists())
par.mkdirs()
cp.delete()
Files.copy(f.toPath, cp.toPath)
} .leftMap(_.toString)
lastModified <- \/.fromTryCatchNonFatal {
new DateTime(cp.lastModified())
} .leftMap(_.toString)
} yield
List(CheckPoint(content.checkpointId, lastModified.toString)).asJson
else {
val reqJson = reqJsonOpt getOrElse Json.obj()
val _type = (reqJson.hcursor --\ "type").as[String].result getOrElse "file"
val extOpt = (reqJson.hcursor --\ "ext").as[String].result.toOption orElse {
for {
() <- Some(()) if _type == "notebook"
kernelId <- (reqJson.hcursor --\ "kernel_name").as[String].result.toOption.filter(_.nonEmpty) orElse kernel.defaultKernel
(info, _) <- kernel.kernelsWithInfo.get(kernelId)
ext <- info.extensions.headOption
} yield ext
}
for {
d <- content.fileFor(path).flatMap(f => if (f.isDirectory) \/-(f) else -\/("Not a directory"))
name = content.newIn(d, _type, extOpt, count = 0)
m <- content.model(new File(d, name), path :+ name, withContent = false)
} yield m.asJson
}
{
case GET -> Root / "api" / "contents" =>
get(Nil)
case req @ (POST -> Root / "api" / "contents") =>
req.decode[Option[Json]] { reqJsonOpt =>
post(Nil, reqJsonOpt)
}
case GET -> Content(path) =>
get(path)
case req @ (PUT -> Content(path)) =>
// FIXME Handle form content or query string params?
req.decode[Option[Json]] { reqJsonOpt =>
for {
f <- content.fileFor(path)
_type = reqJsonOpt.flatMap(_.hcursor.--\("type").as[String].result.toOption) getOrElse "file"
_ <- \/.fromTryCatchNonFatal {
if (!f.exists()) content.create(_type, f)
}.leftMap(_.toString)
contentOpt <- {
if (_type == "directory")
\/-(None)
else
reqJsonOpt.flatMap(_.hcursor.--\("content").focus.map(_.spaces2)).toRightDisjunction("No content").map(Some(_))
}
_ <- \/.fromTryCatchNonFatal {
for (content <- contentOpt) {
val w = new PrintWriter(f)
w write content
w.close()
}
}.leftMap(_.toString)
m <- content.model(f, path, withContent = false)
} yield m
}
case req @ (PATCH -> Content(path)) =>
// FIXME Handle form content or query string params?
req.decode[Option[Json]] { reqJsonOpt =>
for {
source <- content.fileFor(path).flatMap(f => if (f.exists()) f.right else "File not found".left)
destPath <- reqJsonOpt.flatMap(_.hcursor.--\("path").as[String].result.toOption) toRightDisjunction "No path specified"
dest <- content.fileFor(destPath)
_ <- \/.fromTryCatchNonFatal {
Files.move(source.toPath, dest.toPath)
}.leftMap(_.toString)
m <- content.model(dest, content.splitPath(destPath), withContent = false)
} yield m
}
case req @ (POST -> Content(path)) =>
req.decode[Option[Json]] { reqJsonOpt =>
post(path, reqJsonOpt)
}
case DELETE -> Content(path) =>
for {
f <- content.fileFor(path)
_ <- \/.fromTryCatchNonFatal {
logger info s"Deleting ${f.getAbsolutePath} / ${f.getAbsoluteFile.toPath.toString}"
Files.delete(f.getAbsoluteFile.toPath)
} .leftMap(_.toString)
} yield ()
}
}
}