Only in ./: .DS_Store diff -urp /Users/openbook/Downloads/opensource/drupal/modules/d6/salesforce/salesforce_api/salesforce_api.admin.inc ./salesforce_api/salesforce_api.admin.inc --- /Users/openbook/Downloads/opensource/drupal/modules/d6/salesforce/salesforce_api/salesforce_api.admin.inc 2009-07-31 09:04:05.000000000 +0100 +++ ./salesforce_api/salesforce_api.admin.inc 2009-09-16 15:57:15.000000000 +0100 @@ -70,7 +70,30 @@ function salesforce_api_settings_form() ), '#default_value' => variable_get('salesforce_api_error_log', SALESFORCE_LOG_ALL), ); - + $form['objects'] = array( + '#type' => 'fieldset', + '#title' => t('Object settings'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + '#weight' => -9, + ); + $form['objects']['clear_cache'] = array( + '#type' => 'item', + '#value' => t('Caching data improves performance, however your Drupal site will be unaware of any alterations made to your Salesforce installation unless the cached data is refreshed. Select the lifetime the object data after which the cache will be automatically refreshed. To refresh all cached object data on your site, click the button below.'), + ); + $period = drupal_map_assoc(array(32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval'); + $period[CACHE_PERMANENT] = t(''); + $form['objects']['salesforce_api_object_expire'] = array( + '#type' => 'select', + '#title' => t('Cache lifetime'), + '#options' => $period, + '#default_value' => variable_get('salesforce_api_object_expire', CACHE_PERMANENT), + ); + $form['objects']['clear_cache_clear'] = array( + '#type' => 'submit', + '#value' => t('Clear cached object data'), + '#submit' => array('salesforce_api_cache_build'), + ); // Validate handler makes sure that the salesforce_api_password doesn't get set to null on accident $form['#validate'][] = 'salesforce_api_settings_form_validate'; $form['#submit'][] = 'salesforce_api_settings_form_submit'; @@ -422,6 +445,88 @@ function theme_salesforce_api_fieldmap_e return theme('table', $header, $rows, $attributes, $caption); } + /** + * Ask salesforce for a list of objects and display a checklist for the user. + * Based on user selection, set up or tear down cached/synched Salesforce data. + * @TODO make this more user friendly. At the moment it's possible for an admin user to blow away + * their entire local SalesForce cache with a few clicks. This is not necessarily desirable. + * + * @param string $form_state + * @return void + * @author aaron + */ +function salesforce_api_admin_object(&$form_state) { + $objects = salesforce_api_describeGlobal(); + $cache = cache_get('salesforce_api_sf_objects'); + $defaults = is_array($cache->data) ? array_keys($cache->data) : array(); + + if (empty($objects->types)) { + drupal_set_message(t('There was an error retrieving the list of SalesForce objects. Please verify that your SalesForce instance is properly configured.'), 'error'); + return; + } + + $options = array_combine($objects->types, $objects->types); + $fields = array('objects' => array( + '#type' => 'checkboxes', + '#title' => 'SalesForce Objects', + '#description' => 'Check the SalesForce objects you would like to synchronize locally.', + '#options' => $options, + '#default_value' => $defaults, + ), + '#theme' => 'salesforce_api_object_options', + 'submit' => array( + '#type' => 'submit', + '#value' => 'Save' + ), + ); + return $fields; +} + +/** + * FAPI submit handler + */ +function salesforce_api_admin_object_submit($form, &$form_state) { + $values = $form_state['values']['objects']; + foreach ($values as $i => $t) { + if (empty($t)) continue; + $real_types[] = $t; + } + $sf_objects = variable_set('salesforce_api_enabled_objects', $real_types); + $objects = salesforce_api_cache_build(); + return; +} + +function salesforce_api_admin_object_settings($form_state, $type) { + return array('settings' => array( + '#type' => 'markup', + '#value' => 'Placeholder for per-object configuration settings.' + ) + ); +} + +/** + * Theming function for salesforce_api_admin_setup + * For locally-cached SF Objects, add a "configure" or "re-map" link next to the checkbox + */ +function theme_salesforce_api_object_options($element = NULL) { + if (empty($element['objects']['#options'])) return drupal_render($element); + $objects = $element['objects']; + $options = $objects['#options']; + foreach ($options as $i) { + if (empty($objects[$i]['#value'])) continue; + $link = l('configure', SALESFORCE_PATH_OBJECT .'/'. $i); + if ($_SESSION['objects_error'][$i]) { + $element['objects'][$i]['#prefix'] = '
'; + $element['objects'][$i]['#suffix'] = '
'; + unset($_SESSION['objects_error'][$i]); + $link = l('re-map fields', SALESFORCE_PATH_OBJECT .'/'. $i); + } + $element['objects'][$i]['#title'] .= ' | '. $link; + } + unset($_SESSION['objects_error']); + return drupal_render($element); +} + /** * Demonstrates some of the API functionality through the Salesforce class and * fieldmap functionality. diff -urp /Users/openbook/Downloads/opensource/drupal/modules/d6/salesforce/salesforce_api/salesforce_api.install ./salesforce_api/salesforce_api.install --- /Users/openbook/Downloads/opensource/drupal/modules/d6/salesforce/salesforce_api/salesforce_api.install 2009-08-31 16:00:22.000000000 +0100 +++ ./salesforce_api/salesforce_api.install 2009-09-16 16:07:18.000000000 +0100 @@ -20,6 +20,7 @@ function salesforce_api_install() { function salesforce_api_uninstall() { drupal_uninstall_schema('salesforce_api'); db_query("DELETE FROM {variable} WHERE {name} LIKE 'salesforce%'"); + db_query("DELETE FROM {cache} WHERE {cid} = 'salesforce_api_sf_objects'"); } /** @@ -27,6 +28,7 @@ function salesforce_api_uninstall() { */ function salesforce_api_enable() { drupal_set_message(t('Salesforce API: Before making any Salesforce connections, please enter your Salesforce API credentials', array('!url' => url(SALESFORCE_PATH_ADMIN))), 'warning'); +drupal_set_message(t('Salesforce API: The default Salesforce object have been enabled, to export/import any other objects see the Object setup page.', array('!url' => url(SALESFORCE_PATH_OBJECT))), 'warning'); } /** diff -urp /Users/openbook/Downloads/opensource/drupal/modules/d6/salesforce/salesforce_api/salesforce_api.module ./salesforce_api/salesforce_api.module --- /Users/openbook/Downloads/opensource/drupal/modules/d6/salesforce/salesforce_api/salesforce_api.module 2009-08-31 16:00:22.000000000 +0100 +++ ./salesforce_api/salesforce_api.module 2009-09-16 16:16:22.000000000 +0100 @@ -17,10 +17,12 @@ define('SALESFORCE_DIR_TOOLKIT', SALESFO define('SALESFORCE_DIR_SOAPCLIENT', SALESFORCE_DIR_TOOLKIT .'/soapclient'); define('SALESFORCE_DIR_WSDL', SALESFORCE_DIR .'/wsdl'); + // Define Drupal paths for various parts of the Salesforce UI. define('SALESFORCE_PATH_ADMIN', 'admin/settings/salesforce'); -define('SALESFORCE_PATH_FIELDMAPS', 'admin/settings/salesforce/fieldmap'); -define('SALESFORCE_PATH_DEMO', 'admin/settings/salesforce/demo'); +define('SALESFORCE_PATH_FIELDMAPS', SALESFORCE_PATH_ADMIN .'/fieldmap'); +define('SALESFORCE_PATH_DEMO', SALESFORCE_PATH_ADMIN .'/demo'); +define('SALESFORCE_PATH_OBJECT', SALESFORCE_PATH_ADMIN .'/object'); // Define field importing requirements. // TODO: I believe we need to use bitwise operators instead. @@ -111,7 +113,23 @@ function salesforce_api_menu() { 'type' => MENU_CALLBACK, 'file' => 'salesforce_api.admin.inc', ); - + $items[SALESFORCE_PATH_OBJECT] = array( + 'title' => 'Object setup', + 'description' => 'Define which SalesForce objects you would like to be available in your Drupal site.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('salesforce_api_admin_object'), + 'access arguments' => array('administer salesforce'), + 'type' => MENU_LOCAL_TASK, + 'file' => 'salesforce_api.admin.inc', + ); + $items[SALESFORCE_PATH_OBJECT .'/%'] = array( + 'title' => 'Object setup', + 'page callbacck' => 'drupal_get_form', + 'page arguments' => array('salesforce_api_admin_object_settings', count(explode('/', SALESFORCE_PATH_OBJECT))), + 'access arguments' => array('administer salesforce'), + 'type' => MENU_CALLBACK, + 'file' => 'salesforce_api.admin.inc', + ); return $items; } @@ -164,7 +182,7 @@ function salesforce_api_connect($usernam } // Include the file that defines the class. - require_once(drupal_get_path('module', 'salesforce_api') . '/salesforce.class.inc'); + require_once(drupal_get_path('module', 'salesforce_api') .'/salesforce.class.inc'); // Create a new Salesforce object with the API credentials. $sf = new DrupalSalesforce($username, $password, $token); @@ -201,7 +219,7 @@ function salesforce_api_connect($usernam function salesforce_api_reset_expired_password($sf) { // Append one letter and one digit to the password to make sure we meet // salesforce's password validation requirements. - $new_password = user_password() . 'z9'; + $new_password = user_password() .'z9'; // setPassword() may throw InvalidIdFault or UnexpectedErrorFault exceptions. $sf->client->setPassword($sf->login->userId, $new_password); variable_set('salesforce_api_password', $new_password); @@ -239,38 +257,44 @@ function salesforce_api_fieldmap_objects if ($type == 'salesforce') { $cache = cache_get('salesforce_api_sf_objects'); if ($cache->data == '') { - $sf_objects = variable_get('salesforce_api_enabled_objects', array('Campaign', 'Contact', 'Lead')); - $sf = salesforce_api_connect(); - if (!$sf) { - drupal_set_message(t('Unable to connect to Salesforce using current credentials.', array('!url' => url(SALESFORCE_PATH_ADMIN)))); - return array(); - } - - $result = $sf->client->describeSObjects($sf_objects); - foreach ($result as $key => $object) { - $objects[$sf_objects[$key]] = array( - 'label' => t($sf_objects[$key]), - 'fields' => array(), - ); - foreach ($object->fields as $field) { - $objects[$sf_objects[$key]]['fields'][$field->name] = array( - 'label' => t($field->label), - ); - if ($field->createable != 1) { - $objects[$sf_objects[$key]]['fields'][$field->name]['type'] = SALESFORCE_FIELD_SOURCE_ONLY; - } - elseif ($field->nillable != 1 && $field->defaultedOnCreate != 1) { - $objects[$sf_objects[$key]]['fields'][$field->name]['type'] = SALESFORCE_FIELD_REQUIRED; - } - } - } - cache_set('salesforce_api_sf_objects', $objects); + $objects = salesforce_api_cache_build(); } else { $objects = $cache->data; } } + return $objects; +} +/** + * Recreate the salesforce object cache + */ +function salesforce_api_cache_build() { + $sf_objects = variable_get('salesforce_api_enabled_objects', array('Campaign', 'Contact', 'Lead')); + $sf = salesforce_api_connect(); + $result = $sf->client->describeSObjects($sf_objects); + foreach ($result as $key => $object) { + $objects[$sf_objects[$key]] = array( + 'label' => t($sf_objects[$key]), + 'fields' => array(), + ); + foreach ($object->fields as $field) { + $objects[$sf_objects[$key]]['fields'][$field->name] = array( + 'label' => t($field->label), + ); + if ($field->createable != 1) { + $objects[$sf_objects[$key]]['fields'][$field->name]['type'] = SALESFORCE_FIELD_SOURCE_ONLY; + } + elseif ($field->nillable != 1 && $field->defaultedOnCreate != 1) { + $objects[$sf_objects[$key]]['fields'][$field->name]['type'] = SALESFORCE_FIELD_REQUIRED; + } + } + } + // find the expiry time + $lifetime = variable_get('salesforce_api_object_expire', CACHE_PERMANENT); + $expire = ($lifetime == CACHE_PERMANENT) ? CACHE_PERMANENT : time() + $lifetime; + cache_set('salesforce_api_sf_objects', $objects, $table = 'cache', $expire, $headers = NULL); + drupal_set_message(t('Salesforce object cache has been refreshed.')); return $objects; } @@ -643,3 +667,57 @@ function salesforce_api_theme($existing, ), ); } + +/** + * Wrapper for SOAP SforceBaseClient::describeGlobal + * @return an SFQueryResult object (look at ->types for an array of SF object types) + */ +function salesforce_api_describeGlobal() { + static $objects; + if (!empty($objects)) { + return $objects; + } + $sf = salesforce_api_connect(); + if ($sf === FALSE) { + $link = l('Please verify that you have completed your SalesForce credentials', SALESFORCE_PATH_ADMIN); + drupal_set_message(t('Unable to connect to SalesForce. !link', array('!link' => $link)), 'error'); + return; + } + $objects = $sf->client->describeGlobal(); + return $objects; +} + +/** + * Convert Salesforce object fields to fieldmap array for saving + */ +function salesforce_api_object_to_fieldmap_fields($object) { + $fieldmap_object = array(); + $fieldmap_object[$object->name] = array( + 'label' => $object->label, + 'fields' => array() + ); + + foreach ($object->fields as $field) { + $fieldmap_object[$object->name]['fields'][$field->name]['label'] = $field->label; + if ($field->createable != 1) { + $fieldmap_object[$object->name]['fields'][$field->name]['type'] = SALESFORCE_FIELD_SOURCE_ONLY; + } + elseif (!$field->nillable && !$field->defaultedOnCreate) { + $fieldmap_object[$object->name]['fields'][$field->name]['type'] = SALESFORCE_FIELD_REQUIRED; + } + else { + $fieldmap_object[$object->name]['fields'][$field->name]['type'] = SALESFORCE_FIELD_OPTIONAL; + } + } + return $fieldmap_object; +} + +/** + * Implementation of hook_cron(). + */ +function salesforce_api_cron() { + $cache = cache_get('salesforce_api_sf_objects'); + // if the cache has already been delete or is expired then rebuild + if (!$cache || time() > $cache->expire) salesforce_api_cache_build(); + return; +} \ No newline at end of file Only in ./salesforce_api/toolkit: .DS_Store Only in ./: salesforce_api.476978.patch