diff --git a/CRM/TwingleCampaign/BAO/CustomField.php b/CRM/TwingleCampaign/BAO/CustomField.php index dea24f9..174e715 100644 --- a/CRM/TwingleCampaign/BAO/CustomField.php +++ b/CRM/TwingleCampaign/BAO/CustomField.php @@ -62,10 +62,10 @@ class CRM_TwingleCampaign_BAO_CustomField { * * @param bool $upgrade * If true: Does not show UF message if custom field already exists - * + * @returns array Result of custom field creation api call * @throws \CiviCRM_API3_Exception */ - public function create(bool $upgrade = false) { + public function create(bool $upgrade = FALSE): ?array { // Check if the field already exists $field = civicrm_api3( @@ -95,6 +95,7 @@ class CRM_TwingleCampaign_BAO_CustomField { id: $this->id group: $this->custom_group_id" ); + return $this->result; } // If the field could not get created: log error else { @@ -112,12 +113,17 @@ class CRM_TwingleCampaign_BAO_CustomField { $this->result['error_message']"); CRM_Utils_System::setUFMessage(E::ts("Creation of custom field failed. Find more information in the logs.")); } + return $this->result; } } elseif (!$upgrade) { CRM_Utils_System::setUFMessage(E::ts('Creation of custom field \'%1\' failed, because a custom field with that name already exists. Find more information in the logs.', [1 => $this->name])); Civi::log() ->error("$this->extensionName could not create new custom field \"$this->name\" for group \"$this->custom_group_id\" because a field with that name already exists."); + return NULL; + } + else { + return NULL; } } diff --git a/CRM/TwingleCampaign/Upgrader.php b/CRM/TwingleCampaign/Upgrader.php index 6cecff9..3d4d94d 100644 --- a/CRM/TwingleCampaign/Upgrader.php +++ b/CRM/TwingleCampaign/Upgrader.php @@ -13,13 +13,14 @@ use CRM_TwingleCampaign_ExtensionUtil as E; */ class CRM_TwingleCampaign_Upgrader extends CRM_TwingleCampaign_Upgrader_Base { - // By convention, functions that look like "function upgrade_NNNN()" are - // upgrade tasks. They are executed in order (like Drupal's hook_update_N). - /** + * This update function checks whether all custom fields defined in + * CRM/TwingleCampaign/resources/campaigns.php exist and creates them if not. + * To ensure that all newly created custom fields get filled with data, all + * changed campaigns will get pulled from Twingle. * @throws \CiviCRM_API3_Exception */ - public function upgrade_01() { + public function upgrade_01(): bool { $campaign_info = require E::path() . '/CRM/TwingleCampaign/resources/campaigns.php'; @@ -31,7 +32,7 @@ class CRM_TwingleCampaign_Upgrader extends CRM_TwingleCampaign_Upgrader_Base { new CampaignType($campaign_type); } foreach (CampaignType::getCampaignTypes() as $campaign_type) { - $campaign_type->create(true); + $campaign_type->create(TRUE); } // Create custom groups @@ -42,13 +43,61 @@ class CRM_TwingleCampaign_Upgrader extends CRM_TwingleCampaign_Upgrader_Base { } } $cg = new CustomGroup($custom_group); - $cg->create(true); + $cg->create(TRUE); } + // If new fields get created during the update, set a flag to set all + // last_update values of the affected campaigns to "0" and trigger a + // synchronization. This ensures that settings on Twingle's side will not + // get overwritten with empty values. + $updatedCampaignTypes = []; + // Create custom fields foreach ($campaign_info['custom_fields'] as $custom_field) { $cf = new CustomField($custom_field); - $cf->create(true); + $result = $cf->create(TRUE); + + if (!empty($result)) { + preg_match( + '/^Twingle_[a-yA-Z]*/', + $cf->getCustomGroupId(), + $updatedCampaignTypes[] + ); + } + } + + // Filter changed campaign types + foreach ($updatedCampaignTypes as $key => $value) { + $updatedCampaignTypes[str_replace('_', '', $value[0])] + = TRUE; + unset($updatedCampaignTypes[$key]); + } + + // Pull changed campaigns to fill new created fields with data + try { + foreach ($updatedCampaignTypes as $key => $value) { + if ($value === TRUE) { + civicrm_api3( + $key, + 'sync', + ['pull' => TRUE] + ); + } + } + } catch (Exception $e) { + Civi::log()->error( + E::LONG_NAME . + ' could not pull campaigns from Twingle to fill the campaign fields that were created on update.' . + $e->getMessage() + ); + CRM_Core_Session::setStatus( + E::ts( + 'Could not pull campaigns from Twingle to fill the campaign fields that were created within this update: %1', + [1 => $e->getMessage()] + ), + E::ts('Scheduled Job'), + error + ); } // Create option values @@ -124,7 +173,6 @@ class CRM_TwingleCampaign_Upgrader extends CRM_TwingleCampaign_Upgrader_Base { E::ts('Scheduled Job'), error ); - CRM_Utils_System::setUFMessage(E::ts('Could not create scheduled job "TwingleSync". Your Campaigns will not get synchronized to Twingle.')); } } diff --git a/api/v3/TwingleEvent/Sync.php b/api/v3/TwingleEvent/Sync.php index 9de54cb..23a8b88 100644 --- a/api/v3/TwingleEvent/Sync.php +++ b/api/v3/TwingleEvent/Sync.php @@ -41,6 +41,13 @@ function _civicrm_api3_twingle_event_Sync_spec(array &$spec) { 'api.required' => 0, 'description' => E::ts('If this is set true, no database change will be made'), ]; + $spec['pull'] = [ + 'name' => 'pull', + 'title' => E::ts('Pull'), + 'type' => CRM_Utils_Type::T_BOOLEAN, + 'api.required' => 0, + 'description' => E::ts('If this is set true, the event(s) will be pulled from Twingle and updated locally'), + ]; $spec['twingle_api_key'] = [ 'name' => 'twingle_api_key', 'title' => E::ts('Twingle API key'), @@ -111,6 +118,10 @@ function civicrm_api3_twingle_event_Sync(array $params): array { Civi::cache('long')->set('twinglecampaign_twingle_api', $twingleApi); } + // Set pull flag + $pull = (isset($params['pull']) && $params['pull']); + unset($params['pull']); + // If an id or a event_id is provided, synchronize only this one campaign if (isset($params['id']) || isset($params['event_id'])) { @@ -141,7 +152,13 @@ function civicrm_api3_twingle_event_Sync(array $params): array { } // Synchronize events if (!empty($event_from_twingle)) { - return _eventSync($event, $event_from_twingle, $twingleApi, $params); + return _eventSync( + $event, + $event_from_twingle, + $twingleApi, + $params, + $pull + ); } // If Twingle does not know an event with the given event_id, give error @@ -271,7 +288,13 @@ function civicrm_api3_twingle_event_Sync(array $params): array { $event = _instantiateEvent($event_from_civicrm, $event_from_civicrm['id']); // sync event - $result = _eventSync($event, $event_from_twingle, $twingleApi, $params); + $result = _eventSync( + $event, + $event_from_twingle, + $twingleApi, + $params, + $pull + ); if ($result['is_error'] != 0) { $errors_occurred++; $result_values[$event->getId()] = @@ -394,6 +417,7 @@ function _updateEventLocally(array $event_from_twingle, * @param array $event_from_twingle * @param \CRM_TwingleCampaign_BAO_TwingleApiCall $twingleApi * @param array $params + * @param bool $pull Force pulling event from Twingle and update local campaign * * @return array * @throws \CiviCRM_API3_Exception @@ -401,12 +425,13 @@ function _updateEventLocally(array $event_from_twingle, function _eventSync(TwingleEvent $event, array $event_from_twingle, TwingleApiCall $twingleApi, - array $params): array { + array $params, + bool $pull = FALSE): array { // If Twingle's timestamp of the event differs from the timestamp of the // CiviCRM TwingleEvent campaign, update the campaign on CiviCRM's side. // NOTE: Changes on TwingleEvents are not meant to get pushed to Twingle - if ($event_from_twingle['updated_at'] != $event->lastUpdate()) { + if ($event_from_twingle['updated_at'] != $event->lastUpdate() || $pull) { return _updateEventLocally($event_from_twingle, $event, $params, $twingleApi); } diff --git a/api/v3/TwingleProject/Sync.php b/api/v3/TwingleProject/Sync.php index 7768997..0906f14 100644 --- a/api/v3/TwingleProject/Sync.php +++ b/api/v3/TwingleProject/Sync.php @@ -35,6 +35,13 @@ function _civicrm_api3_twingle_project_Sync_spec(array &$spec) { 'api.required' => 0, 'description' => E::ts('If this is set true, no database change will be made'), ]; + $spec['pull'] = [ + 'name' => 'pull', + 'title' => E::ts('Pull from Twingle'), + 'type' => CRM_Utils_Type::T_BOOLEAN, + 'api.required' => 0, + 'description' => E::ts('If this is set true, the project(s) will be pulled from Twingle and updated locally'), + ]; $spec['twingle_api_key'] = [ 'name' => 'twingle_api_key', 'title' => E::ts('Twingle API key'), @@ -90,6 +97,10 @@ function civicrm_api3_twingle_project_Sync(array $params): array { Civi::cache('long')->set('twinglecampaign_twingle_api', $twingleApi); } + // Set pull flag + $pull = (isset($params['pull']) && $params['pull']); + unset($params['pull']); + // If an id or a project_id is given, synchronize only this one campaign if (isset($params['id']) || isset($params['project_id'])) { @@ -106,9 +117,15 @@ function civicrm_api3_twingle_project_Sync(array $params): array { $id = $result['id']; $project = new TwingleProject($result, $id); - // Synchronize projects + // Synchronize project if (!empty($project_from_twingle)) { - return _projectSync($project, $project_from_twingle, $twingleApi, $params); + return _projectSync( + $project, + $project_from_twingle, + $twingleApi, + $params, + $pull + ); } // If Twingle does not know a project with the given project_id, give error @@ -175,8 +192,10 @@ function civicrm_api3_twingle_project_Sync(array $params): array { // Push missing projects to Twingle $returnValues = []; foreach ($projects_from_civicrm['values'] as $project_from_civicrm) { - if (!in_array($project_from_civicrm['project_id'], - array_column($projects_from_twingle, 'id'))) { + if ( + !in_array($project_from_civicrm['project_id'], + array_column($projects_from_twingle, 'id') + )) { // store campaign id in $id $id = $project_from_civicrm['id']; unset($project_from_civicrm['id']); @@ -197,8 +216,11 @@ function civicrm_api3_twingle_project_Sync(array $params): array { // Create missing projects as campaigns in CiviCRM foreach ($projects_from_twingle as $project_from_twingle) { - if (!in_array($project_from_twingle['id'], - array_column($projects_from_civicrm['values'], 'project_id'))) { + if ( + !in_array($project_from_twingle['id'], + array_column($projects_from_civicrm['values'], + 'project_id') + )) { $project = new TwingleProject($project_from_twingle); try { @@ -241,10 +263,12 @@ function civicrm_api3_twingle_project_Sync(array $params): array { // sync project $result = _projectSync( - $project, - $project_from_twingle, - $twingleApi, - $params); + $project, + $project_from_twingle, + $twingleApi, + $params, + $pull + ); if (!$result['is_error'] == 0) { $errors[$result['id']] = $result['error_message']; $returnValues[$project->getId()] = @@ -457,6 +481,7 @@ function _pushProjectToTwingle(TwingleProject $project, * @param array $project_from_twingle * @param \CRM_TwingleCampaign_BAO_TwingleApiCall $twingleApi * @param array $params + * @param bool $pull Force pulling project from Twingle and update local campaign * * @return array * @throws \CiviCRM_API3_Exception @@ -464,11 +489,13 @@ function _pushProjectToTwingle(TwingleProject $project, function _projectSync(TwingleProject $project, array $project_from_twingle, TwingleApiCall $twingleApi, - array $params): array { + array $params, + bool $pull = FALSE): array { // If Twingle's version of the project is newer than the CiviCRM // TwingleProject campaign, update the campaign - if ($project_from_twingle['last_update'] > $project->lastUpdate()) { + if ($project_from_twingle['last_update'] > $project->lastUpdate() || + $pull) { return _updateProjectLocally($project_from_twingle, $project, $params, $twingleApi); } diff --git a/l10n/de_DE/LC_MESSAGES/twinglecampaign.mo b/l10n/de_DE/LC_MESSAGES/twinglecampaign.mo index e4a39ee..47867c3 100644 Binary files a/l10n/de_DE/LC_MESSAGES/twinglecampaign.mo and b/l10n/de_DE/LC_MESSAGES/twinglecampaign.mo differ diff --git a/l10n/de_DE/LC_MESSAGES/twinglecampaign.po b/l10n/de_DE/LC_MESSAGES/twinglecampaign.po index 7bfae67..7e83507 100644 --- a/l10n/de_DE/LC_MESSAGES/twinglecampaign.po +++ b/l10n/de_DE/LC_MESSAGES/twinglecampaign.po @@ -143,6 +143,18 @@ msgstr "keine" msgid "Upgrade %1 to revision %2" msgstr "Upgrade %1 auf Revision %2" +#: CRM/TwingleCampaign/Upgrader.php +msgid "" +"Could not pull campaigns from Twingle to fill the campaign fields that were " +"created within this update: %1" +msgstr "" +"Die zusätzlichen Kampagnenfelder, die in diesem Update erstellt wurden, " +"konnten nicht von Twingle bezogen werden: %1" + +#: CRM/TwingleCampaign/Upgrader.php +msgid "Scheduled Job" +msgstr "Geplante Audgabe" + #: CRM/TwingleCampaign/Upgrader.php msgid "" "Syncronizes all TwingleProjects an TwingleEvents between CiviCRM and Twingle" @@ -154,18 +166,6 @@ msgstr "" msgid "Could not create scheduled job \"TwingleSync\"." msgstr "Geplante Aufgabe \"TwingleSync\" konnte nicht erstellt werden." -#: CRM/TwingleCampaign/Upgrader.php -msgid "Scheduled Job" -msgstr "Geplante Audgabe" - -#: CRM/TwingleCampaign/Upgrader.php -msgid "" -"Could not create scheduled job \"TwingleSync\". Your Campaigns will not get " -"synchronized to Twingle." -msgstr "" -"Geplante Aufgabe \"TwingleSync\" konnte nicht erstellt werden. Ihre " -"Kampagnen werden nicht mit Twingle synchronisiert werden." - #: CRM/TwingleCampaign/Upgrader.php msgid "Could not delete scheduled job \"TwingleSync\"." msgstr "Geplante Aufgabe \"TwingleSync\" konnte nicht gelöscht werden." @@ -892,6 +892,14 @@ msgstr "Eltern Twingle Project ID" msgid "Twingle ID of the parent TwingleProject" msgstr "Twingle ID des Eltern-TwingleProject" +#: api/v3/TwingleCampaign/Get.php api/v3/TwingleCampaign/Sync.php +msgid "Parent Project ID" +msgstr "Eltern-Projekt-ID" + +#: api/v3/TwingleCampaign/Get.php api/v3/TwingleCampaign/Sync.php +msgid "ID of the parent TwingleProject" +msgstr "ID des Eltern-TWinglePRoject" + #: api/v3/TwingleCampaign/Get.php api/v3/TwingleCampaign/Getsingle.php #: api/v3/TwingleEvent/Get.php api/v3/TwingleEvent/Getsingle.php #: api/v3/TwingleProject/Get.php api/v3/TwingleProject/Getsingle.php @@ -1021,6 +1029,18 @@ msgstr "Bestätigt am" msgid "When the Event was confirmed by its initiator" msgstr "Wenn das Event vom Initiator bestätigt wurrde" +#: api/v3/TwingleEvent/Sync.php +msgid "Pull" +msgstr "Ziehen" + +#: api/v3/TwingleEvent/Sync.php +msgid "" +"If this is set true, the event(s) will be pulled from Twingle and updated " +"locally" +msgstr "" +"Wenn dies auf wahr gesetzt ist, werden die Events von Twingle gezogen und " +"lokal geupdated." + #: api/v3/TwingleEvent/Sync.php api/v3/TwingleSync/Sync.php msgid "Limit" msgstr "Limit" @@ -1122,6 +1142,18 @@ msgstr "Twingle Organisations ID" msgid "Your Twingle Organisation ID" msgstr "Ihre Twingle Organisations ID" +#: api/v3/TwingleProject/Sync.php +msgid "Pull from Twingle" +msgstr "Von Twingle ziehen" + +#: api/v3/TwingleProject/Sync.php +msgid "" +"If this is set true, the project(s) will be pulled from Twingle and updated " +"locally" +msgstr "" +"Wenn dies auf wahr gesetzt ist, werden die Projekte von Twingle gezogen und " +"lokal geupdated." + #: templates/CRM/TwingleCampaign/Form/Settings.tpl msgid "General Settings" msgstr "Allgemeine Einstellungen" diff --git a/l10n/pot/twinglecampaign.pot b/l10n/pot/twinglecampaign.pot index 0516610..b4a3038 100644 --- a/l10n/pot/twinglecampaign.pot +++ b/l10n/pot/twinglecampaign.pot @@ -99,11 +99,7 @@ msgid "Upgrade %1 to revision %2" msgstr "" #: ./CRM/TwingleCampaign/Upgrader.php -msgid "Syncronizes all TwingleProjects an TwingleEvents between CiviCRM and Twingle" -msgstr "" - -#: ./CRM/TwingleCampaign/Upgrader.php -msgid "Could not create scheduled job \"TwingleSync\"." +msgid "Could not pull campaigns from Twingle to fill the campaign fields that were created within this update: %1" msgstr "" #: ./CRM/TwingleCampaign/Upgrader.php @@ -111,7 +107,11 @@ msgid "Scheduled Job" msgstr "" #: ./CRM/TwingleCampaign/Upgrader.php -msgid "Could not create scheduled job \"TwingleSync\". Your Campaigns will not get synchronized to Twingle." +msgid "Syncronizes all TwingleProjects an TwingleEvents between CiviCRM and Twingle" +msgstr "" + +#: ./CRM/TwingleCampaign/Upgrader.php +msgid "Could not create scheduled job \"TwingleSync\"." msgstr "" #: ./CRM/TwingleCampaign/Upgrader.php @@ -802,6 +802,14 @@ msgstr "" msgid "Twingle ID of the parent TwingleProject" msgstr "" +#: ./api/v3/TwingleCampaign/Get.php ./api/v3/TwingleCampaign/Sync.php +msgid "Parent Project ID" +msgstr "" + +#: ./api/v3/TwingleCampaign/Get.php ./api/v3/TwingleCampaign/Sync.php +msgid "ID of the parent TwingleProject" +msgstr "" + #: ./api/v3/TwingleCampaign/Get.php ./api/v3/TwingleCampaign/Getsingle.php ./api/v3/TwingleEvent/Get.php ./api/v3/TwingleEvent/Getsingle.php ./api/v3/TwingleProject/Get.php ./api/v3/TwingleProject/Getsingle.php msgid "Campaign Name" msgstr "" @@ -890,6 +898,14 @@ msgstr "" msgid "When the Event was confirmed by its initiator" msgstr "" +#: ./api/v3/TwingleEvent/Sync.php +msgid "Pull" +msgstr "" + +#: ./api/v3/TwingleEvent/Sync.php +msgid "If this is set true, the event(s) will be pulled from Twingle and updated locally" +msgstr "" + #: ./api/v3/TwingleEvent/Sync.php ./api/v3/TwingleSync/Sync.php msgid "Limit" msgstr "" @@ -982,6 +998,14 @@ msgstr "" msgid "Your Twingle Organisation ID" msgstr "" +#: ./api/v3/TwingleProject/Sync.php +msgid "Pull from Twingle" +msgstr "" + +#: ./api/v3/TwingleProject/Sync.php +msgid "If this is set true, the project(s) will be pulled from Twingle and updated locally" +msgstr "" + #: ./templates/CRM/TwingleCampaign/Form/Settings.tpl msgid "General Settings" msgstr ""