diff --git a/README.md b/README.md index 62ffdfa..1e041a3 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ - [EM Settings](#em-settings) - [System Settings](#system-settings) - [Project Settings](#project-settings) + - [Custom Header Logo](#custom-header-logo) - [Translation](#translation) - [REDCapPRO Project Menu](#redcappro-project-menu) - [Home Tab](#home-tab) @@ -128,6 +129,9 @@ These are settings/configuration options accessible in the normal External Modul | **Allow Auto-Enroll Upon Self-Registration** | Checkbox | Allow participants to enroll themselves in a project when they register. If checked, the participant will be automatically enrolled in the REDCapPRO project when they self-register | Unchecked | | **reCaptcha Site Key** | Text | The site key for the reCaptcha v3 service. This is used to prevent bots from registering. *Note: You **cannot** use the same site key as the one utilized by REDCap on surveys, because that site key is a v2 key.* | (blank) | | **reCaptcha Secret Key** | Text | The secret key for the reCaptcha v3 service. This is used to prevent bots from registering. *Note: You **cannot** use the same secret key as the one utilized by REDCap on surveys, because that secret key is a v2 key.* | (blank) | +| **System Header Logo Image** | File | Upload an image file to use as the default logo on all participant-facing pages. Accepted formats: JPG, PNG, GIF, SVG, WebP. Maximum size: 2 MB. | (blank) | +| **Use System Logo** | Checkbox | Display the uploaded system logo on participant-facing pages. Uncheck to revert to the original default REDCapPRO logo without removing the uploaded file. Only shown when a system logo file has been uploaded. | Unchecked | +| **Allow Custom Project Logos** | Checkbox | Allow project administrators to upload a custom logo that appears in participant-facing page headers. If disabled, all projects display the system logo (or the original default if no system logo is set). See [Custom Header Logo](#custom-header-logo). | Unchecked | | **Enable the API** | Checkbox | Enable the API for this system. This allows you to register and enroll participants using the [API](#api). | Unchecked | | **Restrict API project settings to REDCap administrators** | Checkbox | If checked, only REDCap administrators will be able to access the API settings in the project. If unchecked, any REDCapPRO manager will be able to access the API settings. | Unchecked | @@ -135,6 +139,25 @@ These are settings/configuration options accessible in the normal External Modul Project configuration is done within the project's **REDCapPRO** menu. +### Custom Header Logo + +**REDCapPRO** supports custom branding by allowing a logo image to be displayed in the header of all participant-facing pages (login, password reset, etc.). The logo is resolved in the following priority order: + +1. **Project logo** — if the system permits custom project logos and the project has uploaded one, it is shown. +2. **System logo** — if a system-level logo has been uploaded and enabled, it is used as the default across all projects. +3. **Default** — the original REDCapPRO logo (`RCPro_Logo_Alternate.svg`) is shown. + +Custom logos are only shown on **participant-facing pages**. Project staff pages always display the standard REDCapPRO logo. + +**System-level configuration** (Control Center → External Modules → REDCapPRO): +- Upload a logo file with **System Header Logo Image**. +- Toggle it on/off with **Use System Logo** without deleting the file. +- Grant projects the ability to override it with **Allow Custom Project Logos**. + +**Project-level configuration** (REDCapPRO Project Menu → Settings): +- Upload a per-project logo with **Header Logo** (only visible when **Allow Custom Project Logos** is enabled at the system level). +- Remove the custom logo by checking the *Remove custom logo and restore the default* checkbox and saving. + ### Translation This external module makes use of the built-in text translation functions in REDCap's External Module framework. These functions use `.ini` files (located in the [lang](lang) directory of this module's source code) to replace placeholder text with the equivalent translated text. diff --git a/config.json b/config.json index 4ca0ab1..68d7633 100644 --- a/config.json +++ b/config.json @@ -119,6 +119,35 @@ "name": "
reCAPTCHA Secret Key:

Secret key for reCAPTCHA v3 (default is empty)
You cannot use the same secret key that you use for REDCap surveys, since that is a v2 key. This must be a v3 key", "type": "password" }, + { + "key": "system-header-logo-descriptive", + "name": "system_header_logo_descriptive", + "tt_name": true, + "type": "descriptive" + }, + { + "key": "system-header-logo-file", + "name": "system_header_logo_file", + "tt_name": true, + "type": "file" + }, + { + "key": "system-header-logo-enabled", + "name": "system_header_logo_enabled", + "tt_name": true, + "type": "checkbox", + "branchingLogic": { + "field": "system-header-logo-file", + "op": "<>", + "value": "" + } + }, + { + "key": "allow-custom-logo-system", + "name": "allow_custom_logo_system", + "tt_name": true, + "type": "checkbox" + }, { "key": "api-descriptive", "name": "
API Settings

These settings control the use of the API. Please take care to understand how the API may be used before enabling it in the system.

", diff --git a/lang/Chinese.ini b/lang/Chinese.ini index 5a976d2..d135e77 100644 --- a/lang/Chinese.ini +++ b/lang/Chinese.ini @@ -228,3 +228,17 @@ mfa_messaging5 = "请稍等..." + +project_settings_header_logo = "页眉标志" +project_settings_header_logo_desc = "上传自定义标志以显示在参与者页面页眉中。留空以使用默认 REDCapPRO 标志。" +project_settings_header_logo_upload_label = "上传标志图片" +project_settings_header_logo_upload_hint = "接受格式:JPG、PNG、GIF、SVG、WebP。最大大小:2 MB。" +project_settings_header_logo_current = "当前标志" +project_settings_header_logo_clear = "删除自定义标志并恢复默认值" +project_settings_header_logo_preview = "预览" +project_settings_header_logo_type_err = "无效的文件类型。请上传 JPG、PNG、GIF、SVG 或 WebP 图片。" +project_settings_header_logo_size_err = "图片文件太大。最大允许大小为 2 MB。" +system_header_logo_descriptive = "
系统页眉标志设置

这些设置控制参与者页面页眉中显示的标志。可以在此处上传系统级标志作为默认标志。如果启用了自定义项目标志选项,各个项目可以提供自己的标志。

" +system_header_logo_file = "
系统页眉标志图片:

上传图片文件以用作所有参与者页面的默认标志。接受格式:JPG、PNG、GIF、SVG、WebP。最大大小:2 MB。" +system_header_logo_enabled = "
使用系统标志:

在参与者页面上显示上传的系统标志。取消选中以在不删除上传文件的情况下恢复为原始默认 REDCapPRO 标志。" +allow_custom_logo_system = "
允许自定义项目标志:

是否允许项目管理员上传出现在参与者页面页眉中的自定义标志?如果禁用,所有项目将显示系统标志(如果未设置系统标志,则显示原始默认标志)。(默认为否)" diff --git a/lang/Deutsch.ini b/lang/Deutsch.ini index d79aa98..e5a1989 100644 --- a/lang/Deutsch.ini +++ b/lang/Deutsch.ini @@ -216,4 +216,17 @@ mfa_messaging1 = "Fehler beim Senden der E-Mail" mfa_messaging2 = "Fehler beim Anzeigen der MFA-Informationen" mfa_messaging3 = "Fehler beim Senden der Authenticator-Informationen" mfa_messaging4 = "E-Mail mit Authentifikatorinformationen gesendet" -mfa_messaging5 = "Bitte warten…" \ No newline at end of file +mfa_messaging5 = "Bitte warten…" +project_settings_header_logo = "Kopfzeilen-Logo" +project_settings_header_logo_desc = "Laden Sie ein benutzerdefiniertes Logo hoch, das in der Kopfzeile der Teilnehmerseiten angezeigt wird. Leer lassen, um das Standard-REDCapPRO-Logo zu verwenden." +project_settings_header_logo_upload_label = "Logo-Bild hochladen" +project_settings_header_logo_upload_hint = "Akzeptierte Formate: JPG, PNG, GIF, SVG, WebP. Maximale Größe: 2 MB." +project_settings_header_logo_current = "Aktuelles Logo" +project_settings_header_logo_clear = "Benutzerdefiniertes Logo entfernen und Standard wiederherstellen" +project_settings_header_logo_preview = "Vorschau" +project_settings_header_logo_type_err = "Ungültiger Dateityp. Bitte laden Sie ein JPG-, PNG-, GIF-, SVG- oder WebP-Bild hoch." +project_settings_header_logo_size_err = "Die Bilddatei ist zu groß. Die maximal zulässige Größe beträgt 2 MB." +system_header_logo_descriptive = "
Systemkopfzeilen-Logo Einstellungen

Diese Einstellungen steuern das in den Seitenköpfen der Teilnehmerseiten angezeigte Logo. Hier kann ein systemweites Logo hochgeladen und als Standard verwendet werden. Einzelne Projekte können ihr eigenes Logo bereitstellen, wenn die benutzerdefinierte Projektlogo-Option aktiviert ist.

" +system_header_logo_file = "
Systemkopfzeilen-Logo Bild:

Laden Sie eine Bilddatei hoch, die als Standard-Logo auf allen Teilnehmerseiten verwendet wird. Akzeptierte Formate: JPG, PNG, GIF, SVG, WebP. Maximale Größe: 2 MB." +system_header_logo_enabled = "
Systemlogo verwenden:

Das hochgeladene Systemlogo auf Teilnehmerseiten anzeigen. Deaktivieren, um ohne Löschen der hochgeladenen Datei zum ursprünglichen Standard-REDCapPRO-Logo zurückzukehren." +allow_custom_logo_system = "
Benutzerdefinierte Projektlogos erlauben:

Sollen Projektadministratoren ein benutzerdefiniertes Logo hochladen dürfen, das in der Teilnehmerseitenkopfzeile erscheint? Wenn deaktiviert, zeigen alle Projekte das Systemlogo an (oder den ursprünglichen Standard, wenn kein Systemlogo gesetzt ist). (Standard: Nein)" diff --git a/lang/English.ini b/lang/English.ini index ead6def..6660c27 100644 --- a/lang/English.ini +++ b/lang/English.ini @@ -231,3 +231,17 @@ enrollment_failed_message1 = "Sorry, but we were not able to enroll you in this + +system_header_logo_descriptive = "
System Header Logo Settings

These settings control the logo displayed in participant-facing page headers. A system-wide logo can be uploaded here and used as the default. Individual projects may supply their own logo if the custom project logo option is enabled.

" +system_header_logo_file = "
System Header Logo Image:

Upload an image file to use as the default logo on all participant-facing pages. Accepted formats: JPG, PNG, GIF, SVG, WebP. Maximum size: 2 MB." +system_header_logo_enabled = "
Use System Logo:

Display the uploaded system logo on participant-facing pages. Uncheck to revert to the original default REDCapPRO logo without removing the uploaded file." +allow_custom_logo_system = "
Allow Custom Project Logos:

Should project administrators be allowed to upload a custom logo that appears in the participant-facing header? If disabled, all projects will display the system logo (or the original default if no system logo is set). (default is No)" +project_settings_header_logo = "Header Logo" +project_settings_header_logo_desc = "Upload a custom logo to display in the participant-facing header. Leave empty to use the default REDCapPRO logo." +project_settings_header_logo_upload_label = "Upload Logo Image" +project_settings_header_logo_upload_hint = "Accepted formats: JPG, PNG, GIF, SVG, WebP. Maximum size: 2 MB." +project_settings_header_logo_current = "Current Logo" +project_settings_header_logo_clear = "Remove custom logo and restore the default" +project_settings_header_logo_preview = "Preview" +project_settings_header_logo_type_err = "Invalid file type. Please upload a JPG, PNG, GIF, SVG, or WebP image." +project_settings_header_logo_size_err = "Image file is too large. Maximum allowed size is 2 MB." diff --git "a/lang/Espa\303\261ol.ini" "b/lang/Espa\303\261ol.ini" index a53a817..2c3d808 100644 --- "a/lang/Espa\303\261ol.ini" +++ "b/lang/Espa\303\261ol.ini" @@ -216,4 +216,17 @@ mfa_messaging1 = "Error al enviar el correo electrónico" mfa_messaging2 = "Error al mostrar la información de MFA" mfa_messaging3 = "Error al enviar información del autenticador" mfa_messaging4 = "Correo electrónico enviado con información del autenticador" -mfa_messaging5 = "Por favor espere..." \ No newline at end of file +mfa_messaging5 = "Por favor espere..." +project_settings_header_logo = "Logo del encabezado" +project_settings_header_logo_desc = "Suba un logo personalizado para mostrar en el encabezado de las páginas de participantes. Déjelo vacío para usar el logo predeterminado de REDCapPRO." +project_settings_header_logo_upload_label = "Subir imagen del logo" +project_settings_header_logo_upload_hint = "Formatos aceptados: JPG, PNG, GIF, SVG, WebP. Tamaño máximo: 2 MB." +project_settings_header_logo_current = "Logo actual" +project_settings_header_logo_clear = "Eliminar logo personalizado y restaurar el predeterminado" +project_settings_header_logo_preview = "Vista previa" +project_settings_header_logo_type_err = "Tipo de archivo no válido. Por favor, suba una imagen JPG, PNG, GIF, SVG o WebP." +project_settings_header_logo_size_err = "El archivo de imagen es demasiado grande. El tamaño máximo permitido es 2 MB." +system_header_logo_descriptive = "
Configuración del logo del encabezado del sistema

Estos ajustes controlan el logo que se muestra en los encabezados de las páginas de participantes. Se puede subir un logo a nivel de sistema aquí para usarlo como predeterminado. Los proyectos individuales pueden proporcionar su propio logo si la opción de logo de proyecto personalizado está habilitada.

" +system_header_logo_file = "
Imagen del logo del encabezado del sistema:

Suba un archivo de imagen para usarlo como logo predeterminado en todas las páginas de participantes. Formatos aceptados: JPG, PNG, GIF, SVG, WebP. Tamaño máximo: 2 MB." +system_header_logo_enabled = "
Usar logo del sistema:

Mostrar el logo del sistema subido en las páginas de participantes. Desmarque para volver al logo predeterminado original de REDCapPRO sin eliminar el archivo subido." +allow_custom_logo_system = "
Permitir logos de proyecto personalizados:

¿Deben los administradores de proyecto poder subir un logo personalizado que aparezca en el encabezado de las páginas de participantes? Si está desactivado, todos los proyectos mostrarán el logo del sistema (o el logo predeterminado original si no hay logo del sistema configurado). (el valor predeterminado es No)" diff --git "a/lang/Fran\303\247ais.ini" "b/lang/Fran\303\247ais.ini" index 692d4cd..275639a 100644 --- "a/lang/Fran\303\247ais.ini" +++ "b/lang/Fran\303\247ais.ini" @@ -216,4 +216,17 @@ mfa_messaging1 = "Erreur lors de l'envoi de l'e-mail" mfa_messaging2 = "Erreur lors de l'affichage des informations MFA" mfa_messaging3 = "Erreur lors de l'envoi des informations sur l'authentificateur" mfa_messaging4 = "E-mail envoyé avec les informations de l'authentificateur" -mfa_messaging5 = "Veuillez patienter..." \ No newline at end of file +mfa_messaging5 = "Veuillez patienter..." +project_settings_header_logo = "Logo d'en-tête" +project_settings_header_logo_desc = "Téléchargez un logo personnalisé à afficher dans l'en-tête des pages destinées aux participants. Laissez vide pour utiliser le logo REDCapPRO par défaut." +project_settings_header_logo_upload_label = "Télécharger une image de logo" +project_settings_header_logo_upload_hint = "Formats acceptés : JPG, PNG, GIF, SVG, WebP. Taille maximale : 2 Mo." +project_settings_header_logo_current = "Logo actuel" +project_settings_header_logo_clear = "Supprimer le logo personnalisé et restaurer le logo par défaut" +project_settings_header_logo_preview = "Aperçu" +project_settings_header_logo_type_err = "Type de fichier invalide. Veuillez télécharger une image JPG, PNG, GIF, SVG ou WebP." +project_settings_header_logo_size_err = "Le fichier image est trop volumineux. La taille maximale autorisée est de 2 Mo." +system_header_logo_descriptive = "
Paramètres du logo d'en-tête système

Ces paramètres contrôlent le logo affiché dans les en-têtes des pages destinées aux participants. Un logo à l'échelle du système peut être téléchargé ici et utilisé par défaut. Les projets individuels peuvent fournir leur propre logo si l'option de logo de projet personnalisé est activée.

" +system_header_logo_file = "
Image du logo d'en-tête système:

Téléchargez un fichier image à utiliser comme logo par défaut sur toutes les pages destinées aux participants. Formats acceptés : JPG, PNG, GIF, SVG, WebP. Taille maximale : 2 Mo." +system_header_logo_enabled = "
Utiliser le logo système:

Afficher le logo système téléchargé sur les pages destinées aux participants. Décochez pour revenir au logo REDCapPRO par défaut sans supprimer le fichier téléchargé." +allow_custom_logo_system = "
Autoriser les logos de projet personnalisés:

Les administrateurs de projet doivent-ils être autorisés à télécharger un logo personnalisé qui apparaît dans l'en-tête des pages destinées aux participants ? Si désactivé, tous les projets afficheront le logo système (ou le logo par défaut original si aucun logo système n'est défini). (la valeur par défaut est Non)" diff --git a/src/classes/UI.php b/src/classes/UI.php index d1123e8..7c2662e 100644 --- a/src/classes/UI.php +++ b/src/classes/UI.php @@ -13,6 +13,24 @@ function __construct($module) public function ShowParticipantHeader(string $title) { + $customLogoEnabled = (bool) $this->module->framework->getSystemSetting('allow-custom-logo-system'); + $customLogo = $customLogoEnabled ? $this->module->framework->getProjectSetting('project-header-logo') : null; + if ( !empty($customLogo) ) { + $participantLogo = $customLogo; + } else { + $systemLogoEnabled = (bool) $this->module->framework->getSystemSetting('system-header-logo-enabled'); + $systemLogoEdoc = $this->module->framework->getSystemSetting('system-header-logo-file'); + if ( $systemLogoEnabled && !empty($systemLogoEdoc) ) { + try { + [$mime, , $content] = \REDCap::getFile($systemLogoEdoc); + $participantLogo = 'data:' . $mime . ';base64,' . base64_encode($content); + } catch ( \Throwable $e ) { + $participantLogo = $this->module->getUrl('images/RCPro_Logo_Alternate.svg'); + } + } else { + $participantLogo = $this->module->getUrl('images/RCPro_Logo_Alternate.svg'); + } + } echo ' @@ -29,16 +47,19 @@ public function ShowParticipantHeader(string $title) -
-
- +
+
+
+ +
+
+

