? contrib/ec_media
Index: file/file.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ecommerce/file/file.module,v
retrieving revision 1.37
diff -u -F^f -r1.37 file.module
--- file/file.module 31 May 2006 04:53:03 -0000 1.37
+++ file/file.module 31 May 2006 18:16:24 -0000
@@ -142,6 +142,15 @@ function file_productapi(&$node, $op, $a
'#type' => 'fieldset',
'#title' => t('File settings'),
);
+ if (_ec_file_is_managed($node->nid)) {
+ $description = t('Do not edit. File is managed by %nodetype node.',
+ array('%nodetype' => $node->type));
+ $attributes = array('disabled' => 'disabled');
+ }
+ else {
+ $description = t('Enter the filesystem path to this file (not the URL). This path will be prefixed with %file_path/ Here is a list of files in this directory. You may need to FTP your file to this directory before you can create the file product.', array('%file_quicklist' => url('admin/store/products/files'), '%file_path' => variable_get('file_directory_path', 'files')));
+ $attribues = NULL;
+ }
$form['f_settings']['fpath'] = array(
'#type' => 'textfield',
'#title' => t('File path'),
@@ -149,7 +158,8 @@ function file_productapi(&$node, $op, $a
'#size' => 50,
'#maxlength' => 200,
'#autocomplete_path' => 'ec_file/autocomplete',
- '#description' => t('Enter the filesystem path to this file (not the URL). This path will be prefixed with %file_path/ Here is a list of files in this directory. You may need to FTP your file to this directory before you can create the file product.', array('%file_quicklist' => url('admin/store/products/files'), '%file_path' => variable_get('file_directory_path', 'files'))),
+ '#description' => $description,
+ '#attributes' => $attributes,
);
$output = $form;
@@ -164,15 +174,18 @@ function file_productapi(&$node, $op, $a
/* Node has been saved, write to product tables. */
case 'insert':
- return db_query("INSERT INTO {ec_product_file} (nid, fpath, size) VALUES (%d, '%s', '%s')", $node->nid, $node->fpath, $node->size);
+ if (!_ec_file_is_managed($node->nid))
+ return db_query("INSERT INTO {ec_product_file} (nid, fpath, size) VALUES (%d, '%s', '%s')", $node->nid, $node->fpath, $node->size);
break;
case 'update':
- return db_query("UPDATE {ec_product_file} SET fpath = '%s', size = '%s' WHERE nid = %d", $node->fpath, $node->size, $node->nid);
+ if (!_ec_file_is_managed($node->nid))
+ return db_query("UPDATE {ec_product_file} SET fpath = '%s', size = '%s' WHERE nid = %d", $node->fpath, $node->size, $node->nid);
break;
case 'delete':
- return db_query("DELETE FROM {ec_product_file} WHERE nid = %d", $node->nid);
+ if (!_ec_file_is_managed($node->nid))
+ return db_query("DELETE FROM {ec_product_file} WHERE nid = %d", $node->nid);
break;
}
}
@@ -396,10 +409,6 @@ function ec_file_create_url($path) {
if (user_access('administer store')) {
$uid = arg(2);
}
-
- if (strpos($path, variable_get('ec_file_directory_path', 'files')) !== false) {
- $path = trim(substr($path, strlen(variable_get('ec_file_directory_path', 'files'))), '\\/');
- }
return url("store/myfiles/$uid/download", 'file='. urlencode($path));
}
@@ -409,7 +418,7 @@ function ec_file_create_url($path) {
* file system directory.
*
* @param $dest Path to verify
- * @return Path to file with file system directory appended if necessary.
+ * @return Path to file with file system directory prepended if necessary.
* Returns FALSE if the path is invalid (i.e. outside the configured 'files'-directory).
*/
function ec_file_create_path($dest = 0) {
@@ -437,24 +446,44 @@ function ec_file_create_path($dest = 0)
* Call modules to find out if a file is accessible for a given user.
*/
function ec_product_download() {
- $file = $_GET['file'];
+ $file = urldecode($_GET['file']);
if (file_exists(ec_file_create_path($file))) {
- $list = module_list();
- foreach ($list as $module) {
- $headers = ec_file_build_download($file);
- if (!$headers) {
- drupal_access_denied();
- }
- elseif (is_array($headers)) {
- ec_file_transfer($file, $headers);
- }
+ $headers = ec_file_build_download($file);
+ if (!$headers) {
+ drupal_access_denied();
+ return;
+ }
+ elseif (is_array($headers)) {
+ ec_file_transfer($file, $headers);
}
}
drupal_not_found();
}
+function ec_file_may_download($file, $uid) {
+ // TODO: cache results to avoid repeated queries
+
+ /* Check invoice and expiration dates... */
+
+ $expired_length = variable_get('file_expired', '7') * 86400; // Convert expiration to seconds
+ $max_expired_date = time() + $expired_length; // Absolute longest expiration date.
+
+ $data = db_fetch_object(db_query("SELECT st.created, st.expires FROM {ec_transaction} AS st, {users} AS u, {ec_product} AS p, {ec_product_file} AS pf, {ec_transaction_product} AS stp WHERE u.uid = st.uid AND st.uid = %d AND p.nid = stp.nid AND st.txnid = stp.txnid AND pf.nid = p.nid AND st.payment_status = '2' AND pf.fpath = '%s'", $uid, $file));
+
+ /* Expiration date is found via the sitewide file expiration date OR
+ the special case where a store admin has extended the expiration date for
+ a given transaction. The 'special case' always take precedence, so you can
+ disable downloads before the sitewide expiration date is reached. */
+ if ($data &&
+ (($data->created + $expired_length < $max_expired_date && !$data->expires) ||
+ ($data->expires && $data->expires > time()))) {
+ return TRUE;
+ }
+}
+
/**
- * Implementation of the file_download_hook() to find out if a file is accessible for a given user.
+ * Generate headers necessary for a file download. First check that user is
+ * able to download the file.
*/
function ec_file_build_download($file) {
@@ -465,33 +494,20 @@ function ec_file_build_download($file) {
$uid = arg(2);
}
- /* Check invoice and expiration dates... */
-
- $expired_length = variable_get('file_expired', '7') * 86400; // Convert expiration to seconds
- $max_expired_date = time() + $expired_length; // Absolute longest expiration date.
-
- $data = db_fetch_object(db_query("SELECT st.created, st.expires FROM {ec_transaction} AS st, {users} AS u, {ec_product} AS p, {ec_product_file} AS pf, {ec_transaction_product} AS stp WHERE u.uid = st.uid AND st.uid = %d AND p.nid = stp.nid AND st.txnid = stp.txnid AND pf.nid = p.nid AND st.payment_status = '2' AND pf.fpath = '%s'", $uid, $file));
-
- /* Expiration date is found via the sitewide file expiration date OR
- the special case where a store admin has extended the expiration date for
- a given transaction. The 'special case' always take precedence, so you can
- disable downloads before the sitewide expiration date is reached. */
- if (($data->created + $expired_length < $max_expired_date && !$data->expires) ||
- ($data->expires && $data->expires > time())) {
-
+ if (ec_file_may_download($file, $uid)) {
$filename = basename($file);
if (file_iemac_hack()) {
if (strlen($filename) > 30) {
$filename = substr($filename, strlen($filename) - 30);
}
}
-
+
$file = ec_file_create_path($file);
$header[] = 'Content-type: application/x-download';
$header[] = 'Content-Disposition: attachment; filename="'. $filename .'";';
$header[] = 'Accept-Ranges: bytes';
$header[] = 'Content-Length: '. filesize($file);
-
+
return $header;
}
else {
@@ -537,3 +553,117 @@ function ec_file_autocomplete($string) {
print drupal_implode_autocomplete($matches);
exit();
}
+
+/**
+ * Node-managed file functions
+ *
+ * The following hooks allow third-party modules which contain files to treat
+ * their files as products. This module allows downloads only when the
+ * products have been purchased.
+ *
+ * See also the ec_media module (ecommerce/contrib/ec_media).
+ */
+
+/**
+ * Determine which node types are eligible to be treated as products.
+ *
+ * Invokes hook_ec_file_nodetypes. Third-party modules must implement that
+ * hook to be treated as products.
+ */
+function _ec_file_get_managed_types() {
+ static $cache;
+ if (!$cache) {
+ $cache = module_invoke_all('ec_file_nodetypes');
+ }
+ return $cache;
+}
+
+/**
+ * Determine whether a node is an instance of a node-managed product.
+ */
+function _ec_file_is_managed($nid) {
+ $node = node_load($nid);
+ return in_array($node->type, array_keys(_ec_file_get_managed_types()));
+}
+
+/**
+ * Returns settings specific to nodes of the given type.
+ */
+function _ec_file_managed_settings($node) {
+ $settings = _ec_file_get_managed_types();
+ return $settings[$node->type];
+}
+
+/**
+ * hook_file_ec_file_event
+ *
+ * Notification of a file-related event.
+ *
+ * @param $fid
+ * Numerical file ID.
+ * @param $realm
+ * Textual file-type identifier. The $fid and $realm combine to form a unique ID for the file.
+ * @param $node
+ * Node with which the file is associated.
+ * @param $op
+ * Type of event which has occurred. (I.e. 'insert', 'update', 'delete')
+ * @param $info
+ * Associative array of information about the file. Should contain at a minimum 'filepath' and 'filesize'.
+ *
+ * @return
+ * none
+ */
+function file_ec_file_event($fid, $realm, $node, $op, $info) {
+ if (!_ec_file_is_managed($node->nid))
+ return;
+
+ if (($settings = _ec_file_managed_settings($node)) &&
+ ($settings['realm'] == $realm)) {
+ // The file managed by the node type has changed. Keep our data in sync.
+ if ($op == 'insert') {
+ db_query("INSERT INTO {ec_product_file} (nid, fpath, size) VALUES (%d, '%s', '%s')", $node->nid, $info->filepath, $info->filesize);
+ }
+ else if ($op == 'update') {
+ db_query("UPDATE {ec_product_file} SET fpath = '%s', size = '%s' WHERE nid = %d", $info->filepath, $info->filesize, $node->nid);
+ }
+ else if ($op == 'delete') {
+ db_query("DELETE FROM {ec_product_file} WHERE nid = %d", $node->nid);
+ }
+ }
+}
+
+/**
+ * hook_file_ec_file_access
+ *
+ * Grant permission to access files. This implementation allows us to grant
+ * downloads only to users who have purchased files.
+ *
+ * @param $fid
+ * Numerical file ID.
+ * @param $realm
+ * Textual file-type identifier. The $fid and $realm combine to form a unique ID for the file.
+ * @param $node
+ * Node with which the file is associated.
+ * @param $op
+ * Type of access requested. (I.e. 'view', 'download')
+ * @param $info
+ * Associative array of information about the file. Should contain at a minimum 'filepath'.
+ * @param $account
+ * The user data structure for the account requesting permission.
+ *
+ * @return
+ * TRUE, only if user is allowed access to the file.
+ */
+function file_ec_file_access($fid, $realm, $node, $op, $info, $account) {
+ if ($node->ptype != 'file')
+ return;
+
+ if (($settings = _ec_file_managed_settings($node)) &&
+ ($settings['realm'] == $realm)) {
+ // The file is one we oversee.
+ if ($op == 'view' || $op == 'download') {
+ //Check that user may download.
+ return ec_file_may_download($info->filepath, $account->uid);
+ }
+ }
+}