Skip to content

Commit

Permalink
Merge pull request bigbluebutton#22208 from GuiLeme/fix-presentation-…
Browse files Browse the repository at this point in the history
…toast

fix(html5/akka/graphql-server): fix presentation-uploader toast and modal
  • Loading branch information
gustavotrott authored Feb 12, 2025
2 parents 6939245 + 0f4cd09 commit 2c852d9
Show file tree
Hide file tree
Showing 17 changed files with 145 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class PresentationPodHdlrs(implicit val context: ActorContext)
with SetPresenterInDefaultPodInternalMsgHdlr
with RemovePresentationPubMsgHdlr
with SetPresentationDownloadablePubMsgHdlr
with SetPresentationRenderedInToastPubMsgHdlr
with PresentationConversionUpdatePubMsgHdlr
with PresentationPageGeneratedPubMsgHdlr
with PresentationPageCountErrorPubMsgHdlr
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.bigbluebutton.core.apps.presentationpod

import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.db.PresPresentationDAO
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.running.LiveMeeting

trait SetPresentationRenderedInToastPubMsgHdlr extends RightsManagementTrait {
this: PresentationPodHdlrs =>

def handle(
msg: SetPresentationRenderedInToastPubMsg, state: MeetingState2x,
liveMeeting: LiveMeeting, bus: MessageBus
): MeetingState2x = {

if (filterPresentationMessage(liveMeeting.users2x, msg.header.userId) &&
permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to set presentation rendered in toast."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
} else {
val presentationId = msg.body.presentationId
PresPresentationDAO.setPresentationRenderedInToast(presentationId)
}
state
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ case class PresPresentationDbModel(
downloadFileExtension: Option[String],
downloadFileUri: Option[String],
removable: Boolean,
renderedInToast: Boolean,
uploadInProgress: Boolean,
uploadCompleted: Boolean,
uploadErrorMsgKey: Option[String],
Expand All @@ -43,6 +44,7 @@ class PresPresentationDbTableDef(tag: Tag) extends Table[PresPresentationDbModel
val downloadable = column[Boolean]("downloadable")
val downloadFileExtension = column[Option[String]]("downloadFileExtension")
val downloadFileUri = column[Option[String]]("downloadFileUri")
val renderedInToast = column[Boolean]("renderedInToast")
val removable = column[Boolean]("removable")
val uploadInProgress = column[Boolean]("uploadInProgress")
val uploadCompleted = column[Boolean]("uploadCompleted")
Expand All @@ -56,7 +58,8 @@ class PresPresentationDbTableDef(tag: Tag) extends Table[PresPresentationDbModel
// val meeting = foreignKey("meeting_fk", meetingId, Meetings)(_.meetingId, onDelete = ForeignKeyAction.Cascade)

def * = (
presentationId, meetingId, uploadUserId, uploadTemporaryId, uploadToken, name, filenameConverted, isDefault, current, downloadable, downloadFileExtension, downloadFileUri, removable,
presentationId, meetingId, uploadUserId, uploadTemporaryId, uploadToken, name, filenameConverted, isDefault, current,
downloadable, downloadFileExtension, downloadFileUri, removable, renderedInToast,
uploadInProgress, uploadCompleted, uploadErrorMsgKey, uploadErrorDetailsJson, totalPages,
exportToChatStatus, exportToChatCurrentPage, exportToChatHasError
) <> (PresPresentationDbModel.tupled, PresPresentationDbModel.unapply)
Expand All @@ -73,7 +76,7 @@ object PresPresentationDAO {
DatabaseConnection.enqueue(
sqlu"""
insert into "pres_presentation"("meetingId","presentationId","uploadUserId","uploadTemporaryId","uploadToken","name",
"filenameConverted","isDefault","current","downloadable","removable","uploadInProgress","uploadCompleted","totalPages")
"filenameConverted","isDefault","current","downloadable","removable","renderedInToast","uploadInProgress","uploadCompleted","totalPages")
select
${meetingId} as "meetingId",
${presentationId} as "presentationId",
Expand All @@ -86,6 +89,7 @@ object PresPresentationDAO {
false as "current", --Set after pages were inserted
false as "downloadable",
false as "removable",
false as "renderedInToast",
false as "uploadInProgress",
false as "uploadCompleted",
0 as "totalPages"
Expand Down Expand Up @@ -196,6 +200,15 @@ object PresPresentationDAO {
)
}

def setPresentationRenderedInToast(presentationId: String) = {
DatabaseConnection.enqueue(
TableQuery[PresPresentationDbTableDef]
.filter(_.presentationId === presentationId)
.map(p => p.renderedInToast)
.update(true)
)
}

def updateDownloadable(presentationId: String, downloadable : Boolean, downloadableExtension: String) = {
DatabaseConnection.enqueue(
TableQuery[PresPresentationDbTableDef]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ class ReceivedJsonMsgHandlerActor(
routeGenericMsg[PresentationPageCountErrorSysPubMsg](envelope, jsonNode)
case PresentationPageGeneratedSysPubMsg.NAME =>
routeGenericMsg[PresentationPageGeneratedSysPubMsg](envelope, jsonNode)
case SetPresentationRenderedInToastPubMsg.NAME =>
routeGenericMsg[SetPresentationRenderedInToastPubMsg](envelope, jsonNode)
case PresentationPageConvertedSysMsg.NAME =>
routeGenericMsg[PresentationPageConvertedSysMsg](envelope, jsonNode)
case PresentationPageConversionStartedSysMsg.NAME =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ class MeetingActor(
case m: PresentationUploadedFileVirusErrorSysPubMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
case m: PresentationUploadedFileScanFailedErrorSysPubMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
case m: PresentationPageGeneratedSysPubMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
case m: SetPresentationRenderedInToastPubMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
case m: PresentationPageCountErrorSysPubMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
case m: PresentationUploadTokenReqMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
case m: ResizeAndMovePagePubMsg =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ object PreuploadedPresentationsSysPubMsg { val NAME = "PreuploadedPresentationsS
case class PreuploadedPresentationsSysPubMsg(header: BbbClientMsgHeader, body: PreuploadedPresentationsSysPubMsgBody) extends StandardMsg
case class PreuploadedPresentationsSysPubMsgBody(presentations: Vector[PresentationVO])

object SetPresentationRenderedInToastPubMsg { val NAME = "SetPresentationRenderedInToastPubMsg" }
case class SetPresentationRenderedInToastPubMsg(header: BbbClientMsgHeader, body: SetPresentationRenderedInToastPubMsgBody) extends StandardMsg
case class SetPresentationRenderedInToastPubMsgBody(presentationId: String)

object MakePresentationDownloadReqMsg { val NAME = "MakePresentationDownloadReqMsg" }
case class MakePresentationDownloadReqMsg(header: BbbClientMsgHeader, body: MakePresentationDownloadReqMsgBody) extends StandardMsg
case class MakePresentationDownloadReqMsgBody(presId: String, allPages: Boolean, pages: List[Int], fileStateType: String)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export default function buildRedisMessage(sessionVariables: Record<string, unkno
};

const body = {
podId: 'DEFAULT_PRESENTATION_POD',
presentationId: input.presentationId,
};

Expand Down
1 change: 1 addition & 0 deletions bbb-graphql-server/bbb-graphql-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ Permission: Restricted to Presenter
- `name`
- `presentationId`
- `removable`
- `renderedInToast`
- `totalPages`
- `totalPagesUploaded`
- `uploadCompleted`
Expand Down
2 changes: 2 additions & 0 deletions bbb-graphql-server/bbb_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,7 @@ CREATE TABLE "pres_presentation" (
"downloadable" boolean,
"downloadFileExtension" varchar(25),
"downloadFileUri" varchar(500),
"renderedInToast" boolean,
"uploadInProgress" boolean,
"uploadCompleted" boolean,
"uploadErrorMsgKey" varchar(100),
Expand Down Expand Up @@ -1361,6 +1362,7 @@ SELECT pres_presentation."meetingId",
pres_presentation."downloadFileExtension",
pres_presentation."downloadFileUri",
pres_presentation."removable",
pres_presentation."renderedInToast",
pres_presentation."uploadTemporaryId",
pres_presentation."uploadInProgress",
pres_presentation."uploadCompleted",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ select_permissions:
- name
- presentationId
- removable
- renderedInToast
- totalPages
- totalPagesUploaded
- uploadCompleted
Expand Down
1 change: 1 addition & 0 deletions bigbluebutton-html5/imports/ui/Types/presentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface PresPresentation {
totalPages: number;
totalPagesUploaded: number;
presentationId: string;
renderedInToast: boolean;
removable: boolean;
uploadCompleted: boolean;
exportToChatInProgress?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ async function convertAndUpload(presentations: any, padId: string, presentationE
onUpload: () => { },
onProgress: () => { },
onDone: () => { },
}, undefined, undefined, undefined, presentationEnabled);
}, undefined, () => { }, undefined, presentationEnabled);
}

export default {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { defineMessages } from 'react-intl';
import { usePreviousValue } from '/imports/ui/hooks/usePreviousValue';
import { notify } from '/imports/ui/services/notification';
import Session from '/imports/ui/services/storage/in-memory';
import checkSamePresentation from './utils';

const EXPORT_STATUSES = {
RUNNING: 'RUNNING',
Expand Down Expand Up @@ -453,80 +452,91 @@ function renderExportToast(presToShow, intl) {

export const PresentationUploaderToast = ({
intl,
convertingPresentations,
presentations,
setPresentationIdsYetToSee,
presentationsToBeShowed,
setPresentationRenderedInToast,
forceShowToast,
setForceShowToast,
}) => {
const [showToast, setShowToast] = useState(false);
const dismissedErrorItems = useRef([]);
const [dismissedItems, setDismissedItems] = useState([]);
const prevPresentations = usePreviousValue(presentations);
const exportToastIdRef = useRef('presentationUploaderExportPresentationId');
const convertingToastIdRef = useRef('presentationUploaderConvertingPresentationId');

const addPressIdToDismissed = (presId) => {
dismissedErrorItems.current.push(presId);
setDismissedItems((prev) => {
prev.push(presId);
return prev;
});
};

const getIdsFromPresentationsAndDismiss = (pres) => {
const presToRemove = [];
pres.forEach((p) => {
if (p.uploadErrorMsgKey && !dismissedErrorItems.current.includes(p.presentationId)) {
presToRemove.push(p.presentationId);
if (!dismissedItems.includes(p.presentationId)) {
addPressIdToDismissed(p.presentationId);
}
});
setPresentationIdsYetToSee(new Set());
};

useEffect(() => {
presentations
.filter((p) => !dismissedErrorItems.current.includes(p.presentationId))
.forEach((p) => {
const prevPropPres = (prevPresentations || [])
.find((pres) => pres.presentationId === p.presentationId);
// display notification when presentation is exported
if (prevPropPres?.exportToChatStatus
const exportingPres = presentations.map((p) => {
const prevPropPres = (prevPresentations || [])
.find((pres) => pres.presentationId === p.presentationId);
// display notification when presentation is exported
if (prevPropPres?.exportToChatStatus
&& p?.exportToChatStatus === EXPORT_STATUSES.EXPORTED
&& prevPropPres?.exportToChatStatus !== p?.exportToChatStatus
) {
notify(intl.formatMessage(intlMessages.linkAvailable, { 0: p.name }), 'success');
handleDismissToast(exportToastIdRef.current);
}

// display notification for exportation status
if ([
EXPORT_STATUSES.RUNNING,
EXPORT_STATUSES.COLLECTING,
EXPORT_STATUSES.PROCESSING,
].includes(p?.exportToChatStatus)) {
if (toast.isActive(exportToastIdRef.current)) {
toast.update(exportToastIdRef.current, {
render: renderExportToast(presentations, intl),
});
} else {
toast(
renderExportToast(presentations, intl), {
hideProgressBar: true,
autoClose: false,
newestOnTop: true,
closeOnClick: true,
toastId: exportToastIdRef.current,
onClose: () => {
Session.setItem('presentationUploaderExportToastId', null);
getIdsFromPresentationsAndDismiss(presentations);
},
},
);
}
}
});
}, [presentations]);
) {
notify(intl.formatMessage(intlMessages.linkAvailable, { 0: p.name }), 'success');
handleDismissToast(exportToastIdRef.current);
}
return p;
}).filter((p) => (dismissedItems.length > 0 && !dismissedItems.includes(p.presentationId))
|| p.exportToChatInProgress);

if (exportingPres && exportingPres.length > 0) {
if (toast.isActive(exportToastIdRef.current)) {
toast.update(exportToastIdRef.current, {
render: renderExportToast(exportingPres, intl),
});
} else {
toast(
renderExportToast(exportingPres, intl), {
hideProgressBar: true,
autoClose: false,
newestOnTop: true,
closeOnClick: true,
toastId: exportToastIdRef.current,
onClose: () => {
Session.setItem('presentationUploaderExportToastId', null);
getIdsFromPresentationsAndDismiss(exportingPres);
},
},
);
}
}
}, [presentations, dismissedItems]);

useEffect(() => {
setForceShowToast(false);
}, []);

useEffect(() => {
presentationsToBeShowed.filter(
(p) => (p.uploadCompleted && !p.uploadErrorMsgKey),
).forEach(
(p) => setPresentationRenderedInToast({ variables: { presentationId: p.presentationId } }),
);
}, [showToast]);

useEffect(() => {
setShowToast(convertingPresentations
.filter((p) => !dismissedErrorItems.current.includes(p.presentationId)).length > 0);
}, [convertingPresentations]);
const allPresentationsDone = presentationsToBeShowed.every(
(p) => (p.uploadCompleted && !p.uploadErrorMsgKey),
);
// Forcing to show toast will only work if there are any presentations to show
setShowToast(presentationsToBeShowed.length > 0 && (!allPresentationsDone || forceShowToast));
}, [presentationsToBeShowed]);

if (showToast && !toast.isActive(convertingToastIdRef.current)) {
toast(() => renderToastList(presentationsToBeShowed, intl), {
Expand All @@ -538,7 +548,6 @@ export const PresentationUploaderToast = ({
toastId: convertingToastIdRef.current,
onClose: () => {
Session.setItem('presentationUploaderToastId', null);
getIdsFromPresentationsAndDismiss(presentations);
},
});
} else if (!showToast && toast.isActive(convertingToastIdRef.current)) {
Expand Down
Loading

0 comments on commit 2c852d9

Please sign in to comment.