diff --git a/.env b/.env index b6ca6cbad..b8e0b7727 100644 --- a/.env +++ b/.env @@ -116,8 +116,7 @@ LAF_SHOW_PARTICIPANTS_ON_PARTICIPANTS=0 ###> {"ldap1":"Nutzerkreis1"} ### LAF_ADDRESSBOOK_CHECKBOX_LABEL_2_VALUE={} VICH_BASE=http://dummy -LAF_WHITEBOARD_FUNCTION=0 -LAF_ETHERPAD_FUNCTION=0 + LAF_ALLOW_SET_DEPUTY=1 LAF_TERMS_AND_CONDITIONS="" LAF_USE_MULTIFRAME=1 @@ -126,6 +125,7 @@ LAF_HIDE_PROFILEPICTURE=0 LAF_SHOW_TAG_TRANSPARENT_BACKGROUND=0 LAF_DEFAULT_ONLINE_STATUS=1 LAF_FLOATING_TAG_FORCE_SHOW=1 +LAF_SHOW_CALENDLY=1 ###< LaF ### ###> Default Jitsi Server ### @@ -294,16 +294,24 @@ JITSI_MEET_DEFAULT_PARTICIPANTS_PANE=0 ### { removeMultiframe(newInstance); }); @@ -82,10 +86,16 @@ function createIframe(url, title, startMaximized = true, borderColor = '') { removeInteraction(newInstance.frame); }); newInstance.addEventListener('incrementZindex', () => { - zIndex++; + zIndex++; }); newInstance.addEventListener('createNewMultiframe', (data) => { - createIframe(data.url,data.title,data.maximize) + createIframe(data.url, data.title, data.maximize, '', data.roomuid) + }); + newInstance.addEventListener('blockUrlForMultiframe', (data) => { + blockedUrls.push(data.url); + }); + newInstance.addEventListener('openNewMultiframe', (data) => { + sendViaWebsocket('openNewIframe',JSON.stringify(data)); }); multiframes.push(newInstance); @@ -93,22 +103,30 @@ function createIframe(url, title, startMaximized = true, borderColor = '') { counter += 40; if (isFullscreen()) { - if (document){ + if (document) { document.exitFullscreen(); } } } + +function checkIfUrlIsBlocked(url) { + return blockedUrls.includes(url) +} + function multiframeCheck(random) { - return multiframes.some(instance => instance.random === random); + return multiframes.find(instance => instance.random === random); } + function getMultiframeFromHtmlFrame(frame) { - const res= multiframes.find(instance => instance.frame === frame); + const res = multiframes.find(instance => instance.frame === frame); return res; } + function getotherFramesNotActual(instance) { const res = multiframes.filter(frame => frame !== instance); return res; } + function removeMultiframe(instance) { multiframes = multiframes.filter(i => i !== instance); @@ -157,6 +175,7 @@ function switchDragOff() { return null; } } + function moveActualToForeground(actualFrame) { if (actualFrame.isMutable) { actualFrame.playFrame(); @@ -171,7 +190,7 @@ function moveActualToForeground(actualFrame) { const totalFrames = multiframes.length; // Setze das z-index des aktuellen Frames auf die Anzahl der Frames (höchstes z-index) - actualFrame.setZindex(totalFrames +zIndexOffset); + actualFrame.setZindex(totalFrames + zIndexOffset); actualFrame.moveInForeground(); // Sortiere die anderen Frames nach ihrem aktuellen z-index const otherFrames = getotherFramesNotActual(actualFrame) @@ -181,10 +200,11 @@ function moveActualToForeground(actualFrame) { // Vergib die z-index-Werte beginnend bei 1 let zIndex = 1; otherFrames.forEach(frame => { - frame.setZindex(zIndex+zIndexOffset); + frame.setZindex(zIndex + zIndexOffset); zIndex++; }); } + function addInteractions(ele) { const position = {x: counter, y: counter} @@ -372,7 +392,7 @@ function addInteractions(ele) { function makeBlury(frame) { var content = frame.querySelector('.iframeFrame'); - content.style.visibility='hidden'; + content.style.visibility = 'hidden'; frame.style.opacity = 0.5; // for (var f of frames) { // f.insertAdjacentHTML('afterbegin', '
'); @@ -390,6 +410,7 @@ function removeBlury(frame) { function checkIfIsMutable(frame) { } + // function checkIfIsMutable(frame) { // if (frame.classList.contains('isMutable')) { // var actualPause = frame.querySelector('.pauseConference') @@ -435,4 +456,5 @@ function addOverlayOverAllMultiframes() { function removeOverlayFromAllMultiframes() { document.querySelectorAll('.iframe-overlay').forEach(overlay => overlay.remove()); } -export {initStartIframe, createIframe, checkIfIsMutable} + +export {initStartIframe, createIframe, checkIfIsMutable} diff --git a/assets/js/createDialog.js b/assets/js/createDialog.js new file mode 100644 index 000000000..d9b35dd6d --- /dev/null +++ b/assets/js/createDialog.js @@ -0,0 +1,29 @@ +import Swal from 'sweetalert2'; + +export function showDialog(data) { + if (data.type !== 'dialog') return; + + const buttonsHtml = data.buttons.map((button, index) => { + const dataAttributes = button.data ? Object.entries(button.data).map(([key, value]) => `data-${key}='${value}'`).join(' ') : ''; + return ` + ${button.text} + `; + }).join(' '); + + Swal.fire({ + title: data.header, + backdrop: false, + html: `

${data.text}

