Skip to content

Commit

Permalink
Merge pull request #11366 from MaximKhlobystov/updating-poll-ui
Browse files Browse the repository at this point in the history
Updated poll UI: question field and typed responses
  • Loading branch information
antobinary committed Feb 18, 2021
2 parents 49cdf9f + 480602a commit e966d6c
Show file tree
Hide file tree
Showing 26 changed files with 952 additions and 276 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import akka.event.Logging
class PollApp2x(implicit val context: ActorContext)
extends GetCurrentPollReqMsgHdlr
with RespondToPollReqMsgHdlr
with RespondToTypedPollReqMsgHdlr
with ShowPollResultReqMsgHdlr
with StartCustomPollReqMsgHdlr
with StartPollReqMsgHdlr
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.bigbluebutton.core.apps.polls

import org.bigbluebutton.common2.domain.SimplePollResultOutVO
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.models.Polls
import org.bigbluebutton.core.running.{ LiveMeeting }
import org.bigbluebutton.core.models.Users2x

trait RespondToTypedPollReqMsgHdlr {
this: PollApp2x =>

def handle(msg: RespondToTypedPollReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
log.debug("Received RespondToPollReqMsg {}", RespondToTypedPollReqMsg)

def broadcastPollUpdatedEvent(msg: RespondToTypedPollReqMsg, pollId: String, poll: SimplePollResultOutVO): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(PollUpdatedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(PollUpdatedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)

val body = PollUpdatedEvtMsgBody(pollId, poll)
val event = PollUpdatedEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}

def broadcastUserRespondedToTypedPollRespMsg(msg: RespondToTypedPollReqMsg, pollId: String, answer: String, sendToId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, sendToId)
val envelope = BbbCoreEnvelope(UserRespondedToTypedPollRespMsg.NAME, routing)
val header = BbbClientMsgHeader(UserRespondedToTypedPollRespMsg.NAME, liveMeeting.props.meetingProp.intId, sendToId)

val body = UserRespondedToTypedPollRespMsgBody(pollId, msg.header.userId, answer)
val event = UserRespondedToTypedPollRespMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}

for {
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToTypedPollReqMsg(msg.header.userId, msg.body.pollId,
msg.body.questionId, msg.body.answer, liveMeeting)
} yield {
broadcastPollUpdatedEvent(msg, pollId, updatedPoll)

for {
presenter <- Users2x.findPresenter(liveMeeting.users2x)
} yield {
broadcastUserRespondedToTypedPollRespMsg(msg, pollId, msg.body.answer, presenter.intId)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ trait StartCustomPollReqMsgHdlr extends RightsManagementTrait {
val envelope = BbbCoreEnvelope(PollStartedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(PollStartedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)

val body = PollStartedEvtMsgBody(msg.header.userId, poll.id, poll)
val body = PollStartedEvtMsgBody(msg.header.userId, poll.id, msg.body.pollType, msg.body.question, poll)
val event = PollStartedEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
Expand All @@ -29,7 +29,7 @@ trait StartCustomPollReqMsgHdlr extends RightsManagementTrait {
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
} else {
for {
pvo <- Polls.handleStartCustomPollReqMsg(state, msg.header.userId, msg.body.pollId, msg.body.pollType, msg.body.answers, liveMeeting)
pvo <- Polls.handleStartCustomPollReqMsg(state, msg.header.userId, msg.body.pollId, msg.body.pollType, msg.body.answers, msg.body.question, liveMeeting)
} yield {
broadcastEvent(msg, pvo)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ trait StartPollReqMsgHdlr extends RightsManagementTrait {
val envelope = BbbCoreEnvelope(PollStartedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(PollStartedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)

val body = PollStartedEvtMsgBody(msg.header.userId, poll.id, poll)
val body = PollStartedEvtMsgBody(msg.header.userId, poll.id, msg.body.pollType, msg.body.question, poll)
val event = PollStartedEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
Expand All @@ -30,7 +30,7 @@ trait StartPollReqMsgHdlr extends RightsManagementTrait {
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
} else {
for {
pvo <- Polls.handleStartPollReqMsg(state, msg.header.userId, msg.body.pollId, msg.body.pollType, liveMeeting)
pvo <- Polls.handleStartPollReqMsg(state, msg.header.userId, msg.body.pollId, msg.body.pollType, msg.body.question, liveMeeting)
} yield {
broadcastEvent(msg, pvo)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.bigbluebutton.core.running.LiveMeeting

object Polls {

def handleStartPollReqMsg(state: MeetingState2x, userId: String, pollId: String, pollType: String,
def handleStartPollReqMsg(state: MeetingState2x, userId: String, pollId: String, pollType: String, question: String,
lm: LiveMeeting): Option[SimplePollOutVO] = {

def createPoll(stampedPollId: String): Option[Poll] = {
Expand Down Expand Up @@ -156,8 +156,18 @@ object Polls {

}

def handleRespondToTypedPollReqMsg(requesterId: String, pollId: String, questionId: Int, answer: String,
lm: LiveMeeting): Option[(String, SimplePollResultOutVO)] = {
for {
poll <- getSimplePollResult(pollId, lm.polls)
pvo <- handleRespondToTypedPoll(poll, requesterId, pollId, questionId, answer, lm)
} yield {
(pollId, pvo)
}
}

def handleStartCustomPollReqMsg(state: MeetingState2x, requesterId: String, pollId: String, pollType: String,
answers: Seq[String], lm: LiveMeeting): Option[SimplePollOutVO] = {
answers: Seq[String], question: String, lm: LiveMeeting): Option[SimplePollOutVO] = {

def createPoll(stampedPollId: String): Option[Poll] = {
val numRespondents: Int = Users2x.numUsers(lm.users2x) - 1 // subtract the presenter
Expand Down Expand Up @@ -227,7 +237,17 @@ object Polls {
} yield {
updatedPoll
}
}

private def handleRespondToTypedPoll(poll: SimplePollResultOutVO, requesterId: String, pollId: String, questionId: Int,
answer: String, lm: LiveMeeting): Option[SimplePollResultOutVO] = {

addQuestionResponse(poll.id, questionId, answer, lm.polls)
for {
updatedPoll <- getSimplePollResult(poll.id, lm.polls)
} yield {
updatedPoll
}
}

private def pollResultToWhiteboardShape(result: SimplePollResultOutVO): scala.collection.immutable.Map[String, Object] = {
Expand Down Expand Up @@ -366,6 +386,14 @@ object Polls {
}
}

def addQuestionResponse(pollId: String, questionID: Int, answer: String, polls: Polls) {
polls.polls.get(pollId) match {
case Some(p) => {
p.addQuestionResponse(questionID, answer)
}
case None =>
}
}
}

object PollType {
Expand All @@ -375,6 +403,7 @@ object PollType {
val CustomPollType = "CUSTOM"
val LetterPollType = "A-"
val NumberPollType = "1-"
val ResponsePollType = "RP"
}

object PollFactory {
Expand All @@ -383,29 +412,29 @@ object PollFactory {
val NumberArray = Array("1", "2", "3", "4", "5", "6")

private def processYesNoPollType(qType: String): Question = {
val answers = new Array[Answer](2)
val answers = new ArrayBuffer[Answer];

answers(0) = new Answer(0, "Yes", Some("Yes"))
answers(1) = new Answer(1, "No", Some("No"))
answers += new Answer(0, "Yes", Some("Yes"))
answers += new Answer(1, "No", Some("No"))

new Question(0, PollType.YesNoPollType, false, None, answers)
}

private def processYesNoAbstentionPollType(qType: String): Question = {
val answers = new Array[Answer](3)
val answers = new ArrayBuffer[Answer]

answers(0) = new Answer(0, "Yes", Some("Yes"))
answers(1) = new Answer(1, "No", Some("No"))
answers(2) = new Answer(2, "Abstention", Some("Abstention"))
answers += new Answer(0, "Yes", Some("Yes"))
answers += new Answer(1, "No", Some("No"))
answers += new Answer(2, "Abstention", Some("Abstention"))

new Question(0, PollType.YesNoAbstentionPollType, false, None, answers)
}

private def processTrueFalsePollType(qType: String): Question = {
val answers = new Array[Answer](2)
val answers = new ArrayBuffer[Answer];

answers(0) = new Answer(0, "True", Some("True"))
answers(1) = new Answer(1, "False", Some("False"))
answers += new Answer(0, "True", Some("True"))
answers += new Answer(1, "False", Some("False"))

new Question(0, PollType.TrueFalsePollType, false, None, answers)
}
Expand All @@ -417,10 +446,9 @@ object PollFactory {
var questionOption: Option[Question] = None

if (numQs > 0 && numQs <= 6) {
val answers = new Array[Answer](numQs)

val answers = new ArrayBuffer[Answer];
for (i <- 0 until numQs) {
answers(i) = new Answer(i, LetterArray(i), Some(LetterArray(i)))
answers += new Answer(i, LetterArray(i), Some(LetterArray(i)))
val question = new Question(0, PollType.LetterPollType, multiResponse, None, answers)
questionOption = Some(question)
}
Expand All @@ -436,20 +464,20 @@ object PollFactory {
var questionOption: Option[Question] = None

if (numQs > 0 && numQs <= 6) {
val answers = new Array[Answer](numQs)
val answers = new ArrayBuffer[Answer];
for (i <- 0 until numQs) {
answers(i) = new Answer(i, NumberArray(i), Some(NumberArray(i)))
answers += new Answer(i, NumberArray(i), Some(NumberArray(i)))
val question = new Question(0, PollType.NumberPollType, multiResponse, None, answers)
questionOption = Some(question)
}
}
questionOption
}

private def buildAnswers(answers: Seq[String]): Array[Answer] = {
val ans = new Array[Answer](answers.length)
private def buildAnswers(answers: Seq[String]): ArrayBuffer[Answer] = {
val ans = new ArrayBuffer[Answer]
for (i <- 0 until answers.length) {
ans(i) = new Answer(i, answers(i), Some(answers(i)))
ans += new Answer(i, answers(i), Some(answers(i)))
}

ans
Expand All @@ -467,6 +495,16 @@ object PollFactory {
questionOption
}

private def processResponsePollType(qType: String): Option[Question] = {
var questionOption: Option[Question] = None

val answers = new ArrayBuffer[Answer]
val question = new Question(0, PollType.ResponsePollType, false, None, answers)
questionOption = Some(question)

questionOption
}

private def createQuestion(qType: String, answers: Option[Seq[String]]): Option[Question] = {

val qt = qType.toUpperCase()
Expand All @@ -484,6 +522,8 @@ object PollFactory {
questionOption = processLetterPollType(qt, false)
} else if (qt.startsWith(PollType.NumberPollType)) {
questionOption = processNumberPollType(qt, false)
} else if (qt.startsWith(PollType.ResponsePollType)) {
questionOption = processResponsePollType(qt)
}

questionOption
Expand Down Expand Up @@ -550,6 +590,14 @@ class Poll(val id: String, val questions: Array[Question], val numRespondents: I
})
}

def addQuestionResponse(questionID: Int, answer: String) {
questions.foreach(q => {
if (q.id == questionID) {
q.addQuestionResponse(answer)
}
})
}

def toPollVO(): PollVO = {
val qvos = new ArrayBuffer[QuestionVO]
questions.foreach(q => {
Expand All @@ -568,7 +616,10 @@ class Poll(val id: String, val questions: Array[Question], val numRespondents: I
}
}

class Question(val id: Int, val questionType: String, val multiResponse: Boolean, val text: Option[String], val answers: Array[Answer]) {
class Question(val id: Int, val questionType: String, val multiResponse: Boolean, val text: Option[String], val answers: ArrayBuffer[Answer]) {
def addAnswer(text: String) {
answers += new Answer(answers.size, text, Some(text))
}

def clear() {
answers.foreach(r => r.clear)
Expand All @@ -588,6 +639,10 @@ class Question(val id: Int, val questionType: String, val multiResponse: Boolean
})
}

def addQuestionResponse(answer: String) {
addAnswer(answer)
}

def toQuestionVO(): QuestionVO = {
val rvos = new ArrayBuffer[AnswerVO]
answers.foreach(answer => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ class ReceivedJsonMsgHandlerActor(
routeGenericMsg[GetCurrentPollReqMsg](envelope, jsonNode)
case RespondToPollReqMsg.NAME =>
routeGenericMsg[RespondToPollReqMsg](envelope, jsonNode)
case RespondToTypedPollReqMsg.NAME =>
routeGenericMsg[RespondToTypedPollReqMsg](envelope, jsonNode)

// Webcam
case UserBroadcastCamStartMsg.NAME =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@ class MeetingActor(
case m: RespondToPollReqMsg =>
pollApp.handle(m, liveMeeting, msgBus)
updateUserLastActivity(m.body.requesterId)
case m: RespondToTypedPollReqMsg =>
pollApp.handle(m, liveMeeting, msgBus)
updateUserLastActivity(m.body.requesterId)

// Breakout
case m: BreakoutRoomsListMsg => state = handleBreakoutRoomsListMsg(m, state)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ case class PollShowResultEvtMsgBody(userId: String, pollId: String, poll: Simple

object PollStartedEvtMsg { val NAME = "PollStartedEvtMsg" }
case class PollStartedEvtMsg(header: BbbClientMsgHeader, body: PollStartedEvtMsgBody) extends BbbCoreMsg
case class PollStartedEvtMsgBody(userId: String, pollId: String, poll: SimplePollOutVO)
case class PollStartedEvtMsgBody(userId: String, pollId: String, pollType: String, question: String, poll: SimplePollOutVO)

object PollStoppedEvtMsg { val NAME = "PollStoppedEvtMsg" }
case class PollStoppedEvtMsg(header: BbbClientMsgHeader, body: PollStoppedEvtMsgBody) extends BbbCoreMsg
Expand All @@ -34,21 +34,29 @@ object RespondToPollReqMsg { val NAME = "RespondToPollReqMsg" }
case class RespondToPollReqMsg(header: BbbClientMsgHeader, body: RespondToPollReqMsgBody) extends StandardMsg
case class RespondToPollReqMsgBody(requesterId: String, pollId: String, questionId: Int, answerId: Int)

object RespondToTypedPollReqMsg { val NAME = "RespondToTypedPollReqMsg" }
case class RespondToTypedPollReqMsg(header: BbbClientMsgHeader, body: RespondToTypedPollReqMsgBody) extends StandardMsg
case class RespondToTypedPollReqMsgBody(requesterId: String, pollId: String, questionId: Int, answer: String)

object UserRespondedToPollRespMsg { val NAME = "UserRespondedToPollRespMsg" }
case class UserRespondedToPollRespMsg(header: BbbClientMsgHeader, body: UserRespondedToPollRespMsgBody) extends BbbCoreMsg
case class UserRespondedToPollRespMsgBody(pollId: String, userId: String, answerId: Int)

object UserRespondedToTypedPollRespMsg { val NAME = "UserRespondedToTypedPollRespMsg" }
case class UserRespondedToTypedPollRespMsg(header: BbbClientMsgHeader, body: UserRespondedToTypedPollRespMsgBody) extends BbbCoreMsg
case class UserRespondedToTypedPollRespMsgBody(pollId: String, userId: String, answer: String)

object ShowPollResultReqMsg { val NAME = "ShowPollResultReqMsg" }
case class ShowPollResultReqMsg(header: BbbClientMsgHeader, body: ShowPollResultReqMsgBody) extends StandardMsg
case class ShowPollResultReqMsgBody(requesterId: String, pollId: String)

object StartCustomPollReqMsg { val NAME = "StartCustomPollReqMsg" }
case class StartCustomPollReqMsg(header: BbbClientMsgHeader, body: StartCustomPollReqMsgBody) extends StandardMsg
case class StartCustomPollReqMsgBody(requesterId: String, pollId: String, pollType: String, answers: Seq[String])
case class StartCustomPollReqMsgBody(requesterId: String, pollId: String, pollType: String, answers: Seq[String], question: String)

object StartPollReqMsg { val NAME = "StartPollReqMsg" }
case class StartPollReqMsg(header: BbbClientMsgHeader, body: StartPollReqMsgBody) extends StandardMsg
case class StartPollReqMsgBody(requesterId: String, pollId: String, pollType: String)
case class StartPollReqMsgBody(requesterId: String, pollId: String, pollType: String, question: String)

object StopPollReqMsg { val NAME = "StopPollReqMsg" }
case class StopPollReqMsg(header: BbbClientMsgHeader, body: StopPollReqMsgBody) extends StandardMsg
Expand Down
2 changes: 2 additions & 0 deletions bigbluebutton-html5/imports/api/polls/server/eventHandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import handlePollStopped from './handlers/pollStopped';
import handlePollPublished from './handlers/pollPublished';
import handleUserVoted from './handlers/userVoted';
import handleUserResponded from './handlers/userResponded';
import handleUserTypedResponse from './handlers/userTypedResponse';

RedisPubSub.on('PollShowResultEvtMsg', handlePollPublished);
RedisPubSub.on('PollStartedEvtMsg', handlePollStarted);
RedisPubSub.on('PollStoppedEvtMsg', handlePollStopped);
RedisPubSub.on('PollUpdatedEvtMsg', handleUserVoted);
RedisPubSub.on('UserRespondedToPollRespMsg', handleUserResponded);
RedisPubSub.on('UserRespondedToTypedPollRespMsg', handleUserTypedResponse);

0 comments on commit e966d6c

Please sign in to comment.