diff --git a/uc_attribute_files.inc b/uc_attribute_files.inc new file mode 100644 index 0000000..98b8b90 --- /dev/null +++ b/uc_attribute_files.inc @@ -0,0 +1,72 @@ + + * @author Lee Rowlands contact at rowlandsgroup dot com + * + */ + +/** + * Our overriden callback for the store attributes table +*/ +function uc_attribute_files_admin() { + $header = array( + array('data' => t('Name'), 'field' => 'a.name', 'sort' => 'asc'), + array('data' => t('Label'), 'field' => 'a.label'), + t('Required'), + array('data' => t('List position'), 'field' => 'a.ordering'), + t('Number of options'), + t('Display type'), + t('Operations'), + ); + + $display_types = array( + 0 => t('Text field'), + 1 => t('Select box'), + 2 => t('Radio buttons'), + 3 => t('Checkboxes'), + UC_ATTRIBUTE_FILES_TYPE => t('File Upload'), + ); + + $result = pager_query("SELECT a.aid, a.name, a.label, a.required, a.ordering, + a.display, COUNT(ao.oid) AS options + FROM {uc_attributes} AS a + LEFT JOIN {uc_attribute_options} AS ao + ON a.aid = ao.aid + GROUP BY a.aid, a.name, a.label, a.ordering, a.required, + a.display". tablesort_sql($header), 30, 0, + "SELECT COUNT(aid) FROM {uc_attributes}"); + while ($attr = db_fetch_object($result)) { + if (empty($attr->label)) { + $attr->label = $attr->name; + } + $ops = array( + l(t('edit'), 'admin/store/attributes/'. $attr->aid .'/edit'), + l(t('options'), 'admin/store/attributes/'. $attr->aid .'/options'), + l(t('delete'), 'admin/store/attributes/'. $attr->aid .'/delete'), + ); + $rows[] = array( + check_plain($attr->name), + check_plain($attr->label), + $attr->required == 1 ? t('Yes') : t('No'), + array('data' => $attr->ordering, 'align' => 'center'), + array('data' => $attr->options, 'align' => 'center'), + $display_types[$attr->display], + implode(' ', $ops), + ); + } + + if (count($rows) == 0) { + $rows[] = array( + array('data' => t('No product attributes have been added yet.'), + 'colspan' => '6') + ); + } + + $output = theme('table', $header, $rows) . theme('pager', NULL, 30) . l(t('Add an attribute'), 'admin/store/attributes/add'); + + return $output; +} \ No newline at end of file diff --git a/uc_attribute_files.info b/uc_attribute_files.info index e40956c..7c33b89 100644 --- a/uc_attribute_files.info +++ b/uc_attribute_files.info @@ -1,8 +1,9 @@ -; $Id$ -name = UC_attribute_files +name = Ubercart Attributes - Files description = Extends product attributes in Ubercart to allow a customer to attach a file upload to a product in their cart. Module supports filtering of file types allowed to upload either globally, or by adding the file type extension to the list of options. dependencies[] = uc_product dependencies[] = uc_cart +dependencies[] = upload +dependencies[] = user_files dependencies[] = uc_attribute dependencies[] = uc_order package = "Ubercart - Contrib (optional)" diff --git a/uc_attribute_files.install b/uc_attribute_files.install index 72cc5dd..ec6ff7f 100644 --- a/uc_attribute_files.install +++ b/uc_attribute_files.install @@ -1,20 +1,14 @@ + * Install hooks for uc_attribute_files.module. + * */ /** - * Implemenation of hook_schema() - *//* -function uc_attribute_files_schema() { - return $schema; -} - -/** - * Implmentation of hook_install(). + * Implments of hook_install(). */ function uc_attribute_files_install() { variable_set('uc_attribute_files_cart_filepath', file_directory_path() . '/cart'); @@ -22,10 +16,10 @@ function uc_attribute_files_install() { } /** - * Implementation of hook_uninstall(). + * Implements of hook_uninstall(). */ function uc_attribute_files_uninstall() { variable_del('uc_attribute_files_cart_filepath'); variable_del('uc_attribute_files_order_filepath'); -} -//*/ + variable_del('uc_attribute_files_attribute_number'); +} \ No newline at end of file diff --git a/uc_attribute_files.module b/uc_attribute_files.module index 9ac3f29..f33fa8e 100644 --- a/uc_attribute_files.module +++ b/uc_attribute_files.module @@ -1,566 +1,399 @@ + * @author Lee Rowlands contact at rowlandsgroup dot com + * @todo Fix http://localhost/drupal/?q=node/6/edit/options so notes on use with file upload is output + * @todo Adjust the price of items in the cart based on the extension of the option chosen + */ +/******************************************************* + * Constants + *******************************************************/ + +define('UC_ATTRIBUTE_FILES_TYPE', 213); //completely random but less likely to cause collisions + +/******************************************************* + * Core Hooks + *******************************************************/ + +/** + * Implements hook_perm +*/ function uc_attribute_files_perm() { - return array('view all uploads', 'upload files', 'view upload'); -} - -function uc_attribute_files_menu() { - $items = array(); - $items['uploads/cart/%'] = array( - 'page callback' => '_uc_attribute_files_download', - 'page arguments' => array(1, 2), - 'access callback' => 'uc_attribute_files_user_view_upload_access', - 'type' => MENU_CALLBACK, - ); - $items['uploads/order/%/%/%'] = array( - 'page callback' => '_uc_attribute_files_download', - 'page arguments' => array(1, 4, 2, 3), - 'access callback' => 'uc_attribute_files_user_view_upload_access', - 'type' => MENU_CALLBACK, - - ); - return $items; -} - -function uc_attribute_files_user_view_upload_access() { - if (user_access('view upload') || user_access('view all uploads') ) { - return TRUE; - } - else { - return FALSE; - } + return array('view all attribute uploads', 'upload attribute files', 'view attribute uploads'); } +/** + * Implements hook_menu_alter +*/ function uc_attribute_files_menu_alter(&$items) { + // We take over the menu callback $items['admin/store/attributes']['page callback'] = 'uc_attribute_files_admin'; - unset($items['admin/store/attributes']['file']); -} - -function uc_attribute_files_admin() { - $header = array( - array('data' => t('Name'), 'field' => 'a.name', 'sort' => 'asc'), - array('data' => t('Label'), 'field' => 'a.label'), - t('Required'), - array('data' => t('List position'), 'field' => 'a.ordering'), - t('Number of options'), - t('Display type'), - t('Operations'), - ); - - $display_types = array( - 0 => t('Text field'), - 1 => t('Select box'), - 2 => t('Radio buttons'), - 3 => t('Checkboxes'), - variable_get('uc_attribute_files_attribute_number', 4) => t('File Upload'), - ); - - $result = pager_query("SELECT a.aid, a.name, a.label, a.required, a.ordering, a.display, COUNT(ao.oid) AS options FROM {uc_attributes} AS a LEFT JOIN {uc_attribute_options} AS ao ON a.aid = ao.aid GROUP BY a.aid, a.name, a.label, a.ordering, a.required, a.display". tablesort_sql($header), 30, 0, "SELECT COUNT(aid) FROM {uc_attributes}"); - while ($attr = db_fetch_object($result)) { - if (empty($attr->label)) { - $attr->label = $attr->name; - } - $ops = array( - l(t('edit'), 'admin/store/attributes/'. $attr->aid .'/edit'), - l(t('options'), 'admin/store/attributes/'. $attr->aid .'/options'), - l(t('delete'), 'admin/store/attributes/'. $attr->aid .'/delete'), - ); - $rows[] = array( - check_plain($attr->name), - check_plain($attr->label), - $attr->required == 1 ? t('Yes') : t('No'), - array('data' => $attr->ordering, 'align' => 'center'), - array('data' => $attr->options, 'align' => 'center'), - $display_types[$attr->display], - implode(' ', $ops), - ); - } - - if (count($rows) == 0) { - $rows[] = array( - array('data' => t('No product attributes have been added yet.'), 'colspan' => '6') - ); - } - - $output = theme('table', $header, $rows) . theme('pager', NULL, 30) . l(t('Add an attribute'), 'admin/store/attributes/add'); - - return $output; -} - -function _uc_attribute_files_download($type, $file, $uid = NULL, $order_id = NULL) { - global $user; - - switch ($type) { - case 'cart': - $dir = variable_get('uc_attribute_files_cart_filepath', NULL) . "/" . uc_cart_get_id(); - break; - - case 'anonymous': - case 'order': - $dir = variable_get('uc_attribute_files_order_filepath', NULL) . "/" . $uid . "/" . $order_id; - - if ($type !== 'anonymous' && $uid == $user->uid && $uid == 0) { //Force anonymous orders to provide zip - return drupal_get_form('uc_attribute_files_anonymous_zip_form', $file, $uid, $order_id); - } - break; - - default: - $dir = NULL; - break; - } - - if ( !is_null(variable_get('uc_attribute_files_cart_filepath', NULL)) && //Validate variable set - !is_null(variable_get('uc_attribute_files_order_filepath', NULL)) && //Validate variable set - ($uid == $user->uid || user_access('view all uploads')) && //Check permission - !is_null($dir) && is_readable($dir . '/' . check_plain($file)) //Check dir & file are valid - ) { - uc_attribute_files_download_transfer(check_plain($file), $dir); - - } - elseif ($user->uid == 0) { - drupal_set_title(t('Access denied')); - return t('You must logon to access this file.'); - } - else { - //Handle & Log Errors - if (is_null(variable_get('uc_attribute_files_cart_filepath', NULL))) { - watchdog('uc_attribute_files', 'uc_attribute_files_cart_filepath is not set'); - $dir = NULL; - if ($user->uid == 1) { - drupal_set_message(t('uc_attribute_files_cart_filepath is not set. !link to edit.', array('!link' => l(t('Click here'), 'admin/store/settings/attributes')))); - } - } - - if (is_null(variable_get('uc_attribute_files_order_filepath', NULL))) { - watchdog('uc_attribute_files', 'uc_attribute_files_order_filepath is not set'); - $dir = NULL; - if ($user->uid == 1) { - drupal_set_message(t('uc_attribute_files_order_filepath is not set. !link to edit.', array('!link' => l(t('Click here'), 'admin/store/settings/attributes')))); - } - } - - if (is_readable($dir . '/' . check_plain($file))) { - watchdog('uc_attribute_files', 'File not readable: %user attempted to access %file from %type: %id. in dir: %dir', array('%user' => $user->name, '%file' => check_plain($file), '%type' => $type, '%id' => $id, '%dir' => $dir)); - } - - if (is_null($dir)) { - watchdog('uc_attribute_files', 'Invalid type of %type was passed by user %user for file %file', array('%user' => $user->name, '%file' => check_plain($file), '%type' => $type)); - } - - drupal_set_header('HTTP/1.1 404 Not Found'); - drupal_set_title(t('Page not found')); - return t('The requested page could not be found.'); - } -} - -function uc_attribute_files_anonymous_zip_form($form_state, $file, $uid, $order_id) { - $form['zip'] = array( '#type' => 'textfield', - '#description' => t('Enter the billing zip code for the order'), - '#title' => t('Billing Zip Code'), - '#size' => 5, - '#maxlength' => 5, - ); - $form['a'] = array( '#type' => 'hidden', '#value' => $file ); - $form['b'] = array( '#type' => 'hidden', '#value' => $uid ); - $form['c'] = array( '#type' => 'hidden', '#value' => $order_id ); - $form['submit'] = array('#type' => 'submit', '#value' => t('Submit')); - return $form; -} - -function uc_attribute_files_anonymous_zip_form_submit($form, &$form_state) { - $zip = $form_state['values']['zip']; - $file = $form_state['values']['a']; - $uid = $form_state['values']['b']; - $order_id = $form_state['values']['c']; - - if (intval($order_id) > 0) { - $order = uc_order_load($order_id); - if ($order->billing_postal_code == $zip) { - return _uc_attribute_files_download('anonymous', $file, $uid, $order_id); - } - } - drupal_set_message(t('Zip code does not match order.')); -} - -function uc_attribute_files_download_transfer($file, $path) { - //Function copied and modified slightly from uc_file.module - - $filepath = $path . "/" . $file; - - // Gather relevant info about the file. - $size = filesize($filepath); - $mimetype = file_get_mimetype($filepath); - - // Workaround for IE filename bug with multiple periods / multiple dots in filename - // that adds square brackets to filename - eg. setup.abc.exe becomes setup[1].abc.exe - if (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) { - $file = preg_replace('/\./', '%2e', $file, substr_count($file, '.') - 1); - } - - // Check if HTTP_RANGE is sent by browser (or download manager) - if (isset($_SERVER['HTTP_RANGE'])) { - list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2); - - if ($size_unit == 'bytes') { - // Multiple ranges could be specified at the same time, but for simplicity only serve the first range - // See http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt - list($range, $extra_ranges) = explode(',', $range_orig, 2); - } - else { - $range = ''; - } - } - else { - $range = ''; - } - - // Figure out download piece from range (if set) - list($seek_start, $seek_end) = explode('-', $range, 2); - - // Set start and end based on range (if set), else set defaults and check for invalid ranges. - $seek_end = intval((empty($seek_end)) ? ($size - 1) : min(abs(intval($seek_end)), ($size - 1))); - $seek_start = intval((empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)), 0)); - - ob_end_clean(); - - //Only send partial content header if downloading a piece of the file (IE workaround) - if ($seek_start > 0 || $seek_end < ($size - 1)) { - drupal_set_header('HTTP/1.1 206 Partial Content'); - } - - // Standard headers, including content-range and length - drupal_set_header('Pragma: public'); - drupal_set_header('Cache-Control: cache, must-revalidate'); - drupal_set_header('Accept-Ranges: bytes'); - drupal_set_header('Content-Range: bytes '. $seek_start .'-'. $seek_end .'/'. $size); - drupal_set_header('Content-Type: '. $mimetype); - drupal_set_header('Content-Disposition: attachment; filename="'. $file .'"'); - drupal_set_header('Content-Length: '. ($seek_end - $seek_start + 1)); - - // Last-Modified is required for content served dynamically - drupal_set_header('Last-Modified: '. gmdate("D, d M Y H:i:s", filemtime($filepath)) ." GMT"); - - // Etag header is required for Firefox3 and other managers - drupal_set_header('ETag: '. md5($filepath)); - - // Open the file and seek to starting byte - $fp = fopen($filepath, 'rb'); - fseek($fp, $seek_start); - - // Start buffered download - while (!feof($fp)) { - // Reset time limit for large files - set_time_limit(30); - - // Push the data to the client. - print(fread($fp, 8192)); - flush(); - ob_flush(); - } - - fclose($fp); -} - - -//Implements hook_add_to_cart. Gives item information for anything added to cart -function uc_attribute_files_uc_form_alter(&$form_state, $node) { - if (count($form_state['node']['#value']->attributes) > 0) { - foreach ($form_state['node']['#value']->attributes as $attribute) { - if ($attribute->display == variable_get('uc_attribute_files_attribute_number', 4)) { - $form_state['#attributes']['enctype']='multipart/form-data'; - $form_state['#validate'][] = "uc_attribute_files_cart_validate"; - } - } - } + $items['admin/store/attributes']['file'] = 'uc_attribute_files.inc'; + $items['admin/store/attributes']['module'] = 'uc_attribute_files'; + $items['admin/store/attributes/overview']['page callback'] = 'uc_attribute_files_admin'; + $items['admin/store/attributes/overview']['file'] = 'uc_attribute_files.inc'; + $items['admin/store/attributes/overview']['module'] = 'uc_attribute_files'; } +/** + * Implements hook_form_alter +*/ function uc_attribute_files_form_alter(&$form, $form_state, $form_id) { global $user; if (strpos($form_id, "add_to_cart_form")) { - - if (count($form['attributes']) > 0) { + if (!empty($form['attributes']) && + is_array($form['attributes']) && + count($form['attributes']) > 0) { foreach ($form['attributes'] as $id => $attribute) { - if ($form['node']['#value']->attributes[$id]->display == variable_get('uc_attribute_files_attribute_number', 4)) { - if (!user_access('upload files')) { - $form['attributes'][$id]['#type'] = 'hidden'; + if ($form['node']['#value']->attributes[$id]->display == UC_ATTRIBUTE_FILES_TYPE) { + if (!user_access('upload attribute files')) { + $form['attributes'][$id]['#type'] = 'value'; $form['attributes'][$id]['#value'] = ''; if ($attribute['#required']) { $form['submit']['#attributes']['disabled'] = 'disabled'; - $form['submit']['#title'] = 'You must login to add this to your cart'; + $form['submit']['#title'] = t('You must login to add this to your cart'); if ($user->uid == 0) { - $form['uc_attribute_files_login_required']['#value'] = '
' . t('Please !login to see if you can add this item to your cart.', array('!login' => l(t('login'), 'user/login'))) . '
'; + $form['uc_attribute_files_login_required']['#value'] = '
' . t('Only certain users can add this item to their cart, please !login to see if your account has this permission.', array('!login' => l(t('login'), 'user/login'))) . '
'; } else { - $form['uc_attribute_files_login_required']['#value'] = '
' . t('Your userid can not add this item. Please contact an administrator for assistance.') . '
'; + $form['uc_attribute_files_login_required']['#value'] = '
' . t('Your user account cannot add this item. Please contact an administrator for assistance.') . '
'; } - }//* + } } else { - $form['attributes'][$id]['#type'] = 'file'; - $form['attributes'][$id]['#name'] = "files[" . check_plain($form['node']['#value']->attributes[$id]->name) . "]"; - $form['attributes'][$id]['#value_callback'] = "uc_attribute_files_value_callback"; + // To allow this to work with lazy sessions (pressflow) + if (count($_SESSION) == 0 || empty($_SESSION) && !$user->uid) { + // Inject something into session to ensure we have a persistent session id + $_SESSION['uc_attribute_files'] = 1; + } + // Set the form encoding + if (!empty($form['#attributes'])) { + $form['#attributes']['enctype'] = "multipart/form-data"; + } + else { + $form['#attributes'] = array('enctype' => "multipart/form-data"); + } + // Make sure our submit function goes before uc_attributes (but only once!) + if (!in_array('uc_attribute_files_cart_submit', $form['#submit'])) { + array_unshift($form['#submit'], 'uc_attribute_files_cart_submit'); + } + // Unfortunately file elements don't support being part of #TREE so + // we have to provide unique field names + $field_name = 'attributes_'. $id; + // clone the existing field + $form['attributes'][$field_name] = $form['attributes'][$id]; + // make it a file + $form['attributes'][$field_name]['#type'] = 'file'; + // unset the parents nesting + $form['attributes'][$field_name]['#parents'] = array($field_name); + // remove the old field - move it to a value + $form['attributes'][$id]['#type'] = 'value'; + if (empty($form['attributes'][$id]['#default_value']) && + // No default is chosen - we need to select at least one - use the first + count($form['attributes'][$id]['#options']) > 0) { + $form['attributes'][$id]['#default_value'] = array_shift(array_keys($form['attributes'][$id]['#options'])); + } + $form['attributes'][$id]['#value'] = $form['attributes'][$id]['#default_value']; } } } } } - else { - switch ($form_id) { - case 'uc_attribute_admin_settings': - //Remove first form element, and put into array to be used so new form can be inserted before - //the submit buttons. This essentiall re-orders the form so it doesn't look stupid. - $uc_attribute_files_form[key($form)] = array_shift($form); - $uc_attribute_files_form['uc_attribute_files_cart_filepath'] = - array( - '#type' => 'textfield', - '#title' => t('File path for cart file uploads'), - '#description' => t('The absolute path (or relative to Drupal root) where files uploaded to a cart for an attribute should be put. For security reasons, it is recommended to choose a path outside the web root.'), - '#default_value' => variable_get('uc_attribute_files_cart_filepath', NULL), - ); - $uc_attribute_files_form['uc_attribute_files_order_filepath'] = - array( - '#type' => 'textfield', - '#title' => t('File path for order files'), - '#description' => t('The absolute path (or relative to Drupal root) where uploaded files should be moved after a cart becomes an order. For security reasons, it is recommended to choose a path outside the web root.'), - '#default_value' => variable_get('uc_attribute_files_order_filepath', NULL), - ); - $uc_attribute_files_form['uc_attribute_files_file_extensions'] = - array( - '#type' => 'textfield', - '#title' => t('List of file extensions allowed (Use a ; to separate)'), - '#description' => t('Default list of file extensions for files that can be uploaded. Separate each by a semi-colin (;) or use * as a wild card to allow any file type.
' . 'NOTE: This can be overridden on an attribute by adding an option for each acceptable filetype. If any option is specified on the attribute directly, this setting is ignored for that attribute.'), - '#default_value' => variable_get('uc_attribute_files_file_extensions', "PDF;JPG;GIF;JPEG;TIFF;BMP"), - ); - - //Takes the above array and inserts it into the beginning of the form array - $form = array_merge($uc_attribute_files_form, $form); - $form['#validate'][] = "uc_attribute_files_admin_validate"; - break; - case 'uc_attribute_form': - $numb = variable_get('uc_attribute_files_attribute_number', NULL); - if (is_null($numb)) { - $numb = count($form['display']['#options']); - variable_set('uc_attribute_files_attribute_number', $numb); - } - $form['display']['#options'][$numb] = t('File Upload'); +} - break; - case 'user_login_block': - //Add Hidden form element to pass old cart id on logon - $form['uc_attribute_files_cartid'] = array('#type' => 'hidden', '#value' => uc_cart_get_id() ); - break; +/** + * Implements hook_form_FORM_ID_alter +*/ +function uc_attribute_files_form_uc_attribute_admin_settings_form_alter(&$form, $form_state) { + //Remove first form element, and put into array to be used so new form can be inserted before + //the submit buttons. This essentiall re-orders the form so it doesn't look stupid. + $uc_attribute_files_form[key($form)] = array_shift($form); + $uc_attribute_files_form['uc_attribute_files_cart_filepath'] = + array( + '#type' => 'textfield', + '#title' => t('File path for cart file uploads'), + '#description' => t('The absolute path (or relative to Drupal root) where files uploaded to a cart for an attribute should be put. For security reasons, it is recommended to choose a path outside the web root.'), + '#default_value' => variable_get('uc_attribute_files_cart_filepath', NULL), + ); + $uc_attribute_files_form['uc_attribute_files_order_filepath'] = + array( + '#type' => 'textfield', + '#title' => t('File path for order files'), + '#description' => t('The absolute path (or relative to Drupal root) where uploaded files should be moved after a cart becomes an order. For security reasons, it is recommended to choose a path outside the web root.'), + '#default_value' => variable_get('uc_attribute_files_order_filepath', NULL), + ); + $uc_attribute_files_form['uc_attribute_files_file_extensions'] = + array( + '#type' => 'textfield', + '#title' => t('List of file extensions allowed (Use a ; to separate)'), + '#description' => t('Default list of file extensions for files that can be uploaded. Separate each by a semi-colin (;) or use * as a wild card to allow any file type.
' . 'NOTE: This can be overridden on an attribute by adding an option for each acceptable filetype. If any option is specified on the attribute directly, this setting is ignored for that attribute.'), + '#default_value' => variable_get('uc_attribute_files_file_extensions', "PDF;JPG;GIF;JPEG;TIFF;BMP"), + ); - case 'uc_attribute_options_form': - if (count($form['#parameters']) < 1) { - break; - } - foreach ($form['#parameters'] as $id => $param) { - if ($param->display == 4) { - $form['uc_attribute_files_notes']['#value'] = - '
' . t('NOTE: Enter file extensions as options above to limit uploads to the file types listed. Enter a * for any file extension. This overrides site defaults.') . '
'; - } - } - break; - case 'uc_attribute_option_form': - if (count($form['#parameters']) < 1) { - break; - } + //Takes the above array and inserts it into the beginning of the form array + $form = array_merge($uc_attribute_files_form, $form); + $form['#validate'][] = "uc_attribute_files_admin_validate"; +} + +/** + * Implements hook_form_FORM_ID_alter +*/ +function uc_attribute_files_form_uc_attribute_form_alter(&$form, $form_state) { + $form['display']['#options'][UC_ATTRIBUTE_FILES_TYPE] = t('File Upload'); +} - foreach ($form['#parameters'] as $id => $param) { - if ($param->display == 4) { - $form['name']['#description'] = - t('The extension of a file type you would like a user to be able to upload. Enter a * for any extension.') . ''; - } - } +/** + * Implements hook_form_FORM_ID_alter +*/ +function uc_attribute_files_form_uc_attribute_options_form_form_alter(&$form, $form_state) { + if (count($form['#parameters']) < 1) { break; - case 'uc_object_attributes_form': - if (count($form['attributes']) < 1) { - break; + } + foreach ($form['#parameters'] as $id => $param) { + if ($param->display == UC_ATTRIBUTE_FILES_TYPE) { + $form['uc_attribute_files_notes']['#value'] = + '
' . t('NOTE: Enter file extensions as options above to limit uploads to the file types listed. Enter a * for any file extension. This overrides site defaults.') . '
'; } + } +} - foreach ($form['attributes'] as $id => $attribute) { - $form['attributes'][$id]['display']['#options'][variable_get('uc_attribute_files_attribute_number', 4)] = t('File Upload'); - } +/** + * Implements hook_form_FORM_ID_alter +*/ +function uc_attribute_files_form_uc_attribute_option_form_form_alter(&$form, $form_state) { + if (count($form['#parameters']) < 1) { break; + } - default: - /*print("abc"); - print_r($form_id);//*/ - + foreach ($form['#parameters'] as $id => $param) { + if ($param->display == UC_ATTRIBUTE_FILES_TYPE) { + $form['name']['#description'] = + t('The extension of a file type you would like a user to be able to upload. Enter a * for any extension.') . ''; } } } -function uc_attribute_files_admin_validate($form, &$form_state) { - $cart_dir = check_plain($form_state['values']['uc_attribute_files_cart_filepath']); - $order_dir = check_plain($form_state['values']['uc_attribute_files_order_filepath']); - - if (!is_dir($cart_dir) && !@mkdir($cart_dir, 0755, TRUE)) { - form_set_error('uc_attribute_files_cart_filepath', t('Could not open or create path:') . $cart_dir); +/** + * Implements hook_form_FORM_ID_alter +*/ +function uc_attribute_files_form_uc_object_attributes_form_alter(&$form, $form_state) { + if (count($form['attributes']) < 1) { + return; } - if (!is_dir($order_dir) && !@mkdir($order_dir, 0755, TRUE)) { - form_set_error('uc_attribute_files_order_filepath', t('Could not open or create path:') . $order_dir); + foreach ($form['attributes'] as $id => $attribute) { + $form['attributes'][$id]['display']['#options'][UC_ATTRIBUTE_FILES_TYPE] = t('File Upload'); } } -function uc_attribute_files_value_callback($form, $edit = FALSE) { - if ($edit !== FALSE) { - preg_match("/files\[(.+)\]/", $form['#name'], $name); - - if (count($_FILES['files']) > 0) { - $filename = file_munge_filename($_FILES['files']['name'][$name[1]], ""); - $return = '[UC_ATTRIBUTE_FILES]' . $filename . '[/UC_ATTRIBUTE_FILES]'; - } - return (string)$return; - } +/** + * Implementation of hook_theme(). + */ +function uc_attribute_files_theme($existing, $type, $theme, $path) { + return array( + 'uc_product_attributes_files' => array( + 'arguments' => array('element' => NULL), + ), + ); } -function uc_attribute_files_cart_validate($form, &$form_state) { - $cart_id = uc_cart_get_id(); - $_SESSION['uc_attribute_files_cartid']; +/******************************************************* + * Access callbacks + *******************************************************/ - if (is_null(variable_get('uc_attribute_files_cart_filepath', NULL))) { - form_set_error('file', t('Upload to directory failed. Please contact an administrator.')); - return FALSE; - } - $upload_dir = variable_get('uc_attribute_files_cart_filepath', NULL) . '/' . $cart_id; - - //Check if folder exists, or create it. - if (!is_dir($upload_dir) && !@mkdir($upload_dir, 0755, TRUE)) { - form_set_error('file', t('Upload to directory failed. Please contact an administrator.')); - return FALSE; - } +/** + * Access callback for viewing/downloading files +*/ +function uc_attribute_files_user_view_upload_access() { + return (user_access('view attribute uploads') || user_access('view all attribute uploads')); +} - //Validate file type & file was uploaded properly - foreach ($_FILES['files']['name'] as $id => $value) { - foreach ($form['node']['#value']->attributes as $attribute) { - if ($attribute->name == $id) { - //Test to see if there are any options, since they can represent ok file types - $result = db_query("SELECT name FROM {uc_attribute_options} WHERE aid = %d", $attribute->aid); - unset($file_types); +/******************************************************* + * Non core hooks + *******************************************************/ - while ($option = db_fetch_object($result)) { - $file_types[] = strtolower($option->name); - } - if (count($file_types) < 1) { //If there are no options, load the default acceptable file types - $file_types = array_map('strtolower', explode(';', variable_get('uc_attribute_files_file_extensions', NULL))); - } - $filename = file_munge_filename($value, ""); - $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); - if (!in_array($ext, $file_types) && !in_array('*', $file_types)) { - form_set_error($id, t('Sorry, but %label only accepts the following file types: !types', array('%label' => $attribute->label, '!types' => implode(";", $file_types)))); +/** + * Implements hook_add_to_cart_data +*/ +function uc_attribute_files_add_to_cart_data($form_values) { + return array('file_attributes' => $form_values['file_attributes']); +} +/** + * Implements hook_product_description_alter + * Allows us to render our links as desired +*/ +function uc_attribute_files_product_description_alter(&$item, $product) { + if (isset($item['attributes'])) { + foreach ($product->data['file_attributes'] as $aid => $fid) { + $form_key = $aid; + $attribute = db_fetch_object(db_query("SELECT * FROM {uc_attributes} + WHERE aid = %d", $aid)); + if (empty($item['attributes'][$form_key])) { + // We're viewing an order here @see uc_attribute_product_description + // we've been passed attributes keyed arbitrarily instead of aid (fooey) + $ix = 0; + foreach ((array)$product->data['attributes'] as $attribute_name => $option) { + // Try and match our key + if ($attribute_name == $attribute->name || + $attribute_name == $attribute->label) { + $form_key = $ix; + break; + } + $ix++; } - elseif (intval($_FILES['files']['error'][$id]) !== 0 || intval($_FILES['files']['size'][$id]) < 1 || !@copy($_FILES['files']['tmp_name'][$id], $upload_dir . '/' . $filename)) { - form_set_error($id, t('!filename: File upload failed for %label.', array('!filename' => $filename, '%lable' => $attribute->label))); + } + if (empty($item['attributes'][$form_key])) { + // Still no match, make sure we use the attribute name for the $form_key + // otherwise the display is fooey + $form_key = $attribute->label; + } + if ($attribute->display == UC_ATTRIBUTE_FILES_TYPE) { + // We've got a file here - load it + $file = db_fetch_object(db_query('SELECT f.* FROM {files} f WHERE f.fid = %d', $fid)); + if ($file) { + $url = _user_files_generate_url($file->filepath); + // Override the value + $item['attributes'][$form_key]['#options'][0] = l($file->filename, $url); + $item['attributes'][$form_key]['#html'] = TRUE; + // Override the theming so we can pass through the url without a check_plain + $item['attributes']['#theme'] = 'uc_product_attributes_files'; } } } } - return TRUE; -} - -function uc_attribute_files_product_description_alter($item) { - $item['#post_render'][] = "uc_attribute_files_render_links"; return $item; } -function uc_attribute_files_render_links($html) { - preg_match('!\orders?/(\d+)!', $_SERVER[request_uri()], $order); - - if (count($order[1]) > 0) { - $order_user = db_fetch_object(db_query("SELECT uid FROM {uc_orders} WHERE order_id = %d", $order[1])); - $uri = 'uploads/order/' . $order_user->uid . '/' . $order[1] . '/'; - } - else { - $uri = "uploads/cart/"; - } - - preg_match_all('!\[UC_ATTRIBUTE_FILES\](.*)\[/UC_ATTRIBUTE_FILES\]!U', $html, $links); +/******************************************************* + * Module functions + *******************************************************/ +/** + * Util to fetch allowed extensions for an attribute and add them to those + * provided by upload module + * @param $attribute object the attribute object + * @param $validators array of validators keyed by validator function + * @return array of validators +*/ +function uc_attribute_files_fetch_extensions($attribute, $validators) { + $result = db_query("SELECT name FROM {uc_attribute_options} WHERE aid = %d", $attribute->aid); + + $file_types = array(); + while ($option = db_fetch_object($result)) { + $file_types[] = strtolower($option->name); + } + if (count($file_types)) { + $validators['file_validate_extensions'][0] .= ' '. implode(' ', $file_types); + } + return $validators; +} +/** + * Validation function for admin form +*/ +function uc_attribute_files_admin_validate($form, &$form_state) { + $cart_dir = check_plain($form_state['values']['uc_attribute_files_cart_filepath']); + $order_dir = check_plain($form_state['values']['uc_attribute_files_order_filepath']); - for ($x =0; $x < count($links[1]); $x++) { - $find = $links[0][$x]; - $replace = l($links[1][$x], $uri . $links[1][$x]); - $html = str_replace($find, $replace, $html ) ."\n"; + if (!is_dir($cart_dir) && !@mkdir($cart_dir, 0755, TRUE)) { + form_set_error('uc_attribute_files_cart_filepath', t('Could not open or create path:') . $cart_dir); } - return $html; -} -function uc_attribute_files_cron() { - $dir = realpath(variable_get('uc_attribute_files_cart_filepath', NULL) .'/'); - $cart_dirs = array_flip(scandir($dir)); - $result = db_query("SELECT DISTINCT cart_id FROM {uc_cart_products}"); - while ($row = db_fetch_object($result)) { - unset($cart_dirs[$row->cart_id]); - } - unset($cart_dirs['.'], $cart_dirs['..']); - foreach ($cart_dirs as $id => $jnk) { - _uc_attribute_files_rrmdir($dir . $id); + if (!is_dir($order_dir) && !@mkdir($order_dir, 0755, TRUE)) { + form_set_error('uc_attribute_files_order_filepath', t('Could not open or create path:') . $order_dir); } } -function _uc_attribute_files_rrmdir($dir) { - if (is_dir($dir)) { - $objects = scandir($dir); - foreach ($objects as $object) { - if ($object != "." && $object != "..") { - if (filetype($dir . "/" . $object) == "dir") _uc_attribute_files_rrmdir($dir . "/" . $object); else unlink($dir . "/" . $object); +/** + * Submit handler for add to cart +*/ +function uc_attribute_files_cart_submit($form, &$form_state) { + global $user; + $limits = _upload_file_limits($user); + $validators = array( + 'file_validate_extensions' => array($limits['extensions']), + 'file_validate_image_resolution' => array($limits['resolution']), + 'file_validate_size' => array($limits['file_size'], $limits['user_size']), + ); + + // Allow other modules to intervene. + drupal_alter('user_files_validators', $validators); + // Save new file uploads. + foreach ($form_state['values']['node']->attributes as $attribute) { + if (user_access('upload attribute files') && + user_access('own and manage a private file repository') && + $attribute->display == UC_ATTRIBUTE_FILES_TYPE && + isset($_FILES['files']['name']['attributes_'. $attribute->aid]) && + ($full_validators = uc_attribute_files_fetch_extensions($attribute, $validators)) && + ($file = file_save_upload('attributes_'. $attribute->aid, $full_validators, file_create_path('user-files')))) { + // Store our fid against the attribute for uc to find + if (empty($form_state['values']['file_attributes'])) { + $form_state['values']['file_attributes'] = array(); + } + $form_state['values']['file_attributes'][$attribute->aid] = $file->fid; + if ($user->uid != 0) { + file_set_status($file, FILE_STATUS_PERMANENT); + } + else { + // Remove lazy session handler (pressflow), uc's cart_order_id takes over from here + unset($_SESSION['uc_attribute_files']); + $result = _user_files_assoc_anon($file->fid); + if ($result == FALSE) { + drupal_set_message(t('Could not associate anonymous user with file')); + watchdog('user_files', t('Could not associate anonymous user with file')); + form_set_error('', t('Session failure')); + } + } + } + else { + // Make sure they actually uploaded something here (could be optional) + if (!empty($_FILES['files']['name']['attributes_'. $attribute->aid])) { + drupal_set_message(t('Could not upload your file.'), 'error'); + // Redirect them back to the node (immediately, do not pass go and all that) + drupal_goto('node/'. $form_state['values']['node']->nid); + } + if ($attribute->display == UC_ATTRIBUTE_FILES_TYPE) { + // Don't indicate we've got something here + unset($form_state['values']['attributes'][$attribute->aid]); } } - reset($objects); - rmdir($dir); - } -} - -function uc_attribute_files_user($op, &$edit, &$user, $category = NULL) { - switch ($op) { - case 'login': - $dir = realpath(variable_get('uc_attribute_files_cart_filepath', NULL)); - uc_attribute_files_move_files($dir . "/" . $edit['uc_attribute_files_cartid'], $dir . '/' . uc_cart_get_id()); - break; } } - -function uc_attribute_files_move_files($old_dir, $new_dir) { - if (is_dir($old_dir)) { - if (!is_dir($new_dir) && !@mkdir($new_dir, 0755, TRUE)) { - return FALSE; - } - foreach (scandir($old_dir) as $file) { - if ($file == '.' || $file == '..') { - continue; +/********************************************* + * Theme callbacks +**********************************************/ +/** + * Theme override for the module so we can show our elements as links if needs be +*/ +function theme_uc_product_attributes_files($element) { + $option_rows = array(); + foreach (element_children($element) as $key) { + $optionstr = ''; + + foreach ((array)$element[$key]['#options'] as $option) { + // We only need to allow translation from the second option onward + if (empty($optionstr)) { + $optionstr .= $option; + } + else { + $optionstr .= t(', !option', array('!option' => $option)); } - @rename($old_dir . '/' . $file, $new_dir . '/' . $file); } - _uc_attribute_files_rrmdir($old_dir); + if (!empty($element[$key]['#html'])) { + $option_rows[$key] = t('@attribute: !option', array('@attribute' => $element[$key]['#attribute_name'], '!option' => $optionstr)); + } + else { + $option_rows[$key] = t('@attribute: @option', array('@attribute' => $element[$key]['#attribute_name'], '@option' => $optionstr)); + } } -} -function uc_attribute_files_order($op, &$arg1, $arg2) { - global $user; - switch ($op) { - case 'submit': - $cart_dir = variable_get('uc_attribute_files_cart_filepath', NULL) . '/' . uc_cart_get_id(); - $order_dir = variable_get('uc_attribute_files_order_filepath', NULL) . '/' . $user->uid . '/' . $arg1->order_id; - uc_attribute_files_move_files($cart_dir, $order_dir); - break; + if (!empty($option_rows)) { + return theme('item_list', array_values($option_rows), NULL, 'ul', array('class' => 'product-description')); } -} -function uc_attribute_files_preprocess_table(&$variables) { - print_r("printed"); -} + return ''; +} \ No newline at end of file