* SPDX-License-Identifier: AGPL-3.0-only ************************************/ // crmv@161554 cmrv@163697 require_once('include/BaseClasses.php'); require_once('modules/Morphsuit/utils/RSA/Crypt/Random.php'); require_once('vtlib/Vtecrm/SettingsBlock.php'); require_once('vtlib/Vtecrm/SettingsField.php'); require_once('modules/Update/Update.php'); class GDPRWS extends SDKExtendableUniqueClass { public static $supportedModules = array('Contacts', 'Leads'); public $availableFields = array( 'Contacts' => array( 'salutation', 'firstname', 'phone', 'lastname', 'mobile', 'homephone', 'otherphone', 'title', 'fax', 'department', 'birthday', 'assistant', 'assistantphone', 'mailingstreet', 'mailingcity', 'mailingzip', 'mailingstate', 'mailingcountry', 'mailingpobox', 'otherstreet', 'othercity', 'otherzip', 'otherstate', 'othercountry', 'otherpobox', ), 'Leads' => array( 'firstname', 'lastname', 'mobile', 'company', 'designation', 'website', 'annualrevenue', 'noofemployees', 'lane', 'city', 'code', 'state', 'country', 'pobox' ), ); public $gdprFields = array( 'gdpr_privacypolicy', 'gdpr_personal_data', 'gdpr_marketing', 'gdpr_thirdparties', 'gdpr_profiling', 'gdpr_restricted', 'gdpr_notifychange', ); public $emailFields = array(); protected $cid = null; protected $cidData = null; protected $authTable = null; protected $logTable = null; protected $confirmTable = null; protected $senderName = null; protected $senderEmail = null; protected $templates = null; protected $noconfirm_deletion_months = null; public $default_noconfirm_deletion_months = 12; public function __construct() { global $table_prefix; $this->emailFields = array( 'Accounts' => array('fieldname' => 'email1', 'tablename' => $table_prefix.'_account', 'columnname' => 'email1'), 'Contacts' => array('fieldname' => 'email', 'tablename' => $table_prefix.'_contactdetails', 'columnname' => 'email'), 'Leads' => array('fieldname' => 'email', 'tablename' => $table_prefix.'_leaddetails', 'columnname' => 'email'), ); $this->authTable = $table_prefix.'_gdpr_auth'; $this->logTable = $table_prefix.'_gdpr_log'; $this->confirmTable = $table_prefix.'_gdpr_confirm_queue'; } public function install() { global $adb, $table_prefix, $site_URL, $HELPDESK_SUPPORT_EMAIL_ID, $HELPDESK_SUPPORT_NAME; $vteProp = VTEProperties::getInstance(); $BU = BusinessUnit::getInstance(); $businessList = $BU->getBusinessList(); $prop = $vteProp->get('services.gdpr.general_settings'); if ($prop === null) { $generalSettings = array(); $generalSettings['default_business'] = $businessList[0]['organizationid']; $vteProp->set('services.gdpr.general_settings', $generalSettings); } foreach ($businessList as $business) { $bid = $business['organizationid']; $prop = $vteProp->get("services.gdpr.config.business.{$bid}"); if ($prop === null) { $config = array(); $config['webservice_endpoint'] = $site_URL; $user = Users::getActiveAdminUser(); $username = $user->column_fields['user_name']; $accesskey = $user->column_fields['accesskey']; $config['webservice_username'] = $username; $config['webservice_accesskey'] = $accesskey; $config['default_language'] = 'en'; $config['sender_name'] = $HELPDESK_SUPPORT_NAME; $config['sender_email'] = $HELPDESK_SUPPORT_EMAIL_ID; $config['noconfirm_deletion_months'] = $this->default_noconfirm_deletion_months; $logo = ''; $companyDetailsResult = $adb->pquery("SELECT logoname FROM {$table_prefix}_organizationdetails WHERE organizationid = ?", array($bid)); if ($companyDetailsResult && $adb->num_rows($companyDetailsResult)) { $companyDetails = $adb->fetchByAssoc($companyDetailsResult, -1, false); $logo = $companyDetails['logoname']; $logo = $site_URL.'/storage/logo/'.$logo; } $config['website_logo'] = $logo; $vteProp->set("services.gdpr.config.business.{$bid}", $config); } $prop = $vteProp->get("services.gdpr.templates.business.{$bid}"); if ($prop === null) { $templates = array(); $templates['support_request_template'] = $this->createTemplateEmail('support_request_template', 'GDPR - Support request template - EN', 'New support request', 'Template used for support request', 'en'); $this->createTemplateEmail('support_request_template', 'GDPR - Template richiesta supporto - IT', 'Nuova richiesta di supporto', 'Template utilizzato per le richieste di supporto', 'it'); $templates['access_template'] = $this->createTemplateEmail('access_template', 'GDPR - Access template - EN', 'Access to manage your contact', 'Template used for sending the access details to the contact', 'en'); $this->createTemplateEmail('access_template', 'GDPR - Template accesso - IT', 'Accesso per la gestione del tuo contatto', 'Template utilizzato per l\'invio dell\'accesso al contatto', 'it'); $templates['confirm_update_template'] = $this->createTemplateEmail('confirm_update_template', 'GDPR - Confirm update template - EN', 'Confirm your contact\'s changes', 'Template used for confirming the contact update', 'en'); $this->createTemplateEmail('confirm_update_template', 'GDPR - Template conferma modifiche - IT', 'Conferma le modifiche del tuo contatto', 'Template utilizzato per la conferma dell\'aggiornamento del contatto', 'it'); $templates['contact_updated_template'] = $this->createTemplateEmail('contact_updated_template', 'GDPR - Contact updated template - EN', 'Contact update', 'Template used for sending update notifications to the contact', 'en'); $this->createTemplateEmail('contact_updated_template', 'GDPR - Template dati contatto aggiornati - IT', 'Aggiornamento contatto', 'Template utilizzato per inviare le notifiche di cambio dati al contatto', 'it'); $vteProp->set("services.gdpr.templates.business.{$bid}", $templates); } $PPU = PrivacyPolicyUtils::getInstance(); $ok = $PPU->save($bid, 'Company', file_get_contents('include/utils/GDPRWS/templates/privacy_policy.html')); } $this->checkTables(); $this->createTemplateEmail('gdpr_verify_newsletter', 'GDPR - Default newsletter - EN', 'Verify your contact', 'The default template used for sending GDPR newsletter', 'en', 'Newsletter'); $this->createTemplateEmail('gdpr_verify_newsletter', 'GDPR - Default newsletter - IT', 'Verifica il tuo contatto', 'Template di default utilizzato per l\'invio della newsletter GDPR', 'it', 'Newsletter'); $translations = array(); $gdprModules = self::$supportedModules; $GDPRFields = array('gdpr_privacypolicy', 'gdpr_personal_data', 'gdpr_marketing', 'gdpr_thirdparties', 'gdpr_profiling', 'gdpr_restricted', 'gdpr_notifychange', 'gdpr_deleted'); foreach ($gdprModules as $module) { $moduleInstance = Vtecrm_Module::getInstance($module); $blockInstance = Vtecrm_Block::getInstance('LBL_GDPR_INFORMATION', $moduleInstance); if (!$blockInstance) { $blockInstance = new Vtecrm_Block(); $blockInstance->label = 'LBL_GDPR_INFORMATION'; $moduleInstance->addBlock($blockInstance); } $fields = array(); foreach ($GDPRFields as $field) { $label = 'LBL_'.strtoupper($field); $fields[] = array('module' => $module, 'block' => 'LBL_GDPR_INFORMATION', 'name' => $field, 'label' => $label, 'uitype' => '56', 'readonly' => '99', 'columntype' => 'CHAR(1)', 'typeofdata' => 'C~O', 'quickcreate' => 1); // crmv@187404 $fields[] = array('module' => $module, 'block' => 'LBL_GDPR_INFORMATION', 'name' => $field.'_checkedtime', 'label' => $label.'_CHECKEDTIME', 'uitype' => '1', 'readonly' => '99', 'columntype' => 'DATETIME', 'typeofdata' => 'V~O', 'quickcreate' => 1); // crmv@187404 $fields[] = array('module' => $module, 'block' => 'LBL_GDPR_INFORMATION', 'name' => $field.'_remote_addr', 'label' => $label.'_REMOTE_ADDRESS', 'uitype' => '1', 'readonly' => '99', 'columntype' => 'C(45)', 'typeofdata' => 'V~O', 'quickcreate' => 1); // crmv@187404 } $fields[] = array('module' => $module, 'block' => 'LBL_GDPR_INFORMATION', 'name' => 'gdpr_sentdate', 'label' => 'LBL_GDPR_SENTTIME', 'uitype' => '1', 'readonly' => '99', 'columntype' => 'DATETIME', 'typeofdata' => 'V~O', 'quickcreate' => 1); // crmv@187404 Update::create_fields($fields); $translations[$module]['it_it'] = array( 'LBL_GDPR_INFORMATION' => 'Informazioni GDPR', 'LBL_GDPR_PRIVACYPOLICY' => 'Visione Informativa', 'LBL_GDPR_PRIVACYPOLICY_CHECKEDTIME' => 'Data Visione Informativa', 'LBL_GDPR_PRIVACYPOLICY_REMOTE_ADDRESS' => 'Indirizzo IP Visione Informativa', 'LBL_GDPR_PERSONAL_DATA' => 'Consenso Dati Personali', 'LBL_GDPR_PERSONAL_DATA_CHECKEDTIME' => 'Data Consenso Dati Personali', 'LBL_GDPR_PERSONAL_DATA_REMOTE_ADDRESS' => 'Indirizzo IP Dati Personali', 'LBL_GDPR_MARKETING' => 'Consenso Marketing', 'LBL_GDPR_MARKETING_CHECKEDTIME' => 'Data Consenso Marketing', 'LBL_GDPR_MARKETING_REMOTE_ADDRESS' => 'Indirizzo IP Consenso Marketing', 'LBL_GDPR_THIRDPARTIES' => 'Consenso Terze Parti', 'LBL_GDPR_THIRDPARTIES_CHECKEDTIME' => 'Data Consenso Terze Parti', 'LBL_GDPR_THIRDPARTIES_REMOTE_ADDRESS' => 'Indirizzo IP Consenso Terze Parti', 'LBL_GDPR_PROFILING' => 'Consenso Profilazione', 'LBL_GDPR_PROFILING_CHECKEDTIME' => 'Data Consenso Profilazione', 'LBL_GDPR_PROFILING_REMOTE_ADDRESS' => 'Indirizzo IP Consenso Profilazione', 'LBL_GDPR_RESTRICTED' => 'Consenso Comunicazione Dati Ambiti Informativa', 'LBL_GDPR_RESTRICTED_CHECKEDTIME' => 'Data Consenso Comunicazione Dati Ambiti Informativa', 'LBL_GDPR_RESTRICTED_REMOTE_ADDRESS' => 'Indirizzo IP Consenso Comunicazione Dati Ambiti Informativa', 'LBL_GDPR_NOTIFYCHANGE' => 'Avvisa Cambio Dati', 'LBL_GDPR_NOTIFYCHANGE_CHECKEDTIME' => 'Data Consenso Avvisa Cambio Dati', 'LBL_GDPR_NOTIFYCHANGE_REMOTE_ADDRESS' => 'Indirizzo IP Avvisa Cambio Dati', 'LBL_GDPR_DELETED' => 'Eliminato', 'LBL_GDPR_DELETED_CHECKEDTIME' => 'Data Eliminazione', 'LBL_GDPR_DELETED_REMOTE_ADDRESS' => 'Indirizzo IP Eliminazione', 'LBL_GDPR_SENTTIME' => 'Data Invio GDPR', ); $translations[$module]['en_us'] = array( 'LBL_GDPR_INFORMATION' => 'GDPR Information', 'LBL_GDPR_PRIVACYPOLICY' => 'Privacy Policy', 'LBL_GDPR_PRIVACYPOLICY_CHECKEDTIME' => 'Privacy Policy - Date', 'LBL_GDPR_PRIVACYPOLICY_REMOTE_ADDRESS' => 'Privacy Policy - IP Address', 'LBL_GDPR_PERSONAL_DATA' => 'Consent to Personal Data', 'LBL_GDPR_PERSONAL_DATA_CHECKEDTIME' => 'Consent to Personal Data - Date', 'LBL_GDPR_PERSONAL_DATA_REMOTE_ADDRESS' => 'Consent to Personal Data - IP Address', 'LBL_GDPR_MARKETING' => 'Consent to Marketing', 'LBL_GDPR_MARKETING_CHECKEDTIME' => 'Consent to Marketing - Date', 'LBL_GDPR_MARKETING_REMOTE_ADDRESS' => 'Consent to Marketing - IP Address', 'LBL_GDPR_THIRDPARTIES' => 'Consent to Third Parties', 'LBL_GDPR_THIRDPARTIES_CHECKEDTIME' => 'Consent to Third Parties - Date', 'LBL_GDPR_THIRDPARTIES_REMOTE_ADDRESS' => 'Consent to Third Parties - IP Address', 'LBL_GDPR_PROFILING' => 'Consent to Profiling', 'LBL_GDPR_PROFILING_CHECKEDTIME' => 'Consent to Profiling - Date', 'LBL_GDPR_PROFILING_REMOTE_ADDRESS' => 'Consent to Profiling - IP Address', 'LBL_GDPR_RESTRICTED' => 'Consent only to specified institutions', 'LBL_GDPR_RESTRICTED_CHECKEDTIME' => 'Consent only to specified institutions - Date', 'LBL_GDPR_RESTRICTED_REMOTE_ADDRESS' => 'Consent only to specified institutions - IP Address', 'LBL_GDPR_NOTIFYCHANGE' => 'Notify contact changes', 'LBL_GDPR_NOTIFYCHANGE_CHECKEDTIME' => 'Notify contact changes - Date', 'LBL_GDPR_NOTIFYCHANGE_REMOTE_ADDRESS' => 'Notify contact changes - IP Address', 'LBL_GDPR_DELETED' => 'Deleted', 'LBL_GDPR_DELETED_CHECKEDTIME' => 'Deleted - Date', 'LBL_GDPR_DELETED_REMOTE_ADDRESS' => 'Deleted - IP Address', 'LBL_GDPR_SENTTIME' => 'GDPR Sent Date', ); } $block = Vtecrm_SettingsBlock::getInstance('LBL_COMMUNICATION_TEMPLATES'); $res = $adb->pquery("SELECT fieldid FROM {$table_prefix}_settings_field WHERE name = ?", array('LBL_GDPR')); if ($block && $res && $adb->num_rows($res) == 0) { $field = new Vtecrm_SettingsField(); $field->name = 'LBL_GDPR'; $field->iconpath = 'themes/images/PrivacySettings.png'; $field->description = 'LBL_GDPR_DESCRIPTION'; $field->linkto = 'index.php?module=Settings&action=GDPRConfig&parenttab=Settings'; $block->addField($field); } $result = $adb->pquery("SELECT campaigntype FROM {$table_prefix}_campaigntype WHERE campaigntype = ?", array('GDPR')); if ($result && $adb->num_rows($result) < 1) { $field = Vtecrm_Field::getInstance('campaigntype', Vtecrm_Module::getInstance('Campaigns')); if ($field) { $field->setPicklistValues(array('GDPR')); } } $translations['Newsletter'] = array( 'it_it' => array( 'LBL_GDPR_AND_PRICAY_POLICY' => 'GDPR e informativa privacy', 'LBL_GDPR_VERIFY_LINK' => 'GDPR Accesso - Link di verifica', 'LBL_GDPR_ACCESS_LINK' => 'GDPR Accesso - Link di accesso', 'LBL_GDPR_CONFIRM_LINK' => 'GDPR Aggiornamento - Link di conferma', 'LBL_GDPR_SUPPORT_REQUEST_SENDER' => 'GDPR Richiesta supporto - Mittente', 'LBL_GDPR_SUPPORT_REQUEST_SUBJECT' => 'GDPR Richiesta supporto - Oggetto', 'LBL_GDPR_SUPPORT_REQUEST_DESC' => 'GDPR Richiesta supporto - Descrizione', ), 'en_us' => array( 'LBL_GDPR_AND_PRICAY_POLICY' => 'GDPR and privacy policy', 'LBL_GDPR_VERIFY_LINK' => 'GDPR Access - Verify link', 'LBL_GDPR_ACCESS_LINK' => 'GDPR Access - Access link', 'LBL_GDPR_CONFIRM_LINK' => 'GDPR Update - Confirm link', 'LBL_GDPR_SUPPORT_REQUEST_SENDER' => 'GDPR Support Request - Sender', 'LBL_GDPR_SUPPORT_REQUEST_SUBJECT' => 'GDPR Support Request - Subject', 'LBL_GDPR_SUPPORT_REQUEST_DESC' => 'GDPR Support Request - Description', ), ); $translations['APP_STRINGS'] = array( 'it_it' => array( 'LBL_GDPR_ANONYMIZE' => 'Anonimizza', ), 'en_us' => array( 'LBL_GDPR_ANONYMIZE' => 'Anonymize', ), ); $translations['Settings'] = array( 'it_it' => array( 'GDPR' => 'GDPR', 'LBL_GDPR' => 'GDPR', 'LBL_GDPR_DESCRIPTION' => 'Configura le impostazioni del GDPR', 'LBL_WEBSERVICE' => 'Webservice', 'LBL_WEBSERVICE_ENDPOINT' => 'Webservice endpoint', 'LBL_WEBSERVICE_USERNAME' => 'Webservice username', 'LBL_WEBSERVICE_ACCESSKEY' => 'Webservice accesskey', 'LBL_DEFAULT_LANGUAGE' => 'Lingua di default', 'LBL_WEBSITE_LOGO' => 'Logo di default', 'LBL_SENDER_NAME' => 'Nome mittente', 'LBL_SENDER_EMAIL' => 'Email mittente', 'LBL_TEMPLATES' => 'Template', 'LBL_PRIVACY_POLICY' => 'Informativa Privacy', 'LBL_WEBSERVICE_ENDPOINT_DESC' => 'L\'URL dove è installato il CRM', 'LBL_WEBSERVICE_USERNAME_DESC' => 'Utente utilizzato per le chiamate Webservice', 'LBL_WEBSERVICE_ACCESSKEY_DESC' => 'Accesskey dell\'utente utilizzato per le chiamate Webservice', 'LBL_WEBSITE_LOGO_DESC' => 'Il logo di default utilizzato nell\'app', 'LBL_SENDER_NAME_DESC' => 'Il nome del mittente utilizzato per le comunicazioni GDPR', 'LBL_SENDER_EMAIL_DESC' => 'L\'email del mittente utilizzata per le comunicazioni GDPR', 'LBL_ENGLISH_LANG' => 'EN English', 'LBL_ITALIAN_LANG' => 'IT Italiano', 'LBL_DEFAULT_LANGUAGE_DESC' => 'La lingua di default utilizzata nell\'app', 'LBL_SUPPORT_REQUEST_TEMPLATE' => 'Template richiesta supporto', 'LBL_SUPPORT_REQUEST_TEMPLATE_DESC' => 'Template utilizzato per le richieste di supporto', 'LBL_ACCESS_TEMPLATE' => 'Template accesso', 'LBL_ACCESS_TEMPLATE_DESC' => 'Template utilizzato per l\'invio dell\'accesso al contatto', 'LBL_CONFIRM_UPDATE_TEMPLATE' => 'Template di richiesta conferma', 'LBL_CONFIRM_UPDATE_TEMPLATE_DESC' => 'Template utilizzato per la conferma dell\'aggiornamento del contatto', 'LBL_CONTACT_UPDATED_TEMPLATE' => 'Template modifiche contatto', 'LBL_CONTACT_UPDATED_TEMPLATE_DESC' => 'Template utilizzato per inviare le notifiche di cambio dati al contatto', 'LBL_GDPR_VERIFY_LINK' => 'GDPR Accesso - Link di verifica', 'LBL_GDPR_ACCESS_LINK' => 'GDPR Accesso - Link di accesso', 'LBL_GDPR_CONFIRM_LINK' => 'GDPR Aggiornamento - Link di conferma', 'LBL_GDPR_SUPPORT_REQUEST_SENDER' => 'GDPR Richiesta supporto - Mittente', 'LBL_GDPR_SUPPORT_REQUEST_SUBJECT' => 'GDPR Richiesta supporto - Oggetto', 'LBL_GDPR_SUPPORT_REQUEST_DESC' => 'GDPR Richiesta supporto - Descrizione', 'CompanyDetails' => 'Dettagli societa`', 'LBL_ANONYMOUS' => 'Anonymous', 'LBL_GDPR_NOTIFY_ANONYMIZE_SUBJECT'=>'Anonimizzazione contatto', 'LBL_GDPR_NOTIFY_ANONYMIZE_BODY'=>'E\' stata effettuata l\'anonimizzazione di %s, %s, %s.
Entro il %s devi assicurarti che vengano eliminati i suoi dati anche da eventuali supporti cartacei o esterni.
Ricordati di cancellare anche questa email!', 'LBL_NOCONFIRM_DELETION_MOTHS' => 'Mesi attesa conferma', 'LBL_NOCONFIRM_DELETION_MOTHS_DESC' => 'Il numero di mesi dopo il quale il contatto verra` anonimizzato', 'LBL_GENERAL_SETTINGS' => 'Impostazioni generali', 'LBL_DEFAULT_BUSINESS_UNIT' => 'Default Business Unit', 'LBL_DEFAULT_BUSINESS_UNIT_DESC' => 'La business unit di default utilizzata come fallback', ), 'en_us' => array( 'GDPR' => 'GDPR', 'LBL_GDPR' => 'GDPR', 'LBL_GDPR_DESCRIPTION' => 'Configure the GDPR settings', 'LBL_WEBSERVICE' => 'Webservice', 'LBL_WEBSERVICE_ENDPOINT' => 'Webservice endpoint', 'LBL_WEBSERVICE_USERNAME' => 'Webservice username', 'LBL_WEBSERVICE_ACCESSKEY' => 'Webservice access key', 'LBL_DEFAULT_LANGUAGE' => 'Default language', 'LBL_WEBSITE_LOGO' => 'Default logo', 'LBL_SENDER_NAME' => 'Sender name', 'LBL_SENDER_EMAIL' => 'Sender email', 'LBL_TEMPLATES' => 'Template', 'LBL_PRIVACY_POLICY' => 'Privacy Policy', 'LBL_WEBSERVICE_ENDPOINT_DESC' => 'The URL where CRM is installed', 'LBL_WEBSERVICE_USERNAME_DESC' => 'User employed for the Webservice calls', 'LBL_WEBSERVICE_ACCESSKEY_DESC' => 'User Access key used for the Webservice calls', 'LBL_WEBSITE_LOGO_DESC' => 'The default logo used in the app', 'LBL_SENDER_NAME_DESC' => 'The sender name used for GDPR communication', 'LBL_SENDER_EMAIL_DESC' => 'The sender email used for GDPR communication', 'LBL_ENGLISH_LANG' => 'EN English', 'LBL_ITALIAN_LANG' => 'IT Italiano', 'LBL_DEFAULT_LANGUAGE_DESC' => 'The default language used in the app', 'LBL_SUPPORT_REQUEST_TEMPLATE' => 'Support request Template', 'LBL_SUPPORT_REQUEST_TEMPLATE_DESC' => 'Template used for support request', 'LBL_ACCESS_TEMPLATE' => 'Access Template', 'LBL_ACCESS_TEMPLATE_DESC' => 'Template used for sending the access details to the contact', 'LBL_CONFIRM_UPDATE_TEMPLATE' => 'Confirm update template', 'LBL_CONFIRM_UPDATE_TEMPLATE_DESC' => 'Template used for confirming the contact update', 'LBL_CONTACT_UPDATED_TEMPLATE' => 'Contact updated template', 'LBL_CONTACT_UPDATED_TEMPLATE_DESC' => 'Template used for sending update notifications to the contact', 'LBL_GDPR_VERIFY_LINK' => 'GDPR Access - Verify link', 'LBL_GDPR_ACCESS_LINK' => 'GDPR Access - Access link', 'LBL_GDPR_CONFIRM_LINK' => 'GDPR Update - Confirm link', 'LBL_GDPR_SUPPORT_REQUEST_SENDER' => 'GDPR Support Request - Sender', 'LBL_GDPR_SUPPORT_REQUEST_SUBJECT' => 'GDPR Support Request - Subject', 'LBL_GDPR_SUPPORT_REQUEST_DESC' => 'GDPR Support Request - Description', 'CompanyDetails' => 'Company details', 'LBL_ANONYMOUS' => 'Anonymous', 'LBL_GDPR_NOTIFY_ANONYMIZE_SUBJECT'=>'Contact anonymization', 'LBL_GDPR_NOTIFY_ANONYMIZE_BODY'=>'Has been made the anonymization of %s, %s and %s was made.
Within the %s you must ensure that your data is also deleted from any paper or external media.
Remember to also delete this email!', 'LBL_NOCONFIRM_DELETION_MOTHS' => 'Number of waiting months for confirm', 'LBL_NOCONFIRM_DELETION_MOTHS_DESC' => 'The number of months after which the contact will be anonymised', 'LBL_GENERAL_SETTINGS' => 'General settings', 'LBL_DEFAULT_BUSINESS_UNIT' => 'Default Business Unit', 'LBL_DEFAULT_BUSINESS_UNIT_DESC' => 'The default business unit used as fallback', ), ); $languages = vtlib_getToggleLanguageInfo(); foreach ($translations as $module => $modlang) { foreach ($modlang as $lang => $translist) { if (array_key_exists($lang, $languages)) { foreach ($translist as $label => $translabel) { SDK::setLanguageEntry($module, $lang, $label, $translabel); } } } } $this->initCustomWebserviceOperations(); if (Vtecrm_Event::hasSupport()) { Vtecrm_Event::register('', 'vte.entity.beforesave', 'GDPRHandler', 'include/utils/GDPRWS/handlers/GDPRHandler.php');//crmv@207852 } $focus = ModNotifications::getInstance(); // crmv@164122 $focus->addNotificationType('GDPR_INSTALLED', 'GDPR_INSTALLED', 0); $notifications = array( 'it_it' => "E' stato installato un importante aggiornamento relativo alla gestione del GDPR. Scopri come permettere ai tuoi contatti la tutela delle loro informazioni personali in tuo possesso consultando la guida online. Per maggiori informazioni sul GDPR in generale clicca qui.", 'en_us' => "An important update concerning the management of the GDPR has been installed. Find out how to allow your contacts to protect their personal information in your possession by consulting the online guide. For more information on GDPR in general click here.", ); $subjects = array( 'it_it' => "E' stato installato un importante aggiornamento relativo alla gestione del GDPR.", 'en_us' => "An important update concerning the management of the GDPR has been installed.", ); SDK::setLanguageEntry('ModNotifications', 'it_it', 'GDPR_INSTALLED', $notifications['it_it']); SDK::setLanguageEntry('ModNotifications', 'en_us', 'GDPR_INSTALLED', $notifications['en_us']); $users = array(); $usersLang = array(); $userListResult = $adb->pquery("SELECT id, default_language FROM {$table_prefix}_users WHERE status = ? AND is_admin = ?", array('Active', 'on')); if ($userListResult && $adb->num_rows($userListResult)) { while ($row = $adb->fetchByAssoc($userListResult, -1, false)) { $users[] = $row['id']; $usersLang[$row['id']] = $row['default_language']; } } $focus = ModNotifications::getInstance(); // crmv@164122 if (!empty($users)) { $alreadyNotifiedUsers = array(); foreach ($users as $user) { if (in_array($user, $alreadyNotifiedUsers)) { continue; } $LU = LanguageUtils::getInstance(); $LU->changeCurrentLanguage($usersLang[$user]); $notifiedUsers = $focus->saveFastNotification(array( 'assigned_user_id' => $user, 'related_to' => '', 'mod_not_type' => 'GDPR_INSTALLED', 'subject' => $subjects[$usersLang[$user]], 'description' => getTranslatedString('GDPR_INSTALLED', 'ModNotifications'), 'createdtime' => date('Y-m-d H:i:s'), 'modifiedtime' => date('Y-m-d H:i:s'), )); $LU->restoreCurrentLanguage($usersLang[$user]); if (!empty($notifiedUsers)) { foreach ($notifiedUsers as $notifiedUser) { $alreadyNotifiedUsers[] = $notifiedUser; } } } } $contactsInstance = Vtecrm_Module::getInstance('Contacts'); Vtecrm_Link::addLink($contactsInstance->id, 'DETAILVIEWBASIC', 'LBL_GDPR_ANONYMIZE', 'javascript:gdprAnonymize(\'$MODULE$\',$RECORD$);'); $leadsInstance = Vtecrm_Module::getInstance('Leads'); Vtecrm_Link::addLink($leadsInstance->id, 'DETAILVIEWBASIC', 'LBL_GDPR_ANONYMIZE', 'javascript:gdprAnonymize(\'$MODULE$\',$RECORD$);'); $result = $adb->pquery("SELECT * FROM {$table_prefix}_cronjobs WHERE cronname = ?", array('GDPR')); if ($adb->num_rows($result) == 0) { require_once('include/utils/CronUtils.php'); $CU = CronUtils::getInstance(); $cj = new CronJob(); $cj->name = 'GDPR'; $cj->active = 1; $cj->singleRun = false; $cj->fileName = 'cron/modules/Newsletter/GDPR.service.php'; $cj->timeout = 5400; $cj->repeat = 14400; // repeat every 4 hours $CU->insertCronJob($cj); } $this->updateConvertLead(); // crmv@194712 } public function createTemplateEmail($name, $label, $subject, $description, $language, $type = 'Email') { global $adb, $table_prefix; $emailTemplatesResult = $adb->pquery("SELECT * FROM {$table_prefix}_emailtemplates WHERE templatename = ? AND deleted = 0", array($label)); if ($emailTemplatesResult && $adb->num_rows($emailTemplatesResult)) { $row = $adb->fetchByAssoc($emailTemplatesResult, -1, false); return $row['templateid']; } $templateFile = 'include/utils/GDPRWS/templates/'.$name.'_'.$language.'.html'; if (!(file_exists($templateFile) && is_readable($templateFile))) { return false; } $id = $adb->getUniqueID($table_prefix . '_emailtemplates'); $body = file_get_contents($templateFile); $params = array( 'foldername' => 'Public', 'templatename' => $label, 'subject' => $subject, 'description' => $description, 'body' => $adb->getEmptyClob(false), 'deleted' => 0, 'templateid' => $id, 'templatetype' => $type, 'overwrite_message' => 1, ); $columns = array_keys($params); $adb->format_columns($columns); $adb->pquery("INSERT INTO {$table_prefix}_emailtemplates (" . implode(',', $columns) . ") VALUES (" . generateQuestionMarks($params) . ")", $params); $adb->updateClob($table_prefix . '_emailtemplates', 'body', "templateid=$id", $body); return $id; } public function checkTables() { global $adb, $table_prefix; $schema_table = ' ENGINE=InnoDB authtoken_expire accesstoken_expire
'; if (!Vtecrm_Utils::CheckTable($this->authTable)) { $schema_obj = new adoSchema($adb->database); $schema_obj->ExecuteSchema($schema_obj->ParseSchemaString($schema_table)); } $schema_table = ' ENGINE=InnoDB timestamp operation
'; if (!Vtecrm_Utils::CheckTable($this->logTable)) { $schema_obj = new adoSchema($adb->database); $schema_obj->ExecuteSchema($schema_obj->ParseSchemaString($schema_table)); } $schema_table = ' ENGINE=InnoDB
'; if (!Vtecrm_Utils::CheckTable($this->confirmTable)) { $schema_obj = new adoSchema($adb->database); $schema_obj->ExecuteSchema($schema_obj->ParseSchemaString($schema_table)); } } public static function isEnabledForModule($module) { return in_array($module, self::$supportedModules); } public function validateContactId($cid, &$error) { global $adb, $table_prefix, $current_user; $contactid = $module = $email = null; if (!is_numeric($cid)) { list($msgtype, $email, $module) = explode('|', base64_decode(urldecode($cid))); } else { $contactid = $cid; $module = getSalesEntityType($contactid); } if (!self::isEnabledForModule($module)) { return $this->validateUnsupportedModule($cid, $module, $email, $error); } if (empty($contactid)) { $column = $this->emailFields[$module]['tablename'].'.'.$this->emailFields[$module]['columnname']; $qg = QueryGenerator::getInstance($module, $current_user); $idcol = $qg->getSQLColumn('id', false); $qg->initForAllCustomView(); $qg->addField('id'); $qg->addFieldAlias('id', 'crmid'); $query = $qg->getQuery(); $query .= " AND $column = ? AND COALESCE(gdpr_deleted, 0) <> 1 ORDER BY crmid"; $contactResult = $adb->limitpquery($query, 0, 1, array($email)); if ($contactResult && $adb->num_rows($contactResult)) { $contactid = intval($adb->query_result($contactResult, 0, 'crmid')); } else { $error = 'RECORD_NOT_FOUND'; return false; } } $focus = CRMEntity::getInstance($module); $ret = $focus->retrieve_entity_info_no_html($contactid, $module, false); $focus->id = $contactid; if ($ret == 'LBL_RECORD_DELETE') { $error = 'RECORD_DELETED'; return false; } elseif ($ret == 'LBL_RECORD_NOT_FOUND') { $error = 'RECORD_NOT_FOUND'; return false; } if ($focus->column_fields['gdpr_deleted'] === '1') { $error = 'RECORD_DELETED'; return false; } $emailField = $this->emailFields[$module]['fieldname']; $availableData = array(); $fields = array_flip($this->getAvailableFields($module)); $columnFields = $focus->column_fields; foreach ($columnFields as $fieldname => $value) { if (isset($fields[$fieldname])) { $availableData[$fieldname] = $value; } } $email = $columnFields[$emailField]; $gdprws = GDPRWS::getInstance(); $bid = $gdprws->getBusinessId($contactid, $module, $email); $this->initBusinessData($bid); $newsletterFocus = CRMEntity::getInstance('Newsletter'); //$availableData['gdpr_marketing'] = $newsletterFocus->receivingNewsletter($email); // crmv@181193 $cid = urlencode(base64_encode("C|".$email."|".$module)); $this->cid = $cid; $this->cidData = array(); $this->cidData['email'] = $email; $this->cidData['module'] = $module; $contactData = array( 'module' => $module, 'contactid' => $contactid, 'email' => $email, 'focus' => $focus, 'email_field' => $this->emailFields[$module], 'available_data' => $availableData, 'business_id' => $bid, ); // crmv@164120 global $current_auth_record; if (empty($current_auth_record)) $current_auth_record = array('module' => $module, 'id' => $contactid); // crmv@164120e return $contactData; } public function validateAccess($accesstoken, &$error) { global $adb, $table_prefix; $error = null; $contactid = $this->validateAccessToken($accesstoken, $error); if (!empty($error)) return false; $contactid = intval($contactid); $error = null; $contactData = $this->validateContactId($contactid, $error); if (!empty($error)) return false; return $contactData; } public function validateUnsupportedModule($cid, $module, $email, &$error) { global $adb, $table_prefix, $current_user; $this->cid = $cid; $this->cidData = array(); $this->cidData['email'] = $email; $this->cidData['module'] = $module; $contactData = array(); $contactData['module'] = $module; $contactData['email'] = $email; $contactData['business_id'] = false; $contactData['contactid'] = false; if (isset($this->emailFields[$module])) { $crmid = null; $column = $this->emailFields[$module]['tablename'].'.'.$this->emailFields[$module]['columnname']; $qg = QueryGenerator::getInstance($module, $current_user); $idcol = $qg->getSQLColumn('id', false); $qg->initForAllCustomView(); $qg->addField('id'); $qg->addFieldAlias('id', 'crmid'); $query = $qg->getQuery(); $query .= " AND $column = ? ORDER BY crmid"; $result = $adb->limitpquery($query, 0, 1, array($email)); if ($result && $adb->num_rows($result)) { $crmid = intval($adb->query_result($result, 0, 'crmid')); } $contactData['contactid'] = $crmid; $bid = $this->getBusinessId($crmid, $module, $email); $contactData['business_id'] = $bid; $this->initBusinessData($bid); } $error = 'OPERATION_DENIED'; return $contactData; } protected function initBusinessData($bid) { $vteProp = VTEProperties::getInstance(); $config = $vteProp->get("services.gdpr.config.business.{$bid}"); $this->senderName = $config['sender_name']; $this->senderEmail = $config['sender_email']; $this->noconfirm_deletion_months = $config['noconfirm_deletion_months']; $templates = $vteProp->get("services.gdpr.templates.business.{$bid}"); $this->templates = $templates; } public function generateAuthToken($cid) { global $adb, $table_prefix; $error = null; $contactData = $this->validateContactId($cid, $error); if (!empty($error)) return $this->error($error); $contactid = $contactData['contactid']; $contractEmail = $contactData['email']; $authToken = $this->generateToken(32); $servertime = time(); $expireTime = time() + (60*5); $params = array( 'contactid' => $contactid, 'authtoken' => $authToken, 'authtoken_expire' => date('Y-m-d H:i:s', $expireTime), 'authtoken_createdtime' => date('Y-m-d H:i:s'), 'authtoken_remote_addr' => getIp(), 'authtoken_confirmed' => 0, ); $columns = array_keys($params); $adb->format_columns($columns); $adb->pquery("INSERT INTO {$this->authTable} (" . implode(',', $columns) . ") VALUES (" . generateQuestionMarks($params) . ")", $params); $this->log($contactid, 'AUTHTOKEN_GENERATED', array()); return $this->success(array('email' => $contractEmail, 'token' => $authToken, 'servertime' => $servertime, 'expiretime' => $expireTime)); } public function generateAccessToken($cid, $authtoken) { global $adb, $table_prefix; $error = null; $contactData = $this->validateContactId($cid, $error); if (!empty($error)) return $this->error($error); $contactid = $contactData['contactid']; $contractEmail = $contactData['email']; if ($this->validateAuthToken($contactid, $authtoken)) { if ($this->countActiveAccessToken($contactid) >= 4) { $this->log($contactid, 'ACCESSTOKEN_LIMIT_REACHED', array()); return $this->error('ACCESSTOKEN_LIMIT_REACHED'); } } else { $this->log($contactid, 'AUTHTOKEN_EXPIRED', array()); return $this->error('AUTHTOKEN_EXPIRED'); } $params = array( 'authtoken_confirmed' => 1, 'authtoken_confirmedtime' => date('Y-m-d H:i:s'), ); $upd = array(); foreach ($params as $col => $value) { $upd[] = "$col = ?"; } $sql = "UPDATE {$this->authTable} SET " . implode(',', $upd) . " WHERE contactid = ? AND authtoken = ?"; $adb->pquery($sql, array($params, $contactid, $authtoken)); $this->log($contactid, 'AUTHTOKEN_CONFIRMED', array()); // Let's create accesstoken $accessToken = $this->generateToken(32); $servertime = time(); $expireTime = time() + (60*60*2); $params = array( 'accesstoken' => $accessToken, 'accesstoken_expire' => date('Y-m-d H:i:s', $expireTime), 'accesstoken_createdtime' => date('Y-m-d H:i:s'), 'accesstoken_remote_addr' => getIp(), 'accesstoken_confirmed' => 0, ); $upd = array(); foreach ($params as $col => $value) { $upd[] = "$col = ?"; } $sql = "UPDATE {$this->authTable} SET " . implode(',', $upd) . " WHERE contactid = ? AND authtoken = ?"; $adb->pquery($sql, array($params, $contactid, $authtoken)); $this->deleteOrphanToken($contactid); $this->log($contactid, 'ACCESSTOKEN_GENERATED', array()); return $this->success(array('email' => $contractEmail, 'token' => $accessToken, 'servertime' => $servertime, 'expiretime' => $expireTime)); } public function sendVerify($cid, $authtoken) { global $adb, $table_prefix; $error = null; $contactData = $this->validateContactId($cid, $error); if (!empty($error)) return $this->error($error); $module = $contactData['module']; $contactid = $contactData['contactid']; $contactEmail = $contactData['email']; $requestAccesstoken = $this->generateAccessToken($cid, $authtoken); if ($requestAccesstoken['success']) { $accesstoken = $requestAccesstoken['token']; $emailStatus = $this->sendAccessEmail($contactData, $accesstoken); if (!$emailStatus) { return $this->error('SEND_EMAIL_FAILED'); } } else { return $this->error($requestAccesstoken['error']); } return $this->success(array('email' => $contactEmail)); } public function checkAccessToken($accesstoken, $options = array()) { global $adb, $table_prefix; $error = null; $contactData = $this->validateAccess($accesstoken, $error); if (!empty($error)) return $this->error($error); $output = $this->formatOutputData(array(), $contactData, $options); return $this->success($output); } public function updateContact($accesstoken, $data, $options = array()) { global $adb, $table_prefix; $error = null; $contactData = $this->validateAccess($accesstoken, $error); if (!empty($error)) return $this->error($error); $module = $contactData['module']; $fields = array_flip($this->getAvailableFields($module)); foreach ($data as $fieldname => $value) { if (!isset($fields[$fieldname])) { unset($data[$fieldname]); } } $error = null; $success = $this->enqueueUpdate($contactData, $accesstoken, 'UPDATE_CONTACT', $data, $error); if (!empty($error)) return $this->error($error); $output = $this->formatOutputData(array(), $contactData, $options); return $this->success($output); } public function deleteContact($accesstoken, $options = array()) { global $adb, $table_prefix; $error = null; $contactData = $this->validateAccess($accesstoken, $error); if (!empty($error)) return $this->error($error); $error = null; $success = $this->enqueueUpdate($contactData, $accesstoken, 'DELETE_CONTACT', array(), $error); if (!empty($error)) return $this->error($error); $output = $this->formatOutputData(array(), $contactData, $options); return $this->success($output); } public function confirmUpdate($accesstoken, $token, $options = array()) { global $adb, $table_prefix; $error = null; $contactData = $this->validateAccess($accesstoken, $error); if (!empty($error)) return $this->error($error); $contactid = $contactData['contactid']; if (!$this->validateConfirmToken($contactid, $accesstoken, $token)) { $this->log($contactid, 'CONFIRMTOKEN_EXPIRED', array()); return $this->error('CONFIRMTOKEN_EXPIRED'); } $params = array( 'token_confirmed' => 1, 'token_confirmedtime' => date('Y-m-d H:i:s'), ); $upd = array(); foreach ($params as $col => $value) { $upd[] = "$col = ?"; } $sql = "UPDATE {$this->confirmTable} SET " . implode(',', $upd) . " WHERE contactid = ? AND accesstoken = ? AND token = ?"; $adb->pquery($sql, array($params, $contactid, $accesstoken, $token)); $this->log($contactid, 'CONFIRMTOKEN_CONFIRMED', array()); $this->deleteOrphanConfirmToken($contactid); $error = null; $changes = $this->applyContactChanges($contactData, $accesstoken, $token, $error); if (!empty($error)) return $this->error($error); $output = $this->formatOutputData(array(), $contactData, $options); return $this->success($output); } public function mergeContactData($accesstoken, $maincontact, $otherids, $options = array()) { global $adb, $table_prefix, $current_user; $error = null; $contactData = $this->validateAccess($accesstoken, $error); if (!empty($error)) return $this->error($error); $module = $contactData['module']; $contactid = $contactData['contactid']; $contactEmail = $contactData['email']; $column = $contactData['email_field']['tablename'].'.'.$contactData['email_field']['columnname']; // 1. Validate ids $otherids = array_filter(array_map('intval', $otherids)); $otherids = array_filter($otherids, function($v1) use($module) { return in_array(getSalesEntityType($v1), array($module)); }); // 2. Get all duplicate contacts data $qg = QueryGenerator::getInstance($module, $current_user); $idcol = $qg->getSQLColumn('id', false); $qg->initForAllCustomView(); $qg->addField('id'); $qg->addFieldAlias('id', 'crmid'); $fields = $this->getAvailableFields($module, false); foreach ($fields as $field) { $qg->addField($field); $qg->addFieldAlias($field, $field); } $query = $qg->getQuery(); $query .= " AND $column = ? AND COALESCE(gdpr_deleted, 0) <> 1 AND $idcol IN (".generateQuestionMarks($otherids).")"; $duplicates = array(); $duplicateResult = $adb->pquery($query, array($contactEmail, $otherids)); if ($duplicateResult && $adb->num_rows($duplicateResult)) { while ($row = $adb->fetchByAssoc($duplicateResult, -1, false)) { $duplicates[] = $row; } } // 3. Merge contacts data and send confirm $obj1 = CRMEntity::getInstance($module); $obj1->id = $maincontact; $obj1->mode = 'edit'; $obj1->retrieve_entity_info_no_html($maincontact, $module); // crmv@164120 $changeLogQuery = "SELECT parent_id, changelogid, description, modified_date FROM {$table_prefix}_changelog WHERE parent_id IN (".generateQuestionMarks($otherids).") AND description NOT LIKE '%_Relation%' ORDER BY modified_date ASC"; // crmv@164120e $changeLogResult = $adb->pquery($changeLogQuery, array($otherids)); $changeLogInfo = array(); if ($changeLogResult && $adb->num_rows($changeLogResult) > 0) { while ($row = $adb->fetchByAssoc($changeLogResult, -1, false)) { $descriptionInfo = Zend_Json::decode($row['description']); for ($i = 0; $i < count($descriptionInfo); $i++) { if (!empty($descriptionInfo[$i][2])) { if ($descriptionInfo[$i][3] == 'assigned_user_id') { $changeLogInfo[$descriptionInfo[$i][3]] = getIdfromUsername($descriptionInfo[$i][2]); } else { $changeLogInfo[$descriptionInfo[$i][3]] = $descriptionInfo[$i][2]; } } } } } $mergedRecord = array(); $emptyValues = array('', null, '0', '0000-00-00 00:00:00', '--None--', '--Nessuno--'); foreach ($duplicates as $duplicate) { $duplicateId = $duplicate['crmid']; $obj2 = CRMEntity::getInstance($module); $obj2->id = $duplicateId; $obj2->mode = 'edit'; $obj2->retrieve_entity_info_no_html($duplicateId, $module); $colFields = array_keys($obj1->column_fields); foreach ($colFields as $key) { if (!in_array($key, array('firstname', 'lastname', 'email', 'bu_mc'))) { // crmv@163697 if (!isset($changeLogInfo[$key])) { if (!in_array($obj1->column_fields[$key], $emptyValues)) { $mergedRecord[$key] = $obj1->column_fields[$key]; } elseif (!in_array($obj2->column_fields[$key], $emptyValues)) { $mergedRecord[$key] = $obj2->column_fields[$key]; } else { $mergedRecord[$key] = $obj1->column_fields[$key]; } } elseif (!in_array($changeLogInfo[$key], $emptyValues)) { $mergedRecord[$key] = $changeLogInfo[$key]; } else { $mergedRecord[$key] = $obj1->column_fields[$key]; } } else { if ($key === 'bu_mc') { if (empty($mergedRecord['bu_mc'])) { $bumc1 = $obj1->column_fields['bu_mc']; } else { $bumc1 = $mergedRecord[$key]; } $bumc2 = $obj2->column_fields['bu_mc']; $bumc = implode(' |##| ', array_unique(array_merge(explode(' |##| ', $bumc1), explode(' |##| ', $bumc2)))); $mergedRecord[$key] = $bumc; } else { $mergedRecord[$key] = $obj1->column_fields[$key]; } } } unset($obj2); } unset($obj1); // Unset useless fields unset($mergedRecord['record_id']); unset($mergedRecord['record_module']); unset($mergedRecord['createdtime']); unset($mergedRecord['modifiedtime']); unset($mergedRecord['creator']); unset($mergedRecord['assigned_user_id']); $mergedRecord['transfer_relations'] = $otherids; $mergedRecord['main_contact'] = $maincontact; $error = null; $success = $this->enqueueUpdate($contactData, $accesstoken, 'MERGE_CONTACT', $mergedRecord, $error); if (!empty($error)) return $this->error($error); $output = $this->formatOutputData(array(), $contactData, $options); return $this->success($output); } public function getFields($accesstoken, $options = array()) { global $adb, $table_prefix, $current_user; $error = null; $contactData = $this->validateAccess($accesstoken, $error); if (!empty($error)) return $this->error($error); $module = $contactData['module']; $structure = $this->calculateFieldStructure($module); $output = $this->formatOutputData(array('structure' => $structure), $contactData, $options); return $this->success($output); } public function sendSupportRequest($cid, $subject, $description, $options = array()) { global $adb, $table_prefix; $error = null; $contactData = $this->validateContactId($cid, $error); if (!empty($error)) { if ($error === 'OPERATION_DENIED') { if (empty($contactData['business_id'])) { return $this->error($error); } } else { return $this->error($error); } } if (empty($subject)) { return $this->error('INVALID_SUBJECT'); } if (empty($description)) { return $this->error('INVALID_DESCRIPTION'); } $module = $contactData['module']; $contactid = $contactData['contactid']; $contactEmail = $contactData['email']; $templateid = $this->templates['support_request_template']; $r = array( '$custom||gdpr_support_request_sender$' => $contactEmail, '$custom||gdpr_support_request_subject$' => $subject, '$custom||gdpr_support_request_description$' => $description ); $status = $this->sendEmailTemplate($module, $contactid, $this->senderEmail, $templateid, $r); if ($status) { $this->log($contactid, 'SUPPORT_REQUEST_SENT', array()); } else { $this->log($contactid, 'SUPPORT_REQUEST_NOT_SENT', array()); } return $status ? $this->success(array()) : $this->error('SEND_EMAIL_FAILED'); } public function getPrivacyPolicy($cid, $options = array()) { global $adb, $table_prefix; $error = null; $contactData = $this->validateContactId($cid, $error); if (!empty($error)) { if ($error === 'OPERATION_DENIED') { if (empty($contactData['business_id'])) { return $this->error($error); } } else { return $this->error($error); } } $bid = $contactData['business_id']; $PPU = PrivacyPolicyUtils::getInstance(); $companyPrivacyPolicy = $PPU->get($bid, 'Company'); $output = array('privacy_policy' => $companyPrivacyPolicy); return $this->success($output); } public function sendPrivacyPolicy($cid, $options = array()) { global $adb, $table_prefix; $error = null; $contactData = $this->validateContactId($cid, $error); if (!empty($error)) { if ($error === 'OPERATION_DENIED') { if (empty($contactData['business_id'])) { return $this->error($error); } } else { return $this->error($error); } } $bid = $contactData['business_id']; $PPU = PrivacyPolicyUtils::getInstance(); $companyPrivacyPolicy = $PPU->get($bid, 'Company'); $contactEmail = $contactData['email']; $success = send_mail('', $contactEmail, $this->senderName, $this->senderEmail, 'Privacy Policy', $companyPrivacyPolicy); return $success ? $this->success(array()) : $this->error('SEND_EMAIL_FAILED'); } protected function sendAccessEmail($contactData, $accesstoken) { $module = $contactData['module']; $contactid = $contactData['contactid']; $email = $contactData['email']; $templateid = $this->templates['access_template']; $newsletterFocus = CRMEntity::getInstance('Newsletter'); $gdprLink = $newsletterFocus->gdpr_link; $r = array( '$custom||gdpr_access_login_link$' => $gdprLink.'?action=detailview&accesstoken='.urlencode($accesstoken), ); $status = $this->sendEmailTemplate($module, $contactid, $email, $templateid, $r); if ($status) { $this->log($contactid, 'ACCESSTOKEN_SENT', array()); } else { $this->log($contactid, 'ACCESSTOKEN_NOT_SENT', array()); } return $status; } protected function deleteOrphanToken($contactid) { global $adb, $table_prefix; // Clean old expired authtoken $sql = "DELETE FROM {$this->authTable} WHERE contactid = ? AND authtoken_confirmed = 0 AND authtoken_expire <= ?"; $adb->pquery($sql, array($contactid, date('Y-m-d H:i:s'))); // Clean old expired accesstoken $sql = "DELETE FROM {$this->authTable} WHERE contactid = ? AND accesstoken_expire <= ?"; $adb->pquery($sql, array($contactid, date('Y-m-d H:i:s'))); } protected function deleteOrphanConfirmToken($contactid) { global $adb, $table_prefix; // Clean old expired token $sql = "DELETE FROM {$this->confirmTable} WHERE contactid = ? AND token_expire <= ?"; $adb->pquery($sql, array($contactid, date('Y-m-d H:i:s'))); } protected function validateAuthToken($contactid, $authtoken) { global $adb, $table_prefix; $checkQuery = "SELECT 1 FROM {$this->authTable} WHERE contactid = ? AND authtoken = ? AND authtoken_confirmed = 0 AND authtoken_expire > ?"; $checkResult = $adb->pquery($checkQuery, array($contactid, $authtoken, date('Y-m-d H:i:s'))); return $checkResult && $adb->num_rows($checkResult) > 0; } protected function countActiveAccessToken($contactid) { global $adb, $table_prefix; $checkQuery = "SELECT 1 FROM {$this->authTable} WHERE contactid = ? AND accesstoken_confirmed = 1 AND accesstoken_expire > ?"; $checkResult = $adb->pquery($checkQuery, array($contactid, date('Y-m-d H:i:s'))); return $adb->num_rows($checkResult); } protected function validateAccessToken($accesstoken, &$error) { global $adb, $table_prefix; $contactid = null; if ($this->checkFirstAccess($accesstoken, $contactid)) return $contactid; if (!$this->checkAccessTokenExpire($accesstoken, $contactid)) { $error = 'SESSION_EXPIRED'; } return $contactid; } protected function checkAccessTokenExpire($accesstoken, &$contactid = null) { global $adb, $table_prefix; $checkQuery = "SELECT contactid FROM {$this->authTable} WHERE accesstoken = ? AND accesstoken_confirmed = 1 AND accesstoken_expire > ?"; $checkResult = $adb->pquery($checkQuery, array($accesstoken, date('Y-m-d H:i:s'))); if ($checkResult && $adb->num_rows($checkResult) > 0) { $contactid = intval($adb->query_result($checkResult, 0, 'contactid')); return true; } return false; } protected function checkFirstAccess($accesstoken, &$contactid = null) { global $adb, $table_prefix; $checkQuery = "SELECT contactid FROM {$this->authTable} WHERE accesstoken = ? AND accesstoken_confirmed = 0 AND accesstoken_expire > ?"; $checkResult = $adb->pquery($checkQuery, array($accesstoken, date('Y-m-d H:i:s'))); if ($checkResult && $adb->num_rows($checkResult) > 0) { $contactid = intval($adb->query_result($checkResult, 0, 'contactid')); $adb->pquery("UPDATE {$this->authTable} SET accesstoken_confirmed = 1, accesstoken_confirmedtime = ? WHERE accesstoken = ?", array(date('Y-m-d H:i:s'), $accesstoken)); return true; } return false; } protected function updateAccessTokenContact($contactid, $accesstoken, $maincontact) { global $adb, $table_prefix; if (!$this->checkAccessTokenExpire($accesstoken)) { return false; } $adb->pquery("UPDATE {$this->authTable} SET contactid = ? WHERE contactid = ? AND accesstoken = ?", array($maincontact, $contactid, $accesstoken)); return true; } protected function invalidateContactTokens($contactid) { global $adb, $table_prefix; $adb->pquery("DELETE FROM {$this->authTable} WHERE contactid = ?", array($contactid)); return true; } protected function validateConfirmToken($contactid, $accesstoken, $token) { global $adb, $table_prefix; $checkQuery = "SELECT 1 FROM {$this->confirmTable} WHERE contactid = ? AND accesstoken = ? AND token = ? AND token_confirmed = 0 AND token_expire > ?"; $checkResult = $adb->pquery($checkQuery, array($contactid, $accesstoken, $token, date('Y-m-d H:i:s'))); return $checkResult && $adb->num_rows($checkResult) > 0; } protected function getContactDuplicates($module, $contactid, $column, $value) { global $adb, $table_prefix, $current_user; $RM = RelationManager::getInstance(); $qg = QueryGenerator::getInstance($module, $current_user); $idcol = $qg->getSQLColumn('id', false); $qg->initForAllCustomView(); $qg->addField('id'); $qg->addFieldAlias('id', 'crmid'); $fields = $this->getAvailableFields($module, false); foreach ($fields as $field) { $qg->addField($field); $qg->addFieldAlias($field, $field); } $query = $qg->getQuery(); $query .= " AND $column = ? AND COALESCE(gdpr_deleted, 0) <> 1"; $duplicates = array(); $duplicateResult = $adb->pquery($query, array($value)); if ($duplicateResult && $adb->num_rows($duplicateResult)) { while ($row = $adb->fetchByAssoc($duplicateResult, -1, false)) { $contact = array(); $contact['crmid'] = $row['crmid']; $contact['entityname'] = getEntityName($module, array($row['crmid']), true); $contact['details'] = array(); foreach ($fields as $field) { $fieldWS = WebserviceField::fromCachedWS($module, $field); $contact['details'][] = array( 'fieldname' => $field, 'fieldlabel' => getTranslatedString($fieldWS->getFieldLabelKey(), $module), 'value' => $row[$field], ); } $relids = $RM->getRelatedIds($module, $row['crmid']); $contact['relids'] = count($relids); $contact['suggested'] = false; $duplicates[] = $contact; } } if (count($duplicates) < 2) $duplicates = array(); if (!empty($duplicates)) { $suggestedDuplicate = $duplicates[0]; foreach ($duplicates as $duplicate) { if ($duplicate['relids'] > $maxRelations) { $suggestedDuplicate = $duplicate; } } foreach ($duplicates as &$duplicate) { if ($duplicate['crmid'] !== $suggestedDuplicate['crmid']) continue; $duplicate['suggested'] = true; } } return $duplicates; } protected function getAvailableFields($module, $gdprFields = true) { $fields = array(); if (is_array($this->availableFields[$module])) { $fields = array_merge($fields, $this->availableFields[$module]); } if ($gdprFields && is_array($this->gdprFields)) { $fields = array_merge($fields, $this->gdprFields); } return $fields; } protected function calculateFieldStructure($module) { global $adb, $table_prefix; $structure = array(); $blocks = array(); $fields = $this->getAvailableFields($module, false); foreach ($fields as $fieldname) { $fieldWS = WebserviceField::fromCachedWS($module, $fieldname); $fld = array(); $fld['name'] = $fieldWS->getFieldName(); $fld['blockid'] = $fieldWS->getBlockId(); $fld['label'] = strtolower(preg_replace('/\s+/', '_', $fieldWS->getFieldLabelKey())); $fld['type'] = array('name' => $fieldWS->getFieldDataType()); $fld['uitype'] = $fieldWS->getUIType(); $blockid = $fieldWS->getBlockId(); if ($blockid > 0) { if (!is_array($blocks[$blockid])) { $res = $adb->pquery("SELECT * FROM {$table_prefix}_blocks WHERE blockid = ?", array($blockid)); if ($res && $adb->num_rows($res) > 0) { $row = $adb->fetchByAssoc($res, -1, false); $block = array( 'blockid' => $blockid, 'module' => $module, 'tabid' => getTabid($module), 'label' => strtolower(str_replace('LBL_', '', $row['blocklabel'])), 'sequence' => $row['sequence'], ); $blocks[$blockid] = $block; } } $blocks[$blockid]['fields'][] = $fld; } } foreach ($blocks as $blockid => $binfo) { usort($blocks[$blockid]['fields'], function($v1,$v2) { return ($v1["sequence"] > $v2["sequence"] ? +1 : ($v1["sequence"] < $v2["sequence"] ? -1 : 0)); }); $blocks[$blockid]['fields'] = $blocks[$blockid]['fields']; } $structure = array_values($blocks); usort($structure, function($v1,$v2) { return ($v1["sequence"] > $v2["sequence"] ? +1 : ($v1["sequence"] < $v2["sequence"] ? -1 : 0)); }); return $structure; } protected function enqueueUpdate($contactData, $accesstoken, $operation, $data, &$error) { global $adb, $table_prefix; $contactid = $contactData['contactid']; $token = $this->generateToken(32); $servertime = time(); $expireTime = time() + (60*60*2); $params = array( 'queueid' => $adb->getUniqueID($this->confirmTable), 'contactid' => $contactid, 'accesstoken' => $accesstoken, 'timestamp' => date('Y-m-d H:i:s'), 'operation' => $operation, 'operation_remote_addr' => getIp(), 'data' => Zend_Json::encode($data), 'token' => $token, 'token_expire' => date('Y-m-d H:i:s', $expireTime), 'token_createdtime' => date('Y-m-d H:i:s'), 'token_remote_addr' => getIp(), 'token_confirmed' => 0, ); $columns = array_keys($params); $adb->format_columns($columns); $adb->pquery("INSERT INTO {$this->confirmTable} (" . implode(',', $columns) . ") VALUES (" . generateQuestionMarks($params) . ")", $params); $this->log($contactid, 'REQUEST_CONTACT_UPDATE', array()); $error = null; $success = $this->sendConfirmEmail($contactData, $accesstoken, $token, $error); if (!$success) $error = "SEND_EMAIL_FAILED"; return $success; } protected function applyContactChanges($contactData, $accesstoken, $token, &$error) { global $adb, $table_prefix; $output = array(); $module = $contactData['module']; $contactid = $contactData['contactid']; $email = $contactData['email']; $changesQuery = "SELECT * FROM {$this->confirmTable} WHERE contactid = ? AND accesstoken = ? AND token = ? AND token_confirmed = 1"; $changesResult = $adb->pquery($changesQuery, array($contactid, $accesstoken, $token)); if ($changesResult && $adb->num_rows($changesResult)) { $row = $adb->fetchByAssoc($changesResult, -1, false); $operation = $row['operation']; $data = Zend_Json::decode($row['data']); if ($operation === 'UPDATE_CONTACT') { $this->applyContactUpdate($contactData, $accesstoken, $data); } elseif ($operation === 'DELETE_CONTACT') { $this->applyContactDelete($contactData, $accesstoken, $data); } elseif ($operation === 'MERGE_CONTACT') { $this->applyContactMerge($contactData, $accesstoken, $data); } $this->log($contactid, $operation, array()); } return $output; } public function applyContactUpdate($contactData, $accesstoken, $data) { global $adb, $table_prefix; $module = $contactData['module']; $contactid = $contactData['contactid']; $email = $contactData['email']; $focus = CRMEntity::getInstance($module); $focus->retrieve_entity_info_no_html($contactid, $module, false); $focus->mode = 'edit'; $focus->id = $contactid; $gdprFields = $this->gdprFields; foreach ($data as $fieldname => $value) { if (in_array($fieldname, $gdprFields)) { $value = $value === 'true' ? '1' : '0'; $focus->column_fields[$fieldname] = $value; $focus->column_fields[$fieldname.'_checkedtime'] = date('Y-m-d H:i:s'); $focus->column_fields[$fieldname.'_remote_addr'] = getIp(); } else { if (isset($focus->column_fields[$fieldname])) { $focus->column_fields[$fieldname] = $value; } } } $focus->save($module); $newsletterFocus = CRMEntity::getInstance('Newsletter'); if ($focus->column_fields['gdpr_marketing'] === '0') { $newsletterFocus->lockReceivingNewsletter($email, 'lock'); } else { $newsletterFocus->lockReceivingNewsletter($email, 'unlock'); } $this->log($contactid, 'CONTACT_UPDATED', array($data)); } public function applyContactDelete($contactData, $accesstoken, $data) { global $adb, $table_prefix; $module = $contactData['module']; $contactid = $contactData['contactid']; $email = $contactData['email']; $focus = CRMEntity::getInstance($module); $err = $focus->retrieve_entity_info_no_html($contactid, $module, false); // crmv@182782 $focus->mode = 'edit'; $focus->id = $contactid; $RM = RelationManager::getInstance(); $fields = $this->getAvailableFields($module); $gdprFields = $this->gdprFields; // 0. Notify $this->notifyAnonymize($focus); // 1. Empty fields foreach ($fields as $fieldname) { if (in_array($fieldname, $gdprFields)) { $focus->column_fields[$fieldname] = '0'; $focus->column_fields[$fieldname.'_checkedtime'] = date('Y-m-d H:i:s'); $focus->column_fields[$fieldname.'_remote_addr'] = getIp(); } else { if ($fieldname === 'gdpr_sentdate') continue; if (isset($focus->column_fields[$fieldname])) { $focus->column_fields[$fieldname] = getTranslatedString('LBL_ANONYMOUS', 'Settings'); } } } // 2. Set contact as GDPR deleted $focus->column_fields['gdpr_deleted'] = '1'; $focus->column_fields['gdpr_deleted_checkedtime'] = date('Y-m-d H:i:s'); $focus->column_fields['gdpr_deleted_remote_addr'] = getIp(); $emailField = $this->emailFields[$module]['fieldname']; $focus->column_fields[$emailField] = getTranslatedString('LBL_ANONYMOUS', 'Settings'); // crmv@182782 if ($err == 'LBL_RECORD_DELETE') { $focus->save($module,false,false,false); } else { $focus->save($module); } // crmv@182782e // 3. Turn off the automatic emails $newsletterFocus = CRMEntity::getInstance('Newsletter'); $newsletterFocus->lockReceivingNewsletter($email, 'lock'); // 4. Empty changelog history // crmv@164120 $changeLogFocus = ChangeLog::getInstance(); $changeLogFocus->deleteforRecord($module, $contactid); // crmv@164120e // 5. Invalidate accesstoken $this->invalidateContactTokens($contactid); $this->log($contactid, 'CONTACT_DELETED', array()); } public function applyContactMerge($contactData, $accesstoken, $data) { global $adb, $table_prefix; $module = $contactData['module']; $contactid = $contactData['contactid']; $email = $contactData['email']; $RM = RelationManager::getInstance(); $maincontact = $data['main_contact']; $focus = CRMEntity::getInstance($module); $focus->retrieve_entity_info_no_html($maincontact, $module, false); $focus->mode = 'edit'; $focus->id = $maincontact; foreach ($data as $fieldname => $value) { if (isset($focus->column_fields[$fieldname])) { $focus->column_fields[$fieldname] = $value; } } global $global_skip_notifications; $tmp_global_skip_notifications = $global_skip_notifications; $global_skip_notifications = true; $focus->save($module); $global_skip_notifications = $tmp_global_skip_notifications; $transferRelations = $data['transfer_relations']; foreach ($transferRelations as $transferid) { $relatedIds = $RM->getRelatedIds($module, $transferid); // crmv@164120 // Transfer all relations foreach ($relatedIds as $id) { $RM->relate($module, $maincontact, getSalesEntityType($id), $id); } $transferFocus = CRMEntity::getInstance($module); $transferFocus->retrieve_entity_info_no_html($transferid, $module, false); $transferFocus->mode = 'edit'; $transferFocus->id = $transferid; $transferFocus->mark_deleted($transferid); } // Update access token with selected contact $this->updateAccessTokenContact($contactid, $accesstoken, $maincontact); $this->log($contactid, 'CONTACT_MERGED', array()); } public function lockContact($email) { global $adb; foreach ($this->emailFields as $module => $field) { if (self::isEnabledForModule($module)) { $focus = CRMEntity::getInstance($module); $update = array('gdpr_sentdate = ?' => date('Y-m-d H:i:s')); foreach ($this->gdprFields as $gdprField) { $update["$gdprField = ?"] = 0; } $adb->pquery("UPDATE {$field['tablename']} SET " . implode(',', array_keys($update)) . " WHERE {$field['columnname']} = ?", array(array_values($update), $email)); } } $newsletterFocus = CRMEntity::getInstance('Newsletter'); $newsletterFocus->lockReceivingNewsletter($email, 'lock'); } protected function sendConfirmEmail($contactData, $accesstoken, $token, &$error) { $module = $contactData['module']; $contactid = $contactData['contactid']; $email = $contactData['email']; $templateid = $this->templates['confirm_update_template']; $newsletterFocus = CRMEntity::getInstance('Newsletter'); $gdprLink = $newsletterFocus->gdpr_link; $r = array( '$custom||gdpr_update_confirm_link$' => $gdprLink.'?action=confirm-update&accesstoken='.urlencode($accesstoken).'&token='.urlencode($token), ); $status = $this->sendEmailTemplate($module, $contactid, $email, $templateid, $r); if ($status) { $this->log($contactid, 'CONFIRM_EMAIL_SENT', array()); } else { $this->log($contactid, 'CONFIRM_EMAIL_NOT_SENT', array()); } return $status; } public function sendContactNotifyChangeEmail($module, $contactid) { $templateid = $this->templates['contact_updated_template']; $focus = CRMEntity::getInstance($module); $ret = $focus->retrieve_entity_info_no_html($contactid, $module, false); $focus->id = $contactid; $emailField = $this->emailFields[$module]['fieldname']; $email = $focus->column_fields[$emailField]; $newsletterFocus = CRMEntity::getInstance('Newsletter'); $gdprLink = $newsletterFocus->gdpr_link; $cid = urlencode(base64_encode("C|".$email."|".$module)); $r = array( '$custom||gdpr_verify_link$' => $gdprLink.'?action=verify&cid='.$cid, ); $status = $this->sendEmailTemplate($module, $contactid, $email, $templateid, $r); if ($status) { $this->log($contactid, 'NOTIFY_CHANGE_EMAIL_SENT', array()); } else { $this->log($contactid, 'NOTIFY_CHANGE_EMAIL_NOT_SENT', array()); } return $status; } protected function sendEmailTemplate($module, $contactid, $email, $templateid, $replacements = array()) { global $adb, $table_prefix; $emailTemplateId = $templateid; $result = $adb->pquery("SELECT subject, body FROM {$table_prefix}_emailtemplates WHERE templateid = ?", array($emailTemplateId)); $tsubject = $adb->query_result_no_html($result, 0, 'subject'); $tdescription = $adb->query_result_no_html($result, 0, 'body'); if (empty($tsubject) || empty($tdescription) || empty($emailTemplateId)) return false; $r = $replacements; $tdescription = str_replace(array_keys($r), array_values($r), $tdescription); $tdescription = getMergedDescription($tdescription, $contactid, $module); $success = send_mail('', $email, $this->senderName, $this->senderEmail, $tsubject, $tdescription); return $success; } protected function formatOutputData($data, $contactData, $options = array()) { $out = array_merge(array(), $data); $options = array_merge(array('include_contacts_data' => true), $options); if ($options && $options['include_contacts_data']) { $module = $contactData['module']; $contactid = $contactData['contactid']; $contactEmail = $contactData['email']; $column = $contactData['email_field']['tablename'].'.'.$contactData['email_field']['columnname']; $value = $contactEmail; $duplicates = $this->getContactDuplicates($module, $contactid, $column, $value); $out = array_merge(array('email' => $contactEmail, 'contact' => $contactData['available_data'], 'duplicates' => $duplicates, 'business_id' => $contactData['business_id']), $out); } return $out; } protected function log($contactid, $operation, $data = array()) { global $adb, $table_prefix; if (empty($operation)) return; $params = array( 'logid' => $adb->getUniqueID($this->logTable), 'contactid' => $contactid, 'timestamp' => date('Y-m-d H:i:s'), 'operation' => $operation, 'operation_remote_addr' => getIp(), 'data' => Zend_Json::encode($data), ); $columns = array_keys($params); $adb->format_columns($columns); $adb->pquery("INSERT INTO {$this->logTable} (" . implode(',', $columns) . ") VALUES (" . generateQuestionMarks($params) . ")", $params); } public function generateToken($length = 32) { return base64_encode(crypt_random_string($length)); } public function error($message, $data = array()) { $out = array_merge(array('success' => false, 'error' => $message, 'cid' => $this->cid, 'cid_data' => $this->cidData), $data); return $out; } public function success($data = array()) { $out = array_merge(array('success' => true, 'cid' => $this->cid, 'cid_data' => $this->cidData), $data); return $out; } protected function initCustomWebserviceOperations() { $operations = array(); $parameters = array('contactid' => 'string'); $operations['gdpr_authtoken'] = array('file' => 'include/utils/GDPRWS/webservices/AuthToken.php', 'handler' => 'gdpr_authtoken', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $parameters = array('contactid' => 'string', 'authtoken' => 'string'); $operations['gdpr_sendverify'] = array('file' => 'include/utils/GDPRWS/webservices/SendVerify.php', 'handler' => 'gdpr_sendverify', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $parameters = array('contactid' => 'string', 'authtoken' => 'string'); $operations['gdpr_accesstoken'] = array('file' => 'include/utils/GDPRWS/webservices/AccessToken.php', 'handler' => 'gdpr_accesstoken', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $parameters = array('accesstoken' => 'string'); $operations['gdpr_checkaccesstoken'] = array('file' => 'include/utils/GDPRWS/webservices/CheckAccessToken.php', 'handler' => 'gdpr_checkaccesstoken', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $parameters = array('accesstoken' => 'string', 'data' => 'encoded'); $operations['gdpr_update'] = array('file' => 'include/utils/GDPRWS/webservices/Update.php', 'handler' => 'gdpr_update', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $parameters = array('accesstoken' => 'string', 'maincontact' => 'int', 'otherids' => 'encoded'); $operations['gdpr_mergecontact'] = array('file' => 'include/utils/GDPRWS/webservices/Merge.php', 'handler' => 'gdpr_mergecontact', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $parameters = array('accesstoken' => 'string'); $operations['gdpr_fields'] = array('file' => 'include/utils/GDPRWS/webservices/Fields.php', 'handler' => 'gdpr_fields', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $parameters = array('accesstoken' => 'string', 'token' => 'string'); $operations['gdpr_confirmupdate'] = array('file' => 'include/utils/GDPRWS/webservices/ConfirmUpdate.php', 'handler' => 'gdpr_confirmupdate', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $parameters = array('accesstoken' => 'string'); $operations['gdpr_delete'] = array('file' => 'include/utils/GDPRWS/webservices/Delete.php', 'handler' => 'gdpr_delete', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $parameters = array('contactid' => 'string'); $operations['gdpr_privacypolicy'] = array('file' => 'include/utils/GDPRWS/webservices/PrivacyPolicy.php', 'handler' => 'gdpr_privacypolicy', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $parameters = array('contactid' => 'string', 'subject' => 'string', 'description' => 'string'); $operations['gdpr_supportrequest'] = array('file' => 'include/utils/GDPRWS/webservices/SupportRequest.php', 'handler' => 'gdpr_supportrequest', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $parameters = array('contactid' => 'string'); $operations['gdpr_sendprivacypolicy'] = array('file' => 'include/utils/GDPRWS/webservices/SendPrivacyPolicy.php', 'handler' => 'gdpr_sendprivacypolicy', 'reqtype' => 'POST', 'prelogin' => '0', 'parameters' => $parameters); $this->registerCustomWebservices($operations); } protected function registerCustomWebservices($operations) { global $adb, $table_prefix; foreach ($operations as $operationName => $operationInfo) { $exists = $adb->pquery("SELECT operationid FROM {$table_prefix}_ws_operation WHERE name = ?", array($operationName)); if ($exists && $adb->num_rows($exists) < 1) { $operationId = $adb->getUniqueId($table_prefix . '_ws_operation'); $params = array( 'operationid' => $operationId, 'name' => $operationName, 'handler_path' => $operationInfo['file'], 'handler_method' => $operationInfo['handler'], 'type' => $operationInfo['reqtype'], 'prelogin' => $operationInfo['prelogin'] ); $columns = array_keys($params); $adb->format_columns($columns); $adb->pquery("INSERT INTO {$table_prefix}_ws_operation (" . implode(',', $columns) . ") VALUES (" . generateQuestionMarks($params) . ")", $params); $parameters = $operationInfo['parameters']; $parameterIndex = 0; foreach ($parameters as $parameterName => $parameterType) { $params = array( 'operationid' => $operationId, 'name' => $parameterName, 'type' => $parameterType, 'sequence' => ($parameterIndex + 1) ); $columns = array_keys($params); $adb->format_columns($columns); $adb->pquery("INSERT INTO {$table_prefix}_ws_operation_parameters (" . implode(',', $columns) . ") VALUES (" . generateQuestionMarks($params) . ")", $params); ++$parameterIndex; } } } } // crmv@194712 public function updateConvertLead() { global $adb, $table_prefix; $gdprFieldMappingList = $this->getGdprFieldMappingList(); $fieldMap = array(); $fieldIds = array('Leads' => array(), 'Accounts' => array(), 'Contacts' => array(), 'Potentials' => array()); foreach ($gdprFieldMappingList as $gdprField) { $fieldMap[] = $gdprField; if (!empty($gdprField[0])) { $fieldIds['Leads'][$gdprField[0]] = null; } if (!empty($gdprField[1])) { $fieldIds['Accounts'][$gdprField[1]] = null; } if (!empty($gdprField[2])) { $fieldIds['Contacts'][$gdprField[2]] = null; } if (!empty($gdprField[3])) { $fieldIds['Potentials'][$gdprField[3]] = null; } } foreach ($fieldIds as $module => $fields) { if (!empty($fields)) { $fieldQuery = "SELECT fieldname, fieldid FROM {$table_prefix}_field WHERE tabid = ? AND fieldname IN (" . generateQuestionMarks($fields) . ")"; $fieldRes = $adb->pquery($fieldQuery, array(getTabid($module), array_keys($fields))); if (!!$fieldRes && $adb->num_rows($fieldRes) > 0) { while ($row = $adb->fetchByAssoc($fieldRes, -1, false)) { $fieldIds[$module][$row['fieldname']] = $row['fieldid']; } } } } foreach ($fieldMap as $values) { $leadfid = $fieldIds['Leads'][$values[0]]; if (empty($leadfid)) continue; $checkMappingQuery = "SELECT 1 FROM {$table_prefix}_convertleadmapping WHERE leadfid = ?"; $checkMappingRes = $adb->pquery($checkMappingQuery, array($leadfid)); if (!!$checkMappingRes && $adb->num_rows($checkMappingRes) > 0) { continue; } $accountfid = $fieldIds['Accounts'][$values[1]]; if (empty($accountfid)) $accountfid = null; $contactfid = $fieldIds['Contacts'][$values[2]]; if (empty($contactfid)) $contactfid = null; $potentialfid = $fieldIds['Potentials'][$values[3]]; if (empty($potentialfid)) $potentialfid = null; $insertQuery = "INSERT INTO {$table_prefix}_convertleadmapping (cfmid, leadfid, accountfid, contactfid, potentialfid) VALUES (?, ?, ?, ?, ?)"; $adb->pquery($insertQuery, array($adb->getUniqueID($table_prefix . "_convertleadmapping"), $leadfid, $accountfid, $contactfid, $potentialfid)); } } // crmv@194712e public function checkNoConfirmDeletion() { global $adb, $table_prefix; if (empty($this->noconfirm_deletion_months)) $this->noconfirm_deletion_months = $this->default_noconfirm_deletion_months; $deletion_time = date('Y-m-d H:i:s', strtotime("-{$this->noconfirm_deletion_months} months")); foreach ($this->emailFields as $module => $field) { if (self::isEnabledForModule($module)) { $focus = CRMEntity::getInstance($module); $result = $adb->pquery("SELECT {$focus->tab_name_index[$field['tablename']]} as \"crmid\", {$field['columnname']} as \"email\" FROM {$field['tablename']} WHERE gdpr_privacypolicy = ? and gdpr_deleted = ? and gdpr_sentdate is not null and gdpr_sentdate <> ? and gdpr_sentdate < ?", array(0,0, '0000-00-00 00:00:00', $adb->formatDate($deletion_time, true))); // crmv@182782 if ($result && $adb->num_rows($result) > 0) { while ($row = $adb->fetchByAssoc($result)) { $this->applyContactDelete(array('module' => $module, 'contactid' => $row['crmid'], 'email' => $row['email']), null, null); } } } } } protected function notifyAnonymize($focus) { $subject = getTranslatedString('LBL_GDPR_NOTIFY_ANONYMIZE_SUBJECT', 'Settings'); $description = getTranslatedString('LBL_GDPR_NOTIFY_ANONYMIZE_BODY', 'Settings'); $description = sprintf($description, $focus->column_fields['firstname'], $focus->column_fields['lastname'], $focus->column_fields['email'], date('Y-m-d', strtotime("+{$this->noconfirm_deletion_months} months"))); $success = send_mail('', $this->senderEmail, $this->senderName, $this->senderEmail, $subject, $description); return $success; } public function getBusinessId($crmid, $module, $email = '') { global $adb, $table_prefix, $current_user; $BU = BusinessUnit::getInstance(); if ($module === 'Contacts' && !BusinessUnit::isEnabledForModule($module)) { $contactFocus = CRMEntity::getInstance('Contacts'); $contactFocus->id = $crmid; $s = $contactFocus->retrieve_entity_info($crmid, 'Contacts', false); if (empty($s)) { $accountId = intval($contactFocus->column_fields['account_id']); if ($accountId > 0) { $module = 'Accounts'; $crmid = $accountId; } } } $business = BusinessUnit::getBusinessForId($crmid); $useDefaultBusiness = false; if (!empty($email)) { if (BusinessUnit::isEnabledForModule($module) && isset($this->emailFields[$module])) { $focus = CRMEntity::getInstance($module); $tableIndex = $focus->table_index; $column = $this->emailFields[$module]['tablename'].'.'.$this->emailFields[$module]['columnname']; $businessByEmail = $adb->pquery("SELECT DISTINCT(bu_mc) FROM {$this->emailFields[$module]['tablename']} INNER JOIN {$table_prefix}_crmentity ON {$this->emailFields[$module]['tablename']}.{$tableIndex} = {$table_prefix}_crmentity.crmid WHERE {$table_prefix}_crmentity.deleted = 0 AND {$column} = ?", array($email)); if ($businessByEmail && $adb->num_rows($businessByEmail) > 1) { $useDefaultBusiness = true; } } } $businessId = 0; if ($business) { $vteProp = VTEProperties::getInstance(); $generalSettings = $vteProp->get('services.gdpr.general_settings'); $businessId = $generalSettings['default_business']; if ((count($business) === 1 && !empty($business[0])) && !$useDefaultBusiness) { $businessInfo = $BU->getBusinessInfoByName($business[0]); $businessId = $businessInfo['organizationid']; } else { $businessId = $generalSettings['default_business']; } } else { $businessList = $BU->getBusinessList(); if (!empty($businessList)) { $businessId = $businessList[0]['organizationid']; } } return $businessId; } // crmv@194712 public function getGdprFieldMappingList() { $fields = array(); $gdprFields = $this->gdprFields; foreach ($gdprFields as $gdprField) { $fields[] = array($gdprField, null, $gdprField, null); $fields[] = array($gdprField.'_checkedtime', null, $gdprField.'_checkedtime', null); $fields[] = array($gdprField.'_remote_addr', null, $gdprField.'_remote_addr', null); } $fields[] = array('gdpr_deleted', null, 'gdpr_deleted', null); $fields[] = array('gdpr_deleted_checkedtime', null, 'gdpr_deleted_checkedtime', null); $fields[] = array('gdpr_deleted_remote_addr', null, 'gdpr_deleted_remote_addr', null); $fields[] = array('gdpr_sentdate', null, 'gdpr_sentdate', null); return $fields; } // crmv@194712e }