typesafe study chapter id
This commit is contained in:
parent
8821c2b7ae
commit
127399efe8
|
@ -8,7 +8,7 @@ import lila.api.Context
|
|||
import lila.app._
|
||||
import lila.common.HTTPRequest
|
||||
import lila.study.Study.WithChapter
|
||||
import lila.study.{ Order, Study => StudyModel }
|
||||
import lila.study.{ Chapter, Order, Study => StudyModel }
|
||||
import views._
|
||||
|
||||
object Study extends LilaController {
|
||||
|
@ -277,4 +277,5 @@ object Study extends LilaController {
|
|||
study.isPublic || ctx.userId.exists(study.members.contains)
|
||||
|
||||
private implicit def makeStudyId(id: String): StudyModel.Id = StudyModel.Id(id)
|
||||
private implicit def makeChapterId(id: String): Chapter.Id = Chapter.Id(id)
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<div class="embedded_study analyse cg-512">@miniBoardContent</div>
|
||||
</div>
|
||||
<footer>
|
||||
@defining(routes.Study.chapter(s.id.value, chapter.id)) { url =>
|
||||
@defining(routes.Study.chapter(s.id.value, chapter.id.value)) { url =>
|
||||
<div class="left">
|
||||
<a target="_blank" href="@url"><h1>@s.name</h1></a> <em>brought to you by <a target="_blank" href="@netBaseUrl">@netDomain</a></em>
|
||||
</div>
|
||||
|
|
|
@ -12,7 +12,7 @@ case class StudyProgress(moves: StudyProgress.ChapterNbMoves) extends AnyVal {
|
|||
|
||||
object StudyProgress {
|
||||
|
||||
type ChapterNbMoves = Map[lila.study.Chapter.ID, StudyProgress.NbMoves]
|
||||
type ChapterNbMoves = Map[lila.study.Chapter.Id, StudyProgress.NbMoves]
|
||||
|
||||
def empty = StudyProgress(moves = Map.empty)
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ object BSONHandlers {
|
|||
import Chapter._
|
||||
|
||||
implicit val StudyIdBSONHandler = stringIsoHandler[Study.Id](Study.idIso)
|
||||
implicit val ChapterIdBSONHandler = stringIsoHandler[Chapter.Id](Chapter.idIso)
|
||||
|
||||
private implicit val PosBSONHandler = new BSONHandler[BSONString, Pos] {
|
||||
def read(bsonStr: BSONString): Pos = Pos.posAt(bsonStr.value) err s"No such pos: ${bsonStr.value}"
|
||||
|
@ -209,7 +210,7 @@ object BSONHandlers {
|
|||
implicit val ChapterBSONHandler = Macros.handler[Chapter]
|
||||
implicit val ChapterMetadataBSONHandler = Macros.handler[Chapter.Metadata]
|
||||
|
||||
private implicit val ChaptersMap = BSON.MapDocument.MapHandler[Chapter.ID, Chapter]
|
||||
private implicit val ChaptersMap = BSON.MapDocument.MapHandler[Chapter.Id, Chapter]
|
||||
|
||||
implicit val PositionRefBSONHandler = new BSONHandler[BSONString, Position.Ref] {
|
||||
def read(b: BSONString) = Position.Ref.decode(b.value) err s"Invalid position ${b.value}"
|
||||
|
|
|
@ -10,7 +10,7 @@ import lila.tree.Node.{ Shapes, Comment }
|
|||
import lila.user.User
|
||||
|
||||
case class Chapter(
|
||||
_id: Chapter.ID,
|
||||
_id: Chapter.Id,
|
||||
studyId: Study.Id,
|
||||
name: String,
|
||||
setup: Chapter.Setup,
|
||||
|
@ -68,10 +68,11 @@ case class Chapter(
|
|||
|
||||
object Chapter {
|
||||
|
||||
type ID = String
|
||||
case class Id(value: String) extends AnyVal with StringValue
|
||||
implicit val idIso = lila.common.Iso.string[Id](Id.apply, _.value)
|
||||
|
||||
sealed trait Like {
|
||||
val _id: Chapter.ID
|
||||
val _id: Chapter.Id
|
||||
val name: String
|
||||
val setup: Chapter.Setup
|
||||
def id = _id
|
||||
|
@ -88,7 +89,7 @@ object Chapter {
|
|||
}
|
||||
|
||||
case class Metadata(
|
||||
_id: Chapter.ID,
|
||||
_id: Chapter.Id,
|
||||
name: String,
|
||||
setup: Chapter.Setup) extends Like
|
||||
|
||||
|
@ -96,7 +97,7 @@ object Chapter {
|
|||
def compare(that: Ply) = value - that.value
|
||||
}
|
||||
|
||||
case class FullId(studyId: Study.Id, chapterId: Chapter.ID)
|
||||
case class FullId(studyId: Study.Id, chapterId: Chapter.Id)
|
||||
|
||||
private val defaultNamePattern = """^Chapter \d+$""".r.pattern
|
||||
def isDefaultName(str: String) = defaultNamePattern.matcher(str).matches
|
||||
|
@ -105,7 +106,7 @@ object Chapter {
|
|||
|
||||
val idSize = 8
|
||||
|
||||
def makeId = scala.util.Random.alphanumeric take idSize mkString
|
||||
def makeId = Id(scala.util.Random.alphanumeric take idSize mkString)
|
||||
|
||||
def make(studyId: Study.Id, name: String, setup: Setup, root: Node.Root, tags: List[Tag], order: Int, ownerId: User.ID, practice: Boolean, conceal: Option[Ply]) = Chapter(
|
||||
_id = makeId,
|
||||
|
|
|
@ -188,7 +188,7 @@ private[study] object ChapterMaker {
|
|||
initial: Boolean) extends ChapterData
|
||||
|
||||
case class EditData(
|
||||
id: String,
|
||||
id: Chapter.Id,
|
||||
name: String,
|
||||
orientation: String,
|
||||
mode: String) extends ChapterData
|
||||
|
|
|
@ -12,15 +12,15 @@ final class ChapterRepo(coll: Coll) {
|
|||
|
||||
val noRootProjection = $doc("root" -> false)
|
||||
|
||||
def byId(id: Chapter.ID): Fu[Option[Chapter]] = coll.byId[Chapter](id)
|
||||
def byId(id: Chapter.Id): Fu[Option[Chapter]] = coll.byId[Chapter, Chapter.Id](id)
|
||||
|
||||
// def metadataById(id: Chapter.ID): Fu[Option[Chapter.Metadata]] =
|
||||
// def metadataById(id: Chapter.Id): Fu[Option[Chapter.Metadata]] =
|
||||
// coll.find($id(id), noRootProjection).one[Chapter.Metadata]
|
||||
|
||||
def deleteByStudy(s: Study): Funit = coll.remove($studyId(s.id)).void
|
||||
|
||||
def byIdAndStudy(id: Chapter.ID, studyId: Study.Id): Fu[Option[Chapter]] =
|
||||
coll.byId[Chapter](id).map { _.filter(_.studyId == studyId) }
|
||||
def byIdAndStudy(id: Chapter.Id, studyId: Study.Id): Fu[Option[Chapter]] =
|
||||
coll.byId[Chapter, Chapter.Id](id).map { _.filter(_.studyId == studyId) }
|
||||
|
||||
def firstByStudy(studyId: Study.Id): Fu[Option[Chapter]] =
|
||||
coll.find($studyId(studyId)).sort($sort asc "order").one[Chapter]
|
||||
|
@ -38,7 +38,7 @@ final class ChapterRepo(coll: Coll) {
|
|||
.cursor[Chapter](readPreference = ReadPreference.secondaryPreferred)
|
||||
.gather[List](maxChapters)
|
||||
|
||||
def sort(study: Study, ids: List[Chapter.ID]): Funit = ids.zipWithIndex.map {
|
||||
def sort(study: Study, ids: List[Chapter.Id]): Funit = ids.zipWithIndex.map {
|
||||
case (id, index) =>
|
||||
coll.updateField($studyId(study.id) ++ $id(id), "order", index + 1)
|
||||
}.sequenceFu.void
|
||||
|
@ -50,10 +50,10 @@ final class ChapterRepo(coll: Coll) {
|
|||
"order"
|
||||
) map { order => ~order + 1 }
|
||||
|
||||
def setConceal(chapterId: Chapter.ID, conceal: Chapter.Ply) =
|
||||
def setConceal(chapterId: Chapter.Id, conceal: Chapter.Ply) =
|
||||
coll.updateField($id(chapterId), "conceal", conceal).void
|
||||
|
||||
def removeConceal(chapterId: Chapter.ID) =
|
||||
def removeConceal(chapterId: Chapter.Id) =
|
||||
coll.unsetField($id(chapterId), "conceal").void
|
||||
|
||||
def setTagsFor(chapter: Chapter) =
|
||||
|
@ -84,7 +84,7 @@ final class ChapterRepo(coll: Coll) {
|
|||
|
||||
def update(c: Chapter): Funit = coll.update($id(c.id), c).void
|
||||
|
||||
def delete(id: Chapter.ID): Funit = coll.remove($id(id)).void
|
||||
def delete(id: Chapter.Id): Funit = coll.remove($id(id)).void
|
||||
def delete(c: Chapter): Funit = delete(c.id)
|
||||
|
||||
private def $studyId(id: Study.Id) = $doc("studyId" -> id)
|
||||
|
|
|
@ -94,6 +94,7 @@ object JsonView {
|
|||
case class JsData(study: JsObject, analysis: JsObject)
|
||||
|
||||
implicit val studyIdWrites: Writes[Study.Id] = stringAnyValWriter[Study.Id](_.value)
|
||||
implicit val chapterIdWrites: Writes[Chapter.Id] = stringAnyValWriter[Chapter.Id](_.value)
|
||||
|
||||
private implicit val uciWrites: Writes[Uci] = Writes[Uci] { u =>
|
||||
JsString(u.uci)
|
||||
|
|
|
@ -4,7 +4,7 @@ case class Position(chapter: Chapter, path: Path)
|
|||
|
||||
case object Position {
|
||||
|
||||
case class Ref(chapterId: Chapter.ID, path: Path) {
|
||||
case class Ref(chapterId: Chapter.Id, path: Path) {
|
||||
|
||||
def encode = s"$chapterId $path"
|
||||
|
||||
|
@ -16,8 +16,8 @@ case object Position {
|
|||
object Ref {
|
||||
|
||||
def decode(str: String): Option[Ref] = str.split(' ') match {
|
||||
case Array(chapterId, path) => Ref(chapterId, Path(path)).some
|
||||
case Array(chapterId) => Ref(chapterId, Path.root).some
|
||||
case Array(chapterId, path) => Ref(Chapter.Id(chapterId), Path(path)).some
|
||||
case Array(chapterId) => Ref(Chapter.Id(chapterId), Path.root).some
|
||||
case _ => none
|
||||
}
|
||||
}
|
||||
|
|
|
@ -241,7 +241,7 @@ private object Socket {
|
|||
case class ChangeChapter(uid: Uid)
|
||||
case class SetConceal(position: Position.Ref, ply: Option[Chapter.Ply])
|
||||
case class SetLiking(liking: Study.Liking, uid: Uid)
|
||||
case class SetTags(chapterId: Chapter.ID, tags: List[chess.format.pgn.Tag], uid: Uid)
|
||||
case class SetTags(chapterId: Chapter.Id, tags: List[chess.format.pgn.Tag], uid: Uid)
|
||||
|
||||
case class Messadata(trollish: Boolean = false)
|
||||
case object NotifyCrowd
|
||||
|
|
|
@ -60,7 +60,7 @@ private[study] final class SocketHandler(
|
|||
for {
|
||||
userId <- member.userId
|
||||
d ← o obj "d"
|
||||
chapterId <- d str "chapterId"
|
||||
chapterId <- d.get[Chapter.Id]("chapterId")
|
||||
} api.addNode(
|
||||
userId,
|
||||
studyId,
|
||||
|
@ -85,7 +85,7 @@ private[study] final class SocketHandler(
|
|||
for {
|
||||
userId <- member.userId
|
||||
d ← o obj "d"
|
||||
chapterId <- d str "chapterId"
|
||||
chapterId <- d.get[Chapter.Id]("chapterId")
|
||||
} api.addNode(
|
||||
userId,
|
||||
studyId,
|
||||
|
@ -172,7 +172,7 @@ private[study] final class SocketHandler(
|
|||
|
||||
case ("setChapter", o) => for {
|
||||
byUserId <- member.userId
|
||||
chapterId <- o str "d"
|
||||
chapterId <- o.get[Chapter.Id]("d")
|
||||
} api.setChapter(byUserId, studyId, chapterId, socket, uid)
|
||||
|
||||
case ("editChapter", o) =>
|
||||
|
@ -184,12 +184,12 @@ private[study] final class SocketHandler(
|
|||
|
||||
case ("deleteChapter", o) => for {
|
||||
byUserId <- member.userId
|
||||
id <- o str "d"
|
||||
id <- o.get[Chapter.Id]("d")
|
||||
} api.deleteChapter(byUserId, studyId, id, socket, uid)
|
||||
|
||||
case ("sortChapters", o) => for {
|
||||
byUserId <- member.userId
|
||||
ids <- o strs "d"
|
||||
ids <- o.get[List[Chapter.Id]]("d")
|
||||
} api.sortChapters(byUserId, studyId, ids, socket, uid)
|
||||
|
||||
case ("editStudy", o) if owner =>
|
||||
|
@ -242,9 +242,10 @@ private[study] final class SocketHandler(
|
|||
private def reading[A](o: JsValue)(f: A => Unit)(implicit reader: Reads[A]): Unit =
|
||||
o obj "d" flatMap { d => reader.reads(d).asOpt } foreach f
|
||||
|
||||
private case class AtPosition(path: String, chapterId: Chapter.ID) {
|
||||
private case class AtPosition(path: String, chapterId: Chapter.Id) {
|
||||
def ref = Position.Ref(chapterId, Path(path))
|
||||
}
|
||||
private implicit val chapterIdReader = Reads.of[String].map(Chapter.Id.apply)
|
||||
private implicit val atPositionReader = Json.reads[AtPosition]
|
||||
private case class SetRole(userId: String, role: String)
|
||||
private implicit val SetRoleReader = Json.reads[SetRole]
|
||||
|
|
|
@ -136,7 +136,7 @@ object Study {
|
|||
_id = makeId,
|
||||
name = s"${user.username}'s Study",
|
||||
members = StudyMembers(Map(user.id -> owner)),
|
||||
position = Position.Ref("", Path.root),
|
||||
position = Position.Ref(Chapter.Id(""), Path.root),
|
||||
ownerId = user.id,
|
||||
visibility = Visibility.Public,
|
||||
settings = Settings.init,
|
||||
|
|
|
@ -32,7 +32,7 @@ final class StudyApi(
|
|||
|
||||
def publicByIds(ids: Seq[Study.Id]) = byIds(ids) map { _.filter(_.isPublic) }
|
||||
|
||||
private def fetchAndFixChapter(id: Chapter.ID): Fu[Option[Chapter]] =
|
||||
private def fetchAndFixChapter(id: Chapter.Id): Fu[Option[Chapter]] =
|
||||
chapterRepo.byId(id) flatMap {
|
||||
_ ?? { c => tagsFixer(c) map some }
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ final class StudyApi(
|
|||
}
|
||||
}
|
||||
|
||||
def byIdWithChapter(id: Study.Id, chapterId: Chapter.ID): Fu[Option[Study.WithChapter]] = byId(id) flatMap {
|
||||
def byIdWithChapter(id: Study.Id, chapterId: Chapter.Id): Fu[Option[Study.WithChapter]] = byId(id) flatMap {
|
||||
_ ?? { study =>
|
||||
fetchAndFixChapter(chapterId) map {
|
||||
_.filter(_.studyId == study.id) map { Study.WithChapter(study, _) }
|
||||
|
@ -303,11 +303,11 @@ final class StudyApi(
|
|||
}
|
||||
}
|
||||
|
||||
def setChapter(byUserId: User.ID, studyId: Study.Id, chapterId: Chapter.ID, socket: ActorRef, uid: Uid) = sequenceStudy(studyId) { study =>
|
||||
def setChapter(byUserId: User.ID, studyId: Study.Id, chapterId: Chapter.Id, socket: ActorRef, uid: Uid) = sequenceStudy(studyId) { study =>
|
||||
study.canContribute(byUserId) ?? doSetChapter(study, chapterId, socket, uid)
|
||||
}
|
||||
|
||||
private def doSetChapter(study: Study, chapterId: Chapter.ID, socket: ActorRef, uid: Uid) =
|
||||
private def doSetChapter(study: Study, chapterId: Chapter.Id, socket: ActorRef, uid: Uid) =
|
||||
(study.position.chapterId != chapterId) ?? {
|
||||
chapterRepo.byIdAndStudy(chapterId, study.id) flatMap {
|
||||
_ ?? { chapter =>
|
||||
|
@ -355,7 +355,7 @@ final class StudyApi(
|
|||
}
|
||||
}
|
||||
|
||||
def deleteChapter(byUserId: User.ID, studyId: Study.Id, chapterId: Chapter.ID, socket: ActorRef, uid: Uid) = sequenceStudy(studyId) { study =>
|
||||
def deleteChapter(byUserId: User.ID, studyId: Study.Id, chapterId: Chapter.Id, socket: ActorRef, uid: Uid) = sequenceStudy(studyId) { study =>
|
||||
Contribute(byUserId, study) {
|
||||
chapterRepo.byIdAndStudy(chapterId, studyId) flatMap {
|
||||
_ ?? { chapter =>
|
||||
|
@ -372,7 +372,7 @@ final class StudyApi(
|
|||
}
|
||||
}
|
||||
|
||||
def sortChapters(byUserId: User.ID, studyId: Study.Id, chapterIds: List[Chapter.ID], socket: ActorRef, uid: Uid) = sequenceStudy(studyId) { study =>
|
||||
def sortChapters(byUserId: User.ID, studyId: Study.Id, chapterIds: List[Chapter.Id], socket: ActorRef, uid: Uid) = sequenceStudy(studyId) { study =>
|
||||
Contribute(byUserId, study) {
|
||||
chapterRepo.sort(study, chapterIds) >>- reloadChapters(study)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,6 @@ package actorApi
|
|||
|
||||
case class SaveStudy(study: Study)
|
||||
case class RemoveStudy(id: Study.Id)
|
||||
case class SetTag(chapterId: Chapter.ID, name: String, value: String) {
|
||||
case class SetTag(chapterId: Chapter.Id, name: String, value: String) {
|
||||
def tag = chess.format.pgn.Tag(name, value take 140)
|
||||
}
|
||||
|
|
|
@ -6,5 +6,5 @@ package object study extends PackageObject with WithPlay with WithSocket {
|
|||
|
||||
private[study] val logger = lila.log("study")
|
||||
|
||||
private[study]type ChapterMap = Map[lila.study.Chapter.ID, lila.study.Chapter]
|
||||
private[study]type ChapterMap = Map[lila.study.Chapter.Id, lila.study.Chapter]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue