bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/poll/service.js
germanocaumo c213b88451 refactor(poll): improve poll types code
this also fixes certain poll type detection for other languages than english,
so that the correct poll type is sent in the events (they were being detected as custom)
2021-05-26 17:52:55 +00:00

169 lines
5.6 KiB
JavaScript

import Users from '/imports/api/users';
import Auth from '/imports/ui/services/auth';
import Polls from '/imports/api/polls';
import caseInsensitiveReducer from '/imports/utils/caseInsensitiveReducer';
const POLL_AVATAR_COLOR = '#3B48A9';
const MAX_POLL_RESULT_BARS = 20;
// 'YN' = Yes,No
// 'YNA' = Yes,No,Abstention
// 'TF' = True,False
// 'A-2' = A,B
// 'A-3' = A,B,C
// 'A-4' = A,B,C,D
// 'A-5' = A,B,C,D,E
const pollTypes = {
YesNo: 'YN',
YesNoAbstention: 'YNA',
TrueFalse: 'TF',
Letter: 'A-',
A2: 'A-2',
A3: 'A-3',
A4: 'A-4',
A5: 'A-5',
Custom: 'custom',
Response: 'R-',
}
const pollAnswerIds = {
true: {
id: 'app.poll.answer.true',
description: 'label for poll answer True',
},
false: {
id: 'app.poll.answer.false',
description: 'label for poll answer False',
},
yes: {
id: 'app.poll.answer.yes',
description: 'label for poll answer Yes',
},
no: {
id: 'app.poll.answer.no',
description: 'label for poll answer No',
},
abstention: {
id: 'app.poll.answer.abstention',
description: 'label for poll answer Abstention',
},
a: {
id: 'app.poll.answer.a',
description: 'label for poll answer A',
},
b: {
id: 'app.poll.answer.b',
description: 'label for poll answer B',
},
c: {
id: 'app.poll.answer.c',
description: 'label for poll answer C',
},
d: {
id: 'app.poll.answer.d',
description: 'label for poll answer D',
},
e: {
id: 'app.poll.answer.e',
description: 'label for poll answer E',
},
};
const getPollResultString = (isDefaultPoll, answers, numRespondents) => {
let responded = 0;
let resultString = '';
let optionsString = '';
answers.map((item) => {
responded += item.numVotes;
return item;
}).reduce(caseInsensitiveReducer, []).map((item) => {
const numResponded = responded === numRespondents ? numRespondents : responded;
const pct = Math.round(item.numVotes / numResponded * 100);
const pctBars = "|".repeat(pct * MAX_POLL_RESULT_BARS / 100);
const pctFotmatted = `${Number.isNaN(pct) ? 0 : pct}%`;
if (isDefaultPoll) {
resultString += `${item.key}: ${item.numVotes || 0} |${pctBars} ${pctFotmatted}\n`;
} else {
resultString += `${item.id+1}: ${item.numVotes || 0} |${pctBars} ${pctFotmatted}\n`;
optionsString += `${item.id+1}: ${item.key}\n`;
}
});
return { resultString, optionsString };
}
const matchYesNoPoll = (yesValue, noValue, contentString) => {
const ynPollString = `(${yesValue}\\s*\\/\\s*${noValue})|(${noValue}\\s*\\/\\s*${yesValue})`;
const ynOptionsRegex = new RegExp(ynPollString, 'gi');
const ynPoll = contentString.match(ynOptionsRegex) || [];
return ynPoll;
}
const matchYesNoAbstentionPoll = (yesValue, noValue, abstentionValue, contentString) => {
const ynaPollString = `(${yesValue}\\s*\\/\\s*${noValue}\\s*\\/\\s*${abstentionValue})|(${yesValue}\\s*\\/\\s*${abstentionValue}\\s*\\/\\s*${noValue})|(${abstentionValue}\\s*\\/\\s*${yesValue}\\s*\\/\\s*${noValue})|(${abstentionValue}\\s*\\/\\s*${noValue}\\s*\\/\\s*${yesValue})|(${noValue}\\s*\\/\\s*${yesValue}\\s*\\/\\s*${abstentionValue})|(${noValue}\\s*\\/\\s*${abstentionValue}\\s*\\/\\s*${yesValue})`;
const ynaOptionsRegex = new RegExp(ynaPollString, 'gi');
const ynaPoll = contentString.match(ynaOptionsRegex) || [];
return ynaPoll;
}
const matchTrueFalsePoll = (trueValue, falseValue, contentString) => {
const tfPollString = `(${trueValue}\\s*\\/\\s*${falseValue})|(${falseValue}\\s*\\/\\s*${trueValue})`;
const tgOptionsRegex = new RegExp(tfPollString, 'gi');
const tfPoll = contentString.match(tgOptionsRegex) || [];
return tfPoll;
}
const checkPollType = (type, optList, yesValue, noValue, abstentionValue, trueValue, falseValue) => {
let _type = type;
let pollString = '';
let defaultMatch = null;
let isDefault = null;
switch (_type) {
case pollTypes.Letter:
pollString = optList.map((x) => x.val).sort().join('');
defaultMatch = pollString.match(/^(ABCDEFG)|(ABCDEF)|(ABCDE)|(ABCD)|(ABC)|(AB)$/gi);
isDefault = defaultMatch && pollString.length === defaultMatch[0].length;
_type = isDefault ? `${_type}${defaultMatch[0].length}` : pollTypes.Custom;
break;
case pollTypes.TrueFalse:
pollString = optList.map((x) => x.val).join('/');
defaultMatch = matchTrueFalsePoll(trueValue, falseValue, pollString);
isDefault = defaultMatch.length > 0 && pollString.length === defaultMatch[0].length;
if (!isDefault) _type = pollTypes.Custom;
break;
case pollTypes.YesNoAbstention:
pollString = optList.map((x) => x.val).join('/');
defaultMatch = matchYesNoAbstentionPoll(yesValue, noValue, abstentionValue, pollString);
isDefault = defaultMatch.length > 0 && pollString.length === defaultMatch[0].length;
if (!isDefault) {
// also try to match only yes/no
defaultMatch = matchYesNoPoll(yesValue, noValue, pollString);;
isDefault = defaultMatch.length > 0 && pollString.length === defaultMatch[0].length;
_type = isDefault ? pollTypes.YesNo : _type = pollTypes.Custom;
}
break;
default:
break;
}
return _type;
}
export default {
amIPresenter: () => Users.findOne(
{ userId: Auth.userID },
{ fields: { presenter: 1 } },
).presenter,
pollTypes,
currentPoll: () => Polls.findOne({ meetingId: Auth.meetingID }),
pollAnswerIds,
POLL_AVATAR_COLOR,
isDefaultPoll: (pollType) => { return pollType !== pollTypes.Custom && pollType !== pollTypes.Response},
getPollResultString: getPollResultString,
matchYesNoPoll: matchYesNoPoll,
matchYesNoAbstentionPoll: matchYesNoAbstentionPoll,
matchTrueFalsePoll: matchTrueFalsePoll,
checkPollType: checkPollType,
};