From 9fd53a3c9e68c7de172fd5e405fb53ce4fdaf7c3 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Fri, 17 Jan 2020 16:00:58 -0600 Subject: [PATCH] class student real name WIP --- app/controllers/Clas.scala | 8 +++---- app/views/clas/clas.scala | 8 +++---- app/views/clas/student.scala | 11 +++++++++- modules/clas/src/main/ClasApi.scala | 20 +++++++++++------- modules/clas/src/main/ClasForm.scala | 27 +++++++++++++++++------- modules/clas/src/main/Student.scala | 6 +++++- modules/security/src/main/DataForm.scala | 14 ++++-------- 7 files changed, 58 insertions(+), 36 deletions(-) diff --git a/app/controllers/Clas.scala b/app/controllers/Clas.scala index 5bcc51a6b0..eb9085c0c3 100644 --- a/app/controllers/Clas.scala +++ b/app/controllers/Clas.scala @@ -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 diff --git a/app/views/clas/clas.scala b/app/views/clas/clas.scala index 750e2b9ff5..292c23d9e3 100644 --- a/app/views/clas/clas.scala +++ b/app/views/clas/clas.scala @@ -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)), diff --git a/app/views/clas/student.scala b/app/views/clas/student.scala index 76707bb62d..79e2ad9823 100644 --- a/app/views/clas/student.scala +++ b/app/views/clas/student.scala @@ -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()) ) ) diff --git a/modules/clas/src/main/ClasApi.scala b/modules/clas/src/main/ClasApi.scala index e590eeb363..060d330eb4 100644 --- a/modules/clas/src/main/ClasApi.scala +++ b/modules/clas/src/main/ClasApi.scala @@ -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 } diff --git a/modules/clas/src/main/ClasForm.scala b/modules/clas/src/main/ClasForm.scala index 7014ec07d3..6b0e6a8f6f 100644 --- a/modules/clas/src/main/ClasForm.scala +++ b/modules/clas/src/main/ClasForm.scala @@ -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 + ) } diff --git a/modules/clas/src/main/Student.scala b/modules/clas/src/main/Student.scala index d770ee0ac2..fc111f8792 100644 --- a/modules/clas/src/main/Student.scala +++ b/modules/clas/src/main/Student.scala @@ -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 diff --git a/modules/security/src/main/DataForm.scala b/modules/security/src/main/DataForm.scala index e6f8da100d..32e44a1196 100644 --- a/modules/security/src/main/DataForm.scala +++ b/modules/security/src/main/DataForm.scala @@ -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