================================================================================
  GOOGLE CALENDAR SYNC PLUS - DOCUMENTAZIONE install.php e manifest.xml
  Analisi del pacchetto con codice e commenti su cosa fa ogni parte
================================================================================

================================================================================
PARTE 1 - MANIFEST.XML
================================================================================
Il manifest definisce metadati del modulo, licenza, tabelle create dall'installer
VTE e l'elenco dei file inclusi nel pacchetto. Viene usato dal sistema di
installazione moduli (es. Module Manager) per sapere cosa installare.

--------------------------------------------------------------------------------
SEZIONE: Intestazione modulo
--------------------------------------------------------------------------------
- name: nome tecnico del modulo (GoogleSyncPlus)
- label: etichetta visuale (Google Calendar Sync Plus)
- parent: categoria (Tools)
- version: versione del plugin (2.2.5)
- short_description: descrizione breve
- dependencies / vtiger_version: versione minima VTE richiesta (25.02)

--------------------------------------------------------------------------------
SEZIONE: license (inline)
--------------------------------------------------------------------------------
Testo della licenza d'uso Pantarei: titolare diritti, concessione licenza,
diritti e limitazioni, proprietà intellettuale, aggiornamenti, supporto,
garanzia, risoluzione, legge applicabile. L'installazione implica accettazione.

