coach credentials WIP

This commit is contained in:
Thibault Duplessis 2016-09-01 20:02:08 +02:00
parent 983477f329
commit 338bfe3581
9 changed files with 45 additions and 36 deletions

View file

@ -41,7 +41,7 @@ final class Env(
getRanks = Env.user.cached.ranking.getAll,
isHostingSimul = Env.simul.isHosting,
isStreamer = Env.tv.isStreamer.apply,
fetchIsCoach = Env.coach.api.isEnabledCoach,
fetchIsCoach = Env.coach.api.isListedCoach,
insightShare = Env.insight.share,
getPlayTime = Env.game.playTime.apply,
completionRate = Env.playban.api.completionRate) _

View file

@ -14,27 +14,32 @@ object Coach extends LilaController {
def allDefault(page: Int) = all(CoachPager.Order.Login.key, page)
def all(o: String, page: Int) = Open { implicit ctx =>
val order = CoachPager.Order(o)
Env.coach.pager(order, page) map { pager =>
Ok(html.coach.index(pager, order))
}
private val canViewCoaches = (u: UserModel) =>
isGranted(_.Admin, u) || isGranted(_.Coach, u) || isGranted(_.PreviewCoach, u)
def all(o: String, page: Int) = SecureF(canViewCoaches) { implicit ctx =>
me =>
val order = CoachPager.Order(o)
Env.coach.pager(order, page) map { pager =>
Ok(html.coach.index(pager, order))
}
}
def show(username: String) = Open { implicit ctx =>
OptionFuResult(api find username) { c =>
WithVisibleCoach(c) {
Env.study.api.byIds {
c.coach.profile.studyIds.map(_.value)
} flatMap Env.study.pager.withChaptersAndLiking(ctx.me) flatMap { studies =>
api.reviews.approvedByCoach(c.coach) flatMap { reviews =>
ctx.me.?? { api.reviews.isPending(_, c.coach) } map { isPending =>
Ok(html.coach.show(c, reviews, studies, reviewApproval = isPending))
def show(username: String) = SecureF(canViewCoaches) { implicit ctx =>
me =>
OptionFuResult(api find username) { c =>
WithVisibleCoach(c) {
Env.study.api.byIds {
c.coach.profile.studyIds.map(_.value)
} flatMap Env.study.pager.withChaptersAndLiking(ctx.me) flatMap { studies =>
api.reviews.approvedByCoach(c.coach) flatMap { reviews =>
ctx.me.?? { api.reviews.isPending(_, c.coach) } map { isPending =>
Ok(html.coach.show(c, reviews, studies, reviewApproval = isPending))
}
}
}
}
}
}
}
def review(username: String) = AuthBody { implicit ctx =>
@ -62,7 +67,7 @@ object Coach extends LilaController {
}
private def WithVisibleCoach(c: CoachModel.WithUser)(f: Fu[Result])(implicit ctx: Context) =
if (c.coach.isFullyEnabled || ctx.me.??(c.coach.is) || isGranted(_.PreviewCoach)) f
if ((c.coach.isListed || ctx.me.??(c.coach.is)) && ctx.me.??(canViewCoaches)) f
else notFound
def edit = Secure(_.Coach) { implicit ctx =>

View file

@ -124,6 +124,12 @@ private[controllers] trait LilaController
isGranted(perm).fold(f(ctx)(me), fuccess(authorizationFailed(ctx.req)))
}
protected def SecureF(s: UserModel => Boolean)(f: Context => UserModel => Fu[Result]): Action[AnyContent] =
Auth(BodyParsers.parse.anyContent) { implicit ctx =>
me =>
s(me).fold(f(ctx)(me), fuccess(authorizationFailed(ctx.req)))
}
protected def SecureBody[A](p: BodyParser[A])(perm: Permission)(f: BodyContext[A] => UserModel => Fu[Result]): Action[A] =
AuthBody(p) { implicit ctx =>
me =>

View file

@ -93,7 +93,7 @@ moreCss = moreCss) {
<tr class="edit">
<th>Admin</th>
<td>
@if(c.coach.isFullyEnabled) {
@if(c.coach.isListed) {
This page is now public.
} else {
This page is not public yet.

View file

@ -6,7 +6,7 @@ import reactivemongo.bson._
private[coach] object BsonHandlers {
implicit val CoachIdBSONHandler = stringAnyValHandler[Coach.Id](_.value, Coach.Id.apply)
implicit val CoachEnabledBSONHandler = booleanAnyValHandler[Coach.Enabled](_.value, Coach.Enabled.apply)
implicit val CoachListedBSONHandler = booleanAnyValHandler[Coach.Listed](_.value, Coach.Listed.apply)
implicit val CoachAvailableBSONHandler = booleanAnyValHandler[Coach.Available](_.value, Coach.Available.apply)
implicit val CoachPicturePathBSONHandler = stringAnyValHandler[Coach.PicturePath](_.value, Coach.PicturePath.apply)

View file

@ -6,8 +6,7 @@ import lila.user.User
case class Coach(
_id: Coach.Id, // user ID
enabledByUser: Coach.Enabled,
enabledByMod: Coach.Enabled,
listed: Coach.Listed,
available: Coach.Available,
profile: CoachProfile,
picturePath: Option[Coach.PicturePath],
@ -21,16 +20,15 @@ case class Coach(
def hasPicture = picturePath.isDefined
def isFullyEnabled = enabledByUser.value && enabledByMod.value
def isListed = listed.value
}
object Coach {
def make(user: User) = Coach(
_id = Id(user.id),
enabledByUser = Enabled(false),
enabledByMod = Enabled(false),
available = Available(false),
listed = Listed(false),
available = Available(true),
profile = CoachProfile(),
picturePath = None,
nbReviews = 0,
@ -40,7 +38,7 @@ object Coach {
case class WithUser(coach: Coach, user: User)
case class Id(value: String) extends AnyVal with StringValue
case class Enabled(value: Boolean) extends AnyVal
case class Listed(value: Boolean) extends AnyVal
case class Available(value: Boolean) extends AnyVal
case class PicturePath(value: String) extends AnyVal with StringValue
}

View file

@ -35,16 +35,16 @@ final class CoachApi(
fuccess(Coach.WithUser(Coach make user, user).some)
}
def isEnabledCoach(user: User): Fu[Boolean] =
def isListedCoach(user: User): Fu[Boolean] =
Granter(_.Coach)(user) ?? all.map(_.exists { c =>
c.is(user) && c.isFullyEnabled
c.is(user) && c.isListed
})
def enabledWithUserList: Fu[List[Coach.WithUser]] =
all.map(_.filter(_.isFullyEnabled)) flatMap { coaches =>
def listedWithUserList: Fu[List[Coach.WithUser]] =
all.map(_.filter(_.isListed)) flatMap { coaches =>
UserRepo.byIds(coaches.map(_.id.value)) map { users =>
coaches.flatMap { coach =>
users find coach.is map { Coach.WithUser(coach, _) }
users find coach.is filter Granter(_.Coach) map { Coach.WithUser(coach, _) }
}
}
}

View file

@ -9,7 +9,7 @@ final class CoachPager(api: CoachApi) {
import CoachPager._
def apply(order: Order, page: Int): Fu[Paginator[Coach.WithUser]] =
api.enabledWithUserList.map { all =>
api.listedWithUserList.map { all =>
Paginator.fromList(
list = all sortWith order.predicate,
currentPage = page,

View file

@ -8,21 +8,21 @@ import play.api.data.Forms._
object CoachProfileForm {
def edit(coach: Coach) = Form(mapping(
"enabledByUser" -> boolean,
"listed" -> boolean,
"available" -> boolean,
"profile" -> profileMapping
)(Data.apply)(Data.unapply)) fill Data(
enabledByUser = coach.enabledByUser.value,
listed = coach.listed.value,
available = coach.available.value,
profile = coach.profile)
case class Data(
enabledByUser: Boolean,
listed: Boolean,
available: Boolean,
profile: CoachProfile) {
def apply(coach: Coach) = coach.copy(
enabledByUser = Coach.Enabled(enabledByUser),
listed = Coach.Listed(listed),
available = Coach.Available(available),
profile = profile,
updatedAt = DateTime.now)