Files
meetletacbfree/settings.php
T

968 lines
38 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Admin settings for MeetLet Adobe Connect Bridge (tabbed).
*
* @package mod_meetletacbfree
* @copyright 2026 MeetLet <info@meetlet.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
use mod_meetletacbfree\admin\settingspage_tabs;
use mod_meetletacbfree\local\config;
use mod_meetletacbfree\local\conntest_runner;
use mod_meetletacbfree\local\privacy_policy;
use mod_meetletacbfree\local\server_guide;
use mod_meetletacbfree\registration\manager as registration_manager;
// Ensure class is available even if Moodle classmap cache is stale after adding this file.
require_once(__DIR__ . '/classes/local/server_guide.php');
require_once(__DIR__ . '/classes/local/privacy_policy.php');
if ($ADMIN->fulltree) {
global $OUTPUT;
$settings = new settingspage_tabs(
$settings->name,
$settings->visiblename,
$settings->req_capability,
$settings->hidden
);
$logo = $OUTPUT->image_url('adobeconnect', 'meetletacbfree');
$stylesurl = new moodle_url('/mod/meetletacbfree/styles.css', ['v' => '2026090146']);
$jsurl = new moodle_url('/mod/meetletacbfree/javascript/settings_conntest.js', ['v' => '2026082135']);
$togglejsurl = new moodle_url('/mod/meetletacbfree/javascript/settings_toggles.js', ['v' => '2026081907']);
$matrixjsurl = new moodle_url('/mod/meetletacbfree/javascript/featureaccess_matrix.js');
$accessresetjsurl = new moodle_url('/mod/meetletacbfree/javascript/settings_access_reset.js', ['v' => '2026090115']);
$resetajaxurl = new moodle_url('/mod/meetletacbfree/ajax/settings_reset.php');
$modalscrolljsurl = new moodle_url('/mod/meetletacbfree/javascript/meetlet_modal_scroll.js', ['v' => '2026082239']);
$registrationjsurl = new moodle_url('/mod/meetletacbfree/javascript/settings_registration.js', ['v' => '2026090144']);
$cronjsurl = null;
$ajaxurl = new moodle_url('/mod/meetletacbfree/ajax/conntest.php');
// Load styles.css explicitly on admin tabs (theme concatenate alone is not enough for switch CSS).
$styles = '
<link rel="stylesheet" href="' . s($stylesurl->out(false)) . '">
<style>
.path-admin #adminsettings .settingsform > h2 {
display: none;
}
.path-admin .meetlet-settings-hero {
display:flex; gap:1rem; align-items:center;
padding:1.15rem 1.25rem; margin:0 0 1rem;
border-radius:16px;
background:
radial-gradient(700px 180px at 100% 0%, rgba(82,204,163,.22), transparent 55%),
linear-gradient(135deg, #00261a 0%, #0a3d2e 60%, #145c45 100%);
color:#fff;
border:1px solid rgba(82,204,163,.25);
}
.path-admin .meetlet-settings-hero img {
width:56px; height:56px; object-fit:contain;
background:rgba(255,255,255,.95); border-radius:12px; padding:6px;
}
.path-admin .meetlet-settings-hero h3 {
margin:0 0 .2rem; font-size:1.2rem; font-weight:700; color:#fff;
display:flex; flex-wrap:wrap; align-items:center; gap:.45rem .55rem;
}
.path-admin .meetlet-settings-hero .meetlet-settings-version {
display:inline-block;
flex:0 0 auto;
align-self:center;
margin-inline-start:auto;
padding:.12rem .55rem;
font-size:.72rem; font-weight:650; line-height:1.35;
letter-spacing:.02em;
border-radius:999px;
background:rgba(82,204,163,.18);
border:1px solid rgba(82,204,163,.35);
color:#b8f5df;
white-space:nowrap;
direction:ltr;
unicode-bidi:isolate;
}
.path-admin .meetlet-settings-hero p {
margin:0; opacity:.85; color:#e6faf3;
white-space:nowrap;
max-width:none;
}
.path-admin .meetlet-settings-copy {
min-width:0; flex:1 1 auto;
}
@media (max-width: 900px) {
.path-admin .meetlet-settings-hero p {
white-space:normal;
}
}
.path-admin #adminsettings .nav-tabs {
border-bottom:2px solid #cfe8de;
gap:.2rem;
}
.path-admin #adminsettings .nav-tabs .nav-link {
border:0 !important;
border-radius:6px !important;
padding:.45rem .9rem;
color:#00261a;
font-weight:650;
box-shadow:none !important;
outline:none !important;
}
.path-admin #adminsettings .nav-tabs .nav-link:hover {
background:#e6faf3; color:#00261a;
}
.path-admin #adminsettings .nav-tabs .nav-link.active {
background:#52cca3; color:#00261a;
}
.path-admin #adminsettings .nav-tabs .nav-link:focus,
.path-admin #adminsettings .nav-tabs .nav-link:focus-visible,
.path-admin #adminsettings .nav-tabs .nav-link:active {
outline:none !important;
box-shadow:none !important;
border:0 !important;
}
.path-admin .meetlet-feature-group {
margin:1rem 0 .35rem;
padding:1rem 1.1rem .35rem;
border:1px solid #cfe8de;
border-radius:12px;
background:linear-gradient(180deg, #f3fbf8 0%, #ffffff 55%);
}
.path-admin .meetlet-feature-group h4 {
margin:0 0 .25rem; color:#00261a; font-size:1.02rem; font-weight:700;
}
.path-admin .meetlet-feature-group p {
margin:0 0 .5rem; color:#4a6b5f; font-size:.9rem;
}
.path-admin .meetlet-settings-card {
background:#fff; border:1px solid #cfe8de; border-radius:14px;
padding:1rem 1.15rem; margin:.35rem 0 1rem;
}
.meetlet-license-badge {
font-weight: 700;
border-radius: 999px;
padding: .35rem .65rem;
}
.meetlet-license-badge--active {
background: var(--ml-green, #52cca3);
color: var(--ml-green-deep, #00261a);
}
.meetlet-license-badge--inactive {
background: #fff4d6;
color: #5a4700;
}
.path-admin #meetlet-license-modal.meetlet-modal,
.path-admin #meetlet-registration-modal.meetlet-modal,
.path-admin #meetlet-cronmon-modal.meetlet-modal,
.path-admin #meetlet-access-reset-modal.meetlet-modal {
z-index: 20000 !important;
}
.path-admin .meetlet-access-reset-toolbar {
display: flex;
justify-content: flex-end;
margin: 0 0 .65rem;
}
html[dir="rtl"] .path-admin .meetlet-access-reset-toolbar {
justify-content: flex-start;
}
/* Cron videos ops cell: no extra cell/wrapper border (icon buttons keep theirs). */
.path-admin .meetlet-cronmon__table td.meetlet-cronmon__dl {
border-left: 0 !important;
border-right: 0 !important;
border-top: 0 !important;
background: transparent !important;
box-shadow: none !important;
}
.path-admin .meetlet-cronmon__dl .meetlet-iconactions {
border: 0 !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
}
.path-admin .meetlet-modal--confirm .meetlet-modal__dialog {
width: min(480px, 100%);
max-height: min(86vh, 640px);
overflow: hidden;
display: flex;
flex-direction: column;
}
.path-admin .meetlet-modal--confirm .meetlet-modal__head {
padding: 1.2rem 1.15rem 1rem;
border-radius: 18px 18px 0 0;
}
.path-admin .meetlet-modal__lead {
margin: 0 0 .85rem;
font-size: 1rem;
font-weight: 650;
line-height: 1.65;
color: #00261a;
}
.path-admin .meetlet-modal__callout {
margin: 0 0 .9rem;
padding: .85rem 1rem .7rem;
border-radius: 12px;
border: 1px solid #e6c56a;
background: #fff8e6;
color: #5a4700;
}
.path-admin .meetlet-modal__callout-title {
margin: 0 0 .4rem;
font-weight: 700;
}
.path-admin .meetlet-modal__limits {
margin: 0 0 .55rem;
padding-inline-start: 1.2rem;
}
.path-admin .meetlet-modal__keep {
margin: 0;
color: #334942;
line-height: 1.65;
}
.path-admin .meetlet-modal__foot {
display: flex;
justify-content: flex-end;
align-items: center;
gap: .6rem;
flex-wrap: wrap;
padding: .9rem 1.15rem 1.05rem;
border-top: 1px solid #cfe8de;
background: linear-gradient(180deg, #f7fcfa 0%, #ffffff 70%);
}
.path-admin .meetlet-modal__foot .btn {
border-radius: 10px;
font-weight: 700;
padding: .5rem 1.15rem;
}
.path-admin .meetlet-modal__foot .btn-success {
background: #52cca3 !important;
border-color: #3db892 !important;
color: #00261a !important;
}
.path-admin .meetlet-modal__foot .btn-outline-danger {
color: #a33b3b !important;
border-color: #d9a0a0 !important;
background: #fff !important;
}
.path-admin .meetlet-modal__foot .btn-outline-danger:hover,
.path-admin .meetlet-modal__foot .btn-outline-danger:focus {
color: #fff !important;
background: #c0392b !important;
border-color: #c0392b !important;
}
.path-admin .meetlet-about {
display:grid; gap:1.1rem;
}
.path-admin .meetlet-about__brand {
display:flex; justify-content:center; align-items:center;
padding:1.35rem 1.2rem;
border-radius:14px;
background:#f0f2f4;
border:1px solid #e2e6ea;
}
.path-admin .meetlet-about__brand img {
max-width:240px; width:100%; height:auto; display:block; margin:0 auto;
}
.path-admin .meetlet-about h4 { margin:0 0 .55rem; color:#00261a; }
.path-admin .meetlet-about p {
margin:0 0 .85rem; color:#334942; line-height:1.75; text-align:justify;
}
.path-admin .meetlet-guide { display:grid; gap:1rem; }
.path-admin .meetlet-guide__heading { margin:0; color:#00261a; font-size:1.15rem; }
.path-admin .meetlet-guide__intro {
margin:0; color:#334942; line-height:1.7;
}
.path-admin .meetlet-guide__callout {
padding:.85rem 1rem; border-radius:10px; line-height:1.65;
border:1px solid #e6c56a; background:#fff8e6; color:#5a4700;
}
.path-admin .meetlet-guide__section {
padding:1rem 1.05rem; border-radius:12px;
border:1px solid #cfe8de; background:#f7fcfa;
}
.path-admin .meetlet-guide__section--current { background:#fff; }
.path-admin .meetlet-guide__section h4 {
margin:0 0 .55rem; color:#00261a; font-size:1.02rem; font-weight:700;
}
.path-admin .meetlet-guide__section h5 {
margin:.85rem 0 .35rem; color:#0a3d2e; font-size:.95rem; font-weight:700;
}
.path-admin .meetlet-guide__body,
.path-admin .meetlet-guide__body p,
.path-admin .meetlet-guide__body li {
color:#334942; line-height:1.7;
}
.path-admin .meetlet-guide__body p { margin:0 0 .55rem; }
.path-admin .meetlet-guide__body ol,
.path-admin .meetlet-guide__body ul { margin:0 0 .35rem; padding-inline-start:1.25rem; }
.path-admin .meetlet-guide__body li { margin:0 0 .35rem; }
.path-admin .meetlet-guide__body code,
.path-admin .meetlet-guide__table code {
font-size:.88em; padding:.05rem .3rem; border-radius:4px;
background:#e6faf3; color:#00261a;
}
.path-admin .meetlet-guide__table {
width:100%; margin:.35rem 0 0; border-collapse:collapse;
}
.path-admin .meetlet-guide__table th,
.path-admin .meetlet-guide__table td {
padding:.45rem .55rem; border:1px solid #cfe8de; vertical-align:top;
text-align:start;
}
.path-admin .meetlet-guide__table thead th,
.path-admin .meetlet-guide__table tbody th {
background:#e6faf3; color:#00261a; font-weight:650;
}
.path-admin .meetlet-guide__code {
margin:.35rem 0 0; padding:.75rem .9rem; overflow-x:auto;
border-radius:10px; border:1px solid #cfe8de;
background:#0a3d2e; color:#e6faf3;
font-size:.82rem; line-height:1.45; direction:ltr; text-align:left;
white-space:pre;
}
.path-admin .meetlet-guide__code-cell code {
font-weight:800; letter-spacing:.02em; direction:ltr; unicode-bidi:isolate;
}
.path-admin .meetlet-guide__table td ol,
.path-admin .meetlet-guide__table td ul {
margin:.15rem 0 0; padding-inline-start:1.15rem;
}
.path-admin .meetlet-guide__table td li { margin:0 0 .25rem; }
.path-admin .meetlet-hourpicker { max-width: 42rem; }
.path-admin .meetlet-hourpicker.is-dimmed,
.path-admin #adminsettings .form-item.is-dimmed {
opacity: .45;
pointer-events: none;
}
.path-admin .meetlet-hourpicker__tz {
margin: 0 0 .55rem; color:#4a6b5f; font-size:.88rem;
}
.path-admin .meetlet-hourpresets {
display:flex; flex-wrap:wrap; gap:.4rem; margin:0 0 .65rem;
}
.path-admin .meetlet-hourpreset {
border:1px solid #9fdcc4; background:#fff; color:#00261a;
border-radius:999px; padding:.28rem .7rem; font-size:.8rem; font-weight:650;
cursor:pointer;
}
.path-admin .meetlet-hourpreset:hover { background:#e6faf3; }
.path-admin .meetlet-hourpreset--ghost { border-color:#cfe8de; color:#4a6b5f; }
.path-admin .meetlet-hourgrid {
display:grid; grid-template-columns:repeat(8, minmax(0,1fr)); gap:.35rem;
}
.path-admin .meetlet-hourchip {
border:1px solid #cfe8de; background:#f7fcfa; color:#00261a;
border-radius:10px; padding:.45rem 0; font-size:.82rem; font-weight:750;
cursor:pointer;
}
.path-admin .meetlet-hourchip.is-on {
background:#52cca3; border-color:#0d9f6e; color:#00261a;
}
.path-admin .meetlet-hourchip.is-now { box-shadow:0 0 0 2px rgba(13,159,110,.35); }
@media (max-width: 720px) {
.path-admin .meetlet-hourgrid { grid-template-columns:repeat(6, minmax(0,1fr)); }
}
.path-admin .meetlet-about__cta-wrap {
display:flex; justify-content:center; margin-top:.35rem; padding-top:.35rem;
}
.path-admin .meetlet-about__cta {
display:inline-flex; align-items:center; justify-content:center;
min-width:220px; padding:.7rem 1.35rem; border-radius:10px;
background:#52cca3; color:#00261a !important;
text-decoration:none !important; font-weight:700;
border:1px solid #3db892;
box-shadow:0 6px 16px rgba(0,38,26,.08);
}
.path-admin .meetlet-about__cta:hover {
background:#6fd9b5; color:#00261a !important;
}
.path-admin .meetlet-settings-btn {
display:inline-flex; align-items:center; justify-content:center; gap:.45rem;
padding:.6rem 1.15rem; border-radius:10px; border:0; cursor:pointer;
background:#52cca3; color:#00261a !important;
text-decoration:none !important; font-weight:700;
}
.path-admin .meetlet-settings-btn:hover { background:#6fd9b5; color:#00261a !important; }
.path-admin .meetlet-settings-btn:disabled { opacity:.65; cursor:wait; }
.path-admin .meetlet-settings-btn svg {
width:1.1rem; height:1.1rem; flex:0 0 auto; display:block;
}
.path-admin .meetlet-license-actions {
display:flex; flex-wrap:wrap; gap:.55rem; align-items:center;
}
.path-admin .meetlet-license-actions .btn {
display:inline-flex; align-items:center; justify-content:center; gap:.45rem;
}
.path-admin .meetlet-license-actions .btn svg {
width:1.05rem; height:1.05rem; flex:0 0 auto; display:block;
}
.path-admin .meetlet-license-btn--free {
background: linear-gradient(180deg, #e6faf3 0%, #d4f5ea 100%) !important;
border: 2px solid #52cca3 !important;
color: #00261a !important;
border-radius: 10px !important;
font-weight: 700 !important;
padding: .6rem 1.15rem !important;
box-shadow: 0 4px 12px rgba(82, 204, 163, 0.18) !important;
}
.path-admin .meetlet-license-btn--free:hover,
.path-admin .meetlet-license-btn--free:focus {
background: linear-gradient(180deg, #6fd9b5 0%, #52cca3 100%) !important;
border-color: #3db892 !important;
color: #00261a !important;
box-shadow: 0 6px 16px rgba(82, 204, 163, 0.28) !important;
}
.path-admin .meetlet-conntest { max-width:none; margin:0; }
.path-admin .meetlet-conntest__actions {
display:flex; flex-wrap:wrap; gap:.75rem; align-items:center;
margin:.85rem 0 1rem;
}
.path-admin .meetlet-conntest__status { color:#4a6b5f; font-size:.9rem; }
.path-admin .meetlet-conntest__progress {
margin:0 0 1rem; padding:.85rem 1rem;
border:1px solid #cfe8de; border-radius:12px; background:#f7fcfa;
}
.path-admin .meetlet-conntest__progress-label {
display:flex; justify-content:space-between; gap:.75rem;
margin:0 0 .45rem; color:#00261a; font-weight:650; font-size:.92rem;
}
.path-admin .meetlet-conntest__progress-track {
height:10px; border-radius:999px; background:#d9eee5; overflow:hidden;
}
.path-admin .meetlet-conntest__progress-fill {
height:100%; width:0; border-radius:999px;
background:linear-gradient(90deg, #2f9f7a, #52cca3);
transition:width .28s ease;
}
.path-admin .meetlet-conntest__num {
min-width:1.7rem; height:1.7rem; border-radius:8px;
display:inline-flex; align-items:center; justify-content:center;
background:#e6faf3; color:#00261a; font-weight:750; font-size:.85rem;
}
.path-admin .meetlet-conntest__card--pending { opacity:.78; background:#fbfefe; }
.path-admin .meetlet-conntest__card--running {
border-color:#e6b422;
box-shadow:0 0 0 2px rgba(230,180,34,.22);
background:#fff8e6;
}
.path-admin .meetlet-conntest__card--running .meetlet-conntest__num {
background:#ffe08a; color:#5c4700;
}
.path-admin .meetlet-conntest__card--ok {
border-color:#9fdcc4; background:#f3fbf8;
}
.path-admin .meetlet-conntest__card--fail {
border-color:#ead3d0; background:#fff8f7;
}
.path-admin .meetlet-conntest__card--skipped { opacity:.55; }
.path-admin .meetlet-dot--pending { background:#9bb7ac; box-shadow:0 0 0 4px rgba(155,183,172,.18); }
.path-admin .meetlet-dot--running {
background:#e6b422; box-shadow:0 0 0 4px rgba(230,180,34,.28);
animation:meetletPulse 1s ease-in-out infinite;
}
.path-admin .meetlet-dot--skipped { background:#b7c4be; box-shadow:none; }
.path-admin .meetlet-pill--pending { background:#e8efec; color:#456257; }
.path-admin .meetlet-pill--running { background:#ffe08a; color:#5c4700; }
.path-admin .meetlet-pill--skipped { background:#eef1f0; color:#667a72; }
@keyframes meetletPulse {
0%, 100% { transform:scale(1); opacity:1; }
50% { transform:scale(1.15); opacity:.75; }
}
.path-admin #adminsettings form.settingsform {
padding-bottom:1rem;
}
/* Single save row: spacing only — no stacked border/gradient bands. */
.path-admin #adminsettings .settingsform > .row:has(.btn-primary),
.path-admin #adminsettings .form-buttons,
.path-admin #adminsettings .btns-group {
margin-top:1.25rem !important;
padding:0;
border:0;
background:transparent;
border-radius:0;
}
.path-admin #adminsettings .meetlet-savebar {
margin-top: 1.25rem !important;
margin-right: 0 !important;
margin-left: 0 !important;
margin-inline: 0 !important;
flex: 0 0 100% !important;
max-width: 100% !important;
width: 100% !important;
padding: .35rem 0 !important;
border: 0 !important;
background: transparent !important;
border-radius: 0 !important;
}
@media (min-width: 576px) {
.path-admin #adminsettings .meetlet-savebar.offset-sm-3,
.path-admin #adminsettings .meetlet-savebar {
margin-right: 0 !important;
margin-left: 0 !important;
}
}
.path-admin #adminsettings .btn-primary,
.path-admin #adminsettings input[type="submit"].btn-primary,
.path-admin #adminsettings button[type="submit"].btn-primary,
.path-admin #adminsettings .meetlet-btn-with-icon.btn-primary {
background:#52cca3 !important;
border-color:#3db892 !important;
color:#00261a !important;
font-weight:700 !important;
border-radius:10px !important;
padding:.55rem 1.35rem !important;
box-shadow:none !important;
}
.path-admin #adminsettings .btn-primary:hover,
.path-admin #adminsettings input[type="submit"].btn-primary:hover,
.path-admin #adminsettings button[type="submit"].btn-primary:hover {
background:#6fd9b5 !important;
border-color:#52cca3 !important;
color:#00261a !important;
}
.path-admin .meetlet-btn-with-icon {
display:inline-flex !important;
align-items:center;
justify-content:center;
gap:.45rem;
}
.path-admin .meetlet-btn-with-icon svg {
width:1.1rem;
height:1.1rem;
flex:0 0 auto;
display:block;
}
.path-admin .meetlet-btn-with-icon__label {
line-height:1.2;
}
.path-admin .meetlet-server-group {
margin:1.1rem 0 .4rem; padding:1rem 1.1rem .2rem;
border:1px solid #cfe8de; border-radius:12px;
background:linear-gradient(180deg, #f3fbf8 0%, #ffffff 60%);
}
.path-admin .meetlet-server-group h4 {
margin:0 0 .25rem; color:#00261a; font-size:1.02rem; font-weight:700;
}
.path-admin .meetlet-server-group p {
margin:0 0 .55rem; color:#4a6b5f; font-size:.9rem; line-height:1.55;
}
/* RTL alignment for Persian/Arabic admin settings */
html[dir="rtl"] .path-admin #adminsettings,
html[dir="rtl"] .path-admin #adminsettings .settingsform,
html[dir="rtl"] .path-admin #adminsettings .tab-content,
html[dir="rtl"] .path-admin #adminsettings .form-item {
direction: rtl;
}
html[dir="rtl"] .path-admin #adminsettings .form-item .form-label,
html[dir="rtl"] .path-admin #adminsettings .form-item .form-label.label,
html[dir="rtl"] .path-admin #adminsettings .form-item .form-label > label,
html[dir="rtl"] .path-admin #adminsettings .form-item .form-label .form-shortname,
html[dir="rtl"] .path-admin #adminsettings .form-description,
html[dir="rtl"] .path-admin #adminsettings .form-defaultinfo,
html[dir="rtl"] .path-admin #adminsettings .form-setting .form-check,
html[dir="rtl"] .path-admin #adminsettings .form-setting .checkbox,
html[dir="rtl"] .path-admin #adminsettings .form-setting label,
html[dir="rtl"] .path-admin #adminsettings h3.main,
html[dir="rtl"] .path-admin #adminsettings .form-item .form-label.text-sm-end,
html[dir="rtl"] .path-admin #adminsettings .form-item .form-label.text-end {
text-align: right !important;
direction: rtl;
}
html[dir="rtl"] .path-admin #adminsettings .meetlet-feature-group,
html[dir="rtl"] .path-admin #adminsettings .meetlet-feature-group h4,
html[dir="rtl"] .path-admin #adminsettings .meetlet-feature-group p,
html[dir="rtl"] .path-admin #adminsettings .meetlet-settings-card,
html[dir="rtl"] .path-admin #adminsettings .meetlet-about,
html[dir="rtl"] .path-admin #adminsettings .meetlet-about p,
html[dir="rtl"] .path-admin #adminsettings .meetlet-about h4,
html[dir="rtl"] .path-admin #adminsettings .meetlet-privacy,
html[dir="rtl"] .path-admin #adminsettings .meetlet-privacy p,
html[dir="rtl"] .path-admin #adminsettings .meetlet-privacy h3,
html[dir="rtl"] .path-admin #adminsettings .meetlet-privacy h4,
html[dir="rtl"] .path-admin #adminsettings .meetlet-conntest,
html[dir="rtl"] .path-admin #adminsettings .meetlet-conntest__intro,
html[dir="rtl"] .path-admin #adminsettings .meetlet-conntest__title,
html[dir="rtl"] .path-admin #adminsettings .meetlet-conntest__status,
html[dir="rtl"] .path-admin #adminsettings .meetlet-conntest__progress-label,
html[dir="rtl"] .path-admin .meetlet-settings-hero,
html[dir="rtl"] .path-admin .meetlet-settings-hero h3,
html[dir="rtl"] .path-admin .meetlet-settings-hero .meetlet-settings-version,
html[dir="rtl"] .path-admin .meetlet-settings-hero p,
html[dir="rtl"] .path-admin .meetlet-settings-copy {
direction: rtl;
text-align: right;
}
html[dir="rtl"] .path-admin .meetlet-settings-hero {
flex-direction: row;
}
html[dir="rtl"] .path-admin #adminsettings .nav-tabs {
direction: rtl;
}
html[dir="rtl"] .path-admin #adminsettings .form-setting input[type="text"],
html[dir="rtl"] .path-admin #adminsettings .form-setting input[type="password"],
html[dir="rtl"] .path-admin #adminsettings .form-setting input[type="url"],
html[dir="rtl"] .path-admin #adminsettings .form-setting input[type="number"],
html[dir="rtl"] .path-admin #adminsettings .form-setting select,
html[dir="rtl"] .path-admin #adminsettings .form-setting textarea {
direction: ltr;
text-align: left;
unicode-bidi: isolate;
}
html[dir="rtl"] .path-admin #adminsettings .form-setting .form-check,
html[dir="rtl"] .path-admin #adminsettings .form-setting .checkbox,
html[dir="rtl"] .path-admin #adminsettings .form-setting .form-checkbox {
display: flex;
flex-direction: row-reverse;
justify-content: flex-end;
align-items: center;
gap: .5rem;
text-align: right;
}
html[dir="rtl"] .path-admin #adminsettings .form-item .form-label .form-shortname {
direction: ltr;
unicode-bidi: isolate;
text-align: right !important;
display: block;
}
html[dir="rtl"] .path-admin #adminsettings .form-setting .form-checkbox {
direction: rtl;
text-align: right;
}
html[dir="rtl"] .path-admin #adminsettings .form-setting .defaultsnext {
text-align: right;
}
html[dir="rtl"] .path-admin #adminsettings .meetlet-savebar,
html[dir="rtl"] .path-admin #adminsettings .form-buttons {
text-align: right;
}
</style>
<script src="' . s($modalscrolljsurl->out(false)) . '" defer></script>
<script src="' . s($registrationjsurl->out(false)) . '" defer></script>
<script src="' . s($jsurl->out(false)) . '" defer></script>
<script src="' . s($togglejsurl->out(false)) . '" defer></script>
<script src="' . s($matrixjsurl->out(false)) . '" defer></script>
<script src="' . s($accessresetjsurl->out(false)) . '" defer></script>';
$plugin = new stdClass();
include(__DIR__ . '/version.php');
$release = $plugin->release ?? '';
if ($release !== '' && strpos(current_language(), 'fa') === 0) {
$release = strtr($release, [
'0' => '۰', '1' => '۱', '2' => '۲', '3' => '۳', '4' => '۴',
'5' => '۵', '6' => '۶', '7' => '۷', '8' => '۸', '9' => '۹',
]);
}
$versionbadge = $release !== ''
? html_writer::span(get_string('settingsversion', 'meetletacbfree', $release), 'meetlet-settings-version')
: '';
$hero = $styles . html_writer::div(
html_writer::img($logo, 'Adobe Connect', ['alt' => 'Adobe Connect']) .
html_writer::div(
html_writer::tag('h3', get_string('pluginname', 'meetletacbfree')) .
html_writer::tag('p', get_string('settingsintro', 'meetletacbfree')),
'meetlet-settings-copy'
) .
$versionbadge,
'meetlet-settings-hero'
);
$settings->set_hero($hero);
// Tab: Online activation (required before other features work).
$page = new admin_settingpage('meetletacbfree_registration', get_string('tab_registration', 'meetletacbfree'));
$page->add(new admin_setting_heading(
'meetletacbfree/registrationheading',
get_string('registration_heading', 'meetletacbfree'),
get_string('registration_heading_desc', 'meetletacbfree')
));
$page->add(new admin_setting_configtext(
'meetletacbfree/registration_api_url',
get_string('registration_api_url', 'meetletacbfree'),
get_string('registration_api_url_desc', 'meetletacbfree'),
registration_manager::DEFAULT_API_URL,
PARAM_URL
));
$page->add(new \mod_meetletacbfree\admin\setting_registration());
$settings->add($page);
// Tab: Privacy (always visible — read policy before activating).
$page = new admin_settingpage('meetletacbfree_privacy', get_string('tab_privacy', 'meetletacbfree'));
$page->add(new admin_setting_heading(
'meetletacbfree/privacycard',
'',
privacy_policy::render()
));
$settings->add($page);
$registered = registration_manager::is_registered();
if ($registered) {
// Tab: Server setup guide.
$page = new admin_settingpage('meetletacbfree_serverguide', get_string('tab_serverguide', 'meetletacbfree'));
$page->add(new admin_setting_heading(
'meetletacbfree/serverguidecard',
'',
server_guide::render()
));
$settings->add($page);
// Tab 2: Server settings (API / admin / offline listener).
$page = new admin_settingpage('meetletacbfree_connection', get_string('settings_connection', 'meetletacbfree'));
$page->add(new admin_setting_heading(
'meetletacbfree/connectionheading',
get_string('settings_connection', 'meetletacbfree'),
get_string('settings_connection_desc', 'meetletacbfree')
));
$page->add(new admin_setting_heading(
'meetletacbfree/server_api_group',
'',
html_writer::div(
html_writer::tag('h4', get_string('server_group_api', 'meetletacbfree')) .
html_writer::tag('p', get_string('server_group_api_desc', 'meetletacbfree')),
'meetlet-server-group'
)
));
$page->add(new admin_setting_configtext(
'meetletacbfree/host', get_string('host', 'meetletacbfree'), get_string('host_desc', 'meetletacbfree'),
'https://connect.example.edu/api/xml', PARAM_URL
));
$page->add(new admin_setting_configtext(
'meetletacbfree/meethost', get_string('meethost', 'meetletacbfree'), get_string('meethost_desc', 'meetletacbfree'),
'connect.example.edu', PARAM_HOST
));
$page->add(new admin_setting_configtext(
'meetletacbfree/port', get_string('port', 'meetletacbfree'), get_string('port_desc', 'meetletacbfree'),
'443', PARAM_INT
));
$page->add(new admin_setting_configcheckbox(
'meetletacbfree/https', get_string('https', 'meetletacbfree'), get_string('https_desc', 'meetletacbfree'), 1
));
$page->add(new admin_setting_heading(
'meetletacbfree/server_admin_group',
'',
html_writer::div(
html_writer::tag('h4', get_string('server_group_admin', 'meetletacbfree')) .
html_writer::tag('p', get_string('server_group_admin_desc', 'meetletacbfree')),
'meetlet-server-group'
)
));
$page->add(new admin_setting_configtext(
'meetletacbfree/admin_login', get_string('admin_login', 'meetletacbfree'), get_string('admin_login_desc', 'meetletacbfree'),
'', PARAM_RAW_TRIMMED
));
$page->add(new admin_setting_configpasswordunmask(
'meetletacbfree/admin_password', get_string('admin_password', 'meetletacbfree'), get_string('admin_password_desc', 'meetletacbfree'), ''
));
$page->add(new admin_setting_configtext(
'meetletacbfree/admin_httpauth', get_string('admin_httpauth', 'meetletacbfree'), get_string('admin_httpauth_desc', 'meetletacbfree'),
'Generate-Safe-Random-Token', PARAM_TEXT
));
$page->add(new admin_setting_configcheckbox(
'meetletacbfree/email_login', get_string('email_login', 'meetletacbfree'), get_string('email_login_desc', 'meetletacbfree'), 1
));
$settings->add($page);
// Tab 4: Connection test (Ajax).
$page = new admin_settingpage('meetletacbfree_test', get_string('tab_connectiontest', 'meetletacbfree'));
$steplabels = [
'login' => get_string('testlogin', 'meetletacbfree'),
'folders' => get_string('testfolders', 'meetletacbfree'),
'user' => get_string('testuser', 'meetletacbfree'),
'sso' => get_string('testsso', 'meetletacbfree'),
'cleanup' => get_string('testcleanup', 'meetletacbfree'),
];
$testui = html_writer::div(
html_writer::start_div('meetlet-conntest__hero') .
html_writer::img($logo, 'Adobe Connect', ['class' => 'meetlet-conntest__logo']) .
html_writer::tag('h2', get_string('conntesttitle', 'meetletacbfree'), ['class' => 'meetlet-conntest__title']) .
html_writer::tag('p', get_string('conntestintro', 'meetletacbfree'), ['class' => 'meetlet-conntest__intro']) .
html_writer::end_div() .
html_writer::div(
html_writer::tag('button',
'<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">'
. '<path fill="currentColor" d="M8 5v14l11-7z"/></svg>'
. html_writer::span(get_string('runtest', 'meetletacbfree'), 'meetlet-btn-with-icon__label'),
[
'type' => 'button',
'class' => 'meetlet-settings-btn meetlet-btn-with-icon',
'data-meetlet-run-test' => '1',
]
) .
html_writer::span('', 'meetlet-conntest__status', ['data-meetlet-test-status' => '1']),
'meetlet-conntest__actions'
) .
html_writer::div(
html_writer::div(
html_writer::span('', 'meetlet-conntest__progress-text', ['data-meetlet-progress-label' => '1']),
'meetlet-conntest__progress-label'
) .
html_writer::div(
html_writer::div('', 'meetlet-conntest__progress-fill', ['data-meetlet-progress-fill' => '1']),
'meetlet-conntest__progress-track'
),
'meetlet-conntest__progress',
['data-meetlet-progress' => '1', 'hidden' => 'hidden']
) .
html_writer::div('', 'meetlet-conntest__grid', ['data-meetlet-test-grid' => '1']),
'meetlet-conntest',
[
'id' => 'meetlet-acb-conntest',
'data-endpoint' => $ajaxurl->out(false),
'data-sesskey' => sesskey(),
'data-steps' => implode(',', conntest_runner::STEPS),
'data-step-labels' => json_encode($steplabels, JSON_UNESCAPED_UNICODE),
'data-str-ok' => get_string('testok', 'meetletacbfree'),
'data-str-fail' => get_string('testfail', 'meetletacbfree'),
'data-str-running' => get_string('testrunning', 'meetletacbfree'),
'data-str-idle' => '',
'data-str-waiting' => get_string('testwaiting', 'meetletacbfree'),
'data-str-runningstep' => get_string('testrunningstep', 'meetletacbfree'),
'data-str-skipped' => get_string('testskipped', 'meetletacbfree'),
'data-str-progress' => get_string('testprogress', 'meetletacbfree'),
]
);
$page->add(new admin_setting_heading('meetletacbfree/testui', '', $testui));
$settings->add($page);
// Tab 4: Meeting settings (defaults + feature visibility).
$page = new admin_settingpage('meetletacbfree_meetings', get_string('tab_meetingsettings', 'meetletacbfree'));
$page->add(new admin_setting_heading(
'meetletacbfree/roomdefaultsheading',
get_string('roomdefaults', 'meetletacbfree'),
get_string('roomdefaults_desc', 'meetletacbfree')
));
$page->add(new admin_setting_configselect(
'meetletacbfree/default_meetinglang',
get_string('default_meetinglang', 'meetletacbfree'),
get_string('default_meetinglang_desc', 'meetletacbfree'),
'',
config::meeting_lang_options()
));
$page->add(new admin_setting_configcheckbox(
'meetletacbfree/default_waitforhost',
get_string('default_waitforhost', 'meetletacbfree'),
get_string('default_waitforhost_desc', 'meetletacbfree'),
0
));
$page->add(new admin_setting_heading(
'meetletacbfree/featuresheading',
get_string('featuresheading', 'meetletacbfree'),
get_string('featuresheading_desc', 'meetletacbfree')
));
$featuregroups = ['recordingstab', 'contenttab'];
foreach ($featuregroups as $feature) {
$grouphtml = html_writer::div(
html_writer::tag('h4', get_string('featuregroup_' . $feature, 'meetletacbfree')) .
html_writer::tag('p', get_string('featuregroup_' . $feature . '_desc', 'meetletacbfree')),
'meetlet-feature-group'
);
$page->add(new admin_setting_heading(
'meetletacbfree/featuregroup_' . $feature,
'',
$grouphtml
));
// ZIP download is off by default; other features stay on.
$enabledefault = ($feature === 'zip') ? 0 : 1;
$page->add(new admin_setting_configcheckbox(
'meetletacbfree/enable_' . $feature,
get_string('enable_' . $feature, 'meetletacbfree'),
get_string('enable_' . $feature . '_desc', 'meetletacbfree'),
$enabledefault
));
$page->add(new admin_setting_configcheckbox(
'meetletacbfree/allow_override_' . $feature,
get_string('allow_override_' . $feature, 'meetletacbfree'),
get_string('allow_override_' . $feature . '_desc', 'meetletacbfree'),
1
));
}
$settings->add($page);
// Tab 5: Role feature access + Adobe room role mapping.
$page = new admin_settingpage('meetletacbfree_access', get_string('tab_accesssettings', 'meetletacbfree'));
$page->add(new admin_setting_heading(
'meetletacbfree/rolemappingheading',
get_string('siterolemapping', 'meetletacbfree'),
get_string('siterolemapping_desc', 'meetletacbfree')
));
$page->add(new \mod_meetletacbfree\admin\setting_rolemapping());
$page->add(new admin_setting_heading(
'meetletacbfree/accessheading',
get_string('featureaccess', 'meetletacbfree'),
get_string('featureaccess_desc', 'meetletacbfree')
));
$page->add(new admin_setting_configcheckbox(
'meetletacbfree/activity_featureaccess',
get_string('activity_featureaccess', 'meetletacbfree'),
get_string('activity_featureaccess_desc', 'meetletacbfree'),
1
));
$page->add(new \mod_meetletacbfree\admin\setting_featureaccess());
$page->add(new admin_setting_heading(
'meetletacbfree/accessresetassets',
'',
\mod_meetletacbfree\admin\access_reset_ui::page_assets($resetajaxurl)
));
$settings->add($page);
} // End tabs unlocked after online activation.
// Tab: About developer / MeetLet (read-only; always visible).
$page = new admin_settingpage('meetletacbfree_about', get_string('tab_aboutdev', 'meetletacbfree'));
$meetletlogo = $OUTPUT->image_url('meetlet_logo', 'meetletacbfree');
$abouturl = new moodle_url('https://meetlet.net/', [
'utm_source' => 'moodle',
'utm_medium' => 'plugin',
'utm_campaign' => 'meetletacbfree',
'utm_content' => 'about_developer_tab',
]);
$about = html_writer::div(
html_writer::div(
html_writer::img($meetletlogo, 'MeetLet', ['alt' => 'MeetLet']),
'meetlet-about__brand'
) .
html_writer::tag('h4', get_string('about_heading', 'meetletacbfree')) .
html_writer::tag('p', get_string('about_body_p1', 'meetletacbfree')) .
html_writer::tag('p', get_string('about_body_p2', 'meetletacbfree')) .
html_writer::tag('p', get_string('about_body_p3', 'meetletacbfree')) .
html_writer::tag('p', get_string('about_body_p4', 'meetletacbfree')) .
html_writer::tag('p', get_string('marketplace_commercial_note', 'meetletacbfree'), [
'class' => 'meetlet-about__commercial',
]) .
html_writer::div(
html_writer::link($abouturl, get_string('about_visit_website', 'meetletacbfree'), [
'class' => 'meetlet-about__cta',
'target' => '_blank',
'rel' => 'noopener',
]),
'meetlet-about__cta-wrap'
),
'meetlet-about meetlet-settings-card'
);
$page->add(new admin_setting_heading('meetletacbfree/aboutcard', '', $about));
$settings->add($page);
}