diff --git a/bigbluebutton-html5/imports/api/polls/server/handlers/pollPublished.js b/bigbluebutton-html5/imports/api/polls/server/handlers/pollPublished.js index e2f754c76cee6845a77c614878655381f4f2292c..22bc358a79e655c1ea4a32c7356af0151f491c25 100644 --- a/bigbluebutton-html5/imports/api/polls/server/handlers/pollPublished.js +++ b/bigbluebutton-html5/imports/api/polls/server/handlers/pollPublished.js @@ -1,5 +1,4 @@ import { check } from 'meteor/check'; -import removePoll from '../modifiers/removePoll'; import setPublishedPoll from '../../../meetings/server/modifiers/setPublishedPoll'; export default function pollPublished({ body }, meetingId) { @@ -9,6 +8,4 @@ export default function pollPublished({ body }, meetingId) { check(pollId, String); setPublishedPoll(meetingId, true); - - return removePoll(meetingId, pollId); } diff --git a/bigbluebutton-html5/imports/api/polls/server/handlers/sendPollChatMsg.js b/bigbluebutton-html5/imports/api/polls/server/handlers/sendPollChatMsg.js index 34101bf31fc7d6c0491b078776409e2ece591fb6..9f4c934aace193cb5a5d3bb7e7bf1c193d59e9f9 100644 --- a/bigbluebutton-html5/imports/api/polls/server/handlers/sendPollChatMsg.js +++ b/bigbluebutton-html5/imports/api/polls/server/handlers/sendPollChatMsg.js @@ -1,4 +1,7 @@ import addSystemMsg from '../../../group-chat-msg/server/modifiers/addSystemMsg'; +import Polls from '/imports/api/polls'; +import removePoll from '../modifiers/removePoll'; +import Logger from '/imports/startup/server/logger'; export default function sendPollChatMsg({ body }, meetingId) { const { poll } = body; @@ -11,8 +14,16 @@ export default function sendPollChatMsg({ body }, meetingId) { const { answers, numRespondents } = poll; + const pollData = Polls.findOne({ meetingId }); + + if (!pollData) { + Logger.error(`Attempted to send chat message of inexisting poll for meetingId: ${meetingId}`); + return false; + } + let responded = 0; - let resultString = 'bbb-published-poll-\n'; + let resultString = `bbb-published-poll-\n${pollData.question.split('<br/>').join('<br#>').split('\n').join('<br#>')}\n`; + answers.map((item) => { responded += item.numVotes; return item; @@ -35,5 +46,6 @@ export default function sendPollChatMsg({ body }, meetingId) { message: resultString, }; + removePoll(meetingId, pollData.id); return addSystemMsg(meetingId, PUBLIC_GROUP_CHAT_ID, payload); } diff --git a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/component.jsx index 7ac4e74166ff82ab86bd475b169cb2ab5bd03a4b..859ed751e80cc5c3af784f6a0c18201fe709eb3a 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/component.jsx @@ -194,6 +194,7 @@ class TimeWindowChatItem extends PureComponent { color, intl, isDefaultPoll, + extractPollQuestion, messages, scrollArea, chatAreaId, @@ -236,6 +237,7 @@ class TimeWindowChatItem extends PureComponent { scrollArea={scrollArea} color={color} isDefaultPoll={isDefaultPoll(messages[0].text.replace('bbb-published-poll-<br/>', ''))} + extractPollQuestion={extractPollQuestion} /> </div> </div> diff --git a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/container.jsx b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/container.jsx index 2971429b24055cad40dd975225d44bb1667f4700..e7346b6541ee9c825f18e22694e1d396743f41b6 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/container.jsx @@ -9,8 +9,19 @@ const CHAT_CONFIG = Meteor.settings.public.chat; const SYSTEM_CHAT_TYPE = CHAT_CONFIG.type_system; const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator; +const extractPollQuestion = (pollText) => { + if (!pollText) return {}; + + const pollQuestion = pollText.split('<br/>')[0]; + pollText = pollText.replace(`${pollQuestion}<br/>`,''); + + return { pollQuestion, pollText }; +}; + const isDefaultPoll = (pollText) => { - const pollValue = pollText.replace(/<br\/>|[ :|%\n\d+]/g, ''); + const { pollQuestion, pollText: newPollText} = extractPollQuestion(pollText); + + const pollValue = newPollText.replace(/<br\/>|[ :|%\n\d+]/g, ''); switch (pollValue) { case 'A': case 'AB': case 'ABC': case 'ABCD': case 'ABCDE': case 'YesNo': case 'TrueFalse': @@ -47,6 +58,7 @@ export default function TimeWindowChatItemContainer(props) { read: message.read, messages, isDefaultPoll, + extractPollQuestion, user, timestamp, systemMessage: messageId.startsWith(SYSTEM_CHAT_TYPE) || !sender, diff --git a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/message-chat-item/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/message-chat-item/component.jsx index 9438912c5bfbd440d50499fb357bf3feac49439f..40c94aa1db60b88ae5c30b16e16c251978643511 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/message-chat-item/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/message-chat-item/component.jsx @@ -41,6 +41,10 @@ const intlMessages = defineMessages({ id: 'app.polling.pollingTitle', description: 'heading for chat poll legend', }, + pollQuestionTitle: { + id: 'app.polling.pollQuestionTitle', + description: 'title displayed before poll question', + }, }); class MessageChatItem extends PureComponent { @@ -166,24 +170,33 @@ class MessageChatItem extends PureComponent { className, color, isDefaultPoll, + extractPollQuestion, } = this.props; const formatBoldBlack = s => s.bold().fontcolor('black'); + // Sanitize. See: https://gist.github.com/sagewall/47164de600df05fb0f6f44d48a09c0bd + const sanitize = (value) => { + const div = document.createElement('div'); + div.appendChild(document.createTextNode(value)); + return div.innerHTML; + }; + let _text = text.replace('bbb-published-poll-<br/>', ''); + const { pollQuestion, pollText: newPollText } = extractPollQuestion(_text); + _text = newPollText; + if (!isDefaultPoll) { const entries = _text.split('<br/>'); const options = []; _text = _text.split('<br#>').join('<br/>'); entries.map((e) => { - // Sanitize. See: https://gist.github.com/sagewall/47164de600df05fb0f6f44d48a09c0bd e = e.split('<br#>').join('<br/>'); - const div = document.createElement('div'); - div.appendChild(document.createTextNode(e)); - _text = _text.replace(e, div.innerHTML); - e = div.innerHTML; + const sanitizedEntry = sanitize(e); + _text = _text.replace(e, sanitizedEntry); + e = sanitizedEntry; options.push([e.slice(0, e.indexOf(':'))]); return e; @@ -203,12 +216,22 @@ class MessageChatItem extends PureComponent { }); } + if (isDefaultPoll) { + _text = formatBoldBlack(_text); + } + + if (pollQuestion.trim() !== '') { + const sanitizedPollQuestion = sanitize(pollQuestion.split('<br#>').join(' ')); + + _text = `${formatBoldBlack(intl.formatMessage(intlMessages.pollQuestionTitle))}<br/>${sanitizedPollQuestion}<br/><br/>${_text}`; + } + return ( <p className={className} style={{ borderLeft: `3px ${color} solid` }} ref={(ref) => { this.text = ref; }} - dangerouslySetInnerHTML={{ __html: isDefaultPoll ? formatBoldBlack(_text) : _text }} + dangerouslySetInnerHTML={{ __html: _text }} data-test="chatPollMessageText" /> );