--------------------------------------------------------------------------------
SEZIONE: tables
--------------------------------------------------------------------------------
Definisce le tabelle che il modulo può creare (se l'installer le gestisce).
Qui sono dichiarate solo le due tabelle "custom" del plugin (la terza
vte_gspl_user_seats è creata solo da install.php, non dal manifest).

  - vte_googlesyncplus_map: mapping evento Google <-> attività VTE
    (google_id, crmid, userid, calendar_id, last_sync, google_updated)
  - vte_googlesyncplus_otp: OTP per verifica email (registrazione licenza)
    (id, userid, email, otp_hash, expires_at, attempts, sent_at, created_at)

--------------------------------------------------------------------------------
SEZIONE: files
--------------------------------------------------------------------------------
Elenco di tutti i file del modulo inclusi nel pacchetto. Il package manager
copia/estrae questi path dalla zip. Include:
  - PHP core: GoogleSyncPlus.php, install.php, uninstall.php, auth.php,
    SyncToGoogle.php, cron_sync.php, EventHandler.php, License.php, Settings*.php
  - JS: injector.js, calendar_button.js, Settings/Admin.js
  - Altri: index.php, flush_js.php, fix_links.php, debug_links.php,
    ota_public.pem, language/*.lang.php, .htaccess, README.txt

--------------------------------------------------------------------------------
CODICE MANIFEST.XML (integrale)
--------------------------------------------------------------------------------

<?xml version="1.0"?>
<module>
    <name>GoogleSyncPlus</name>
    <label>Google Calendar Sync Plus</label>
    <parent>Tools</parent>
    <version>2.2.5</version>
    <short_description>Sincronizzazione Bidirezionale Avanzata Google Calendar</short_description>
    <dependencies>
        <vtiger_version>25.02</vtiger_version>
    </dependencies>
    <license>
        <inline><![CDATA[
LICENZA D'USO DEL PLUGIN
Pantarei Informatica Srl – VTE NEXT
[... testo licenza ...]
© Pantarei Informatica Srl – Tutti i diritti riservati
        ]]></inline>
    </license>
    <tables>
        <table>
            <name>vte_googlesyncplus_map</name>
            <sql><![CDATA[CREATE TABLE IF NOT EXISTS `vte_googlesyncplus_map` (
  `google_id` varchar(255) NOT NULL,
  `crmid` int(19) NOT NULL,
  `userid` int(19) NOT NULL,
  `calendar_id` varchar(255) DEFAULT 'primary',
  `last_sync` datetime DEFAULT NULL,
  `google_updated` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`google_id`,`userid`),
  KEY `crmid` (`crmid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8]]></sql>
        </table>
        <table>
            <name>vte_googlesyncplus_otp</name>
            <sql><![CDATA[CREATE TABLE IF NOT EXISTS `vte_googlesyncplus_otp` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userid` int(19) NOT NULL,
  `email` varchar(255) NOT NULL,
  `otp_hash` varchar(255) NOT NULL,
  `expires_at` datetime NOT NULL,
  `attempts` int(11) NOT NULL DEFAULT 0,
  `sent_at` datetime NOT NULL,
  `created_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_user_email` (`userid`,`email`),
  KEY `idx_expires` (`expires_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8]]></sql>
        </table>
    </tables>
    <files>
        <!-- elenco file: GoogleSyncPlus.php, install.php, uninstall.php, auth.php,
             SyncToGoogle.php, injector.js, calendar_button.js, cron_sync.php,
             EventHandler.php, License.php, index.php, flush_js.php, fix_links.php,
             debug_links.php, Settings.php, SettingsAjax.php, Settings/*.php, Admin.js,
             language/it_it.lang.php, language/en_us.lang.php, .htaccess, README.txt,
             ota_public.pem -->
    </files>
    <exporttime>2025-12-18 12:00:00</exporttime>
</module>


================================================================================
PARTE 2 - INSTALL.PHP
================================================================================
Lo script di installazione viene eseguito una tantum (o a ogni re-install/upgrade)
quando si installa il modulo. Imposta proprietà globali, colonne, blocchi/campi,
traduzioni, tabelle, link JS, event handler, cron, voce Settings, patch e permessi.

--------------------------------------------------------------------------------
BLOCCO 0 - Default globali (VTEProperties / vte_vteprop)
--------------------------------------------------------------------------------
Imposta chiavi globali usate dal plugin, solo se non già presenti:
  - gspl.meet_default = true (creazione automatica link Meet negli eventi)
  - gspl.oauth_mode = 'proxy' o 'native' (da $GLOBALS['GSPL_OAUTH_MODE'] se definito)

--------------------------------------------------------------------------------
BLOCCO 1 - Colonne in vte_users
--------------------------------------------------------------------------------
Aggiunge alla tabella users quattro colonne (solo se non esistono):
  - google_sync_calendars (TEXT): ID calendari Google da sincronizzare (virgola)
  - google_sync_target_calendar (VARCHAR 255): calendario destinazione VTE→Google
  - google_sync_direction (VARCHAR 50): bidirectional | vte_to_google | google_to_vte
  - google_sync_use_meet (TINYINT 1): override utente per usare Google Meet (NULL = default)

--------------------------------------------------------------------------------
BLOCCO 2 - Blocco e campi nel modulo Users
--------------------------------------------------------------------------------
  - Cerca o crea il blocco con label LBL_GOOGLE_SYNC_PLUS (o riusa "Sincronizzazione Calendari")
  - Crea il campo google_sync_calendars (textarea, readonly 99, modifica da widget)
  - Crea il campo google_sync_use_meet (checkbox, readonly 99)
  - Forza readonly=99 sui due campi in vte_field per il tabid Users

--------------------------------------------------------------------------------
BLOCCO 2b - Campo "Calendario Google destinazione" in Calendar (Activity)
--------------------------------------------------------------------------------
  - Aggiunge colonna cf_gspl_dest_calendar in vte_activitycf se manca
  - Registra il campo gspl_dest_calendar nel modulo Calendar (blocco LBL_CUSTOM_INFORMATION)
    per permettere di scegliere su quale calendario Google inviare l'evento

--------------------------------------------------------------------------------
BLOCCO 3 - Traduzioni
--------------------------------------------------------------------------------
  - sdk_language: inserisce/aggiorna LBL_GOOGLE_SYNC_PLUS, LBL_GSPL_SETTINGS,
    LBL_GSPL_SETTINGS_DESC per moduli Users, Settings, APP_STRINGS (it_it e en_us)
  - Backup: inietta 'LBL_GOOGLE_SYNC_PLUS' in modules/Users/language/it_it.lang.php se assente
  - Crea/scrive modules/GoogleSyncPlus/language/it_it.lang.php e en_us.lang.php
    (etichette modulo + LBL_GSPL_INVITATION_CANCELLED, LBL_GSPL_EVENT_CANCELLED_BODY)

--------------------------------------------------------------------------------
BLOCCO 4 - Tabelle custom
--------------------------------------------------------------------------------
  - vte_googlesyncplus_map: mapping google_id <-> crmid per userid/calendar_id (sync)
  - vte_gspl_user_seats: assegnazione posti licenza (userid, assigned_at)
  - vte_googlesyncplus_otp: OTP per verifica email (registrazione licenza)

--------------------------------------------------------------------------------
BLOCCO 5 - Registrazione script JS (vte_links)
--------------------------------------------------------------------------------
  - Elimina eventuali link precedenti con gli stessi linklabel
  - Inserisce HEADERSCRIPT:
    - GoogleSyncPlus_JS (injector.js) su tab Users e tab Settings
    - GoogleSyncPlus_JS_Cal / GoogleSyncPlus_JS_Evt (calendar_button.js) su Calendar e Events
    - GoogleSyncPlus_JS_Settings (injector.js) su Settings
  - URL con ?v=2.2.5 per cache-buster

--------------------------------------------------------------------------------
BLOCCO 6 - Event Handler
--------------------------------------------------------------------------------
Registra GoogleSyncPlusHandler in VTEventsManager per:
  - vtiger.entity.beforesave
  - vtiger.entity.aftersave
  - vtiger.entity.beforedelete
File: modules/GoogleSyncPlus/EventHandler.php

--------------------------------------------------------------------------------
BLOCCO 7 - Cron Job
--------------------------------------------------------------------------------
Registra il cron "GoogleSyncPlus" (CronUtils):
  - fileName: modules/GoogleSyncPlus/cron_sync.php
  - repeat: 60 secondi, timeout 300, maxAttempts 5
  - Se esiste già un cron con nome diverso (es. path vecchio), aggiorna il fileName

--------------------------------------------------------------------------------
BLOCCO 8 - Visibilità modulo
--------------------------------------------------------------------------------
Nasconde il modulo dal menu principale:
  - vte_tab: presence = 1 per il tabid GoogleSyncPlus
  - vte_parenttabrel: rimuove collegamento al parent tab
  - tbl_s_menu_modules: rimuove dal menu moduli

--------------------------------------------------------------------------------
BLOCCO 9 - Voce Impostazioni (Settings)
--------------------------------------------------------------------------------
  - Cerca il blocco LBL_OTHER_SETTINGS (SettingsUtils)
  - Se esiste già una voce con nome LBL_GSPL_SETTINGS / Google Sync Plus / Google Calendar Sync Plus:
    aggiorna name, description, linkto in vte_settings_field
  - Altrimenti inserisce nuova riga in vte_settings_field (linkto = index.php?module=GoogleSyncPlus&action=Settings&parenttab=Settings)

--------------------------------------------------------------------------------
BLOCCO 9a - Pulizia vecchi file Settings
--------------------------------------------------------------------------------
Rimuove eventuali file obsoleti della vecchia struttura Settings nel core:
  - modules/Settings/GoogleSyncPlus/ (directory)
  - modules/Settings/GoogleSyncPlus.php (wrapper)

--------------------------------------------------------------------------------
BLOCCO 10 - Fix label blocco Users
--------------------------------------------------------------------------------
Aggiorna in vte_blocks il blocklabel del blocco Google Sync nel modulo Users:
  da LBL_GOOGLE_SYNC_PLUS o "Calendari Google Extra" a "Google Calendar Sync Plus"
  (così in interfaccia non si vede la chiave di traduzione)

--------------------------------------------------------------------------------
BLOCCO 11 - Cache
--------------------------------------------------------------------------------
Elimina file di cache per forzare ricaricamento menu e lingue:
  - cache/sys/getMenuModuleList.json
  - cache/sys/getMenuLayout.json
  - cache/sys/SDK/vte_languages/*.json

--------------------------------------------------------------------------------
BLOCCO 12 - config_override.php (mail override)
--------------------------------------------------------------------------------
Aggiunge in config_override.php un blocco COMMENTATO che carica
modules/GoogleSyncPlus/send_mail_bootstrap.php (override send_mail per togliere
ICS dagli inviti e evitare doppio evento in Gmail). Disabilitato di default
perché su alcune installazioni causa pagina bianca sul Calendario.

--------------------------------------------------------------------------------
BLOCCO 13 - Patch Activity.php (mail evento annullato)
--------------------------------------------------------------------------------
Inserisce in modules/Calendar/Activity.php (in prossimità della chiamata a
CRMEntity::trash per eliminazione evento) una chiamata a
gspl_send_cancellation_emails() definita in SendCancellationEmails.php,
così alla cancellazione di un evento vengono inviate email "Invito annullato"
agli invitati. Cerca il marker crmv@209426 o la stringa // crmv@189362e e
CRMEntity::trash per posizionare il blocco.

--------------------------------------------------------------------------------
BLOCCO 14 - Permessi file/cartelle
--------------------------------------------------------------------------------
Funzione gspl_install_set_permissions: ricorsivamente imposta 0755 su directory
e 0644 su file nella cartella del modulo (e 0644 su logs/gs_license.dat se esiste),
così la disinstallazione via web può cancellare i file.

--------------------------------------------------------------------------------
CODICE INSTALL.PHP (integrale con commenti inline)
--------------------------------------------------------------------------------

<?php
// modules/GoogleSyncPlus/install.php
chdir(dirname(__FILE__) . '/../../');
require_once('include/utils/utils.php');
require_once('include/database/PearDatabase.php');

global $adb, $table_prefix;

/**
 * Imposta permessi ricorsivi su directory e file (necessari per uninstall che deve poter cancellare).
 * Directory: 0755, File: 0644.
 */
function gspl_install_set_permissions($dirOrFile) {
    if (!file_exists($dirOrFile)) return 0;
    $count = 0;
    if (is_dir($dirOrFile)) {
        @chmod($dirOrFile, 0755);
        $count++;
        foreach (new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($dirOrFile, RecursiveDirectoryIterator::SKIP_DOTS | RecursiveDirectoryIterator::FOLLOW_SYMLINKS),
            RecursiveIteratorIterator::SELF_FIRST
        ) as $item) {
            if ($item->isDir()) {
                @chmod($item->getPathname(), 0755);
            } else {
                @chmod($item->getPathname(), 0644);
            }
            $count++;
        }
    } else {
        @chmod($dirOrFile, 0644);
        $count = 1;
    }
    return $count;
}

