study move comments WIP

pull/1846/head
Thibault Duplessis 2016-04-28 13:18:45 +07:00
parent ba4a9aab23
commit 29c53ae936
9 changed files with 90 additions and 7 deletions

View File

@ -65,6 +65,10 @@ private object BSONHandlers {
private implicit val FenBSONHandler = stringAnyValHandler[FEN](_.value, FEN.apply)
import Node.Comment
private implicit val CommentBSONHandler = Macros.handler[Comment]
private implicit val SymbolBSONHandler = stringAnyValHandler[Node.Symbol](_.value, Node.Symbol.apply)
private implicit def NodeBSONHandler: BSON[Node] = new BSON[Node] {
def reads(r: Reader) = Node(
id = r.get[UciCharPair]("i"),
@ -73,6 +77,8 @@ private object BSONHandlers {
fen = r.get[FEN]("f"),
check = r boolD "c",
shapes = r.getsD[Shape]("h"),
comments = Node.Comments(r.getsD[Node.Comment]("co")),
symbols = r.getsD[Node.Symbol]("sy"),
by = r str "b",
children = r.get[Node.Children]("n"))
def writes(w: Writer, s: Node) = BSONDocument(
@ -83,6 +89,8 @@ private object BSONHandlers {
"f" -> s.fen,
"c" -> w.boolO(s.check),
"h" -> w.listO(s.shapes),
"co" -> w.listO(s.comments.list),
"sy" -> w.listO(s.symbols),
"b" -> s.by,
"n" -> s.children)
}
@ -93,12 +101,16 @@ private object BSONHandlers {
fen = r.get[FEN]("f"),
check = r boolD "c",
shapes = r.getsD[Shape]("h"),
comments = Node.Comments(r.getsD[Node.Comment]("co")),
symbols = r.getsD[Node.Symbol]("sy"),
children = r.get[Node.Children]("n"))
def writes(w: Writer, s: Root) = BSONDocument(
"p" -> s.ply,
"f" -> s.fen,
"c" -> w.boolO(s.check),
"h" -> w.listO(s.shapes),
"co" -> w.listO(s.comments.list),
"sy" -> w.listO(s.symbols),
"n" -> s.children)
}
implicit val ChildrenBSONHandler = new BSONHandler[BSONArray, Node.Children] {

View File

@ -29,6 +29,9 @@ case class Chapter(
def setShapes(shapes: List[Shape], path: Path): Option[Chapter] =
updateRoot(_.setShapesAt(shapes, path))
def setComment(comment: Node.Comment, path: Path): Option[Chapter] =
updateRoot(_.setCommentAt(comment, path))
def opening: Option[FullOpening] =
if (!Variant.openingSensibleVariants(setup.variant)) none
else FullOpeningDB searchInFens root.mainLine.map(_.fen)

View File

@ -37,13 +37,11 @@ private final class ChapterMaker(domain: String, importer: Importer) {
ply = sit.turns,
fen = FEN(Forsyth.>>(sit)),
check = sit.situation.check,
shapes = Nil,
children = Node.emptyChildren)
case None => Node.Root(
ply = 0,
fen = FEN(variant.initialFen),
check = false,
shapes = Nil,
children = Node.emptyChildren)
}
Chapter.make(

View File

@ -0,0 +1,3 @@
package lila.study
import lila.user.User

View File

@ -38,6 +38,13 @@ object JsonView {
private[study] implicit val visibilityWriter = Writes[Study.Visibility] { v =>
JsString(v.key)
}
private[study] implicit val symbolWriter: Writes[Node.Symbol] = Writes[Node.Symbol] { s =>
JsString(s.value)
}
private[study] implicit val commentWriter = Json.writes[Node.Comment]
private[study] implicit val commentsWriter: Writes[Node.Comments] = Writes[Node.Comments] { s =>
JsArray(s.list.map(commentWriter.writes))
}
private implicit val rootWrites = Writes[Node.Root] { n =>
Json.obj(
@ -45,6 +52,8 @@ object JsonView {
"fen" -> n.fen,
"check" -> n.check,
"shapes" -> n.shapes,
"comments" -> n.comments,
"symbols" -> n.symbols,
"children" -> n.children.nodes)
}
@ -97,6 +106,8 @@ object JsonView {
"fen" -> fenWriter.writes(n.fen),
"check" -> n.check,
"shapes" -> n.shapes,
"comments" -> n.comments,
"symbols" -> n.symbols,
"by" -> n.by,
"children" -> n.children.nodes)
}

View File

@ -12,6 +12,8 @@ sealed trait RootOrNode {
val check: Boolean
val shapes: List[Shape]
val children: Node.Children
val comments: Node.Comments
val symbols: List[Node.Symbol]
def fullMoveNumber = 1 + ply / 2
}
@ -21,7 +23,9 @@ case class Node(
move: Uci.WithSan,
fen: FEN,
check: Boolean,
shapes: List[Shape],
shapes: List[Shape] = Nil,
comments: Node.Comments = Node.Comments(Nil),
symbols: List[Node.Symbol] = Nil,
by: User.ID,
children: Node.Children) extends RootOrNode {
@ -32,11 +36,27 @@ case class Node(
copy(children = newChildren)
}
def setComment(comment: Node.Comment) = copy(comments = comments set comment)
def mainLine: List[Node] = this :: children.first.??(_.mainLine)
}
object Node {
case class Comment(text: String, by: User.ID)
case class Comments(value: List[Comment]) extends AnyVal {
def list = value
def by(userId: User.ID) = list.find(_.by == userId)
def set(comment: Comment) = Comments {
if (by(comment.by).isDefined) list.map {
case c if c.by == comment.by => comment
case c => c
}
else list :+ comment
}
}
case class Symbol(value: String) extends AnyVal
case class Children(nodes: Vector[Node]) {
def first = nodes.headOption
@ -77,6 +97,12 @@ object Node {
case Some((head, tail)) => updateChildren(head, _.setShapesAt(shapes, tail))
}
def setCommentAt(comment: Comment, path: Path): Option[Children] = path.split match {
case None => none
case Some((head, Path(Nil))) => updateWith(head, _.setComment(comment).some)
case Some((head, tail)) => updateChildren(head, _.setCommentAt(comment, tail))
}
def get(id: UciCharPair): Option[Node] = nodes.find(_.id == id)
def has(id: UciCharPair): Boolean = nodes.exists(_.id == id)
@ -99,7 +125,9 @@ object Node {
ply: Int,
fen: FEN,
check: Boolean,
shapes: List[Shape],
shapes: List[Shape] = Nil,
comments: Comments = Comments(Nil),
symbols: List[Symbol] = Nil,
children: Children) extends RootOrNode {
def withChildren(f: Children => Option[Children]) =
@ -116,6 +144,10 @@ object Node {
if (path.isEmpty) copy(shapes = shapes).some
else withChildren(_.setShapesAt(shapes, path))
def setCommentAt(comment: Comment, path: Path): Option[Root] =
if (path.isEmpty) copy(comments = comments set comment).some
else withChildren(_.setCommentAt(comment, path))
def mainLine: List[Node] = children.first.??(_.mainLine)
def mainLineLastNodePath = Path(mainLine.map(_.id))
@ -127,14 +159,12 @@ object Node {
ply = 0,
fen = FEN(Forsyth.initial),
check = false,
shapes = Nil,
children = emptyChildren)
def fromRootBy(userId: User.ID)(b: lila.socket.tree.Root): Root = Root(
ply = b.ply,
fen = FEN(b.fen),
check = b.check,
shapes = Nil,
children = Children(b.children.toVector.map(fromBranchBy(userId))))
}
@ -144,7 +174,6 @@ object Node {
move = b.move,
fen = FEN(b.fen),
check = b.check,
shapes = Nil,
by = userId,
children = Children(b.children.toVector.map(fromBranchBy(userId))))
}

View File

@ -68,6 +68,11 @@ private final class Socket(
"w" -> who(uid)
), Messadata())
case SetComment(pos, comment) => notifyVersion("comment", Json.obj(
"p" -> pos,
"c" -> comment
), Messadata())
case lila.chat.actorApi.ChatLine(_, line) => line match {
case line: lila.chat.UserLine =>
notifyVersion("message", lila.chat.JsonView(line), Messadata(trollish = line.troll))
@ -140,6 +145,7 @@ private object Socket {
case class SetPath(position: Position.Ref, uid: Uid)
case class ReloadMembers(members: StudyMembers)
case class SetShapes(position: Position.Ref, shapes: List[Shape], uid: Uid)
case class SetComment(position: Position.Ref, comment: Node.Comment)
case class ReloadChapters(chapters: List[Chapter.Metadata])
case object ReloadAll
case object ChangeChapter

View File

@ -156,6 +156,15 @@ private[study] final class SocketHandler(
api.editStudy(byUserId, studyId, data)
}
}
case ("comment", o) =>
reading[AtPosition](o) { position =>
(o \ "d" \ "text").asOpt[String] foreach { text =>
member.userId foreach { userId =>
api.setComment(userId, studyId, position.ref, text)
}
}
}
}
private def reading[A](o: JsValue)(f: A => Unit)(implicit reader: Reads[A]): Unit =

View File

@ -148,6 +148,18 @@ final class StudyApi(
}
}
def setComment(userId: User.ID, studyId: Study.ID, position: Position.Ref, text: String) = sequenceStudyWithChapter(studyId) {
case Study.WithChapter(study, chapter) => Contribute(userId, study) {
val comment = Node.Comment(text = escapeHtml4(text.take(2000)), by = userId)
chapter.setComment(comment, position.path) match {
case Some(newChapter) =>
chapterRepo.update(newChapter) >>-
sendTo(study.id, Socket.SetComment(position, comment))
case None => fufail(s"Invalid setComment $studyId $position")
}
}
}
def addChapter(byUserId: User.ID, studyId: Study.ID, data: ChapterMaker.Data, socket: ActorRef) = sequenceStudy(studyId) { study =>
(study isOwner byUserId) ?? {
chapterRepo.nextOrderByStudy(study.id) flatMap { order =>