upload ublog images towards picfit (yay!)

pull/9705/head
Thibault Duplessis 2021-08-30 18:57:03 +02:00
parent 1fc9315ad3
commit 266f03945b
7 changed files with 85 additions and 51 deletions

View File

@ -8,7 +8,7 @@ import lila.ublog.UblogPost
final class Ublog(env: Env) extends LilaController(env) {
import views.html.ublog.post.urlOf
import views.html.ublog.post.{ editUrlOf, urlOf }
def index(username: String, page: Int) = Open { implicit ctx =>
OptionFuOk(env.user.repo named username) { user =>
@ -80,43 +80,17 @@ final class Ublog(env: Env) extends LilaController(env) {
}
}
// private val handleFilePartAsFile: play.core.parsers.Multipart.FilePartHandler[java.io.File] = {
// case Multipart.FileInfo(partName, filename, contentType, dispositionType) =>
// val perms = java.util.EnumSet.of(OWNER_READ, OWNER_WRITE)
// val attr = PosixFilePermissions.asFileAttribute(perms)
// val path = JFiles.createTempFile("multipartBody", "tempFile", attr)
// val file = path.toFile
// val fileSink = FileIO.toPath(path)
// val accumulator = Accumulator(fileSink)
// accumulator.map { case IOResult(count, status) =>
// FilePart(partName, filename, contentType, file, count, dispositionType)
// }(ec)
// }
import play.api.mvc.BodyParser
import akka.stream.scaladsl.Source
import akka.util.ByteString
import play.api.libs.streams.Accumulator
def verbatimBodyParser: BodyParser[Source[ByteString, _]] = BodyParser { _ =>
// Return the source directly. We need to return
// an Accumulator[Either[Result, T]], so if we were
// handling any errors we could map to something like
// a Left(BadRequest("error")). Since we're not
// we just wrap the source in a Right(...)
Accumulator.source[ByteString].map(Right.apply)
}
def image(unusedUsername: String, id: String) =
AuthBody(parse.multipartFormData(handleFilePartAsFile)) { implicit ctx => me =>
AuthBody(parse.multipartFormData) { implicit ctx => me =>
env.ublog.api.findByAuthor(UblogPost.Id(id), me) flatMap {
_ ?? { post =>
ctx.body.body.file("image") match {
case FilePart(key, filename, contentType, file, fileSize, dispositionType) =>
case Some(image) =>
env.ublog.api.uploadImage(post, image) recover { case e: Exception =>
BadRequest(html.ublog.form.edit(me, post, env.ublog.form.edit(post)))
.flashFailure(e.getMessage)
} inject Redirect(routes.Streamer.edit)
case None => fuccess(Redirect(routes.Streamer.edit))
} inject Redirect(editUrlOf(post))
case None => fuccess(Redirect(editUrlOf(post)))
}
}
}

View File

@ -12,6 +12,8 @@ import lila.user.User
object form {
import views.html.ublog.{ post => postView }
def create(user: User, f: Form[UblogPostData])(implicit ctx: Context) =
views.html.base.layout(
moreCss = frag(cssTag("ublog")),
@ -33,10 +35,29 @@ object form {
div(cls := "ublog-post-form__publish")(
p(if (post.live) "This post is published" else "This is a draft")
),
imageForm(user, post),
inner(user, f, post.some)
)
}
private def imageForm(user: User, post: UblogPost)(implicit ctx: Context) =
postForm(
cls := "ublog-post-form__image",
action := routes.Ublog.image(user.username, post.id.value),
enctype := "multipart/form-data"
)(
form3.split(
div(cls := "form-group form-half")(
postView.imageOf(post)
),
div(cls := "form-group form-half")(
p(trans.streamer.maxSize(s"${lila.memo.PicfitApi.uploadMaxMb}MB.")),
form3.file.image("image"),
submitButton(cls := "button")(trans.streamer.uploadPicture())
)
)
)
private def inner(user: User, form: Form[UblogPostData], post: Option[UblogPost])(implicit
ctx: Context
) =

View File

@ -57,4 +57,24 @@ object post {
def urlOf(post: UblogPost) = routes.Ublog.post(usernameOrId(post.user), post.slug, post.id.value)
def editUrlOf(post: UblogPost) = routes.Ublog.edit(usernameOrId(post.user), post.id.value)
def imageOf(post: UblogPost, size: Int = 300) =
post.image match {
// case Some(image) =>
// img(
// width := size,
// height := size,
// cls := "picture",
// src := dbImageUrl(path.value),
// alt := s"${u.titleUsername} Lichess streamer picture"
// )
case _ =>
img(
width := size,
height := size,
cls := "default image",
src := assetUrl("images/placeholder.png"),
alt := "Default blog post image"
)
}
}

View File

@ -387,7 +387,7 @@ memo {
}
picfit {
collection = picfit_image
endpoint = "127.0.0.1:3001"
endpoint = "http://127.0.0.1:3001"
}
}
redis {

View File

@ -1,10 +1,12 @@
package lila.memo
import java.nio.file.Path
import akka.stream.scaladsl.{ FileIO, Source }
import akka.util.ByteString
import org.joda.time.DateTime
import play.api.libs.ws.StandaloneWSClient
import play.api.mvc.MultipartFormData
import reactivemongo.api.bson.Macros
import scala.concurrent.ExecutionContext
import play.api.libs.ws.StandaloneWSClient
import lila.db.dsl._
@ -38,8 +40,9 @@ final class PicfitApi(coll: Coll, ws: StandaloneWSClient, endpoint: String)(impl
if (uploaded.fileSize > uploadMaxBytes)
fufail(s"File size must not exceed ${uploadMaxMb}MB.")
else {
import WSBodyWritables._
val image = PicfitImage(
_id = PicfitImage.Id(lila.common.ThreadLocalRandom nextString 8),
_id = PicfitImage.Id(lila.common.ThreadLocalRandom nextString 10),
user = userId,
scope = scope,
name = sanitizeName(uploaded.filename),
@ -47,23 +50,20 @@ final class PicfitApi(coll: Coll, ws: StandaloneWSClient, endpoint: String)(impl
size = uploaded.fileSize.toInt,
createdAt = DateTime.now
)
// ws.url(s"$endpoint/upload")
// .post(
// Source(
// FilePart(
// "File",
// fileName,
// Option("application/pdf"),
// FileIO.fromPath(Paths.get(pathToFile))
// ) :: List()
// )
// )
// .post(body(source)) flatMap {
// case res if res.status != 200 =>
// fufail(res.statusText)
// case res => funit
// } >>
coll.insert.one(image) inject image
type Part = MultipartFormData.FilePart[Source[ByteString, _]]
val part: Part = MultipartFormData.FilePart(
key = "data",
filename = image.id.value,
contentType = uploaded.contentType,
ref = FileIO.fromPath(uploaded.ref.path),
fileSize = uploaded.fileSize
)
val source: Source[Part, _] = Source(part :: List())
ws.url(s"$endpoint/upload").post(source).flatMap {
case res if res.status != 200 => fufail(res.statusText)
case _ => funit
} >>
coll.insert.one(image) inject image
}
private def sanitizeName(name: String) = {
@ -77,4 +77,17 @@ object PicfitApi {
val uploadMaxMb = 4
type Uploaded = play.api.mvc.MultipartFormData.FilePart[play.api.libs.Files.TemporaryFile]
// from playframework/transport/client/play-ws/src/main/scala/play/api/libs/ws/WSBodyWritables.scala
object WSBodyWritables {
import play.api.libs.ws.BodyWritable
import play.api.libs.ws.SourceBody
import play.core.formatters.Multipart
implicit val bodyWritableOf_Multipart
: BodyWritable[Source[MultipartFormData.Part[Source[ByteString, _]], _]] = {
val boundary = Multipart.randomBoundary()
val contentType = s"multipart/form-data; boundary=$boundary"
BodyWritable(b => SourceBody(Multipart.transform(b, boundary)), contentType)
}
}
}

View File

@ -1,3 +1,4 @@
@import '../../../common/css/plugin';
@import '../../../common/css/form/form3';
@import '../ublog/ublog';
@import '../ublog/form';

View File

@ -0,0 +1,5 @@
.ublog-post-form {
&__publish {
margin: 3vh 0;
}
}