uid == $node->uid)))); } /** * Access used within Ubercart Marketplace */ function mp_file_uc_mp_feature_access() { global $user; return ((user_access('administer product features') || (user_access('administer own product features') && ($user->uid == $node->uid)))); } /** * An element process callback for the mp_file_widget. * * Includes the option to commit files to product features. */ function mp_file_widget_process($element, $edit, &$form_state, $form) { $element['data']['commit'] = array( '#type' => variable_get('mp_file_show_commit_checkbox', TRUE) ? 'checkbox' : 'hidden', '#title' => t('Commit file to product feature'), '#default_value' => FALSE, '#value' => variable_get('mp_file_allow_sellers_perm', FALSE), '#access' => mp_file_uc_mp_feature_access(), ); return $element; } /** * An element validate callback for the mp_file_widget. */ function mp_file_widget_validate($element, &$form_state) { ; } /** * Implements hook_nodeapi(). */ function mp_file_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { if (mp_file_product_class_is_enabled($node->type)) {//in_array(, variable_get('mp_product_tools_enabled_classes', array()))) { if ($op === 'insert' || $op === 'update') { if ($node->mp_file_attached) { $file_committed = mp_file_commit($node, $node->mp_file_path, $node->mp_file_description, $node->mp_file_title, $node->mp_file_fid); if ($file_committed == TRUE) { mp_file_clear_filefield($node->mp_file_fid, $node->mp_file_path); drupal_set_message(t('The file was attached to this product. For security reasons, it has now been hidden from the product edit form.')); } } } elseif ($op === 'load') { $node->feature_count = 0; $node->feature_file_name = array(); $result = db_query("SELECT * FROM {uc_product_features} WHERE nid = %d AND fid = 'file' ORDER BY pfid ASC", $node->nid); while ($feature = db_fetch_object($result)) { preg_match_all("|]+>(.*)<[^>]+>|U", $feature->description, $out, PREG_PATTERN_ORDER); $node->feature_file_name[$feature->pfid] = $out[1][1]; $node->feature_count = $node->feature_count + 1; } } elseif ($op === 'prepare') { if (empty($node->feature_file_name)) { $node->feature_file_name = array(); } } } } /** * Checks to see if this product class has mp_file features enabled */ function mp_file_product_class_is_enabled($product_class) { if ($product_class) { if (module_exists('mp_product_tools')) { // Is this even a marketplace product? if (in_array($product_class, variable_get('mp_product_tools_enabled_classes', array()))) { $enabled_mp_file_classes = array(); $classes = db_query("SELECT pcid FROM {mp_file_class_settings} WHERE enabled = 1"); while ($class = db_fetch_object($classes)) { $enabled_mp_file_classes[] = $class->pcid; } return in_array($product_class, $enabled_mp_file_classes); } else { FALSE; // This is a standard Ubercart product (non-marketplace) } } else { TRUE; // If we aren't managing classes, assume we want this product to be digital (otherwise why even enable mp_file?) } } else { return FALSE; } } /** * Implements hook_form_alter(). */ function mp_file_form_alter(&$form, $form_state, $form_id) { // Strip the class name from the form name, if this is a product class form $position = strpos($form_id, "_node_form"); $product_class = $position ? substr($form_id, 0, $position) : NULL; switch ($form_id) { case mp_file_product_class_is_enabled($product_class): // Append data to the field download data $field_name = 'field_'. variable_get('mp_file_field_name', 'download'); // Sift through the elements to add custom process and validation functions to every upload field (should probably just do the first occurance...) foreach (element_children($form[$field_name]) as $key) { if ($form[$field_name][$key]['#type'] == 'filefield_widget') { // Include original process and validation functions and append custom mp_file_widget_process and mp_file_widget_validate $form[$field_name][$key]['#process'] = array('filefield_widget_process', 'imagefield_widget_widget_process', 'mp_file_widget_process'); $form[$field_name][$key]['#element_validate'] = array('filefield_widget_validate', 'imagefield_widget_validate', 'mp_file_widget_validate'); } } // Maybe this should be themed? $form[t($field_name)]['mp_file_title'] = array( '#type' => (0 < $form['#node']->feature_count) && variable_get('mp_file_show_feature_list', TRUE) ? 'markup' : 'hidden', '#prefix' => '
', '#value' => variable_get('mp_file_replace_feature_on_upload', FALSE) ? 'These features will be replaced when a new product is uploaded:' : 'Delete existing product(s)?', '#suffix' => '
', '#weight' => t($form[t($field_name)]['#weight'] + 1), ); // Product features... if (!empty($form['#node']->feature_file_name)) { foreach ($form['#node']->feature_file_name as $pfid => $filename) { $form[t($field_name)]['mp_file_pfid_' . t($pfid)] = array( '#type' => variable_get('mp_file_show_feature_list', TRUE) ? 'checkbox' : 'hidden', '#title' => t($filename), '#default_value' => variable_get('mp_file_replace_feature_on_upload', FALSE), '#disabled' => variable_get('mp_file_replace_feature_on_upload', FALSE), '#weight' => t($form[t($field_name)]['#weight'] + 2), ); } } $form['feature_count'] = array( '#type' => 'hidden', '#value' => $form['#node']->feature_count, ); // Add our own additional form validation and submission functions $form['#validate'][] = 'mp_file_form_validate'; $form['#submit'][] = 'mp_file_form_submit'; break; case 'mp_marketplace_settings_seller_form': $form['mp_file_fieldset']['mp_file_replace_feature_on_upload'] = array( '#type' => 'checkbox', '#title' => t('Replace feature on upload'), '#description' => t('The existing feature(s) will be overwritten automatically by the newest feature uploaded.'), '#default_value' => variable_get('mp_file_replace_feature_on_upload', FALSE), ); $form['mp_file_fieldset']['mp_file_require_upload'] = array( '#type' => 'checkbox', '#title' => t('Require feature'), '#description' => t('Requires at least one file feature be attached to the product.'), '#default_value' => variable_get('mp_file_require_upload', FALSE), ); // Could probably do this through theming... $form['mp_file_fieldset']['mp_file_show_commit_checkbox'] = array( '#type' => 'checkbox', '#title' => t('Show commit feature checkbox'), '#description' => t('Shows the commit feature checkbox. Useful if you always plan to, or not to, commit files'), '#default_value' => variable_get('mp_file_show_commit_checkbox', TRUE), ); // Could probably do this through theming... $form['mp_file_fieldset']['mp_file_show_feature_list'] = array( '#type' => 'checkbox', '#title' => t('Show feature list on node form'), '#description' => t('Shows a feature list on the node form. Useful for viewing feature information directly on the node form'), '#default_value' => variable_get('mp_file_show_feature_list', TRUE), ); break; } return $form; } function mp_file_form_validate($form, &$form_state) { $field_name = 'field_'. variable_get('mp_file_field_name', 'download'); $feature_count = $form_state['values']['feature_count']; $upload_filename = $form_state['values'][t($field_name)]['0']['filename']; if (variable_get('mp_file_require_upload', FALSE) && empty($feature_count) && empty($upload_filename)) { form_set_error(t($field_name), t('No file upload attached.')); } } function mp_file_form_submit($form, &$form_state) { if (mp_file_uc_mp_feature_access() || variable_get('mp_file_allow_sellers_perm', FALSE) ) { // Get ready to commit a file if necessary $field_name = 'field_'. variable_get('mp_file_field_name', 'download'); $field = $form_state['values'][$field_name]; // Collect file features/downloads that are to be deleted, FIX ME, the code below is overkill... $delete_all_files = TRUE; $pfid_array = array(); foreach ($field as $key => $value) { if (drupal_substr($key, 0, drupal_strlen('mp_file_pfid_')) == 'mp_file_pfid_') { $pfid = drupal_substr($key, drupal_strlen('mp_file_pfid_')); $pfid_array[$pfid] = variable_get('mp_file_replace_feature_on_upload', FALSE) ? TRUE : $value; // Is there a $pfid we aren't deleting? if ($pfid_array[$pfid] == FALSE) { $delete_all_files = FALSE; } } } if (empty($pfid_array)) { $delete_all_files = FALSE; } $feature_uploaded = !empty($field[0]['filepath']); $commit_feature = $field[0]['data']['commit']; $file_committed = FALSE; if ($feature_uploaded) { $description = check_plain($field[0]['description']); $file_path = $field[0]['filepath']; $fid = $field[0]['fid']; $title = $nodearray['title']; if ($commit_feature && variable_get('mp_file_allow_sellers_perm', FALSE)) { // nid is not available for new nodes so we have to call mp_file commit // from nodeapi (an oversite on my part which is leading to less than simple code) $form_state['values']['mp_file_attached'] = TRUE; $form_state['values']['mp_file_path'] = $file_path; $form_state['values']['mp_file_description'] = $description; $form_state['values']['mp_file_title'] = $title; $form_state['values']['mp_file_fid'] = $fid; $file_committed = TRUE; } else { mp_file_clear_filefield($fid, $file_path); } } if ($file_committed || !$delete_all_files) { mp_file_delete_features($pfid_array); } elseif ($delete_all_files == TRUE && !variable_get('mp_file_replace_feature_on_upload', FALSE)) { drupal_set_message(t("Cannot delete all existing products unless a new product is uploaded."), 'error'); } } } /** * Clears file from filefield and deletes file from files directory. * Necessary as a security feature. * * NOTE: Bypasses call to hook_filefield('file_delete') */ function mp_file_clear_filefield($fid, $file_path) { db_query('DELETE FROM {files} WHERE fid = %d', $fid); return file_delete($file_path); } /** * Transfers file download from files directory to file download directory. * Programatically fills out "product feature form" to commit file. * * TODO: add support for model field */ function mp_file_commit($node, $file_path, $description, $title, $fid) { // Check if paths are correctly set $dir = variable_get('uc_file_base_dir', NULL) .'/'; if (!is_dir($dir)) { drupal_set_message('File download directory not set.', 'error'); return FALSE; } // Rename file... $file_name = drupal_substr(filename($file_path), 0, strrpos(filename($file_path), ".")); $file_name_ext = drupal_substr(filename($file_path), strrpos(filename($file_path), ".") + 1); $new_name_hook = module_invoke_all('mp_file_name', $dir, $file_name, $file_name_ext, $node->nid, $title); $new_name = $new_name_hook[count($new_name_hook)-1]; // Finally, copy the file to a more secure directory copy($file_path, $dir . $new_name); //Insert the file to the uc_files table so it will pass validation $result = db_query("INSERT INTO {uc_files} (filename) VALUES ('%s')", $new_name); // programatically fill out product feature form $form_state = Array(); $form_state['values']['uc_file_filename'] = $new_name; $form_state['values']['uc_file_description'] = $description; $submitted = drupal_execute('uc_file_feature_form', $form_state, $node, array()); return TRUE; } /** * Implements hook_mp_file_name(). * * Returns the filename to be used for this feature. */ function mp_file_mp_file_name($dir, $file_name, $file_name_ext, $node_id, $title ,$new_name_hook ) { $node_sanitized_title = preg_replace('/[^0-9a-z\.\_\-]/i', '', $title); $new_file_name = $node_id . "_" . $file_name . "." . $file_name_ext; // We could now return $new_file_name but first let's rename it if this file name already exists. // NB: $file_name also has a counter in it for files in the temp directory $i_file = 0; while (file_exists($dir . $new_file_name)) { $i_file++; $new_file_name = $node_id . "_" . $file_name . "_" . sprintf('%03d', $i_file) . "." . $file_name_ext; } return $new_file_name; } /** * Deletes features listed in the $pfid_array as true */ function mp_file_delete_features($pfid_array) { $fid = 'file'; foreach ($pfid_array as $pfid => $delete_feature) { if ($delete_feature) { mp_file_remove_feature($pfid, $fid); } } } /** * Deletes a given feature programmatically */ function mp_file_remove_feature($pfid, $fid) { $result = db_query("SELECT * FROM {uc_product_features} WHERE pfid = %d AND fid = '%s'", intval($pfid), $fid); if ($feature = db_fetch_array($result)) { // Call the delete function for this product feature if it exists. $func = uc_product_feature_data($feature['fid'], 'delete'); if (function_exists($func)) { // $func($feature) should be equivalent to either of the following // (1) uc_file_feature_delete($feature); // (2) db_query("DELETE FROM {uc_file_products} WHERE pfid = %d", $feature['pfid']); $func($feature); } // Remove the product feature data from the database. db_query("DELETE FROM {uc_product_features} WHERE pfid = %d", intval($pfid)); drupal_set_message(t('Product feature ' . t($pfid) . ' has been deleted.')); } else { drupal_set_message(t("Product feature could not be deleted because it doesn't exist."), 'error'); } }