echo "<h2>Installazione GoogleSyncPlus</h2><hr>";

// 0. Default globale Google Meet in vte_vteprop (solo se assente)
require_once('include/utils/VTEProperties.php');
$VP = VTEProperties::getInstance();
$curMeetDefault = $VP->get('gspl.meet_default');
if ($curMeetDefault === null) {
    $VP->set('gspl.meet_default', true);
    echo "Impostato gspl.meet_default in vte_vteprop.<br>";
} else {
    echo "gspl.meet_default già presente in vte_vteprop.<br>";
}

// 0b. Default OAuth mode in vte_vteprop (solo se assente)
$curOauthMode = $VP->get('gspl.oauth_mode');
if ($curOauthMode === null || $curOauthMode === '') {
    $defaultMode = strtolower(trim((string)($GLOBALS['GSPL_OAUTH_MODE'] ?? 'proxy')));
    if (!in_array($defaultMode, ['proxy', 'native'])) $defaultMode = 'proxy';
    $VP->set('gspl.oauth_mode', $defaultMode);
    echo "Impostato gspl.oauth_mode in vte_vteprop ($defaultMode).<br>";
} else {
    echo "gspl.oauth_mode già presente in vte_vteprop.<br>";
}

// 1. Aggiunta colonne per configurazione GoogleSyncPlus a vte_users
$tableName = $table_prefix . '_users';
// google_sync_calendars, google_sync_target_calendar, google_sync_direction, google_sync_use_meet
// (ALTER TABLE solo se colonna non esiste)

