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

Outsourcing from HomeController

parent 14a1a761
......@@ -61,9 +61,9 @@ function readSolution(cardType: string): Solution | null {
}
function onCorrectionSuccess(result: CorrectionResult): void {
console.info(JSON.stringify(result, null, 2));
// console.info(JSON.stringify(result, null, 2));
correctionTextPar.prop('hidden', false).text('Ihre Lösung war ' + (result.correct ? '' : 'nicht ') + 'korrekt.');
correctionTextPar.text('Ihre Lösung war ' + (result.correct ? '' : 'nicht ') + 'korrekt.');
if (result.correct) {
checkSolutionBtn.prop('disabled', true);
......
package controllers
import model._
import play.api.mvc._
import scala.concurrent.{ExecutionContext, Future}
trait ControllerHelpers extends Secured {
self: AbstractController =>
protected val tableDefs: TableDefs
private def onNoSuchLanguage(langId: Int): Result = NotFound(s"Es gibt keine Sprache mit der ID $langId")
private def onNoSuchCollection(language: Language, collId: Int): Result =
NotFound(s"Es gibt keine Sammlung mit der ID $collId für die Sprache ${language.name}")
private def onNuSuchFlashcard(language: Language, collection: Collection, cardId: Int): Result =
NotFound(s"Es gibt keine Karteikarte mit der ID $cardId für die Sammlung ${collection.name} für die Sprache ${language.name}")
protected def futureWithUserAndLanguage(langId: Int)(f: (User, Language) => Request[AnyContent] => Future[Result])
(implicit ec: ExecutionContext): EssentialAction =
futureWithUser { user =>
implicit request =>
tableDefs.futureLanguageById(langId) flatMap {
case None => Future(onNoSuchLanguage(langId))
case Some(language) => f(user, language)(request)
}
}
protected def futureWithUserAndCollection(langId: Int, collId: Int)(f: (User, Language, Collection) => Request[AnyContent] => Future[Result])
(implicit ec: ExecutionContext): EssentialAction =
futureWithUserAndLanguage(langId) { (user, language) =>
implicit request =>
tableDefs.futureCollectionById(language, collId) flatMap {
case None => Future(onNoSuchCollection(language, collId))
case Some(collection) => f(user, language, collection)(request)
}
}
protected def withUserAndCompleteFlashcard(langId: Int, collId: Int, cardId: Int)
(f: (User, Language, Collection, CompleteFlashcard) => Request[AnyContent] => Result)
(implicit ec: ExecutionContext): EssentialAction =
futureWithUserAndCollection(langId, collId) { (user, language, collection) =>
implicit request =>
tableDefs.futureFlashcardById(collection, cardId) flatMap {
case None => Future(onNuSuchFlashcard(language, collection, cardId))
case Some(flashcard) => tableDefs.futureChoiceAnswersForFlashcard(flashcard) map {
answers => f(user, language, collection, CompleteFlashcard(flashcard, answers))(request)
}
}
}
protected def futureWithUserAndCompleteFlashcard(langId: Int, collId: Int, cardId: Int)
(f: (User, Language, Collection, CompleteFlashcard) => Request[AnyContent] => Future[Result])
(implicit ec: ExecutionContext): EssentialAction =
futureWithUserAndCollection(langId, collId) { (user, language, collection) =>
implicit request =>
tableDefs.futureFlashcardById(collection, cardId) flatMap {
case None => Future(onNuSuchFlashcard(language, collection, cardId))
case Some(flashcard) => tableDefs.futureChoiceAnswersForFlashcard(flashcard) flatMap {
answers => f(user, language, collection, CompleteFlashcard(flashcard, answers))(request)
}
}
}
}
package controllers
import javax.inject.{Inject, Singleton}
import model._
import model.{Corrector, JsonFormats, TableDefs}
import play.api.libs.json.{JsError, JsSuccess}
import play.api.mvc._
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.ExecutionContext
@Singleton
class HomeController @Inject()(cc: ControllerComponents, protected val tableDefs: TableDefs)(implicit ec: ExecutionContext)
extends AbstractController(cc) with Secured with play.api.i18n.I18nSupport {
// Helper methods
private def onNoSuchLanguage(langId: Int): Result = NotFound(s"Es gibt keine Sprache mit der ID $langId")
private def onNoSuchCollection(language: Language, collId: Int): Result =
NotFound(s"Es gibt keine Sammlung mit der ID $collId für die Sprache ${language.name}")
private def onNuSuchFlashcard(language: Language, collection: Collection, cardId: Int): Result =
NotFound(s"Es gibt keine Karteikarte mit der ID $cardId für die Sammlung ${collection.name} für die Sprache ${language.name}")
private def futureWithUserAndLanguage(langId: Int)(f: (User, Language) => Request[AnyContent] => Future[Result]): EssentialAction =
futureWithUser { user =>
implicit request =>
tableDefs.futureLanguageById(langId) flatMap {
case None => Future(onNoSuchLanguage(langId))
case Some(language) => f(user, language)(request)
}
}
// private def withUserLanguageAndCollection(langId: Int, collId: Int)(f: (User, Language, Collection) => Request[AnyContent] => Result): EssentialAction =
// futureWithUserAndLanguage(langId) { (user, language) =>
// implicit request =>
// tableDefs.futureCollectionById(language, collId) map {
// case None => onNoSuchCollection(language, collId)
// case Some(collection) => f(user, language, collection)(request)
// }
// }
private def futureWithUserAndCollection(langId: Int, collId: Int)(f: (User, Language, Collection) => Request[AnyContent] => Future[Result]): EssentialAction =
futureWithUserAndLanguage(langId) { (user, language) =>
implicit request =>
tableDefs.futureCollectionById(language, collId) flatMap {
case None => Future(onNoSuchCollection(language, collId))
case Some(collection) => f(user, language, collection)(request)
}
}
private def withUserAndCompleteFlashcard(langId: Int, collId: Int, cardId: Int)
(f: (User, Language, Collection, CompleteFlashcard) => Request[AnyContent] => Result): EssentialAction =
futureWithUserAndCollection(langId, collId) { (user, language, collection) =>
implicit request =>
tableDefs.futureFlashcardById(collection, cardId) flatMap {
case None => Future(onNuSuchFlashcard(language, collection, cardId))
case Some(flashcard) => tableDefs.futureChoiceAnswersForFlashcard(flashcard) map {
answers => f(user, language, collection, CompleteFlashcard(flashcard, answers))(request)
}
}
}
private def futureWithUserAndCompleteFlashcard(langId: Int, collId: Int, cardId: Int)
(f: (User, Language, Collection, CompleteFlashcard) => Request[AnyContent] => Future[Result]): EssentialAction =
futureWithUserAndCollection(langId, collId) { (user, language, collection) =>
implicit request =>
tableDefs.futureFlashcardById(collection, cardId) flatMap {
case None => Future(onNuSuchFlashcard(language, collection, cardId))
case Some(flashcard) => tableDefs.futureChoiceAnswersForFlashcard(flashcard) flatMap {
answers => f(user, language, collection, CompleteFlashcard(flashcard, answers))(request)
}
}
}
extends AbstractController(cc) with ControllerHelpers with play.api.i18n.I18nSupport {
// Routes
......@@ -123,23 +62,25 @@ class HomeController @Inject()(cc: ControllerComponents, protected val tableDefs
def startLearning(langId: Int, collId: Int): EssentialAction = futureWithUserAndCollection(langId, collId) { (user, _, collection) =>
implicit request =>
tableDefs.futureMaybeIdentifierNextFlashcardToLearn(user, collection) map {
case None => ???
case None => Redirect(routes.HomeController.collection(langId, collId))
case Some(identifier) => Redirect(routes.HomeController.learn(identifier.langId, identifier.collId, identifier.cardId))
}
}
def learn(langId: Int, collId: Int, cardId: Int): EssentialAction = withUserAndCompleteFlashcard(langId, collId, cardId) { (user, language, collection, completeFlashcard) =>
implicit request => Ok(views.html.learn(user, completeFlashcard))
def learn(langId: Int, collId: Int, cardId: Int): EssentialAction = withUserAndCompleteFlashcard(langId, collId, cardId) { (user, _, _, completeFlashcard) =>
implicit request => Ok(views.html.learn(user, completeFlashcard, isRepeating = false))
}
def startRepeating(langId: Int, collId: Int): EssentialAction = futureWithUserAndCollection(langId, collId) { (_, _, _) =>
def startRepeating(langId: Int, collId: Int): EssentialAction = futureWithUserAndCollection(langId, collId) { (user, _, collection) =>
implicit request =>
???
tableDefs.futureMaybeIdentifierNextFlashcardToRepeat(user, collection) map {
case None => Redirect(routes.HomeController.collection(langId, collId))
case Some(identifier) => Redirect(routes.HomeController.repeat(identifier.langId, identifier.collId, identifier.cardId))
}
}
def repeat(langId: Int, collId: Int, cardId: Int): EssentialAction = withUserAndCompleteFlashcard(langId, collId, cardId) { (_, _, _, _) =>
implicit request =>
???
def repeat(langId: Int, collId: Int, cardId: Int): EssentialAction = withUserAndCompleteFlashcard(langId, collId, cardId) { (user, _, _, completeFlashcard) =>
implicit request => Ok(views.html.learn(user, completeFlashcard, isRepeating = false))
}
def checkSolution(langId: Int, collId: Int, cardId: Int): EssentialAction = futureWithUserAndCompleteFlashcard(langId, collId, cardId) { (user, _, _, completeFlashcard) =>
......
......@@ -26,7 +26,7 @@ trait Secured {
Security.Authenticated(username, onUnauthorized)(user => controllerComponents.actionBuilder.async(bodyParser)(request => f(user)(request)))
def withUser(f: User => Request[AnyContent] => Result)(implicit ec: ExecutionContext): EssentialAction = withAuth { username =>
protected def withUser(f: User => Request[AnyContent] => Result)(implicit ec: ExecutionContext): EssentialAction = withAuth { username =>
implicit request => {
tableDefs.futureUserByUserName(username) map {
case Some(user) => f(user)(request)
......@@ -35,7 +35,7 @@ trait Secured {
}
}
def futureWithUser(f: User => Request[AnyContent] => Future[Result])(implicit ec: ExecutionContext): EssentialAction = withAuth { username =>
protected def futureWithUser(f: User => Request[AnyContent] => Future[Result])(implicit ec: ExecutionContext): EssentialAction = withAuth { username =>
implicit request =>
tableDefs.futureUserByUserName(username) flatMap {
case Some(user) => f(user)(request)
......
......@@ -104,16 +104,24 @@ class TableDefs @Inject()(override protected val dbConfigProvider: DatabaseConfi
}.size.result)
def futureMaybeIdentifierNextFlashcardToLearn(user: User, collection: Collection): Future[Option[FlashcardIdentifier]] =
db.run(
flashcardsToLearnTQ
.filter { fctl => fctl.collId === collection.id && fctl.langId === collection.langId && fctl.username === user.username }
.result
.headOption
.map {
case None => None
case Some((cardId, collId, langId, _)) => Some(FlashcardIdentifier(cardId, collId, langId))
}
)
db.run(flashcardsToLearnTQ
.filter { fctl => fctl.collId === collection.id && fctl.langId === collection.langId && fctl.username === user.username }
.result
.headOption
.map {
case None => None
case Some((cardId, collId, langId, _)) => Some(FlashcardIdentifier(cardId, collId, langId))
})
def futureMaybeIdentifierNextFlashcardToRepeat(user: User, collection: Collection): Future[Option[FlashcardIdentifier]] =
db.run(flashcardsToRepeatTQ
.filter { fctr => fctr.collId === collection.id && fctr.langId === collection.langId && fctr.username === user.username }
.result
.headOption
.map {
case None => None
case Some((cardId, collId, langId, _, _, _)) => Some(FlashcardIdentifier(cardId, collId, langId))
})
def futureFlashcardsToLearn(user: User, collection: Collection): Future[Seq[Flashcard]] = {
db.run(flashcardsToLearnTQ
......@@ -214,7 +222,7 @@ ON DUPLICATE KEY UPDATE date_answered = NOW(), correct = $correct,
def distanceDays: Rep[Int] = column[Int]("distance_days")
def * : ProvenShape[Bucket] = (id, distanceDays) <> (Bucket.tupled, Bucket.unapply)
override def * : ProvenShape[Bucket] = (id, distanceDays) <> (Bucket.tupled, Bucket.unapply)
}
......@@ -318,7 +326,7 @@ ON DUPLICATE KEY UPDATE date_answered = NOW(), correct = $correct,
class FlashcardsToLearnView(tag: Tag) extends Table[(Int, Int, Int, String)](tag, "flashcards_to_learn") {
def cardId: Rep[Int] = column[Int](idName)
def cardId: Rep[Int] = column[Int]("card_id")
def collId: Rep[Int] = column[Int]("coll_id")
......@@ -340,7 +348,7 @@ ON DUPLICATE KEY UPDATE date_answered = NOW(), correct = $correct,
class FlashcardsToRepeatView(tag: Tag) extends Table[(Int, Int, Int, String, Boolean, Int)](tag, "flashcards_to_repeat") {
def cardId: Rep[Int] = column[Int](idName)
def cardId: Rep[Int] = column[Int]("card_id")
def collId: Rep[Int] = column[Int]("coll_id")
......
@import model.{CardType, CompleteFlashcard, User}
@(user: User, completeFlashcard: CompleteFlashcard)(implicit requestHeader: RequestHeader, messagesProvider: MessagesProvider)
@(user: User, completeFlashcard: CompleteFlashcard, isRepeating: Boolean)(implicit requestHeader: RequestHeader, messagesProvider: MessagesProvider)
@title = @{
"Lernen"
......@@ -38,14 +38,12 @@
</div>
</div>
<br>
<p id="correctionTextPar" hidden>&nbsp;</p>
<p id="correctionTextPar">&nbsp;</p>
}
case CardType.SingleChoice | CardType.MultipleChoice => {
@for(answer <- completeFlashcard.choiceAnswers) {
@for(answer <- scala.util.Random.shuffle(completeFlashcard.choiceAnswers)) {
<p>
<label for="choice_@answer.id">
<input id="choice_@answer.id" name="choice_answers" type="@choiceInputType" data-choiceid="@answer.id">
......@@ -66,7 +64,12 @@
data-href="@routes.HomeController.checkSolution(completeFlashcard.flashcard.langId, completeFlashcard.flashcard.collId, completeFlashcard.flashcard.id)">
Lösung testen
</button>
<a href="@routes.HomeController.startLearning(completeFlashcard.flashcard.langId, completeFlashcard.flashcard.collId)"
<a
@if(isRepeating) {
href="@routes.HomeController.startLearning(completeFlashcard.flashcard.langId, completeFlashcard.flashcard.collId)"
} else {
href="@routes.HomeController.startRepeating(completeFlashcard.flashcard.langId, completeFlashcard.flashcard.collId)"
}
id="nextFlashcardBtn" class="btn btn-large waves-effect blue disabled">Weiter</a>
</div>
}
......
......@@ -173,7 +173,7 @@ create table if not exists users_answered_flashcards
-- Views
create view flashcards_to_learn as
select id, fcs.coll_id, fcs.lang_id, us.username
select id as card_id, fcs.coll_id, fcs.lang_id, us.username
from flashcards fcs
join users us
left outer join users_answered_flashcards uaf
......@@ -188,7 +188,7 @@ from flashcards f
on uaf.card_id = f.id and uaf.coll_id = f.coll_id and uaf.lang_id = f.lang_id
join buckets b on uaf.bucket_id = b.id
where datediff(now(), date_answered) >= b.distance_days
and uaf.correct = false;
or uaf.correct = false;
# --- !Downs
......
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