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

Update IMporter

parent be2b2cce
......@@ -11,7 +11,7 @@ object Importer {
private val cardTypeCellIndex: Int = 0
private val questionCellIndex: Int = 1
private val meaningCellIndex : Int = 2
private val hintCellIndex : Int = 2
private def cardTypeFromString(cardTypeStr: String): Either[String, CardType] = cardTypeStr match {
case "Wort" => Right(CardType.Vocable)
......@@ -56,9 +56,9 @@ object Importer {
val lastCellNum = row.getLastCellNum
val maxCellIndex = if (lastCellNum % 2 == 1) lastCellNum + 1 else lastCellNum
val (_, answers): (Seq[String], Seq[ChoiceAnswer]) = partitionEitherSeq((meaningCellIndex to maxCellIndex by 2).map { cellIndex =>
val (_, answers): (Seq[String], Seq[ChoiceAnswer]) = partitionEitherSeq((hintCellIndex to maxCellIndex by 2).map { cellIndex =>
readStringCell(row, cellIndex) map { answer =>
val id = (cellIndex - meaningCellIndex) / 2
val id = (cellIndex - hintCellIndex) / 2
val correctnessCellStringValue = row.getCell(cellIndex + 1, MissingCellPolicy.CREATE_NULL_AS_BLANK).getStringCellValue
......@@ -72,21 +72,26 @@ object Importer {
}
private def readTextualRow(row: ExcelRow, courseId: Int, collId: Int, cardType: CardType, question: String): Either[String, Flashcard] =
readStringCell(row, meaningCellIndex) map { meaning =>
Flashcard(row.getRowNum, collId, courseId, cardType, question, meaning)
}
private def readTextualRow(
row: ExcelRow, courseId: Int, collId: Int, cardType: CardType, question: String
): Either[String, Flashcard] = for {
questionHint <- readOptionalStringCell(row, hintCellIndex)
meaning <- readStringCell(row, hintCellIndex + 1)
meaningHint <- readOptionalStringCell(row, hintCellIndex + 2)
} yield Flashcard(row.getRowNum, collId, courseId, cardType, question, questionHint, meaning, meaningHint)
private def readBlankRow(row: ExcelRow, courseId: Int, collId: Int, question: String): Either[String, Flashcard] = {
val cardId = row.getRowNum
val (_, answers): (Seq[String], Seq[BlanksAnswer]) = partitionEitherSeq((meaningCellIndex to row.getLastCellNum).map { cellIndex =>
val (_, answers): (Seq[String], Seq[BlanksAnswerFragment]) = partitionEitherSeq((hintCellIndex to row.getLastCellNum).map { cellIndex =>
readStringCell(row, cellIndex) map {
answer => BlanksAnswer(cellIndex - meaningCellIndex, cardId, collId, courseId, answer)
answer =>
val isAnswer: Boolean = (cellIndex - hintCellIndex) % 2 == 0
BlanksAnswerFragment(cellIndex - hintCellIndex, cardId, collId, courseId, answer, isAnswer)
}
})
Right(Flashcard(cardId, collId, courseId, CardType.Blank, question, meaning = "", answers))
Right(Flashcard(cardId, collId, courseId, CardType.Blank, question, blanksAnswers = answers))
}
private def readRow(row: ExcelRow, courseId: Int, collId: Int): Either[String, Flashcard] = for {
......@@ -100,7 +105,6 @@ object Importer {
}
} yield flashcard
private def readStringCell(row: ExcelRow, index: Int): Either[String, String] = {
val cell = row.getCell(index, MissingCellPolicy.CREATE_NULL_AS_BLANK)
......@@ -110,4 +114,14 @@ object Importer {
}
}
private def readOptionalStringCell(row: ExcelRow, index: Int): Either[String, Option[String]] = {
val cell = row.getCell(index, MissingCellPolicy.CREATE_NULL_AS_BLANK)
cell.getCellType match {
case CellType.BLANK => Right(None)
case CellType.STRING => Right(Some(cell.getStringCellValue.trim))
case other => Left(s"Column $index of row ${row.getRowNum} should be a string but was ${other.name()}")
}
}
}
......@@ -46,8 +46,10 @@ final case class Flashcard(
cardId: Int, collId: Int, courseId: Int,
cardType: CardType,
question: String,
questionHint: Option[String] = None,
meaning: String = "",
blanksAnswers: Seq[BlanksAnswer] = Seq.empty,
meaningHint: Option[String] = None,
blanksAnswers: Seq[BlanksAnswerFragment] = Seq.empty,
choiceAnswers: Seq[ChoiceAnswer] = Seq.empty
) {
......@@ -55,21 +57,20 @@ final case class Flashcard(
}
sealed trait CardAnswer {
sealed trait FlashcardComponent {
val answerId: Int
val cardId : Int
val collId : Int
val courseId: Int
val answer : String
}
// Blanks
final case class BlanksAnswer(answerId: Int, cardId: Int, collId: Int, courseId: Int, answer: String) extends CardAnswer
final case class BlanksAnswerFragment(answerId: Int, cardId: Int, collId: Int, courseId: Int, answer: String, isAnswer: Boolean) extends FlashcardComponent
// Single and Multiple choice
final case class ChoiceAnswer(answerId: Int, cardId: Int, collId: Int, courseId: Int, answer: String, correctness: Correctness) extends CardAnswer
final case class ChoiceAnswer(answerId: Int, cardId: Int, collId: Int, courseId: Int, answer: String, correctness: Correctness) extends FlashcardComponent
sealed trait Correctness extends EnumEntry
......
......@@ -28,7 +28,7 @@ trait CoursesCollectionsFlashcardsTableDefs
protected val choiceAnswersTQ: TableQuery[ChoiceAnswersTable] = TableQuery[ChoiceAnswersTable]
protected val blanksAnswersTQ: TableQuery[BlanksAnswersTable] = TableQuery[BlanksAnswersTable]
protected val blanksAnswersTQ: TableQuery[BlanksAnswerFragmentsTable] = TableQuery[BlanksAnswerFragmentsTable]
// Column types
......@@ -84,19 +84,23 @@ trait CoursesCollectionsFlashcardsTableDefs
def question: Rep[String] = column[String](questionName)
def questionHint: Rep[Option[String]] = column[Option[String]]("question_hint")
def meaning: Rep[String] = column[String](meaningName)
def meaningHint: Rep[Option[String]] = column[Option[String]]("meaning_hint")
def pk: PrimaryKey = primaryKey("fc_pk", (id, collId, courseId))
def collFk: ForeignKeyQuery[CollectionsTable, Collection] = foreignKey("fc_coll_fk", (collId, courseId), collectionsTQ)(coll => (coll.id, coll.courseId))
override def * : ProvenShape[DBFlashcard] = (id, collId, courseId, flashcardType, question, meaning) <> (DBFlashcard.tupled, DBFlashcard.unapply)
override def * : ProvenShape[DBFlashcard] = (id, collId, courseId, flashcardType, question, questionHint, meaning, meaningHint) <> (DBFlashcard.tupled, DBFlashcard.unapply)
}
abstract class CardAnswersTable[CA <: CardAnswer](tag: Tag, tableName: String) extends Table[CA](tag, tableName) {
abstract class FlashcardComponentsTable[FC <: FlashcardComponent](tag: Tag, tableName: String) extends Table[FC](tag, tableName) {
def id: Rep[Int] = column[Int](idName, O.AutoInc)
......@@ -109,13 +113,13 @@ trait CoursesCollectionsFlashcardsTableDefs
def answer: Rep[String] = column[String](answerName)
def pk: PrimaryKey = primaryKey("ca_pk", (id, cardId, collId))
def pk: PrimaryKey = primaryKey("ca_pk", (id, cardId, collId, courseId))
def cardFk: ForeignKeyQuery[FlashcardsTable, DBFlashcard] = foreignKey("ca_card_fk", (cardId, collId), flashcardsTQ)(fc => (fc.id, fc.collId))
def cardFk: ForeignKeyQuery[FlashcardsTable, DBFlashcard] = foreignKey("ca_card_fk", (cardId, collId, courseId), flashcardsTQ)(fc => (fc.id, fc.collId, fc.courseId))
}
class ChoiceAnswersTable(tag: Tag) extends CardAnswersTable[ChoiceAnswer](tag, "choice_answers") {
class ChoiceAnswersTable(tag: Tag) extends FlashcardComponentsTable[ChoiceAnswer](tag, "choice_answers") {
def correctness: Rep[Correctness] = column[Correctness](correctnessName)
......@@ -124,9 +128,12 @@ trait CoursesCollectionsFlashcardsTableDefs
}
class BlanksAnswersTable(tag: Tag) extends CardAnswersTable[BlanksAnswer](tag, "blanks_answers") {
class BlanksAnswerFragmentsTable(tag: Tag) extends FlashcardComponentsTable[BlanksAnswerFragment](tag, "blanks_answer_fragments") {
def isAnswer: Rep[Boolean] = column[Boolean]("is_answer")
override def * : ProvenShape[BlanksAnswer] = (id, cardId, collId, courseId, answer) <> (BlanksAnswer.tupled, BlanksAnswer.unapply)
override def * : ProvenShape[BlanksAnswerFragment] = (id, cardId, collId, courseId, answer, isAnswer) <> (BlanksAnswerFragment.tupled, BlanksAnswerFragment.unapply)
}
......
package model.persistence
import model.{BlanksAnswer, ChoiceAnswer, Collection, Course, Flashcard}
import model.{BlanksAnswerFragment, ChoiceAnswer, Collection, Course, Flashcard}
import scala.concurrent.Future
......@@ -41,7 +41,7 @@ trait CoursesCollectionsFlashcardsTableQueries {
def futureInsertCollection(collection: Collection): Future[Boolean] = db.run(collectionsTQ += collection).transform(_ == 1, identity)
private def blanksAnswersForDbFlashcard(dbfc: DBFlashcard): Future[Seq[BlanksAnswer]] = {
private def blanksAnswersForDbFlashcard(dbfc: DBFlashcard): Future[Seq[BlanksAnswerFragment]] = {
val blanksAnswersForDbFlashcardQuery = blanksAnswersTQ.filter {
ba => ba.cardId === dbfc.cardId && ba.collId === dbfc.collId
}.result
......@@ -119,7 +119,7 @@ trait CoursesCollectionsFlashcardsTableQueries {
private def futureInsertChoiceAnswer(choiceAnswer: ChoiceAnswer): Future[Boolean] =
db.run(choiceAnswersTQ insertOrUpdate choiceAnswer).transform(_ == 1, identity)
private def futureInsertBlanksAnswer(blanksAnswer: BlanksAnswer): Future[Boolean] =
private def futureInsertBlanksAnswer(blanksAnswer: BlanksAnswerFragment): Future[Boolean] =
db.run(blanksAnswersTQ insertOrUpdate blanksAnswer).transform(_ == 1, identity)
}
......@@ -5,21 +5,21 @@ import model._
object PersistenceModels {
def flashcardToDbFlashcard(fc: Flashcard): DBCompleteFlashcard = DBCompleteFlashcard(
flashcard = DBFlashcard(fc.cardId, fc.collId, fc.courseId, fc.cardType, fc.question, fc.meaning),
flashcard = DBFlashcard(fc.cardId, fc.collId, fc.courseId, fc.cardType, fc.question, fc.questionHint, fc.meaning, fc.meaningHint),
choiceAnswers = fc.choiceAnswers, blanksAnswers = fc.blanksAnswers
)
def dbFlashcardToFlashcard(dbfc: DBCompleteFlashcard): Flashcard = dbfc match {
case DBCompleteFlashcard(DBFlashcard(cardId, collId, courseId, cardType, question, meaning), choiceAnswers, blanksAnswers) =>
Flashcard(cardId, collId, courseId, cardType, question, meaning, blanksAnswers, choiceAnswers)
case DBCompleteFlashcard(DBFlashcard(cardId, collId, courseId, cardType, question, questionHint, meaning, meaningHint), choiceAnswers, blanksAnswers) =>
Flashcard(cardId, collId, courseId, cardType, question, questionHint, meaning, meaningHint, blanksAnswers, choiceAnswers)
}
}
final case class DBFlashcard(cardId: Int, collId: Int, courseId: Int, cardType: CardType, question: String, meaning: String)
final case class DBFlashcard(cardId: Int, collId: Int, courseId: Int, cardType: CardType, question: String, questionHint: Option[String], meaning: String, meaningHint: Option[String])
final case class DBCompleteFlashcard(flashcard: DBFlashcard, choiceAnswers: Seq[ChoiceAnswer], blanksAnswers: Seq[BlanksAnswer])
final case class DBCompleteFlashcard(flashcard: DBFlashcard, choiceAnswers: Seq[ChoiceAnswer], blanksAnswers: Seq[BlanksAnswerFragment])
trait FlashcardToDoData {
......
......@@ -40,7 +40,7 @@
<div class="row">
<div class="col s12">
<a href="@routes.AdminController.uploadCardsFileForm(courseId, collection.id)"
class="btn btn-large waves-effect waves-block @accentColor">Sammlung erstellen</a>
class="btn btn-large waves-effect waves-block @accentColor">Karten importieren</a>
</div>
</div>
......
......@@ -5,7 +5,7 @@
)
@title = @{
"Lernen"
"Vokabeln " + (if(isRepeating) "wiederholen" else "Lernen")
}
@scripts = {
......@@ -25,7 +25,7 @@
<div class="row">
<div class="col s12 l8 offset-l2" id="flashcardDiv" data-cardtype="@flashcard.cardType">
<div class="card-panel">
<h4 class="center-align">@flashcard.question</h4>
<h4 class="center-align">@flashcard.question @flashcard.questionHint.map(h => Html(s"<i>$h</i>")).getOrElse(Html(""))</h4>
</div>
<p class="center-align">
......
......@@ -82,7 +82,9 @@ create table if not exists flashcards
course_id int,
flash_card_type enum ('Vocable', 'Text', 'Blank', 'Choice') not null default 'Vocable',
question text not null,
question_hint text,
meaning text not null,
meaning_hint text,
primary key (id, coll_id, course_id),
foreign key (coll_id, course_id) references collections (id, course_id)
......@@ -120,13 +122,14 @@ values (1, 4, 1, 1, 'Maskulinum', 'CORRECT'),
(3, 5, 1, 1, 'Wörter auf -x sind meist weiblich', 'CORRECT'),
(4, 5, 1, 1, 'Wörter auf -en sind immer neutrum', 'CORRECT');
create table if not exists blanks_answers
create table if not exists blanks_answer_fragments
(
id int,
card_id int,
coll_id int,
course_id int,
answer text not null,
answer text not null,
is_answer boolean not null default false,
primary key (id, card_id, coll_id, course_id),
foreign key (card_id, coll_id, course_id) references flashcards (id, coll_id, course_id)
......@@ -183,7 +186,7 @@ drop table if exists users_answered_flashcards;
drop table if exists buckets;
drop table if exists blanks_answers;
drop table if exists blanks_answer_fragments;
drop table if exists choice_answers;
......
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