Fixes leaderboard calculation

parent bd60944e
import { ObjectId } from 'bson';
import { MemberEntity } from '../entities/member/MemberEntity';
import { DbCollection, DbEvent } from '../enums/DbOperation';
import { IMemberEntity } from '../interfaces/entities/Member/IMemberEntity';
import { IMemberSerialized } from '../interfaces/entities/Member/IMemberSerialized';
import { AbstractDAO } from './AbstractDAO';
import DbDAO from './DbDAO';
......@@ -66,7 +67,7 @@ class MemberDAO extends AbstractDAO<Array<MemberEntity>> {
}
}
public getMembersOfQuiz(quizName: string): Array<MemberEntity> {
public getMembersOfQuiz(quizName: string): Array<IMemberEntity> {
return this.storage.filter(val => !!val.currentQuizName.match(new RegExp(`^${quizName}$`, 'i')));
}
......
......@@ -143,11 +143,25 @@ class QuizDAO extends AbstractDAO<Array<IQuizEntity>> {
this.updateEmitter.emit(DbEvent.Change, this.getJoinableQuizzes());
}
public addQuiz(doc: IQuizSerialized): IQuizEntity {
public async addQuiz(doc: IQuizSerialized): Promise<IQuizEntity> {
if (this.getQuizByName(doc.name)) {
throw new Error(`Duplicate quiz insertion: ${doc.name}`);
}
await DbDAO.readMany(DbCollection.Members, { currentQuizName: doc.name }).forEach(memberDoc => {
if (!Array.isArray(doc.memberGroups)) {
doc.memberGroups = [];
}
if (!doc.memberGroups.find(memberGroup => memberGroup.name === memberDoc.groupName)) {
doc.memberGroups.push(new MemberGroupEntity({ name: memberDoc.groupName }));
}
if (doc.memberGroups.find(memberGroup => memberGroup.name === memberDoc.groupName).members.includes(memberDoc.name)) {
return;
}
doc.memberGroups.find(memberGroup => memberGroup.name === memberDoc.groupName).members.push(memberDoc.name);
});
const entity = new QuizEntity(doc);
this.storage.push(entity);
return entity;
......
import MemberDAO from '../../db/MemberDAO';
import { IMemberEntity } from '../../interfaces/entities/Member/IMemberEntity';
import { IMemberSerialized } from '../../interfaces/entities/Member/IMemberSerialized';
import { IMemberGroupEntity } from '../../interfaces/users/IMemberGroupEntity';
import { IMemberGroupSerialized } from '../../interfaces/users/IMemberGroupSerialized';
import { AbstractEntity } from '../AbstractEntity';
export class MemberGroupEntity extends AbstractEntity implements IMemberGroupEntity {
private _members: Array<IMemberEntity>;
private _members: Array<string>;
get members(): Array<IMemberEntity> {
get members(): Array<string> {
return this._members;
}
set members(value: Array<IMemberEntity>) {
set members(value: Array<string>) {
this._members = value;
}
......@@ -26,13 +23,13 @@ export class MemberGroupEntity extends AbstractEntity implements IMemberGroupEnt
super();
this._name = data.name;
this._members = (data.members || []).map(val => MemberDAO.getMemberByName(val.name));
this._members = data.members || [];
}
public serialize(): IMemberGroupSerialized {
return {
name: this.name,
members: this.members.map(val => val ? val.serialize() : {} as IMemberSerialized),
members: this.members,
};
}
}
......@@ -184,7 +184,7 @@ export class QuizEntity extends AbstractEntity implements IQuizEntity {
return;
}
this.memberGroups.find(group => group.name === member.groupName).members.push(member);
this.memberGroups.find(group => group.name === member.groupName).members.push(member.name);
this._socketChannel.forEach(socket => SendSocketMessageService.sendMessage(socket, {
status: StatusProtocol.Success,
step: MessageProtocol.Added,
......@@ -197,7 +197,7 @@ export class QuizEntity extends AbstractEntity implements IQuizEntity {
}
const memberGroup = this.memberGroups.find(group => group.name === member.groupName);
memberGroup.members.splice(memberGroup.members.findIndex(quizMembers => quizMembers.name === member.name), 1);
memberGroup.members.splice(memberGroup.members.findIndex(quizMember => quizMember === member.name), 1);
this._socketChannel.forEach(socket => SendSocketMessageService.sendMessage(socket, {
status: StatusProtocol.Success,
......
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';
......@@ -72,11 +73,11 @@ export abstract class ExcelWorksheet {
this._columnsToFormat = 4;
if (questionIndex) {
this._responsesWithConfidenceValue = this._quiz.memberGroups[0].members.filter(nickname => {
this._responsesWithConfidenceValue = MemberDAO.getMembersOfQuiz(this._quiz.name).filter(nickname => {
return nickname.responses[questionIndex].confidence > -1;
});
} else {
this._responsesWithConfidenceValue = this._quiz.memberGroups[0].members.filter(nickname => {
this._responsesWithConfidenceValue = MemberDAO.getMembersOfQuiz(this._quiz.name).filter(nickname => {
return nickname.responses.filter(responseItem => responseItem.confidence > -1);
});
}
......@@ -102,7 +103,7 @@ export abstract class ExcelWorksheet {
const correctResponses: any = {};
const question: AbstractQuestionEntity = this.quiz.questionList[questionIndex];
this.quiz.memberGroups[0].members.forEach(attendee => {
MemberDAO.getMembersOfQuiz(this._quiz.name).forEach(attendee => {
if (leaderBoard.isCorrectResponse(attendee.responses[questionIndex], question) === 1) {
if (!correctResponses[attendee.name]) {
correctResponses[attendee.name] = {
......
import MemberDAO from '../db/MemberDAO';
import { FreeTextAnswerEntity } from '../entities/answer/FreetextAnwerEntity';
import { FreeTextQuestionEntity } from '../entities/question/FreeTextQuestionEntity';
import { IMemberEntity } from '../interfaces/entities/Member/IMemberEntity';
......@@ -8,7 +9,7 @@ export class FreeTextExcelWorksheet extends ExcelWorksheet implements IExcelWork
private _isCasRequired = this.quiz.sessionConfig.nicks.restrictToCasLogin;
private _question: FreeTextQuestionEntity;
private readonly _questionIndex: number;
private allResponses: Array<IMemberEntity> = this.quiz.memberGroups[0].members.filter(nickname => {
private allResponses: Array<IMemberEntity> = MemberDAO.getMembersOfQuiz(this.quiz.name).filter(nickname => {
return nickname.responses.filter(response => {
return !!response.value && response.value !== -1 ? response.value : null;
})[0];
......@@ -168,7 +169,7 @@ export class FreeTextExcelWorksheet extends ExcelWorksheet implements IExcelWork
if (this.responsesWithConfidenceValue.length > 0) {
this.ws.cell(8, 1).string(this.mf('export.average_confidence') + ':');
let confidenceSummary = 0;
this.quiz.memberGroups[0].members.forEach((nickItem) => {
MemberDAO.getMembersOfQuiz(this.quiz.name).forEach((nickItem) => {
confidenceSummary += nickItem.responses[this._questionIndex].confidence;
});
this.ws.cell(8, 2).number(Math.round(confidenceSummary / this.responsesWithConfidenceValue.length));
......
import MemberDAO from '../db/MemberDAO';
import { AbstractAnswerEntity } from '../entities/answer/AbstractAnswerEntity';
import { MultipleChoiceQuestionEntity } from '../entities/question/MultipleChoiceQuestionEntity';
import { IMemberEntity } from '../interfaces/entities/Member/IMemberEntity';
......@@ -102,7 +103,8 @@ export class MultipleChoiceExcelWorksheet extends ExcelWorksheet implements IExc
});
this.quiz.memberGroups.forEach((memberGroup) => {
const responses = memberGroup.members.map(nickname => nickname.responses[this._questionIndex]);
const responses = MemberDAO.getMembersOfQuiz(this.quiz.name).filter(attendee => attendee.groupName === memberGroup.name)
.map(nickname => nickname.responses[this._questionIndex]);
const hasEntries: boolean = responses.length > 0;
const attendeeEntryRows: number = hasEntries ? (responses.length) : 1;
const attendeeEntryRowStyle: Object = hasEntries ? defaultStyles.attendeeEntryRowStyle : Object.assign({}, defaultStyles.attendeeEntryRowStyle,
......@@ -138,7 +140,7 @@ export class MultipleChoiceExcelWorksheet extends ExcelWorksheet implements IExc
public addSheetData(): void {
const answerList = this._question.answerOptionList;
const allResponses: Array<IMemberEntity> = this.quiz.memberGroups[0].members.filter(nickname => {
const allResponses: Array<IMemberEntity> = MemberDAO.getMembersOfQuiz(this.quiz.name).filter(nickname => {
return nickname.responses.map(response => {
return !!response.value && response.value !== -1 ? response.value : null;
});
......@@ -153,7 +155,7 @@ export class MultipleChoiceExcelWorksheet extends ExcelWorksheet implements IExc
if (this.responsesWithConfidenceValue.length > 0) {
this.ws.cell(8, 1).string(this.mf('export.average_confidence') + ':');
let confidenceSummary = 0;
this.quiz.memberGroups[0].members.forEach((nickItem) => {
MemberDAO.getMembersOfQuiz(this.quiz.name).forEach((nickItem) => {
confidenceSummary += nickItem.responses[this._questionIndex].confidence;
});
this.ws.cell(8, 2).number(Math.round(confidenceSummary / this.responsesWithConfidenceValue.length));
......@@ -182,13 +184,13 @@ export class MultipleChoiceExcelWorksheet extends ExcelWorksheet implements IExc
nextStartRow++;
this.ws.cell(nextStartRow, nextColumnIndex++).string(responseItem.name);
if (this._isCasRequired) {
const profile = this.quiz.memberGroups[0].members.filter((nick: IMemberEntity) => {
const profile = MemberDAO.getMembersOfQuiz(this.quiz.name).filter((nick: IMemberEntity) => {
return nick.name === responseItem.name;
})[0].casProfile;
this.ws.cell(nextStartRow, nextColumnIndex++).string(profile.username[0]);
this.ws.cell(nextStartRow, nextColumnIndex++).string(profile.mail[0]);
}
const nickItem = this.quiz.memberGroups[0].members.filter(nick => nick.name === responseItem.name)[0];
const nickItem = MemberDAO.getMembersOfQuiz(this.quiz.name).filter(nick => nick.name === responseItem.name)[0];
const chosenAnswer = this._question.answerOptionList.filter((answer, index) => {
const responseValue = nickItem.responses[this._questionIndex].value;
// noinspection SuspiciousInstanceOfGuard
......
import MemberDAO from '../db/MemberDAO';
import { RangedQuestionEntity } from '../entities/question/RangedQuestionEntity';
import { IMemberEntity } from '../interfaces/entities/Member/IMemberEntity';
import { IExcelWorksheet } from '../interfaces/iExcel';
......@@ -151,7 +152,7 @@ export class RangedExcelWorksheet extends ExcelWorksheet implements IExcelWorksh
if (this._isCasRequired) {
nextColumnIndex += 2;
}
const responseItem = this.quiz.memberGroups[0].members.filter(nickitem => {
const responseItem = MemberDAO.getMembersOfQuiz(this.quiz.name).filter(nickitem => {
return nickitem.name === leaderboardItem.name;
})[0].responses[this._questionIndex];
const castedQuestion = <RangedQuestionEntity>this._question;
......@@ -216,7 +217,7 @@ export class RangedExcelWorksheet extends ExcelWorksheet implements IExcelWorksh
if (this.responsesWithConfidenceValue.length > 0) {
this.ws.cell(8, 1).string(this.mf('export.average_confidence') + ':');
let confidenceSummary = 0;
this.quiz.memberGroups[0].members.forEach((nickItem) => {
MemberDAO.getMembersOfQuiz(this.quiz.name).forEach((nickItem) => {
confidenceSummary += nickItem.responses[this._questionIndex].confidence;
});
this.ws.cell(8, 2).number(Math.round(confidenceSummary / this.responsesWithConfidenceValue.length));
......@@ -236,7 +237,7 @@ export class RangedExcelWorksheet extends ExcelWorksheet implements IExcelWorksh
let nextStartRow = 10;
this.leaderBoardData.forEach((leaderboardItem) => {
const responseItem = this.quiz.memberGroups[0].members.filter(nickitem => {
const responseItem = MemberDAO.getMembersOfQuiz(this.quiz.name).filter(nickitem => {
return nickitem.name === leaderboardItem.name;
})[0].responses[this._questionIndex];
......@@ -244,7 +245,7 @@ export class RangedExcelWorksheet extends ExcelWorksheet implements IExcelWorksh
nextStartRow++;
this.ws.cell(nextStartRow, nextColumnIndex++).string(leaderboardItem.name);
if (this._isCasRequired) {
const profile = this.quiz.memberGroups[0].members.filter((nick: IMemberEntity) => {
const profile = MemberDAO.getMembersOfQuiz(this.quiz.name).filter((nick: IMemberEntity) => {
return nick.name === leaderboardItem.name;
})[0].casProfile;
this.ws.cell(nextStartRow, nextColumnIndex++).string(profile.username[0]);
......
import MemberDAO from '../db/MemberDAO';
import { AbstractAnswerEntity } from '../entities/answer/AbstractAnswerEntity';
import { SingleChoiceQuestionEntity } from '../entities/question/SingleChoiceQuestionEntity';
import { IMemberEntity } from '../interfaces/entities/Member/IMemberEntity';
......@@ -100,7 +101,7 @@ export class SingleChoiceExcelWorksheet extends ExcelWorksheet implements IExcel
lastColumn: minColums,
});
const responses = this.quiz.memberGroups[0].members.map(nickname => nickname.responses[this._questionIndex]);
const responses = MemberDAO.getMembersOfQuiz(this.quiz.name).map(nickname => nickname.responses[this._questionIndex]);
const hasEntries: boolean = responses.length > 0;
const attendeeEntryRows: number = hasEntries ? (responses.length) : 1;
const attendeeEntryRowStyle: any = hasEntries ? defaultStyles.attendeeEntryRowStyle : Object.assign({}, defaultStyles.attendeeEntryRowStyle, {
......@@ -148,7 +149,7 @@ export class SingleChoiceExcelWorksheet extends ExcelWorksheet implements IExcel
public addSheetData(): void {
const answerList = this._question.answerOptionList;
const allResponses: Array<IMemberEntity> = this.quiz.memberGroups[0].members.filter(nickname => {
const allResponses: Array<IMemberEntity> = MemberDAO.getMembersOfQuiz(this.quiz.name).filter(nickname => {
return nickname.responses.map(response => {
return !!response.value && response.value !== -1 ? response.value : null;
});
......@@ -172,7 +173,7 @@ export class SingleChoiceExcelWorksheet extends ExcelWorksheet implements IExcel
if (this.responsesWithConfidenceValue.length > 0) {
this.ws.cell(8, 1).string(this.mf('export.average_confidence') + ':');
let confidenceSummary = 0;
this.quiz.memberGroups[0].members.forEach((nickItem) => {
MemberDAO.getMembersOfQuiz(this.quiz.name).forEach((nickItem) => {
confidenceSummary += nickItem.responses[this._questionIndex].confidence;
});
this.ws.cell(8, 2).number(Math.round(confidenceSummary / this.responsesWithConfidenceValue.length));
......@@ -196,7 +197,7 @@ export class SingleChoiceExcelWorksheet extends ExcelWorksheet implements IExcel
nextStartRow++;
this.ws.cell(nextStartRow, nextColumnIndex++).string(responseItem.name);
if (this._isCasRequired) {
const profile: any = this.quiz.memberGroups[0].members.filter(nickname => nickname.name === responseItem.name)[0].casProfile;
const profile: any = MemberDAO.getMembersOfQuiz(this.quiz.name).filter(nickname => nickname.name === responseItem.name)[0].casProfile;
this.ws.cell(nextStartRow, nextColumnIndex++).string(profile.username[0]);
// noinspection SuspiciousInstanceOfGuard
this.ws.cell(nextStartRow, nextColumnIndex++).string(Array.isArray(profile.mail) ? profile.mail.slice(-1)[0] : profile.mail);
......
import * as path from 'path';
import MemberDAO from '../db/MemberDAO';
import { AbstractQuestionEntity } from '../entities/question/AbstractQuestionEntity';
import { QuestionType } from '../enums/QuestionType';
import { IMemberEntity } from '../interfaces/entities/Member/IMemberEntity';
......@@ -169,12 +170,12 @@ export class SummaryExcelWorksheet extends ExcelWorksheet implements IExcelWorks
public addSheetData(): void {
let currentRowIndex = 1;
const numberOfResponses = this.quiz.memberGroups[0].members.filter(nickname => {
const numberOfResponses = MemberDAO.getMembersOfQuiz(this.quiz.name).filter(nickname => {
return nickname.responses.filter(response => {
return !!response.value && response.value !== -1;
}).length;
}).length;
const allResponses: Array<IMemberEntity> = this.quiz.memberGroups[0].members.filter(nickname => {
const allResponses: Array<IMemberEntity> = MemberDAO.getMembersOfQuiz(this.quiz.name).filter(nickname => {
return nickname.responses.map(response => {
return !!response.value && response.value !== -1 ? response.value : null;
});
......@@ -262,7 +263,7 @@ export class SummaryExcelWorksheet extends ExcelWorksheet implements IExcelWorks
const targetRow = indexInList + currentRowIndex;
this.ws.cell(targetRow, nextColumnIndex++).string(leaderboardItem.name);
if (this._isCasRequired) {
const profile = this.quiz.memberGroups[0].members.filter((nick: IMemberEntity) => {
const profile = MemberDAO.getMembersOfQuiz(this.quiz.name).filter((nick: IMemberEntity) => {
return nick.name === leaderboardItem.name;
})[0].casProfile;
this.ws.cell(targetRow, nextColumnIndex++).string(profile.username[0]);
......@@ -303,7 +304,7 @@ export class SummaryExcelWorksheet extends ExcelWorksheet implements IExcelWorks
const targetRow = indexInList + nextStartRow;
this.ws.cell(targetRow, nextColumnIndex++).string(responseItem.name);
if (this._isCasRequired) {
const profile = this.quiz.memberGroups[0].members.filter((nick: IMemberEntity) => {
const profile = MemberDAO.getMembersOfQuiz(this.quiz.name).filter((nick: IMemberEntity) => {
return nick.name === responseItem.name;
})[0].casProfile;
this.ws.cell(targetRow, nextColumnIndex++).string(profile.username[0]);
......@@ -331,7 +332,7 @@ export class SummaryExcelWorksheet extends ExcelWorksheet implements IExcelWorks
const leaderBoard = new Leaderboard();
const correctResponses: any = {};
this.quiz.memberGroups[0].members.forEach(attendee => {
MemberDAO.getMembersOfQuiz(this.quiz.name).forEach(attendee => {
for (let i = 0; i < this.quiz.questionList.length; i++) {
const question: AbstractQuestionEntity = this.quiz.questionList[i];
if (leaderBoard.isCorrectResponse(attendee.responses[i], question) === 1) {
......
import MemberDAO from '../db/MemberDAO';
import { SurveyQuestionEntity } from '../entities/question/SurveyQuestionEntity';
import { IMemberEntity } from '../interfaces/entities/Member/IMemberEntity';
import { IExcelWorksheet } from '../interfaces/iExcel';
......@@ -141,7 +142,7 @@ export class SurveyExcelWorksheet extends ExcelWorksheet implements IExcelWorksh
if (this.responsesWithConfidenceValue.length > 0) {
this.ws.cell(7, 1).string(this.mf('export.average_confidence') + ':');
let confidenceSummary = 0;
this.quiz.memberGroups[0].members.forEach((nickItem) => {
MemberDAO.getMembersOfQuiz(this.quiz.name).forEach((nickItem) => {
confidenceSummary += nickItem.responses[this._questionIndex].confidence;
});
this.ws.cell(7, 2).number(Math.round(confidenceSummary / this.responsesWithConfidenceValue.length));
......@@ -164,7 +165,7 @@ export class SurveyExcelWorksheet extends ExcelWorksheet implements IExcelWorksh
nextColumnIndex = 1;
nextStartRow++;
this.ws.cell(nextStartRow, nextColumnIndex++).string(leaderboardItem.name);
const nickItem = this.quiz.memberGroups[0].members.filter((nick: IMemberEntity) => {
const nickItem = MemberDAO.getMembersOfQuiz(this.quiz.name).filter((nick: IMemberEntity) => {
return nick.name === leaderboardItem.name;
})[0];
if (this._isCasRequired) {
......
import MemberDAO from '../../db/MemberDAO';
import { IQuizEntity } from '../../interfaces/quizzes/IQuizEntity';
export function calculateNumberOfAnswers(quiz: IQuizEntity, questionIndex: number, answerNumber: number): number {
let numberOfAnswers = 0;
quiz.memberGroups[0].members.forEach(nickname => {
MemberDAO.getMembersOfQuiz(quiz.name).forEach(nickname => {
const response = nickname.responses[questionIndex].value;
// noinspection SuspiciousInstanceOfGuard
if (Array.isArray(response)) {
......@@ -14,17 +15,18 @@ export function calculateNumberOfAnswers(quiz: IQuizEntity, questionIndex: numbe
return numberOfAnswers;
}
export function calculateNumberOfRangedAnswers(quiz: IQuizEntity,
questionIndex: number,
minRange,
correctValue,
maxRange,
export function calculateNumberOfRangedAnswers(
quiz: IQuizEntity,
questionIndex: number,
minRange,
correctValue,
maxRange,
): { minRange: number, correctValue: number, maxRange: number } {
let numberOfAnswersInMinRange = 0;
let numberOfAnswersInMaxRange = 0;
let numberOfCorrectAnswers = 0;
quiz.memberGroups[0].members.forEach((nickname) => {
MemberDAO.getMembersOfQuiz(quiz.name).forEach((nickname) => {
if (nickname.responses[questionIndex].value <= maxRange && nickname.responses[questionIndex].value > correctValue) {
numberOfAnswersInMaxRange++;
} else if (nickname.responses[questionIndex].value === correctValue) {
......
import { ObjectId } from 'bson';
import * as WebSocket from 'ws';
import { IQuizResponse } from '../../quizzes/IQuizResponse';
import { ICasData } from '../../users/ICasData';
import { IMemberBase } from './IMemberBase';
import { IMemberSerialized } from './IMemberSerialized';
......@@ -17,4 +18,5 @@ export interface IMemberEntity extends IMemberBase {
setReadingConfirmation(): void;
generateResponseForQuiz(questionAmount: number): Array<IQuizResponse>;
}
import { ObjectId } from 'bson';
import { IMemberEntity } from '../entities/Member/IMemberEntity';
import { IMemberGroupBase } from './IMemberGroupBase';
import { IMemberGroupSerialized } from './IMemberGroupSerialized';
export interface IMemberGroupEntity extends IMemberGroupBase {
id?: ObjectId;
members: Array<IMemberEntity>;
members: Array<string>;
serialize(): IMemberGroupSerialized;
}
......
import { IMemberSerialized } from '../entities/Member/IMemberSerialized';
import { IMemberGroupBase } from './IMemberGroupBase';
export interface IMemberGroupSerialized extends IMemberGroupBase {
members?: Array<IMemberSerialized>;
members?: Array<string>;
}
import MemberDAO from '../../db/MemberDAO';
import { FreeTextAnswerEntity } from '../../entities/answer/FreetextAnwerEntity';
import { AbstractChoiceQuestionEntity } from '../../entities/question/AbstractChoiceQuestionEntity';
import { AbstractQuestionEntity } from '../../entities/question/AbstractQuestionEntity';
......@@ -8,6 +9,7 @@ import { QuestionType } from '../../enums/QuestionType';
import { ILeaderBoardItemBase } from '../../interfaces/leaderboard/ILeaderBoardItemBase';
import { IQuizEntity } from '../../interfaces/quizzes/IQuizEntity';
import { IQuizResponse } from '../../interfaces/quizzes/IQuizResponse';
import LoggerService from '../../services/LoggerService';
import { staticStatistics } from '../../statistics';
import { AbstractLeaderboardScore } from './AbstractLeaderboardScore';
import { PointBasedLeaderboardScore } from './PointBasedLeaderboardScore';
......@@ -93,8 +95,14 @@ export class Leaderboard {
memberAmount: memberGroup.members.length,
};
memberGroup.members.forEach(attendee => {
for (let i = questionIndex || 0; i < endIndex; i++) {
memberGroup.members.forEach(attendeeName => {
const attendee = MemberDAO.getMembersOfQuiz(activeQuiz.name).find(quizAttendee => quizAttendee.name === attendeeName);
if (!attendee) {
LoggerService.error(`Cannot find member ${attendeeName} in DAO which should be in quiz ${activeQuiz.name}`);
return;
}
for (let i = 0; i < endIndex; i++) {
const question: AbstractQuestionEntity = activeQuiz.questionList[i];
if ([QuestionType.SurveyQuestion, QuestionType.ABCDSingleChoiceQuestion].includes(question.TYPE)) {
continue;
......@@ -124,6 +132,7 @@ export class Leaderboard {
responseTime: 0,
correctQuestions: [],
confidenceValue: 0,
score: 0,
};
}
......@@ -135,7 +144,6 @@ export class Leaderboard {
} else {
delete correctResponses[attendee.name];
delete partiallyCorrectResponses[attendee.name];
break;
}
}
......@@ -158,6 +166,20 @@ export class Leaderboard {
};
}
public sortBy(correctResponses: Array<ILeaderBoardItemBase>, parameter: string): Array<ILeaderBoardItemBase>;
public sortBy(correctResponses: object, parameter: string): Array<ILeaderBoardItemBase>;
public sortBy(correctResponses: object | Array<ILeaderBoardItemBase>, parameter: string): Array<ILeaderBoardItemBase> {
const comparator = (a, b) => {
return a[parameter] > b[parameter] ? 1 : a[parameter] === b[parameter] ? 0 : -1;
};
if (Array.isArray(correctResponses)) {
return correctResponses.sort(comparator);
} else {
return this.objectToArray(correctResponses).sort(comparator);
}
}
private isCorrectSingleChoiceQuestion(response: number, question: AbstractChoiceQuestionEntity): boolean {
return question.answerOptionList[response].isCorrect;
}
......
......@@ -230,7 +230,7 @@ export class MemberRouter extends AbstractRouter {
}
const names: Array<String> = activeQuiz.sessionConfig.nicks.selectedNicks.filter((nick) => {
return !activeQuiz.memberGroups.find(memberGroup => {
return !!memberGroup.members.find(value => value.name === nick);
return !!memberGroup.members.find(value => value === nick);
});
});
return {
......
......@@ -668,9 +668,9 @@ export class QuizRouter extends AbstractRouter {
status: StatusProtocol.Success,
step: MessageProtocol.GetLeaderboardData,
payload: {
correctResponses: this._leaderboard.objectToArray(correctResponses),
partiallyCorrectResponses: this._leaderboard.objectToArray(partiallyCorrectResponses),
memberGroupResults: this._leaderboard.objectToArray(memberGroupResults),
correctResponses: this._leaderboard.sortBy(correctResponses, 'score'),
partiallyCorrectResponses: this._leaderboard.sortBy(partiallyCorrectResponses, 'score'),
memberGroupResults: this._leaderboard.sortBy(memberGroupResults, 'score'),
},
};
}
......
import * as WebSocket from 'ws';
import MemberDAO from '../../db/MemberDAO';
import QuizDAO from '../../db/quiz/QuizDAO';
import { DbEvent } from '../../enums/DbOperation';
import { MessageProtocol, StatusProtocol } from '../../enums/Message';
import { WebSocketStatus } from '../../enums/WebSocketStatus';
import { IMessage } from '../../interfaces/communication/IMessage';
import { IMemberEntity } from '../../interfaces/entities/Member/IMemberEntity';
import { IQuizEntity } from '../../interfaces/quizzes/IQuizEntity';
import { IGlobal } from '../../main';
import LoggerService from '../../services/LoggerService';
......@@ -33,14 +33,7 @@ export class WebSocketRouter {
} else {
res.step = MessageProtocol.AllPlayers;
res.payload = {
members: activeQuiz.memberGroups.map((memberGroup) => {
// TODO: this does strange stuff
return memberGroup.members.map((nickname: IMemberEntity) => {
return nickname.serialize();
});
}).reduce((previousValue, currentValue) => {
return previousValue.concat(...currentValue);
}),
members: MemberDAO.getMembersOfQuiz(activeQuiz.name).map(nickname => nickname.serialize()),
};
}
ws.send(JSON.stringify(res));
......
......@@ -8,7 +8,6 @@ import { slow, suite, test } from 'mocha-typescript';
import * as path from 'path';
import QuizDAO from '../../db/quiz/QuizDAO';
import { FreeTextAnswerEntity } from '../../entities/answer/FreetextAnwerEntity';
import { MemberEntity } from '../../entities/member/MemberEntity';
import { FreeTextQuestionEntity } from '../../entities/question/FreeTextQuestionEntity';
import { RangedQuestionEntity } from '../../entities/question/RangedQuestionEntity';
import { SurveyQuestionEntity } from '../../entities/question/SurveyQuestionEntity';
......@@ -114,13 +113,7 @@ class ExcelExportTestSuite {
public async addMembers(): Promise<void> {
const quiz = QuizDAO.getActiveQuizByName(this._hashtag);
for (let memberIndex = 0; memberIndex < this._memberCount; memberIndex++) {
quiz.memberGroups[0].members.push(new MemberEntity({
id: '',
name: `testnick${memberIndex + 1}`,
groupName: 'Default',
token: 'token',
currentQuizName: this._hashtag,
}));
quiz.memberGroups[0].members.push(`testnick${memberIndex + 1}`);
}
await assert.equal(quiz.memberGroups[0].members.length, this._memberCount, `Expected that the quiz has ${this._memberCount} members`);
}
......@@ -189,12 +182,14 @@ class ExcelExportTestSuite {
default:
throw new Error(`Unsupported question type ${question.TYPE}`);
}
quiz.memberGroups[0].members[memberIndex].responses.push({
value: value,
responseTime: this.randomIntFromInterval(0, quiz.questionList[questionIndex].timer),
confidence: this.randomIntFromInterval(0, 100),
readingConfirmation: true,
});
const responses = [
{
value: value,
responseTime: this.randomIntFromInterval(0, quiz.questionList[questionIndex].timer),
confidence: this.randomIntFromInterval(0, 100),
readingConfirmation: true,
},
];
}
}
}
......