class news WIP
parent
a5a9c23829
commit
ed5e69cf67
|
@ -46,12 +46,12 @@ final class Clas(
|
|||
}
|
||||
|
||||
def form = Secure(_.Teacher) { implicit ctx => _ =>
|
||||
Ok(html.clas.clas.create(env.clas.forms.create)).fuccess
|
||||
Ok(html.clas.clas.create(env.clas.forms.clas.create)).fuccess
|
||||
}
|
||||
|
||||
def create = SecureBody(_.Teacher) { implicit ctx => me =>
|
||||
WithTeacher(me) { t =>
|
||||
env.clas.forms.create
|
||||
env.clas.forms.clas.create
|
||||
.bindFromRequest()(ctx.body)
|
||||
.fold(
|
||||
err => BadRequest(html.clas.clas.create(err)).fuccess,
|
||||
|
@ -91,6 +91,39 @@ final class Clas(
|
|||
}
|
||||
}
|
||||
|
||||
def wall(id: String) = Secure(_.Teacher) { implicit ctx => me =>
|
||||
WithClass(me, id) { _ => clas =>
|
||||
env.clas.api.student.allWithUsers(clas) map { students =>
|
||||
val wall = scalatags.Text.all.raw(env.clas.markup(clas.wall))
|
||||
views.html.clas.wall.show(clas, wall, students)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def wallEdit(id: String) = Secure(_.Teacher) { implicit ctx => me =>
|
||||
WithClass(me, id) { _ => clas =>
|
||||
env.clas.api.student.activeWithUsers(clas) map { students =>
|
||||
Ok(html.clas.wall.edit(clas, students, env.clas.forms.clas.wall fill clas.wall))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def wallUpdate(id: String) = SecureBody(_.Teacher) { implicit ctx => me =>
|
||||
WithClass(me, id) { _ => clas =>
|
||||
env.clas.forms.clas.wall
|
||||
.bindFromRequest()(ctx.body)
|
||||
.fold(
|
||||
err =>
|
||||
env.clas.api.student.activeWithUsers(clas) map { students =>
|
||||
BadRequest(html.clas.wall.edit(clas, students, err))
|
||||
},
|
||||
text =>
|
||||
env.clas.api.clas.updateWall(clas, text) inject
|
||||
Redirect(routes.Clas.wall(clas.id.value)).flashSuccess
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def archived(id: String) = Secure(_.Teacher) { implicit ctx => me =>
|
||||
WithClass(me, id) { _ => clas =>
|
||||
env.clas.api.student.allWithUsers(clas) map { students =>
|
||||
|
@ -114,14 +147,14 @@ final class Clas(
|
|||
def edit(id: String) = Secure(_.Teacher) { implicit ctx => me =>
|
||||
WithClass(me, id) { _ => clas =>
|
||||
env.clas.api.student.activeWithUsers(clas) map { students =>
|
||||
Ok(html.clas.clas.edit(clas, students, env.clas.forms.edit(clas)))
|
||||
Ok(html.clas.clas.edit(clas, students, env.clas.forms.clas.edit(clas)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def update(id: String) = SecureBody(_.Teacher) { implicit ctx => me =>
|
||||
WithClass(me, id) { _ => clas =>
|
||||
env.clas.forms
|
||||
env.clas.forms.clas
|
||||
.edit(clas)
|
||||
.bindFromRequest()(ctx.body)
|
||||
.fold(
|
||||
|
|
|
@ -32,6 +32,7 @@ object teacherDashboard {
|
|||
),
|
||||
st.nav(cls := "dashboard-nav")(
|
||||
a(cls := active.active("overview"), href := routes.Clas.show(c.id.value))("Overview"),
|
||||
a(cls := active.active("wall"), href := routes.Clas.wall(c.id.value))("News"),
|
||||
a(
|
||||
cls := active.active("progress"),
|
||||
href := routes.Clas.progress(c.id.value, PerfType.Blitz.key, 7)
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package views.html.clas
|
||||
|
||||
import play.api.data.Form
|
||||
|
||||
import controllers.routes
|
||||
import lila.api.Context
|
||||
import lila.app.templating.Environment._
|
||||
import lila.app.ui.ScalatagsTemplate._
|
||||
import lila.clas.{ Clas, Student }
|
||||
|
||||
object wall {
|
||||
|
||||
def show(
|
||||
c: Clas,
|
||||
html: Frag,
|
||||
students: List[Student.WithUser]
|
||||
)(implicit ctx: Context) =
|
||||
teacherDashboard.layout(c, students.filter(_.student.isActive), "wall") {
|
||||
if (c.wall.isEmpty)
|
||||
div(cls := "box__pad clas-wall clas-wall--empty")("Nothing here, yet.")
|
||||
else
|
||||
div(cls := "box__pad clas-wall")(html)
|
||||
}
|
||||
|
||||
def edit(
|
||||
c: Clas,
|
||||
students: List[Student.WithUser],
|
||||
form: Form[_]
|
||||
)(implicit ctx: Context) =
|
||||
teacherDashboard.layout(c, students, "wall")(
|
||||
div(cls := "box-pad")(
|
||||
postForm(cls := "form3", action := routes.Clas.wallUpdate(c.id.value))(
|
||||
form3.globalError(form),
|
||||
form3.group(
|
||||
form("wall"),
|
||||
frag("Class news"),
|
||||
help = frag("Add the most recent news at the top.").some
|
||||
)(form3.textarea(_)(rows := 20)),
|
||||
form3.actions(
|
||||
a(href := routes.Clas.show(c.id.value))(trans.cancel()),
|
||||
form3.submit(trans.apply())
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
|
@ -375,7 +375,7 @@ lazy val teamSearch = module("teamSearch",
|
|||
|
||||
lazy val clas = module("clas",
|
||||
Seq(common, memo, db, user, security, msg, history, puzzle),
|
||||
reactivemongo.bundle
|
||||
Seq(markdown) ++ reactivemongo.bundle
|
||||
)
|
||||
|
||||
lazy val bookmark = module("bookmark",
|
||||
|
|
|
@ -446,6 +446,9 @@ GET /class/verify-teacher controllers.Clas.verifyTeacher
|
|||
GET /class/$id<\w{8}> controllers.Clas.show(id: String)
|
||||
GET /class/$id<\w{8}>/edit controllers.Clas.edit(id: String)
|
||||
POST /class/$id<\w{8}>/edit controllers.Clas.update(id: String)
|
||||
GET /class/$id<\w{8}>/news controllers.Clas.wall(id: String)
|
||||
GET /class/$id<\w{8}>/news/edit controllers.Clas.wallEdit(id: String)
|
||||
POST /class/$id<\w{8}>/news/edit controllers.Clas.wallUpdate(id: String)
|
||||
POST /class/$id<\w{8}>/archive controllers.Clas.archive(id: String, v: Boolean)
|
||||
GET /class/$id<\w{8}>/archived controllers.Clas.archived(id: String)
|
||||
GET /class/$id<\w{8}>/progress/:pt/:days controllers.Clas.progress(id: String, pt: String, days: Int)
|
||||
|
|
|
@ -7,6 +7,7 @@ case class Clas(
|
|||
_id: Clas.Id,
|
||||
name: String,
|
||||
desc: String,
|
||||
wall: String = "",
|
||||
teachers: NonEmptyList[Teacher.Id], // first is owner
|
||||
created: Clas.Recorded,
|
||||
viewedAt: DateTime,
|
||||
|
|
|
@ -82,6 +82,9 @@ final class ClasApi(
|
|||
}
|
||||
}
|
||||
|
||||
def updateWall(clas: Clas, text: String): Funit =
|
||||
coll.updateField($id(clas.id), "wall", text).void
|
||||
|
||||
def getAndView(id: Clas.Id, teacher: Teacher): Fu[Option[Clas]] =
|
||||
coll.ext
|
||||
.findAndUpdate[Clas](
|
||||
|
|
|
@ -13,26 +13,32 @@ final class ClasForm(
|
|||
|
||||
import ClasForm._
|
||||
|
||||
val form = Form(
|
||||
mapping(
|
||||
"name" -> text(minLength = 3, maxLength = 100),
|
||||
"desc" -> text(minLength = 0, maxLength = 2000),
|
||||
"teachers" -> nonEmptyText.verifying("Invalid teacher list", str => {
|
||||
val ids = readTeacherIds(str)
|
||||
ids.nonEmpty && ids.size <= 10 && ids.forall { id =>
|
||||
blockingFetchUser(id.value).isDefined
|
||||
}
|
||||
})
|
||||
)(ClasData.apply)(ClasData.unapply)
|
||||
)
|
||||
object clas {
|
||||
|
||||
def create = form
|
||||
val form = Form(
|
||||
mapping(
|
||||
"name" -> text(minLength = 3, maxLength = 100),
|
||||
"desc" -> text(minLength = 0, maxLength = 2000),
|
||||
"teachers" -> nonEmptyText.verifying("Invalid teacher list", str => {
|
||||
val ids = readTeacherIds(str)
|
||||
ids.nonEmpty && ids.size <= 10 && ids.forall { id =>
|
||||
blockingFetchUser(id.value).isDefined
|
||||
}
|
||||
})
|
||||
)(ClasData.apply)(ClasData.unapply)
|
||||
)
|
||||
|
||||
def edit(c: Clas) = form fill ClasData(
|
||||
name = c.name,
|
||||
desc = c.desc,
|
||||
teachers = c.teachers.toList mkString "\n"
|
||||
)
|
||||
def create = form
|
||||
|
||||
def edit(c: Clas) = form fill ClasData(
|
||||
name = c.name,
|
||||
desc = c.desc,
|
||||
teachers = c.teachers.toList mkString "\n"
|
||||
)
|
||||
|
||||
def wall =
|
||||
Form(single("wall" -> text))
|
||||
}
|
||||
|
||||
object student {
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package lila.clas
|
||||
|
||||
import com.github.blemale.scaffeine.Cache
|
||||
import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension
|
||||
import com.vladsch.flexmark.ext.tables.TablesExtension
|
||||
import com.vladsch.flexmark.ext.autolink.AutolinkExtension
|
||||
import com.vladsch.flexmark.html.HtmlRenderer
|
||||
import com.vladsch.flexmark.parser.Parser
|
||||
import com.vladsch.flexmark.util.data.MutableDataSet
|
||||
import java.util.Arrays
|
||||
import scala.concurrent.duration._
|
||||
|
||||
final class ClasMarkup {
|
||||
|
||||
type Text = String
|
||||
type Html = String
|
||||
|
||||
private val options = new MutableDataSet()
|
||||
options.set(
|
||||
Parser.EXTENSIONS,
|
||||
Arrays.asList(
|
||||
TablesExtension.create(),
|
||||
StrikethroughExtension.create(),
|
||||
AutolinkExtension.create()
|
||||
)
|
||||
)
|
||||
options.set(HtmlRenderer.SOFT_BREAK, "<br>\n")
|
||||
options.set(TablesExtension.CLASS_NAME, "slist")
|
||||
private val parser = Parser.builder(options).build()
|
||||
private val renderer = HtmlRenderer.builder(options).build()
|
||||
|
||||
private val cache: Cache[Text, Html] = lila.memo.CacheApi.scaffeineNoScheduler
|
||||
.expireAfterAccess(10 minutes)
|
||||
.maximumSize(64)
|
||||
.build[Text, Html]
|
||||
|
||||
private def compute(text: Text): Html =
|
||||
renderer.render(parser.parse(text))
|
||||
|
||||
def apply(text: Text): Html = cache.get(text, compute)
|
||||
}
|
|
@ -31,6 +31,8 @@ final class Env(
|
|||
|
||||
lazy val progressApi = wire[ClasProgressApi]
|
||||
|
||||
lazy val markup = wire[ClasMarkup]
|
||||
|
||||
lila.common.Bus.subscribeFuns(
|
||||
"finishGame" -> {
|
||||
case lila.game.actorApi.FinishGame(game, _, _) => progressApi.onFinishGame(game)
|
||||
|
|
|
@ -16,7 +16,7 @@ final private class RelayMarkup {
|
|||
|
||||
private val options = new MutableDataSet()
|
||||
options.set(Parser.EXTENSIONS, Arrays.asList(TablesExtension.create(), StrikethroughExtension.create()))
|
||||
options.set(HtmlRenderer.SOFT_BREAK, "<br />\n")
|
||||
options.set(HtmlRenderer.SOFT_BREAK, "<br>\n")
|
||||
options.set(TablesExtension.CLASS_NAME, "slist")
|
||||
private val parser = Parser.builder(options).build()
|
||||
private val renderer = HtmlRenderer.builder(options).build()
|
||||
|
|
|
@ -101,6 +101,7 @@ $c-bg-clas-over-dim: mix($c-bg-clas-over, $c-bg-clas, 80%);
|
|||
}
|
||||
|
||||
.clas-show {
|
||||
@extend %box-neat-force;
|
||||
|
||||
&__top {
|
||||
background: $c-bg-clas;
|
||||
|
@ -190,12 +191,12 @@ $c-bg-clas-over-dim: mix($c-bg-clas-over, $c-bg-clas, 80%);
|
|||
background: mix($c-bg-zebra, $c-clas, 20%);
|
||||
}
|
||||
&.active {
|
||||
background: $c-bg-zebra;
|
||||
background: $c-bg-box;
|
||||
color: $c-font-clas;
|
||||
font-weight: bold;
|
||||
.dashboard-teacher-edit &,
|
||||
.dashboard-teacher-archived & {
|
||||
background: $c-bg-box;
|
||||
.dashboard-teacher-overview &,
|
||||
.dashboard-teacher-progress & {
|
||||
background: $c-bg-zebra;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,6 +281,12 @@ $c-bg-clas-over-dim: mix($c-bg-clas-over, $c-bg-clas, 80%);
|
|||
}
|
||||
}
|
||||
|
||||
.clas-wall {
|
||||
margin: 4em 0;
|
||||
font-size: 1.1em;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
|
||||
.student-show {
|
||||
|
||||
padding-bottom: 3em;
|
||||
|
|
Loading…
Reference in New Issue