study move comments WIP
parent
ba4a9aab23
commit
29c53ae936
|
@ -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] {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
package lila.study
|
||||
|
||||
import lila.user.User
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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))))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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 =>
|
||||
|
|
Loading…
Reference in New Issue