// 2. Registrazione Blocco e Campo in Users (Vtiger_Module/Block/Field)
// Blocco LBL_GOOGLE_SYNC_PLUS, campi google_sync_calendars (uitype 21) e google_sync_use_meet (uitype 56)
// UPDATE vte_field SET readonly = 99 per i due campi

// 2b. Colonna cf_gspl_dest_calendar in vte_activitycf + campo gspl_dest_calendar in modulo Calendar

// 3. Traduzioni: sdk_language (LBL_GOOGLE_SYNC_PLUS, LBL_GSPL_SETTINGS, LBL_GSPL_SETTINGS_DESC)
//    + backup in Users/language/it_it.lang.php + language/it_it.lang.php e en_us.lang.php

// 4. CREATE TABLE vte_googlesyncplus_map, vte_gspl_user_seats, vte_googlesyncplus_otp

// 5. DELETE vecchi + INSERT vte_links (HEADERSCRIPT per Users, Calendar, Events, Settings)

// 6. VTEventsManager::registerHandler per beforesave, aftersave, beforedelete

// 7. CronUtils::insertCronJob GoogleSyncPlus -> cron_sync.php, repeat 60, timeout 300

// 8. UPDATE vte_tab SET presence=1, DELETE vte_parenttabrel, DELETE tbl_s_menu_modules

// 9. Settings: SELECT/UPDATE o INSERT vte_settings_field (Google Calendar Sync Plus, linkto Settings)

// 9a. Rimozione modules/Settings/GoogleSyncPlus (dir e wrapper PHP)

// 10. UPDATE vte_blocks SET blocklabel = 'Google Calendar Sync Plus' per blocco Users

// 11. Unlink cache (getMenuModuleList.json, getMenuLayout.json, SDK/vte_languages/*.json)

// 12. Append a config_override.php blocco commentato send_mail_bootstrap

// 13. Patch modules/Calendar/Activity.php: require SendCancellationEmails + gspl_send_cancellation_emails()

// 14. gspl_install_set_permissions(moduleDir) + chmod logs/gs_license.dat

echo "<hr><b>Installazione Completata.</b>";
?>

================================================================================
FINE DOCUMENTO
================================================================================
