Commit 491ad6c8 authored by Christopher Mark Fullarton's avatar Christopher Mark Fullarton
Browse files

Adds performance improvements for attendees. Adds more config switches to...

Adds performance improvements for attendees. Adds more config switches to control the visibility of public and active quizzes
parent 6e725ace
......@@ -255,6 +255,14 @@ class QuizDAO extends AbstractDAO<Array<IQuizEntity>> {
return this.storage.find(val => val.id.equals(id));
}
public getRenameAsToken(name: string): string {
let token;
do {
token = generateToken(name, new Date().getTime()).substr(0, 10);
} while (this.getQuizByName(token));
return token;
}
private checkABCDOrdering(quizname: string): boolean {
let ordered = true;
if (!quizname || quizname.length < 2 || quizname.charAt(0) !== 'a') {
......
import { ObjectId } from 'bson';
import * as WebSocket from 'ws';
import CasDAO from '../../db/CasDAO';
import DbDAO from '../../db/DbDAO';
import QuizDAO from '../../db/quiz/QuizDAO';
......@@ -12,16 +11,6 @@ import { ICasData } from '../../interfaces/users/ICasData';
import { AbstractEntity } from '../AbstractEntity';
export class MemberEntity extends AbstractEntity implements IMemberEntity {
private _webSocket: WebSocket;
get webSocket(): WebSocket {
return this._webSocket;
}
set webSocket(value: WebSocket) {
this._webSocket = value;
}
private _currentQuizName: string;
get currentQuizName(): string {
......
......@@ -78,7 +78,7 @@ export class QuizEntity extends AbstractEntity implements IQuizEntity {
}
set state(value: QuizState) {
if (this._state === QuizState.Inactive && value !== QuizState.Inactive) {
if (this._state !== value && value !== QuizState.Inactive) {
clearInterval(this._dropEmptyQuizSettings.intervalInstance);
this._dropEmptyQuizSettings.intervalInstance = setInterval(() => {
this.checkExistingConnection();
......@@ -166,7 +166,7 @@ export class QuizEntity extends AbstractEntity implements IQuizEntity {
this._questionList = (quiz.questionList || []).map(val => getQuestionForType(val.TYPE, val));
this._sessionConfig = quiz.sessionConfig ? new SessionConfigurationEntity(quiz.sessionConfig) : null;
this._expiry = quiz.expiry;
this._state = quiz.state || QuizState.Inactive;
this.state = quiz.state || QuizState.Inactive;
this._currentStartTimestamp = quiz.currentStartTimestamp || -1;
this._currentQuestionIndex = typeof quiz.currentQuestionIndex !== 'undefined' ? quiz.currentQuestionIndex : -1;
this._privateKey = quiz.privateKey;
......@@ -174,10 +174,6 @@ export class QuizEntity extends AbstractEntity implements IQuizEntity {
this._visibility = quiz.visibility;
this._description = quiz.description;
this._exchangeName = encodeURI(`quiz_${quiz.name}`);
this._dropEmptyQuizSettings.intervalInstance = setInterval(() => {
this.checkExistingConnection();
}, this._dropEmptyQuizSettings.interval);
}
public setInactive(): void {
......@@ -216,7 +212,7 @@ export class QuizEntity extends AbstractEntity implements IQuizEntity {
status: StatusProtocol.Success,
step: MessageProtocol.Closed,
})));
AMQPConnector.channel.deleteExchange(this._exchangeName);
AMQPConnector.channel.deleteExchange(this._exchangeName).catch(() => {});
}
public reset(): void {
......@@ -408,15 +404,6 @@ export class QuizEntity extends AbstractEntity implements IQuizEntity {
this._dropEmptyQuizSettings.isEmpty = true;
});
response.on('error', () => {
if (this._dropEmptyQuizSettings.isEmpty) {
this.setInactive();
return;
}
this._dropEmptyQuizSettings.isEmpty = true;
});
});
}
}
import { ObjectId } from 'bson';
import * as WebSocket from 'ws';
import { IQuizResponse } from '../../quizzes/IQuizResponse';
import { ICasData } from '../../users/ICasData';
import { IMemberBase } from './IMemberBase';
......@@ -8,7 +7,6 @@ import { IMemberSerialized } from './IMemberSerialized';
export interface IMemberEntity extends IMemberBase {
id?: ObjectId;
casProfile: ICasData;
webSocket?: WebSocket;
serialize(): IMemberSerialized;
......
......@@ -180,16 +180,15 @@ export class MemberRouter extends AbstractRouter {
}
const result: DeleteWriteOpResultObject = await activeQuiz.removeMember(nickname);
const response: Object = { status: result.deletedCount ? StatusProtocol.Success : StatusProtocol.Failed };
if (result && result.deletedCount) {
Object.assign(response, {
step: MessageProtocol.Removed,
payload: {},
});
} else {
Object.assign(response, {
message: result,
payload: {
ok: result.result.ok,
deletedCount: result.deletedCount,
},
});
}
return response;
}
......
......@@ -24,13 +24,16 @@ import AMQPConnector from '../../db/AMQPConnector';
import { default as DbDAO } from '../../db/DbDAO';
import MemberDAO from '../../db/MemberDAO';
import QuizDAO from '../../db/quiz/QuizDAO';
import UserDAO from '../../db/UserDAO';
import { AbstractAnswerEntity } from '../../entities/answer/AbstractAnswerEntity';
import { QuizEntity } from '../../entities/quiz/QuizEntity';
import { DbCollection } from '../../enums/DbOperation';
import { MessageProtocol, StatusProtocol } from '../../enums/Message';
import { QuizState } from '../../enums/QuizState';
import { QuizVisibility } from '../../enums/QuizVisibility';
import { UserRole } from '../../enums/UserRole';
import { ExcelWorkbook } from '../../export/ExcelWorkbook';
import { IMessage } from '../../interfaces/communication/IMessage';
import { IQuizStatusPayload } from '../../interfaces/IQuizStatusPayload';
import { IQuizEntity, IQuizSerialized } from '../../interfaces/quizzes/IQuizEntity';
import { asyncForEach } from '../../lib/async-for-each';
......@@ -48,7 +51,7 @@ export class QuizRouter extends AbstractRouter {
public getIsAvailableQuiz(
@Params() params: { [key: string]: any }, //
@HeaderParam('authorization', { required: false }) token: string, //
): object {
): IMessage {
const quizName = params.quizName;
const member = MemberDAO.getMemberByToken(token);
......@@ -90,6 +93,24 @@ export class QuizRouter extends AbstractRouter {
};
}
@Get('/full-status/:quizName?')
public getFullQuizStatusData(
@Params() params: { [key: string]: any }, //
@HeaderParam('authorization', { required: false }) token: string, //
): object {
const status = this.getIsAvailableQuiz(params, token);
const quiz = this.getQuiz(params, token);
return {
status: status.status === StatusProtocol.Success && quiz.status === StatusProtocol.Success ? StatusProtocol.Success : StatusProtocol.Failed,
step: status.step === MessageProtocol.Available && quiz.step === MessageProtocol.Available ? MessageProtocol.Available
: MessageProtocol.Unavailable,
payload: {
status: status.payload,
quiz: quiz.payload,
},
};
}
@Get('/generate/demo/:languageId')
public generateDemoQuiz(
@Param('languageId') languageId: string, //
......@@ -268,6 +289,7 @@ export class QuizRouter extends AbstractRouter {
quiz.readingConfirmationRequested = false;
quiz.currentStartTimestamp = currentStartTimestamp;
quiz.startNextQuestion();
return {
status: StatusProtocol.Success,
step: MessageProtocol.Start,
......@@ -727,6 +749,56 @@ export class QuizRouter extends AbstractRouter {
return QuizDAO.getAllPublicQuizzes().filter(quiz => quiz.privateKey !== privateKey).map(quiz => quiz.serialize());
}
@Post('/public/init')
private async initQuizInstance(
@BodyParam('name') quizName: string,
@HeaderParam('X-Access-Token') loginToken: string,
@HeaderParam('authorization') privateKey: string,
): Promise<IMessage> {
const user = UserDAO.getUserByToken(loginToken);
if (!user || !user.userAuthorizations.includes(UserRole.CreateQuiz)) {
throw new UnauthorizedError('Unauthorized to create quiz');
}
const quiz = QuizDAO.getAllPublicQuizzes().find(q => q.name === quizName);
if (!quiz) {
throw new NotFoundError('Quiz name not found');
}
const serializedQuiz = quiz.serialize();
delete quiz.id;
serializedQuiz.name = QuizDAO.getRenameAsToken(serializedQuiz.name);
serializedQuiz.privateKey = privateKey;
serializedQuiz.state = QuizState.Active;
serializedQuiz.visibility = QuizVisibility.Account;
serializedQuiz.currentQuestionIndex = -1;
serializedQuiz.currentStartTimestamp = -1;
serializedQuiz.readingConfirmationRequested = false;
const quizValidator = new QuizModel(serializedQuiz);
const result = quizValidator.validateSync();
if (result) {
throw result;
}
await quizValidator.save();
AMQPConnector.channel.publish('global', '.*', Buffer.from(JSON.stringify({
status: StatusProtocol.Success,
step: MessageProtocol.SetActive,
payload: {
quizName: serializedQuiz.name,
},
})));
return {
status: StatusProtocol.Success,
step: MessageProtocol.Init,
payload: {
quiz: serializedQuiz,
},
};
}
@Get('/public/amount')
private getPublicQuizAmount(@HeaderParam('authorization') privateKey: string): number {
return this.getPublicQuizzes(privateKey).length;
......@@ -751,7 +823,7 @@ export class QuizRouter extends AbstractRouter {
private getQuiz(
@Params() params: { [key: string]: any }, //
@HeaderParam('authorization', { required: false }) token: string, //
): object {
): IMessage {
const quizName = params.quizName;
const member = MemberDAO.getMemberByToken(token);
......
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