' . $title . '

'; } diff --git a/src/settings.php b/src/settings.php index d0200b3..c83753c 100644 --- a/src/settings.php +++ b/src/settings.php @@ -43,6 +43,7 @@ $showApi = $allowApiSystem && ($isAdmin || !$module->framework->getSystemSetting("api-require-admin")); $showSelfRegistration = $allowSelfRegistrationSystem && ($isAdmin || !$module->framework->getSystemSetting("self-registration-require-admin")); $showTimeoutTimeSetting = $module->framework->getSystemSetting("allow-project-timeout-time-override"); +$showCustomLogo = (bool) $module->framework->getSystemSetting("allow-custom-logo-system"); // Update settings if requested if ( $_SERVER["REQUEST_METHOD"] == "POST" ) { @@ -67,6 +68,28 @@ // Validate Prevent Email Login $new_settings["prevent-email-login"] = $post_settings["prevent-email-login"] === "true"; + // Validate Header Logo Upload + if ( $showCustomLogo ) { + $clearLogo = isset($post_settings["project-header-logo-clear"]) && $post_settings["project-header-logo-clear"] === "on"; + if ( $clearLogo ) { + $new_settings["project-header-logo"] = null; + } elseif ( isset($_FILES["project-header-logo-file"]) && $_FILES["project-header-logo-file"]["error"] === UPLOAD_ERR_OK ) { + $allowedTypes = ["image/jpeg", "image/png", "image/gif", "image/svg+xml", "image/webp"]; + $maxSize = 2 * 1024 * 1024; // 2 MB + $file = $_FILES["project-header-logo-file"]; + if ( !in_array($file["type"], $allowedTypes, true) ) { + $header_logo_err = $module->tt("project_settings_header_logo_type_err"); + $any_err = true; + } elseif ( $file["size"] > $maxSize ) { + $header_logo_err = $module->tt("project_settings_header_logo_size_err"); + $any_err = true; + } else { + $imageData = base64_encode(file_get_contents($file["tmp_name"])); + $new_settings["project-header-logo"] = "data:{$file['type']};base64,{$imageData}"; + } + } + } + // Validate Primary Contact $new_settings["pc-name"] = \REDCap::escapeHtml($post_settings["pc-name"]); $new_settings["pc-email"] = \REDCap::escapeHtml($post_settings["pc-email"]); @@ -434,6 +457,48 @@ class="form-control
+ +
+
+ + + + + tt("project_settings_header_logo"); ?> +
+
+
+ tt("project_settings_header_logo_desc"); ?> +
+ + +
+
+ Current Logo +
+
+ + +
+ +
+ + +
tt("project_settings_header_logo_upload_hint"); ?>
+ + + +
+ +
+
+
+
@@ -494,6 +559,23 @@ class="form-control " form.addEventListener('change', function () { $('#rcpro-submit-button').attr("disabled", null); }); + // Logo file preview + document.getElementById('project-header-logo-file').addEventListener('change', function () { + const file = this.files[0]; + const container = document.getElementById('logo-preview-container'); + const preview = document.getElementById('logo-preview'); + if (file) { + const reader = new FileReader(); + reader.onload = function (e) { + preview.src = e.target.result; + container.style.display = 'block'; + }; + reader.readAsDataURL(file); + } else { + container.style.display = 'none'; + preview.src = ''; + } + }); const isChecked = $('#allow-self-registration-form-check').get(0).checked; if (!isChecked) {