From 953adaf319c0d326b636cffe340ce8a5104d59ed Mon Sep 17 00:00:00 2001 From: Marc Michalsky forumZFD Date: Tue, 6 Oct 2020 19:57:09 +0200 Subject: [PATCH] implemented sync from CiviCRM to Twingle --- .../Upgrader/resources/campaigns.json | 4 +- api/v3/TwingleSync/BAO/TwingleApiCall.php | 66 +++++--- api/v3/TwingleSync/BAO/TwingleProject.php | 157 +++++++++++------- api/v3/TwingleSync/Get.php | 2 +- .../resources/project_settings_template.json | 73 -------- .../resources/twingle_api_templates.json | 83 +++++++++ 6 files changed, 229 insertions(+), 156 deletions(-) delete mode 100644 api/v3/TwingleSync/resources/project_settings_template.json create mode 100644 api/v3/TwingleSync/resources/twingle_api_templates.json diff --git a/CRM/TwingleCampaign/Upgrader/resources/campaigns.json b/CRM/TwingleCampaign/Upgrader/resources/campaigns.json index f695761..9c088ed 100644 --- a/CRM/TwingleCampaign/Upgrader/resources/campaigns.json +++ b/CRM/TwingleCampaign/Upgrader/resources/campaigns.json @@ -123,10 +123,10 @@ "help_post": "Choose the project type. Allow users to create own events or to pay a membership fee.", "default_value": "default" }, - "twingle_project_target": { + "twingle_project_project_target": { "custom_group_id": "Twingle_Project_Information", "label": "Twingle Project target", - "name": "twingle_project_target", + "name": "twingle_project_project_target", "is_required": 0, "is_searchable": 1, "data_type": "Money", diff --git a/api/v3/TwingleSync/BAO/TwingleApiCall.php b/api/v3/TwingleSync/BAO/TwingleApiCall.php index 93de5c5..b732fe9 100644 --- a/api/v3/TwingleSync/BAO/TwingleApiCall.php +++ b/api/v3/TwingleSync/BAO/TwingleApiCall.php @@ -123,32 +123,43 @@ class TwingleApiCall { if (is_array($values)) { $project = new TwingleProject($values, TwingleProject::TWINGLE); - $result = $project->create($is_test); + + // Check if the TwingleProject campaign already exists + if (!$project->exists()) { + // ... if not, create it + $result = $project->create($is_test); + } + else { + $result = $project->getResponse('TwingleProject exists'); + } // If Twingle's version of the project is newer than the CiviCRM // TwingleProject campaign update the campaign if ( - $result['state'] == 'TwingleProject already exists' && + $result['state'] == 'TwingleProject exists' && $values['last_update'] > $project->lastUpdate() ) { - $result = $project->update($is_test); + $project->update($values, TwingleProject::TWINGLE); + $result = $project->create(); } // If the CiviCRM TwingleProject campaign was changed, update the project // on Twingle's side elseif ( - $result['state'] == 'TwingleProject already exists' && + $result['state'] == 'TwingleProject exists' && $values['last_update'] < $project->lastUpdate() ) { // If this is a test do not make database changes if ($is_test) { - $result = TwingleProject::fetch($values['id'])->getResponse( + $result = $project->getResponse( 'TwingleProject ready to push' ); } else { - $result = $this->updateProject($project->export()); + $result = $this->updateProject($project); } - + } + elseif ($result['state'] == 'TwingleProject exists') { + $result = $project->getResponse('TwingleProject up to date'); } // Return a response of the synchronization @@ -161,14 +172,19 @@ class TwingleApiCall { } /** - * @param array $values - * @param bool $is_test + * Sends an curl post call to Twingle to update an existing project and then + * updates the TwingleProject campaign. + * + * @param \CRM\TwingleCampaign\BAO\TwingleProject $project + * The TwingleProject object that should get pushed to Twingle * * @return array - * @throws \CiviCRM_API3_Exception - * @throws \Exception + * Returns a response array that contains title, id, project_id and state + * */ - public function updateProject(array $values) { + public function updateProject(TwingleProject $project) { + + $values = $project->export(); // Prepare url for curl $url = $this->protocol . 'project' . $this->baseUrl . $values['id']; @@ -177,13 +193,23 @@ class TwingleApiCall { $result = $this->curlPost($url, $values); // Update TwingleProject in Civi with results from api call - $updated_project = new TwingleProject($result, TwingleProject::TWINGLE); - $updated_project->create(); - return $updated_project->getResponse("TwingleProject pushed to Twingle"); + if (is_array($result) && !array_key_exists('message', $result)) { + $project->update($result, TwingleProject::TWINGLE); + $project->create(); + return $project->getResponse('TwingleProject pushed to Twingle'); + } + else { + $message = $result['message']; + return $project->getResponse( + $message + ? "TwingleProject could not get pushed to Twingle: $message" + : 'TwingleProject could not get pushed to Twingle' + ); + } } - + public function updateEvent() { } @@ -202,7 +228,8 @@ class TwingleApiCall { * * @param null $params * - * @return mixed + * @return array|bool + * Returns the result array of the curl or FALSE, if the curl failed */ private function curlGet($url, $params = NULL) { if (!empty($params)) { @@ -230,10 +257,11 @@ class TwingleApiCall { "x-access-code: $this->apiKey", 'Content-Type: application/json', ]); - curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); + $json = json_encode($data); + curl_setopt($curl, CURLOPT_POSTFIELDS, $json); $response = json_decode(curl_exec($curl), TRUE); if (empty($response)) { - $response = curl_error($curl); + $response = FALSE; } curl_close($curl); return $response; diff --git a/api/v3/TwingleSync/BAO/TwingleProject.php b/api/v3/TwingleSync/BAO/TwingleProject.php index 065b109..a674373 100644 --- a/api/v3/TwingleSync/BAO/TwingleProject.php +++ b/api/v3/TwingleSync/BAO/TwingleProject.php @@ -108,37 +108,35 @@ class TwingleProject { // Create campaign only if it does not already exist - if (!$this->exists()) { - if (!$is_test) { + if (!$is_test) { - // Translate Twingle field names into custom field names - $translatedFields = $this->values; - self::translateCustomFields($translatedFields, self::OUT); + // Translate Twingle field names into custom field names + $translatedFields = $this->values; + self::translateCustomFields($translatedFields, self::IN); - // Create campaign - $result = civicrm_api3('Campaign', 'create', $translatedFields); + // Set id + $translatedFields['id'] = $this->id; - // Set id attribute - $this->id = $result['id']; + // Create campaign + $result = civicrm_api3('Campaign', 'create', $translatedFields); - // Check if campaign was created successfully - if ($result['is_error'] == 0) { - $response = $this->getResponse('TwingleProject created'); - } - else { - $response = $this->getResponse('TwingleProject creation failed'); - } + // Update id + $this->id = $result['id']; + // Check if campaign was created successfully + if ($result['is_error'] == 0) { + $response = $this->getResponse('TwingleProject created'); } - // If this is a test, do not create campaign else { - $response = $this->getResponse('TwingleProject not yet created'); + $response = $this->getResponse('TwingleProject creation failed'); } + } + // If this is a test, do not create campaign else { - // Give information back if campaign already exists - $response = $this->getResponse('TwingleProject already exists'); + $response = $this->getResponse('TwingleProject not yet created'); } + return $response; } @@ -146,38 +144,35 @@ class TwingleProject { /** * Update an existing project * - * If true: don't do any changes + * @param array $values + * Array with values to update * - * @param bool $is_test + * @param string $origin + * Origin of the array. It can be one of two constants: + * TwingleProject::TWINGLE|CIVICRM * - * @return array - * @throws \CiviCRM_API3_Exception */ - public function update(bool $is_test = FALSE) { + public function update(array $values, string $origin) { - $response = ''; + if ($origin == self::TWINGLE) { + // Format values and translate keys + self::translateKeys($values, self::IN); + self::formatValues($values, self::IN); + } + elseif ($origin == self::CIVICRM) { + $this->id = $values['id']; + self::translateCustomFields($values, self::OUT); + } - // Translate Twingle field names to custom field names + // Update attributes + $this->values = array_merge($this->values, $values); + + // Translate Twingle field names into custom field names $translatedFields = $this->values; - self::translateCustomFields($translatedFields, self::OUT); + self::translateCustomFields($translatedFields, self::IN); - if (!$is_test) { - $result = civicrm_api3('Campaign', 'create', $translatedFields); - // If the TwingleProject campaign was updated successfully - if ($result['is_error'] == 0) { - $response = $this->getResponse('TwingleProject updated from Twingle'); - } - // If the update failed for any reason - else { - $response = $this->getResponse('Updated from Twingle failed'); - } - } - // If the TwingleProjects campaign has to get updated but this is in test mode - else { - $response = $this->getResponse('TwingleProject outdated'); - } - - return $response; + // Set id + $translatedFields['id'] = $this->id; } @@ -191,7 +186,23 @@ class TwingleProject { $values = $this->values; self::formatValues($values, self::OUT); self::translateKeys($values, self::OUT); - unset($values['campaign_type_id']); + + $json_file = file_get_contents(E::path() . + '/api/v3/TwingleSync/resources/twingle_api_templates.json'); + $twingle_api_templates = json_decode($json_file, TRUE); + $project_template = $twingle_api_templates['project']; + + if (!$project_template) { + \Civi::log()->error("Could not read json file"); + throw new \Exception('Could not read json file'); + } + + foreach ($values as $key => $value) { + if (!in_array($key, $project_template)) { + unset($values[$key]); + } + } + return $values; } @@ -214,8 +225,7 @@ class TwingleProject { while (!$single) { $result = civicrm_api3('Campaign', 'get', [ 'sequential' => 1, - 'return' => ['id', 'last_modified_date'], - 'is_active' => '1', + 'is_active' => 1, $cf_project_id => $this->values['id'], ]); @@ -231,12 +241,8 @@ class TwingleProject { // project's attributes must be updated from the campaign if ($result['count'] == 1) { - // set campaign id attribute - $this->id = $result['values'][0]['id']; - - // set last_modified_date - $this->values['last_modified_date'] = - $result['values'][0]['last_modified_date']; + // Set attributes to the values of the existing TwingleProject campaign + $this->update($result['values'][0], self::CIVICRM); return TRUE; } @@ -283,10 +289,9 @@ class TwingleProject { // Delete the newest project from array to keep it active array_shift($result['values']); - // Instantiate the left projects to deactivate them + // deactivate the projects foreach ($result['values'] as $p) { - $project = TwingleProject::fetch($p['id']); - $project->deactivate(); + self::deactivateById($p['id']); } } @@ -384,6 +389,9 @@ class TwingleProject { ? '' : $values['type']; + // Cast project_target to integer + $values['project_target'] = (int) $values['project_target']; + } else { @@ -426,7 +434,11 @@ class TwingleProject { '', $field )]; - unset($values[$field]); + unset($values[str_replace( + 'twingle_project_', + '', + $field + )]); } } } @@ -451,7 +463,7 @@ class TwingleProject { /** - * Deactivate a TwingleProject campaign + * Deactivate this TwingleProject campaign * * @return bool * TRUE if deactivation was successful @@ -459,9 +471,32 @@ class TwingleProject { * @throws \CiviCRM_API3_Exception */ public function deactivate() { + + return self::deactivateByid($this->id); + + } + + /** + * Deactivate a TwingleProject campaign by ID + * + * @param $id + * ID of the TwingleProject campaign that should get deactivated + * + * @return bool + * TRUE if deactivation was successful + * + * @throws \CiviCRM_API3_Exception + */ + public static function deactivateById($id) { + + $result = civicrm_api3('Campaign', 'getsingle', [ + 'id' => $id, + 'sequential' => 1, + ]); + $result = civicrm_api3('Campaign', 'create', [ - 'title' => $this->values['title'], - 'id' => $this->id, + 'title' => $result['title'], + 'id' => $id, 'is_active' => '0', ]); diff --git a/api/v3/TwingleSync/Get.php b/api/v3/TwingleSync/Get.php index e2a7933..17eb1da 100644 --- a/api/v3/TwingleSync/Get.php +++ b/api/v3/TwingleSync/Get.php @@ -21,7 +21,7 @@ function _civicrm_api3_twingle_sync_Get_spec(&$spec) { 'api.required' => 0, 'description' => E::ts('The key to access the Twingle API'), ]; - $spec['test'] = [ + $spec['is_test'] = [ 'name' => 'is_test', 'title' => E::ts('Test'), 'type' => CRM_Utils_Type::T_BOOLEAN, diff --git a/api/v3/TwingleSync/resources/project_settings_template.json b/api/v3/TwingleSync/resources/project_settings_template.json deleted file mode 100644 index b70db6b..0000000 --- a/api/v3/TwingleSync/resources/project_settings_template.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "id": 2237, - "has_confirmation_mail": false, - "has_confirmation_mail_api": false, - "has_donation_receipt": true, - "has_contact_data": false, - "donation_rhythm": { - "yearly": true, - "halfyearly": false, - "quarterly": false, - "monthly": true, - "one_time": true - }, - "has_newsletter_registration": false, - "has_postinfo_registration": false, - "design_background_color": "", - "design_primary_color": "", - "design_font": "", - "design_font_color": "", - "design_button_font_color": "", - "design_button_font_color_light": "", - "image": "", - "bcc_email_address": "demo-zfd@twingle.de", - "donation_value_min": 5, - "donation_value_max": 500, - "donation_value_default": 50, - "exclude_contact_fields": "birthday", - "custom_js": null, - "custom_css": null, - "share_url": null, - "has_contact_mandatory": false, - "has_doi": true, - "doi_redirect": null, - "has_force_donation_target_buttons": false, - "has_show_single_target": false, - "betterpayment_credit_card_theme": null, - "last_update": 1600433614, - "app_js": null, - "slidericon": "heart", - "extra_field": [], - "has_hidden_logo": false, - "has_projecttarget_as_money": false, - "rapidmail_recipient_list": null, - "mailchimp_recipient_list": null, - "has_mailchimp_add_all_user": null, - "has_mail_hide_paymentblock": false, - "has_mail_hide_paymentblock_api": false, - "has_donationtarget_textfield": false, - "has_civi_crm_activated": false, - "has_step_index": false, - "gift_donation": "", - "gift_donation_icon": null, - "gift_donation_image": null, - "languages": "de", - "has_buttons": false, - "has_no_slider": false, - "buttons": { - "button1": { - "amount": "" - }, - "button2": { - "amount": "" - }, - "button3": { - "amount": "" - } - }, - "has_newsletter_namerequest": false, - "has_show_donator_data": false, - "has_donation_letter": false, - "has_donation_letter_api": false, - "amount_images": [] -} \ No newline at end of file diff --git a/api/v3/TwingleSync/resources/twingle_api_templates.json b/api/v3/TwingleSync/resources/twingle_api_templates.json new file mode 100644 index 0000000..7a50a81 --- /dev/null +++ b/api/v3/TwingleSync/resources/twingle_api_templates.json @@ -0,0 +1,83 @@ +{ "project": [ + "id", + "allow_more", + "name", + "organisation_id", + "project_target", + "transaction_type", + "type" +], + "project_settings": { + "id": 2237, + "has_confirmation_mail": false, + "has_confirmation_mail_api": false, + "has_donation_receipt": true, + "has_contact_data": false, + "donation_rhythm": { + "yearly": true, + "halfyearly": false, + "quarterly": false, + "monthly": true, + "one_time": true + }, + "has_newsletter_registration": false, + "has_postinfo_registration": false, + "design_background_color": "", + "design_primary_color": "", + "design_font": "", + "design_font_color": "", + "design_button_font_color": "", + "design_button_font_color_light": "", + "image": "", + "bcc_email_address": "demo-zfd@twingle.de", + "donation_value_min": 5, + "donation_value_max": 500, + "donation_value_default": 50, + "exclude_contact_fields": "birthday", + "custom_js": null, + "custom_css": null, + "share_url": null, + "has_contact_mandatory": false, + "has_doi": true, + "doi_redirect": null, + "has_force_donation_target_buttons": false, + "has_show_single_target": false, + "betterpayment_credit_card_theme": null, + "last_update": 1600433614, + "app_js": null, + "slidericon": "heart", + "extra_field": [], + "has_hidden_logo": false, + "has_projecttarget_as_money": false, + "rapidmail_recipient_list": null, + "mailchimp_recipient_list": null, + "has_mailchimp_add_all_user": null, + "has_mail_hide_paymentblock": false, + "has_mail_hide_paymentblock_api": false, + "has_donationtarget_textfield": false, + "has_civi_crm_activated": false, + "has_step_index": false, + "gift_donation": "", + "gift_donation_icon": null, + "gift_donation_image": null, + "languages": "de", + "has_buttons": false, + "has_no_slider": false, + "buttons": { + "button1": { + "amount": "" + }, + "button2": { + "amount": "" + }, + "button3": { + "amount": "" + } + }, + "has_newsletter_namerequest": false, + "has_show_donator_data": false, + "has_donation_letter": false, + "has_donation_letter_api": false, + "amount_images": [] + } +} \ No newline at end of file