From ca2ad30e12df3b0b9f5d8f3f268fe4d907260004 Mon Sep 17 00:00:00 2001 From: germanocaumo <germanocaumo@gmail.com> Date: Tue, 11 May 2021 18:01:03 +0000 Subject: [PATCH] fix(record): add missing info to polling events Add PollPublishedRecordEvent with all infos (also fix duplicated handlePollStoppedEvtMsg) Add answer text to UserRespondedToPollRecordEvent (useful for custom answers) Add type in PollStartedRecordEvent --- .../apps/polls/RespondToPollReqMsgHdlr.scala | 11 ++-- .../org/bigbluebutton/core/models/Polls.scala | 12 ++--- .../events/PollPublishedRecordEvent.scala | 53 +++++++++++++++++++ .../events/PollStartedRecordEvent.scala | 5 ++ .../UserRespondedToPollRecordEvent.scala | 5 ++ .../endpoint/redis/RedisRecorderActor.scala | 21 +++++--- .../common2/domain/Meeting2x.scala | 2 +- .../common2/msgs/PollsMsgs.scala | 2 +- .../api/polls/server/handlers/userVoted.js | 1 + .../imports/ui/components/poll/component.jsx | 22 ++++---- .../ui/components/polling/component.jsx | 4 +- bigbluebutton-html5/public/locales/pt_BR.json | 2 +- 12 files changed, 107 insertions(+), 33 deletions(-) create mode 100755 akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/PollPublishedRecordEvent.scala diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/RespondToPollReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/RespondToPollReqMsgHdlr.scala index e422ca0d42..4796ac11ab 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/RespondToPollReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/RespondToPollReqMsgHdlr.scala @@ -23,12 +23,12 @@ trait RespondToPollReqMsgHdlr { bus.outGW.send(msgEvent) } - def broadcastUserRespondedToPollRecordMsg(msg: RespondToPollReqMsg, pollId: String, answerId: Int): Unit = { + def broadcastUserRespondedToPollRecordMsg(msg: RespondToPollReqMsg, pollId: String, answerId: Int, answer: String): Unit = { val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId) val envelope = BbbCoreEnvelope(UserRespondedToPollRecordMsg.NAME, routing) val header = BbbClientMsgHeader(UserRespondedToPollRecordMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId) - val body = UserRespondedToPollRecordMsgBody(pollId, answerId) + val body = UserRespondedToPollRecordMsgBody(pollId, answerId, answer) val event = UserRespondedToPollRecordMsg(header, body) val msgEvent = BbbCommonEnvCoreMsg(envelope, event) bus.outGW.send(msgEvent) @@ -50,7 +50,12 @@ trait RespondToPollReqMsgHdlr { msg.body.questionId, msg.body.answerId, liveMeeting) } yield { broadcastPollUpdatedEvent(msg, pollId, updatedPoll) - broadcastUserRespondedToPollRecordMsg(msg, pollId, msg.body.answerId) + for { + simplePoll <- Polls.getSimplePoll(pollId, liveMeeting.polls) + } yield { + val answerText = simplePoll.answers(msg.body.answerId).key + broadcastUserRespondedToPollRecordMsg(msg, pollId, msg.body.answerId, answerText) + } for { presenter <- Users2x.findPresenter(liveMeeting.users2x) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Polls.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Polls.scala index 0170f6200b..b419931635 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Polls.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Polls.scala @@ -18,7 +18,7 @@ object Polls { val numRespondents: Int = Users2x.numUsers(lm.users2x) - 1 // subtract the presenter for { - poll <- PollFactory.createPoll(stampedPollId, pollType, numRespondents, None) + poll <- PollFactory.createPoll(stampedPollId, pollType, numRespondents, None, Some(question)) } yield { lm.polls.save(poll) poll @@ -172,7 +172,7 @@ object Polls { def createPoll(stampedPollId: String): Option[Poll] = { val numRespondents: Int = Users2x.numUsers(lm.users2x) - 1 // subtract the presenter for { - poll <- PollFactory.createPoll(stampedPollId, pollType, numRespondents, Some(answers)) + poll <- PollFactory.createPoll(stampedPollId, pollType, numRespondents, Some(answers), Some(question)) } yield { lm.polls.save(poll) poll @@ -435,7 +435,7 @@ object PollType { val CustomPollType = "CUSTOM" val LetterPollType = "A-" val NumberPollType = "1-" - val ResponsePollType = "RP" + val ResponsePollType = "R-" } object PollFactory { @@ -561,12 +561,12 @@ object PollFactory { questionOption } - def createPoll(id: String, pollType: String, numRespondents: Int, answers: Option[Seq[String]]): Option[Poll] = { + def createPoll(id: String, pollType: String, numRespondents: Int, answers: Option[Seq[String]], title: Option[String]): Option[Poll] = { var poll: Option[Poll] = None createQuestion(pollType, answers) match { case Some(question) => { - poll = Some(new Poll(id, Array(question), numRespondents, None)) + poll = Some(new Poll(id, Array(question), numRespondents, title)) } case None => poll = None } @@ -644,7 +644,7 @@ class Poll(val id: String, val questions: Array[Question], val numRespondents: I } def toSimplePollResultOutVO(): SimplePollResultOutVO = { - new SimplePollResultOutVO(id, questions(0).toSimpleVotesOutVO(), numRespondents, _numResponders) + new SimplePollResultOutVO(id, title, questions(0).toSimpleVotesOutVO(), numRespondents, _numResponders) } } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/PollPublishedRecordEvent.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/PollPublishedRecordEvent.scala new file mode 100755 index 0000000000..091c512204 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/PollPublishedRecordEvent.scala @@ -0,0 +1,53 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2017 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 3.0 of the License, or (at your option) any later + * version. + * + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. + * + */ + +package org.bigbluebutton.core.record.events + +import org.bigbluebutton.common2.domain.SimpleVoteOutVO +import org.bigbluebutton.common2.util.JsonUtil + +class PollPublishedRecordEvent extends AbstractPollRecordEvent { + import PollPublishedRecordEvent._ + + setEvent("PollPublishedRecordEvent") + + def setQuestion(question: String) { + eventMap.put(QUESTION, question) + } + + def setAnswers(answers: Array[SimpleVoteOutVO]) { + eventMap.put(ANSWERS, JsonUtil.toJson(answers)) + } + + def setNumRespondents(numRespondents: Int) { + eventMap.put(NUM_RESPONDENTS, Integer.toString(numRespondents)) + } + + def setNumResponders(numResponders: Int) { + eventMap.put(NUM_RESPONDERS, Integer.toString(numResponders)) + } +} + +object PollPublishedRecordEvent { + protected final val USER_ID = "userId" + protected final val QUESTION = "question" + protected final val ANSWERS = "answers" + protected final val NUM_RESPONDENTS = "numRespondents" + protected final val NUM_RESPONDERS = "numResponders" +} \ No newline at end of file diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/PollStartedRecordEvent.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/PollStartedRecordEvent.scala index 06e6db0795..db4a2d44d5 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/PollStartedRecordEvent.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/PollStartedRecordEvent.scala @@ -38,10 +38,15 @@ class PollStartedRecordEvent extends AbstractPollRecordEvent { def setAnswers(answers: Array[SimpleAnswerOutVO]) { eventMap.put(ANSWERS, JsonUtil.toJson(answers)) } + + def setType(pollType: String) { + eventMap.put(TYPE, pollType) + } } object PollStartedRecordEvent { protected final val USER_ID = "userId" protected final val QUESTION = "question" protected final val ANSWERS = "answers" + protected final val TYPE = "type" } \ No newline at end of file diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/UserRespondedToPollRecordEvent.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/UserRespondedToPollRecordEvent.scala index ea955895b7..508e58af6f 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/UserRespondedToPollRecordEvent.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/UserRespondedToPollRecordEvent.scala @@ -31,9 +31,14 @@ class UserRespondedToPollRecordEvent extends AbstractPollRecordEvent { def setAnswerId(answerId: Int) { eventMap.put(ANSWER_ID, Integer.toString(answerId)) } + + def setAnswer(answer: String) { + eventMap.put(ANSWER, answer) + } } object UserRespondedToPollRecordEvent { protected final val USER_ID = "userId" protected final val ANSWER_ID = "answerId" + protected final val ANSWER = "answer" } \ No newline at end of file diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala index 58b16e1fd6..74571505ff 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala @@ -557,6 +557,7 @@ class RedisRecorderActor( ev.setPollId(msg.body.pollId) ev.setQuestion(msg.body.question) ev.setAnswers(msg.body.poll.answers) + ev.setType(msg.body.pollType) record(msg.header.meetingId, ev.toMap.asJava) } @@ -566,23 +567,27 @@ class RedisRecorderActor( ev.setPollId(msg.body.pollId) ev.setUserId(msg.header.userId) ev.setAnswerId(msg.body.answerId) + ev.setAnswer(msg.body.answer) record(msg.header.meetingId, ev.toMap.asJava) } private def handlePollStoppedEvtMsg(msg: PollStoppedEvtMsg): Unit = { - pollStoppedRecordHelper(msg.header.meetingId, msg.body.pollId) - } + val ev = new PollStoppedRecordEvent() + ev.setPollId(msg.body.pollId) - private def handlePollShowResultEvtMsg(msg: PollShowResultEvtMsg): Unit = { - pollStoppedRecordHelper(msg.header.meetingId, msg.body.pollId) + record(msg.header.meetingId, ev.toMap.asJava) } - private def pollStoppedRecordHelper(meetingId: String, pollId: String): Unit = { - val ev = new PollStoppedRecordEvent() - ev.setPollId(pollId) + private def handlePollShowResultEvtMsg(msg: PollShowResultEvtMsg): Unit = { + val ev = new PollPublishedRecordEvent() + ev.setPollId(msg.body.pollId) + ev.setQuestion(msg.body.poll.title.getOrElse("")) + ev.setAnswers(msg.body.poll.answers) + ev.setNumRespondents(msg.body.poll.numRespondents) + ev.setNumResponders(msg.body.poll.numResponders) - record(meetingId, ev.toMap.asJava) + record(msg.header.meetingId, ev.toMap.asJava) } private def checkRecordingDBStatus(): Unit = { diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala index 67f842e615..3863338020 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala @@ -75,7 +75,7 @@ case class Meeting2x(defaultProps: DefaultProps, meetingStatus: MeetingStatus) case class SimpleAnswerOutVO(id: Int, key: String) case class SimplePollOutVO(id: String, answers: Array[SimpleAnswerOutVO]) case class SimpleVoteOutVO(id: Int, key: String, numVotes: Int) -case class SimplePollResultOutVO(id: String, answers: Array[SimpleVoteOutVO], numRespondents: Int, numResponders: Int) +case class SimplePollResultOutVO(id: String, title: Option[String], answers: Array[SimpleVoteOutVO], numRespondents: Int, numResponders: Int) case class Responder(userId: String, name: String) case class AnswerVO(id: Int, key: String, text: Option[String], responders: Option[Array[Responder]]) case class QuestionVO(id: Int, questionType: String, multiResponse: Boolean, questionText: Option[String], answers: Option[Array[AnswerVO]]) diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PollsMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PollsMsgs.scala index efc6c00880..ee209cd9b2 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PollsMsgs.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PollsMsgs.scala @@ -28,7 +28,7 @@ case class PollUpdatedEvtMsgBody(pollId: String, poll: SimplePollResultOutVO) object UserRespondedToPollRecordMsg { val NAME = "UserRespondedToPollRecordMsg" } case class UserRespondedToPollRecordMsg(header: BbbClientMsgHeader, body: UserRespondedToPollRecordMsgBody) extends BbbCoreMsg -case class UserRespondedToPollRecordMsgBody(pollId: String, answerId: Int) +case class UserRespondedToPollRecordMsgBody(pollId: String, answerId: Int, answer: String) object RespondToPollReqMsg { val NAME = "RespondToPollReqMsg" } case class RespondToPollReqMsg(header: BbbClientMsgHeader, body: RespondToPollReqMsgBody) extends StandardMsg diff --git a/bigbluebutton-html5/imports/api/polls/server/handlers/userVoted.js b/bigbluebutton-html5/imports/api/polls/server/handlers/userVoted.js index d73d8b6790..0ba233ae72 100644 --- a/bigbluebutton-html5/imports/api/polls/server/handlers/userVoted.js +++ b/bigbluebutton-html5/imports/api/polls/server/handlers/userVoted.js @@ -7,6 +7,7 @@ export default function userVoted({ body }, meetingId) { check(meetingId, String); check(poll, { id: String, + title: String, answers: [ { id: Number, diff --git a/bigbluebutton-html5/imports/ui/components/poll/component.jsx b/bigbluebutton-html5/imports/ui/components/poll/component.jsx index b3ee657046..5629c5ac7b 100644 --- a/bigbluebutton-html5/imports/ui/components/poll/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/poll/component.jsx @@ -231,7 +231,7 @@ class Poll extends Component { const { optList, type, error } = this.state; const list = [...optList]; const validatedVal = validateInput(e.target.value).replace(/\s{2,}/g, ' '); - const clearError = validatedVal.length > 0 && type !== 'RP'; + const clearError = validatedVal.length > 0 && type !== 'R-'; list[index] = { val: validatedVal }; this.setState({ optList: list, error: clearError ? null : error }); } @@ -239,7 +239,7 @@ class Poll extends Component { handleTextareaChange(e) { const { type, error } = this.state; const validatedQuestion = validateInput(e.target.value); - const clearError = validatedQuestion.length > 0 && type === 'RP'; + const clearError = validatedQuestion.length > 0 && type === 'R-'; this.setState({ question: validateInput(e.target.value), error: clearError ? null : error }); } @@ -365,7 +365,7 @@ class Poll extends Component { ) : <div style={{ width: '40px' }} />} </div> - {!hasVal && type !== 'RP' && error ? ( + {!hasVal && type !== 'R-' && error ? ( <div className={styles.inputError}>{error}</div> ) : ( <div className={styles.errorSpacer}> </div> @@ -427,7 +427,7 @@ class Poll extends Component { maxLength={QUESTION_MAX_INPUT_CHARS} placeholder={intl.formatMessage(intlMessages.questionLabel)} /> - {(type === 'RP' && question.length === 0 && error) ? ( + {(type === 'R-' && question.length === 0 && error) ? ( <div className={styles.inputError}>{error}</div> ) : ( <div className={styles.errorSpacer}> </div> @@ -485,8 +485,8 @@ class Poll extends Component { <Button label={intl.formatMessage(intlMessages.userResponse)} color="default" - onClick={() => { this.setState({ type: 'RP' }); }} - className={cx(styles.pBtn, styles.fullWidth, { [styles.selectedBtnWhite]: type === 'RP' })} + onClick={() => { this.setState({ type: 'R-' }); }} + className={cx(styles.pBtn, styles.fullWidth, { [styles.selectedBtnWhite]: type === 'R-' })} /> </div> { type @@ -494,7 +494,7 @@ class Poll extends Component { <div data-test="responseChoices"> <h4>{intl.formatMessage(intlMessages.responseChoices)}</h4> { - type === 'RP' + type === 'R-' && ( <div> <span>{intl.formatMessage(intlMessages.typedResponseDesc)}</span> @@ -508,7 +508,7 @@ class Poll extends Component { ) } { - (defaultPoll || type === 'RP') + (defaultPoll || type === 'R-') && ( <div style={{ display: 'flex', @@ -540,8 +540,8 @@ class Poll extends Component { }); let err = null; - if (type === 'RP' && question.length === 0) err = intl.formatMessage(intlMessages.questionErr); - if (!hasVal && type !== 'RP') err = intl.formatMessage(intlMessages.optionErr); + if (type === 'R-' && question.length === 0) err = intl.formatMessage(intlMessages.questionErr); + if (!hasVal && type !== 'R-') err = intl.formatMessage(intlMessages.optionErr); if (err) return this.setState({ error: err }); return this.setState({ isPolling: true }, () => { @@ -563,7 +563,7 @@ class Poll extends Component { }} /> { - FILE_DRAG_AND_DROP_ENABLED && type !== 'RP' && this.renderDragDrop() + FILE_DRAG_AND_DROP_ENABLED && type !== 'R-' && this.renderDragDrop() } </div> ) diff --git a/bigbluebutton-html5/imports/ui/components/polling/component.jsx b/bigbluebutton-html5/imports/ui/components/polling/component.jsx index 399635a75b..a47c684803 100644 --- a/bigbluebutton-html5/imports/ui/components/polling/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/polling/component.jsx @@ -129,7 +129,7 @@ class Polling extends Component { ) } { - poll.pollType !== 'RP' && ( + poll.pollType !== 'R-' && ( <span> { question.length === 0 @@ -184,7 +184,7 @@ class Polling extends Component { ) } { - poll.pollType === 'RP' + poll.pollType === 'R-' && ( <div className={styles.typedResponseWrapper}> <input diff --git a/bigbluebutton-html5/public/locales/pt_BR.json b/bigbluebutton-html5/public/locales/pt_BR.json index 139b351bb0..61ad9140e5 100644 --- a/bigbluebutton-html5/public/locales/pt_BR.json +++ b/bigbluebutton-html5/public/locales/pt_BR.json @@ -766,7 +766,7 @@ "app.createBreakoutRoom.randomlyAssign": "Atribuir aleatoriamente", "app.createBreakoutRoom.endAllBreakouts": "Encerrar todas as salas de apoio", "app.createBreakoutRoom.roomName": "{0} (Sala - {1})", - "app.createBreakoutRoom.doneLabel": "Finalizado", + "app.createBreakoutRoom.doneLabel": "Confirmar", "app.createBreakoutRoom.nextLabel": "Próximo", "app.createBreakoutRoom.minusRoomTime": "Diminuir o tempo da sala de apoio para", "app.createBreakoutRoom.addRoomTime": "Aumentar o tempo da sala de apoio para", -- GitLab