class student real name WIP

pull/5932/head
Thibault Duplessis 2020-01-17 16:00:58 -06:00
parent 104b7d99a0
commit 9fd53a3c9e
7 changed files with 58 additions and 36 deletions

View File

@ -104,8 +104,8 @@ final class Clas(
err
)
).fuccess,
username =>
env.clas.api.student.create(clas, username, t) map {
data =>
env.clas.api.student.create(clas, data, t) map {
case (user, password) =>
Redirect(routes.Clas.studentShow(clas.id.value, user.username))
.flashing("password" -> password.value)
@ -129,8 +129,8 @@ final class Clas(
env.clas.forms.student.create
)
).fuccess,
username =>
env.user.repo named username flatMap {
data =>
env.user.repo named data.username flatMap {
_ ?? { user =>
env.clas.api.student.invite(clas, user, t) inject
Redirect(routes.Clas.studentForm(clas.id.value)).flashSuccess

View File

@ -6,7 +6,7 @@ import lila.api.Context
import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._
import lila.clas.{ Clas, Student }
import lila.clas.ClasForm.Data
import lila.clas.ClasForm.ClasData
import controllers.routes
object clas {
@ -92,21 +92,21 @@ object clas {
fragList(clas.teachers.toList.map(t => userIdLink(t.value.some)))
)
def create(form: Form[Data])(implicit ctx: Context) =
def create(form: Form[ClasData])(implicit ctx: Context) =
bits.layout("New class", Right("newClass"))(
cls := "box-pad",
h1("New class"),
innerForm(form, routes.Clas.create)
)
def edit(c: lila.clas.Clas, form: Form[Data])(implicit ctx: Context) =
def edit(c: lila.clas.Clas, form: Form[ClasData])(implicit ctx: Context) =
bits.layout(c.name, Left(c))(
cls := "box-pad",
h1("Edit ", c.name),
innerForm(form, routes.Clas.update(c.id.value))
)
private def innerForm(form: Form[Data], url: play.api.mvc.Call)(implicit ctx: Context) =
private def innerForm(form: Form[ClasData], url: play.api.mvc.Call)(implicit ctx: Context) =
postForm(cls := "form3", action := url)(
form3.globalError(form),
form3.group(form("name"), frag("Class name"))(form3.input(_)(autofocus)),

View File

@ -142,7 +142,14 @@ object student {
)
)
def form(c: lila.clas.Clas, invite: Form[String], create: Form[String])(implicit ctx: Context) =
private def realName(form: Form[_])(implicit ctx: Context) =
form3.group(
form("realName"),
frag("Real name"),
help = frag("Private info, never visible on Lichess. Helps you remember who that student is.").some
)(form3.input(_))
def form(c: lila.clas.Clas, invite: Form[_], create: Form[_])(implicit ctx: Context) =
bits.layout("Add student", Left(c))(
cls := "box-pad student-add",
h1("Add student"),
@ -166,6 +173,7 @@ object student {
form3.group(invite("invite"), frag("Invite username"))(
form3.input(_, klass = "user-autocomplete")(autofocus)(dataTag := "span")
),
realName(invite),
form3.submit("Invite")
)
),
@ -186,6 +194,7 @@ object student {
),
postForm(cls := "form3", action := routes.Clas.studentCreate(c.id.value))(
form3.group(create("username"), frag("Create username"))(form3.input(_)(autofocus)),
realName(create),
form3.submit(trans.signUp())
)
)

View File

@ -50,12 +50,12 @@ final class ClasApi(
.sort($sort desc "viewedAt")
.list[Clas]()
def create(data: ClasForm.Data, teacher: Teacher): Fu[Clas] = {
def create(data: ClasForm.ClasData, teacher: Teacher): Fu[Clas] = {
val clas = Clas.make(teacher, data.name, data.desc)
coll.insert.one(clas) inject clas
}
def update(from: Clas, data: ClasForm.Data): Fu[Clas] = {
def update(from: Clas, data: ClasForm.ClasData): Fu[Clas] = {
val clas = data update from
coll.update.one($id(clas.id), clas) inject clas
}
@ -109,23 +109,27 @@ final class ClasApi(
def isIn(clas: Clas, userId: User.ID): Fu[Boolean] =
coll.exists($id(Student.id(userId, clas.id)))
def create(clas: Clas, username: String, teacher: Teacher.WithUser): Fu[(User, ClearPassword)] = {
val email = EmailAddress(s"noreply.class.${clas.id}.$username@lichess.org")
def create(
clas: Clas,
data: ClasForm.NewStudent,
teacher: Teacher.WithUser
): Fu[(User, ClearPassword)] = {
val email = EmailAddress(s"noreply.class.${clas.id}.${data.username}@lichess.org")
val password = Student.password.generate
lila.mon.clas.studentCreate(teacher.user.id)
userRepo
.create(
username = username,
username = data.username,
passwordHash = authenticator.passEnc(password),
email = email,
blind = false,
mobileApiVersion = none,
mustConfirmEmail = false
)
.orFail(s"No user could be created for $username")
.orFail(s"No user could be created for ${data.username}")
.flatMap { user =>
userRepo.setKid(user, true) >>
coll.insert.one(Student.make(user, clas, teacher.teacher.id, managed = true)) >>
coll.insert.one(Student.make(user, clas, teacher.teacher.id, data.realName, managed = true)) >>
sendWelcomeMessage(teacher, user, clas, s"$baseUrl/class/${clas.id}") inject
(user -> password)
}
@ -139,7 +143,7 @@ final class ClasApi(
}
private[ClasApi] def join(clas: Clas, user: User, teacherId: Teacher.Id): Fu[Student] = {
val student = Student.make(user, clas, teacherId, managed = false)
val student = Student.make(user, clas, teacherId, "", managed = false)
coll.insert.one(student) inject student
}

View File

@ -15,26 +15,32 @@ final class ClasForm(
mapping(
"name" -> text(minLength = 3, maxLength = 100),
"desc" -> text(minLength = 0, maxLength = 2000)
)(Data.apply)(Data.unapply)
)(ClasData.apply)(ClasData.unapply)
)
def create = form
def edit(c: Clas) = form fill Data(
def edit(c: Clas) = form fill ClasData(
name = c.name,
desc = c.desc
)
object student {
def create = securityForms.signup.managed
def create = Form(
mapping(
"username" -> securityForms.signup.username,
"realName" -> nonEmptyText
)(NewStudent.apply)(NewStudent.unapply)
)
def invite = Form(
single(
"invite" -> lila.user.DataForm.historicalUsernameField.verifying("Unknown username", {
mapping(
"username" -> lila.user.DataForm.historicalUsernameField.verifying("Unknown username", {
blockingFetchUser(_).isDefined
})
)
}),
"realName" -> nonEmptyText
)(NewStudent.apply)(NewStudent.unapply)
)
private def blockingFetchUser(username: String) =
@ -44,7 +50,7 @@ final class ClasForm(
object ClasForm {
case class Data(
case class ClasData(
name: String,
desc: String
) {
@ -53,4 +59,9 @@ object ClasForm {
desc = desc
)
}
case class NewStudent(
username: String,
realName: String
)
}

View File

@ -8,6 +8,8 @@ case class Student(
_id: Student.Id, // userId:clasId
userId: User.ID,
clasId: Clas.Id,
realName: String,
notes: String,
managed: Boolean, // created for the class by the teacher
created: Clas.Recorded,
archived: Option[Clas.Recorded]
@ -27,10 +29,12 @@ object Student {
def id(userId: User.ID, clasId: Clas.Id) = Id(s"${userId}:${clasId}")
def make(user: User, clas: Clas, teacherId: Teacher.Id, managed: Boolean) = Student(
def make(user: User, clas: Clas, teacherId: Teacher.Id, realName: String, managed: Boolean) = Student(
_id = id(user.id, clas.id),
userId = user.id,
clasId = clas.id,
realName = realName,
notes = "",
managed = managed,
created = Clas.Recorded(teacherId, DateTime.now),
archived = none

View File

@ -52,7 +52,7 @@ final class DataForm(
object signup {
private val username = trimField(nonEmptyText)
val username = trimField(nonEmptyText)
.verifying(
Constraints minLength 2,
Constraints maxLength 20,
@ -83,7 +83,7 @@ final class DataForm(
val website = Form(
mapping(
"username" -> trimField(username),
"username" -> username,
"password" -> text(minLength = 4),
"email" -> withAcceptableDns(acceptableUniqueEmail(none)),
"agreement" -> agreement,
@ -94,17 +94,11 @@ final class DataForm(
val mobile = Form(
mapping(
"username" -> trimField(username),
"username" -> username,
"password" -> text(minLength = 4),
"email" -> withAcceptableDns(acceptableUniqueEmail(none))
)(MobileSignupData.apply)(_ => None)
)
val managed = Form(
single(
"username" -> trimField(username)
)
)
}
val passwordReset = Form(
@ -214,7 +208,7 @@ final class DataForm(
val reopen = Form(
mapping(
"username" -> nonEmptyText,
"username" -> trimField(nonEmptyText),
"email" -> sendableEmail, // allow unacceptable emails for BC
"gameId" -> text,
"move" -> text