Merge branch 'v3.0.x-release' into pres-content-from-uri-30

This commit is contained in:
Paul Trudel 2023-10-17 13:21:41 -04:00 committed by GitHub
commit 8c76b9f652
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 176 additions and 86 deletions

View File

@ -259,11 +259,12 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
) )
ChatMessageDAO.insertSystemMsg(liveMeeting.props.meetingProp.intId, GroupChatApp.MAIN_PUBLIC_CHAT, "", GroupChatMessageType.PRESENTATION, presentationDownloadInfo, "") ChatMessageDAO.insertSystemMsg(liveMeeting.props.meetingProp.intId, GroupChatApp.MAIN_PUBLIC_CHAT, "", GroupChatMessageType.PRESENTATION, presentationDownloadInfo, "")
} else if (m.body.fileStateType == "Converted") { } else if (m.body.fileStateType == "Converted") {
PresPresentationDAO.updatDownloadUri(m.body.presId, m.body.convertedFileURI) PresPresentationDAO.updateDownloadUri(m.body.presId, m.body.convertedFileURI)
} else if (m.body.fileStateType == "Original") { } else if (m.body.fileStateType == "Original") {
PresPresentationDAO.updatDownloadUri(m.body.presId, m.body.originalFileURI) PresPresentationDAO.updateDownloadUri(m.body.presId, m.body.originalFileURI)
} }
PresPresentationDAO.updateExportToChatStatus(m.body.presId, "EXPORTED")
bus.outGW.send(buildBroadcastNewPresFileAvailable(m, liveMeeting)) bus.outGW.send(buildBroadcastNewPresFileAvailable(m, liveMeeting))
} }
@ -279,6 +280,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
} }
def handle(m: PresAnnStatusMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = { def handle(m: PresAnnStatusMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
PresPresentationDAO.updateExportToChat(m.body.presId, m.body.status, m.body.pageNumber, m.body.error)
bus.outGW.send(buildBroadcastPresAnnStatusMsg(m, liveMeeting)) bus.outGW.send(buildBroadcastPresAnnStatusMsg(m, liveMeeting))
} }

View File

@ -1,39 +1,38 @@
package org.bigbluebutton.core.db package org.bigbluebutton.core.db
import org.bigbluebutton.core.models.{ PresentationInPod, PresentationPage } import org.bigbluebutton.core.models.{ PresentationInPod, PresentationPage }
import PostgresProfile.api._
import org.bigbluebutton.core.models.PresentationInPod import spray.json.JsValue
import slick.jdbc.PostgresProfile.api._
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{ Failure, Success } import scala.util.{ Failure, Success }
case class PresPageDbModel( case class PresPageDbModel(
pageId: String, pageId: String,
presentationId: String, presentationId: String,
num: Int, num: Int,
urls: String, urlsJson: JsValue,
content: String, content: String,
slideRevealed: Boolean, slideRevealed: Boolean,
current: Boolean, current: Boolean,
xOffset: Double, xOffset: Double,
yOffset: Double, yOffset: Double,
widthRatio: Double, widthRatio: Double,
heightRatio: Double, heightRatio: Double,
width: Double, width: Double,
height: Double, height: Double,
viewBoxWidth: Double, viewBoxWidth: Double,
viewBoxHeight: Double, viewBoxHeight: Double,
maxImageWidth: Int, maxImageWidth: Int,
maxImageHeight: Int, maxImageHeight: Int,
converted: Boolean uploadCompleted: Boolean
) )
class PresPageDbTableDef(tag: Tag) extends Table[PresPageDbModel](tag, None, "pres_page") { class PresPageDbTableDef(tag: Tag) extends Table[PresPageDbModel](tag, None, "pres_page") {
val pageId = column[String]("pageId", O.PrimaryKey) val pageId = column[String]("pageId", O.PrimaryKey)
val presentationId = column[String]("presentationId") val presentationId = column[String]("presentationId")
val num = column[Int]("num") val num = column[Int]("num")
val urls = column[String]("urls") val urlsJson = column[JsValue]("urlsJson")
val content = column[String]("content") val content = column[String]("content")
val slideRevealed = column[Boolean]("slideRevealed") val slideRevealed = column[Boolean]("slideRevealed")
val current = column[Boolean]("current") val current = column[Boolean]("current")
@ -47,9 +46,9 @@ class PresPageDbTableDef(tag: Tag) extends Table[PresPageDbModel](tag, None, "pr
val viewBoxHeight = column[Double]("viewBoxHeight") val viewBoxHeight = column[Double]("viewBoxHeight")
val maxImageWidth = column[Int]("maxImageWidth") val maxImageWidth = column[Int]("maxImageWidth")
val maxImageHeight = column[Int]("maxImageHeight") val maxImageHeight = column[Int]("maxImageHeight")
val converted = column[Boolean]("converted") val uploadCompleted = column[Boolean]("uploadCompleted")
// val presentation = foreignKey("presentation_fk", presentationId, Presentations)(_.presentationId, onDelete = ForeignKeyAction.Cascade) // val presentation = foreignKey("presentation_fk", presentationId, Presentations)(_.presentationId, onDelete = ForeignKeyAction.Cascade)
def * = (pageId, presentationId, num, urls, content, slideRevealed, current, xOffset, yOffset, widthRatio, heightRatio, width, height, viewBoxWidth, viewBoxHeight, maxImageWidth, maxImageHeight, converted) <> (PresPageDbModel.tupled, PresPageDbModel.unapply) def * = (pageId, presentationId, num, urlsJson, content, slideRevealed, current, xOffset, yOffset, widthRatio, heightRatio, width, height, viewBoxWidth, viewBoxHeight, maxImageWidth, maxImageHeight, uploadCompleted) <> (PresPageDbModel.tupled, PresPageDbModel.unapply)
} }
object PresPageDAO { object PresPageDAO {

View File

@ -1,6 +1,6 @@
package org.bigbluebutton.core.db package org.bigbluebutton.core.db
import slick.jdbc.PostgresProfile.api._ import PostgresProfile.api._
import org.bigbluebutton.core.models.{ PresentationInPod } import org.bigbluebutton.core.models.{ PresentationInPod }
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
@ -8,20 +8,24 @@ import scala.util.{ Failure, Success }
import spray.json._ import spray.json._
case class PresPresentationDbModel( case class PresPresentationDbModel(
presentationId: String, presentationId: String,
meetingId: String, meetingId: String,
name: String, name: String,
filenameConverted: String, filenameConverted: String,
isDefault: Boolean, isDefault: Boolean,
current: Boolean, current: Boolean,
downloadable: Boolean, downloadable: Boolean,
downloadFileExtension: Option[String], downloadFileExtension: Option[String],
downloadFileUri: Option[String], downloadFileUri: Option[String],
removable: Boolean, removable: Boolean,
uploadCompleted: Boolean, uploadInProgress: Boolean,
numPages: Int, uploadCompleted: Boolean,
errorMsgKey: String, uploadErrorMsgKey: String,
errorDetails: String uploadErrorDetailsJson: JsValue,
totalPages: Int,
exportToChatStatus: Option[String],
exportToChatCurrentPage: Option[Int],
exportToChatHasError: Option[Boolean]
) )
class PresPresentationDbTableDef(tag: Tag) extends Table[PresPresentationDbModel](tag, None, "pres_presentation") { class PresPresentationDbTableDef(tag: Tag) extends Table[PresPresentationDbModel](tag, None, "pres_presentation") {
@ -35,14 +39,21 @@ class PresPresentationDbTableDef(tag: Tag) extends Table[PresPresentationDbModel
val downloadFileExtension = column[Option[String]]("downloadFileExtension") val downloadFileExtension = column[Option[String]]("downloadFileExtension")
val downloadFileUri = column[Option[String]]("downloadFileUri") val downloadFileUri = column[Option[String]]("downloadFileUri")
val removable = column[Boolean]("removable") val removable = column[Boolean]("removable")
val uploadInProgress = column[Boolean]("uploadInProgress")
val uploadCompleted = column[Boolean]("uploadCompleted") val uploadCompleted = column[Boolean]("uploadCompleted")
val numPages = column[Int]("numPages") val uploadErrorMsgKey = column[String]("uploadErrorMsgKey")
val errorMsgKey = column[String]("errorMsgKey") val uploadErrorDetailsJson = column[JsValue]("uploadErrorDetailsJson")
val errorDetails = column[String]("errorDetails") val totalPages = column[Int]("totalPages")
val exportToChatStatus = column[Option[String]]("exportToChatStatus")
val exportToChatCurrentPage = column[Option[Int]]("exportToChatCurrentPage")
val exportToChatHasError = column[Option[Boolean]]("exportToChatHasError")
// val meeting = foreignKey("meeting_fk", meetingId, Meetings)(_.meetingId, onDelete = ForeignKeyAction.Cascade) // val meeting = foreignKey("meeting_fk", meetingId, Meetings)(_.meetingId, onDelete = ForeignKeyAction.Cascade)
def * = ( def * = (
presentationId, meetingId, name, filenameConverted, isDefault, current, downloadable, downloadFileExtension, downloadFileUri, removable, uploadCompleted, numPages, errorMsgKey, errorDetails presentationId, meetingId, name, filenameConverted, isDefault, current, downloadable, downloadFileExtension, downloadFileUri, removable,
uploadInProgress, uploadCompleted, uploadErrorMsgKey, uploadErrorDetailsJson, totalPages,
exportToChatStatus, exportToChatCurrentPage, exportToChatHasError
) <> (PresPresentationDbModel.tupled, PresPresentationDbModel.unapply) ) <> (PresPresentationDbModel.tupled, PresPresentationDbModel.unapply)
} }
@ -70,10 +81,14 @@ object PresPresentationDAO {
}, },
downloadFileUri = None, downloadFileUri = None,
removable = presentation.removable, removable = presentation.removable,
uploadInProgress = !presentation.uploadCompleted,
uploadCompleted = presentation.uploadCompleted, uploadCompleted = presentation.uploadCompleted,
numPages = presentation.numPages, totalPages = presentation.numPages,
errorMsgKey = presentation.errorMsgKey, uploadErrorMsgKey = presentation.errorMsgKey,
errorDetails = presentation.errorDetails.toJson.asJsObject.compactPrint uploadErrorDetailsJson = presentation.errorDetails.toJson,
exportToChatStatus = None,
exportToChatCurrentPage = None,
exportToChatHasError = None,
) )
) )
).onComplete { ).onComplete {
@ -89,7 +104,7 @@ object PresPresentationDAO {
pageId = page._2.id, pageId = page._2.id,
presentationId = presentation.id, presentationId = presentation.id,
num = page._2.num, num = page._2.num,
urls = page._2.urls.toJson.asJsObject.compactPrint, urlsJson = page._2.urls.toJson,
content = page._2.content, content = page._2.content,
slideRevealed = page._2.current, slideRevealed = page._2.current,
current = page._2.current, current = page._2.current,
@ -103,7 +118,7 @@ object PresPresentationDAO {
viewBoxHeight = 1, viewBoxHeight = 1,
maxImageWidth = 1440, maxImageWidth = 1440,
maxImageHeight = 1080, maxImageHeight = 1080,
converted = page._2.converted uploadCompleted = page._2.converted
) )
) )
} }
@ -133,7 +148,7 @@ object PresPresentationDAO {
} }
} }
def updatDownloadUri(presentationId: String, downloadFileUri: String) = { def updateDownloadUri(presentationId: String, downloadFileUri: String) = {
DatabaseConnection.db.run( DatabaseConnection.db.run(
TableQuery[PresPresentationDbTableDef] TableQuery[PresPresentationDbTableDef]
.filter(_.presentationId === presentationId) .filter(_.presentationId === presentationId)
@ -149,14 +164,38 @@ object PresPresentationDAO {
DatabaseConnection.db.run( DatabaseConnection.db.run(
TableQuery[PresPresentationDbTableDef] TableQuery[PresPresentationDbTableDef]
.filter(_.presentationId === presentationId) .filter(_.presentationId === presentationId)
.map(p => (p.errorMsgKey, p.errorDetails)) .map(p => (p.uploadErrorMsgKey, p.uploadErrorDetailsJson))
.update(errorMsgKey, errorDetails.toJson.asJsObject.compactPrint) .update(errorMsgKey, errorDetails.toJson)
).onComplete { ).onComplete {
case Success(rowAffected) => DatabaseConnection.logger.debug(s"$rowAffected row(s) updated errorMsgKey on PresPresentation table") case Success(rowAffected) => DatabaseConnection.logger.debug(s"$rowAffected row(s) updated errorMsgKey on PresPresentation table")
case Failure(e) => DatabaseConnection.logger.error(s"Error updating errorMsgKey on PresPresentation: $e") case Failure(e) => DatabaseConnection.logger.error(s"Error updating errorMsgKey on PresPresentation: $e")
} }
} }
def updateExportToChat(presentationId: String, exportToChatStatus: String, exportToChatCurrentPage: Int, exportToChatHasError: Boolean) = {
DatabaseConnection.db.run(
TableQuery[PresPresentationDbTableDef]
.filter(_.presentationId === presentationId)
.map(p => (p.exportToChatStatus, p.exportToChatCurrentPage, p.exportToChatHasError))
.update(Some(exportToChatStatus), Some(exportToChatCurrentPage), Some(exportToChatHasError))
).onComplete {
case Success(rowAffected) => DatabaseConnection.logger.debug(s"$rowAffected row(s) updated exportToChat on PresPresentation table")
case Failure(e) => DatabaseConnection.logger.error(s"Error updating exportToChat on PresPresentation: $e")
}
}
def updateExportToChatStatus(presentationId: String, exportToChatStatus: String) = {
DatabaseConnection.db.run(
TableQuery[PresPresentationDbTableDef]
.filter(_.presentationId === presentationId)
.map(p => p.exportToChatStatus)
.update(Some(exportToChatStatus))
).onComplete {
case Success(rowAffected) => DatabaseConnection.logger.debug(s"$rowAffected row(s) updated exportToChatStatus on PresPresentation table")
case Failure(e) => DatabaseConnection.logger.error(s"Error updating exportToChatStatus on PresPresentation: $e")
}
}
def delete(presentationId: String) = { def delete(presentationId: String) = {
DatabaseConnection.db.run( DatabaseConnection.db.run(
TableQuery[PresPresentationDbTableDef] TableQuery[PresPresentationDbTableDef]

View File

@ -3,6 +3,26 @@ package org.bigbluebutton.presentation.handlers;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
public class Png2SvgConversionHandler extends AbstractCommandHandler { public class Png2SvgConversionHandler extends AbstractCommandHandler {
private final StringBuilder stderr = new StringBuilder();
@Override
public void onStderr(ByteBuffer buffer, boolean closed) {
if (!closed) {
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
stderr.append(new String(bytes, StandardCharsets.UTF_8));
}
}
public String getStderrString() {
return stderr.toString();
}
private static Logger log = LoggerFactory.getLogger(Png2SvgConversionHandler.class); private static Logger log = LoggerFactory.getLogger(Png2SvgConversionHandler.class);
} }

View File

@ -252,9 +252,15 @@ public class SvgImageCreatorImp implements SvgImageCreator {
if(svgHandler.isCommandTimeout()) { if(svgHandler.isCommandTimeout()) {
log.error("Command execution (convertPngToSvg) exceeded the {} secs timeout for {} page {}.", convPdfToSvgTimeout, pres.getName(), page); log.error("Command execution (convertPngToSvg) exceeded the {} secs timeout for {} page {}.", convPdfToSvgTimeout, pres.getName(), page);
} }
done = svgHandler.isCommandSuccessful(); done = svgHandler.isCommandSuccessful();
if(!svgHandler.isCommandSuccessful()) {
String errorOutput = svgHandler.getStderrString();
if (!errorOutput.isEmpty()) {
log.error("Error during conversion from PNG to SVG: " + errorOutput);
}
}
if(destsvg.length() > 0) { if(destsvg.length() > 0) {
// Step 3: Add SVG namespace to the destionation file // Step 3: Add SVG namespace to the destionation file
// Check : https://phabricator.wikimedia.org/T43174 // Check : https://phabricator.wikimedia.org/T43174
@ -272,7 +278,6 @@ public class SvgImageCreatorImp implements SvgImageCreator {
} catch (InterruptedException e) { } catch (InterruptedException e) {
log.error("Interrupted Exception while adding SVG namespace {}", pres.getName(), e); log.error("Interrupted Exception while adding SVG namespace {}", pres.getName(), e);
} }
if (namespaceHandler.isCommandTimeout()) { if (namespaceHandler.isCommandTimeout()) {
log.error("Command execution (addNameSpaceToSVG) exceeded the {} secs timeout for {} page {}.", convPdfToSvgTimeout, pres.getName(), page); log.error("Command execution (addNameSpaceToSVG) exceeded the {} secs timeout for {} page {}.", convPdfToSvgTimeout, pres.getName(), page);
} }

View File

@ -10,6 +10,7 @@ import java.io.{ BufferedReader, IOException, InputStreamReader }
import java.net.URL import java.net.URL
import java.util.stream.Collectors import java.util.stream.Collectors
import javax.imageio.ImageIO import javax.imageio.ImageIO
import scala.io.Source
import scala.xml.XML import scala.xml.XML
object MsgBuilder { object MsgBuilder {
@ -82,11 +83,18 @@ object MsgBuilder {
val urls = Map("thumb" -> thumbUrl, "text" -> txtUrl, "svg" -> svgUrl, "png" -> pngUrl) val urls = Map("thumb" -> thumbUrl, "text" -> txtUrl, "svg" -> svgUrl, "png" -> pngUrl)
try { try {
val imgUrl = new URL(svgUrl) val svgSource = Source.fromURL(new URL(svgUrl))
val imgContent = XML.load(imgUrl) val svgContent = svgSource.mkString
svgSource.close()
val w = (imgContent \ "@width").text.replaceAll("[^.0-9]", "") // XML parser configuration in use disallows the DOCTYPE declaration within the XML document
val h = (imgContent \ "@height").text.replaceAll("[^.0-9]", "") // Sanitize the XML content removing DOCTYPE
val sanitizedSvgContent = "(?i)<!DOCTYPE[^>]*>".r.replaceAllIn(svgContent, "")
val xmlContent = XML.loadString(sanitizedSvgContent)
val w = (xmlContent \ "@width").text.replaceAll("[^.0-9]", "")
val h = (xmlContent \ "@height").text.replaceAll("[^.0-9]", "")
val width = w.toDouble val width = w.toDouble
val height = h.toDouble val height = h.toDouble

View File

@ -869,15 +869,18 @@ CREATE TABLE "pres_presentation" (
"filenameConverted" varchar(500), "filenameConverted" varchar(500),
"isDefault" boolean, "isDefault" boolean,
"current" boolean, "current" boolean,
"removable" boolean,
"downloadable" boolean, "downloadable" boolean,
"downloadFileExtension" varchar(25), "downloadFileExtension" varchar(25),
"downloadFileUri" varchar(500), "downloadFileUri" varchar(500),
"removable" boolean, "uploadInProgress" boolean,
"converting" boolean,
"uploadCompleted" boolean, "uploadCompleted" boolean,
"numPages" integer, "uploadErrorMsgKey" varchar(100),
"errorMsgKey" varchar(100), "uploadErrorDetailsJson" jsonb,
"errorDetails" TEXT "totalPages" integer,
"exportToChatStatus" varchar(25),
"exportToChatCurrentPage" integer,
"exportToChatHasError" boolean
); );
CREATE INDEX "idx_pres_presentation_meetingId" ON "pres_presentation"("meetingId"); CREATE INDEX "idx_pres_presentation_meetingId" ON "pres_presentation"("meetingId");
CREATE INDEX "idx_pres_presentation_meetingId_curr" ON "pres_presentation"("meetingId") where "current" is true; CREATE INDEX "idx_pres_presentation_meetingId_curr" ON "pres_presentation"("meetingId") where "current" is true;
@ -886,7 +889,7 @@ CREATE TABLE "pres_page" (
"pageId" varchar(100) PRIMARY KEY, "pageId" varchar(100) PRIMARY KEY,
"presentationId" varchar(100) REFERENCES "pres_presentation"("presentationId") ON DELETE CASCADE, "presentationId" varchar(100) REFERENCES "pres_presentation"("presentationId") ON DELETE CASCADE,
"num" integer, "num" integer,
"urls" TEXT, "urlsJson" jsonb,
"content" TEXT, "content" TEXT,
"slideRevealed" boolean default false, "slideRevealed" boolean default false,
"current" boolean, "current" boolean,
@ -900,7 +903,7 @@ CREATE TABLE "pres_page" (
"viewBoxHeight" NUMERIC, "viewBoxHeight" NUMERIC,
"maxImageWidth" integer, "maxImageWidth" integer,
"maxImageHeight" integer, "maxImageHeight" integer,
"converted" boolean "uploadCompleted" boolean
); );
CREATE INDEX "idx_pres_page_presentationId" ON "pres_page"("presentationId"); CREATE INDEX "idx_pres_page_presentationId" ON "pres_page"("presentationId");
CREATE INDEX "idx_pres_page_presentationId_curr" ON "pres_page"("presentationId") where "current" is true; CREATE INDEX "idx_pres_page_presentationId_curr" ON "pres_page"("presentationId") where "current" is true;
@ -916,12 +919,23 @@ SELECT pres_presentation."meetingId",
pres_presentation."downloadFileExtension", pres_presentation."downloadFileExtension",
pres_presentation."downloadFileUri", pres_presentation."downloadFileUri",
pres_presentation."removable", pres_presentation."removable",
pres_presentation."converting", pres_presentation."uploadInProgress",
pres_presentation."uploadCompleted", pres_presentation."uploadCompleted",
pres_presentation."numPages", pres_presentation."totalPages",
pres_presentation."errorMsgKey", ( SELECT count(*)
pres_presentation."errorDetails", FROM pres_page
(SELECT count(*) FROM pres_page WHERE pres_page."presentationId" = pres_presentation."presentationId" AND "converted" is true) as "pagesUploaded" WHERE pres_page."presentationId" = pres_presentation."presentationId"
AND "uploadCompleted" is true
) as "totalPagesUploaded",
pres_presentation."uploadErrorMsgKey",
pres_presentation."uploadErrorDetailsJson",
case when pres_presentation."exportToChatStatus" is not null
and pres_presentation."exportToChatStatus" != 'EXPORTED'
and pres_presentation."exportToChatHasError" is not true
then true else false end "exportToChatInProgress",
pres_presentation."exportToChatStatus",
pres_presentation."exportToChatCurrentPage",
pres_presentation."exportToChatHasError"
FROM pres_presentation; FROM pres_presentation;
CREATE OR REPLACE VIEW public.v_pres_page AS CREATE OR REPLACE VIEW public.v_pres_page AS
@ -929,7 +943,7 @@ SELECT pres_presentation."meetingId",
pres_page."presentationId", pres_page."presentationId",
pres_page."pageId", pres_page."pageId",
pres_page.num, pres_page.num,
pres_page.urls, pres_page."urlsJson",
pres_page.content, pres_page.content,
pres_page."slideRevealed", pres_page."slideRevealed",
CASE WHEN pres_presentation."current" IS TRUE AND pres_page."current" IS TRUE THEN true ELSE false END AS "isCurrentPage", CASE WHEN pres_presentation."current" IS TRUE AND pres_page."current" IS TRUE THEN true ELSE false END AS "isCurrentPage",
@ -945,7 +959,7 @@ SELECT pres_presentation."meetingId",
(pres_page."height" * LEAST(pres_page."maxImageWidth" / pres_page."width", pres_page."maxImageHeight" / pres_page."height")) AS "scaledHeight", (pres_page."height" * LEAST(pres_page."maxImageWidth" / pres_page."width", pres_page."maxImageHeight" / pres_page."height")) AS "scaledHeight",
(pres_page."width" * pres_page."widthRatio" / 100 * LEAST(pres_page."maxImageWidth" / pres_page."width", pres_page."maxImageHeight" / pres_page."height")) AS "scaledViewBoxWidth", (pres_page."width" * pres_page."widthRatio" / 100 * LEAST(pres_page."maxImageWidth" / pres_page."width", pres_page."maxImageHeight" / pres_page."height")) AS "scaledViewBoxWidth",
(pres_page."height" * pres_page."heightRatio" / 100 * LEAST(pres_page."maxImageWidth" / pres_page."width", pres_page."maxImageHeight" / pres_page."height")) AS "scaledViewBoxHeight", (pres_page."height" * pres_page."heightRatio" / 100 * LEAST(pres_page."maxImageWidth" / pres_page."width", pres_page."maxImageHeight" / pres_page."height")) AS "scaledViewBoxHeight",
pres_page."converted" pres_page."uploadCompleted"
FROM pres_page FROM pres_page
JOIN pres_presentation ON pres_presentation."presentationId" = pres_page."presentationId"; JOIN pres_presentation ON pres_presentation."presentationId" = pres_page."presentationId";
@ -960,9 +974,9 @@ SELECT pres_presentation."meetingId",
case when pres_presentation."downloadable" then pres_presentation."downloadFileExtension" else null end "downloadFileExtension", case when pres_presentation."downloadable" then pres_presentation."downloadFileExtension" else null end "downloadFileExtension",
case when pres_presentation."downloadable" then pres_presentation."downloadFileUri" else null end "downloadFileUri", case when pres_presentation."downloadable" then pres_presentation."downloadFileUri" else null end "downloadFileUri",
pres_presentation."removable", pres_presentation."removable",
pres_presentation."numPages", pres_presentation."totalPages",
pres_page.num, pres_page.num,
pres_page.urls, pres_page."urlsJson",
pres_page.content, pres_page.content,
pres_page."slideRevealed", pres_page."slideRevealed",
CASE WHEN pres_presentation."current" IS TRUE AND pres_page."current" IS TRUE THEN true ELSE false END AS "isCurrentPage", CASE WHEN pres_presentation."current" IS TRUE AND pres_page."current" IS TRUE THEN true ELSE false END AS "isCurrentPage",

View File

@ -32,7 +32,7 @@ select_permissions:
- scaledViewBoxWidth - scaledViewBoxWidth
- scaledWidth - scaledWidth
- slideRevealed - slideRevealed
- urls - urlsJson
- viewBoxHeight - viewBoxHeight
- viewBoxWidth - viewBoxWidth
- width - width

View File

@ -19,7 +19,7 @@ select_permissions:
- isCurrentPage - isCurrentPage
- isDefaultPresentation - isDefaultPresentation
- num - num
- numPages - totalPages
- pageId - pageId
- presentationFilenameConverted - presentationFilenameConverted
- presentationId - presentationId
@ -30,7 +30,7 @@ select_permissions:
- scaledViewBoxWidth - scaledViewBoxWidth
- scaledWidth - scaledWidth
- slideRevealed - slideRevealed
- urls - urlsJson
- viewBoxHeight - viewBoxHeight
- viewBoxWidth - viewBoxWidth
- width - width

View File

@ -20,21 +20,24 @@ select_permissions:
- role: bbb_client - role: bbb_client
permission: permission:
columns: columns:
- converting
- current - current
- downloadFileUri - downloadFileUri
- downloadable - downloadable
- downloadFileExtension - downloadFileExtension
- errorDetails - uploadInProgress
- errorMsgKey - uploadCompleted
- uploadErrorMsgKey
- uploadErrorDetailsJson
- exportToChatStatus
- exportToChatCurrentPage
- exportToChatHasError
- filenameConverted - filenameConverted
- isDefault - isDefault
- name - name
- numPages - totalPages
- pagesUploaded - totalPagesUploaded
- presentationId - presentationId
- removable - removable
- uploadCompleted
filter: filter:
meetingId: meetingId:
_eq: X-Hasura-PresenterInMeeting _eq: X-Hasura-PresenterInMeeting

View File

@ -161,7 +161,7 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({
color={messageContent.color} color={messageContent.color}
moderator={messageContent.isModerator} moderator={messageContent.isModerator}
> >
{!message.user || message.user?.avatar.length === 0 ? messageContent.name.toLowerCase().slice(0, 2) || 'q' : 'a'} {!message.user || message.user?.avatar.length === 0 ? messageContent.name.toLowerCase().slice(0, 2) || '' : ''}
</ChatAvatar> </ChatAvatar>
)} )}
<ChatContent sameSender={message?.user ? sameSender : false}> <ChatContent sameSender={message?.user ? sameSender : false}>

View File

@ -1,3 +1,3 @@
. ./opts-global.sh . ./opts-global.sh
OPTS="$OPTS -t deb -d zip,unzip,imagemagick,redis-server,xpdf-utils,bbb-libreoffice-docker,psmisc,fonts-crosextra-carlito,fonts-crosextra-caladea,fonts-noto,openjdk-17-jdk,file" OPTS="$OPTS -t deb -d zip,unzip,imagemagick,redis-server,xpdf-utils,bbb-libreoffice-docker,psmisc,fonts-crosextra-carlito,fonts-crosextra-caladea,fonts-noto,openjdk-17-jdk,file,potrace"