${buttonsHtml}`, + icon: data.dialogType, + showConfirmButton: false, + heightAuto: false, + didRender: () => { + data.buttons.forEach((button, index) => { + document.getElementById(`swal-btn-${index}`).addEventListener('click', () => { + Swal.close(); + }); + }); + } + }); +} + diff --git a/assets/js/frontend.js b/assets/js/frontend.js index ffaa902e0..b6482e42b 100644 --- a/assets/js/frontend.js +++ b/assets/js/frontend.js @@ -12,6 +12,7 @@ import {initSchedulePublic} from './scheduling' import {initGenerell} from './init'; import {setSnackbar} from "./myToastr"; import * as h2Button from "h2-invent-apps"; +import {initAllComponents} from "./confirmation"; $(document).ready(function () { initGenerell(); @@ -30,6 +31,7 @@ $(window).on('load', function () { initMDB({ Popover }); + initAllComponents(); $('[data-mdb-toggle="toastr"]').click(function (e) { setSnackbar($(this).data('text'),'',$(this).data('type')) diff --git a/assets/js/livekit/livekitUtils.js b/assets/js/livekit/livekitUtils.js index b57e3b0de..73e160784 100644 --- a/assets/js/livekit/livekitUtils.js +++ b/assets/js/livekit/livekitUtils.js @@ -28,7 +28,7 @@ export class LivekitUtils { initStartWhiteboard(); showPlayPause(); initSocialIcons(changeCamera.bind(this)); - this.initChatToggle(); + // this.initChatToggle(); this.conferenceRunning = true; this.initMicAndCamera(); window.onbeforeunload = function (e) { @@ -112,6 +112,9 @@ export class LivekitUtils { this.conferencePaused = false; this.playConference(); break; + case 'pleaseClose': + this.hangup(); + break; // Weitere Fälle können hier hinzugefügt werden default: console.log(`Unbekannter Nachrichtentyp: ${decoded.type}`); diff --git a/assets/js/lobbyModerator.js b/assets/js/lobbyModerator.js index e37058c75..2201fde78 100644 --- a/assets/js/lobbyModerator.js +++ b/assets/js/lobbyModerator.js @@ -155,6 +155,7 @@ function askHangup() { showCancelButton: true, confirmButtonText: hangupText, cancelButtonText: cancel, + heightAuto: false, customClass: { confirmButton: 'btn-danger btn', denyButton: 'btn-danger btn', diff --git a/assets/js/lobbyNotification.js b/assets/js/lobbyNotification.js index 59279d477..b7aab3d07 100644 --- a/assets/js/lobbyNotification.js +++ b/assets/js/lobbyNotification.js @@ -15,6 +15,7 @@ import {close, inIframe} from './moderatorIframe' import {initStarSend} from "./endModal"; import { Tooltip, initMDB } from "mdb-ui-kit"; import {initAllComponents} from "./confirmation"; +import {showDialog} from "./createDialog"; var callersoundplay = new Audio(callerSound); callersoundplay.loop = true; @@ -32,6 +33,10 @@ function masterNotify(data) { Push.Permission.request(); if (data.type === 'notification') { notifymoderator(data) + }else if (data.type === 'browserPush') { + showPush(data) + }else if (data.type === 'playSound') { + playSound(data) } else if (data.type === 'cleanNotification') { deleteToast(data.messageId); } else if (data.type === 'refresh') { @@ -42,7 +47,10 @@ function masterNotify(data) { redirect(data); } else if (data.type === 'snackbar') { setSnackbar(data.message,'', data.color, false,'0x00',data.closeAfter) - } else if (data.type === 'newJitsi') { + } + else if (data.type === 'dialog') { + showDialog(data); + }else if (data.type === 'newJitsi') { //do nothing. Is handeled somewhere localy } else if (data.type === 'refreshDashboard') { refreshDashboard(); @@ -178,6 +186,22 @@ function showPush(data) { }, 2500) }, Math.floor(Math.random() * 50) + 50); } +function playSound(data) { + setTimeout(function () { + TabUtils.lockFunction('notification' + data.messageId, function () { + if (data.soundName === 'caller'){ + var audio = new Audio(callerSound); + audio.play(); + }else if (data.soundName === 'notfication'){ + var audio = new Audio(notificationSound); + audio.play(); + }else if (data.soundName === 'newMessage'){ + var audio = new Audio(newMessageSound); + audio.play(); + } + }, 2500) + }, Math.floor(Math.random() * 50) + 50); +} function callAddhock(data) { setTimeout(function () { @@ -199,6 +223,7 @@ function callAddhock(data) { }, 5000) }, Math.floor(Math.random() * 50) + 50); + setSnackbar(data.message,'Lobby', data.color, true); } diff --git a/assets/js/lobbyParticipant.js b/assets/js/lobbyParticipant.js index 129a754c1..6b5efee1c 100644 --- a/assets/js/lobbyParticipant.js +++ b/assets/js/lobbyParticipant.js @@ -266,6 +266,7 @@ function askHangup() { showCancelButton: true, confirmButtonText: hangupText, cancelButtonText: cancel, + heightAuto: false, customClass: { confirmButton: 'btn-danger btn', cancelButton: 'btn-outline-primary btn' diff --git a/assets/js/multiframe.js b/assets/js/multiframe.js index 14b0be153..96198c189 100644 --- a/assets/js/multiframe.js +++ b/assets/js/multiframe.js @@ -4,6 +4,7 @@ import {tooltip} from 'mdb-ui-kit'; import {setCookie} from "./cookie"; import {checkIfIsMutable, zIndex} from "./createConference"; import { Tooltip, initMDB } from "mdb-ui-kit"; +import {sendViaWebsocket} from "./websocket"; export class multiframe { @@ -15,7 +16,7 @@ export class multiframe { isPaused = false; random = null; eventListeners = {}; - + roomUid = null; constructor( url, title, @@ -26,6 +27,7 @@ export class multiframe { height, width, zIndex, + roomUid = null, ) { this.url = url; this.title = title; @@ -35,6 +37,7 @@ export class multiframe { this.height = height; this.width = width; this.zIndex = zIndex; + this.roomUid = roomUid; this.createIframe(); if (startMaximized) { this.prepareMaximize(); @@ -63,7 +66,7 @@ export class multiframe {
- +
@@ -166,8 +169,18 @@ export class multiframe { delete this.closingTimeout; } else if (type === 'openNewIframe') { //todo in controllerklasse - this.triggerCreateNewMultiframe(decoded.url, decoded.title, false); - } else if (type === 'showPlayPause') { + this.triggerCreateNewMultiframe(decoded.url, decoded.title, false,decoded.roomuid); + } + else if (type === 'openNewIframeOnOthers') { + this.triggerBlockUrlForMultiframe(decoded.url); + var message = { + room: this.roomUid, + url: decoded.url, + title: decoded.title + } + this.triggerOpenNewFrameOnOthers(message); + + }else if (type === 'showPlayPause') { this.frame.classList.add('isMutable'); this.frame.dataset.muted = "0"; this.frame.querySelector('.pauseConference').classList.remove('d-none'); @@ -416,8 +429,16 @@ export class multiframe { } - triggerCreateNewMultiframe(url, title, maximize) { - this.triggerEvent('createNewMultiframe', {url: url, title: title, maximize: maximize}) + triggerCreateNewMultiframe(url, title, maximize,roomuid=null) { + this.triggerEvent('createNewMultiframe', {url: url, title: title, maximize: maximize,roomuid:roomuid}) + + } + triggerBlockUrlForMultiframe(url) { + this.triggerEvent('blockUrlForMultiframe', {url: url}) + + } + triggerOpenNewFrameOnOthers(data) { + this.triggerEvent('openNewMultiframe', data) } } \ No newline at end of file diff --git a/assets/js/myToastr.js b/assets/js/myToastr.js index 99e6cce02..98800d6ff 100644 --- a/assets/js/myToastr.js +++ b/assets/js/myToastr.js @@ -1,45 +1,56 @@ -import * as Toastr from "toastr"; - -Toastr.options = { - "closeButton": true, - "debug": false, - "newestOnTop": true, - "progressBar": true, - "positionClass": "toast-top-right", - "preventDuplicates": true, - "onclick": null, - "showDuration": "300", - "hideDuration": "1000", - "timeOut": "0", - "extendedTimeOut": "200", - "showEasing": "swing", - "hideEasing": "linear", - "showMethod": "fadeIn", - "hideMethod": "fadeOut" -} +import Swal from "sweetalert2"; +import * as Snackbar from 'node-snackbar' +// +// Toastr.options = { +// "closeButton": true, +// "debug": false, +// "newestOnTop": true, +// "progressBar": true, +// "positionClass": "toast-top-right", +// "preventDuplicates": true, +// "onclick": null, +// "showDuration": "300", +// "hideDuration": "1000", +// "timeOut": "0", +// "extendedTimeOut": "200", +// "showEasing": "swing", +// "hideEasing": "linear", +// "showMethod": "fadeIn", +// "hideMethod": "fadeOut" +// } + +function setSnackbar(text,title, color='blue', closeWithHover = false, id = '0x00',timeout=0) { -function setSnackbar(text,title, color, closeWithHover = false, id = '0x00',timeout=0) { if (color === 'danger') { - color = 'error'; - } - Toastr.options.timeOut = timeout; - if (closeWithHover === true) { - Toastr.options.timeOut = 0; - Toastr.options.extendedTimeOut = 0; - } else { - Toastr.options.extendedTimeOut = 200; - } - text = '' + text; - if (title!==''){ - Toastr[color](text,title); - }else { - Toastr[color](text); + color = 'red'; } + Snackbar.show({ + pos: 'top-center', + text: text, + duration: timeout, + textColor: color + }) + // Toastr.options.timeOut = timeout; + // if (closeWithHover === true) { + // Toastr.options.timeOut = 0; + // Toastr.options.extendedTimeOut = 0; + // } else { + // Toastr.options.extendedTimeOut = 200; + // } + // text = '' + text; + // if (title!==''){ + // Toastr[color](text,title); + // }else { + // Toastr[color](text); + // } } +function setDiolog(header, text,buttons) { + +} function deleteToast(id) { var tid = '#jitsi_toastr_' + id; if (document.querySelector(tid)) { diff --git a/assets/js/startWhiteboard.js b/assets/js/startWhiteboard.js index d3f072d93..21b333786 100644 --- a/assets/js/startWhiteboard.js +++ b/assets/js/startWhiteboard.js @@ -14,7 +14,8 @@ export function initStartWhiteboard() { ele.addEventListener('click', function (ev) { var selfurl = this.dataset.selfurl; var url = this.dataset.url; - if (this.dataset.room) { + const roomUid = this.dataset.roomuid||null; + if (this.dataset.room && url) { var message = { room: this.dataset.room, url: url, @@ -24,14 +25,17 @@ export function initStartWhiteboard() { } if (inIframe()) { - const parentMessage = JSON.stringify({ - type: 'openNewIframe', - url: selfurl, - 'title': document.title - }); - window.parent.postMessage(parentMessage, '*'); + if (selfurl){ + const parentMessage = JSON.stringify({ + type: 'openNewIframe', + url: selfurl, + 'title': document.title, + roomuid: roomUid, + }); + window.parent.postMessage(parentMessage, '*'); + } } else { - createIframe(selfurl, document.title, false); + createIframe(selfurl, document.title, false,'',roomUid); } }) } diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index 80c5e7c52..e181b9dd2 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -3,7 +3,9 @@ twig: debug: '%kernel.debug%' strict_variables: '%kernel.debug%' exception_controller: null - form_themes: ['bootstrap_4_layout.html.twig','form/ja_theme.html.twig'] + form_themes: + - 'bootstrap_4_layout.html.twig' + - 'form/ja_theme.html.twig' paths: '%kernel.project_dir%/public/mail/css': css globals: diff --git a/config/services.yaml b/config/services.yaml index c0fdc2a91..b636785c8 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -49,6 +49,7 @@ parameters: LAF_DEFAULT_ONLINE_STATUS: '%env(LAF_DEFAULT_ONLINE_STATUS)%' LAF_FLOATING_TAG_FORCE_SHOW: '%env(LAF_FLOATING_TAG_FORCE_SHOW)%' LAF_RESEND_SUBSCRIPTION_DOUBLE_OPTIN_EMAIL: '%env(LAF_RESEND_SUBSCRIPTION_DOUBLE_OPTIN_EMAIL)%' + LAF_SHOW_CALENDLY: '%env(LAF_SHOW_CALENDLY)%' ALLOW_SERVER_CHANGE_WHEN_DISABLED: '%env(ALLOW_SERVER_CHANGE_WHEN_DISABLED)%' enterprise_noExternal: '%env(enterprise_noExternal)%' diff --git a/en-GB/translations/ux_message+intl-icu.en.yaml b/en-GB/translations/ux_message+intl-icu.en.yaml deleted file mode 100644 index 528f21766..000000000 --- a/en-GB/translations/ux_message+intl-icu.en.yaml +++ /dev/null @@ -1 +0,0 @@ -email_send_invitation: Einladung wurde erfolgreich an {email} versendet. diff --git a/es-ES/translations/ux_message+intl-icu.es.yaml b/es-ES/translations/ux_message+intl-icu.es.yaml deleted file mode 100644 index 528f21766..000000000 --- a/es-ES/translations/ux_message+intl-icu.es.yaml +++ /dev/null @@ -1 +0,0 @@ -email_send_invitation: Einladung wurde erfolgreich an {email} versendet. diff --git a/fr/translations/ux_message+intl-icu.fr.yaml b/fr/translations/ux_message+intl-icu.fr.yaml deleted file mode 100644 index 528f21766..000000000 --- a/fr/translations/ux_message+intl-icu.fr.yaml +++ /dev/null @@ -1 +0,0 @@ -email_send_invitation: Einladung wurde erfolgreich an {email} versendet. diff --git a/ja/translations/ux_message+intl-icu.ja.yaml b/ja/translations/ux_message+intl-icu.ja.yaml deleted file mode 100644 index 528f21766..000000000 --- a/ja/translations/ux_message+intl-icu.ja.yaml +++ /dev/null @@ -1 +0,0 @@ -email_send_invitation: Einladung wurde erfolgreich an {email} versendet. diff --git a/ko/translations/ux_message+intl-icu.ko.yaml b/ko/translations/ux_message+intl-icu.ko.yaml deleted file mode 100644 index 528f21766..000000000 --- a/ko/translations/ux_message+intl-icu.ko.yaml +++ /dev/null @@ -1 +0,0 @@ -email_send_invitation: Einladung wurde erfolgreich an {email} versendet. diff --git a/nodejs/websocket.js b/nodejs/websocket.js index b98727c0c..0a0d003a1 100644 --- a/nodejs/websocket.js +++ b/nodejs/websocket.js @@ -65,8 +65,10 @@ io.use(function (socket, next) { io.on("connection", async (socket) => { var jwtObj = jwt.decode(socket.handshake.query.token); + console.log(jwtObj.rooms); + for (var i = 0; i < jwtObj.rooms.length; i++) { - socket.join(jwtObj.rooms[i]); + socket.join(jwtObj.rooms[i]) } var user = loginUser(socket); diff --git a/nodejs/websocketState.mjs b/nodejs/websocketState.mjs index 07f8cb22b..645eb01e1 100644 --- a/nodejs/websocketState.mjs +++ b/nodejs/websocketState.mjs @@ -49,6 +49,7 @@ export function websocketState(event, socket, message) { sendStatus(socket); break; case 'openNewIframe': + console.log(message); sendNewIframe(socket, message) break; case 'giveOnlineStatus': @@ -78,11 +79,16 @@ function sendStatusToOwnUSer(socket) { } function sendNewIframe(socket, data) { - var message = JSON.parse(data); - socket.to(message.room).emit('openNewIframe', JSON.stringify({ - url: message.url, - title: message.title - } + try { + var message = JSON.parse(data); + socket.to(message.room).emit('openNewIframe', JSON.stringify({ + url: message.url, + title: message.title + } + ) ) - ) + }catch (e) { + console.log(e) + } + } diff --git a/pa-IN/translations/ux_message+intl-icu.pa.yaml b/pa-IN/translations/ux_message+intl-icu.pa.yaml deleted file mode 100644 index 528f21766..000000000 --- a/pa-IN/translations/ux_message+intl-icu.pa.yaml +++ /dev/null @@ -1 +0,0 @@ -email_send_invitation: Einladung wurde erfolgreich an {email} versendet. diff --git a/package-lock.json b/package-lock.json index 9b992eba6..2b3833648 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "file-loader": "^6.2.0", "flatpickr": "^4.6.9", "fs": "^0.0.1-security", - "h2-invent-apps": "^2.4.0", + "h2-invent-apps": "^2.5.0", "h2-invent-material-tabs": "^1.10.0", "hotkeys-js": "^3.9.4", "interactjs": "^1.10.17", @@ -42,6 +42,7 @@ "moment": "^2.29.1", "moveable": "^0.36.3", "net": "^1.0.2", + "node-snackbar": "^0.1.16", "node-waves": "^0.7.6", "popper.js": "^1.16.1", "pretty-print-json": "^1.3.1", @@ -56,6 +57,7 @@ }, "devDependencies": { "@babel/plugin-proposal-class-properties": "^7.18.6", + "@hotwired/stimulus": "^3.0.0", "@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets", "@symfony/webpack-encore": "^4.0.0", "chromedriver": "^105.0.0", @@ -65,6 +67,7 @@ "regenerator-runtime": "^0.13.7", "sass-loader": "^13.0.0", "socket.io-client": "^4.6.1", + "typed.js": "^2.0", "webpack-notifier": "^1.12.0" } }, @@ -1985,6 +1988,13 @@ "resolved": "https://registry.npmjs.org/@holema/mdtimepicker/-/mdtimepicker-1.1.0.tgz", "integrity": "sha512-SrYE/AWLqYgqE9FXmnbyPvYGB60Z+mDn+UuKzTcma2ZLEtyzVs8qiKAkZYFPa3M4Z5zsESLFm8kDllSbrMeD2A==" }, + "node_modules/@hotwired/stimulus": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@hotwired/stimulus/-/stimulus-3.2.2.tgz", + "integrity": "sha512-eGeIqNOQpXoPAIP7tC1+1Yc1yl1xnwYqg+3mzqxyrbE5pg5YFBZcA6YoTiByJB6DKAEsiWtl6tjTJS4IYtbB7A==", + "dev": true, + "license": "MIT" + }, "node_modules/@interactjs/types": { "version": "1.10.17", "resolved": "https://registry.npmjs.org/@interactjs/types/-/types-1.10.17.tgz", @@ -8221,6 +8231,12 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" }, + "node_modules/node-snackbar": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/node-snackbar/-/node-snackbar-0.1.16.tgz", + "integrity": "sha512-3s43QMKgABXdnqUfpKAXG+WlvS8bbuO6n6LAOmmLNZs87CGdpexqfGYCktFVi9NHFgREwNJARgeVTLOFAf2MQg==", + "license": "MIT" + }, "node_modules/node-waves": { "version": "0.7.6", "resolved": "https://registry.npmjs.org/node-waves/-/node-waves-0.7.6.tgz", @@ -10961,6 +10977,13 @@ "node": ">= 0.6" } }, + "node_modules/typed.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/typed.js/-/typed.js-2.1.0.tgz", + "integrity": "sha512-bDuXEf7YcaKN4g08NMTUM6G90XU25CK3bh6U0THC/Mod/QPKlEt9g/EjvbYB8x2Qwr2p6J6I3NrsoYaVnY6wsQ==", + "dev": true, + "license": "MIT" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -11911,6 +11934,20 @@ "optional": false } } + }, + "vendor/symfony/ux-typed/assets": { + "name": "@symfony/ux-typed", + "version": "2.23.0", + "extraneous": true, + "license": "MIT", + "devDependencies": { + "@hotwired/stimulus": "^3.0.0", + "typed.js": "^2.0" + }, + "peerDependencies": { + "@hotwired/stimulus": "^3.0.0", + "typed.js": "^2.0" + } } } } diff --git a/package.json b/package.json index 2f5ec45d2..cccc28e54 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "devDependencies": { "@babel/plugin-proposal-class-properties": "^7.18.6", + "@hotwired/stimulus": "^3.0.0", "@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets", "@symfony/webpack-encore": "^4.0.0", "chromedriver": "^105.0.0", @@ -10,6 +11,7 @@ "regenerator-runtime": "^0.13.7", "sass-loader": "^13.0.0", "socket.io-client": "^4.6.1", + "typed.js": "^2.0", "webpack-notifier": "^1.12.0" }, "license": "UNLICENSED", @@ -46,7 +48,7 @@ "file-loader": "^6.2.0", "flatpickr": "^4.6.9", "fs": "^0.0.1-security", - "h2-invent-apps": "^2.4.0", + "h2-invent-apps": "^2.5.0", "h2-invent-material-tabs": "^1.10.0", "hotkeys-js": "^3.9.4", "interactjs": "^1.10.17", @@ -58,6 +60,7 @@ "moment": "^2.29.1", "moveable": "^0.36.3", "net": "^1.0.2", + "node-snackbar": "^0.1.16", "node-waves": "^0.7.6", "popper.js": "^1.16.1", "pretty-print-json": "^1.3.1", diff --git a/pl/translations/ux_message+intl-icu.pl.yaml b/pl/translations/ux_message+intl-icu.pl.yaml deleted file mode 100644 index 528f21766..000000000 --- a/pl/translations/ux_message+intl-icu.pl.yaml +++ /dev/null @@ -1 +0,0 @@ -email_send_invitation: Einladung wurde erfolgreich an {email} versendet. diff --git a/pt-BR/translations/ux_message+intl-icu.pt.yaml b/pt-BR/translations/ux_message+intl-icu.pt.yaml deleted file mode 100644 index 528f21766..000000000 --- a/pt-BR/translations/ux_message+intl-icu.pt.yaml +++ /dev/null @@ -1 +0,0 @@ -email_send_invitation: Einladung wurde erfolgreich an {email} versendet. diff --git a/public/notification.json b/public/notification.json index b4e1611db..5c468cb28 100644 --- a/public/notification.json +++ b/public/notification.json @@ -1,6 +1,7 @@ [ {"text": "Auf Grund eines Server Updates steht der PantherAdmin am kommenden Freitag 19.07.2024 ab 13 Uhr nicht zur Verfügung", "head": "PantherAdmin Wartungsarbeiten", - "type": "info" + "type": "info", + "identifier": "pantherupdate" } ] \ No newline at end of file diff --git a/ro/translations/ux_message+intl-icu.ro.yaml b/ro/translations/ux_message+intl-icu.ro.yaml deleted file mode 100644 index 528f21766..000000000 --- a/ro/translations/ux_message+intl-icu.ro.yaml +++ /dev/null @@ -1 +0,0 @@ -email_send_invitation: Einladung wurde erfolgreich an {email} versendet. diff --git a/ru/translations/ux_message+intl-icu.ru.yaml b/ru/translations/ux_message+intl-icu.ru.yaml deleted file mode 100644 index 528f21766..000000000 --- a/ru/translations/ux_message+intl-icu.ru.yaml +++ /dev/null @@ -1 +0,0 @@ -email_send_invitation: Einladung wurde erfolgreich an {email} versendet. diff --git a/src/Controller/DashboardController.php b/src/Controller/DashboardController.php index f996a5cb1..bcea5870e 100644 --- a/src/Controller/DashboardController.php +++ b/src/Controller/DashboardController.php @@ -79,6 +79,7 @@ public function dashboard( ], ); } + $roomsFuture = $this->doctrine->getRepository(Rooms::class)->findRoomsInFuture($this->getUser()); $r = []; @@ -180,6 +181,14 @@ public function dashboard( } + $res->headers->setCookie( + Cookie::create( + 'is_loggedIn_user', + 1, + time() + (2 * 365 * 24 * 60 * 60), + '/', // Path. + ) + ); return $res; } diff --git a/src/Controller/OwnRoomController.php b/src/Controller/OwnRoomController.php index e9486d7e4..420a63f06 100644 --- a/src/Controller/OwnRoomController.php +++ b/src/Controller/OwnRoomController.php @@ -27,13 +27,16 @@ class OwnRoomController extends JitsiAdminController { #[Route(path: '/myRoom/start/{uid}', name: 'own_room_startPage')] + #[Route(path: '/room/myRoom/start/{uid}', name: 'own_room_startPage_protected')] public function index($uid, Request $request, RoomService $roomService, TranslatorInterface $translator, StartMeetingService $startMeetingService): Response { + $session = $request->getSession(); $rooms = $this->doctrine->getRepository(Rooms::class)->findOneBy(['uid' => $uid, 'totalOpenRooms' => true]); if (!$rooms) { $this->addFlash('danger', $translator->trans('Konferenz nicht gefunden. Zugangsdaten erneut eingeben')); return $this->redirectToRoute('join_index_no_slug'); } + if (!StartMeetingService::checkTime($rooms)) { $startPrint = $rooms->getTimeZone() ? clone ($rooms->getStartUtc())->setTimeZone(new \DateTimeZone($rooms->getTimeZone())) : $rooms->getStart(); $startPrint->modify('-30min'); @@ -51,7 +54,19 @@ public function index($uid, Request $request, RoomService $roomService, Translat } $data = []; + if (!$this->getUser() && $request->cookies->get('is_loggedIn_user')== 1) { // the user was logged in the past, so we send him to the login page + + if ($session->get('login_attempted')) {// second try + $session->remove('login_attempted'); // Zurücksetzen + $response = $this->redirectToRoute('own_room_startPage',['uid' => $rooms->getUid()]); + $response->headers->clearCookie('is_loggedIn_user'); + return $response; + } + $session->set('login_attempted', true); + return $this->redirectToRoute('own_room_startPage_protected',['uid' => $rooms->getUid()]); + } if ($this->getUser()) { + $session->remove('login_attempted'); // Zurücksetzen $data['name'] = $this->getUser()->getFirstName() . ' ' . $this->getUser()->getLastName(); } elseif ($request->get('name')) { $data['name'] = base64_decode($request->get('name')); diff --git a/src/Controller/PublicConferenceController.php b/src/Controller/PublicConferenceController.php index 08aa6855f..410405abc 100644 --- a/src/Controller/PublicConferenceController.php +++ b/src/Controller/PublicConferenceController.php @@ -50,10 +50,14 @@ public function index(Request $request): Response return $this->redirectToRoute('dashboard'); } $data = [ - 'roomName' => UtilsHelper::readable_random_string(20), + 'server'=>$this->server, + 'roomName' => UtilsHelper::readable_random_string(5), 'myName'=> $this->requestStack->getSession()->get('myName')?:'' ]; $form = $this->createForm(PublicConferenceType::class, $data); + if ($this->server->isLiveKitServer()){ + $form->remove('myName'); + } $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $data = $form->getData(); diff --git a/src/Controller/TestNotificationController.php b/src/Controller/TestNotificationController.php new file mode 100644 index 000000000..d334bafff --- /dev/null +++ b/src/Controller/TestNotificationController.php @@ -0,0 +1,102 @@ +getUser(); + $topic = 'personal/' . $user->getUid(); + echo 'set user topic: ' . $topic . '
'; + flush(); + + $this->directSendService->sendSnackbar($topic, 'test Snackbar', 'red', 5000); + echo 'send snackbar
'; + flush(); + sleep(5); + + $this->directSendService->sendBrowserNotification( + $topic, + 'test Title', + "I'm a test message title", + "I'm a push message text", + '0x23', + 'red', + 5000 + ); + echo 'send browser notification
'; + flush(); + sleep(5); + + $this->directSendService->sendDialog($topic, 'dialog header', "I'm a test dialog body.", "do you want to accept this dialog?", [ + [ + 'class' => 'testclass', + 'text' => 'test button text', + 'link' => 'testlink', + 'data' => ['roomname' => 'test'], + ], + [ + 'class' => 'btn btn-danger', + 'text' => '', + 'data' => [], + ], + ]); + echo 'send dialog
'; + flush(); + sleep(5); + + $this->directSendService->sendBrowserPush($topic, 'test message for push', 'test pushmessage', '123'); + echo 'send browser push
'; + flush(); + sleep(5); + $this->directSendService->sendCleanBrowserNotification($topic, 123); + echo 'remove browser push message
'; + flush(); + sleep(1); + $this->directSendService->sendMessage($topic, 'test message', 'testuser'); + echo 'send message
'; + flush(); + sleep(5); + $this->directSendService->sendRefreshDashboard($topic); + echo 'refresh dashboard
'; + flush(); + sleep(15); + $this->directSendService->sendModal($topic, '

test html modal

'); + echo 'send modal
'; + flush(); + sleep(5); + $this->directSendService->sendRedirect($topic,'room/dashboard'); + echo 'redirect to room dashboard
'; + flush(); + sleep(15); + $this->directSendService->sendPlaySound($topic, 'caller', '123'); + echo 'send caller sound
'; + flush(); + sleep(2); + echo 'Fertig.
'; + flush(); + }); + } +} diff --git a/src/Controller/UploadThemeController.php b/src/Controller/UploadThemeController.php index ad6436992..bc131f4eb 100644 --- a/src/Controller/UploadThemeController.php +++ b/src/Controller/UploadThemeController.php @@ -114,6 +114,47 @@ public function save(Request $request): Response return $this->redirectToRoute('app_upload_theme_form'); } + private function processTheme(string $themeFilePath): void + { + $path = $this->CACHE_DIR . md5(uniqid()); + $zip = new \ZipArchive(); + + if ($zip->open($themeFilePath) !== true) { + throw new \RuntimeException('Unable to open the zip file'); + } + + $zip->extractTo($path); + $zip->close(); + + $finder = new Finder(); + $finder->files()->in($path)->name('*.json.signed'); + + if ($finder->count() !== 1) { + throw new \RuntimeException('No valid theme file found in the zip'); + } + + $items = iterator_to_array($finder); + $themePath = reset($items)->getRealPath(); + + if (!$themePath) { + throw new \RuntimeException('Unable to read theme file'); + } + + $themeContent = file_get_contents($themePath); + $validSignature = $this->checkSignature->verifySignature($themeContent); + + if (!$validSignature) { + throw new \RuntimeException('Invalid theme signature'); + } + + $this->moveTheme($themePath, $path); + + $filesystem = new Filesystem(); + $filesystem->remove($path); + + $this->cacheItemPool->clear(); + } + private function moveTheme($themePath, $path) { $filesystem = new Filesystem(); diff --git a/src/EventListener/CorsHeaderListener.php b/src/EventListener/CorsHeaderListener.php new file mode 100644 index 000000000..fa41e712c --- /dev/null +++ b/src/EventListener/CorsHeaderListener.php @@ -0,0 +1,24 @@ +getRequest(); + $response = $event->getResponse(); + + // Nur auf bestimmte Pfade beschränken, z. B. /theme/ + $path = $request->getPathInfo(); + + // Beispiel: Alle .jpg-Dateien im /theme/-Ordner + if (preg_match('#^/uploads/.*\.*$#', $path)) { + $response->headers->set('Access-Control-Allow-Origin', '*'); + } + } +} diff --git a/src/EventListener/OAuthRedirectListener.php b/src/EventListener/OAuthRedirectListener.php new file mode 100644 index 000000000..928e2ae55 --- /dev/null +++ b/src/EventListener/OAuthRedirectListener.php @@ -0,0 +1,41 @@ +getRequest(); + $route = $request->attributes->get('_route'); + + // Nur für bestimmte Pfade aktiv (z. B. beginnt mit /myRoom/start/) + $path = $request->getPathInfo(); + if (!str_starts_with($path, '/myRoom/start/')) { + return; + } + + $cookie = $request->cookies->get('was_logged_in'); + + if ($cookie === '1' && !$request->getSession()->has('oauth_authenticated')) { + // Aktuelle URL merken für Rückleitung + $this->session->set('target_path', $request->getUri()); + + // Weiterleitung zu Keycloak Login + $redirectUrl = $this->router->generate('connect_keycloak_start'); + + $event->setResponse(new RedirectResponse($redirectUrl)); + } + } + +} \ No newline at end of file diff --git a/src/Form/CalendlyTokenType.php b/src/Form/CalendlyTokenType.php index 92006ca57..b9890818b 100644 --- a/src/Form/CalendlyTokenType.php +++ b/src/Form/CalendlyTokenType.php @@ -35,7 +35,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'required' => true, ] ) - ->add('calendly_token', TextareaType::class, ['attr' => ['placeholder' => 'label.calendlyToken'], 'label' => false, 'required' => true, 'translation_domain' => 'form']) + ->add('calendly_token', TextareaType::class, ['attr' => ['placeholder' => 'label.calendlyToken'], 'label' => 'label.calendlyToken', 'required' => true, 'translation_domain' => 'form']) ->add('submit', SubmitType::class, ['attr' => ['class' => 'btn btn-primary'], 'label' => 'label.speichern', 'translation_domain' => 'form']);; } diff --git a/src/Form/Type/AddressGroupType.php b/src/Form/Type/AddressGroupType.php index e76caccc6..609e6936e 100644 --- a/src/Form/Type/AddressGroupType.php +++ b/src/Form/Type/AddressGroupType.php @@ -35,7 +35,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) $user = $options['user']; $builder - ->add('name', TextType::class, ['attr' => ['placeholder' => 'label.addressgroupName'], 'label' => false, 'required' => true, 'translation_domain' => 'form']) + ->add('name', TextType::class, ['attr' => ['placeholder' => 'label.addressgroupName'], 'label' => 'label.addressgroupName', 'required' => true, 'translation_domain' => 'form']) ->add( 'member', UserLineType::class, diff --git a/src/Form/Type/JoinMyRoomType.php b/src/Form/Type/JoinMyRoomType.php index 91f656d8e..812494b4d 100644 --- a/src/Form/Type/JoinMyRoomType.php +++ b/src/Form/Type/JoinMyRoomType.php @@ -31,7 +31,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('name', TextType::class, ['attr' => ['placeholder' => 'label.name'], 'label' => false, 'required' => true, 'translation_domain' => 'form']); + ->add('name', TextType::class, ['attr' => ['placeholder' => 'label.name'], 'label' => 'label.name', 'required' => true, 'translation_domain' => 'form']); if ($this->themeService->getApplicationProperties('start_dropdown_allow_browser')) { $builder->add('joinBrowser', SubmitType::class, ['attr' => ['class' => 'btn btn-primary btn-block '], 'label' => 'label.beitretenBrowser', 'translation_domain' => 'form']); diff --git a/src/Form/Type/JoinViewType.php b/src/Form/Type/JoinViewType.php index 1c573eba4..6be949d71 100644 --- a/src/Form/Type/JoinViewType.php +++ b/src/Form/Type/JoinViewType.php @@ -31,9 +31,9 @@ public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('uid', TextType::class, ['attr' => ['placeholder' => 'label.konferenzId'], 'label' => false, 'required' => true, 'translation_domain' => 'form']) - ->add('email', TextType::class, ['attr' => ['placeholder' => 'label.email'], 'label' => false, 'required' => true, 'translation_domain' => 'form']) - ->add('name', TextType::class, ['attr' => ['placeholder' => 'label.name'], 'label' => false, 'required' => true, 'translation_domain' => 'form']); + ->add('uid', TextType::class, ['attr' => ['placeholder' => 'label.konferenzId'], 'label' => 'label.konferenzId', 'required' => true, 'translation_domain' => 'form']) + ->add('email', TextType::class, ['attr' => ['placeholder' => 'label.email'], 'label' => 'label.email', 'required' => true, 'translation_domain' => 'form']) + ->add('name', TextType::class, ['attr' => ['placeholder' => 'label.name'], 'label' => 'label.name', 'required' => true, 'translation_domain' => 'form']); if ($this->themeService->getApplicationProperties('start_dropdown_allow_browser')) { $builder->add('joinBrowser', SubmitType::class, ['attr' => ['class' => 'btn btn-primary btn-block '], 'label' => 'label.beitretenBrowser', 'translation_domain' => 'form']); } diff --git a/src/Form/Type/PublicConferenceType.php b/src/Form/Type/PublicConferenceType.php index 742e3d871..e141f646c 100644 --- a/src/Form/Type/PublicConferenceType.php +++ b/src/Form/Type/PublicConferenceType.php @@ -24,9 +24,10 @@ class PublicConferenceType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { + $builder - ->add('myName', TextType::class, ['attr' => ['placeholder' => 'label.myName'], 'label' => false, 'required' => true, 'translation_domain' => 'form']) - ->add('roomName', TextType::class, ['attr' => ['class' => 'mt-3','placeholder' => 'label.konferenzName'], 'label' => false, 'required' => true, 'translation_domain' => 'form']) + ->add('myName', TextType::class, ['attr' => ['placeholder' => 'label.myName'], 'label' => 'label.myName', 'required' => true, 'translation_domain' => 'form']) + ->add('roomName', TextType::class, ['attr' => ['class' => 'mt-3','placeholder' => 'label.konferenzName'], 'label' => 'label.konferenzName', 'required' => true, 'translation_domain' => 'form']) ->add('submit', SubmitType::class, array('attr' => array('class' => 'btn btn-outline-primary btn-block mt-3'), 'label' => 'label.go', 'translation_domain' => 'form'),); } diff --git a/src/Form/Type/PublicRegisterType.php b/src/Form/Type/PublicRegisterType.php index 9298a9802..635a61ce6 100644 --- a/src/Form/Type/PublicRegisterType.php +++ b/src/Form/Type/PublicRegisterType.php @@ -22,9 +22,9 @@ public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('firstName', TextType::class, ['attr' => ['placeholder' => 'label.vorname'], 'label' => false, 'required' => true, 'translation_domain' => 'form']) - ->add('lastName', TextType::class, ['attr' => ['placeholder' => 'label.nachname'], 'label' => false, 'required' => true, 'translation_domain' => 'form']) - ->add('email', TextType::class, ['attr' => ['placeholder' => 'label.email'], 'label' => false, 'required' => true, 'translation_domain' => 'form']) + ->add('firstName', TextType::class, ['attr' => ['placeholder' => 'label.vorname'], 'label' => 'label.vorname', 'required' => true, 'translation_domain' => 'form']) + ->add('lastName', TextType::class, ['attr' => ['placeholder' => 'label.nachname'], 'label' => 'label.nachname', 'required' => true, 'translation_domain' => 'form']) + ->add('email', TextType::class, ['attr' => ['placeholder' => 'label.email'], 'label' => 'label.email', 'required' => true, 'translation_domain' => 'form']) ->add('subscribe', SubmitType::class, ['attr' => ['class' => 'btn btn-primary btn-block '], 'label' => 'label.subscribe', 'translation_domain' => 'form']); } diff --git a/src/Form/Type/RepeaterType.php b/src/Form/Type/RepeaterType.php index eaa320186..a52516552 100644 --- a/src/Form/Type/RepeaterType.php +++ b/src/Form/Type/RepeaterType.php @@ -61,10 +61,10 @@ public function buildForm(FormBuilderInterface $builder, array $options) // 'multiple' => true, // 'translation_domain' => 'form' // ]) - ->add('repeaterDays', NumberType::class, ['label' => false, 'required' => false, 'attr' => ['placeholder' => 'label.repeaterDays'], 'translation_domain' => 'form']) - ->add('repeaterWeeks', NumberType::class, ['label' => false, 'required' => false, 'attr' => ['placeholder' => 'label.repeaterWeeks'], 'translation_domain' => 'form']) - ->add('repeatMontly', NumberType::class, ['label' => false, 'required' => false, 'attr' => ['placeholder' => 'label.repeatMontly'], 'translation_domain' => 'form']) - ->add('repeatYearly', NumberType::class, ['label' => false, 'required' => false, 'attr' => ['placeholder' => 'label.repeatYearly'], 'translation_domain' => 'form']) + ->add('repeaterDays', NumberType::class, ['label' => 'label.repeaterDays', 'required' => false, 'attr' => ['placeholder' => 'label.repeaterDays'], 'translation_domain' => 'form']) + ->add('repeaterWeeks', NumberType::class, ['label' => 'label.repeaterWeeks', 'required' => false, 'attr' => ['placeholder' => 'label.repeaterWeeks'], 'translation_domain' => 'form']) + ->add('repeatMontly', NumberType::class, ['label' => 'label.repeatMontly', 'required' => false, 'attr' => ['placeholder' => 'label.repeatMontly'], 'translation_domain' => 'form']) + ->add('repeatYearly', NumberType::class, ['label' => 'label.repeatYearly', 'required' => false, 'attr' => ['placeholder' => 'label.repeatYearly'], 'translation_domain' => 'form']) ->add( 'repatMonthRelativNumber', ChoiceType::class, @@ -95,7 +95,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'label' => 'label.montlyRelativeWeekday', 'translation_domain' => 'form'] ) - ->add('repeatMonthlyRelativeHowOften', NumberType::class, ['label' => false, 'required' => false, 'attr' => ['placeholder' => 'label.repeatMontly'], 'translation_domain' => 'form']) + ->add('repeatMonthlyRelativeHowOften', NumberType::class, ['label' => 'label.repeatMontly', 'required' => false, 'attr' => ['placeholder' => 'label.repeatMontly'], 'translation_domain' => 'form']) ->add( 'repeatYearlyRelativeNumber', ChoiceType::class, @@ -147,8 +147,8 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'label' => 'label.montlyRelativeMonth', 'translation_domain' => 'form'] ) - ->add('repeatYearlyRelativeHowOften', NumberType::class, ['label' => false, 'required' => false, 'attr' => ['placeholder' => 'label.repeatYearly'], 'translation_domain' => 'form']) - ->add('repetation', NumberType::class, ['label' => false, 'required' => true, 'attr' => ['placeholder' => 'label.repetation'], 'translation_domain' => 'form']) + ->add('repeatYearlyRelativeHowOften', NumberType::class, ['label' => 'label.repeatYearly', 'required' => false, 'attr' => ['placeholder' => 'label.repeatYearly'], 'translation_domain' => 'form']) + ->add('repetation', NumberType::class, ['label' => 'label.repetation', 'required' => true, 'attr' => ['placeholder' => 'label.repetation'], 'translation_domain' => 'form']) ->add('submit', SubmitType::class, ['attr' => ['class' => 'btn btn-outline-primary'], 'label' => 'label.speichern', 'translation_domain' => 'form']); } diff --git a/src/Service/Lobby/DirectSendService.php b/src/Service/Lobby/DirectSendService.php index c58241bd6..fddc9fcbd 100644 --- a/src/Service/Lobby/DirectSendService.php +++ b/src/Service/Lobby/DirectSendService.php @@ -62,6 +62,21 @@ public function sendSnackbar($topic, $text, $color, $closeAfterMs = null) return $this->publisher->publish($update); } + public function sendDialog($topic, $header, $text, $type='question', $buttons=[]) + { + $data = [ + 'type' => 'dialog', + 'header' => $header, + 'text' => $text, + 'buttons' => $buttons, + 'dialogType' => $type + + ]; + + $update = new Update($topic, json_encode($data)); + return $this->publisher->publish($update); + } + public function sendMessage($topic, $message, string $from) { $data = [ @@ -100,6 +115,27 @@ public function sendBrowserNotification($topic, $title, $message, $pushMessage, return $this->publisher->publish($update); } + public function sendBrowserPush($topic, $title, $pushMessage, $id) + { + $data = [ + 'type' => 'browserPush', + 'title' => $title, + 'pushNotification' => $pushMessage, + 'messageId' => $id, + ]; + $update = new Update($topic, json_encode($data)); + return $this->publisher->publish($update); + } + public function sendPlaySound($topic, $soundName, $id) + { + $data = [ + 'type' => 'playSound', + 'soundName' => $soundName, + 'messageId' => $id, + ]; + $update = new Update($topic, json_encode($data)); + return $this->publisher->publish($update); + } public function sendCleanBrowserNotification($topic, $id) { $data = [ diff --git a/src/Service/Lobby/ToParticipantWebsocketService.php b/src/Service/Lobby/ToParticipantWebsocketService.php index 3e9626a7a..87b67887e 100644 --- a/src/Service/Lobby/ToParticipantWebsocketService.php +++ b/src/Service/Lobby/ToParticipantWebsocketService.php @@ -99,6 +99,7 @@ public function sendDecline(LobbyWaitungUser $lobbyWaitungUser) public function sendMessage(LobbyWaitungUser $lobbyWaitungUser, $message, string $from) { $topic = 'lobby_WaitingUser_websocket/' . $lobbyWaitungUser->getUid(); - $this->directSend->sendMessage($topic, $message, $from); + $this->directSend->sendSnackbar($topic,$message,'red',10000); + } } diff --git a/src/Service/RoomService.php b/src/Service/RoomService.php index f50e02c21..b3eb09a11 100644 --- a/src/Service/RoomService.php +++ b/src/Service/RoomService.php @@ -172,6 +172,10 @@ function genereateJwtPayload($userName, Rooms $room, Server $server, $moderator, "sub" => $room->getServer()->getUrl(), "room" => $roomName, "context" => [ + 'room'=>[ + 'name'=>$room->getName() + + ], 'user' => [ 'name' => $userName, @@ -191,7 +195,17 @@ function genereateJwtPayload($userName, Rooms $room, Server $server, $moderator, if ($userName === 'Meetling' && $server->isLiveKitServer()){ $payload['context']['user']['name'] = ''; } + if ($server->getJigasiNumberUrl()){ + try { + $dialInNumbers = json_decode($server->getJigasiNumberUrl(),true); + $payload['context']['room']['dialIn']['numbers']=$dialInNumbers['numbers']; + $payload['context']['room']['dialIn']['pin']=$room->getCallerRoom()->getCallerId(); + }catch (\Exception $exception){ + $this->logger->error($exception->getMessage()); + } + + } if ($server->isLiveKitServer()) { try { $encSecret = $this->generateEncryptedSecret($server); diff --git a/src/Service/adhocmeeting/AdhocMeetingWebsocketService.php b/src/Service/adhocmeeting/AdhocMeetingWebsocketService.php index 8d15396e8..e4343ba23 100644 --- a/src/Service/adhocmeeting/AdhocMeetingWebsocketService.php +++ b/src/Service/adhocmeeting/AdhocMeetingWebsocketService.php @@ -14,35 +14,67 @@ class AdhocMeetingWebsocketService { public function __construct( - private ParameterBagInterface $parameterBag, - private TranslatorInterface $translator, - private DirectSendService $directSendService, - private UrlGeneratorInterface $urlGen, - private ThemeService $theme, + private ParameterBagInterface $parameterBag, + private TranslatorInterface $translator, + private DirectSendService $directSendService, + private UrlGeneratorInterface $urlGen, + private ThemeService $theme, ) { } - +//todo umbau auf dialog kein toast mehr public function sendAddhocMeetingWebsocket(User $reciever, User $creator, Rooms $room): void { $topic = 'personal/' . $reciever->getUid(); - $format = '%s
%s '; - $toastText = sprintf( - $format, - $this->translator->trans('addhock.notification.pushMessage', ['{name}' => $creator->getFormatedName($this->parameterBag->get('laf_showName'))]), - $this->urlGen->generate('room_join', ['room' => $room->getId(), 't' => 'b']), - $room->getSecondaryName() ?: $room->getName(), - $this->translator->trans('Hier beitreten'), + $header = $this->translator->trans('addhock.notification.title'); + $text = $this->translator->trans('addhock.notification.pushMessage', ['{name}' => $creator->getFormatedName($this->parameterBag->get('laf_showName'))]); + $dialogType = 'question'; + $button = [ + [ + 'class' => 'btn btn-success ' . ($this->theme->getApplicationProperties('LAF_USE_MULTIFRAME') == 1 ? 'startIframe' : ''), + 'text' => ' ' . $this->translator->trans('Hier beitreten'), + 'link' => $this->urlGen->generate('room_join', ['room' => $room->getId(), 't' => 'b']), + 'data' => + [ + 'roomname' => $room->getSecondaryName() ?: $room->getName() + ] + ], + [ + 'class' => 'btn btn-danger ', + 'text' => ' ', + 'data' => [], + ] + ]; + +// $format = '%s +//
%s '; +// $toastText = sprintf( +// $format, +// $this->translator->trans('addhock.notification.pushMessage', ['{name}' => $creator->getFormatedName($this->parameterBag->get('laf_showName'))]), +// $this->urlGen->generate('room_join', ['room' => $room->getId(), 't' => 'b']), +// $room->getSecondaryName() ?: $room->getName(), +// $this->translator->trans('Hier beitreten'), +// ); + $this->directSendService->sendDialog( + $topic, + $header, + $text, + $dialogType, + $button ); - $this->directSendService->sendCallAdhockmeeding( - $this->translator->trans('addhock.notification.title'), + $this->directSendService->sendBrowserPush( + $topic, + $header, + $text, + md5(uniqid()) + ); + + $this->directSendService->sendPlaySound( $topic, - $toastText, - $this->translator->trans('addhock.notification.pushMessage', ['{name}' => $creator->getFormatedName($this->parameterBag->get('laf_showName'))]), - 60000, - $room->getUid() + 'caller', + md5(uniqid()) ); } } diff --git a/src/Service/api/ConferenceMapperService.php b/src/Service/api/ConferenceMapperService.php index d7844dcbf..aba43dd74 100644 --- a/src/Service/api/ConferenceMapperService.php +++ b/src/Service/api/ConferenceMapperService.php @@ -62,8 +62,11 @@ public function checkConference(?CallerRoom $callerRoom, $apiKey, $callerId) ]; } } + $user = null; + if ($callerId){ + $user = $this->findNameFromCallerId(callerId: $callerId); + } - $user = $this->findNameFromCallerId(callerId: $callerId); $res = [ 'state' => 'STARTED', diff --git a/src/Service/api/EventSyncApiService.php b/src/Service/api/EventSyncApiService.php index cbc3f9017..a2862b08c 100644 --- a/src/Service/api/EventSyncApiService.php +++ b/src/Service/api/EventSyncApiService.php @@ -18,7 +18,7 @@ public function getCallerSessionFromUid(string $uid):array if ($roomStatus){ return ['status'=>'ROOM_STARTED']; }else{ - return ['status'=>'ROOOM_CLOSED']; + return ['status'=>'ROOM_CLOSED']; } } } \ No newline at end of file diff --git a/src/Service/ldap/LdapUserService.php b/src/Service/ldap/LdapUserService.php index a0ce8f337..2b3bb06d4 100644 --- a/src/Service/ldap/LdapUserService.php +++ b/src/Service/ldap/LdapUserService.php @@ -58,10 +58,14 @@ public function retrieveUserfromDatabasefromUserNameAttribute(Entry $entry, Ldap $user->setLdapUserProperties($ldap); $user->getLdapUserProperties()->setLdapNumber($ldapType->getSerVerId()); } - - if ($ldapType->getRdn()) { - $user->getLdapUserProperties()->setRdn($ldapType->getRdn() . '=' . $entry->getAttribute($ldapType->getRdn())[0]); + try { + if ($ldapType->getRdn()) { + $user->getLdapUserProperties()->setRdn($ldapType->getRdn() . '=' . $entry->getAttribute($ldapType->getRdn())[0]); + } + }catch (\Exception $exception){ + $this->logger->error($exception->getMessage()); } + $specialField = $this->getSpezialPropertiesFields(ldapType: $ldapType, entry: $entry); $user->setSpezialProperties($specialField); diff --git a/src/Service/livekit/SipTrunkGenerator.php b/src/Service/livekit/SipTrunkGenerator.php index d2f4d193f..c0920d86b 100644 --- a/src/Service/livekit/SipTrunkGenerator.php +++ b/src/Service/livekit/SipTrunkGenerator.php @@ -78,6 +78,10 @@ public function generateSipTrunk(Server $server, Rooms $rooms, $callerId) 'name' => $this->livekitRoomNameGenerator->getLiveKitName($rooms), 'numbers' => [ $this->sipTrunkNumber + ], + 'include_headers'=>1, + 'headers_to_attributes'=>[ + 'X-' ] ] ]; diff --git a/src/Service/webhook/RoomWebhookService.php b/src/Service/webhook/RoomWebhookService.php index c05c557f1..099da6df2 100644 --- a/src/Service/webhook/RoomWebhookService.php +++ b/src/Service/webhook/RoomWebhookService.php @@ -45,34 +45,34 @@ public function startWebhook($data): ?string case 'muc-room-created': $res = $this->roomCreated( $data['room_name'], - $data['is_breakout'], - isset($data['breakout_room_id']) ? $data['breakout_room_id'] : null, + $data['is_breakout']??null, + $data['breakout_room_id'] ?? null, $data['room_jid'], $data['created_at'] ); break; case 'muc-room-destroyed': $res = $this->roomDestroyed( - $data['is_breakout'], - isset($data['breakout_room_id']) ? $data['breakout_room_id'] : null, + $data['is_breakout']??null, + $data['breakout_room_id'] ?? null, $data['room_jid'], $data['destroyed_at'] ); break; case 'muc-occupant-joined': $res = $this->roomParticipantJoin( - $data['is_breakout'], - isset($data['breakout_room_id']) ? $data['breakout_room_id'] : null, + $data['is_breakout']??null, + $data['breakout_room_id'] ?? null, $data['room_jid'], $data['occupant']['occupant_jid'], $data['occupant']['joined_at'], - isset($data['occupant']['name']) ? $data['occupant']['name'] : null + $data['occupant']['name'] ?? null ); break; case 'muc-occupant-left': $res = $this->roomParticipantLeft( - $data['is_breakout'], + $data['is_breakout']??null, $data['breakout_room_id'] ?? null, $data['occupant']['occupant_jid'], $data['occupant']['left_at'], @@ -90,7 +90,7 @@ public function startWebhook($data): ?string public function roomCreated( string $roomName, - bool $isBreakout, + ?bool $isBreakout, ?string $breakoutRoomId, string $roomJid, int $createdAt @@ -152,7 +152,7 @@ public function roomCreated( public function roomDestroyed( - bool $isBreakout, + ?bool $isBreakout, ?string $breakoutRoomId, string $roomJid, int $destroyedAt @@ -224,7 +224,7 @@ public function roomDestroyed( } public function roomParticipantJoin( - ?bool $isBreakput, + ?bool $isBreakout, ?string $breakoutRoomName, string $roomJId, string $occupantJId, @@ -234,7 +234,7 @@ public function roomParticipantJoin( { try { - if ($isBreakput === true) { + if ($isBreakout === true) { $this->logger->debug('This is a breakoutRoom', ['breakout_room_id ' => $breakoutRoomName, 'room_jid' => $roomJId]); return 'Room is a breakout room we don`t join the participant'; } @@ -274,7 +274,7 @@ public function roomParticipantJoin( public function roomParticipantLeft( - bool $isBreakout, + ?bool $isBreakout, ?string $breakoutRoomId, string $occupantJid, int $leftAt, @@ -315,7 +315,7 @@ public function roomParticipantLeft( return null; } - public function clenRoomStatus(RoomStatus $roomStatus) + public function clenRoomStatus(RoomStatus $roomStatus): void { if (!$roomStatus->getRoom()) { foreach ($roomStatus->getRoomStatusParticipants() as $data) { diff --git a/src/UtilsHelper.php b/src/UtilsHelper.php index 4b542fdc2..73a5d438d 100644 --- a/src/UtilsHelper.php +++ b/src/UtilsHelper.php @@ -25,20 +25,87 @@ public static function slugifywithDot($urlString) public static function readable_random_string($length = 6) { - $string = ''; - $vowels = array("a", "e", "i", "o", "u"); - $consonants = array( - 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', - 'n', 'p', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z' - ); - - $max = $length / 2; - for ($i = 1; $i <= $max; $i++) { - $string .= $consonants[rand(0, 19)]; - $string .= $vowels[rand(0, 4)]; - } - - return $string; + $nouns = [ + 'cat', 'dog', 'robot', 'moon', 'tree', 'fish', 'flower', 'cloud', 'book', 'child', + 'star', 'mountain', 'river', 'stone', 'ocean', 'leaf', 'sun', 'window', 'dream', 'car', + 'ghost', 'house', 'hat', 'bottle', 'field', 'forest', 'shoe', 'mirror', 'sky', 'train', + 'music', 'door', 'chair', 'phone', 'apple', 'banana', 'monster', 'lamp', 'table', 'dragon', + 'storm', 'road', 'tiger', 'pencil', 'beach', 'pirate', 'camera', 'castle', 'guitar', 'keyboard', + 'socks', 'tunnel', 'planet', 'rabbit', 'wizard', 'balloon', 'shadow', 'message', 'engine', 'helicopter', + 'plane', 'ball', 'basket', 'clock', 'toaster', 'engineer', 'rocket', 'helmet', 'card', 'potion', + 'map', 'snowflake', 'arrow', 'cup', 'flame', 'ladder', 'cookie', 'cave', 'fire', 'whale', + 'feather', 'bubble', 'coin', 'circle', 'paint', 'sign', 'rope', 'suitcase', 'ship', 'lantern', + 'flag', 'wall', 'gem', 'quill', 'net', 'bridge', 'crown', 'bookcase', 'bell', 'breeze', + 'sandwich', 'telescope', 'owl', 'raven', 'duck', 'flock', 'nest', 'branch', 'seed', 'root', + 'note', 'flute', 'violin', 'portal', 'gate', 'key', 'lock', 'nail', 'glove', 'hammer', + 'brush', 'shell', 'chessboard', 'candle', 'box', 'tower', 'island', 'wave', 'glow', 'bug', + 'circuit', 'screen', 'wheel', 'gear', 'code', 'laser', 'crystal', 'sock', 'wire', 'spring', + 'nut', 'bolt', 'fountain', 'hose', 'dust', 'ink', 'sponge', 'torch', 'antenna', 'radar', + 'fog', 'glitch', 'pixel', 'echo', 'sound', 'trail', 'mist', 'beam', 'flare', 'spark', + 'ring', 'chain', 'vine', 'iceberg', 'tent', 'ballpit', 'mushroom', 'hammock', 'beetle', 'pillow' + ]; + + $adjectives = [ + 'blue', 'green', 'quiet', 'strange', 'tiny', 'lazy', 'brave', 'happy', 'fuzzy', 'bright', + 'shiny', 'cold', 'hot', 'warm', 'gentle', 'wild', 'soft', 'hard', 'silent', 'loud', + 'fast', 'slow', 'ancient', 'modern', 'funny', 'sad', 'angry', 'weird', 'friendly', 'fierce', + 'bold', 'timid', 'rich', 'poor', 'young', 'old', 'massive', 'small', 'giant', 'sharp', + 'dull', 'golden', 'silver', 'broken', 'new', 'used', 'rusty', 'clean', 'dirty', 'sparkling', + 'dark', 'light', 'purple', 'yellow', 'orange', 'pink', 'red', 'black', 'white', 'gray', + 'striped', 'spotted', 'fluffy', 'hairy', 'bald', 'spiky', 'sneaky', 'clumsy', 'sleepy', 'alert', + 'magical', 'mystic', 'robotic', 'natural', 'round', 'square', 'triangular', 'flat', 'hollow', 'solid', + 'creaky', 'noisy', 'icy', 'burning', 'wet', 'dry', 'sticky', 'smooth', 'rough', 'bumpy', + 'twisted', 'melting', 'frozen', 'alive', 'dead', 'electric', 'solar', 'mechanical', 'digital', 'analog', + 'playful', 'serious', 'curious', 'shy', 'wise', 'clever', 'lucky', 'unlucky', 'calm', 'stormy', + 'hectic', 'peaceful', 'fearless', 'colorful', 'cloudy', 'sunny', 'windy', 'dusty', 'muddy', 'greasy', + 'fragrant', 'smelly', 'tasty', 'bitter', 'sweet', 'sour', 'salty', 'savory', 'juicy', 'dry', + 'crunchy', 'chewy', 'bland', 'spicy', 'burnt', 'raw', 'cooked', 'boiled', 'fried', 'grilled', + 'steamed', 'baked', 'roasted', 'frozen', 'chilled', 'warm', 'cozy', 'drafty', 'humid', 'icy', + 'stormy', 'snowy', 'rainy', 'foggy', 'misty', 'clear', 'blazing', 'glowing', 'dim', 'twinkling' + ]; + + $verbs = [ + 'jumps', 'runs', 'flies', 'sleeps', 'dances', 'floats', 'hides', 'sings', 'crawls', 'spins', + 'rolls', 'slides', 'dives', 'climbs', 'skips', 'wanders', 'travels', 'glows', 'explodes', 'screams', + 'whispers', 'laughs', 'cries', 'smiles', 'shakes', 'builds', 'destroys', 'paints', 'writes', 'draws', + 'blinks', 'waves', 'drives', 'bakes', 'burns', 'eats', 'drinks', 'sits', 'stands', 'waits', + 'listens', 'hears', 'sees', 'touches', 'grabs', 'throws', 'catches', 'pushes', 'pulls', 'breaks', + 'fixes', 'turns', 'opens', 'closes', 'locks', 'unlocks', 'connects', 'disconnects', 'charges', 'zaps', + 'programs', 'downloads', 'uploads', 'types', 'codes', 'transforms', 'melts', 'freezes', 'evaporates', 'grows', + 'shrinks', 'multiplies', 'divides', 'fades', 'flashes', 'vibrates', 'glitches', 'buzzes', 'rings', 'echoes', + 'flickers', 'crashes', 'spreads', 'collapses', 'emerges', 'vanishes', 'appears', 'hovers', 'drifts', 'storms', + 'rains', 'snows', 'thunders', 'booms', 'bounces', 'twists', 'shines', 'spits', 'howls', 'claps', + 'cheers', 'groans', 'moans', 'rattles', 'snaps', 'squeaks', 'snores', 'yawns', 'gulps', 'growls', + 'chirps', 'croaks', 'bleats', 'roars', 'meows', 'barks', 'quacks', 'neighs', 'oinks', 'buzzes', + 'clicks', 'ticks', 'beeps', 'whistles', 'chants', 'murmurs', 'hums', 'clunks', 'zips', 'plops' + ]; + + $prepositions = [ + 'under', 'over', 'behind', 'beside', 'on', 'near', 'above', 'below', 'between', 'within', + 'around', 'across', 'against', 'through', 'into', 'out of', 'next to', 'in front of', 'beneath', 'at', + 'by', 'with', 'without', 'before', 'after', 'along', 'towards', 'onto', 'off', 'beyond', + 'amid', 'among', 'inside', 'outside', 'around', 'upon', 'down', 'up', 'past', 'alongside', + 'opposite', 'nearby', 'beneath', 'underneath', 'in', 'on top of', 'about', 'concerning', 'despite', 'during', + 'except', 'like', 'unlike', 'via', 'per', 'amidst', 'amongst', 'notwithstanding', 'since', 'till', + 'throughout', 'to', 'toward', 'underneath', 'versus', 'via', 'within', 'without', 'as', 'barring', + 'counting', 'following', 'excluding', 'including', 'notwithstanding', 'regarding', 'respecting', 'save', 'than', 'until', + 'versus', 'upon', 'aboard', 'across from', 'ahead of', 'apart from', 'as far as', 'as of', 'as well as', 'aside from', + 'atop', 'because of', 'close to', 'due to', 'far from', 'inside of', 'near to', 'next to', 'on behalf of', 'on top of', + 'out from', 'outside of', 'prior to', 'pursuant to', 'rather than', 'subsequent to', 'such as', 'thanks to', 'together with', 'up to' + ]; + + // Pick random words + $adj1 = $adjectives[array_rand($adjectives)]; + $noun1 = $nouns[array_rand($nouns)]; + $verb = $verbs[array_rand($verbs)]; + $prep = $prepositions[array_rand($prepositions)]; + $adj2 = $adjectives[array_rand($adjectives)]; + $noun2 = $nouns[array_rand($nouns)]; + + // Build sentence + $sentence = "The $adj1 $noun1 $verb $prep the $adj2 $noun2"; + + return ucfirst($sentence); } public static function isAllowedToOrganizeRoom(?User $user, ?Rooms $room): bool diff --git a/templates/base/__profileModal.html.twig b/templates/base/__profileModal.html.twig index 74aee567e..107966877 100644 --- a/templates/base/__profileModal.html.twig +++ b/templates/base/__profileModal.html.twig @@ -158,6 +158,8 @@ {% endif %} + + {% if getApplicationProperties('LAF_SHOW_CALENDLY') != false %}
{{ 'calendly.header'|trans }}
@@ -173,6 +175,7 @@
{{'calendly.connection.connected'|trans }}
{{ 'callendly.disconnect'|trans }} {% endif %} + {% endif %}
diff --git a/templates/conference_modules/conferenceSidebar.html.twig b/templates/conference_modules/conferenceSidebar.html.twig index e0e971ba6..c0f5d5967 100644 --- a/templates/conference_modules/conferenceSidebar.html.twig +++ b/templates/conference_modules/conferenceSidebar.html.twig @@ -1,4 +1,3 @@ - {% set logo_small = httpsAbolutUrl(asset('logo_small.png')) %} {% if server is defined and server is not null and server.logoUrl is not null %} @@ -21,26 +20,28 @@ var schowNameInWidgets = "{{ user|nameOfUserNoSymbol }}"; {% endif %} - +
{% if room is defined and room is not null %} - {% if room.server.disableChat != true %} + {% if not room.server.liveKitServer %} + {% if room.server.disableChat != true %} -
-
- -
-
-
- {{ 'options.chat'|trans }} +
+
+ +
+
+
+ {{ 'options.chat'|trans }} +
-
+ {% endif %} {% endif %} {% endif %} @@ -56,11 +57,12 @@ or roomPermissions(app.user,room).moderator == true or roomPermissions(app.user,room).lobbyModerator == true) %} data-selfurl="{{ createWhitebophirLink(room,true) }}" - data-room="whiteboard/{{ room.uidReal }}" + data-room="{{ room.uidReal }}" data-url="{{ createWhitebophirLink(room,false) }}" {% else %} data-selfurl="{{ createWhitebophirLink(room,false) }}" {% endif %} + data-roomUid="{{ room.uid }}" > @@ -73,6 +75,23 @@ {% endif %} {% endif %} + {% if getApplicationProperties('LAF_LOOKYLOOKY_FUNCTION') == 1 %} + +
+
+ + +
+
+ {{ 'options.whiteboard'|trans }} +
+
+ + {% endif %} {% if getApplicationProperties('LAF_ETHERPAD_FUNCTION') == 1 %} {% if name is not defined or name is null %} {% set name = 'Meetling' %} @@ -88,11 +107,12 @@ or roomPermissions(app.user,room).moderator == true or roomPermissions(app.user,room).lobbyModerator == true) %} data-selfurl="{{ createEtherpadLink(room,user) }}" - data-room="whiteboard/{{ room.uidReal }}" + data-room="{{ room.uidReal }}" data-url="{{ createEtherpadLink(room) }}" {% else %} data-selfurl="{{ createEtherpadLink(room,user) }}" {% endif %} + data-roomUid="{{ room.uid }}" >
@@ -105,7 +125,7 @@ {% endif %} {% block extension %}{% endblock %} {% if not room.server.liveKitServer %} - {% include 'conference_modules/__toggleFilmstripe.html.twig' %} + {% include 'conference_modules/__toggleFilmstripe.html.twig' %} {% endif %} {% if room.server.liveKitServer %} {% include 'conference_modules/__livekit_recording.html.twig' %} diff --git a/templates/form/ja_theme.html.twig b/templates/form/ja_theme.html.twig index e69de29bb..8f8995e50 100644 --- a/templates/form/ja_theme.html.twig +++ b/templates/form/ja_theme.html.twig @@ -0,0 +1,49 @@ +{% block form_row -%} + {%- if compound is defined and compound -%} + {%- set element = 'fieldset' -%} + {%- endif -%} + {%- set widget_attr = {} -%} + {%- if help is not empty -%} + {%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%} + {%- endif -%} + <{{ element|default('div') }}{% with {attr: row_attr|merge({class: (row_attr.class|default('') ~ ' form-group')|trim})} %}{{ block('attributes') }}{% endwith %}> + + {{- form_widget(form, widget_attr) -}} + {{- form_help(form) -}} + +{%- endblock form_row %} +{% block text_widget %} +
+ {% set id = form.vars.id %} + {% set attr = attr|merge({'class': (attr.class|default('') ~ ' form-control form-control-lg')|trim}) %} + {{ block('form_widget_simple') }} + +
+{% endblock %} + +{% block email_widget %} + {{ block('text_widget') }} +{% endblock %} + +{% block number_widget %} + {{ block('text_widget') }} +{% endblock %} + +{# Optional: textarea, password, search, etc. #} +{% block textarea_widget %} +
+ + + +
+{% endblock %} + +{% block password_widget %} + {{ block('text_widget') }} +{% endblock %} \ No newline at end of file diff --git a/templates/lobby/__lobbyParticipants.html.twig b/templates/lobby/__lobbyParticipants.html.twig index dd0cb8885..a255a493e 100644 --- a/templates/lobby/__lobbyParticipants.html.twig +++ b/templates/lobby/__lobbyParticipants.html.twig @@ -45,15 +45,11 @@
@@ -62,8 +58,7 @@