diff --git a/CRM/TwingleCampaign/BAO/Campaign.php b/CRM/TwingleCampaign/BAO/Campaign.php index b8d8435..86b0bdc 100644 --- a/CRM/TwingleCampaign/BAO/Campaign.php +++ b/CRM/TwingleCampaign/BAO/Campaign.php @@ -10,6 +10,10 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { // OUT means: coming from the CiviCRM database public const OUT = 'OUT'; + public const PROJECT = 'TwingleProject'; + + public const EVENT = 'TwingleEvent'; + protected $className; protected $id; @@ -22,14 +26,13 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { protected $formattedValues; - /** * ## Campaign constructor. * * @param array $values * @param int|null $id */ - protected function __construct(array $values, int $id = NULL) { + protected function __construct(array $values = [], int $id = NULL) { $this->id = $id; $tmpClassName = explode('_', get_class($this)); @@ -51,7 +54,6 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { * @throws \Exception */ public function create(bool $no_hook = FALSE): bool { - // Prepare project values for import into database $values_prepared_for_import = $this->values; $this->formatValues( @@ -60,6 +62,7 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { ); $this->translateKeys( $values_prepared_for_import, + $this->className, self::IN ); $this->formattedValues = $values_prepared_for_import; @@ -69,13 +72,25 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { ); // Set id - $values_prepared_for_import['id'] = $this->id; + if (isset($this->id)) { + $values_prepared_for_import['id'] = $this->id; + } // Set a flag to not trigger the hook if ($no_hook) { $_SESSION['CiviCRM']['de.forumzfd.twinglecampaign']['no_hook'] = TRUE; } + // Cast booleans to integers + foreach ($values_prepared_for_import as $key => $value) { + if ($value === false) { + $values_prepared_for_import[$key] = 0; + } + elseif ($value === true) { + $values_prepared_for_import[$key] = 1; + } + } + // Create campaign $result = civicrm_api3('Campaign', 'create', $values_prepared_for_import); @@ -89,12 +104,11 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { return TRUE; } - /** * ## Update instance values * This method updates the **$values** array of this instance with the values * from the provided array if they are defined in - * *CRM/TwingleCampaign/resources/twingle_api_templates.json* + * *CRM/TwingleCampaign/resources/twingle_api_templates.php* * * @param array $values * Array with values to update @@ -103,47 +117,33 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { // Update campaign values $filter = Cache::getInstance()->getTemplates()[$this->className]; foreach ($values as $key => $value) { - if ($this->className == "TwingleProject" && $key == 'project_id') { - $this->values['id'] = $value; - } - elseif (in_array($key, $filter)) { + if ($this->in_array_r($key, $filter)) { $this->values[$key] = $value; } - elseif ($key == 'embed') { - self::setEmbedData($value); - } - elseif ($key == 'counter-url') { - self::setCounterUrl($value['url']); - } } } - /** - * ## Set embed data fields - * This method sets all embed data fields that are defined in - * *CRM/TwingleCampaign/resources/twingle_api_templates.json* - * - * @param array $embedData - * Array with embed data from Twingle API + * ## Complement campaign values + * Complement existing campaign values with new ones + * @param array $arrayToComplement */ - public function setEmbedData(array $embedData) { + public function complement(array $arrayToComplement) { + $this->complement_r($this->values, $arrayToComplement); + $this->values = $arrayToComplement; + } - // Get all embed_data keys from template - $embed_data_keys = Cache::getInstance() - ->getTemplates()['project_embed_data']; - - // Transfer all embed_data values - foreach ($embed_data_keys as $key) { - if (array_key_exists($key, $embedData)) { - $this->values[$key] = $embedData[$key]; + private function complement_r($orig, &$fill) { + foreach ($orig as $key => $value) { + if (is_array($value)) { + $this->complement_r($orig[$key], $fill[$key]); + } else { + $fill[$key] = $value; } } } - - public abstract function formatValues(array &$values, string $direction); - + public static abstract function formatValues(array &$values, string $direction); /** * ## Translate array keys between CiviCRM Campaigns and Twingle @@ -156,17 +156,27 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { * * @param array $values * array of keys to translate - * + * @param string $campaignType + * const: Campaign::PROJECT or Campaign::EVENT * @param string $direction * const: Campaign::OUT or Campaign::OUT * - * @throws Exception + * @throws \Exception */ - public function translateKeys(array &$values, string $direction) { + public static function translateKeys( + array &$values, + string $campaignType, + string $direction) { + + if ($campaignType != self::PROJECT && $campaignType != self::EVENT) { + throw new Exception( + "Invalid Parameter $campaignType for translateKeys()" + ); + } // Get translations for fields $field_translations = Cache::getInstance() - ->getTranslations()[$this->className]; + ->getTranslations()[$campaignType]; // Set the direction of the translation if ($direction == self::OUT) { @@ -188,7 +198,6 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { } } - /** * ## Translate field names and custom field names * @@ -256,18 +265,6 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { } } - - /** - * ## Set counter url - * - * @param String $counterUrl - * URL of the counter - */ - public function setCounterUrl(string $counterUrl) { - $this->values['counter'] = $counterUrl; - } - - /** * ## Delete Campaign * Deletes this Campaign from CiviCRM @@ -287,7 +284,6 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { return ($result['is_error'] == 0); } - /** * ## Deactivate this campaign * @@ -300,7 +296,6 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { return self::deactivateByid($this->id); } - /** * ## Deactivate campaign by ID * @@ -335,10 +330,8 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { } } - public abstract function getResponse(string $status): array; - /** * ## Get timestamp * Validates **$input** to be either a *DateTime string* or an *Unix @@ -370,10 +363,8 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { } } - public abstract function lastUpdate(); - /** * ## Get DateTime * Validates **$input** to be either a *DateTime string* or an *Unix @@ -407,7 +398,6 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { } } - /** * ## Get id * Returns the **id** of this campaign. @@ -418,4 +408,52 @@ abstract class CRM_TwingleCampaign_BAO_Campaign { return (int) $this->id; } + /** + * Helper function to search a value in a multidimensional array. + * + * @param $needle + * @param $haystack + * @param bool $strict + * + * @return bool + */ + protected function in_array_r($needle, $haystack, $strict = false): bool { + foreach ($haystack as $item) { + if (($strict ? $item === $needle : $item == $needle) || + (is_array($item) && $this->in_array_r($needle, $item, $strict))) { + return true; + } + } + return false; + } + + /** + * Helper function to check if the provided field is of type Boolean + * + * @param $fieldName + * @param string $campaignType Campaign::PROJECT or Campaign::EVENT + * + * @return bool + * @throws \Exception + */ + public static function isBoolean($fieldName, string $campaignType): bool { + $fields = Cache::getInstance()->getCampaigns()['custom_fields']; + if ($campaignType == self::PROJECT) { + if (isset($fields['twingle_project_' . $fieldName])) { + return $fields['twingle_project_' . $fieldName]['data_type'] == 'Boolean'; + } + else { + return FALSE; + } + } + elseif ($campaignType == self::EVENT) { + if (isset($fields['twingle_event_' . $fieldName])) { + return $fields['twingle_event_' . $fieldName]['data_type'] == 'Boolean'; + } + else { + return FALSE; + } + } + throw new Exception('Unknown campaign type'); + } } diff --git a/CRM/TwingleCampaign/BAO/CampaignType.php b/CRM/TwingleCampaign/BAO/CampaignType.php index 486c970..5957f86 100644 --- a/CRM/TwingleCampaign/BAO/CampaignType.php +++ b/CRM/TwingleCampaign/BAO/CampaignType.php @@ -27,9 +27,12 @@ class CRM_TwingleCampaign_BAO_CampaignType { } /** + * @param bool $upgrade + * If true: Does not show UF message if campaign type already exists + * * @throws \CiviCRM_API3_Exception */ - public function create() { + public function create(bool $upgrade = false) { $field = civicrm_api3( 'OptionValue', @@ -41,8 +44,7 @@ class CRM_TwingleCampaign_BAO_CampaignType { ] ); - if ($field['count'] == 0) - { + if ($field['count'] == 0) { $this->results = civicrm_api3('OptionValue', 'create', $this->getSetAttributes()); $this->value = array_column($this->results['values'], 'value')[0]; @@ -55,11 +57,10 @@ class CRM_TwingleCampaign_BAO_CampaignType { } else { $error_message = $this->results['error_message']; - Civi::log()->error("Twingle Extension could not create new campaign type - for \"$this->label\": $error_message"); + Civi::log()->error("Twingle Extension could not create new campaign type for \"$this->label\": $error_message"); } } - else { + elseif (!$upgrade) { $campaignType = self::fetch($this->name); foreach ($this as $var => $value) { if (array_key_exists($var, $campaignType->getSetAttributes())) { @@ -67,6 +68,9 @@ class CRM_TwingleCampaign_BAO_CampaignType { } } } + else { + $this->value = $field['values'][0]['value']; + } } /** diff --git a/CRM/TwingleCampaign/BAO/CustomField.php b/CRM/TwingleCampaign/BAO/CustomField.php index b393e24..dea24f9 100644 --- a/CRM/TwingleCampaign/BAO/CustomField.php +++ b/CRM/TwingleCampaign/BAO/CustomField.php @@ -53,11 +53,6 @@ class CRM_TwingleCampaign_BAO_CustomField { if (array_key_exists($var, $attributes)) { $this->$var = $attributes[$var]; } - - // translate help_post - if ($this->help_post) { - $this->help_post = E::ts($this->help_post); - } } } @@ -65,9 +60,12 @@ class CRM_TwingleCampaign_BAO_CustomField { /** * Creates a CustomField by calling CiviCRM API v.3 * + * @param bool $upgrade + * If true: Does not show UF message if custom field already exists + * * @throws \CiviCRM_API3_Exception */ - public function create() { + public function create(bool $upgrade = false) { // Check if the field already exists $field = civicrm_api3( @@ -105,27 +103,21 @@ class CRM_TwingleCampaign_BAO_CustomField { ->error("$this->extensionName could not create new custom field \"$this->name\" for group \"$this->custom_group_id\": $this->result['error_message']"); - CRM_Utils_System::setUFMessage("Creation of custom field '$this->name' - failed. Find more information in the logs."); + CRM_Utils_System::setUFMessage(E::ts('Creation of custom field \'%1\' failed. Find more information in the logs.', [1 => $this->name])); } // If there is not enough information: log simple error message else { Civi::log() ->error("$this->extensionName could not create new custom field: $this->result['error_message']"); - CRM_Utils_System::setUFMessage("Creation of custom field - failed. Find more information in the logs."); + CRM_Utils_System::setUFMessage(E::ts("Creation of custom field failed. Find more information in the logs.")); } } } - else { - CRM_Utils_System::setUFMessage("Creation of custom field '$this->name' - failed, because a custom field with that name already exists. - Find more information in the logs."); + 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."); + ->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."); } } @@ -165,16 +157,9 @@ class CRM_TwingleCampaign_BAO_CustomField { if (!$name) { $result = []; - // Get json file with all custom fields for this extension - $json_file = file_get_contents(E::path() . - '/CRM/TwingleCampaign/resources/campaigns.json'); - $campaign_info = json_decode($json_file, TRUE); - - // Log an error and throw an exception if the file cannot get read - if (!$campaign_info) { - Civi::log()->error("Could not read json file"); - throw new Exception('Could not read json file'); - } + // Get array with all custom fields for this extension + $campaign_info = + require E::path() . '/CRM/TwingleCampaign/resources/campaigns.php'; // Recursive method call with all custom field names from the json file foreach ($campaign_info['custom_fields'] as $customField) { diff --git a/CRM/TwingleCampaign/BAO/CustomGroup.php b/CRM/TwingleCampaign/BAO/CustomGroup.php index 3b92099..134b27d 100644 --- a/CRM/TwingleCampaign/BAO/CustomGroup.php +++ b/CRM/TwingleCampaign/BAO/CustomGroup.php @@ -41,9 +41,12 @@ class CRM_TwingleCampaign_BAO_CustomGroup { } /** + * @param bool $upgrade + * If true: Does not show UF message if custom group already exists + * * @throws \CiviCRM_API3_Exception */ - public function create() { + public function create(bool $upgrade = false) { $field = civicrm_api3( 'CustomGroup', @@ -74,18 +77,21 @@ class CRM_TwingleCampaign_BAO_CustomGroup { Civi::log()->error("$this->extensionName could not create new custom group for \"$this->name\": $this->results['error_message']" ); - CRM_Utils_System::setUFMessage("Creation of custom group '$this->name' - failed. Find more information in the logs."); + CRM_Utils_System::setUFMessage(E::ts('Creation of custom group \'%1\' failed. Find more information in the logs.', [1 => $this->name])); } else { Civi::log()->error("$this->extensionName could not create new custom group: $this->results['error_message']"); - CRM_Utils_System::setUFMessage("Creation of custom group - failed. Find more information in the logs."); + CRM_Utils_System::setUFMessage(E::ts('Creation of custom group failed. Find more information in the logs.')); } } } + elseif (!$upgrade) { + CRM_Utils_System::setUFMessage(E::ts('Creation of custom group \'%1\' failed, because a custom group with that name already exists. Find more information in the logs.', [1 => $this->name])); + Civi::log() + ->error("$this->extensionName could not create new custom group \"$this->name\" because a group with that name already exists."); + } } /** diff --git a/CRM/TwingleCampaign/BAO/OptionValue.php b/CRM/TwingleCampaign/BAO/OptionValue.php index e5144d3..9de6594 100644 --- a/CRM/TwingleCampaign/BAO/OptionValue.php +++ b/CRM/TwingleCampaign/BAO/OptionValue.php @@ -33,11 +33,6 @@ class CRM_TwingleCampaign_BAO_OptionValue { if (array_key_exists($var, $attributes)) { $this->$var = $attributes[$var]; } - - // translate description - if ($this->description) { - $this->description = E::ts($this->description); - } } } @@ -144,10 +139,9 @@ class CRM_TwingleCampaign_BAO_OptionValue { if (!$name) { $result = []; - // Get json file with all custom fields for this extension - $json_file = file_get_contents(E::path() . - '/CRM/TwingleCampaign/resources/option_values.json'); - $option_values = json_decode($json_file, TRUE); + // Get all custom fields for this extension from option_values.php + $option_values = + include(E::path() . '/CRM/TwingleCampaign/resources/option_values.php'); // Log an error and throw an exception if the file cannot get read if (!$option_values) { diff --git a/CRM/TwingleCampaign/BAO/TwingleApiCall.php b/CRM/TwingleCampaign/BAO/TwingleApiCall.php index 5d6d037..4ae2536 100644 --- a/CRM/TwingleCampaign/BAO/TwingleApiCall.php +++ b/CRM/TwingleCampaign/BAO/TwingleApiCall.php @@ -1,6 +1,5 @@ protocol . 'project' . $this->baseUrl . 'by-organisation/' . $this->organisationId - : $this->protocol . 'project' . $this->baseUrl . $projectId; + // If no project id is provided, return all projects + if (empty($projectId)) { + $response = []; + $projects = $this->curlGet($this->protocol . 'project' . + $this->baseUrl . 'by-organisation/' . $this->organisationId); + foreach ($projects as $project) { + $response[] = $this->getProject($project['id']); + } + return $response; + } + // If a project id is provided, return only one project + else { - return $this->curlGet($url); + // Get all general project information + $project = $this->curlGet($this->protocol . 'project' . + $this->baseUrl . $projectId); + + // Get project options + $project['project_options'] = $this->getProjectOptions($projectId); + + // Get project payment methods + $project['payment_methods'] = + $this->getProjectPaymentMethods($projectId); + + // Set last update time + $project['last_update'] = max( + $project['last_update'], + $project['project_options']['last_update'], + $project['payment_methods']['updated_at'] + ); + unset($project['project_options']['last_update']); + unset($project['payment_methods']['updated_at']); + + return $project; + } } /** @@ -92,30 +121,79 @@ class CRM_TwingleCampaign_BAO_TwingleApiCall { * * Returns an array with all project values. * - * @param TwingleProject $project - * The TwingleProject object that should get pushed to Twingle + * @param array $project + * The project values array that should get pushed to Twingle * * @return array * @throws \Exception */ - public function pushProject(TwingleProject &$project): array { + public function pushProject(array $project): array { - // Get only those values from the TwingleProject object which Twingle expects - $values = $project->export(); - - // Prepare url for curl - if ($values['id']) { - $url = $this->protocol . 'project' . $this->baseUrl . $values['id']; + if (isset($project['project_options'])) { + $projectOptions = $project['project_options']; + unset($project['project_options']); } - else { - $url = $this->protocol . 'project' . $this->baseUrl . 'by-organisation/' . - $this->organisationId; + if (isset($project['payment_methods'])) { + $paymentMethods = $project['payment_methods']; + unset($project['payment_methods']); } - // Send curl and return result - return $this->curlPost($url, $values); + try { + if (!isset($project['id'])) { + $url = $this->protocol . 'project' . $this->baseUrl . 'by-organisation/' . + $this->organisationId; + + // Post project values + $updatedProject = $this->curlPost($url, $project); + + $url = $this->protocol . 'project' . $this->baseUrl . + $updatedProject['id']; + } + else { + $url = $this->protocol . 'project' . $this->baseUrl . $project['id']; + + // Post project values + $updatedProject = $this->curlPost($url, $project); + } + + // Post project_options + if (isset($projectOptions)) { + $updatedProject['project_options'] = + $this->curlPost($url . '/options', $projectOptions); + } + else { + $updatedProject['project_options'] = $this->getProjectOptions($updatedProject['id']); + } + + // Post payment_methods + if (isset ($paymentMethods)) { + $this->curlPost($url . '/payment-methods', $paymentMethods); + } + $updatedProject['payment_methods'] = + $this->getProjectPaymentMethods($updatedProject['id']); + + + // Set last update time + $updatedProject['last_update'] = max( + $updatedProject['last_update'], + $updatedProject['project_options']['last_update'], + $updatedProject['payment_methods']['updated_at'] + ); + unset($updatedProject['project_options']['last_update']); + unset($updatedProject['payment_methods']['updated_at']); + + return $updatedProject; + } + catch + (Exception $e) { + throw new Exception( + E::SHORT_NAME . 'Call to Twingle API failed: ' . + $e->getMessage() + ); + } } + /** * ## Get event from Twingle * Returns all events for the provided **$projectId** or a single event if an @@ -128,48 +206,48 @@ class CRM_TwingleCampaign_BAO_TwingleApiCall { * @throws Exception */ public function getEvent(int $projectId, int $eventId = NULL): array { - $result = []; + $result = []; - // Construct url for curl - $url = empty($eventId) - ? $this->protocol . 'project' . $this->baseUrl . $projectId . '/event' - : $this->protocol . 'project' . $this->baseUrl . $projectId . '/event/' - . $eventId; + // Construct url for curl + $url = empty($eventId) + ? $this->protocol . 'project' . $this->baseUrl . $projectId . '/event' + : $this->protocol . 'project' . $this->baseUrl . $projectId . '/event/' + . $eventId; - $offset = 0; - $finished = FALSE; + $offset = 0; + $finished = FALSE; - // Get only as much results per call as configured in $this->limit - while (!$finished) { - $params = [ - 'orderby' => 'id', - 'direction' => 'desc', - 'limit' => $this->limit, - 'offset' => $offset, - 'image' => 'as-boolean', - 'public' => 0, - ]; - $response = $this->curlGet($url, $params); + // Get only as much results per call as configured in $this->limit + while (!$finished) { + $params = [ + 'orderby' => 'id', + 'direction' => 'desc', + 'limit' => $this->limit, + 'offset' => $offset, + 'image' => 'as-boolean', + 'public' => 0, + ]; + $response = $this->curlGet($url, $params); - // If no $eventId was given, expect one or more events. - // Store the events, increase the offset and ask again until there - // are no more events incoming. - if (!$eventId) { - $result = array_merge($result, $response['data']); - $offset = $offset + $this->limit; - $finished = count($response['data']) < $this->limit; - } - // If $eventId was given, expect only one event - else { - // If the response array contains 'message', the $eventId does not exist - if (!$response['message']) { - $result = $response; + // If no $eventId was given, expect one or more events. + // Store the events, increase the offset and ask again until there + // are no more events incoming. + if (!$eventId) { + $result = array_merge($result, $response['data']); + $offset = $offset + $this->limit; + $finished = count($response['data']) < $this->limit; + } + // If $eventId was given, expect only one event + else { + // If the response array contains 'message', the $eventId does not exist + if (!$response['message']) { + $result = $response; + } + $finished = TRUE; } - $finished = TRUE; } + return $result; } - return $result; - } /** * ## Get project embed data @@ -182,20 +260,49 @@ class CRM_TwingleCampaign_BAO_TwingleApiCall { */ public function getProjectEmbedData($projectId): array { - $result = $this->getProject($projectId); + $result = $this->getProject($projectId); - if ($result['embed']) { - // Include counter url into embed data - $result['embed']['counter'] = $result['counter-url']['url']; + if ($result['embed']) { + // Include counter url into embed data + $result['embed']['counter'] = $result['counter-url']['url']; - return $result['embed']; + return $result['embed']; + } + else { + throw new Exception( + "Could not get embed data for project $projectId." + ); + } } - else { - throw new Exception( - "Could not get embed data for project $projectId." - ); + + /** + * ## Get project options + * Gets all project options from the Twingle API + * + * @param $projectId + * + * @return array + * @throws \Exception + */ + public function getProjectOptions($projectId): array { + $url = $this->protocol . 'project' . $this->baseUrl . $projectId . '/options'; + return $this->curlGet($url); + } + + /** + * ## Get project payment methods + * Gets all project payment methods from the Twingle API + * + * @param $projectId + * + * @return array + * @throws \Exception + */ + public function getProjectPaymentMethods($projectId): array { + $url = $this->protocol . 'project' . $this->baseUrl . $projectId + . '/payment-methods'; + return $this->curlGet($url); } - } /** @@ -208,9 +315,9 @@ class CRM_TwingleCampaign_BAO_TwingleApiCall { * @throws Exception */ public function deleteProject(int $projectId): bool { - $url = $this->protocol . 'project' . $this->baseUrl . $projectId; - return $this->curlDelete($url); - } + $url = $this->protocol . 'project' . $this->baseUrl . $projectId; + return $this->curlDelete($url); + } /** @@ -226,10 +333,10 @@ class CRM_TwingleCampaign_BAO_TwingleApiCall { * @throws Exception */ public function deleteEvent(int $projectId, int $eventId): bool { - $url = $this->protocol . 'project' . $this->baseUrl . $projectId . - '/event/' . $eventId; - return $this->curlDelete($url); - } + $url = $this->protocol . 'project' . $this->baseUrl . $projectId . + '/event/' . $eventId; + return $this->curlDelete($url); + } /** @@ -267,7 +374,8 @@ class CRM_TwingleCampaign_BAO_TwingleApiCall { } if ($curl_status_code == 404) { throw new Exception('http status code 404 (not found)'); - } elseif ($curl_status_code == 500) { + } + elseif ($curl_status_code == 500) { throw new Exception('https status code 500 (internal error)'); } return $response; @@ -309,9 +417,13 @@ class CRM_TwingleCampaign_BAO_TwingleApiCall { } if ($curl_status_code == 404) { throw new Exception('http status code 404 (not found)'); - } elseif ($curl_status_code == 500) { + } + elseif ($curl_status_code == 500) { throw new Exception('https status code 500 (internal error)'); } + if (sizeof($response) == 1 && isset($response['message'])) { + throw new Exception($response['message']); + } return $response; } @@ -352,7 +464,8 @@ class CRM_TwingleCampaign_BAO_TwingleApiCall { } if ($curl_status_code == 404) { throw new Exception('http status code 404 (not found)'); - } elseif ($curl_status_code == 500) { + } + elseif ($curl_status_code == 500) { throw new Exception('https status code 500 (internal error)'); } return ($curl_status_code == 200); diff --git a/CRM/TwingleCampaign/BAO/TwingleCampaign.php b/CRM/TwingleCampaign/BAO/TwingleCampaign.php index c50118e..58433ed 100644 --- a/CRM/TwingleCampaign/BAO/TwingleCampaign.php +++ b/CRM/TwingleCampaign/BAO/TwingleCampaign.php @@ -26,7 +26,7 @@ class CRM_TwingleCampaign_BAO_TwingleCampaign { * * @throws \CiviCRM_API3_Exception */ - public function __construct(array $values, int $id = NULL) { + public function __construct(array $values = [], int $id = NULL) { $this->prefix = 'twingle_campaign_'; $this->id = $id ?? NULL; @@ -96,7 +96,7 @@ class CRM_TwingleCampaign_BAO_TwingleCampaign { // Get campaign type id for TwingleProject $twingle_project_campaign_type_id = ExtensionCache::getInstance() - ->getCampaigns()['campaign_types']['twingle_project']['id']; + ->getCampaignIds()['campaign_types']['twingle_project']['id']; // Determine the parent project id by looping through the campaign tree // until the parent campaign type is a TwingleProject diff --git a/CRM/TwingleCampaign/BAO/TwingleEvent.php b/CRM/TwingleCampaign/BAO/TwingleEvent.php index 2adc38c..19de97b 100644 --- a/CRM/TwingleCampaign/BAO/TwingleEvent.php +++ b/CRM/TwingleCampaign/BAO/TwingleEvent.php @@ -19,7 +19,7 @@ class CRM_TwingleCampaign_BAO_TwingleEvent extends Campaign { * * @throws \Exception */ - public function __construct(array $event, int $id = NULL) { + public function __construct(array $event = [], int $id = NULL) { parent::__construct($event, $id); $this->prefix = 'twingle_event_'; @@ -100,7 +100,7 @@ class CRM_TwingleCampaign_BAO_TwingleEvent extends Campaign { * * @throws Exception */ - public function formatValues(array &$values, string $direction) { + public static function formatValues(array &$values, string $direction) { if ($direction == self::IN) { diff --git a/CRM/TwingleCampaign/BAO/TwingleProject.php b/CRM/TwingleCampaign/BAO/TwingleProject.php index 2473c3d..b92313e 100644 --- a/CRM/TwingleCampaign/BAO/TwingleProject.php +++ b/CRM/TwingleCampaign/BAO/TwingleProject.php @@ -2,10 +2,35 @@ use CRM_TwingleCampaign_Utils_ExtensionCache as Cache; use CRM_TwingleCampaign_BAO_Campaign as Campaign; +use CRM_TwingleCampaign_Utils_StringOperations as StringOperations; +use CRM_TwingleCampaign_ExtensionUtil as E; class CRM_TwingleCampaign_BAO_TwingleProject extends Campaign { + // All available contact fields in Twingle project forms + const contactFields = [ + 'salutation', + 'firstname', + 'lastname', + 'company', + 'birthday', + 'street', + 'postal_code', + 'city', + 'country', + 'telephone', + ]; + + // All available donation rhythms in Twingle project forms + const donationRhythm = [ + 'yearly', + 'halfyearly', + 'quarterly', + 'monthly', + 'one_time', + ]; + /** * ## TwingleProject constructor * @@ -15,7 +40,16 @@ class CRM_TwingleCampaign_BAO_TwingleProject extends Campaign { * @param int|null $id * CiviCRM Campaign id */ - public function __construct(array $values, int $id = NULL) { + public function __construct(array $values = [], int $id = NULL) { + + // If the $values originally come from the TwingleProject.get API, they + // contain the internal CiviCRM id as 'id' and the external Twingle id as + // 'project_id'. In this case 'id' gets replaced with 'project_id' + if (isset($values['project_id'])) { + $values['id'] = $values['project_id']; + unset($values['project_id']); + } + parent::__construct($values, $id); $this->prefix = 'twingle_project_'; @@ -25,36 +59,98 @@ class CRM_TwingleCampaign_BAO_TwingleProject extends Campaign { } - /** * ## Export values - * Ensures that only those values will be exported which the Twingle API - * expects. These values are defined in - * *CRM/TwingleCampaign/resources/twingle_api_templates.json* + * Change all values to a format accepted by the Twingle API. * * @return array - * Array with all values to send to the Twingle API - * - * @throws Exception + * Array with all values ready to send to the Twingle API + * @throws \Exception */ public function export(): array { - + // copy project values $values = $this->values; - self::formatValues($values, self::OUT); - // Get template for project - $project = Cache::getInstance()->getTemplates()['TwingleProject']; + // Strings to booleans + $this->intToBool($values); - // Replace array items which the Twingle API does not expect - foreach ($values as $key => $value) { - if (!in_array($key, $project)) { - unset($values[$key]); - } + // Strings to integers + $this->strToInt($values); + + // Build counter-url array + if (isset($values['counter-url']) && is_string($values['counter-url'])) { + $url = $values['counter-url']; + unset($values['counter-url']); + $values['counter-url']['url'] = $url; } + // Remove campaign_type_id + unset($values['campaign_type_id']); + return $values; } + /** + * ## Int to bool + * Changes all project values that are defined as CiviCRM 'Boolean' types + * from strings to booleans. + * + * @param array $values + * + * @throws \Exception + */ + private function intToBool(array &$values) { + + $boolArrays = [ + 'payment_methods', + 'donation_rhythm', + ]; + + foreach ($values as $key => $value) { + if (CRM_TwingleCampaign_BAO_Campaign::isBoolean( + $key, + CRM_TwingleCampaign_BAO_Campaign::PROJECT + )) { + $values[$key] = (bool) $value; + } + elseif (in_array($key, $boolArrays)) { + foreach ($values[$key] as $_key => $_value) { + if (is_bool($_value)) { + // nothing to do here + } + elseif (is_numeric($_value) && $_value < 2 || empty($_value)) { + $values[$key][$_key] = (bool) $_value; + } + else { + unset($values[$key][$_key]); + } + } + } + elseif (is_array($value)) { + $this->intToBool($values[$key]); + } + } + } + + /** + * ## Int to bool + * Changes all project values that are strings but originally came as integers + * back to integers. + * + * @param array $values + * + * @throws \Exception + */ + private function strToInt(array &$values) { + foreach ($values as $key => $value) { + if (ctype_digit($value)) { + $values[$key] = intval($value); + } + elseif (is_array($value)) { + $this->strToInt($values[$key]); + } + } + } /** * ## Create this TwingleProject as a campaign in CiviCRM @@ -80,10 +176,87 @@ class CRM_TwingleCampaign_BAO_TwingleProject extends Campaign { } } + /** + * ## Update instance values + * + * @param array $values + * + * @override CRM_TwingleCampaign_BAO_Campaign::update() + */ + public function update(array $values) { + + // Remove old values + unset($this->values); + + // Get allowed values + $projectOptionsKeys = Cache::getInstance() + ->getTemplates()['TwingleProject']['project_options']; + $projectEmbedDataKeys = Cache::getInstance() + ->getTemplates()['TwingleProject']['project_embed_data']; + $projectPaymentMethodsKeys = Cache::getInstance() + ->getTemplates()['TwingleProject']['payment_methods']; + + // Sort allowed values into arrays + foreach ($values as $key => $value) { + if ($key == 'project_options') { + foreach ($value as $optionKey => $optionValue) { + if (in_array($optionKey, $projectOptionsKeys)) { + $this->values['project_options'][$optionKey] = $optionValue; + } + } + } + elseif ($key == 'embed') { + foreach ($value as $embedKey => $embedValue) { + if (in_array($embedKey, $projectEmbedDataKeys)) { + $this->values['embed'][$embedKey] = $embedValue; + } + } + } + elseif ($key == 'payment_methods') { + foreach ($value as $paymentMethodKey => $paymentMethodValue) { + if (in_array($paymentMethodKey, $projectPaymentMethodsKeys)) { + $this->values['payment_methods'][$paymentMethodKey] = + $paymentMethodValue; + } + } + } + elseif ($key == 'counter-url' && is_array($value)) { + $this->values['counter-url'] = $value['url']; + } + else { + parent::update([$key => $value]); + } + } + } + + /** + * ## Complement campaign values + * Complement existing campaign values with new ones + * + * @param array $arrayToComplement + * + * @overrides CRM_TwingleCampaign_BAO_Campaign + */ + public function complement(array $arrayToComplement) { + + // Set all contact fields to false + if ( + isset($arrayToComplement['values']['project_options']['contact_fields']) + ) { + foreach ( + $arrayToComplement['values']['project_options']['contact_fields'] + as $key => $value + ) { + $arrayToComplement['values']['project_options']['contact_fields'][$key] + = FALSE; + } + } + + parent::complement($arrayToComplement); + } /** * ## Clone this TwingleProject - * * This method removes the id and the identifier from this instance and in * the next step it pushes the clone as a new project with the same values to * Twingle. @@ -91,11 +264,163 @@ class CRM_TwingleCampaign_BAO_TwingleProject extends Campaign { * @throws \Exception */ public function clone() { - $this->values['id'] = 0; - $this->values['identifier'] = 0; + $this->values['id'] = ''; + $this->values['identifier'] = ''; $this->create(); // this will also trigger the postSave hook } + /** + * ## Validate + * Validates project values and returns an array containing the result and + * another array with eventual error messages. + * + * @return array ['valid' => bool, 'messages' => array] + */ + public function validate(): array { + $valid = TRUE; + $messages = []; + + // Validate email address + if ( + !filter_var( + $this->values['project_options']['bcc_email_address'], + FILTER_VALIDATE_EMAIL + ) + && !empty($this->values['project_options']['bcc_email_address']) + ) { + $valid = FALSE; + $messages[] = E::ts("BCC email invalid"); + } + + // Validate hexadecimal color fields + $colorFields = + [ + 'design_background_color', + 'design_primary_color', + 'design_font_color', + ]; + foreach ($colorFields as $colorField) { + if ( + !empty($this->values['project_options'][$colorField]) && + ( + !( + ctype_xdigit($this->values['project_options'][$colorField]) || + is_integer($this->values['project_options'][$colorField]) + ) || + strlen((string) $this->values['project_options'][$colorField]) > 6 + ) + ) { + $valid = FALSE; + $messages[] = + E::ts("Invalid hexadecimal value in color field: %1", + [1 => $colorField]); + } + } + + // Check if donation values are integers and if proposed donation value + // lies between max and min values + if ( + // Is integer and >= 0 or empty + ( + empty($this->values['project_options']['donation_value_default']) || + ( + is_integer($this->values['project_options']['donation_value_default']) || + ctype_digit($this->values['project_options']['donation_value_default']) + ) && ( + $this->values['project_options']['donation_value_default'] >= 0 + ) + ) && ( + empty($this->values['project_options']['donation_value_min']) || + ( + is_integer($this->values['project_options']['donation_value_min']) || + ctype_digit($this->values['project_options']['donation_value_min']) + ) && ( + $this->values['project_options']['donation_value_max'] >= 0 + ) + ) && ( + empty($this->values['project_options']['donation_value_max']) || + ( + is_integer($this->values['project_options']['donation_value_max']) || + ctype_digit($this->values['project_options']['donation_value_max']) + ) && ( + $this->values['project_options']['donation_value_max'] >= 0 + ) + ) + ) { + if ( + // all empty + empty($this->values['project_options']['donation_value_default']) && + empty($this->values['project_options']['donation_value_min']) && + empty($this->values['project_options']['donation_value_max']) + ) { + // nothing to validate + } + elseif ( + // Max empty, min not empty + (!empty($this->values['project_options']['donation_value_min']) && + empty($this->values['project_options']['donation_value_max'])) || + // Max empty, default not empty + (!empty($this->values['project_options']['donation_value_default']) && + empty($this->values['project_options']['donation_value_max'])) + ) { + $valid = FALSE; + $messages[] = + E::ts("Missing maximum donation value"); + } + else { + if ( + // Min >= Max + $this->values['project_options']['donation_value_min'] >= + $this->values['project_options']['donation_value_max'] + ) { + $valid = FALSE; + $messages[] = + E::ts("Maximum donation value must be higher than the minimum"); + } + elseif ( + // Default < min or default > max + $this->values['project_options']['donation_value_default'] < + $this->values['project_options']['donation_value_min'] || + $this->values['project_options']['donation_value_default'] > + $this->values['project_options']['donation_value_max'] + ) { + $valid = FALSE; + $messages[] = + E::ts("Default donation value must lie in between maximum and minimum values"); + } + } + } + else { + $valid = FALSE; + $messages[] = + E::ts("Donation values (Min, Max, Default) must be positive integers"); + } + + // Validate sharing url + $urlFields = + [ + 'custom_css', + 'share_url', + ]; + + foreach ($urlFields as $urlField) { + if (!empty($this->values['project_options'][$urlField])) { + if ( + !filter_var( + $this->values['project_options'][$urlField], + FILTER_VALIDATE_URL + ) || empty($this->values['project_options'][$urlField]) + ) { + $valid = FALSE; + $messages[] = + E::ts("Invalid URL: %1", [1 => $urlField]); + } + } + } + + return ['valid' => $valid, 'messages' => $messages]; + } + /** * ## Translate values between CiviCRM Campaigns and Twingle formats @@ -114,23 +439,128 @@ class CRM_TwingleCampaign_BAO_TwingleProject extends Campaign { * * @throws Exception */ - public function formatValues(array &$values, string $direction) { + public + static function formatValues(array &$values, string $direction) { if ($direction == self::IN) { // Change timestamp into DateTime string - if ($values['last_update']) { + if (isset($values['last_update'])) { $values['last_update'] = self::getDateTime($values['last_update']); } // empty project_type to 'default' - if (!$values['type']) { + if (empty($values['type'])) { $values['type'] = 'default'; } + + // Flatten project options array + foreach ($values['project_options'] as $key => $value) { + $values[$key] = $value; + } + unset($values['project_options']); + + // Flatten embed codes array + foreach ($values['embed'] as $key => $value) { + $values[$key] = $value; + } + unset($values['embed']); + + // Flatten button array + if (isset($values['buttons'])) { + foreach ( + $values['buttons'] as $button_key => $button + ) { + $values[$button_key] = $button['amount']; + } + unset($values['buttons']); + } + + // Invert and explode exclude_contact_fields + if (isset($values['exclude_contact_fields'])) { + $values['contact_fields'] = + array_diff( + self::contactFields, + explode(',', $values['exclude_contact_fields']) + ); + unset($values['exclude_contact_fields']); + } + + // Explode mandatory_contact_fields + if (isset($values['mandatory_contact_fields'])) { + $values['mandatory_contact_fields'] = + explode( + ',', + $values['mandatory_contact_fields'] + ); + unset($values['mandatory_contact_fields']); + } + + // Explode languages + if (isset($values['languages'])) { + $values['languages'] = + explode(',', $values['languages']); + } + + // Divide payment methods array into one time and recurring payment + // methods arrays containing only TRUE payment methods + foreach ($values['payment_methods'] as $key => $value) { + if ($value) { + if (StringOperations::endsWith($key, 'recurring')) { + $values['payment_methods_recurring'][] = $key; + } + else { + $values['payment_methods'][] = $key; + } + } + unset($values['payment_methods'][$key]); + } + + // Transform donation rhythm array to contain only TRUE elements + foreach ($values['donation_rhythm'] as $key => $value) { + if ($value) { + $values['donation_rhythm'][] = $key; + } + unset($values['donation_rhythm'][$key]); + } } elseif ($direction == self::OUT) { + $projectOptionsKeys = Cache::getInstance() + ->getTemplates()['TwingleProject']['project_options']; + $projectEmbedDataKeys = Cache::getInstance() + ->getTemplates()['TwingleProject']['project_embed_data']; + + // Merge payment_methods and payment_methods_recurring arrays and change + // keys to values and values to TRUE + if (isset($values['payment_methods'])) { + foreach ($values['payment_methods'] as $key => $value) { + unset($values['payment_methods'][$key]); + $values['payment_methods'][$value] = TRUE; + } + } + if (isset($values['payment_methods_recurring'])) { + foreach ($values['payment_methods_recurring'] as $value) { + $values['payment_methods'][$value] = TRUE; + } + unset($values['payment_methods_recurring']); + } + + // Move options, embed data and payment methods into own arrays + foreach ($values as $key => $value) { + if (in_array($key, $projectOptionsKeys)) { + $values['project_options'][$key] + = $value; + unset($values[$key]); + } + elseif (in_array($key, $projectEmbedDataKeys)) { + $values['embed_data'][$key] + = $value; + unset($values[$key]); + } + } + // Change DateTime string into timestamp $values['last_update'] = self::getTimestamp($values['last_update']); @@ -141,19 +571,80 @@ class CRM_TwingleCampaign_BAO_TwingleProject extends Campaign { : $values['type']; // Cast project target to integer - $values['project_target'] = (int) $values['project_target']; + if (isset($values['project_target'])) { + $values['project_target'] = (int) $values['project_target']; + } // Set default for 'allow_more' - $values['allow_more'] = empty($values['allow_more']) - ? FALSE - : TRUE; + $values['allow_more'] = !empty($values['allow_more']); + + // Invert and concatenate contact fields + if (isset($values['project_options']['contact_fields'])) { + // Invert contact_fields to exclude_contact_fields + $values['project_options']['exclude_contact_fields'] = + array_diff( + self::contactFields, + $values['project_options']['contact_fields'] + ); + unset($values['project_options']['contact_fields']); + // Concatenate contact_fields array + $values['project_options']['exclude_contact_fields'] = + implode( + ',', + $values['project_options']['exclude_contact_fields'] + ); + } + + // Concatenate mandatory project contact fields + if (isset($values['project_options']['mandatory_contact_fields'])) { + $values['project_options']['mandatory_contact_fields'] = + implode( + ',', + $values['project_options']['mandatory_contact_fields'] + ); + } + + // Concatenate project languages + if (isset($values['project_options']['languages'])) { + $values['project_options']['languages'] = + implode(',', $values['project_options']['languages']); + } + + // Build donation_rhythm array + if (isset($values['project_options']['donation_rhythm'])) { + $tmp_array = []; + foreach (self::donationRhythm as $donationRhythm) { + $tmp_array[$donationRhythm] = + in_array( + $donationRhythm, + $values['project_options']['donation_rhythm'] + ); + } + $values['project_options']['donation_rhythm'] = $tmp_array; + } + + // Build payment_methods_array + if (isset($values['payment_methods'])) { + $payment_methods = array_fill_keys(Cache::getInstance() + ->getTemplates()['TwingleProject']['payment_methods'], + FALSE); + $values['payment_methods'] = + array_merge($payment_methods, $values['payment_methods']); + } + + // Build buttons array + for ($i = 1; $i <= 4; $i++) { + if (isset($values['button' . $i])) { + $values['project_options']['buttons']['button' . $i] = + ['amount' => $values['button' . $i]]; + unset($values['button' . $i]); + } + } } else { - throw new Exception( "Invalid Parameter $direction for formatValues()" ); - } } @@ -170,7 +661,8 @@ class CRM_TwingleCampaign_BAO_TwingleProject extends Campaign { * @return array * */ - public function getResponse(string $status = NULL): array { + public + function getResponse(string $status = NULL): array { $project_type = empty($this->values['type']) ? 'default' : $this->values['type']; $response = [ @@ -185,26 +677,88 @@ class CRM_TwingleCampaign_BAO_TwingleProject extends Campaign { return $response; } - /** * ## Last update * Returns a timestamp of the last update of the TwingleProject campaign. * - * @return int|string|null + * @return int|null */ - public function lastUpdate() { + public function lastUpdate(): ?int { return self::getTimestamp($this->values['last_update']); } - /** * ## Get project id * Returns the **project_id** of this TwingleProject. * * @return int */ - public function getProjectId(): int { + public + function getProjectId(): int { return (int) $this->values['id']; } + /** + * ## Get the payment methods array of this project + * + * @return array + */ + public function getValues(): array { + if (isset($this->values)) { + return $this->values; + } + else { + return []; + } + } + + /** + * ## Get the project options array of this project + * + * @return array + */ + public function getOptions(): array { + if (isset($this->values['project_options'])) { + return $this->values['project_options']; + } + else { + return []; + } + } + + /** + * ## Get the payment methods array of this project + * + * @return array + */ + public function getPaymentMethods(): array { + if (isset($this->values['payment_methods'])) { + return $this->values['payment_methods']; + } + else { + return []; + } + } + + /** + * ## Get the payment methods array of this project + */ + public function deleteValues(): void { + unset ($this->values); + } + + /** + * ## Get the project options array of this project + */ + public function deleteOptions(): void { + unset($this->values['project_options']); + } + + /** + * ## Get the payment methods array of this project + */ + public function deletePaymentMethods(): void { + unset($this->values['payment_methods']); + } + } diff --git a/CRM/TwingleCampaign/Upgrader.php b/CRM/TwingleCampaign/Upgrader.php index dea29ab..6cecff9 100644 --- a/CRM/TwingleCampaign/Upgrader.php +++ b/CRM/TwingleCampaign/Upgrader.php @@ -16,15 +16,61 @@ 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). + /** + * @throws \CiviCRM_API3_Exception + */ + public function upgrade_01() { + + $campaign_info = require E::path() . + '/CRM/TwingleCampaign/resources/campaigns.php'; + $option_values = require E::path() . + '/CRM/TwingleCampaign/resources/option_values.php'; + + // Create campaign types + foreach ($campaign_info['campaign_types'] as $campaign_type) { + new CampaignType($campaign_type); + } + foreach (CampaignType::getCampaignTypes() as $campaign_type) { + $campaign_type->create(true); + } + + // Create custom groups + foreach ($campaign_info['custom_groups'] as $custom_group) { + foreach (CampaignType::getCampaignTypes() as $campaign_type) { + if ($campaign_type->getName() == $custom_group['campaign_type']) { + $custom_group['extends_entity_column_value'] = $campaign_type->getValue(); + } + } + $cg = new CustomGroup($custom_group); + $cg->create(true); + } + + // Create custom fields + foreach ($campaign_info['custom_fields'] as $custom_field) { + $cf = new CustomField($custom_field); + $cf->create(true); + } + + // Create option values + foreach ($option_values as $option_value) { + $ov = new OptionValue($option_value); + $ov->create(); + } + + return TRUE; + } + /** * @throws \Exception */ public function install() { // Create campaign types, custom fields and custom groups by the contents - // of the json file "campaigns.json" + // of the campaigns.php file - $campaign_info = Cache::getInstance()->getCampaigns(); - $option_values = Cache::getInstance()->getOptionValues(); + $campaign_info = require E::path() . + '/CRM/TwingleCampaign/resources/campaigns.php'; + $option_values = require E::path() . + '/CRM/TwingleCampaign/resources/option_values.php'; // Create campaign types foreach ($campaign_info['campaign_types'] as $campaign_type) { @@ -88,7 +134,8 @@ class CRM_TwingleCampaign_Upgrader extends CRM_TwingleCampaign_Upgrader_Base { */ public function uninstall() { - $campaign_info = Cache::getInstance()->getCampaigns(); + $campaign_info = require E::path() . + '/CRM/TwingleCampaign/resources/campaigns.php'; $option_values = Cache::getInstance()->getOptionValues(); // Delete campaign types diff --git a/CRM/TwingleCampaign/Utils/ExtensionCache.php b/CRM/TwingleCampaign/Utils/ExtensionCache.php index 365b50a..f813d9a 100644 --- a/CRM/TwingleCampaign/Utils/ExtensionCache.php +++ b/CRM/TwingleCampaign/Utils/ExtensionCache.php @@ -13,13 +13,7 @@ class CRM_TwingleCampaign_Utils_ExtensionCache { private $customFieldMapping; - private $translations; - - private $campaigns; - - private $templates; - - private $option_values; + private $campaignIds; /** * ## Get an instance (singleton) @@ -44,37 +38,11 @@ class CRM_TwingleCampaign_Utils_ExtensionCache { // Get a mapping of custom fields $this->customFieldMapping = CustomField::getMapping(); - // Initialize json files as arrays - $file_paths = [ - 'translations' => '/CRM/TwingleCampaign/resources/dictionary.json', - 'templates' => '/CRM/TwingleCampaign/resources/twingle_api_templates.json', - 'campaigns' => '/CRM/TwingleCampaign/resources/campaigns.json', - 'option_values' => '/CRM/TwingleCampaign/resources/option_values.json', - ]; - - foreach ($file_paths as $key => $file_path) { - - // Get array from json file - $file_path = E::path() . $file_path; - $json_file = file_get_contents($file_path); - $json_file_name = pathinfo($file_path)['filename']; - $array = json_decode($json_file, TRUE); - - // Throw and log an error if json file can't be read - if (!$array) { - $message = ($json_file_name) - ? "Could not read json file $json_file_name" - : "Could not locate json file in path: $file_path"; - Civi::log()->error($message); - throw new Exception($message); - } - - // Set attribute - $this->$key = $array; - } - // Get ids for Twingle related campaign types - foreach ($this->campaigns['campaign_types'] as $campaign_type) { + $this->campaignIds = require( + E::path() . '/CRM/TwingleCampaign/resources/campaigns.php' + ); + foreach ($this->campaignIds['campaign_types'] as $campaign_type) { $campaign_type_id = civicrm_api3( 'OptionValue', 'get', @@ -85,7 +53,7 @@ class CRM_TwingleCampaign_Utils_ExtensionCache { ] )['values']; if ($campaign_type_id) { - $this->campaigns['campaign_types'][$campaign_type['name']]['id'] = + $this->campaignIds['campaign_types'][$campaign_type['name']]['id'] = $campaign_type_id[0]['value']; } } @@ -114,28 +82,43 @@ class CRM_TwingleCampaign_Utils_ExtensionCache { * @return array */ public function getTranslations(): array { - return $this->translations; + return require( + E::path() . '/CRM/TwingleCampaign/resources/dictionary.php' + ); } /** * @return array */ public function getCampaigns(): array { - return $this->campaigns; + return require( + E::path() . '/CRM/TwingleCampaign/resources/campaigns.php' + ); + } + + /** + * @return array + */ + public function getCampaignIds(): array { + return $this->campaignIds; } /** * @return array */ public function getTemplates(): array { - return $this->templates; + return require( + E::path() . '/CRM/TwingleCampaign/resources/twingle_api_templates.php' + ); } /** * @return mixed */ public function getOptionValues() { - return $this->option_values; + return require( + E::path() . '/CRM/TwingleCampaign/resources/option_values.php' + ); } } \ No newline at end of file diff --git a/CRM/TwingleCampaign/Utils/StringOperations.php b/CRM/TwingleCampaign/Utils/StringOperations.php index 00014b7..19c0fd3 100644 --- a/CRM/TwingleCampaign/Utils/StringOperations.php +++ b/CRM/TwingleCampaign/Utils/StringOperations.php @@ -51,4 +51,24 @@ class CRM_TwingleCampaign_Utils_StringOperations { } return $string; } + + /** + * Checks if a string ands with another string. + * @param $haystack + * @param $needle + * @return bool + */ + public static function endsWith($haystack, $needle): bool { + return substr_compare($haystack, $needle, -strlen($needle)) === 0; + } + + /** + * Checks if a string starts with another string. + * @param $haystack + * @param $needle + * @return bool + */ + public static function startsWith($haystack, $needle): bool { + return substr_compare($haystack, $needle, 0, strlen($needle)) === 0; + } } \ No newline at end of file diff --git a/CRM/TwingleCampaign/resources/campaigns.json b/CRM/TwingleCampaign/resources/campaigns.json deleted file mode 100644 index aff49a7..0000000 --- a/CRM/TwingleCampaign/resources/campaigns.json +++ /dev/null @@ -1,469 +0,0 @@ -{ - "campaign_types": { - "twingle_project": { - "name": "twingle_project", - "label": "Twingle Project" - }, - "twingle_event": { - "name": "twingle_event", - "label": "Twingle Event" - }, - "twingle_campaign": { - "name": "twingle_campaign", - "label": "Twingle Campaign" - } - }, - "custom_groups": { - "twingle_project_information": { - "title": "Twingle Project Information", - "name": "Twingle_Project_Information", - "extends": "Campaign", - "campaign_type": "twingle_project", - "weight": "1" - }, - "twingle_project_embed_codes": { - "title": "Twingle Project Embed Codes", - "name": "Twingle_Project_Embed_Codes", - "extends": "Campaign", - "campaign_type": "twingle_project", - "collapse_display": "1", - "weight": "2" - }, - "twingle_event_information": { - "title": "Twingle Event Information", - "name": "Twingle_Event_Information", - "extends": "Campaign", - "campaign_type": "twingle_event" - }, - "twingle_campaign_information": { - "title": "Twingle Campaign Information", - "name": "Twingle_Campaign_Information", - "extends": "Campaign", - "campaign_type": "twingle_campaign" - } - }, - "custom_fields": { - "twingle_project_id": { - "custom_group_id": "Twingle_Project_Information", - "label": "Twingle Project ID", - "name": "twingle_project_id", - "is_required": 0, - "is_searchable": 1, - "data_type": "String", - "html_type": "Text", - "text_length": 16, - "is_active": 1, - "is_view": 1, - "weight": 1 - }, - "twingle_project_organisation_id": { - "custom_group_id": "Twingle_Project_Information", - "label": "Twingle Project organisation ID", - "name": "twingle_project_organisation_id", - "is_required": 0, - "is_searchable": 1, - "data_type": "String", - "html_type": "Text", - "text_length": 32, - "is_active": 1, - "is_view": 1, - "weight": 6 - }, - "twingle_project_identifier": { - "custom_group_id": "Twingle_Project_Information", - "label": "Twingle Project identifier", - "name": "twingle_project_identifier", - "is_required": 0, - "is_searchable": 1, - "data_type": "String", - "html_type": "Text", - "text_length": 15, - "is_active": 1, - "is_view": 1, - "weight": 3, - "help_post": "An unique identifier for a project (auto generated)" - }, - "twingle_project_type": { - "custom_group_id": "Twingle_Project_Information", - "label": "Twingle Project Type", - "name": "twingle_project_type", - "is_required": 0, - "is_searchable": 1, - "data_type": "String", - "html_type": "Select", - "option_values": { - "default": "Default", - "event": "Events", - "membership": "Membership" - }, - "text_length": 32, - "is_active": 1, - "is_view": 0, - "weight": 2, - "help_post": "Choose the project type. Allow users to create own events or to pay a membership fee.", - "default_value": "default" - }, - "twingle_project_allow_more": { - "custom_group_id": "Twingle_Project_Information", - "label": "Twingle Project allow more", - "name": "twingle_project_allow_more", - "is_required": 0, - "is_searchable": 1, - "data_type": "Boolean", - "html_type": "Radio", - "text_length": 4, - "is_active": 1, - "is_view": 0, - "weight": 4, - "help_post": "Allow to donate more than is defined in the target" - }, - "twingle_project_transaction_type": { - "custom_group_id": "Twingle_Project_Information", - "label": "Twingle Project transaction type", - "name": "twingle_project_transaction_type", - "is_required": 0, - "is_searchable": 1, - "data_type": "String", - "html_type": "Text", - "text_length": 32, - "is_active": 1, - "is_view": 0, - "weight": 5 - }, - "twingle_project_url": { - "custom_group_id": "Twingle_Project_Information", - "label": "Twingle Project URL", - "name": "twingle_project_url", - "is_required": 0, - "is_searchable": 0, - "data_type": "Memo", - "html_type": "TextArea", - "text_length": 600, - "is_active": 1, - "is_view": 0, - "weight": 6 - }, - "twingle_project_widget": { - "custom_group_id": "Twingle_Project_Embed_Codes", - "label": "Twingle Project Widget", - "name": "twingle_project_widget", - "is_required": 0, - "is_searchable": 0, - "data_type": "Memo", - "html_type": "TextArea", - "text_length": 600, - "is_active": 1, - "is_view": 1, - "weight": 1 - }, - "twingle_project_form": { - "custom_group_id": "Twingle_Project_Embed_Codes", - "label": "Twingle Project Form", - "name": "twingle_project_form", - "is_required": 0, - "is_searchable": 0, - "data_type": "Memo", - "html_type": "TextArea", - "text_length": 600, - "is_active": 1, - "is_view": 1, - "weight": 2 - }, - "twingle_project_widget-single": { - "custom_group_id": "Twingle_Project_Embed_Codes", - "label": "Twingle Project Widget Single", - "name": "twingle_project_widget-single", - "is_required": 0, - "is_searchable": 0, - "data_type": "Memo", - "html_type": "TextArea", - "text_length": 600, - "is_active": 1, - "is_view": 1, - "weight": 3 - }, - "twingle_project_form-single": { - "custom_group_id": "Twingle_Project_Embed_Codes", - "label": "Twingle Project Form Single", - "name": "twingle_project_form-single", - "is_required": 0, - "is_searchable": 0, - "data_type": "Memo", - "html_type": "TextArea", - "text_length": 600, - "is_active": 1, - "is_view": 1, - "weight": 4 - }, - "twingle_project_eventall": { - "custom_group_id": "Twingle_Project_Embed_Codes", - "label": "Twingle Project All Events", - "name": "twingle_project_eventall", - "is_required": 0, - "is_searchable": 0, - "data_type": "Memo", - "html_type": "TextArea", - "text_length": 1300, - "is_active": 1, - "is_view": 1, - "weight": 5 - }, - "twingle_project_eventlist": { - "custom_group_id": "Twingle_Project_Embed_Codes", - "label": "Twingle Project Event List", - "name": "twingle_project_eventlist", - "is_required": 0, - "is_searchable": 0, - "data_type": "Memo", - "html_type": "TextArea", - "text_length": 1300, - "is_active": 1, - "is_view": 1, - "weight": 6 - }, - "twingle_project_counter": { - "custom_group_id": "Twingle_Project_Embed_Codes", - "label": "Twingle Project Counter", - "name": "twingle_project_counter", - "is_required": 0, - "is_searchable": 0, - "data_type": "Memo", - "html_type": "TextArea", - "text_length": 120, - "is_active": 1, - "is_view": 1, - "weight": 7 - }, - "twingle_project_page": { - "custom_group_id": "Twingle_Project_Embed_Codes", - "label": "Twingle Project Page", - "name": "twingle_project_page", - "is_required": 0, - "is_searchable": 0, - "data_type": "Memo", - "html_type": "TextArea", - "text_length": 600, - "is_active": 1, - "is_view": 1, - "weight": 8 - }, - "twingle_event_id": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event ID", - "name": "twingle_event_id", - "is_required": 1, - "is_searchable": 1, - "data_type": "String", - "html_type": "Text", - "text_length": 16, - "is_active": 1, - "is_view": 1, - "weight": 1 - }, - "twingle_event_project_id": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Project ID", - "name": "twingle_event_project_id", - "is_required": 0, - "is_searchable": 1, - "data_type": "String", - "html_type": "Text", - "text_length": 16, - "is_active": 1, - "is_view": 1, - "weight": 2 - }, - "twingle_event_identifier": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event Identifier", - "name": "twingle_event_identifier", - "is_required": 0, - "is_searchable": 0, - "data_type": "String", - "html_type": "Text", - "text_length": 16, - "is_active": 1, - "is_view": 1, - "weight": 3 - }, - "twingle_event_contact": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event Initiator", - "name": "twingle_event_contact", - "is_required": 0, - "is_searchable": 1, - "data_type": "ContactReference", - "html_type": "Autocomplete-Select", - "is_active": 1, - "is_view": 0, - "weight": 5 - }, - "twingle_event_user_email": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event Initiator Email", - "name": "twingle_event_user_email", - "is_required": 0, - "is_searchable": 0, - "data_type": "String", - "html_type": "Text", - "text_length": 128, - "is_active": 1, - "is_view": 1, - "weight": 6 - }, - "twingle_event_is_public": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event is public", - "name": "twingle_event_is_public", - "is_required": 0, - "is_searchable": 1, - "data_type": "Boolean", - "html_type": "Radio", - "is_active": 1, - "is_view": 1, - "weight": 7 - }, - "twingle_event_deleted": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event Deleted", - "name": "twingle_event_deleted", - "is_required": 0, - "is_searchable": 1, - "data_type": "Boolean", - "html_type": "Radio", - "is_active": 1, - "is_view": 1, - "weight": 8 - }, - "twingle_event_confirmed_at": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event Confirmed At", - "name": "twingle_event_confirmed_at", - "is_required": 0, - "is_searchable": 0, - "data_type": "String", - "html_type": "Text", - "text_length": 64, - "is_active": 1, - "is_view": 1, - "weight": 9 - }, - "twingle_event_created_at": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event Created At", - "name": "twingle_event_created_at", - "is_required": 0, - "is_searchable": 0, - "data_type": "String", - "html_type": "Text", - "text_length": 64, - "is_active": 1, - "is_view": 1, - "weight": 10 - }, - "twingle_event_creation_url": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event Creation URL", - "name": "twingle_event_creation_url", - "is_required": 0, - "is_searchable": 0, - "data_type": "String", - "html_type": "Text", - "text_length": 256, - "is_active": 1, - "is_view": 1, - "weight": 11 - }, - "twingle_event_url_internal": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event Internal URL", - "name": "twingle_event_url_internal", - "is_required": 0, - "is_searchable": 0, - "data_type": "String", - "html_type": "Text", - "text_length": 256, - "is_active": 1, - "is_view": 1, - "weight": 12 - }, - "twingle_event_url_external": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event External URL", - "name": "twingle_event_url_external", - "is_required": 0, - "is_searchable": 0, - "data_type": "String", - "html_type": "Text", - "text_length": 256, - "is_active": 1, - "is_view": 1, - "weight": 13 - }, - "twingle_event_url_edit_internal": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event Edit Internal URL", - "name": "twingle_event_url_edit_internal", - "is_required": 0, - "is_searchable": 0, - "data_type": "String", - "html_type": "Text", - "text_length": 256, - "is_active": 1, - "is_view": 1, - "weight": 14 - }, - "twingle_event_url_edit_external": { - "custom_group_id": "Twingle_Event_Information", - "label": "Twingle Event Edit External URL", - "name": "twingle_event_url_edit_external", - "is_required": 0, - "is_searchable": 0, - "data_type": "String", - "html_type": "Text", - "text_length": 256, - "is_active": 1, - "is_view": 1, - "weight": 15 - }, - "twingle_campaign_parent_project_id": { - "custom_group_id": "Twingle_Campaign_Information", - "label": "Parent TwingleProject ID", - "name": "twingle_campaign_parent_project_id", - "is_required": 0, - "is_searchable": 1, - "data_type": "String", - "html_type": "Text", - "text_length": 16, - "is_active": 1, - "is_view": 1, - "weight": 1 - }, - "twingle_campaign_cid": { - "custom_group_id": "Twingle_Campaign_Information", - "label": "Twingle Campaign CID", - "name": "twingle_campaign_cid", - "is_required": 0, - "is_searchable": 0, - "data_type": "Memo", - "html_type": "Text", - "text_length": 32, - "is_active": 1, - "is_view": 1, - "weight": 2 - }, - "twingle_campaign_url": { - "custom_group_id": "Twingle_Campaign_Information", - "label": "Twingle Campaign URL", - "name": "twingle_campaign_url", - "is_required": 0, - "is_searchable": 0, - "data_type": "Memo", - "html_type": "TextArea", - "text_length": 600, - "is_active": 1, - "is_view": 1, - "weight": 3 - } - } -} diff --git a/CRM/TwingleCampaign/resources/campaigns.php b/CRM/TwingleCampaign/resources/campaigns.php new file mode 100644 index 0000000..1dbeba8 --- /dev/null +++ b/CRM/TwingleCampaign/resources/campaigns.php @@ -0,0 +1,1082 @@ + [ + "twingle_project" => [ + "name" => "twingle_project", + "label" => "Twingle Project" + ], + "twingle_event" => [ + "name" => "twingle_event", + "label" => "Twingle Event" + ], + "twingle_campaign" => [ + "name" => "twingle_campaign", + "label" => "Twingle Campaign" + ] + ], + "custom_groups" => [ + "twingle_project_information" => [ + "title" => E::ts("Twingle Information"), + "name" => "Twingle_Project_Information", + "extends" => "Campaign", + "campaign_type" => "twingle_project", + "weight" => "1" + ], + "twingle_project_options" => [ + "title" => E::ts("Twingle Settings"), + "name" => "Twingle_Project_Options", + "extends" => "Campaign", + "campaign_type" => "twingle_project", + "weight" => "2" + ], + "twingle_project_payment_methods" => [ + "title" => E::ts("Twingle Payment Methods"), + "name" => "Twingle_Project_Payment_Methods", + "extends" => "Campaign", + "campaign_type" => "twingle_project", + "weight" => "3" + ], + "twingle_project_embed_codes" => [ + "title" => E::ts("Twingle Embed Codes"), + "name" => "Twingle_Project_Embed_Codes", + "extends" => "Campaign", + "campaign_type" => "twingle_project", + "collapse_display" => "1", + "weight" => "4" + ], + "twingle_event_information" => [ + "title" => E::ts("Twingle Event Information"), + "name" => "Twingle_Event_Information", + "extends" => "Campaign", + "campaign_type" => "twingle_event" + ], + "twingle_campaign_information" => [ + "title" => E::ts("Twingle Campaign Information"), + "name" => "Twingle_Campaign_Information", + "extends" => "Campaign", + "campaign_type" => "twingle_campaign" + ] + ], + "custom_fields" => [ + "twingle_project_id" => [ + "custom_group_id" => "Twingle_Project_Information", + "label" => E::ts("Twingle Project ID"), + "name" => "twingle_project_id", + "is_required" => FALSE, + "is_searchable" => 1, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 16, + "is_active" => 1, + "is_view" => 1, + "weight" => 1 + ], + "twingle_project_organisation_id" => [ + "custom_group_id" => "Twingle_Project_Information", + "label" => E::ts("Organisation ID"), + "name" => "twingle_project_organisation_id", + "is_required" => FALSE, + "is_searchable" => 1, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 32, + "is_active" => 1, + "is_view" => 1, + "weight" => 6 + ], + "twingle_project_identifier" => [ + "custom_group_id" => "Twingle_Project_Information", + "label" => E::ts("identifier"), + "name" => "twingle_project_identifier", + "is_required" => FALSE, + "is_searchable" => 1, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 15, + "is_active" => 1, + "is_view" => 1, + "weight" => 3, + "help_post" => E::ts("An unique identifier for a project (auto generated)") + ], + "twingle_project_type" => [ + "custom_group_id" => "Twingle_Project_Information", + "label" => E::ts("Type"), + "name" => "twingle_project_type", + "is_required" => FALSE, + "is_searchable" => 1, + "data_type" => "String", + "html_type" => "Select", + "option_values" => [ + "default" => E::ts("Default"), + "event" => E::ts("Events"), + "membership" => E::ts("Membership") + ], + "text_length" => 32, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 2, + "help_post" => E::ts("Choose the project type. Allow users to create own events or to pay a membership fee."), + "default_value" => "default" + ], + "twingle_project_allow_more" => [ + "custom_group_id" => "Twingle_Project_Information", + "label" => E::ts("allow more"), + "name" => "twingle_project_allow_more", + "is_required" => FALSE, + "is_searchable" => 1, + "data_type" => "Boolean", + "html_type" => "Radio", + "text_length" => 4, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 4, + "help_post" => E::ts("Allow to donate more than is defined in the target") + ], + "twingle_project_transaction_type" => [ + "custom_group_id" => "Twingle_Project_Information", + "label" => E::ts("transaction type"), + "name" => "twingle_project_transaction_type", + "is_required" => FALSE, + "is_searchable" => 1, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 32, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 5 + ], + "twingle_project_url" => [ + "custom_group_id" => "Twingle_Project_Information", + "label" => E::ts("URL"), + "name" => "twingle_project_url", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Memo", + "html_type" => "TextArea", + "text_length" => 600, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 6 + ], + "twingle_project_widget" => [ + "custom_group_id" => "Twingle_Project_Embed_Codes", + "label" => E::ts("Widget"), + "name" => "twingle_project_widget", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Memo", + "html_type" => "TextArea", + "text_length" => 600, + "is_active" => 1, + "is_view" => 1, + "weight" => 1 + ], + "twingle_project_form" => [ + "custom_group_id" => "Twingle_Project_Embed_Codes", + "label" => E::ts("Form"), + "name" => "twingle_project_form", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Memo", + "html_type" => "TextArea", + "text_length" => 600, + "is_active" => 1, + "is_view" => 1, + "weight" => 2 + ], + "twingle_project_widget-single" => [ + "custom_group_id" => "Twingle_Project_Embed_Codes", + "label" => E::ts("Widget Single"), + "name" => "twingle_project_widget-single", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Memo", + "html_type" => "TextArea", + "text_length" => 600, + "is_active" => 1, + "is_view" => 1, + "weight" => 3 + ], + "twingle_project_form-single" => [ + "custom_group_id" => "Twingle_Project_Embed_Codes", + "label" => E::ts("Form Single"), + "name" => "twingle_project_form-single", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Memo", + "html_type" => "TextArea", + "text_length" => 600, + "is_active" => 1, + "is_view" => 1, + "weight" => 4 + ], + "twingle_project_eventall" => [ + "custom_group_id" => "Twingle_Project_Embed_Codes", + "label" => E::ts("All Events"), + "name" => "twingle_project_eventall", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Memo", + "html_type" => "TextArea", + "text_length" => 1300, + "is_active" => 1, + "is_view" => 1, + "weight" => 5 + ], + "twingle_project_eventlist" => [ + "custom_group_id" => "Twingle_Project_Embed_Codes", + "label" => E::ts("Event List"), + "name" => "twingle_project_eventlist", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Memo", + "html_type" => "TextArea", + "text_length" => 1300, + "is_active" => 1, + "is_view" => 1, + "weight" => 6 + ], + "twingle_project_counter" => [ + "custom_group_id" => "Twingle_Project_Embed_Codes", + "label" => E::ts("Counter"), + "name" => "twingle_project_counter", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Memo", + "html_type" => "TextArea", + "text_length" => 120, + "is_active" => 1, + "is_view" => 1, + "weight" => 7 + ], + "twingle_project_page" => [ + "custom_group_id" => "Twingle_Project_Embed_Codes", + "label" => E::ts("Page"), + "name" => "twingle_project_page", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Memo", + "html_type" => "TextArea", + "text_length" => 600, + "is_active" => 1, + "is_view" => 1, + "weight" => 8 + ], + "twingle_project_has_confirmation_mail" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Confirmation Mail"), + "name" => "twingle_project_has_confirmation_mail", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "text_length" => 6, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 1, + "help_post" => E::ts("Send confirmation mail") + ], + "twingle_project_has_donation_receipt" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Donation Receipt"), + "name" => "twingle_project_has_donation_receipt", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "text_length" => 6, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 3, + "help_post" => E::ts("Offer donation receipts") + ], + "twingle_project_has_contact_data" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Contact Data"), + "name" => "twingle_project_has_contact_data", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "text_length" => 6, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 4 + ], + "twingle_project_donation_rhythm" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Donation Rhythm"), + "name" => "twingle_project_donation_rhythm", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Multi-Select", + "option_values" => [ + "yearly" => E::ts("yearly"), + "halfyearly" => E::ts("halfyearly"), + "quarterly" => E::ts("quarterly"), + "monthly" => E::ts("monthly"), + "one_time" => E::ts("one time") + ], + "text_length" => 64, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 5, + "help_post" => E::ts("The selected options are available for selection in the donation widget.") + ], + "twingle_project_default_rhythm" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Default Rhythm"), + "name" => "twingle_project_default_rhythm", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Radio", + "option_values" => [ + "yearly" => E::ts("yearly"), + "halfyearly" => E::ts("halfyearly"), + "quarterly" => E::ts("quarterly"), + "monthly" => E::ts("monthly"), + "one_time" => E::ts("one time") + ], + "text_length" => 64, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 6, + "help_post" => E::ts("Which donation rhythm should be displayed as selected by default?") + ], + "twingle_project_has_newsletter_registration" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Newsletter Registration"), + "name" => "twingle_project_has_newsletter_registration", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "text_length" => 6, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 7, + "help_post" => E::ts("Enable newsletter registration") + ], + "twingle_project_has_postinfo_registration" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Postinfo Registration"), + "name" => "twingle_project_has_postinfo_registration", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "text_length" => 6, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 8, + "help_post" => E::ts("Enable post info registration") + ], + "twingle_project_design_background_color" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Background Color"), + "name" => "twingle_project_design_background_color", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 6, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 9, + "help_post" => E::ts("Hex color code (e.g. ffffff for white)") + ], + "twingle_project_design_primary_color" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Primary Color"), + "name" => "twingle_project_design_primary_color", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 6, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 10, + "help_post" => E::ts("Hex color code (e.g. ffffff for white)") + ], + "twingle_project_design_font_color" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Font Color"), + "name" => "twingle_project_design_font_color", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 6, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 12, + "help_post" => E::ts("Hex color code (e.g. ffffff for white)") + ], + "twingle_project_bcc_email_address" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("BCC Email"), + "name" => "twingle_project_bcc_email_address", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 64, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 16, + "help_post" => E::ts("Email address used as bcc addresses for confirmation mail which is send to an user") + ], + "twingle_project_donation_value_min" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Donation Min"), + "name" => "twingle_project_donation_value_min", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 10, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 17, + "help_post" => E::ts("Minimum donation value"), + "default_value" => "5" + ], + "twingle_project_donation_value_max" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Donation Max"), + "name" => "twingle_project_donation_value_max", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 10, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 18, + "help_post" => E::ts("Maximum donation value"), + "default_value" => "500" + ], + "twingle_project_donation_value_default" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Donation Default"), + "name" => "twingle_project_donation_value_default", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 10, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 19, + "help_post" => E::ts("Default donation value"), + "default_value" => "50" + ], + "twingle_project_contact_fields" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Contact Fields"), + "name" => "twingle_project_contact_fields", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Multi-Select", + "option_values" => [ + "salutation" => E::ts("Salutation"), + "firstname" => E::ts("First name"), + "lastname" => E::ts("Last name"), + "company" => E::ts("Company"), + "birthday" => E::ts("Birthday"), + "street" => E::ts("Street"), + "postal_code" => E::ts("Postal Code"), + "city" => E::ts("City"), + "country" => E::ts("Country"), + "telephone" => E::ts("Telephone") + ], + "is_active" => 1, + "is_view" => FALSE, + "weight" => 20, + "help_post" => E::ts("Fields to include in contact form") + ], + "twingle_project_mandatory_contact_fields" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Mandatory Contact Fields"), + "name" => "twingle_project_mandatory_contact_fields", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Multi-Select", + "option_values" => [ + "salutation" => E::ts("Salutation"), + "firstname" => E::ts("First name"), + "lastname" => E::ts("Last name"), + "company" => E::ts("Company"), + "birthday" => E::ts("Birthday"), + "street" => E::ts("Street"), + "postal_code" => E::ts("Postal Code"), + "city" => E::ts("City"), + "country" => E::ts("Country"), + "telephone" => E::ts("Telephone") + ], + "is_active" => 1, + "is_view" => FALSE, + "weight" => 20, + "help_post" => E::ts("Fields that must get filled in the contact form.") + ], + "twingle_project_custom_css" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Custom CSS"), + "name" => "twingle_project_custom_css", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 120, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 21, + "help_post" => E::ts("URL to a custom CSS file that will be included in the frontend") + ], + "twingle_project_share_url" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Share URL"), + "name" => "twingle_project_share_url", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 120, + "is_active" => 1, + "is_view" => FALSE, + "weight" => 22, + "help_post" => E::ts("URL for the sharing component on the last page and doi page") + ], + "twingle_project_has_contact_mandatory" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Contact Mandatory"), + "name" => "twingle_project_has_contact_mandatory", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => 1, + "is_view" => FALSE, + "weight" => 23, + "help_post" => E::ts("If the contact data should be requested mandatory as second step") + ], + "twingle_project_has_doi" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Double Opt-In"), + "name" => "twingle_project_has_doi", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => 1, + "is_view" => FALSE, + "weight" => 24, + "help_post" => E::ts("Enable Twingle's double opt-in (Do not enable, if you use CiviCRM's double opt-in!)") + ], + "twingle_project_has_force_donation_target_buttons" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Force Donation Taget as Button"), + "name" => "twingle_project_has_force_donation_target_buttons", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => 1, + "is_view" => FALSE, + "weight" => 26, + "help_post" => E::ts("Force showing the donation targets as buttons") + ], + "twingle_project_slidericon" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Slider Icon"), + "name" => "twingle_project_slidericon", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Select", + "option_values" => [ + "heart" => E::ts("Heart"), + "asterisk" => E::ts("Asterisk"), + "animal" => E::ts("Animal"), + "Rettungsring" => E::ts("Lifebelt"), + "angellist" => E::ts("Angellist"), + "handshake" => E::ts("Handshake"), + "dollar" => E::ts("Dollar"), + "menue_burger_fine" => E::ts("Menue"), + "office" => E::ts("Office"), + "leaf" => E::ts("Leaf"), + "cog" => E::ts("Cog"), + "wvg" => E::ts("SVG"), + "euro" => E::ts("Euro"), + "stats-dots" => E::ts("Stats"), + "circle_fine" => E::ts("Circle"), + "waterdrop_outline" => E::ts("Water drop outline"), + "waterdrop" => E::ts("Water drop"), + "gift" => E::ts("Gift"), + "biene_b" => E::ts("Bee"), + "blume" => E::ts("Flower"), + "train" => E::ts("Train"), + "empty" => E::ts("No Icon") + ], + "is_active" => 1, + "is_view" => FALSE, + "weight" => 29 + ], + "twingle_project_has_hidden_logo" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Hidden Logo"), + "name" => "twingle_project_has_hidden_logo", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => 1, + "is_view" => FALSE, + "weight" => 35, + "help_post" => E::ts("Hide the Logo on the project page") + ], + "twingle_project_has_projecttarget_as_money" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Target Format"), + "name" => "twingle_project_has_projecttarget_as_money", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => 1, + "is_view" => FALSE, + "weight" => 36, + "help_post" => E::ts("Format of the reached portion of the donation target"), + "default_value" => "0" + ], + "twingle_project_has_donationtarget_textfield" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Donation Purpose as Textfield"), + "name" => "twingle_project_has_donationtarget_textfield", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => 1, + "is_view" => FALSE, + "weight" => 37, + "help_post" => E::ts("Let donors enter their own donation purpose") + ], + "twingle_project_has_civi_crm_activated" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Activate CiviCRM Support"), + "name" => "twingle_project_has_civi_crm_activated", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => 1, + "is_view" => FALSE, + "weight" => 38, + "help_post" => E::ts("Activate support for Twingle Extension (de.systopia.twingle)"), + "default_value" => TRUE, + ], + "twingle_project_has_step_index" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Show Step Index"), + "name" => "twingle_project_has_step_index", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 39, + "help_post" => E::ts("Show a step index during donation process") + ], + "twingle_project_languages" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Languages"), + "name" => "twingle_project_languages", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Multi-Select", + "option_values" => [ + "de" => E::ts("German"), + "en" => E::ts("English"), + "fr" => E::ts("French"), + "es" => E::ts("Spanish") + ], + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 43 + ], + "twingle_project_has_buttons" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Buttons"), + "name" => "twingle_project_has_buttons", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 44, + "help_post" => E::ts("Up to four buttons can be configured. If you leave the amount blank, the button will not be displayed.") + ], + "twingle_project_has_no_slider" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Slider"), + "name" => "twingle_project_has_no_slider", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 44, + "help_post" => E::ts("Show a slider that allows the donor to choose the donation amount.") + ], + "twingle_project_button1" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Button 1"), + "name" => "twingle_project_button1", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 10, + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 44, + "help_post" => E::ts("Amount to be displayed on Button 1") + ], + "twingle_project_button2" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Button 2"), + "name" => "twingle_project_button2", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 10, + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 44, + "help_post" => E::ts("Amount to be displayed on Button 2") + ], + "twingle_project_button3" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Button 3"), + "name" => "twingle_project_button3", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 10, + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 44, + "help_post" => E::ts("Amount to be displayed on Button 3") + ], + "twingle_project_button4" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Button 4"), + "name" => "twingle_project_button4", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 10, + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 44, + "help_post" => E::ts("Amount to be displayed on Button 4") + ], + "twingle_project_has_newsletter_namerequest" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Newsletter Name Requested"), + "name" => "twingle_project_has_newsletter_namerequest", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 44, + "help_post" => E::ts("Must a donor give his name for newsletter sign-up?") + ], + "twingle_project_has_show_donator_data" => [ + "custom_group_id" => "Twingle_Project_Options", + "label" => E::ts("Show List of Donations"), + "name" => "twingle_project_has_show_donator_data", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 44, + "help_post" => E::ts("Display a list of public donations") + ], + "twingle_project_payment_methods" => [ + "custom_group_id" => "Twingle_Project_Payment_Methods", + "label" => E::ts("Payment Methods"), + "name" => "twingle_project_payment_methods", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Multi-Select", + "option_values" => [ + "has_paypal" => E::ts("PayPal"), + "has_banktransfer" => E::ts("Banktransfer"), + "has_debit" => E::ts("Debit"), + "has_sofortueberweisung" => E::ts("Sofortüberweisung") + ], + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 45, + "help_post" => E::ts("Chose which payment methods should be available. NOTE: You might have to activate them first in the Twingle-Manager configuration.") + ], + "twingle_project_payment_methods_recurring" => [ + "custom_group_id" => "Twingle_Project_Payment_Methods", + "label" => E::ts("Recurring Payment Methods"), + "name" => "twingle_project_payment_methods_recurring", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Multi-Select", + "option_values" => [ + "has_paypal_recurring" => E::ts("PayPal"), + "has_debit_recurring" => E::ts("Debit") + ], + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 45, + "help_post" => E::ts("Display a list of public donations") + ], + "twingle_event_id" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Twingle Event ID"), + "name" => "twingle_event_id", + "is_required" => TRUE, + "is_searchable" => TRUE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 16, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 1 + ], + "twingle_event_project_id" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Twingle Project ID"), + "name" => "twingle_event_project_id", + "is_required" => FALSE, + "is_searchable" => TRUE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 16, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 2 + ], + "twingle_event_identifier" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Identifier"), + "name" => "twingle_event_identifier", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 16, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 3 + ], + "twingle_event_contact" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Initiator"), + "name" => "twingle_event_contact", + "is_required" => FALSE, + "is_searchable" => TRUE, + "data_type" => "ContactReference", + "html_type" => "Autocomplete-Select", + "is_active" => TRUE, + "is_view" => FALSE, + "weight" => 5 + ], + "twingle_event_user_email" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Initiator Email"), + "name" => "twingle_event_user_email", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 128, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 6 + ], + "twingle_event_is_public" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Is public"), + "name" => "twingle_event_is_public", + "is_required" => FALSE, + "is_searchable" => TRUE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 7 + ], + "twingle_event_deleted" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Deleted"), + "name" => "twingle_event_deleted", + "is_required" => FALSE, + "is_searchable" => TRUE, + "data_type" => "Boolean", + "html_type" => "Radio", + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 8 + ], + "twingle_event_confirmed_at" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Confirmed At"), + "name" => "twingle_event_confirmed_at", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 64, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 9 + ], + "twingle_event_created_at" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Created At"), + "name" => "twingle_event_created_at", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 64, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 10 + ], + "twingle_event_creation_url" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Creation URL"), + "name" => "twingle_event_creation_url", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 256, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 11 + ], + "twingle_event_url_internal" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Internal URL"), + "name" => "twingle_event_url_internal", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 256, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 12 + ], + "twingle_event_url_external" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("External URL"), + "name" => "twingle_event_url_external", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 256, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 13 + ], + "twingle_event_url_edit_internal" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Edit Internal URL"), + "name" => "twingle_event_url_edit_internal", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 256, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 14 + ], + "twingle_event_url_edit_external" => [ + "custom_group_id" => "Twingle_Event_Information", + "label" => E::ts("Edit External URL"), + "name" => "twingle_event_url_edit_external", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 256, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 15 + ], + "twingle_campaign_parent_project_id" => [ + "custom_group_id" => "Twingle_Campaign_Information", + "label" => E::ts("Parent TwingleProject ID"), + "name" => "twingle_campaign_parent_project_id", + "is_required" => FALSE, + "is_searchable" => TRUE, + "data_type" => "String", + "html_type" => "Text", + "text_length" => 16, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 1 + ], + "twingle_campaign_cid" => [ + "custom_group_id" => "Twingle_Campaign_Information", + "label" => E::ts("CID"), + "name" => "twingle_campaign_cid", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Memo", + "html_type" => "Text", + "text_length" => 32, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 2 + ], + "twingle_campaign_url" => [ + "custom_group_id" => "Twingle_Campaign_Information", + "label" => E::ts("URL"), + "name" => "twingle_campaign_url", + "is_required" => FALSE, + "is_searchable" => FALSE, + "data_type" => "Memo", + "html_type" => "TextArea", + "text_length" => 600, + "is_active" => TRUE, + "is_view" => TRUE, + "weight" => 3 + ] + ] +]; + diff --git a/CRM/TwingleCampaign/resources/dictionary.json b/CRM/TwingleCampaign/resources/dictionary.json deleted file mode 100644 index 150deff..0000000 --- a/CRM/TwingleCampaign/resources/dictionary.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "TwingleProject": { - "name": "title", - "last_update": "last_modified_date", - "project_target": "goal_revenue" - }, - "TwingleEvent": { - "description": "title", - "updated_at": "last_modified_date", - "created_at": "start_date", - "target": "goal_revenue" - } -} \ No newline at end of file diff --git a/CRM/TwingleCampaign/resources/dictionary.php b/CRM/TwingleCampaign/resources/dictionary.php new file mode 100644 index 0000000..e3a909c --- /dev/null +++ b/CRM/TwingleCampaign/resources/dictionary.php @@ -0,0 +1,18 @@ + [ + "name" => "title", + "last_update" => "last_modified_date", + "project_target" => "goal_revenue", + "counter-url" => "counter", + "embed" => "embed_codes" + ], + "TwingleEvent" => [ + "description" => "title", + "updated_at" => "last_modified_date", + "created_at" => "start_date", + "target" => "goal_revenue" + ] +]; + diff --git a/CRM/TwingleCampaign/resources/option_values.json b/CRM/TwingleCampaign/resources/option_values.json deleted file mode 100644 index 03b6564..0000000 --- a/CRM/TwingleCampaign/resources/option_values.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "twingle_event_donation": { - "name": "twingle_event_donation", - "label": "Twingle Event", - "description": "A soft credit type for TwingleEvent initiators.", - "option_group_id": "soft_credit_type" - } -} \ No newline at end of file diff --git a/CRM/TwingleCampaign/resources/option_values.php b/CRM/TwingleCampaign/resources/option_values.php new file mode 100644 index 0000000..c4a25d5 --- /dev/null +++ b/CRM/TwingleCampaign/resources/option_values.php @@ -0,0 +1,10 @@ + [ + "name" => "twingle_event_donation", + "label" => "Twingle Event", + "description" => "A soft credit type for TwingleEvent initiators.", + "option_group_id" => "soft_credit_type" + ] +]; diff --git a/CRM/TwingleCampaign/resources/twingle_api_templates.json b/CRM/TwingleCampaign/resources/twingle_api_templates.json deleted file mode 100644 index de6b202..0000000 --- a/CRM/TwingleCampaign/resources/twingle_api_templates.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "TwingleProject": [ - "id", - "identifier", - "allow_more", - "name", - "organisation_id", - "project_target", - "transaction_type", - "type", - "last_update", - "url" - ], - "project_embed_data": [ - "page", - "widget", - "form", - "form-single", - "widget-single", - "eventall", - "eventlist", - "counter" - ], - "TwingleEvent": [ - "id", - "project_id", - "identifier", - "description", - "user_name", - "user_email", - "is_public", - "deleted", - "confirmed_at", - "created_at", - "updated_at", - "target", - "creation_url", - "show_internal", - "show_external", - "edit_internal", - "edit_external", - "urls" - ], - "event_embed_data": [ - "page", - "eventpage", - "widget", - "form", - "widget-single", - "form-single", - "eventall", - "eventlist", - "eventeditcreate" - ], - "TwingleCampaign": [ - "id", - "parent_id", - "name", - "title" - ] -} \ No newline at end of file diff --git a/CRM/TwingleCampaign/resources/twingle_api_templates.php b/CRM/TwingleCampaign/resources/twingle_api_templates.php new file mode 100644 index 0000000..8e28c4f --- /dev/null +++ b/CRM/TwingleCampaign/resources/twingle_api_templates.php @@ -0,0 +1,114 @@ + [ + "project_data" => [ + "id", + "identifier", + "allow_more", + "name", + "organisation_id", + "project_target", + "transaction_type", + "type", + "last_update", + "url" + ], + "project_embed_data" => [ + "page", + "widget", + "form", + "form-single", + "widget-single", + "eventall", + "eventlist", + "counter" + ], + "project_options" => [ + "has_confirmation_mail", + "has_donation_receipt", + "has_contact_data", + "donation_rhythm", + "default_rhythm", + "has_newsletter_registration", + "has_postinfo_registration", + "design_background_color", + "design_primary_color", + "design_font_color", + "bcc_email_address", + "donation_value_min", + "donation_value_max", + "donation_value_default", + "contact_fields", + "exclude_contact_fields", + "mandatory_contact_fields", + "custom_css", + "share_url", + "has_contact_mandatory", + "has_doi", + "has_force_donation_target_buttons", + "slidericon", + "has_hidden_logo", + "has_projecttarget_as_money", + "has_donationtarget_textfield", + "has_civi_crm_activated", + "has_step_index", + "languages", + "has_buttons", + "has_no_slider", + "buttons", + "has_newsletter_namerequest", + "has_show_donator_data" + ], + "payment_methods" => [ + "has_paypal", + "has_banktransfer", + "has_debit", + "has_sofortueberweisung", + "has_paypal_recurring", + "has_debit_recurring" + ] + ], + "TwingleEvent" => [ + "event_data" => [ + "id", + "project_id", + "identifier", + "description", + "user_name", + "user_email", + "is_public", + "deleted", + "confirmed_at", + "created_at", + "updated_at", + "target", + "creation_url", + "show_internal", + "show_external", + "edit_internal", + "edit_external", + "urls" + ], + "event_embed_data" => [ + "page", + "eventpage", + "widget", + "form", + "widget-single", + "form-single", + "eventall", + "eventlist", + "eventeditcreate" + ] + ], + "TwingleCampaign" => [ + "campaign_data" => [ + "id", + "parent_id", + "name", + "title" + ] + ] +]; + diff --git a/api/v3/TwingleCampaign/Get.php b/api/v3/TwingleCampaign/Get.php index dce6b3a..b0670e1 100644 --- a/api/v3/TwingleCampaign/Get.php +++ b/api/v3/TwingleCampaign/Get.php @@ -105,11 +105,11 @@ function civicrm_api3_twingle_campaign_Get(array $params): array { // Get campaign type id for TwingleCampaign $twingle_campaign_campaign_type_id = Cache::getInstance() - ->getCampaigns()['campaign_types']['twingle_campaign']['id']; + ->getCampaignIds()['campaign_types']['twingle_campaign']['id']; - // If no id but a project_id is provided, get all TwingleCampaign children of - // this TwingleProject - if (array_key_exists('project_id', $params) && $params['project_id']) { + // If no id but a parent_id or a project_id is provided, get all + // TwingleCampaign children of this TwingleProject + if (isset($params['project_id']) && !isset($params['parent_id'])) { // Get TwingleProject $project = civicrm_api3('TwingleProject', diff --git a/api/v3/TwingleEvent/Get.php b/api/v3/TwingleEvent/Get.php index 2398d66..02caaea 100644 --- a/api/v3/TwingleEvent/Get.php +++ b/api/v3/TwingleEvent/Get.php @@ -157,6 +157,7 @@ function civicrm_api3_twingle_event_Get(array $params): array { $tmp_event = new TwingleEvent([]); $tmp_event->translateKeys( $returnValues[$event['id']], + TwingleEvent::EVENT, TwingleEvent::OUT ); TwingleEvent::formatValues( diff --git a/api/v3/TwingleProject/Get.php b/api/v3/TwingleProject/Get.php index 5754ba3..012150a 100644 --- a/api/v3/TwingleProject/Get.php +++ b/api/v3/TwingleProject/Get.php @@ -127,7 +127,7 @@ function civicrm_api3_twingle_project_Get(array $params): array { $query = ['options' => ['limit' => 0]]; foreach ($params as $key => $value) { - if ( $key != 'id' && + if ($key != 'id' && array_key_exists('twingle_project_' . $key, $custom_field_mapping) ) { $query[$custom_field_mapping['twingle_project_' . $key]] = $value; @@ -156,22 +156,28 @@ function civicrm_api3_twingle_project_Get(array $params): array { $returnValues[$project['id']][$key] = $value; } } - foreach($returnValues[$project['id']] as $key => $value) { + foreach ($returnValues[$project['id']] as $key => $value) { if ($key != 'twingle_project_id' && strpos($key, 'twingle_project_') === 0) { - $returnValues[$project['id']][str_replace('twingle_project_', '', $key)] - = $value; + $key_short = str_replace('twingle_project_', '', $key); + $returnValues[$project['id']][$key_short] = $value; unset($returnValues[$project['id']][$key]); - } elseif($key == 'twingle_project_id'){ + } + elseif ($key == 'twingle_project_id') { $returnValues[$project['id']]['project_id'] = $value; unset($returnValues[$project['id']]['twingle_project_id']); } } try { - $tmp_project = new TwingleProject([]); - $tmp_project->translateKeys($returnValues[$project['id']], TwingleProject::OUT); - $tmp_project->formatValues($returnValues[$project['id']], TwingleProject::OUT); - } - catch (Exception $e) { + TwingleProject::translateKeys( + $returnValues[$project['id']], + TwingleProject::PROJECT, + TwingleProject::OUT + ); + TwingleProject::formatValues( + $returnValues[$project['id']], + TwingleProject::OUT + ); + } catch (Exception $e) { throw new API_Exception($e->getMessage()); } } diff --git a/api/v3/TwingleProject/Sync.php b/api/v3/TwingleProject/Sync.php index db1ebb2..7768997 100644 --- a/api/v3/TwingleProject/Sync.php +++ b/api/v3/TwingleProject/Sync.php @@ -104,7 +104,6 @@ function civicrm_api3_twingle_project_Sync(array $params): array { // instantiate project from CiviCRM $id = $result['id']; - unset($result['id']); $project = new TwingleProject($result, $id); // Synchronize projects @@ -131,6 +130,20 @@ function civicrm_api3_twingle_project_Sync(array $params): array { // instantiate project $project = new TwingleProject($result, $id); + // Send project information to Tingle and update project with the + // answer + $projectOptions = $project->getOptions(); + $project->deleteOptions(); + $paymentMethods = $project->getPaymentMethods(); + $project->deletePaymentMethods(); + $projectFromTwingle = $twingleApi->pushProject($project->export()); + $project = new TwingleProject($projectFromTwingle, $project->getId()); + $projectValues = $project->getValues(); + $projectValues['project_options'] = $projectOptions; + $projectValues['payment_methods'] = $paymentMethods; + $project->update($projectValues); + $project->complement($projectFromTwingle); + // Push project to Twingle return _pushProjectToTwingle($project, $twingleApi, $params); } @@ -140,7 +153,7 @@ function civicrm_api3_twingle_project_Sync(array $params): array { else { // Counter for sync errors - $errors_occurred = 0; + $errors = []; // Get all projects from Twingle $projects_from_twingle = $twingleApi->getProject(); @@ -172,7 +185,7 @@ function civicrm_api3_twingle_project_Sync(array $params): array { // push project to Twingle $result = _pushProjectToTwingle($project, $twingleApi, $params); if ($result['is_error'] != 0) { - $errors_occurred++; + $errors[$result['id']] = $result['error_message']; $returnValues[$project->getId()] = $project->getResponse($result['error_message']); } @@ -189,11 +202,6 @@ function civicrm_api3_twingle_project_Sync(array $params): array { $project = new TwingleProject($project_from_twingle); try { - // Get embed data - $project->setEmbedData( - $twingleApi->getProjectEmbedData($project->getProjectId()) - ); - // If this is a test, do not make db changes if (isset($params['is_test']) && $params['is_test']) { $returnValues[$project->getId()] = @@ -204,7 +212,7 @@ function civicrm_api3_twingle_project_Sync(array $params): array { $returnValues[$project->getId()] = $project->getResponse('TwingleProject created'); } catch (Exception $e) { - $errors_occurred++; + $errors[$result['id']] = $result['error_message']; Civi::log()->error( E::LONG_NAME . ' could not create TwingleProject: ' . @@ -223,22 +231,27 @@ function civicrm_api3_twingle_project_Sync(array $params): array { foreach ($projects_from_twingle as $project_from_twingle) { if ($project_from_twingle['id'] == $project_from_civicrm['project_id']) { - // store campaign id in $id + // store campaign id in $id and replace it with project_id $id = $project_from_civicrm['id']; - unset($project_from_civicrm['id']); + $project_from_civicrm['id'] = $project_from_civicrm['project_id']; + unset($project_from_civicrm['project_id']); // instantiate project with values from TwingleProject.Get $project = new TwingleProject($project_from_civicrm, $id); // sync project - $result = _projectSync($project, $project_from_twingle, $twingleApi, $params); - if ($result['is_error'] != 0) { - $errors_occurred++; + $result = _projectSync( + $project, + $project_from_twingle, + $twingleApi, + $params); + if (!$result['is_error'] == 0) { + $errors[$result['id']] = $result['error_message']; $returnValues[$project->getId()] = $project->getResponse($result['error_message']); } else { - $returnValues[$project->getId()] = $result['values']; + $returnValues[$result['id']] = $result['values'][$result['id']]; } break; } @@ -246,13 +259,29 @@ function civicrm_api3_twingle_project_Sync(array $params): array { } // Return results - if ($errors_occurred > 0) { - $errorMessage = ($errors_occurred > 1) - ? "$errors_occurred synchronisation processes resulted with an error" + if (sizeof($errors) > 0) { + + $errorCount = sizeof($errors); + $errorMessage = ($errorCount > 1) + ? "$errorCount synchronisation processes resulted with an error" : "1 synchronisation process resulted with an error"; + + // Log errors + Civi::log()->error(E::LONG_NAME . ': ' . $errorMessage, $errors); + + // Return API Error + $errorMessage = $errorMessage . ': ['; + foreach ($errors as $key => $value) { + $errorMessage = + $errorMessage . + " ['project_id' => '$key', 'error_message' => '$value'],"; + } + $errorMessage = + substr($errorMessage, 0, strlen($errorMessage) - 1) . ' ]'; + return civicrm_api3_create_error( $errorMessage, - $returnValues + $errors ); } else { @@ -284,13 +313,13 @@ function _updateProjectLocally(array $project_from_twingle, try { $project->update($project_from_twingle); - $project->setEmbedData( - $twingleApi->getProjectEmbedData($project->getProjectId()) - ); + // If this is a test, do not make db changes if (array_key_exists('is_test', $params) && $params['is_test']) { + $response[$project->getId()] = + $project->getResponse('TwingleProject ready to update'); return civicrm_api3_create_success( - $project->getResponse('TwingleProject ready to update'), + $response, $params, 'TwingleProject', 'Sync' @@ -298,7 +327,8 @@ function _updateProjectLocally(array $project_from_twingle, } // ... else, update local TwingleProject campaign $project->create(TRUE); - $response = $project->getResponse('TwingleProject updated successfully'); + $response[$project->getId()] = + $project->getResponse('TwingleProject updated successfully'); return civicrm_api3_create_success( $response, $params, @@ -326,18 +356,22 @@ function _updateProjectLocally(array $project_from_twingle, * @param \CRM_TwingleCampaign_BAO_TwingleProject $project * @param \CRM_TwingleCampaign_BAO_TwingleApiCall $twingleApi * @param array $params + * @param bool $update Update project after push? * * @return array * @throws \CiviCRM_API3_Exception */ function _pushProjectToTwingle(TwingleProject $project, TwingleApiCall $twingleApi, - array $params): array { + array $params = [], + bool $update = TRUE): array { // If this is a test, do not make db changes - if ($params['is_test']) { + if (isset($params['is_test']) && $params['is_test']) { + $response[$project->getId()] = + $project->getResponse('TwingleProject ready to push to Twingle'); return civicrm_api3_create_success( - $project->getResponse('TwingleProject ready to push to Twingle'), + $response, $params, 'TwingleProject', 'Sync' @@ -346,7 +380,7 @@ function _pushProjectToTwingle(TwingleProject $project, // Push project to Twingle try { - $result = $twingleApi->pushProject($project); + $result = $twingleApi->pushProject($project->export()); } catch (Exception $e) { Civi::log()->error( E::LONG_NAME . @@ -361,46 +395,55 @@ function _pushProjectToTwingle(TwingleProject $project, } // Update local campaign with data returning from Twingle - if ($result) { - $project->update($result); - // Get embed data - try { - $project->setEmbedData( - $twingleApi->getProjectEmbedData($project->getProjectId()) - ); - // Create updated campaign - $project->create(TRUE); - $response = $project->getResponse('TwingleProject pushed to Twingle'); - return civicrm_api3_create_success( - $response, - $params, - 'TwingleProject', - 'Sync' - ); - } catch (Exception $e) { + if ($update) { + if ($result) { + $project->update($result); + try { + // Create updated campaign + $project->create(TRUE); + $response[$project->getId()] = + $project->getResponse('TwingleProject pushed to Twingle'); + return civicrm_api3_create_success( + $response, + $params, + 'TwingleProject', + 'Sync' + ); + } catch (Exception $e) { + Civi::log()->error( + E::LONG_NAME . + ' pushed TwingleProject to Twingle but local update failed: ' . + $e->getMessage(), + $project->getResponse() + ); + return civicrm_api3_create_error( + 'TwingleProject was pushed to Twingle but local update failed: ' . + $e->getMessage(), + $project->getResponse() + ); + } + } + // If the curl fails, the $result may be empty + else { Civi::log()->error( E::LONG_NAME . - ' pushed TwingleProject to Twingle but local update failed: ' . - $e->getMessage(), + ' could not push TwingleProject campaign', $project->getResponse() ); return civicrm_api3_create_error( - 'TwingleProject was pushed to Twingle but local update failed: ' . - $e->getMessage(), + "Could not push TwingleProject campaign", $project->getResponse() ); } } - // If the curl fails, the $result may be empty else { - Civi::log()->error( - E::LONG_NAME . - ' could not push TwingleProject campaign', - $project->getResponse() - ); - return civicrm_api3_create_error( - "Could not push TwingleProject campaign", - $project->getResponse() + $response[$project->getId()] = + $project->getResponse('TwingleProject pushed to Twingle'); + return civicrm_api3_create_success( + $response, + $params, + 'TwingleProject', + 'Sync' ); } } @@ -432,12 +475,24 @@ function _projectSync(TwingleProject $project, // If the CiviCRM TwingleProject campaign was changed, update the project // on Twingle's side elseif ($project_from_twingle['last_update'] < $project->lastUpdate()) { + // Make sure that the project hast a correct project_id. This is important + // to avoid an accidental cloning of project. + if (empty($project->getProjectId())) { + throw new \CiviCRM_API3_Exception( + 'Missing project_id for project that is meant to get updated on Twingle side.'); + } + + // By merging the project values with the values coming from Twingle, we + // make sure that the project contains all values needed to get pushed + $project->complement($project_from_twingle); + return _pushProjectToTwingle($project, $twingleApi, $params); } // If both versions are still synchronized else { - $response = $project->getResponse('TwingleProject up to date'); + $response[$project->getId()] = + $project->getResponse('TwingleProject up to date'); return civicrm_api3_create_success( $response, $params, diff --git a/docs/Twingle_Project.md b/docs/Twingle_Project.md new file mode 100644 index 0000000..c3a24ce --- /dev/null +++ b/docs/Twingle_Project.md @@ -0,0 +1,34 @@ +# Twingle Project + +This campaign type represents Twingle donation forms. *Twingle Projects* are campaigns which get synchronized between +Twingle and your CiviCRM instance in both directions. A *Twingle Project* has three extra sections: + +## Twingle Information + +This section shows the external Twingle id, the identifier and the project type (default, event or membership). You can +change the project type at any time, but please be aware that your Twingle donation forms will change their appearance +depending on what project type is selevted. + +## Twingle Settings + +Here you can find almost all settings to configure a donation form. Each setting has a help text. + +Currently, there is no front end input validation but all settings get validated on server side when the form gets +saved. If the validation fails, an error message will be displayed that contains further information. In this case, the +form won't get saved. + +## Twingle Payment Methods + +These settings allow you to specify the payment methods that you want to offer to users for one time and recurring +donations. + +Currently, the extension only supports to configure *PayPal*, *bank transfer*, *debit* and *Sofortüberweisung* as one +time payment methods and *PayPal* and *debit* as recurring payment methods. This may be enhanced in future versions. +Nevertheless, you can configure additional payment methods in the *[TwingleMANAGER](https://twinglemanager.de)* – they +won't get overwritten by the *Twingle Campaign* extension. + +Please make sure to establish all payment methods in your general *[TwingleMANAGER](https://twinglemanager.de)* settings +before you try to configure them for *Twingle Projects*. + +## Twingle Project Preview +![TwingleProject](../images/TwingleProject_settings.png) \ No newline at end of file diff --git a/images/TwingleProject_settings.png b/images/TwingleProject_settings.png new file mode 100644 index 0000000..4f97e50 Binary files /dev/null and b/images/TwingleProject_settings.png differ diff --git a/l10n/de_DE/LC_MESSAGES/twinglecampaign.mo b/l10n/de_DE/LC_MESSAGES/twinglecampaign.mo index f491d04..e4a39ee 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 086ae7b..7bfae67 100644 --- a/l10n/de_DE/LC_MESSAGES/twinglecampaign.po +++ b/l10n/de_DE/LC_MESSAGES/twinglecampaign.po @@ -12,6 +12,48 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Language: de_DE\n" +#: CRM/TwingleCampaign/BAO/CustomField.php +msgid "" +"Creation of custom field '%1' failed. Find more information in the logs." +msgstr "" +"Erstellung von Custom Field '%1' fehlgeschlagen. Mehr Informationen in den " +"Logs." + +#: CRM/TwingleCampaign/BAO/CustomField.php +msgid "Creation of custom field failed. Find more information in the logs." +msgstr "" +"Erstellung von Custom Field '%1' fehlgeschlagen. Mehr Informationen in den " +"Logs." + +#: CRM/TwingleCampaign/BAO/CustomField.php +msgid "" +"Creation of custom field '%1' failed, because a custom field with that name " +"already exists. Find more information in the logs." +msgstr "" +"Erstellung der Custom Field '%1' fehlgeschlagen, weil bereits eine Custom " +"Field mit selbem Namen existiert. Mehr Informationen in den Logs." + +#: CRM/TwingleCampaign/BAO/CustomGroup.php +msgid "" +"Creation of custom group '%1' failed. Find more information in the logs." +msgstr "" +"Erstellung von Custom Field '%1' fehlgeschlagen. Mehr Informationen in den " +"Logs." + +#: CRM/TwingleCampaign/BAO/CustomGroup.php +msgid "Creation of custom group failed. Find more information in the logs." +msgstr "" +"Erstellung von Custom Field '%1' fehlgeschlagen. Mehr Informationen in den " +"Logs." + +#: CRM/TwingleCampaign/BAO/CustomGroup.php +msgid "" +"Creation of custom group '%1' failed, because a custom group with that name " +"already exists. Find more information in the logs." +msgstr "" +"Erstellung der Custom Group '%1' fehlgeschlagen, weil bereits eine Custom " +"Group mit selbem Namen existiert. Mehr Informationen in den Logs." + #: CRM/TwingleCampaign/BAO/TwingleCampaign.php msgid "" "Could not determine parent TwingleProject URL. This URL is needed to create " @@ -36,6 +78,37 @@ msgstr "" msgid "No parent TwingleProject found" msgstr "Kein übergeordnetes TwingleProjekt gefunden" +#: CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "BCC email invalid" +msgstr "BCC-Email-Adresse ungültig" + +#: CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Invalid hexadecimal value in color field: %1" +msgstr "Ungültige Hexadezimalzahl in Farbfeld: %1" + +#: CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Missing maximum donation value" +msgstr "Maximale Spendenhöhe fehlt" + +#: CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Maximum donation value must be higher than the minimum" +msgstr "Die maximale Spendenhöhe muss höher als die minimale sein" + +#: CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Default donation value must lie in between maximum and minimum values" +msgstr "" +"Die voreingestellte Spendenhöhe muss zwischen Minimum und Maximum liegen" + +#: CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Donation values (Min, Max, Default) must be positive integers" +msgstr "" +"Die minimale, maximale und die voreingestellte Spendenhöhe müssen positive " +"Ganzzahlen sein" + +#: CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Invalid URL: %1" +msgstr "Ungültige URL: %1" + #: CRM/TwingleCampaign/Form/Settings.php api/v3/TwingleEvent/Delete.php #: api/v3/TwingleEvent/Sync.php api/v3/TwingleProject/Delete.php #: api/v3/TwingleProject/Sync.php api/v3/TwingleSync/Sync.php @@ -109,6 +182,664 @@ msgstr "" msgid "Could not disable scheduled job \"TwingleSync\"." msgstr "Geplante Aufgabe \"TwingleSync\" konnte nicht deaktiviert werden." +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Information" +msgstr "Twingle Informationen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Settings" +msgstr "Twingle Einstellungen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Payment Methods" +msgstr "Twingle Zahlungsarten" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Embed Codes" +msgstr "Twingle Embed Codes" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Event Information" +msgstr "Twingle Event Informationen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Campaign Information" +msgstr "Twingle Campaign Informationen" + +#: CRM/TwingleCampaign/resources/campaigns.php api/v3/TwingleEvent/Delete.php +#: api/v3/TwingleEvent/Get.php api/v3/TwingleEvent/Getsingle.php +#: api/v3/TwingleEvent/Sync.php api/v3/TwingleProject/Create.php +#: api/v3/TwingleProject/Delete.php api/v3/TwingleProject/Get.php +#: api/v3/TwingleProject/Getsingle.php api/v3/TwingleProject/Sync.php +msgid "Twingle Project ID" +msgstr "Twingle Project ID" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Organisation ID" +msgstr "Organisations ID" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "identifier" +msgstr "Kennung" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "An unique identifier for a project (auto generated)" +msgstr "Eindeutige Kennung eines Projekts (automatisch generiert)" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Type" +msgstr "Typ" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Default" +msgstr "Default" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Events" +msgstr "Events" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Membership" +msgstr "Mitgliedschaft" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "" +"Choose the project type. Allow users to create own events or to pay a " +"membership fee." +msgstr "" +"Wähle den Projekt-Typ: erlaube Benutzern ihre eigenen Spenden-Events " +"anzulegen oder eine Mitgliedschaft zu bezahlen." + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "allow more" +msgstr "Mehr zulassen" + +#: CRM/TwingleCampaign/resources/campaigns.php api/v3/TwingleProject/Create.php +#: api/v3/TwingleProject/Get.php api/v3/TwingleProject/Getsingle.php +msgid "Allow to donate more than is defined in the target" +msgstr "Zulassen, dass mehr gespendet wird als im Spendenziel angegeben ist" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "transaction type" +msgstr "Transaktionstyp" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "URL" +msgstr "URL" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Widget" +msgstr "Widget" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Form" +msgstr "Formular" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Widget Single" +msgstr "Einzelnes Widget" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Form Single" +msgstr "Formular Widget" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "All Events" +msgstr "Alle Events" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Event List" +msgstr "Event-Liste" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Counter" +msgstr "Zähler" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Page" +msgstr "Seite" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Confirmation Mail" +msgstr "Bestätigungsmail" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Send confirmation mail" +msgstr "Sende Bestätigungs-E-Mail" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Receipt" +msgstr "Spendenbescheinigung" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Offer donation receipts" +msgstr "Biete Spendenbescheinigungen an" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Contact Data" +msgstr "Kontaktdaten" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Rhythm" +msgstr "Spendenrhythmus" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "yearly" +msgstr "jährlich" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "halfyearly" +msgstr "halbjährlich" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "quarterly" +msgstr "vierteljährlich" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "monthly" +msgstr "monatlich" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "one time" +msgstr "einmalig" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "" +"The selected options are available for selection in the donation widget." +msgstr "Die ausgewählten Optionen stehen im Spenden-Widget zur Verfügung" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Default Rhythm" +msgstr "Standard Spendenrhythmus" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Which donation rhythm should be displayed as selected by default?" +msgstr "Welcher Spendenrhythmus soll standardmäßig ausgewählt sein?" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Newsletter Registration" +msgstr "Newsletter-Registrierung" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Enable newsletter registration" +msgstr "Registrierung für Newsletter aktivieren" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Postinfo Registration" +msgstr "Postinfo-Registrierung" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Enable post info registration" +msgstr "Registrierung für Postinfos aktivieren" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Background Color" +msgstr "Hintergrundfarbe" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Hex color code (e.g. ffffff for white)" +msgstr "Hex-Farbcode (z.B. ffffff für weiß)" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Primary Color" +msgstr "Primärfarbe" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Font Color" +msgstr "Schriftfarbe" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "BCC Email" +msgstr "BCC-E-Mail" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "" +"Email address used as bcc addresses for confirmation mail which is send to " +"an user" +msgstr "E-Mail-Adresse für den BBC beim Versenden der Bestätigungs-E-Mail" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Min" +msgstr "Spendenminimum" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Minimum donation value" +msgstr "Mindestspendenbetrag" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Max" +msgstr "Spendenmaximum" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Maximum donation value" +msgstr "Höchstspendenbetrag" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Default" +msgstr "Standardspendenhöhe" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Default donation value" +msgstr "Standardspendenbetrag" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Contact Fields" +msgstr "Kontaktfelder" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Salutation" +msgstr "Anrede" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "First name" +msgstr "Vorname" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Last name" +msgstr "Nachname" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Company" +msgstr "Firma" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Birthday" +msgstr "Geburtsdatum" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Street" +msgstr "Straße" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Postal Code" +msgstr "Postleitzahl" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "City" +msgstr "Stadt" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Country" +msgstr "Land" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Telephone" +msgstr "Telefon" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Fields to include in contact form" +msgstr "Felder für Kontaktformular" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Mandatory Contact Fields" +msgstr "Pflicht-Kontaktfelder" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Fields that must get filled in the contact form." +msgstr "Pflichtfelder für Kontaktformular" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Custom CSS" +msgstr "Benutzerdefiniertes CSS" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "URL to a custom CSS file that will be included in the frontend" +msgstr "" +"URL einer benutzerdefinierten CSS-Datei, die im Frontend eingebunden wird" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Share URL" +msgstr "Teilen-URL" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "URL for the sharing component on the last page and doi page" +msgstr "URL für Teilen-Elemente auf der letzten Seite und auf der DOI-Seite" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Contact Mandatory" +msgstr "Kontaktdaten sind Pflicht" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "If the contact data should be requested mandatory as second step" +msgstr "Die Kontaktdaten als Pflichtangaben im zweiten Schritt abfragen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Double Opt-In" +msgstr "Doppeltes Opt-In" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "" +"Enable Twingle's double opt-in (Do not enable, if you use CiviCRM's double " +"opt-in!)" +msgstr "" +"Tingles doppelten Opt-In aktivieren (Nicht aktivieren, wenn der doppelte Opt-" +"In von CiviCRM verwendet wird!)" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Force Donation Taget as Button" +msgstr "Spendenziel-Knopf erzwingen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Force showing the donation targets as buttons" +msgstr "Erzwingen der Anzeige der Spendenziele als Knöpfe" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Slider Icon" +msgstr "Icon für Schieberegler" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Heart" +msgstr "Herz" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Asterisk" +msgstr "Sternchen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Animal" +msgstr "Pfote" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Lifebelt" +msgstr "Rettungsring" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Angellist" +msgstr "Peace-Hand" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Handshake" +msgstr "Handschütteln" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Dollar" +msgstr "Dollar" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Menue" +msgstr "Menübalken" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Office" +msgstr "Büro" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Leaf" +msgstr "Blatt" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Cog" +msgstr "Zahnrad" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "SVG" +msgstr "SVG" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Euro" +msgstr "Euro" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Stats" +msgstr "Statistik" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Circle" +msgstr "Kreis" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Water drop outline" +msgstr "Wassertropfen (Umriss)" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Water drop" +msgstr "Wassertropfen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Gift" +msgstr "Geschenk" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Bee" +msgstr "Biene" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Flower" +msgstr "Blume" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Train" +msgstr "Zug" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "No Icon" +msgstr "Kein Icon" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Hidden Logo" +msgstr "Verstecktes Logo" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Hide the Logo on the project page" +msgstr "Verstecke das Logo auf der Projektseite" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Target Format" +msgstr "Spendenzielformat in Euro" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Format of the reached portion of the donation target" +msgstr "Format des Spendenstands" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Purpose as Textfield" +msgstr "Spendenzweck als Textfeld" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Let donors enter their own donation purpose" +msgstr "Erlaubt Spendern, ihre eigenen Spendenzwecke einzutragen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Activate CiviCRM Support" +msgstr "CiviCRM-Unterstützung aktivieren" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Activate support for Twingle Extension (de.systopia.twingle)" +msgstr "" +"Aktiviert die Unterstützung für die Twingle-Erweiterung (de.systopia.twingle)" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Show Step Index" +msgstr "Zeige Fortschrittsanzeige" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Show a step index during donation process" +msgstr "Fortschrittsanzeige beim Spendenprozess anzeigen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Languages" +msgstr "Sprachen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "German" +msgstr "Deutsch" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "English" +msgstr "Englisch" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "French" +msgstr "Französisch" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Spanish" +msgstr "Spanisch" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Buttons" +msgstr "Knöpfe" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "" +"Up to four buttons can be configured. If you leave the amount blank, the " +"button will not be displayed." +msgstr "" +"Bis zu vier Knöpfe können konfiguriert werden. Wenn Sie den Wert frei " +"lassen, wird der Knopf nicht angezeigt." + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Slider" +msgstr "Schieberegler" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Show a slider that allows the donor to choose the donation amount." +msgstr "" +"Zeige einen Schieberegler, der es dem Spender erlaubt, einen Betrag zu wählen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Button 1" +msgstr "Knopf 1" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Amount to be displayed on Button 1" +msgstr "Betrag der auf Knopf 1 angezeigt wird" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Button 2" +msgstr "Knopf 2" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Amount to be displayed on Button 2" +msgstr "Betrag der auf Knopf 2 angezeigt wird" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Button 3" +msgstr "Knopf 3" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Amount to be displayed on Button 3" +msgstr "Betrag der auf Knopf 3 angezeigt wird" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Button 4" +msgstr "Knopf 4" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Amount to be displayed on Button 4" +msgstr "Betrag der auf Knopf 4 angezeigt wird" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Newsletter Name Requested" +msgstr "Name für Newsletter abfragen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Must a donor give his name for newsletter sign-up?" +msgstr "" +"Muss ein Spender seinen Namen für die Newsletter-Registrierung angeben?" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Show List of Donations" +msgstr "Spendenliste anzeigen" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Display a list of public donations" +msgstr "Zeigt eine liste öffentlicher Spenden an" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Payment Methods" +msgstr "Zahlungsarten" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "PayPal" +msgstr "PayPal" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Banktransfer" +msgstr "Banküberweisung" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Debit" +msgstr "Bankeinzug" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Sofortüberweisung" +msgstr "Sofortüberweisung" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "" +"Chose which payment methods should be available. NOTE: You might have to " +"activate them first in the Twingle-Manager configuration." +msgstr "" +"Wählen Sie aus, welche Zahlungsarten verfügbar sein sollen. WICHTIG: Sie " +"müssen die Zahlungsarten eventuell erst im Twingle-Manager konfigurieren." + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Recurring Payment Methods" +msgstr "Wiederkehrende Zahlungsarten" + +#: CRM/TwingleCampaign/resources/campaigns.php api/v3/TwingleEvent/Delete.php +#: api/v3/TwingleEvent/Get.php api/v3/TwingleEvent/Getsingle.php +#: api/v3/TwingleEvent/Sync.php +msgid "Twingle Event ID" +msgstr "Twingle Event ID" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Identifier" +msgstr "Kennung" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Initiator" +msgstr "Initiator" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Initiator Email" +msgstr "Initiator E-Mail" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Is public" +msgstr "Ist öffentlich" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Deleted" +msgstr "Gelöscht" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Confirmed At" +msgstr "Bestätigt am" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Created At" +msgstr "Erstellt am" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Creation URL" +msgstr "Erstell-URL" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Internal URL" +msgstr "Interne URL" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "External URL" +msgstr "Externe URL" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Edit Internal URL" +msgstr "Interne Bearbeitungs-URL" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Edit External URL" +msgstr "Externe Bearbeitungs-URL" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "Parent TwingleProject ID" +msgstr "Twingle ID des Eltern-TwingleProject" + +#: CRM/TwingleCampaign/resources/campaigns.php +msgid "CID" +msgstr "CID" + #: api/v3/TwingleCampaign/Create.php api/v3/TwingleCampaign/Delete.php #: api/v3/TwingleCampaign/Get.php api/v3/TwingleCampaign/Getsingle.php #: api/v3/TwingleCampaign/Sync.php @@ -231,7 +962,7 @@ msgstr "Ist diese Kampagne aktiviert oder deaktiviert/abgesagt?" msgid "" "A unique identifier for a TwingleCampaign generated by a hashing its id + " "name" -msgstr "" +msgstr "Einmalige Kennung einer TwingleCampaign" #: api/v3/TwingleEvent/Delete.php api/v3/TwingleEvent/Get.php #: api/v3/TwingleEvent/Getsingle.php api/v3/TwingleEvent/Sync.php @@ -247,25 +978,12 @@ msgstr "Kampagnen ID" msgid "Unique Campaign ID" msgstr "Einzigartige Kampagnen ID" -#: api/v3/TwingleEvent/Delete.php api/v3/TwingleEvent/Get.php -#: api/v3/TwingleEvent/Getsingle.php api/v3/TwingleEvent/Sync.php -#: api/v3/TwingleProject/Create.php api/v3/TwingleProject/Delete.php -#: api/v3/TwingleProject/Get.php api/v3/TwingleProject/Getsingle.php -#: api/v3/TwingleProject/Sync.php -msgid "Twingle Project ID" -msgstr "Twingle Project ID" - #: api/v3/TwingleEvent/Delete.php api/v3/TwingleEvent/Sync.php #: api/v3/TwingleProject/Delete.php api/v3/TwingleProject/Get.php #: api/v3/TwingleProject/Getsingle.php api/v3/TwingleProject/Sync.php msgid "Twingle ID for this project" msgstr "Twingle ID dieses Projekts" -#: api/v3/TwingleEvent/Delete.php api/v3/TwingleEvent/Get.php -#: api/v3/TwingleEvent/Getsingle.php api/v3/TwingleEvent/Sync.php -msgid "Twingle Event ID" -msgstr "Twingle Event ID" - #: api/v3/TwingleEvent/Delete.php api/v3/TwingleEvent/Get.php #: api/v3/TwingleEvent/Getsingle.php api/v3/TwingleEvent/Sync.php msgid "Twingle ID for this Event" @@ -380,11 +1098,6 @@ msgstr "Typ des Twingle Projects" msgid "Allow more" msgstr "Mehr zulassen" -#: api/v3/TwingleProject/Create.php api/v3/TwingleProject/Get.php -#: api/v3/TwingleProject/Getsingle.php -msgid "Allow to donate more than is defined in the target" -msgstr "Zulassen, dass mehr gespendet wird als im Spendenziel angegeben ist" - #: api/v3/TwingleProject/Create.php msgid "Project Target" msgstr "Spendenziel" @@ -416,3 +1129,31 @@ msgstr "Allgemeine Einstellungen" #: templates/CRM/TwingleCampaign/Form/Settings.tpl msgid "Twingle Event Settings" msgstr "Twingle Event Einstellungen" + +#: twinglecampaign.php +msgid "Campaign cloning failed" +msgstr "Klonen der Kampagne fehlgeschlagen" + +#: twinglecampaign.php +msgid "TwingleCampaign update failed" +msgstr "TwingleCampaign-Update fehlgeschlagen" + +#: twinglecampaign.php +msgid "TwingleCampaign was saved." +msgstr "TwingleCampaign wurde gespeichert" + +#: twinglecampaign.php +msgid "TwingleProject creation failed" +msgstr "Erstellung des TwingleProjects fehlgeschlagen" + +#: twinglecampaign.php +msgid "Could not retrieve Twingle API key" +msgstr "Twingle-API-Schlüssel nicht gefunden" + +#: twinglecampaign.php +msgid "TwingleProject synchronization failed: %1" +msgstr "Synchronisation des TwingleProjects fehlgeschlagen: %1" + +#: twinglecampaign.php +msgid "Input validation failed" +msgstr "Eingabeüberprüfung fehlgeschlagen" diff --git a/l10n/pot/twinglecampaign.pot b/l10n/pot/twinglecampaign.pot index 6e8e0c0..0516610 100644 --- a/l10n/pot/twinglecampaign.pot +++ b/l10n/pot/twinglecampaign.pot @@ -1,3 +1,27 @@ +#: ./CRM/TwingleCampaign/BAO/CustomField.php +msgid "Creation of custom field '%1' failed. Find more information in the logs." +msgstr "" + +#: ./CRM/TwingleCampaign/BAO/CustomField.php +msgid "Creation of custom field failed. Find more information in the logs." +msgstr "" + +#: ./CRM/TwingleCampaign/BAO/CustomField.php +msgid "Creation of custom field '%1' failed, because a custom field with that name already exists. Find more information in the logs." +msgstr "" + +#: ./CRM/TwingleCampaign/BAO/CustomGroup.php +msgid "Creation of custom group '%1' failed. Find more information in the logs." +msgstr "" + +#: ./CRM/TwingleCampaign/BAO/CustomGroup.php +msgid "Creation of custom group failed. Find more information in the logs." +msgstr "" + +#: ./CRM/TwingleCampaign/BAO/CustomGroup.php +msgid "Creation of custom group '%1' failed, because a custom group with that name already exists. Find more information in the logs." +msgstr "" + #: ./CRM/TwingleCampaign/BAO/TwingleCampaign.php msgid "Could not determine parent TwingleProject URL. This URL is needed to create the TwingleEvent URL. Please check the logs." msgstr "" @@ -14,6 +38,34 @@ msgstr "" msgid "No parent TwingleProject found" msgstr "" +#: ./CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "BCC email invalid" +msgstr "" + +#: ./CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Invalid hexadecimal value in color field: %1" +msgstr "" + +#: ./CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Missing maximum donation value" +msgstr "" + +#: ./CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Maximum donation value must be higher than the minimum" +msgstr "" + +#: ./CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Default donation value must lie in between maximum and minimum values" +msgstr "" + +#: ./CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Donation values (Min, Max, Default) must be positive integers" +msgstr "" + +#: ./CRM/TwingleCampaign/BAO/TwingleProject.php +msgid "Invalid URL: %1" +msgstr "" + #: ./CRM/TwingleCampaign/Form/Settings.php ./api/v3/TwingleEvent/Delete.php ./api/v3/TwingleEvent/Sync.php ./api/v3/TwingleProject/Delete.php ./api/v3/TwingleProject/Sync.php ./api/v3/TwingleSync/Sync.php msgid "Twingle API key" msgstr "" @@ -74,6 +126,634 @@ msgstr "" msgid "Could not disable scheduled job \"TwingleSync\"." msgstr "" +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Information" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Settings" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Payment Methods" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Embed Codes" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Event Information" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Twingle Campaign Information" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php ./api/v3/TwingleEvent/Delete.php ./api/v3/TwingleEvent/Get.php ./api/v3/TwingleEvent/Getsingle.php ./api/v3/TwingleEvent/Sync.php ./api/v3/TwingleProject/Create.php ./api/v3/TwingleProject/Delete.php ./api/v3/TwingleProject/Get.php ./api/v3/TwingleProject/Getsingle.php ./api/v3/TwingleProject/Sync.php +msgid "Twingle Project ID" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Organisation ID" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "identifier" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "An unique identifier for a project (auto generated)" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Type" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Default" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Events" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Membership" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Choose the project type. Allow users to create own events or to pay a membership fee." +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "allow more" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php ./api/v3/TwingleProject/Create.php ./api/v3/TwingleProject/Get.php ./api/v3/TwingleProject/Getsingle.php +msgid "Allow to donate more than is defined in the target" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "transaction type" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "URL" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Widget" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Form" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Widget Single" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Form Single" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "All Events" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Event List" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Counter" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Page" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Confirmation Mail" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Send confirmation mail" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Receipt" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Offer donation receipts" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Contact Data" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Rhythm" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "yearly" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "halfyearly" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "quarterly" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "monthly" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "one time" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "The selected options are available for selection in the donation widget." +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Default Rhythm" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Which donation rhythm should be displayed as selected by default?" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Newsletter Registration" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Enable newsletter registration" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Postinfo Registration" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Enable post info registration" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Background Color" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Hex color code (e.g. ffffff for white)" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Primary Color" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Font Color" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "BCC Email" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Email address used as bcc addresses for confirmation mail which is send to an user" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Min" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Minimum donation value" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Max" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Maximum donation value" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Default" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Default donation value" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Contact Fields" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Salutation" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "First name" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Last name" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Company" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Birthday" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Street" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Postal Code" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "City" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Country" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Telephone" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Fields to include in contact form" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Mandatory Contact Fields" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Fields that must get filled in the contact form." +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Custom CSS" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "URL to a custom CSS file that will be included in the frontend" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Share URL" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "URL for the sharing component on the last page and doi page" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Contact Mandatory" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "If the contact data should be requested mandatory as second step" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Double Opt-In" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Enable Twingle's double opt-in (Do not enable, if you use CiviCRM's double opt-in!)" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Force Donation Taget as Button" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Force showing the donation targets as buttons" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Slider Icon" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Heart" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Asterisk" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Animal" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Lifebelt" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Angellist" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Handshake" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Dollar" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Menue" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Office" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Leaf" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Cog" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "SVG" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Euro" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Stats" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Circle" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Water drop outline" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Water drop" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Gift" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Bee" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Flower" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Train" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "No Icon" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Hidden Logo" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Hide the Logo on the project page" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Target Format" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Format of the reached portion of the donation target" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Donation Purpose as Textfield" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Let donors enter their own donation purpose" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Activate CiviCRM Support" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Activate support for Twingle Extension (de.systopia.twingle)" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Show Step Index" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Show a step index during donation process" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Languages" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "German" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "English" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "French" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Spanish" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Buttons" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Up to four buttons can be configured. If you leave the amount blank, the button will not be displayed." +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Slider" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Show a slider that allows the donor to choose the donation amount." +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Button 1" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Amount to be displayed on Button 1" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Button 2" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Amount to be displayed on Button 2" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Button 3" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Amount to be displayed on Button 3" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Button 4" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Amount to be displayed on Button 4" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Newsletter Name Requested" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Must a donor give his name for newsletter sign-up?" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Show List of Donations" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Display a list of public donations" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Payment Methods" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "PayPal" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Banktransfer" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Debit" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Sofortüberweisung" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Chose which payment methods should be available. NOTE: You might have to activate them first in the Twingle-Manager configuration." +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Recurring Payment Methods" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php ./api/v3/TwingleEvent/Delete.php ./api/v3/TwingleEvent/Get.php ./api/v3/TwingleEvent/Getsingle.php ./api/v3/TwingleEvent/Sync.php +msgid "Twingle Event ID" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Identifier" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Initiator" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Initiator Email" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Is public" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Deleted" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Confirmed At" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Created At" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Creation URL" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Internal URL" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "External URL" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Edit Internal URL" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Edit External URL" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "Parent TwingleProject ID" +msgstr "" + +#: ./CRM/TwingleCampaign/resources/campaigns.php +msgid "CID" +msgstr "" + #: ./api/v3/TwingleCampaign/Create.php ./api/v3/TwingleCampaign/Delete.php ./api/v3/TwingleCampaign/Get.php ./api/v3/TwingleCampaign/Getsingle.php ./api/v3/TwingleCampaign/Sync.php msgid "Twingle Campaign ID" msgstr "" @@ -178,18 +858,10 @@ msgstr "" msgid "Unique Campaign ID" msgstr "" -#: ./api/v3/TwingleEvent/Delete.php ./api/v3/TwingleEvent/Get.php ./api/v3/TwingleEvent/Getsingle.php ./api/v3/TwingleEvent/Sync.php ./api/v3/TwingleProject/Create.php ./api/v3/TwingleProject/Delete.php ./api/v3/TwingleProject/Get.php ./api/v3/TwingleProject/Getsingle.php ./api/v3/TwingleProject/Sync.php -msgid "Twingle Project ID" -msgstr "" - #: ./api/v3/TwingleEvent/Delete.php ./api/v3/TwingleEvent/Sync.php ./api/v3/TwingleProject/Delete.php ./api/v3/TwingleProject/Get.php ./api/v3/TwingleProject/Getsingle.php ./api/v3/TwingleProject/Sync.php msgid "Twingle ID for this project" msgstr "" -#: ./api/v3/TwingleEvent/Delete.php ./api/v3/TwingleEvent/Get.php ./api/v3/TwingleEvent/Getsingle.php ./api/v3/TwingleEvent/Sync.php -msgid "Twingle Event ID" -msgstr "" - #: ./api/v3/TwingleEvent/Delete.php ./api/v3/TwingleEvent/Get.php ./api/v3/TwingleEvent/Getsingle.php ./api/v3/TwingleEvent/Sync.php msgid "Twingle ID for this Event" msgstr "" @@ -286,10 +958,6 @@ msgstr "" msgid "Allow more" msgstr "" -#: ./api/v3/TwingleProject/Create.php ./api/v3/TwingleProject/Get.php ./api/v3/TwingleProject/Getsingle.php -msgid "Allow to donate more than is defined in the target" -msgstr "" - #: ./api/v3/TwingleProject/Create.php msgid "Project Target" msgstr "" @@ -322,3 +990,31 @@ msgstr "" msgid "Twingle Event Settings" msgstr "" +#: ./twinglecampaign.php +msgid "Campaign cloning failed" +msgstr "" + +#: ./twinglecampaign.php +msgid "TwingleCampaign update failed" +msgstr "" + +#: ./twinglecampaign.php +msgid "TwingleCampaign was saved." +msgstr "" + +#: ./twinglecampaign.php +msgid "TwingleProject creation failed" +msgstr "" + +#: ./twinglecampaign.php +msgid "Could not retrieve Twingle API key" +msgstr "" + +#: ./twinglecampaign.php +msgid "TwingleProject synchronization failed: %1" +msgstr "" + +#: ./twinglecampaign.php +msgid "Input validation failed" +msgstr "" + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 0f9f25d..af5fa8c 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ - + - + ./tests/phpunit diff --git a/tests/phpunit/CRM/TwingleCampaign/BAO/TwingleProjectTest.php b/tests/phpunit/CRM/TwingleCampaign/BAO/TwingleProjectTest.php new file mode 100644 index 0000000..bf82a4b --- /dev/null +++ b/tests/phpunit/CRM/TwingleCampaign/BAO/TwingleProjectTest.php @@ -0,0 +1,142 @@ +installMe(__DIR__) + ->apply(); + } + + /** + * @throws \Exception + */ + public function setUp() { + + // Create project from dummy values + $this->dummyProject = + require(E::path() . '/tests/resources/twingle_project_dummy.php'); + $this->badDummyProject = + require(E::path() . '/tests/resources/twingle_project_bad_dummy.php'); + $this->project = new TwingleProject($this->dummyProject); + $this->project->create(TRUE); + + parent::setUp(); + } + + /** + * @throws \CiviCRM_API3_Exception + */ + public function tearDown() { + + // Delete project + $this->project->delete(); + unset($this->project); + + parent::tearDown(); + } + + /** + * ## The full TwingleProject circle + * This test simulates a TwingleProject that is fetched from the database and + * than gets instantiated and sent back to Twingle. + * + * It is important that all project values sent to the Twingle API have the + * same data types like when they were retrieved from Twingle. To test this, + * the export array will be compared to the original dummy array. + * + * dummy:array -> project:object -> database -> project:object -> export:array + * + * @throws \CiviCRM_API3_Exception + * @throws \Exception + */ + public function testFullTwingleProjectCircle() { + + // Get project via API from database + $project = civicrm_api3( + 'TwingleProject', + 'getsingle', + ['id' => $this->project->getId()]); + $project = new TwingleProject($project, $project['id']); + + // Complement project values with dummy values. This is important because + // not all values coming from the Twingle API are stored in the database, + // but the Twingle API requires that all parameters are set. + $project->complement($this->dummyProject); + + // Export project + $export = $project->export(); + + // Check if the project is sent to Twingle in the same state it arrived + $this->assertEquals( + $this->dummyProject, + $export, + 'Export values differ from import values.' + ); + } + + /** + * ## Input validation + * Checks if the input validation works properly. + * + * @throws \CiviCRM_API3_Exception + * @throws \Exception + */ + public function testInputValidation() { + + // Get project via API from database + $project = civicrm_api3( + 'TwingleProject', + 'getsingle', + ['id' => $this->project->getId()]); + $project = new TwingleProject($project, $project['id']); + + // Check if validation successes with healthy input + $validation_success = $project->validate(); + $this->assertTrue( + $validation_success['valid'], + 'Validation failed with healthy inputs.' + ); + + // Update project with values which simulate incorrect user input + $project->update($this->badDummyProject); + + // Run validation again + $validation_fail = $project->validate(); + + // Check if validation failed (as it should) + $this->assertFalse( + $validation_fail['valid'], + 'Validation did not fail as expected.' + ); + + // Check if all 6 wrong inputs were found + $this->assertCount( + 6, $validation_fail['messages'], + 'Did not find all 6 wrong inputs.' + ); + } +} + diff --git a/tests/resources/twingle_project_bad_dummy.php b/tests/resources/twingle_project_bad_dummy.php new file mode 100644 index 0000000..a6aeda6 --- /dev/null +++ b/tests/resources/twingle_project_bad_dummy.php @@ -0,0 +1,136 @@ + 2243, + "internal_id" => NULL, + "name" => "TestProject", + "organisation_id" => 555, + "slug" => "test_project", + "identifier" => "tw5555555555555", + "type" => "event", + "transaction_type" => NULL, + "project_target" => 1000, + "image_directory" => NULL, + "allow_more" => FALSE, + "last_update" => 1614166801, + "embed" => [ + "page" => "https://spenden.twingle.de/my-awesome-ngo/testprojekt/tw555555a555555c/page", + "eventpage" => "https://my-awesome-ngo/event/testprojekt/tw555555a555555c/edit", + "widget" => "", + "form" => "", + "widget-single" => "", + "form-single" => "", + "eventall" => "", + "eventlist" => "", + "eventeditcreate" => "", + "giftdonationexample" => "https://spenden.twingle.de/gift/my-awesome-ngo/tw555555a555555c/example", + "letterexample" => "https://spenden.twingle.de/letter/my-awesome-ngo/tw555555a555555c/example", + ], + "counter-url" => [ + "url" => "https://donationstatus.twingle.de/donation-status/555aaa", + ], + "host" => "https://spenden.twingle.de/", + "project_options" => [ + "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" => TRUE, + "monthly" => TRUE, + "one_time" => TRUE, + ], + "default_rhythm" => "", + "has_newsletter_registration" => FALSE, + "has_postinfo_registration" => FALSE, + "design_background_color" => "not_a_hex", // not a hex + "design_primary_color" => "green", // no hex either + "design_font" => "", + "design_font_color" => "true", // no hex either + "design_button_font_color" => "", + "design_button_font_color_light" => "", + "image" => "", + "bcc_email_address" => "mustermann@awesome", // no valid email + "donation_value_min" => 50, // higher than max + "donation_value_max" => 10, + "donation_value_default" => 30, // higher than max, lower than min + "exclude_contact_fields" => "company,birthday,telephone", + "mandatory_contact_fields" => "firstname,lastname", + "custom_js" => NULL, + "custom_css" => "", + "share_url" => "not_a_url", // no valid url + "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, + "app_js" => NULL, + "slidericon" => "handshake", + "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, + "cleverreach_group_id" => NULL, + "cleverreach_form_id" => NULL, + "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" => "5", + ], + "button2" => [ + "amount" => "50", + ], + "button3" => [ + "amount" => "100", + ], + "button4" => [ + "amount" => "", + ], + ], + "has_newsletter_namerequest" => FALSE, + "has_show_donator_data" => FALSE, + "has_donation_letter" => FALSE, + "has_donation_letter_api" => FALSE, + "amount_images" => [], + "video_url" => NULL, + ], + "payment_methods" => [ + "has_paypal" => TRUE, + "has_betterpayment" => FALSE, + "has_sixpay" => FALSE, + "has_banktransfer" => TRUE, + "has_debit" => TRUE, + "has_sofortueberweisung" => FALSE, + "has_betterpayment_creditcard" => FALSE, + "has_mbe4" => FALSE, + "has_generic" => FALSE, + "has_konfipay" => FALSE, + "has_konfipay_recurring" => FALSE, + "has_betterpayment_creditcard_recurring" => FALSE, + "has_paypal_recurring" => FALSE, + "has_debit_recurring" => TRUE, + "has_generic_recurring" => FALSE, + "has_sixpay_recurring" => FALSE, + "has_apple_pay" => FALSE, + "has_apple_pay_recurring" => FALSE, + "has_paydirekt" => FALSE, + "has_paydirekt_recurring" => FALSE, + ], +]; + diff --git a/tests/resources/twingle_project_dummy.php b/tests/resources/twingle_project_dummy.php new file mode 100644 index 0000000..760f52b --- /dev/null +++ b/tests/resources/twingle_project_dummy.php @@ -0,0 +1,137 @@ + 2243, + "internal_id" => NULL, + "name" => "TestProject", + "organisation_id" => 555, + "slug" => "test_project", + "identifier" => "tw5555555555555", + "type" => "event", + "transaction_type" => NULL, + "project_target" => 1000, + "image_directory" => NULL, + "allow_more" => FALSE, + "last_update" => 1614166801, + "embed" => [ + "page" => "https://spenden.twingle.de/my-awesome-ngo/testprojekt/tw555555a555555c/page", + "eventpage" => "https://my-awesome-ngo/event/testprojekt/tw555555a555555c/edit", + "widget" => "", + "form" => "", + "widget-single" => "", + "form-single" => "", + "eventall" => "", + "eventlist" => "", + "eventeditcreate" => "", + "giftdonationexample" => "https://spenden.twingle.de/gift/my-awesome-ngo/tw555555a555555c/example", + "letterexample" => "https://spenden.twingle.de/letter/my-awesome-ngo/tw555555a555555c/example", + ], + "counter-url" => [ + "url" => "https://donationstatus.twingle.de/donation-status/555aaa", + ], + "host" => "https://spenden.twingle.de/", + "project_options" => [ + "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" => TRUE, + "monthly" => TRUE, + "one_time" => TRUE, + ], + "default_rhythm" => "", + "has_newsletter_registration" => FALSE, + "has_postinfo_registration" => FALSE, + "design_background_color" => "ffffff", + "design_primary_color" => "102045", + "design_font" => "", + "design_font_color" => "102045", + "design_button_font_color" => "", + "design_button_font_color_light" => "", + "image" => "", + "bcc_email_address" => "mustermann@awesome-ngo.org", + "donation_value_min" => 5, + "donation_value_max" => 1000, + "donation_value_default" => 50, + "exclude_contact_fields" => "company,birthday,telephone", + "mandatory_contact_fields" => "firstname,lastname", + "custom_js" => NULL, + "custom_css" => "https://awesome-ngo.org/css", + "share_url" => "https://awesome-ngo.org/donate", + "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, + "app_js" => NULL, + "slidericon" => "handshake", + "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, + "cleverreach_group_id" => NULL, + "cleverreach_form_id" => NULL, + "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" => "5", + ], + "button2" => [ + "amount" => "50", + ], + "button3" => [ + "amount" => "100", + ], + "button4" => [ + "amount" => "", + ], + ], + "has_newsletter_namerequest" => FALSE, + "has_show_donator_data" => FALSE, + "has_donation_letter" => FALSE, + "has_donation_letter_api" => FALSE, + "amount_images" => [], + "video_url" => NULL, + ], + "payment_methods" => [ + "has_paypal" => TRUE, + "has_betterpayment" => FALSE, + "has_sixpay" => FALSE, + "has_banktransfer" => TRUE, + "has_debit" => TRUE, + "has_sofortueberweisung" => FALSE, + "has_betterpayment_creditcard" => FALSE, + "has_mbe4" => FALSE, + "has_generic" => FALSE, + "has_konfipay" => FALSE, + "has_konfipay_recurring" => FALSE, + "has_betterpayment_creditcard_recurring" => FALSE, + "has_paypal_recurring" => FALSE, + "has_debit_recurring" => TRUE, + "has_generic_recurring" => FALSE, + "has_sixpay_recurring" => FALSE, + "has_apple_pay" => FALSE, + "has_apple_pay_recurring" => FALSE, + "has_paydirekt" => FALSE, + "has_paydirekt_recurring" => FALSE, + ], +]; + diff --git a/twinglecampaign.php b/twinglecampaign.php index 72558e1..e210c34 100644 --- a/twinglecampaign.php +++ b/twinglecampaign.php @@ -1,6 +1,8 @@ id, $dao->campaign_type_id] - ); + + if (_validateAndSendInput($dao->id, $dao->campaign_type_id)) { + + CRM_Core_Transaction::addCallback( + CRM_Core_Transaction::PHASE_POST_COMMIT, + 'twinglecampaign_postSave_campaign_update_callback', + [$dao->id, $dao->campaign_type_id] + ); + } } + // If the transaction is already finished, call the function directly else { - twinglecampaign_postSave_campaign_callback($dao->id, $dao->campaign_type_id); + twinglecampaign_postSave_campaign_update_callback($dao->id, $dao->campaign_type_id); } } @@ -89,21 +97,13 @@ function twinglecampaign_civicrm_postSave_civicrm_campaign($dao) { * * @throws \CiviCRM_API3_Exception */ -function twinglecampaign_postSave_campaign_callback ( +function twinglecampaign_postSave_campaign_update_callback( int $campaign_id, int $campaign_type_id ) { - // Get campaign type id for TwingleProject - $twingle_project_campaign_type_id = - ExtensionCache::getInstance() - ->getCampaigns()['campaign_types']['twingle_project']['id']; - - // Get campaign type id for TwingleCampaign - $twingle_campaign_campaign_type_id = - ExtensionCache::getInstance() - ->getCampaigns()['campaign_types']['twingle_campaign']['id']; - + $twingle_project_campaign_type_id = _get_campaign_type_id_twingle_project(); + $twingle_campaign_campaign_type_id = _get_campaign_type_id_twingle_campaign(); // If $campaign_type_id is a TwingleProject or TwingleCampaign campaign, // synchronize it @@ -121,15 +121,14 @@ function twinglecampaign_postSave_campaign_callback ( } if (isset($_POST['action'])) { - if ($_POST['action'] == 'clone') { + if ($_POST['action'] == 'clone' && $entity == 'TwingleProject') { unset($_POST['action']); - $result = civicrm_api3($entity, 'getsingle', + $result = civicrm_api3('TwingleProject', 'getsingle', ['id' => $campaign_id] - )['values'][$campaign_id]; - $className = 'CRM_TwingleCampaign_BAO_' . $entity; + ); $id = $result['id']; unset($result['id']); - $project = new $className($result, $id); + $project = new TwingleProject($result, $id); try { $project->clone(); } catch (Exception $e) { @@ -137,51 +136,42 @@ function twinglecampaign_postSave_campaign_callback ( E::LONG_NAME . ' could not clone ' . $entity . ': ' . $e->getMessage() ); - CRM_Utils_System::setUFMessage($entity . ' could not get cloned.'); - } - } - elseif ($entity == 'TwingleProject') { - try { - civicrm_api3('TwingleProject', 'sync', ['id' => $campaign_id]); - CRM_Utils_System::setUFMessage('TwingleProject was saved.'); - } catch (CiviCRM_API3_Exception $e) { - Civi::log()->error( - 'twinglecampaign_postSave_callback ' . $e->getMessage() - ); - } - } - else { - try { - civicrm_api3('TwingleCampaign', 'create', ['id' => $campaign_id]); - CRM_Utils_System::setUFMessage('TwingleCampaign was saved.'); - } catch (CiviCRM_API3_Exception $e) { - Civi::log()->error( - 'twinglecampaign_postSave_callback ' . $e->getMessage() + CRM_Core_Session::setStatus( + $e->getMessage(), + E::ts("Campaign cloning failed"), + error, + [unique => TRUE] ); } } } + + // If a TwingleProject is getting saved elseif ($entity == 'TwingleProject') { - // Also synchronize all child TwingleCampaign campaigns + + // Synchronize all child TwingleCampaign campaigns try { - civicrm_api3('TwingleCampaign', 'sync', ['project_id' => $campaign_id]); + civicrm_api3( + 'TwingleCampaign', + 'sync', + ['parent_id' => $campaign_id]); } catch (CiviCRM_API3_Exception $e) { + CRM_Core_Session::setStatus( + $e->getMessage(), + E::ts("TwingleCampaign update failed"), + error, [unique => TRUE] + ); Civi::log()->error( - 'twinglecampaign_postSave_callback ' . $e->getMessage() + E::SHORT_NAME . + ' Update of TwingleCampaigns failed: ' . $e->getMessage() ); } + } + else { try { - civicrm_api3('TwingleProject', 'sync', ['id' => $campaign_id]); - CRM_Utils_System::setUFMessage('TwingleProject was saved.'); - } catch (CiviCRM_API3_Exception $e) { - Civi::log()->error( - 'twinglecampaign_postSave_callback ' . $e->getMessage() - ); - } - } else { - try { - civicrm_api3('TwingleCampaign', 'create', ['id' => $campaign_id]); - CRM_Utils_System::setUFMessage('TwingleCampaign was saved.'); + civicrm_api3('TwingleCampaign', 'create', + ['id' => $campaign_id, 'parent_id' => $_POST['parent_id']]); + CRM_Utils_System::setUFMessage(E::ts('TwingleCampaign was saved.')); } catch (CiviCRM_API3_Exception $e) { Civi::log()->error( 'twinglecampaign_postSave_callback ' . $e->getMessage() @@ -191,6 +181,189 @@ function twinglecampaign_postSave_campaign_callback ( } } +function _get_campaign_type_id_twingle_project() { + return ExtensionCache::getInstance() + ->getCampaignIds()['campaign_types']['twingle_project']['id']; +} + +function _get_campaign_type_id_twingle_campaign() { + return ExtensionCache::getInstance() + ->getCampaignIds()['campaign_types']['twingle_campaign']['id']; +} + +/** + * Callback to sync a project after its creation. + * @param int $campaign_id + */ +function twinglecampaign_postSave_project_create_callback( + int $campaign_id +) { + try { + civicrm_api3( + 'TwingleProject', + 'sync', + ['id' => $campaign_id]); + } catch (Exception $e) { + CRM_Core_Session::setStatus( + $e->getMessage(), + E::ts("TwingleProject creation failed"), + error, [unique => TRUE] + ); + Civi::log()->error( + E::SHORT_NAME . + ' Update of TwingleProject creation failed: ' . $e->getMessage() + ); + } +} + +/** + * First validate and then sends the input of this transaction to Twinge. + * If the call to the Twingle API succeeded, this function returns TRUE; + * + * @param $id + * @param $campaign_type_id + * + * @return bool + * @throws \CiviCRM_API3_Exception + */ +function _validateAndSendInput($id, $campaign_type_id): bool { + + // Set callback for cloning + if (isset($_POST['action'])) { + CRM_Core_Transaction::addCallback( + CRM_Core_Transaction::PHASE_POST_COMMIT, + 'twinglecampaign_postSave_campaign_update_callback', + [$id, $campaign_type_id] + ); + return FALSE; + } + + if ($campaign_type_id == _get_campaign_type_id_twingle_project()) { + + // Instantiate project + $project = new TwingleProject(); + + // Translate custom fields from $_POST + $customFields = []; + $customFieldsKeys = preg_grep('/^custom_/', array_keys($_POST)); + foreach ($customFieldsKeys as $key) { + $customFields[preg_replace('/_-?\d*$/', '', $key)] = + $_POST[$key]; + } + $project->translateCustomFields( + $customFields, + TwingleProject::OUT + ); + TwingleProject::formatValues($customFields, TwingleProject::OUT); + + // Update project + $project->update($customFields); + + // Validate project values + $validation = $project->validate(); + + // If the input is valid, send it to Twingle + if ($validation['valid']) { + + // Try to retrieve twingleApi from cache or create a new + $twingleApi = Civi::cache()->get('twinglecampaign_twingle_api'); + if (NULL === $twingleApi) { + try { + $twingleApi = + new TwingleApiCall(Civi::settings()->get('twingle_api_key')); + } catch (Exception $e) { + + // Roll back transaction if input validation failed + CRM_Core_Transaction::rollbackIfFalse(FALSE); + + CRM_Core_Session::setStatus( + $e->getMessage(), + E::ts("Could not retrieve Twingle API key"), + error, + [unique => TRUE] + ); + Civi::log()->error( + E::SHORT_NAME . + ' Could not retrieve Twingle API key: ' . $e->getMessage() + ); + } + Civi::cache('long')->set('twinglecampaign_twingle_api', $twingleApi); + } + + try { + // Complement project values with values from Twingle if it has a + // project_id + if ($project->getProjectId()) { + $project_from_twingle = $twingleApi->getProject($project->getProjectId()); + $project->complement($project_from_twingle); + } + // If this campaign is just about to become created, add a callback to + // sync it after the transaction has finished + else { + CRM_Core_Transaction::addCallback( + CRM_Core_Transaction::PHASE_POST_COMMIT, + 'twinglecampaign_postSave_project_create_callback', [$id] + ); + return FALSE; + } + + // Push project + require E::path() . '/api/v3/TwingleProject/Sync.php'; + $result = _pushProjectToTwingle($project, $twingleApi, [], FALSE); + if ($result['is_error'] != 0) { + throw new \CiviCRM_API3_Exception($result['error_message']); + } + } catch (Exception $e) { + + // Roll back transaction if input validation failed + CRM_Core_Transaction::rollbackIfFalse(FALSE); + + // Display and log error message + CRM_Core_Session::setStatus( + $e->getMessage(), + E::ts("TwingleProject synchronization failed: %1", + [1 => $e->getMessage()]), + error, + [unique => TRUE] + ); + Civi::log()->error( + E::SHORT_NAME . + ' TwingleProject synchronization failed: ' . $e->getMessage() + ); + // Push failed + return FALSE; + } + // Push succeeded + return TRUE; + } + // Display error message if validation failed + else { + + // Roll back transaction if input validation failed + CRM_Core_Transaction::rollbackIfFalse(FALSE); + + // Build error message + $errorMessage = ''; + + CRM_Core_Session::setStatus( + $errorMessage, + E::ts("Input validation failed"), + error, + [unique => TRUE] + ); + // Validation failed + return FALSE; + } + } + + // TwingleCampaigns always return TRUE; + return TRUE; +} + ///** // * ## Implements hook_civicrm_post().