Fixes export bugs

parent 0d2864c8
{"export":{"page_header":"&LQuiz-Statistik und Ranglisten generiert in einer Live-Session mit arsnova.click&R__createdAt__","page_footer":"&L&A&Carsnova.click ist Open Source Software, siehe arsnova.io&R &P/&N","summary":"Zusammenfassung","exported_at_date":"Exportiert am","session_content":"Archivierte Quizfragen (Um das Quiz zu importieren, kopiere den vollständigen Zellinhalt in eine leere .json-Datei. Importiere dann die Datei mit dem entsprechenden Icon in der Fußzeile der App.)","cas_account_id":"CAS Account-ID","cas_account_email":"CAS E-Mail","quiz_name":"Quizname","question":"Quizfrage","question_type":"Typ der Quizfrage","number_of_answers":"Anzahl der Antworten","percent_correct":"Korrekte Antworten (in %)","answer":"Antwort","attendee":"Teilnehmer/in","attendee_complete_correct":"Teilnehmer/innen mit vollständig richtig beantworteten Fragen","attendee_complete_correct_none_available":"Keine Einträge vorhanden","correct_questions_none_available":"Keine","attendee_all_entries":"Alle Teilnehmer/innen","time":"Antwortzeit (in ms)","confidence_level":"Antwortsicherheit","correct_value":"Richtiger Wert","min_range":"Mindestwert","max_range":"Maximalwert","correct_questions":"Richtig beantwortete Fragen","overall_response_time":"Kumulierte Antwortzeit (in ms)","average_response_time":"Durchschnittliche Antwortzeit (in ms)","number_attendees":"Anzahl der Teilnehmer/innen","average_number_attendees_participated":"Durchschnittliche Teilnahmen am Quiz (in %)","average_correct_answered_questions":"Durchschnittlich richtig beantwortete Fragen","average_confidence":"Durchschnittliche Antwortsicherheit (in %)","exported_at":"um","exported_at_time":"Uhr","type":{"SurveyQuestion":"Umfragen","TrueFalseSingleChoiceQuestion":"Wahr-Falsch Frage","YesNoSingleChoiceQuestion":"Ja-Nein Frage","ABCDSingleChoiceQuestion":"ABCD Single-Choice Frage","SingleChoiceQuestion":"Single-Choice Frage","RangedQuestion":"Schätzfrage","FreeTextQuestion":"Freitext Frage","MultipleChoiceQuestion":"Multiple-Choice Frage"}},"view":{"answeroptions":{"free_text_question":{"config_case_sensitive":"Groß- und Kleinschreibung beachten","config_trim_whitespaces":"Leerzeichen entfernen","config_use_keywords":"Reihenfolge der Wörter beachten","config_use_punctuation":"Interpunktion beachten"}}},"global":{"no":"Nein","yes":"Ja"}}
\ No newline at end of file
{
"export": {
"page_header": "&LQuiz-Statistik und Ranglisten generiert in einer Live-Session mit arsnova.click&R__createdAt__",
"page_footer": "&L&A&Carsnova.click ist Open Source Software, siehe arsnova.io&R &P/&N",
"summary": "Zusammenfassung",
"exported_at_date": "Exportiert am",
"session_content": "Archivierte Quizfragen (Um das Quiz zu importieren, kopiere den vollständigen Zellinhalt in eine leere .json-Datei. Importiere dann die Datei mit dem entsprechenden Icon in der Fußzeile der App.)",
"cas_account_id": "CAS Account-ID",
"cas_account_email": "CAS E-Mail",
"quiz_name": "Quizname",
"question": "Quizfrage",
"question_type": "Typ der Quizfrage",
"number_of_answers": "Anzahl der Antworten",
"percent_correct": "Korrekte Antworten (in %)",
"answer": "Antwort",
"attendee": "Teilnehmer/in",
"attendee_complete_correct": "Teilnehmer/innen mit vollständig richtig beantworteten Fragen",
"attendee_complete_correct_none_available": "Keine Einträge vorhanden",
"correct_questions_none_available": "Keine",
"attendee_all_entries": "Alle Teilnehmer/innen",
"time": "Antwortzeit (in ms)",
"confidence_level": "Antwortsicherheit",
"correct_value": "Richtiger Wert",
"min_range": "Mindestwert",
"max_range": "Maximalwert",
"correct_questions": "Richtig beantwortete Fragen",
"overall_response_time": "Kumulierte Antwortzeit (in ms)",
"average_response_time": "Durchschnittliche Antwortzeit (in ms)",
"number_attendees": "Anzahl der Teilnehmer/innen",
"average_number_attendees_participated": "Durchschnittliche Teilnahmen am Quiz (in %)",
"average_correct_answered_questions": "Durchschnittlich richtig beantwortete Fragen",
"average_confidence": "Durchschnittliche Antwortsicherheit (in %)",
"exported_at": "um",
"exported_at_time": "Uhr",
"type": {
"SurveyQuestion": "Umfrage",
"TrueFalseSingleChoiceQuestion": "Wahr-Falsch Frage",
"YesNoSingleChoiceQuestion": "Ja-Nein Frage",
"ABCDSingleChoiceQuestion": "ABCD Single-Choice Frage",
"SingleChoiceQuestion": "Single-Choice Frage",
"RangedQuestion": "Schätzfrage",
"FreeTextQuestion": "Freitext Frage",
"MultipleChoiceQuestion": "Multiple-Choice Frage"
}
},
"view": {
"answeroptions": {
"free_text_question": {
"config_case_sensitive": "Groß- und Kleinschreibung beachten",
"config_trim_whitespaces": "Leerzeichen entfernen",
"config_use_keywords": "Reihenfolge der Wörter beachten",
"config_use_punctuation": "Interpunktion beachten"
}
}
},
"global": {
"no": "Nein",
"yes": "Ja"
}
}
\ No newline at end of file
......@@ -183,7 +183,7 @@ export class MemberEntity extends AbstractEntity implements IMemberEntity {
responses[i] = {
value: [],
responseTime: -1,
confidence: 0,
confidence: -1,
readingConfirmation: false,
};
}
......
import * as xlsx from 'excel4node';
import * as MessageFormat from 'messageformat';
import MemberDAO from '../db/MemberDAO';
import { AbstractQuestionEntity } from '../entities/question/AbstractQuestionEntity';
import { IMemberEntity } from '../interfaces/entities/Member/IMemberEntity';
import { ILeaderBoardItemBase } from '../interfaces/leaderboard/ILeaderBoardItemBase';
import { IQuizEntity } from '../interfaces/quizzes/IQuizEntity';
......@@ -78,7 +77,7 @@ export abstract class ExcelWorksheet {
});
} else {
this._responsesWithConfidenceValue = MemberDAO.getMembersOfQuiz(this._quiz.name).filter(nickname => {
return nickname.responses.filter(responseItem => responseItem.confidence > -1);
return nickname.responses.some(responseItem => responseItem.confidence > -1);
});
}
if (this._responsesWithConfidenceValue.length > 0) {
......@@ -100,27 +99,8 @@ export abstract class ExcelWorksheet {
protected getLeaderboardData(questionIndex: number): Array<ILeaderBoardItemBase> {
const leaderBoard = new Leaderboard();
const correctResponses: any = {};
const question: AbstractQuestionEntity = this.quiz.questionList[questionIndex];
MemberDAO.getMembersOfQuiz(this._quiz.name).forEach(attendee => {
if (leaderBoard.isCorrectResponse(attendee.responses[questionIndex], question) === 1) {
if (!correctResponses[attendee.name]) {
correctResponses[attendee.name] = {
responseTime: 0,
correctQuestions: [],
confidenceValue: 0,
};
}
correctResponses[attendee.name].responseTime += <number>attendee.responses[questionIndex].responseTime;
correctResponses[attendee.name].correctQuestions.push(questionIndex);
correctResponses[attendee.name].confidenceValue += <number>attendee.responses[questionIndex].confidence;
} else {
delete correctResponses[attendee.name];
}
});
return leaderBoard.objectToArray(correctResponses);
const { correctResponses } = leaderBoard.buildLeaderboard(this.quiz);
return leaderBoard.sortBy(correctResponses, 'score');
}
private prefixNumberWithZero(num: number): string {
......
......@@ -44,7 +44,7 @@ export class FreeTextExcelWorksheet extends ExcelWorksheet implements IExcelWork
this.ws.row(1).setHeight(20);
this.ws.column(1).setWidth(this.responsesWithConfidenceValue.length > 0 ? 40 : 30);
this.ws.column(2).setWidth(30);
this.ws.column(3).setWidth(35);
this.ws.column(3).setWidth(45);
this.ws.column(4).setWidth(35);
this.ws.cell(1, 1, 1, columnsToFormat).style(defaultStyles.quizNameRowStyle);
......@@ -156,7 +156,9 @@ export class FreeTextExcelWorksheet extends ExcelWorksheet implements IExcelWork
${this.mf(answerOption.configTrimWhitespaces ? 'global.yes' : 'global.no')}`);
this.ws.cell(7, 1).string(this.mf('export.percent_correct') + ':');
const correctResponsesPercentage: number = this.leaderBoardData.length / MemberDAO.getMembersOfQuiz(this.quiz.name).length * 100;
const correctResponsesPercentage: number = this.leaderBoardData.map(leaderboard => leaderboard.correctQuestions)
.filter(correctQuestions => correctQuestions.includes(this._questionIndex)).length
/ MemberDAO.getMembersOfQuiz(this.quiz.name).length * 100;
this.ws.cell(7, 2).number((isNaN(correctResponsesPercentage) ? 0 : Math.round(correctResponsesPercentage)));
this.ws.cell(7, 3).string(`
......
......@@ -150,8 +150,12 @@ export class MultipleChoiceExcelWorksheet extends ExcelWorksheet implements IExc
this.ws.cell(2, 1).string(this.mf('export.question'));
this.ws.cell(6, 1).string(this.mf('export.number_of_answers') + ':');
this.ws.cell(7, 1).string(this.mf('export.percent_correct') + ':');
const correctResponsesPercentage: number = this.leaderBoardData.length / MemberDAO.getMembersOfQuiz(this.quiz.name).length * 100;
const correctResponsesPercentage: number = this.leaderBoardData.map(leaderboard => leaderboard.correctQuestions)
.filter(correctQuestions => correctQuestions.includes(this._questionIndex)).length
/ MemberDAO.getMembersOfQuiz(this.quiz.name).length * 100;
this.ws.cell(7, 2).number((isNaN(correctResponsesPercentage) ? 0 : Math.round(correctResponsesPercentage)));
if (this.responsesWithConfidenceValue.length > 0) {
this.ws.cell(8, 1).string(this.mf('export.average_confidence') + ':');
let confidenceSummary = 0;
......@@ -160,22 +164,30 @@ export class MultipleChoiceExcelWorksheet extends ExcelWorksheet implements IExc
});
this.ws.cell(8, 2).number(Math.round(confidenceSummary / this.responsesWithConfidenceValue.length));
}
this.ws.cell(4, 1).string(this._question.questionText.replace(/[#]*[*]*/g, ''));
for (let j = 0; j < answerList.length; j++) {
this.ws.cell(2, (j + 2)).string(this.mf('export.answer') + ' ' + (j + 1));
this.ws.cell(4, (j + 2)).string(answerList[j].answerText);
this.ws.cell(6, (j + 2)).number(calculateNumberOfAnswers(this.quiz, this._questionIndex, j));
}
let nextColumnIndex = 1;
this.ws.cell(10, nextColumnIndex++).string(this.mf('export.attendee'));
if (this._isCasRequired) {
this.ws.cell(10, nextColumnIndex++).string(this.mf('export.cas_account_id'));
this.ws.cell(10, nextColumnIndex++).string(this.mf('export.cas_account_email'));
}
this.ws.cell(10, nextColumnIndex++).string(this.mf('export.answer'));
if (this.responsesWithConfidenceValue.length > 0) {
this.ws.cell(10, nextColumnIndex++).string(this.mf('export.confidence_level'));
}
this.ws.cell(10, nextColumnIndex++).string(this.mf('export.time'));
let nextStartRow = 10;
......
......@@ -211,7 +211,9 @@ export class RangedExcelWorksheet extends ExcelWorksheet implements IExcelWorksh
this.ws.cell(6, 4).number(numberOfInputValuesPerGroup.maxRange);
this.ws.cell(7, 1).string(this.mf('export.percent_correct') + ':');
const correctResponsesPercentage: number = this.leaderBoardData.length / MemberDAO.getMembersOfQuiz(this.quiz.name).length * 100;
const correctResponsesPercentage: number = this.leaderBoardData.map(leaderboard => leaderboard.correctQuestions)
.filter(correctQuestions => correctQuestions.includes(this._questionIndex)).length
/ MemberDAO.getMembersOfQuiz(this.quiz.name).length * 100;
this.ws.cell(7, 2).number((isNaN(correctResponsesPercentage) ? 0 : Math.round(correctResponsesPercentage)));
if (this.responsesWithConfidenceValue.length > 0) {
......
......@@ -167,7 +167,9 @@ export class SingleChoiceExcelWorksheet extends ExcelWorksheet implements IExcel
this.ws.cell(6, 1).string(this.mf('export.number_of_answers') + ':');
this.ws.cell(7, 1).string(this.mf('export.percent_correct') + ':');
const correctResponsesPercentage: number = this.leaderBoardData.length / MemberDAO.getMembersOfQuiz(this.quiz.name).length * 100;
const correctResponsesPercentage: number = this.leaderBoardData.map(leaderboard => leaderboard.correctQuestions)
.filter(correctQuestions => correctQuestions.includes(this._questionIndex)).length
/ MemberDAO.getMembersOfQuiz(this.quiz.name).length * 100;
this.ws.cell(7, 2).number((isNaN(correctResponsesPercentage) ? 0 : Math.round(correctResponsesPercentage)));
if (this.responsesWithConfidenceValue.length > 0) {
......
This diff is collapsed.
import MemberDAO from '../db/MemberDAO';
import { SurveyQuestionEntity } from '../entities/question/SurveyQuestionEntity';
import { IMemberEntity } from '../interfaces/entities/Member/IMemberEntity';
import { IExcelWorksheet } from '../interfaces/iExcel';
import { ExcelWorksheet } from './ExcelWorksheet';
import { calculateNumberOfAnswers } from './lib/excel_function_library';
......@@ -161,22 +160,17 @@ export class SurveyExcelWorksheet extends ExcelWorksheet implements IExcelWorksh
this.ws.cell(9, nextColumnIndex++).string(this.mf('export.time'));
let nextStartRow = 9;
this.leaderBoardData.forEach((leaderboardItem) => {
MemberDAO.getMembersOfQuiz(this.quiz.name).forEach((nickItem, indexInList) => {
nextColumnIndex = 1;
nextStartRow++;
this.ws.cell(nextStartRow, nextColumnIndex++).string(leaderboardItem.name);
const nickItem = MemberDAO.getMembersOfQuiz(this.quiz.name).find((nick: IMemberEntity) => {
return nick.name === leaderboardItem.name;
});
this.ws.cell(nextStartRow, nextColumnIndex++).string(nickItem.name);
if (this._isCasRequired) {
const profile = nickItem.casProfile;
this.ws.cell(nextStartRow, nextColumnIndex++).string(profile.username[0]);
this.ws.cell(nextStartRow, nextColumnIndex++).string(profile.mail[0]);
}
const chosenAnswer: Array<string> = <any>nickItem.responses[this._questionIndex].value;
chosenAnswer.forEach((answerIndex: string, index: number) => {
chosenAnswer[index] = this._question.answerOptionList[parseInt(answerIndex, 10)].answerText;
});
const chosenAnswer: Array<string> = (<Array<any>>nickItem.responses[this._questionIndex].value).map(
answerIndex => this._question.answerOptionList[parseInt(answerIndex, 10)].answerText);
this.ws.cell(nextStartRow, nextColumnIndex++).string(chosenAnswer.join(', '));
if (this.responsesWithConfidenceValue.length > 0) {
this.ws.cell(nextStartRow, nextColumnIndex++).number(Math.round(nickItem.responses[this._questionIndex].confidence));
......
......@@ -41,6 +41,7 @@ export class ExcelTheme {
alignment: {
wrapText: true,
vertical: 'top',
horizontal: 'left',
},
},
statisticsRowStyle: {
......
......@@ -37,7 +37,7 @@ export class Leaderboard {
case QuestionType.SingleChoiceQuestion:
case QuestionType.YesNoSingleChoiceQuestion:
case QuestionType.TrueFalseSingleChoiceQuestion:
return this.isCorrectSingleChoiceQuestion(<number>response.value, <AbstractChoiceQuestionEntity>question) ? 1 : -1;
return this.isCorrectSingleChoiceQuestion(<number>response.value[0], <AbstractChoiceQuestionEntity>question) ? 1 : -1;
case QuestionType.MultipleChoiceQuestion:
return this.isCorrectMultipleChoiceQuestion(<Array<number>>response.value, <AbstractChoiceQuestionEntity>question);
case QuestionType.ABCDSingleChoiceQuestion:
......
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