Commit e524a4d2 authored by Björn Eyselein's avatar Björn Eyselein
Browse files

Added login from moodle

parent 295cad3c
......@@ -16,6 +16,56 @@ import scala.language.postfixOps
class LoginController @Inject()(cc: ControllerComponents, val dbConfigProvider: DatabaseConfigProvider, val tableDefs: TableDefs)(implicit ec: ExecutionContext)
extends AbstractController(cc) with HasDatabaseConfigProvider[JdbcProfile] with play.api.i18n.I18nSupport {
def lti: Action[AnyContent] = Action.async {
implicit request =>
request.body.asFormUrlEncoded match {
case None => Future(BadRequest("Body did not contain awaited values..."))
case Some(data) =>
def onError: Form[LtiFormValues] => Future[Result] = { formWithErrors =>
formWithErrors.errors.foreach(println)
Future(BadRequest("The form was not valid!"))
}
def onRead: LtiFormValues => Future[Result] = { ltiFormValues =>
for {
user <- selectOrInsertUser(ltiFormValues.username)
course <- selectOrInsertCourse(ltiFormValues.courseIdentifier, ltiFormValues.courseName)
_ <- selectOrInsertUserInCourse(user, course)
} yield Redirect(routes.HomeController.index()).withSession(idName -> user.username)
}
FormMappings.ltiValuesForm.bindFromRequest().fold(onError, onRead)
}
}
private def selectOrInsertUser(username: String): Future[User] = tableDefs.futureUserByUserName(username) flatMap {
case Some(user) => Future.successful(user)
case None =>
val newUser = User(username)
tableDefs.futureInsertUser(newUser) map {
case true => newUser
case false => ???
}
}
private def selectOrInsertCourse(id: String, name: String): Future[Course] = tableDefs.futureCourseById(id) flatMap {
case Some(course) => Future.successful(course)
case None =>
val newCourse = Course(id, name)
tableDefs.futureInsertCourse(newCourse) map {
case true => newCourse
case false => ???
}
}
private def selectOrInsertUserInCourse(user: User, course: Course): Future[Boolean] = tableDefs.futureUserInCourse(user, course) flatMap {
case true => Future.successful(true)
case false => tableDefs.futureAddUserToCourse(user, course)
}
def registerForm: Action[AnyContent] = Action {
implicit request => Ok(views.html.forms.registerForm(FormMappings.registerValuesForm))
}
......@@ -30,7 +80,7 @@ class LoginController @Inject()(cc: ControllerComponents, val dbConfigProvider:
val newUser = User(credentials.username)
val pwHash = UserPassword(credentials.username, credentials.pw.bcrypt)
tableDefs.futureSaveUser(newUser) flatMap {
tableDefs.futureInsertUser(newUser) flatMap {
case false => Future(BadRequest("Could not save user!"))
case true => tableDefs.futureSavePwHash(pwHash) map {
_ => Redirect(routes.LoginController.loginForm())
......
......@@ -10,6 +10,8 @@ final case class RegisterFormValues(username: String, pw: String, pwRepeat: Stri
final case class NewCollectionFormValues()
final case class LtiFormValues(username: String, courseName: String, courseIdentifier: String)
object FormMappings {
val loginValuesForm: Form[LoginFormValues] = Form(
......@@ -31,4 +33,12 @@ object FormMappings {
val newCollectionValuesForm: Form[String] = Form(single(nameName -> nonEmptyText))
val ltiValuesForm: Form[LtiFormValues] = Form(
mapping(
"ext_user_username" -> nonEmptyText,
"context_label" -> nonEmptyText,
"context_title" -> nonEmptyText
)(LtiFormValues.apply)(LtiFormValues.unapply)
)
}
......@@ -12,6 +12,10 @@ final case class User(username: String, isAdmin: Boolean = false)
final case class UserPassword(username: String, pwHash: String)
// Course
final case class Course(id: String, name: String)
// Languages and Collections
final case class Language(id: Int, name: String)
......
package model.persistence
import model.Consts.usernameName
import model.{User, UserPassword}
import model.Consts._
import model.{Course, User, UserPassword}
import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider}
import slick.jdbc.JdbcProfile
import slick.lifted.ProvenShape
import slick.lifted.{ForeignKeyQuery, PrimaryKey, ProvenShape}
import scala.concurrent.{ExecutionContext, Future}
......@@ -22,16 +22,40 @@ trait UserTableDefs extends HasDatabaseConfigProvider[JdbcProfile] {
protected val userPasswordsTQ: TableQuery[UserPasswordsTable] = TableQuery[UserPasswordsTable]
// Queries
protected val coursesTQ: TableQuery[CoursesTable] = TableQuery[CoursesTable]
protected val usersInCoursesTQ: TableQuery[UsersInCoursesTable] = TableQuery[UsersInCoursesTable]
// Queries - User
def futureUserByUserName(username: String): Future[Option[User]] = db.run(usersTQ.filter(_.username === username).result.headOption)
def futurePwHashForUser(username: String): Future[Option[UserPassword]] = db.run(userPasswordsTQ.filter(_.username === username).result.headOption)
def futureInsertUser(user: User): Future[Boolean] = db.run(usersTQ += user).transform(_ == 1, identity)
// Queries - UserPasswords
def futureSaveUser(user: User): Future[Boolean] = db.run(usersTQ += user).transform(_ == 1, identity)
def futurePwHashForUser(username: String): Future[Option[UserPassword]] = db.run(userPasswordsTQ.filter(_.username === username).result.headOption)
def futureSavePwHash(userPassword: UserPassword): Future[Boolean] = db.run(userPasswordsTQ += userPassword).transform(_ == 1, identity)
// Queries - Courses
def futureAllCourses: Future[Seq[Course]] = db.run(coursesTQ.result)
def futureCourseById(id: String): Future[Option[Course]] = db.run(coursesTQ.filter(_.id === id).result.headOption)
def futureInsertCourse(course: Course): Future[Boolean] = db.run(coursesTQ += course).transform(_ == 1, identity)
// Queries - UsersInCourses
def futureUserInCourse(user: User, course: Course): Future[Boolean] =
db.run(usersInCoursesTQ.filter {
uic => uic.username === user.username && uic.courseId === course.id
}.result.map(_.nonEmpty))
def futureAddUserToCourse(user: User, course: Course): Future[Boolean] =
db.run(usersInCoursesTQ += (user.username, course.id)).transform(_ == 1, identity)
// Table definitions
class UsersTable(tag: Tag) extends Table[User](tag, "users") {
......@@ -55,4 +79,33 @@ trait UserTableDefs extends HasDatabaseConfigProvider[JdbcProfile] {
}
class CoursesTable(tag: Tag) extends Table[Course](tag, "courses") {
def id: Rep[String] = column[String](idName, O.PrimaryKey)
def name: Rep[String] = column[String](nameName)
override def * : ProvenShape[Course] = (id, name) <> (Course.tupled, Course.unapply)
}
class UsersInCoursesTable(tag: Tag) extends Table[(String, String)](tag, "users_in_courses") {
def username: Rep[String] = column[String](usernameName)
def courseId: Rep[String] = column[String]("course_id")
def pk: PrimaryKey = primaryKey("pk", (username, courseId))
def userFk: ForeignKeyQuery[UsersTable, User] = foreignKey("uic_user_fk", username, usersTQ)(_.username)
def courseFk: ForeignKeyQuery[CoursesTable, Course] = foreignKey("uic_course_fk", courseId, coursesTQ)(_.id)
def * : ProvenShape[(String, String)] = (username, courseId)
}
}
......@@ -29,6 +29,28 @@ values ('first_user', '$2a$10$6loikDKMzBkdP1HG33BeheyhF7e1.gNBx3mM1CiePRg2AaicJm
('second_user', '$2a$10$Mjaar2EAS0olPjsWRNozcuEsST/IMhgt.iPJX9qBCDoBLmyv/WaSq'),
('third_user', '$2a$10$hQjCkndxdP7185BRjM8fJuFLr0UrySpyN4/dKhrjxr.9dAcMRqha.');
-- Courses
create table if not exists courses
(
id varchar(50) primary key,
name varchar(100) not null
);
-- Users <-> Courses
create table if not exists users_in_courses
(
username varchar(50),
course_id varchar(50),
primary key (username, course_id),
foreign key (username) references users (username)
on update cascade on delete cascade,
foreign key (course_id) references courses (id)
on update cascade on delete cascade
);
-- Language
create table if not exists languages
......@@ -209,6 +231,10 @@ drop table if exists user_learns_language;
drop table if exists languages;
drop table if exists users_in_courses;
drop table if exists courses;
drop table if exists user_passwords;
drop table if exists users;
......@@ -10,6 +10,9 @@ GET /loginForm
POST /login controllers.LoginController.login
GET /logout controllers.LoginController.logout
+ nocsrf
POST /lti controllers.LoginController.lti
# Languages
GET /languages controllers.HomeController.allLanguages
......@@ -20,7 +23,7 @@ GET /deselectLanguage/:langId
GET /languages/:langId/collections/:collId controllers.HomeController.collection(langId: Int, collId: Int)
GET /languages/:langId/collections/:collId/startLearning/:isRepeating controllers.HomeController.startLearning(langId: Int, collId: Int, isRepeating: Boolean)
GET /languages/:langId/collections/:collId/startLearning/:isRepeating controllers.HomeController.startLearning(langId: Int, collId: Int, isRepeating: Boolean)
GET /languages/:langId/collections/:collId/cards/:cardId/learn/:isRepeating controllers.HomeController.learn(langId: Int, collId: Int, cardId:Int, isRepeating: Boolean)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment