Commit 7f36bd87 authored by Eric Rasmussen's avatar Eric Rasmussen
Browse files

[gh-417] Upgrade Media suite to latest versions

parent b34db6bb
......@@ -49,7 +49,7 @@ function file_entity_admin_files($form, &$form_state) {
// Build the sortable table header.
$header = array(
'title' => array('data' => t('Title'), 'field' => 'f.filename'),
'type' => array('data' => t('Type'), 'field' => 'f.filemime'),
'type' => array('data' => t('Type'), 'field' => 'f.type'),
'size' => array('data' => t('Size'), 'field' => 'f.filesize'),
'author' => array('data' => t('Author'), 'field' => 'u.name'),
'timestamp' => array('data' => t('Updated'), 'field' => 'f.timestamp', 'sort' => 'desc'),
......@@ -63,6 +63,8 @@ function file_entity_admin_files($form, &$form_state) {
$query->condition('f.status', FILE_STATUS_PERMANENT);
$query->limit($limit);
$query->orderByHeader($header);
$query->addTag('admin_files');
$query->addMetaData('form_state', $form_state);
foreach (array_keys(file_entity_get_hidden_stream_wrappers()) as $name) {
$query->condition('f.uri', $name . '%', 'NOT LIKE');
......@@ -83,14 +85,26 @@ function file_entity_admin_files($form, &$form_state) {
$destination = drupal_get_destination();
$options = array();
foreach ($files as $file) {
$file_type = file_type_load($file->type);
$options[$file->fid] = array(
'title' => theme('file_entity_file_link', array('file' => $file)),
'type' => check_plain($file->filemime),
'type' => $file_type ? check_plain($file_type->label) : FILE_TYPE_NONE,
'size' => format_size($file->filesize),
'author' => theme('username', array('account' => $accounts[$file->uid])),
'timestamp' => format_date($file->timestamp, 'short'),
);
// Show a warning for files that do not exist.
if (@!file_exists($file->uri)) {
$options[$file->fid]['#attributes']['class'][] = 'error';
if (!file_stream_wrapper_get_instance_by_uri($file->uri)) {
$options[$file->fid]['#attributes']['title'] = t('The stream wrapper for @scheme files is missing.', array('@scheme' => file_uri_scheme($file->uri)));
}
else {
$options[$file->fid]['#attributes']['title'] = t('The file does not exist.');
}
}
$options[$file->fid]['operations'] = array(
'data' => array(
'#theme' => 'links__file_operations',
......@@ -98,18 +112,20 @@ function file_entity_admin_files($form, &$form_state) {
'#attributes' => array('class' => array('links', 'inline')),
),
);
$options[$file->fid]['operations']['data']['#links']['edit'] = array(
'title' => t('Edit'),
'href' => 'file/' . $file->fid . '/edit',
'query' => $destination,
);
$options[$file->fid]['operations']['data']['#links']['delete'] = array(
'title' => t('Delete'),
'href' => 'file/' . $file->fid . '/delete',
'query' => $destination,
);
if (file_entity_access('edit', $file)) {
$options[$file->fid]['operations']['data']['#links']['edit'] = array(
'title' => t('Edit'),
'href' => 'file/' . $file->fid . '/edit',
'query' => $destination,
);
}
if (file_entity_access('delete', $file)) {
$options[$file->fid]['operations']['data']['#links']['delete'] = array(
'title' => t('Delete'),
'href' => 'file/' . $file->fid . '/delete',
'query' => $destination,
);
}
}
$form['files'] = array(
......@@ -172,23 +188,25 @@ function file_entity_admin_files_submit($form, &$form_state) {
* Displays the file type admin overview page.
*/
function file_entity_list_types_page() {
$types = file_info_file_types();
$entity_info = entity_get_info('file');
$file_entity_info = entity_get_info('file');
$field_ui = module_exists('field_ui');
$header = array(
array('data' => t('Name')),
array('data' => t('Operations'), 'colspan' => $field_ui ? '3' : '1'),
array('data' => t('Operations'), 'colspan' => $field_ui ? '4' : '2'),
);
$rows = array();
foreach ($types as $type => $info) {
$row = array(array('data' => theme('file_entity_file_type_overview', $info)));
$path = isset($entity_info['bundles'][$type]['admin']['real path']) ? $entity_info['bundles'][$type]['admin']['real path'] : NULL;
foreach (file_type_get_all_types(TRUE) as $type) {
$row = array(array('data' => theme('file_entity_file_type_overview', array('label' => $type->label, 'description' => $type->description))));
$path = isset($file_entity_info['bundles'][$type->type]['admin']['real path']) ? $file_entity_info['bundles'][$type->type]['admin']['real path'] : NULL;
$row[] = array('data' => isset($path) ? l(t('edit file type'), $path . '/edit') : '');
if ($field_ui) {
$row[] = array('data' => isset($path) ? l(t('manage fields'), $path . '/fields') : '');
$row[] = array('data' => isset($path) ? l(t('manage display'), $path . '/display') : '');
}
$row[] = array('data' => isset($path) ? l(t('manage file display'), $path . '/file-display') : '');
$rows[] = $row;
}
......@@ -206,6 +224,8 @@ function file_entity_list_types_page() {
* Form callback; presents file display settings for a given view mode.
*/
function file_entity_file_display_form($form, &$form_state, $file_type, $view_mode) {
$file_type = $file_type->type;
$form['#file_type'] = $file_type;
$form['#view_mode'] = $view_mode;
$form['#tree'] = TRUE;
......@@ -345,3 +365,119 @@ function theme_file_entity_file_display_order($variables) {
return $output;
}
/**
* Form constructor for the file type settings form.
*
* @param object $type
* The file type.
*
* @see file_entity_file_type_form_validate()
* @see file_entity_file_type_form_submit()
*/
function file_entity_file_type_form($form, &$form_state, $type) {
$form['#file_type'] = $type->type;
$form['label'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#description' => t('This is the human readable name of the file type.'),
'#required' => TRUE,
'#default_value' => $type->label,
);
$form['description'] = array(
'#type' => 'textarea',
'#title' => t('Description'),
'#description' => t('This is the description of the file type.'),
'#default_value' => $type->description,
);
$form['mimetypes'] = array(
'#type' => 'textarea',
'#title' => t('Mimetypes'),
'#description' => t('Enter one mimetype per line.'),
'#default_value' => implode("\n", $type->mimetypes),
);
include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
$mimetypes = file_mimetype_mapping();
$form['mimetype_mapping'] = array(
'#type' => 'fieldset',
'#title' => t('Mimetype List'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['mimetype_mapping']['mapping'] = array(
'#theme' => 'item_list',
'#items' => $mimetypes['mimetypes'],
);
// Options for allowed Streams.
$options = array('public' => t('Public files'), 'private' => t('Private files'));
foreach (file_get_stream_wrappers() as $stream => $wrapper) {
$options[$stream] = $wrapper['name'];
}
unset($options['temporary']);
$default_value = array();
if (isset($type->streams)) {
foreach ($type->streams as $stream) {
$default_value[$stream] = $stream;
}
}
$form['streams'] = array(
'#type' => 'checkboxes',
'#title' => t('Allowed streams'),
'#options' => $options,
'#default_value' => $default_value,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
/**
* Form validation handler for file_entity_file_type_form().
*
* @see file_entity_file_type_form_submit()
*/
function file_entity_file_type_form_validate($form, &$form_state) {
include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
$mimetype_mapping = file_mimetype_mapping();
$valid_mimetypes = $mimetype_mapping['mimetypes'];
$submitted_mimetypes = array_filter(array_map('trim', explode("\n", $form_state['values']['mimetypes'])));
$invalid_mimetypes = array_diff($submitted_mimetypes, $valid_mimetypes);
foreach ($invalid_mimetypes as $mimetype) {
form_set_error('mimetypes', t('The mimetype %mimetype is not a valid mimetype.', array('%mimetype' => $mimetype)));
}
}
/**
* Form submission handler for file_entity_file_type_form().
*
* @see file_entity_file_type_form_validate()
*/
function file_entity_file_type_form_submit($form, &$form_state) {
$type = file_type_load($form['#file_type']);
$type->label = $form_state['values']['label'];
$type->description = $form_state['values']['description'];
$type->mimetypes = array_filter(array_map('trim', explode("\n", $form_state['values']['mimetypes'])));
$type->streams = array();
foreach ($form_state['values']['streams'] as $stream) {
if ($stream) {
$type->streams[] = $stream;
}
}
file_type_save($type);
drupal_set_message(t('The file type %type has been updated.', array('%type' => $type->label)));
$form_state['redirect'] = 'admin/structure/file-types';
}
......@@ -6,61 +6,56 @@
*/
/**
* Define file types.
* Declare that your module provides default file types.
*
* @return
* An array whose keys are file type names and whose values are arrays
* describing the file type, with the following key/value pairs:
* - label: The human-readable name of the file type.
* - default view callback: (optional) The name of the function that returns a
* drupal_render() array for displaying the file. Used when there are no
* administrator configured file formatters, or none of the configured ones
* return a display. See hook_file_type_TYPE_default_view() for details.
* - description: (optional) A short description of the file type.
* - weight: (optional) A number defining the order in which the 'claim
* callback' function for this type is called relative to the claim
* callbacks of other defined types, when the type of a file needs to be
* determined. The type with the lowest weighted claim callback to return
* TRUE is assigned to the file. Also, on administrative pages listing file
* types, the types are ordered by weight.
* - admin: (optional) An array of information, to be added to the
* ['bundles'][TYPE]['admin'] entry for the 'file' entity type, thereby
* controlling the path at which Field UI pages are attached for this file
* type, and which users may access them. Defaults to attaching the Field UI
* pages to the admin/structure/file-types/manage/TYPE path and requiring
* 'administer site configuration' permission. See hook_entity_info() for
* details about this array. This value can also be set to NULL to suppress
* Field UI pages from attaching at all for this file type.
*
* @see hook_file_type_info_alter()
* Your module may already implement this hook for other CTools plugin types.
* If so, copy the body of this function into the existing hook.
*/
function hook_file_type_info() {
return array(
'image' => array(
'label' => t('Image'),
),
);
function hook_ctools_plugin_api($owner, $api) {
if ($owner == 'file_entity' && $api == 'file_type') {
return array('version' => 1);
}
}
/**
* Perform alterations on file types.
* Define default file types.
*
* @param $info
* Array of information on file types exposed by hook_file_type_info()
* implementations.
* File types are implemented as CTools exportables, so modules can alter the
* defaults via hook_file_default_types_alter(), and the administrator can
* save overridden and custom types to the {file_type} database table.
*
* @return array
* An array whose keys are file type names and whose values are objects
* representing the file type, with the following key/value pairs:
* - api_version: The version of this data.
* - type: The file type name.
* - label: The human-readable name of the file type.
* - description: The description of this file type.
* - mimetypes: An array of mimetypes that this file type will map to.
*/
function hook_file_type_info_alter(&$info) {
// @todo Add example.
function hook_file_default_types() {
return array(
'image' => (object) array(
'api_version' => 1,
'type' => 'image',
'label' => t('Image'),
'description' => t("An <em>Image</em> is a two-dimensional picture that has a similar appearance to some subject, usually a physical object or a person."),
'mimetypes' => array(
'image/jpeg',
'image/gif',
'image/png',
),
),
);
}
/**
* @todo Add documentation.
* Alter default file types.
*
* Note: This is not really a hook. The function name is manually specified via
* 'default view callback' in hook_file_type_info(), with this recommended
* callback name pattern.
* @see hook_file_default_types()
*/
function hook_file_type_TYPE_default_view($file, $view_mode, $langcode) {
function hook_file_default_types_alter(&$types) {
$types['image']->mimetypes[] = 'image/svg+xml';
}
/**
......@@ -128,46 +123,97 @@ function hook_file_view_alter($build, $type) {
}
/**
* Defines bulk file operations.
* Control access to a file.
*
* Modules may implement this hook if they want to have a say in whether or not
* a given user has access to perform a given operation on a file.
*
* The administrative account (user ID #1) always passes any access check,
* so this hook is not called in that case. Users with the "bypass file access"
* permission may always view and edit files through the administrative
* interface.
*
* This hook enables modules to inject custom operations into the mass
* operations dropdown found at admin/content/file, by associating a callback
* function with the operation, which is called when the form is submitted.
* The callback function receives one initial argument, which is an array of
* the checked files.
* Note that not all modules will want to influence access on all
* file types. If your module does not want to actively grant or
* block access, return FILE_ENTITY_ACCESS_IGNORE or simply return nothing.
* Blindly returning FALSE will break other file access modules.
*
* @param $op
* The operation to be performed. Possible values:
* - "create"
* - "delete"
* - "update"
* - "view"
* @param $file
* The file on which the operation is to be performed, or, if it does
* not yet exist, the type of file to be created.
* @param $account
* A user object representing the user for whom the operation is to be
* performed.
*
* @return
* An associave array of operations keyed by machine name.
* - label: A string to show in the operations dropdown.
* - callback (string): A callback function to call for the operation. This
* function will be passed an array of file_ids which were selected.
* - confirm (boolean): Whether or not this operation requires a confirm form
* In the case where confirm is set to true, callback should be a function
* which can return a confirm form.
*
* @see hook_file_operation_info_alter()
* @see file_entity_get_file_operation_info()
* FILE_ENTITY_ACCESS_ALLOW if the operation is to be allowed;
* FILE_ENTITY_ACCESS_DENY if the operation is to be denied;
* FILE_ENTITY_ACCESS_IGNORE to not affect this operation at all.
*
* @ingroup file_entity_access
*/
function hook_file_operation_info() {
$info['fluff'] = array(
'label' => t('Fluff selected files'),
'callback' => 'file_fluff_files',
);
function hook_file_entity_access($op, $file, $account) {
$type = is_string($file) ? $file : $file->type;
return $info;
if ($op !== 'create' && (REQUEST_TIME - $file->timestamp) < 3600) {
// If the file was uploaded in the last hour, deny access to it.
return FILE_ENTITY_ACCESS_DENY;
}
// Returning nothing from this function would have the same effect.
return FILE_ENTITY_ACCESS_IGNORE;
}
/**
* Perform alterations on bulk file operations.
* Control access to listings of files.
*
* @param $info
* Array of information on bulk file operations exposed by
* hook_file_operation_info() implementations.
* @param $query
* A query object describing the composite parts of a SQL query related to
* listing files.
*
* @see hook_query_TAG_alter()
* @ingroup file_entity_access
*/
function hook_query_file_entity_access_alter(QueryAlterableInterface $query) {
// Only show files that have been uploaded more than an hour ago.
$query->condition('timestamp', REQUEST_TIME - 3600, '<=');
}
/**
* Decides which file type (bundle) should be assigned to a file entity.
*
* @param $file
* File object.
*
* @return
* Array of file type machine names that can be assigned to a given file type.
* If there are more proposed file types the one, that was returned the first,
* wil be chosen. This can be, however, changed in alter hook.
*
* @see hook_file_type_alter()
*/
function hook_file_type($file) {
// Assign all files uploaded by anonymous users to a special file type.
if (user_is_anonymous()) {
return array('untrusted_files');
}
}
/**
* Alters list of file types that can be assigned to a file.
*
* @see hook_file_operation_info()
* @see file_entity_get_file_operation_info()
* @param $types
* List of proposed types.
* @param $file
* File object.
*/
function hook_file_operation_info_alter(&$info) {
// Remove the 'Fluff selected files' operation.
unset($info['fluff']);
function hook_file_type_alter(&$types, $file) {
// Choose a specific, non-first, file type.
$types = array($types[4]);
}
......@@ -14,12 +14,39 @@ function file_entity_file_presave($file) {
$file->filemime = file_get_mimetype($file->uri);
}
// Always update file type based on filemime.
$file->type = file_get_type($file);
// The file type is used as a bundle key, and therefore, must not be NULL.
// It defaults to FILE_TYPE_NONE when loaded via file_load(), but in case
// file_save() is called on a new file object, default it here too.
if (!isset($file->type)) {
$file->type = FILE_TYPE_NONE;
}
// If the file isn't already assigned a real type, determine what type should
// be assigned to it.
if ($file->type === FILE_TYPE_NONE) {
$type = file_get_type($file);
if (isset($type)) {
$file->type = $type;
}
}
field_attach_presave('file', $file);
}
/**
* Implements hook_file_type().
*/
function file_entity_file_type($file) {
$types = array();
foreach (file_type_get_enabled_types() as $type) {
if (in_array($file->filemime, $type->mimetypes)) {
$types[] = $type->type;
}
}
return $types;
}
/**
* Implements hook_file_insert().
*/
......
......@@ -6,59 +6,9 @@
*/
/**
* Returns information about file types from hook_file_type_info().
*
* @param $file_type
* (optional) A file type name. If ommitted, all file types will be returned.
*
* @return
* Either a file type description, as provided by hook_file_type_info(), or an
* array of all existing file types, keyed by file type name.
*/
function file_info_file_types($file_type = NULL) {
$info = &drupal_static(__FUNCTION__);
if (!isset($info)) {
$info = module_invoke_all('file_type_info');
// Add support for the standard file types until this can be fully
// abstracted out of Media module.
$info += array(
'application' => array('label' => t('Application (multipurpose)')),
'audio' => array('label' => t('Audio')),
'image' => array('label' => t('Image')),
'text' => array('label' => t('Text')),
'video' => array('label' => t('Video')),
);
drupal_alter('file_type_info', $info);
uasort($info, '_file_entity_sort_weight_label');
}
if ($file_type) {
if (isset($info[$file_type])) {
return $info[$file_type];
}
}
else {
return $info;
}
}
/**
* Determines the file type of a passed in file object.
*
* The file type is determined by extracting the 'first' part of the file's
* MIME type. For example, a PNG image with a MIME type of 'image/png' will
* have a file type of 'image'.
*
* @link http://www.iana.org/assignments/media-types/index.html IANA list of official MIME media types @endlink
* The {file_managed}.type value when the file type has not yet been determined.
*/
function file_get_type($file) {
// Ensure that a MIME type has been determined first.
if (empty($file->filemime)) {
$file->filemime = file_get_mimetype($file->uri);
}
return substr($file->filemime, 0, strpos($file->filemime, '/'));
}
define('FILE_TYPE_NONE', 'undefined');
/**
* Returns information about file formatters from hook_file_formatter_info().
......@@ -90,11 +40,19 @@ function file_info_formatter_types($formatter_type = NULL) {
}
/**
* Clears the file info cache.
* Clears all cached configuration related to file types, formatters, and display settings.
*/
function file_info_cache_clear() {
drupal_static_reset('file_info_file_types');
// Clear the CTools managed caches.
ctools_include('export');
ctools_export_load_object_reset('file_type');
ctools_export_load_object_reset('file_display');
// Clear the formatter type cache, managed by file_info_formatter_types().
drupal_static_reset('file_info_formatter_types');
// Clear file type caches
drupal_static_reset('file_type_get_names');
}
/**
......@@ -169,7 +127,7 @@ function file_view($file, $view_mode = 'full', $langcode = NULL) {
// displayed on its own page. Modules may alter this behavior (for example,
// to restrict contextual links to certain view modes) by implementing
// hook_file_view_alter().
if (!empty($file->fid) && !($view_mode == 'full' && file_is_page($file