Merge pull request #12353 from germanocaumo/poll-record-improvs
Recorded polling events improvements
This commit is contained in:
commit
1bc324b657
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
}
|
@ -31,12 +31,22 @@ class PollStartedRecordEvent extends AbstractPollRecordEvent {
|
||||
eventMap.put(USER_ID, userId)
|
||||
}
|
||||
|
||||
def setQuestion(question: String) {
|
||||
eventMap.put(QUESTION, question)
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -555,7 +555,9 @@ class RedisRecorderActor(
|
||||
private def handlePollStartedEvtMsg(msg: PollStartedEvtMsg): Unit = {
|
||||
val ev = new PollStartedRecordEvent()
|
||||
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)
|
||||
}
|
||||
@ -565,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)
|
||||
|
||||
record(msg.header.meetingId, ev.toMap.asJava)
|
||||
}
|
||||
|
||||
private def handlePollShowResultEvtMsg(msg: PollShowResultEvtMsg): Unit = {
|
||||
pollStoppedRecordHelper(msg.header.meetingId, msg.body.pollId)
|
||||
}
|
||||
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)
|
||||
|
||||
private def pollStoppedRecordHelper(meetingId: String, pollId: String): Unit = {
|
||||
val ev = new PollStoppedRecordEvent()
|
||||
ev.setPollId(pollId)
|
||||
|
||||
record(meetingId, ev.toMap.asJava)
|
||||
record(msg.header.meetingId, ev.toMap.asJava)
|
||||
}
|
||||
|
||||
private def checkRecordingDBStatus(): Unit = {
|
||||
|
@ -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]])
|
||||
|
@ -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
|
||||
|
@ -7,6 +7,7 @@ export default function userVoted({ body }, meetingId) {
|
||||
check(meetingId, String);
|
||||
check(poll, {
|
||||
id: String,
|
||||
title: String,
|
||||
answers: [
|
||||
{
|
||||
id: Number,
|
||||
|
@ -229,7 +229,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 });
|
||||
}
|
||||
@ -237,7 +237,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 });
|
||||
}
|
||||
|
||||
@ -363,7 +363,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>
|
||||
@ -425,7 +425,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>
|
||||
@ -483,8 +483,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
|
||||
@ -492,7 +492,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>
|
||||
@ -506,7 +506,7 @@ class Poll extends Component {
|
||||
)
|
||||
}
|
||||
{
|
||||
(defaultPoll || type === 'RP')
|
||||
(defaultPoll || type === 'R-')
|
||||
&& (
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
@ -538,8 +538,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 }, () => {
|
||||
@ -561,7 +561,7 @@ class Poll extends Component {
|
||||
}}
|
||||
/>
|
||||
{
|
||||
FILE_DRAG_AND_DROP_ENABLED && type !== 'RP' && this.renderDragDrop()
|
||||
FILE_DRAG_AND_DROP_ENABLED && type !== 'R-' && this.renderDragDrop()
|
||||
}
|
||||
</div>
|
||||
)
|
||||
|
@ -167,6 +167,7 @@
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
@keyframes ellipsis {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user