diff --git a/sites/all/modules/contrib/flag/flag/README.txt b/sites/all/modules/contrib/flag/flag/README.txt index 21a013f0..4b1141be 100644 --- a/sites/all/modules/contrib/flag/flag/README.txt +++ b/sites/all/modules/contrib/flag/flag/README.txt @@ -7,13 +7,13 @@ The Flag module is a flexible flagging system whose primary goal is to give all the control to the administrator. Using this module, the site administrator can provide an arbitrary number of 'flags'. -A flag is really just a boolean toggle that is set on a node, comment, -or user. Flags may be per-user, meaning that each user can flag an item +A flag is really just a boolean toggle that is set on an entity such as a node, +comment, or user. Flags may be per-user, meaning that each user can flag an item individually, or global, meaning that the item is either flagged or it is not flagged, and any user who changes that changes it for everyone. -In this way, additional flags (similar to 'published' and 'sticky') can -be put on nodes, or other items, and dealt with by the system however +In this way, additional flags (similar to 'published' and 'sticky') can +be put on nodes, or other items, and dealt with by the system however the administration likes. Each flag allows the administrator to choose the 'flag this' text, and @@ -25,19 +25,19 @@ Each flag can be restricted to use only by certain roles. Each flag provides data to the Views module, and provides a default view to list 'My bookmarks'. These default views are somewhat crude, but are easily tailored to whatever the system administrator would like -it to do. +it to do. -Each flag also provides an 'argument' to the Views module that can be -used to allow a user to view other people's flagged content. This isn't -turned on by default anywhere, though, and the administrator will need +Each flag also provides an 'argument' to the Views module that can be +used to allow a user to view other people's flagged content. This isn't +turned on by default anywhere, though, and the administrator will need to construct a view in order to take advantage of it. -The module will come installed with a simple flag called "bookmarks" and -a simple view for 'My bookmarks'. This is a default view provided by the -Flag module, but can be customized to fit the needs of your site. To -customize this view, go to admin/structure/views and find the -'flags_bookmarks' view. Click the 'Add' action to customize the view. -Once saved, the new version of the view will be used rather than the one +The Flag Bookmark module provides a simple flag called "bookmarks" and +a simple view for 'My bookmarks'. This is a default view provided by the +Flag module, but can be customized to fit the needs of your site. To +customize this view, go to admin/structure/views and find the +'flags_bookmarks' view. Click the 'Add' action to customize the view. +Once saved, the new version of the view will be used rather than the one provided by Flag. Besides editing the default view that comes with the module, Flag @@ -53,6 +53,7 @@ Recommended Modules ------------------- - Views - Session API +- Token, which is required for Flag to provide tokens on flagged entities. Installation ------------ diff --git a/sites/all/modules/contrib/flag/flag/flag.api.php b/sites/all/modules/contrib/flag/flag/flag.api.php index 88aef7a2..9b8cbfe2 100644 --- a/sites/all/modules/contrib/flag/flag/flag.api.php +++ b/sites/all/modules/contrib/flag/flag/flag.api.php @@ -58,11 +58,11 @@ function hook_flag_type_info_alter(&$definitions) { */ function hook_flag_default_flags() { $flags = array(); - $flags['bookmarks'] = array ( + $flags['bookmarks'] = array( 'entity_type' => 'node', 'title' => 'Bookmarks', 'global' => FALSE, - 'types' => array ( + 'types' => array( 0 => 'article', 1 => 'blog', ), @@ -75,7 +75,7 @@ function hook_flag_default_flags() { 'unflag_denied_text' => '', 'link_type' => 'toggle', 'weight' => 0, - 'show_in_links' => array ( + 'show_in_links' => array( 'full' => TRUE, 'token' => FALSE, ), @@ -90,10 +90,22 @@ function hook_flag_default_flags() { return $flags; } +/** + * Alter the definition of default flags. + * + * @param array &$flags + * An array keyed by flag machine name containing flag definitions. + */ +function hook_flag_default_flags_alter(&$flags) { + if (!empty($flags['bookmark'])) { + $flags['bookmark']['title'] = 'Bananana Bookmark'; + } +} + /** * Allow modules to alter a flag when it is initially loaded. * - * @see flag_get_flags(). + * @see flag_get_flags() */ function hook_flag_alter(&$flag) { @@ -183,7 +195,7 @@ function hook_flag_validate($action, $flag, $entity_id, $account, $skip_permissi $count = count($flags[$flag->name]); if ($count >= 2) { // Users may flag only 2 nodes with this flag. - return(array('access-denied' => t('You may only flag 2 nodes with the test flag.'))); + return (array('access-denied' => t('You may only flag 2 nodes with the test flag.'))); } } } @@ -350,15 +362,23 @@ function hook_flag_reset($flag, $entity_id, $rows) { /** * Alter the javascript structure that describes the flag operation. * + * @param $info + * The info array before it is returned from flag_build_javascript_info(). * @param $flag * The full flag object. - * @param $entity_id - * The ID of the node, comment, user or other object being flagged. * * @see flag_build_javascript_info() */ -function hook_flag_javascript_info_alter() { - +function hook_flag_javascript_info_alter(&$info, $flag) { + if ($flag->name === 'test') { + $info['newLink'] = $flag->theme($flag->is_flagged($info['contentId']) ? 'unflag' : 'flag', $info['contentId'], array( + 'after_flagging' => TRUE, + 'errors' => $flag->get_errors(), + // Additional options to pass to theme's preprocess function/template. + 'icon' => TRUE, + 'hide_text' => TRUE, + )); + } } /** diff --git a/sites/all/modules/contrib/flag/flag/flag.info b/sites/all/modules/contrib/flag/flag/flag.info index bde18296..a4125530 100644 --- a/sites/all/modules/contrib/flag/flag/flag.info +++ b/sites/all/modules/contrib/flag/flag/flag.info @@ -4,6 +4,9 @@ core = 7.x package = Flags configure = admin/structure/flags +test_dependencies[] = token +test_dependencies[] = rules + ; Files that contain classes. ; Flag classes files[] = includes/flag/flag_flag.inc @@ -26,9 +29,9 @@ files[] = includes/views/flag_handler_relationships.inc files[] = includes/views/flag_plugin_argument_validate_flaggability.inc files[] = tests/flag.test -; Information added by drupal.org packaging script on 2013-09-13 -version = "7.x-3.2" +; Information added by Drupal.org packaging script on 2015-03-02 +version = "7.x-3.6" core = "7.x" project = "flag" -datestamp = "1379063829" +datestamp = "1425327793" diff --git a/sites/all/modules/contrib/flag/flag/flag.info.inc b/sites/all/modules/contrib/flag/flag/flag.info.inc index 69bbb5c7..890e624d 100644 --- a/sites/all/modules/contrib/flag/flag/flag.info.inc +++ b/sites/all/modules/contrib/flag/flag/flag.info.inc @@ -1,7 +1,8 @@ 0, ), 'sid' => array( - 'description' => "The user's session id as stored in the session table.", + 'description' => "The user's numeric sid from the session_api table.", 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, @@ -113,7 +113,7 @@ function flag_schema() { 'not null' => TRUE, 'default' => 0, 'disp-size' => 11, - ) + ), ), 'primary key' => array('flagging_id'), 'unique keys' => array( @@ -121,7 +121,12 @@ function flag_schema() { ), 'indexes' => array( 'entity_type_uid_sid' => array('entity_type', 'uid', 'sid'), - 'entity_type_entity_id_uid_sid' => array('entity_type', 'entity_id', 'uid', 'sid'), + 'entity_type_entity_id_uid_sid' => array( + 'entity_type', + 'entity_id', + 'uid', + 'sid', + ), 'entity_id_fid' => array('entity_id', 'fid'), ), ); @@ -190,7 +195,7 @@ function flag_schema() { 'not null' => TRUE, 'default' => 0, 'disp-size' => 11, - ) + ), ), 'primary key' => array('fid', 'entity_id'), 'indexes' => array( @@ -296,7 +301,11 @@ function flag_update_6200() { function flag_update_6201() { // Remove "content type" from one key, see http://drupal.org/node/612602. db_drop_unique_key('flag_content', 'fid_content_type_content_id_uid'); - db_add_unique_key('flag_content', 'fid_content_id_uid', array('fid', 'content_id', 'uid')); + db_add_unique_key('flag_content', 'fid_content_id_uid', array( + 'fid', + 'content_id', + 'uid', + )); // Add a count index, see http://drupal.org/node/489610. db_add_index('flag_counts', 'count', array('count')); @@ -311,11 +320,25 @@ function flag_update_6202() { db_drop_index('flag_content', 'content_type_uid'); // Add the column. - db_add_field('flag_content', 'sid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0)); + db_add_field('flag_content', 'sid', array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + )); // Re-add the removed keys. - db_add_unique_key('flag_content', 'fid_content_id_uid_sid', array('fid', 'content_id', 'uid', 'sid')); - db_add_index('flag_content', 'content_type_uid_sid', array('content_type', 'uid', 'sid')); + db_add_unique_key('flag_content', 'fid_content_id_uid_sid', array( + 'fid', + 'content_id', + 'uid', + 'sid', + )); + db_add_index('flag_content', 'content_type_uid_sid', array( + 'content_type', + 'uid', + 'sid', + )); } /** @@ -357,14 +380,25 @@ function flag_update_6206() { db_drop_unique_key('flag_content', 'content_type_content_id_uid_sid'); } - db_add_index('flag_content', 'content_type_content_id_uid_sid', array('content_type', 'content_id', 'uid', 'sid')); + db_add_index('flag_content', 'content_type_content_id_uid_sid', array( + 'content_type', + 'content_id', + 'uid', + 'sid', + )); } /** * Adds column last_updated to flag_counts table. */ function flag_update_6207() { - db_add_field('flag_counts', 'last_updated', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'disp-size' => 11), array('indexes' => array('last_updated' => array('last_updated')))); + db_add_field('flag_counts', 'last_updated', array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'disp-size' => 11), + array('indexes' => array('last_updated' => array('last_updated')))); } /** @@ -482,7 +516,12 @@ function flag_update_7303() { ), 'indexes' => array( 'entity_type_uid_sid' => array('entity_type', 'uid', 'sid'), - 'entity_type_content_id_uid_sid' => array('entity_type', 'content_id', 'uid', 'sid'), + 'entity_type_content_id_uid_sid' => array( + 'entity_type', + 'content_id', + 'uid', + 'sid', + ), 'content_id_fid' => array('content_id', 'fid'), ), ) @@ -510,7 +549,12 @@ function flag_update_7303() { 'fid_entity_id_uid_sid' => array('fid', 'entity_id', 'uid', 'sid'), ), 'indexes' => array( - 'entity_type_entity_id_uid_sid' => array('entity_type', 'entity_id', 'uid', 'sid'), + 'entity_type_entity_id_uid_sid' => array( + 'entity_type', + 'entity_id', + 'uid', + 'sid', + ), 'entity_id_fid' => array('entity_id', 'fid'), ), ) @@ -569,7 +613,7 @@ function flag_update_7304() { 'indexes' => array( 'fid_entity_type' => array('fid', 'entity_type'), 'entity_type_content_id' => array('entity_type', 'content_id'), - ) + ), ) ); @@ -671,7 +715,8 @@ function flag_update_7306() { } // Update show_on_comment and show_on_entity properties to use new view - // mode settings. Since the old logic was to show on all view modes, do that. + // mode settings. Since the old logic was to show on all view modes, do + // that. if (!empty($flag->show_on_entity) || !empty($flag->show_on_comment)) { if ($entity_info = entity_get_info($flag->entity_type)) { foreach ($entity_info['view modes'] as $view_mode => $value) { diff --git a/sites/all/modules/contrib/flag/flag/flag.module b/sites/all/modules/contrib/flag/flag/flag.module index 77fce722..7890b973 100644 --- a/sites/all/modules/contrib/flag/flag/flag.module +++ b/sites/all/modules/contrib/flag/flag/flag.module @@ -33,6 +33,7 @@ function flag_entity_info() { // The following tells EntityAPI how to save flaggings, thus allowing use // of Entity metadata wrappers (if present). 'save callback' => 'flagging_save', + 'creation callback' => 'flagging_create', ), ); @@ -72,6 +73,37 @@ function flagging_load($flagging_id, $reset = FALSE) { return reset($result); } +/** + * Entity API creation callback. + * + * Creates an unsaved flagging object for use with $flag->flag(). + * + * @param $values + * An array of values as described by the entity's property info. Only + * 'flag_name' or 'fid' must be specified, since $flag->flag() does the rest. + * + * @return + * An unsaved flagging object containing the property values. + */ +function flagging_create($values = array()) { + $flagging = (object) array(); + + if (!isset($values['flag_name'])) { + if (isset($values['fid'])) { + // Add flag_name, determined from fid. + $flag = flag_get_flag(NULL, $values['fid']); + $values['flag_name'] = $flag->name; + } + } + + // Apply the given values. + foreach ($values as $key => $value) { + $flagging->$key = $value; + } + + return $flagging; +} + /** * Saves a flagging entity. * @@ -128,14 +160,15 @@ function flagging_save($flagging) { // @todo: flag_reset_flag(): // - it should delete the flaggings. // - (it has other issues; see http://drupal.org/node/894992.) -// - (is problematic: it might not be possible to delete all data in a single page request.) +// - (is problematic: it might not be possible to delete all data in a single +// page request.) // @todo: Discuss: Note that almost all functions/identifiers dealing with // flaggings *aren't* prefixed by "flag_". For example: -// - The menu argument is %flagging, not %flag_flagging. -// - The entity type is "flagging", not "flag_flagging". -// On the one hand this succinct version is readable and nice. On the other hand, it isn't -// very "correct". +// - The menu argument is %flagging, not %flag_flagging. +// - The entity type is "flagging", not "flag_flagging". +// On the one hand this succinct version is readable and nice. On the other +// hand, it isn't very "correct". /** * Implements hook_entity_query_alter(). @@ -150,7 +183,8 @@ function flag_entity_query_alter(EntityFieldQuery $query) { // Alter only flagging queries with bundle conditions. if (isset($conditions['entity_type']) && $conditions['entity_type']['value'] == 'flagging' && isset($conditions['bundle'])) { - $query->addTag('flagging_flag_names'); // Add tag to alter query. + // Add tag to alter query. + $query->addTag('flagging_flag_names'); // Make value and operator of the bundle condition accessible // in hook_query_TAG_alter. $query->addMetaData('flag_name_value', $conditions['bundle']['value']); @@ -185,7 +219,6 @@ function flag_menu() { 'access arguments' => array('administer flags'), 'description' => 'Configure flags for marking content with arbitrary information (such as offensive or bookmarked).', 'file' => 'includes/flag.admin.inc', - 'type' => MENU_NORMAL_ITEM, ); $items[FLAG_ADMIN_PATH . '/list'] = array( 'title' => 'List', @@ -207,7 +240,7 @@ function flag_menu() { 'page arguments' => array('flag_import_form'), 'access arguments' => array('use flag import'), 'file' => 'includes/flag.export.inc', - 'type' => MENU_LOCAL_TASK, + 'type' => MENU_LOCAL_ACTION, 'weight' => 2, ); $items[FLAG_ADMIN_PATH . '/export'] = array( @@ -216,24 +249,26 @@ function flag_menu() { 'page arguments' => array('flag_export_form'), 'access arguments' => array('administer flags'), 'file' => 'includes/flag.export.inc', - 'type' => MENU_LOCAL_TASK, + 'type' => MENU_LOCAL_ACTION, 'weight' => 3, ); $items[FLAG_ADMIN_PATH . '/manage/%flag'] = array( - 'load arguments' => array(TRUE), // Allow for disabled flags. + // Allow for disabled flags. + 'load arguments' => array(TRUE), 'page callback' => 'drupal_get_form', 'page arguments' => array('flag_form', FLAG_ADMIN_PATH_START + 1), 'access callback' => 'user_access', 'access arguments' => array('administer flags'), 'file' => 'includes/flag.admin.inc', - 'type' => MENU_CALLBACK, + 'type' => MENU_LOCAL_TASK, // Make the flag title the default title for descendant menu items. 'title callback' => '_flag_menu_title', 'title arguments' => array(FLAG_ADMIN_PATH_START + 1), ); $items[FLAG_ADMIN_PATH . '/manage/%flag/edit'] = array( - 'load arguments' => array(TRUE), // Allow for disabled flags. + // Allow for disabled flags. + 'load arguments' => array(TRUE), 'title' => 'Edit flag', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, @@ -257,7 +292,8 @@ function flag_menu() { 'type' => MENU_CALLBACK, ); $items[FLAG_ADMIN_PATH . '/manage/%flag/update'] = array( - 'load arguments' => array(TRUE), // Allow for disabled flags. + // Allow for disabled flags. + 'load arguments' => array(TRUE), 'title' => 'Update', 'page callback' => 'flag_update_page', 'page arguments' => array(FLAG_ADMIN_PATH_START + 1), @@ -306,31 +342,6 @@ function flag_admin_menu_map() { ), ); - if (module_exists('field_ui')) { - foreach (entity_get_info() as $obj_type => $info) { - if ($obj_type == 'flagging') { - foreach ($info['bundles'] as $bundle_name => $bundle_info) { - if (isset($bundle_info['admin'])) { - $fields = array(); - - foreach (field_info_instances($obj_type, $bundle_name) as $field) { - $fields[] = $field['field_name']; - } - - $arguments = array( - '%flag' => array($bundle_name), - '%field_ui_menu' => $fields, - ); - - $path = $bundle_info['admin']['path']; - $map["$path/fields/%field_ui_menu"]['parent'] = "$path/fields"; - $map["$path/fields/%field_ui_menu"]['arguments'][] = $arguments; - } - } - } - } - } - return $map; } @@ -384,9 +395,11 @@ function flag_help($path, $arg) { case FLAG_ADMIN_PATH: $output = '
' . t('This page lists all the flags that are currently defined on this system.') . '
'; return $output; + case FLAG_ADMIN_PATH . '/add': $output = '' . t('Select the type of flag to create. An individual flag can only affect one type of object. This cannot be changed once the flag is created.') . '
'; return $output; + case FLAG_ADMIN_PATH . '/manage/%/fields': // Get the existing link types that provide a flagging form. $link_types = flag_get_link_types(); @@ -540,10 +553,10 @@ function flag_get_types() { function flag_create_handler($entity_type) { $definition = flag_fetch_definition($entity_type); if (isset($definition) && class_exists($definition['handler'])) { - $handler = new $definition['handler']; + $handler = new $definition['handler'](); } else { - $handler = new flag_broken; + $handler = new flag_broken(); } $handler->entity_type = $entity_type; $handler->construct(); @@ -566,6 +579,8 @@ function flag_permission() { ), ); + // Reset static cache to ensure all flag permissions are available. + drupal_static_reset('flag_get_flags'); $flags = flag_get_flags(); // Provide flag and unflag permissions for each flag. foreach ($flags as $flag_name => $flag) { @@ -616,12 +631,19 @@ function flag_field_extra_fields() { continue; } - foreach ($flag->types as $bundle_name) { + $applicable_bundles = $flag->types; + // If the list of bundles is empty, it indicates all bundles apply. + if (empty($applicable_bundles)) { + $entity_info = entity_get_info($flag->entity_type); + $applicable_bundles = array_keys($entity_info['bundles']); + } + + foreach ($applicable_bundles as $bundle_name) { if ($flag->show_on_form) { $extra[$flag->entity_type][$bundle_name]['form']['flag'] = array( 'label' => t('Flags'), 'description' => t('Checkboxes for toggling flags'), - 'weight' => 10 + 'weight' => 10, ); } @@ -689,7 +711,7 @@ function flag_form_node_type_form_alter(&$form, &$form_state, $form_id) { * Warning: will not work on entity types that are not fieldable, as this relies * on a field module hook. * - * @see flag_field_attach_submit(). + * @see flag_field_attach_submit() */ function flag_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) { list($id) = entity_extract_ids($entity_type, $entity); @@ -698,6 +720,10 @@ function flag_field_attach_form($entity_type, $entity, &$form, &$form_state, $la $id = NULL; } + // Keep track of whether the entity is new or not, as we're about to fiddle + // with the entity id for the flag's entity cache. + $is_existing_entity = !empty($id); + // Get all possible flags for this entity type. $flags = flag_get_flags($entity_type); @@ -710,7 +736,7 @@ function flag_field_attach_form($entity_type, $entity, &$form, &$form_state, $la } // Get the flag status. - if (isset($id)) { + if ($is_existing_entity) { $flag_status = $flag->is_flagged($id); } else { @@ -719,7 +745,8 @@ function flag_field_attach_form($entity_type, $entity, &$form, &$form_state, $la $flag_status = FALSE; // Apply the per-bundle defaults for nodes. if ($entity_type == 'node') { - $flag_status = variable_get('flag_' . $flag->name . '_default_' . $form['type']['#value'], 0); + $node_type = $entity->type; + $flag_status = variable_get('flag_' . $flag->name . '_default_' . $node_type, 0); } // For a new, unsaved entity, make a dummy entity ID so that the flag @@ -793,7 +820,7 @@ function flag_field_attach_form($entity_type, $entity, &$form, &$form_state, $la /** * Implements hook_field_attach_submit(). * - * @see flag_field_attach_form(). + * @see flag_field_attach_form() */ function flag_field_attach_submit($entity_type, $entity, $form, &$form_state) { // This is invoked for each flag_field_attach_form(), but possibly more than @@ -831,7 +858,7 @@ function flag_field_attach_update($entity_type, $entity) { /** * Shared saving routine between flag_field_attach_insert/update(). * - * @see flag_field_attach_form(). + * @see flag_field_attach_form() */ function flag_field_attach_save($entity_type, $entity) { list($id) = entity_extract_ids($entity_type, $entity); @@ -872,13 +899,14 @@ function flag_contextual_links_view_alter(&$element, $items) { list($entity_id) = entity_extract_ids($entity_type, $entity); if (!$flag->access($entity_id) && (!$flag->is_flagged($entity_id) || !$flag->access($entity_id, 'flag'))) { - // User has no permission to use this flag or flag does not apply to this - // object. The link is not skipped if the user has "flag" access but - // not "unflag" access (this way the unflag denied message is shown). + // User has no permission to use this flag or flag does not apply to + // this object. The link is not skipped if the user has "flag" access + // but not "unflag" access (this way the unflag denied message is + // shown). continue; } - $element['#links']['flag-'. $name] = array( + $element['#links']['flag-' . $name] = array( 'title' => $flag->theme($flag->is_flagged($entity_id) ? 'unflag' : 'flag', $entity_id), 'html' => TRUE, ); @@ -935,7 +963,7 @@ function flag_entity_view($entity, $type, $view_mode, $langcode) { // The pseudofield output. if ($flag->show_as_field) { $entity->content['flag_' . $flag->name] = array( - '#markup' => $flag->theme($flag->is_flagged($entity_id) ? 'unflag' : 'flag', $entity_id, array('needs_wrapping_element' => TRUE)), + '#markup' => $flag->theme($flag->is_flagged($entity_id) ? 'unflag' : 'flag', $entity_id, array('needs_wrapping_element' => TRUE)), ); } } @@ -1136,7 +1164,7 @@ function flag_user_delete($account) { function flag_user_account_removal($account) { // Remove flags by this user. $query = db_select('flagging', 'fc'); - $query->leftJoin('flag_counts', 'c', 'fc.entity_id = c.entity_id AND fc.entity_type = c.entity_type'); + $query->leftJoin('flag_counts', 'c', 'fc.entity_id = c.entity_id AND fc.entity_type = c.entity_type AND fc.fid = c.fid'); $result = $query ->fields('fc', array('fid', 'entity_id')) ->fields('c', array('count')) @@ -1313,8 +1341,9 @@ function flag_flag_trigger($action, $flag, $entity_id, $account, $flagging) { $object = $flag->fetch_entity($entity_id); // Generic "all flags" actions. - foreach (trigger_get_assigned_actions('flag_' . $action) as $aid => $action_info) { - // The 'if ($aid)' is a safeguard against http://drupal.org/node/271460#comment-886564 + foreach (trigger_get_assigned_actions('flag_' . $action) as $aid => $action_info) { + // The 'if ($aid)' is a safeguard against + // http://drupal.org/node/271460#comment-886564 if ($aid) { actions_do($aid, $object, $context); } @@ -1513,8 +1542,8 @@ function template_preprocess_flag(&$variables) { $flag =& $variables['flag']; $action = $variables['action']; $entity_id = $variables['entity_id']; - $errors = join('' . t('The above six texts may contain any of the tokens listed below. For example, "Flag link text" could be entered as:') . '
' . - theme('item_list', array( - 'items' => array( - t('Add <em>[node:title]</em> to your favorites'), - t('Add this [node:type] to your favorites'), - t('Vote for this proposal ([node:flag-vote-count] people have already done so)'), - ), - 'attributes' => array('class' => 'token-examples'), - )) . - '' . t('These tokens will be replaced with the appropriate fields from the node (or user, or comment).') . '
' . - theme('flag_tokens_browser', array('types' => $flag->get_labels_token_types())), + '' . t('The above six texts may contain any of the tokens listed below. For example, "Flag link text" could be entered as:') . '
' . + theme('item_list', array( + 'items' => array( + t('Add <em>[node:title]</em> to your favorites'), + t('Add this [node:type] to your favorites'), + t('Vote for this proposal ([node:flag-vote-count] people have already done so)'), + ), + 'attributes' => array('class' => 'token-examples'), + )) . + '' . t('These tokens will be replaced with the appropriate fields from the node (or user, or comment).') . '
' . + theme('flag_tokens_browser', array('types' => $flag->get_labels_token_types())), '#collapsible' => TRUE, '#collapsed' => TRUE, ); @@ -529,6 +544,8 @@ function flag_form($form, &$form_state, $flag) { '#title' => t('Flag confirmation message'), '#default_value' => isset($flag->flag_confirmation) ? $flag->flag_confirmation : '', '#description' => t('Message displayed if the user has clicked the "flag this" link and confirmation is required. Usually presented in the form of a question such as, "Are you sure you want to flag this content?"'), + // This will get changed to a state by flag_link_type_options_states(). + '#required' => TRUE, ); $form['display']['link_options_confirm']['unflag_confirmation'] = array( @@ -536,6 +553,8 @@ function flag_form($form, &$form_state, $flag) { '#title' => t('Unflag confirmation message'), '#default_value' => isset($flag->unflag_confirmation) ? $flag->unflag_confirmation : '', '#description' => t('Message displayed if the user has clicked the "unflag this" link and confirmation is required. Usually presented in the form of a question such as, "Are you sure you want to unflag this content?"'), + // This will get changed to a state by flag_link_type_options_states(). + '#required' => TRUE, ); $form['actions'] = array( @@ -561,7 +580,7 @@ function flag_form($form, &$form_state, $flag) { } /** - * FormAPI after_build function set states on link type options fieldsets. + * FormAPI after_build function to set states on link type options fieldsets. * * We do this in an after build so we handle further link types fieldsets from * other modules that provide link types. @@ -581,6 +600,20 @@ function flag_link_type_options_states($element) { ':input[name="link_type"]' => array('value' => $radio_value), ), ); + + // If an element in a link type options fieldset is required, then we + // remove this, as this would break the form, by demanding the user + // enter a value for a form element they possibly can't see! + // Instead, we set the required property as a state. + foreach (element_children($element[$key]) as $child_key) { + if (!empty($element[$key][$child_key]['#required'])) { + $element[$key][$child_key]['#required'] = FALSE; + $element[$key][$child_key]['#states']['required'] = array( + ':input[name="link_type"]' => array('value' => $radio_value), + ); + } + } + // Gather up the radio values for the format we need for a multiple // value state. $intro_element_values_array[] = array('value' => $radio_value); @@ -635,16 +668,6 @@ function flag_form_validate($form, &$form_state) { $form_state['values']['title'] = trim($form_state['values']['title']); $form_values = $form_state['values']; - if ($form_values['link_type'] == 'confirm') { - if (empty($form_values['flag_confirmation'])) { - form_set_error('flag_confirmation', t('A flag confirmation message is required when using the confirmation link type.')); - } - if (empty($form_values['unflag_confirmation'])) { - form_set_error('unflag_confirmation', t('An unflag confirmation message is required when using the confirmation link type.')); - } - } - - $flag = $form['#flag']; $flag->form_input($form_values); $errors = $flag->validate(); diff --git a/sites/all/modules/contrib/flag/flag/includes/flag.cookie_storage.inc b/sites/all/modules/contrib/flag/flag/includes/flag.cookie_storage.inc index 856f582e..07a3dfea 100644 --- a/sites/all/modules/contrib/flag/flag/includes/flag.cookie_storage.inc +++ b/sites/all/modules/contrib/flag/flag/includes/flag.cookie_storage.inc @@ -2,7 +2,7 @@ /** * @file - * Contains the FlagCookieStorage class. + * Contains the FlagCookieStorage class. */ /** diff --git a/sites/all/modules/contrib/flag/flag/includes/flag.export.inc b/sites/all/modules/contrib/flag/flag/includes/flag.export.inc index 539899c3..64f7f465 100644 --- a/sites/all/modules/contrib/flag/flag/includes/flag.export.inc +++ b/sites/all/modules/contrib/flag/flag/includes/flag.export.inc @@ -15,7 +15,8 @@ * in hook_flag_default_flags(). */ function flag_export_flags($flags = array(), $module = '', $indent = '') { - module_load_include('inc', 'features', 'features.export'); // For features_var_export() (optional). + // For features_var_export() (optional). + module_load_include('inc', 'features', 'features.export'); $output = $indent . '$flags = array();' . "\n"; foreach ($flags as $item) { if (is_object($item)) { @@ -269,7 +270,7 @@ function flag_update_export(&$flag) { if (substr($class, 0, 11) == 'FlagUpdate_') { // @todo: change this to work with the static class when we drop support // for PHP 5.2: see commit d5b517. - $update_handler = new $class; + $update_handler = new $class(); // Cast to string, as decimals as array keys seem to be rounded down to // ints, WTF PHP? $version = (string) $update_handler->old_api_version; @@ -364,7 +365,8 @@ class FlagUpdate_3 { } // Update show_on_comment and show_on_entity properties to use new view - // mode settings. Since the old logic was to show on all view modes, do that. + // mode settings. Since the old logic was to show on all view modes, do + // that. if (!empty($flag->show_on_entity) || !empty($flag->show_on_comment)) { if ($entity_info = entity_get_info($flag->entity_type)) { foreach ($entity_info['view modes'] as $view_mode => $value) { diff --git a/sites/all/modules/contrib/flag/flag/includes/flag.pages.inc b/sites/all/modules/contrib/flag/flag/includes/flag.pages.inc index cfb91ba3..f3a6132c 100644 --- a/sites/all/modules/contrib/flag/flag/includes/flag.pages.inc +++ b/sites/all/modules/contrib/flag/flag/includes/flag.pages.inc @@ -11,7 +11,11 @@ * Used both for the regular callback as well as the JS version. * * @param $action - * Either 'flag' or 'unflag'. + * The action about to be performed. One of 'flag' or 'unflag'. + * @param $flag + * The flag object. + * @param $entity_id + * The ID of the entity to be acted upon. The type is implicit in the flag. */ function flag_page($action, $flag, $entity_id) { global $user; @@ -93,7 +97,7 @@ function flag_confirm($form, &$form_state, $action, $flag, $entity_id) { $question = $flag->get_label($action . '_confirmation', $entity_id); $path = isset($_GET['destination']) ? $_GET['destination'] : '' . t('This filter is only needed if the relationship used has the "Include only flagged content" option unchecked. Otherwise, this filter is useless, because all records are already limited to flagged content.') . '
' . t('By choosing Not flagged, it is possible to create a list of content that is specifically not flagged.', array('@unflagged-url' => 'http://drupal.org/node/299335')) . '
'; } diff --git a/sites/all/modules/contrib/flag/flag/includes/views/flag_handler_relationships.inc b/sites/all/modules/contrib/flag/flag/includes/views/flag_handler_relationships.inc index 9a7c9644..820e5448 100644 --- a/sites/all/modules/contrib/flag/flag/includes/views/flag_handler_relationships.inc +++ b/sites/all/modules/contrib/flag/flag/includes/views/flag_handler_relationships.inc @@ -44,6 +44,17 @@ abstract class flag_handler_relationship extends views_handler_relationship { return $errors; } + /** + * Get the type of the flag this relationship uses. + * + * This looks at the data set in the relationship definition in Views data. + * + * @return + * The flag's type, e.g., 'node' or 'taxonomy_term', or NULL if this is not + * set in data from hook_views_data(). + * + * @see flag_views_data_alter() + */ function get_flag_type() { return isset($this->definition['flag type']) ? $this->definition['flag type'] : NULL; } @@ -77,7 +88,11 @@ abstract class flag_handler_relationship extends views_handler_relationship { } /** - * Specialized relationship handler associating flags and content. + * Views relationship handler associating flags and content. + * + * This forms a bridge from the entity table to the {flagging} table, with + * options to restrict the join to only flagged content, and to flagged content + * by the current user. * * @ingroup views */ @@ -172,7 +187,10 @@ class flag_handler_relationship_content extends flag_handler_relationship { } /** - * Specialized relationship handler associating flag counts and content. + * Views relationship handler associating flag counts and content. + * + * This forms a bridge from the entity table to the {flag_counts} table, with + * the option to restrict the join to include only flagged content. * * @ingroup views */ @@ -227,7 +245,9 @@ class flag_handler_relationship_counts extends flag_handler_relationship { } /** - * Specialized relationship handler associating flags and users. + * Views relationship handler associating flags and users. + * + * This forms a bridge from the the {users} table to the {flagging} table. * * @ingroup views */ @@ -264,4 +284,3 @@ class flag_handler_relationship_user_content extends flag_handler_relationship { parent::query(); } } - diff --git a/sites/all/modules/contrib/flag/flag/includes/views/flag_handler_sort_flagged.inc b/sites/all/modules/contrib/flag/flag/includes/views/flag_handler_sort_flagged.inc index 63c27875..54fdd37f 100644 --- a/sites/all/modules/contrib/flag/flag/includes/views/flag_handler_sort_flagged.inc +++ b/sites/all/modules/contrib/flag/flag/includes/views/flag_handler_sort_flagged.inc @@ -14,7 +14,8 @@ class flag_handler_sort_flagged extends views_handler_sort { /** * Provide a list of options for the default sort form. - * Should be overridden by classes that don't override sort_form + * + * Should be overridden by classes that don't override sort_form. */ function sort_options() { return array( diff --git a/sites/all/modules/contrib/flag/flag/includes/views/flag_plugin_argument_validate_flaggability.inc b/sites/all/modules/contrib/flag/flag/includes/views/flag_plugin_argument_validate_flaggability.inc index f6534126..7cd52691 100644 --- a/sites/all/modules/contrib/flag/flag/includes/views/flag_plugin_argument_validate_flaggability.inc +++ b/sites/all/modules/contrib/flag/flag/includes/views/flag_plugin_argument_validate_flaggability.inc @@ -66,8 +66,9 @@ class flag_plugin_argument_validate_flaggability extends views_plugin_argument_v } /** - * Returns form #options for the flags. Returns empty array if no flags were - * found. + * Returns form #options for the flags. + * + * Returns empty array if no flags were found. */ function flags_options() { $flags = flag_get_flags($this->flag_type); @@ -96,8 +97,9 @@ class flag_plugin_argument_validate_flaggability extends views_plugin_argument_v } /** - * Declares all tests. This scheme makes it easy for derived classes to add - * and remove tests. + * Declares all tests. + * + * This scheme makes it easy for derived classes to add and remove tests. */ function tests_info($which = NULL) { return array( @@ -130,7 +132,8 @@ class flag_plugin_argument_validate_flaggability extends views_plugin_argument_v if ($flag_name == '*relationship*') { // Pick the first flag mentioned in the relationships. foreach ($this->view->relationship as $id => $handler) { - // Note: we can't do $handler->field, because the relationship handler's init() may overwrite it. + // Note: we can't do $handler->field, because the relationship handler's + // init() may overwrite it. if (strpos($handler->options['field'], 'flag') !== FALSE && !empty($handler->options['flag'])) { $flag = flag_get_flag($handler->options['flag']); if ($flag && $flag->entity_type == $this->flag_type) { @@ -198,7 +201,8 @@ class flag_plugin_argument_validate_flaggability extends views_plugin_argument_v } function test_flagged($ids, $flag) { - // view_break_phrase() is guaranteed to return only integers, so this is SQL safe. + // view_break_phrase() is guaranteed to return only integers, so this is SQL + // safe. $flattened_ids = implode(',', $ids); return $this->_test_by_sql("SELECT entity_id FROM {flag_counts} WHERE fid = :fid AND entity_id IN ($flattened_ids) AND count > 0", array(':fid' => $flag->fid)); } @@ -206,7 +210,7 @@ class flag_plugin_argument_validate_flaggability extends views_plugin_argument_v function test_flagged_by_current_user($ids, $flag) { global $user; if (!$user->uid) { - // Anonymous user + // Anonymous user. return array(); } $flattened_ids = implode(',', $ids); @@ -223,4 +227,3 @@ class flag_plugin_argument_validate_flaggability extends views_plugin_argument_v return $passed; } } - diff --git a/sites/all/modules/contrib/flag/flag/plugins/access/flag_is_flagged/flag_is_flagged.inc b/sites/all/modules/contrib/flag/flag/plugins/access/flag_is_flagged/flag_is_flagged.inc index 68e10210..0f6e0433 100644 --- a/sites/all/modules/contrib/flag/flag/plugins/access/flag_is_flagged/flag_is_flagged.inc +++ b/sites/all/modules/contrib/flag/flag/plugins/access/flag_is_flagged/flag_is_flagged.inc @@ -31,7 +31,7 @@ function flag_flag_is_flagged_access_get_children($plugin, $parent) { foreach ($entities as $entity_type => $info) { if (entity_type_supports($entity_type, 'view')) { - $plugin['title'] = t('@entity_type is flagged', array('@entity_type' => $info['label'])); + $plugin['title'] = t('@entity_type is flagged', array('@entity_type' => $info['label'])); $plugin['keyword'] = $entity_type; $plugin['name'] = $parent . ':' . $entity_type; $plugin['required context'] = new ctools_context_required(t('Entity'), $entity_type); @@ -46,23 +46,36 @@ function flag_flag_is_flagged_access_get_children($plugin, $parent) { * Settings form. */ function flag_flag_is_flagged_access_settings(&$form, &$form_state, $conf) { - $options = array(); + $flag_name_options = array(); $plugin = $form_state['plugin']; $entity_type = explode(':', $plugin['name']); $entity_type = $entity_type[1]; foreach (flag_get_flags($entity_type) as $flag) { - $options[$flag->name] = check_plain($flag->title); + $flag_name_options[$flag->name] = check_plain($flag->title); } + $flag_user_options = array( + 'any' => t('Flagged by anyone'), + 'user' => t('Flagged by current user'), + ); + $flag_user_default = isset($conf['flag_user']) ? $conf['flag_user'] : 'user'; + $form['settings']['flag_name'] = array( '#title' => t('Flag name'), '#type' => 'radios', - '#options' => $options, + '#options' => $flag_name_options, '#description' => t('Include only flagged content.'), '#default_value' => $conf['flag_name'], ); + $form['settings']['flag_user'] = array( + '#title' => t('Filter by flag owner'), + '#type' => 'radios', + '#options' => $flag_user_options, + '#description' => t('Show content flagged by anyone or only by current user.'), + '#default_value' => $flag_user_default, + ); return $form; } @@ -78,19 +91,33 @@ function flag_flag_is_flagged_access_check($conf, $context) { // Get the ID of the entity. list($id) = entity_extract_ids($flag->entity_type, $context->data); - return $flag->is_flagged($id); + // Get either the count of users who have flagged this entity or find out + // whether the current user has flagged this node, depending on settings. + if (isset($conf['flag_user']) && $conf['flag_user'] == 'any') { + $count = count(flag_get_entity_flags($flag->entity_type, $id, $conf['flag_name'])); + return $count; + } + else { + return $flag->is_flagged($id); + } } /** - * Provide a summary description based upon the specified context + * Provide a summary description based upon the specified context. */ function flag_flag_is_flagged_access_summary($conf, $context) { $flag = flag_get_flag($conf['flag_name']); if ($flag) { - return t('@identifier is flagged with "@flag"', array('@flag' => check_plain($flag->title), '@identifier' => $context->identifier)); + $flag_limit_by = ''; + if (isset($conf['flag_user']) && $conf['flag_user'] == 'user') { + return t('@identifier is flagged with "@flag" by current user.', array('@flag' => $flag->title, '@identifier' => $context->identifier)); + } + elseif (isset($conf['flag_user']) && $conf['flag_user'] == 'any') { + return t('@identifier is flagged with "@flag" by anyone.', array('@flag' => $flag->title, '@identifier' => $context->identifier)); + } } else { - return t('Missing/ deleted flag "@flag"', array('@flag' => $conf['flag_name'])); + return t('Missing/deleted flag "@flag"', array('@flag' => $conf['flag_name'])); } } diff --git a/sites/all/modules/contrib/flag/flag/plugins/content_types/flag_link/flag_link.inc b/sites/all/modules/contrib/flag/flag/plugins/content_types/flag_link/flag_link.inc index 33de132f..dbff5e3b 100644 --- a/sites/all/modules/contrib/flag/flag/plugins/content_types/flag_link/flag_link.inc +++ b/sites/all/modules/contrib/flag/flag/plugins/content_types/flag_link/flag_link.inc @@ -24,17 +24,20 @@ function flag_flag_link_content_type_info($entity_type) { * Implements hook_PLUGIN_content_type_content_types(). */ function flag_flag_link_content_type_content_types() { + $types = &drupal_static(__FUNCTION__); + if (isset($types)) { + return $types; + } + $types = array(); $entities = entity_get_info(); foreach ($entities as $entity_type => $info) { - if (entity_type_supports($entity_type, 'view')) { - $types[$entity_type] = array( - 'title' => t('Flag for @entity_type', array('@entity_type' => $info['label'])), - 'category' => t('Entity'), - 'required context' => new ctools_context_required(t('Entity'), $entity_type), - ); - } + $types[$entity_type] = array( + 'title' => t('Flag for @entity_type', array('@entity_type' => $info['label'])), + 'category' => t('Entity'), + 'required context' => new ctools_context_required(t('Entity'), $entity_type), + ); } return $types; diff --git a/sites/all/modules/contrib/flag/flag/tests/flag.test b/sites/all/modules/contrib/flag/flag/tests/flag.test index 8d67758f..3f8ac338 100644 --- a/sites/all/modules/contrib/flag/flag/tests/flag.test +++ b/sites/all/modules/contrib/flag/flag/tests/flag.test @@ -43,7 +43,7 @@ class FlagFlaggingCRUDTestCase extends FlagTestCaseBase { */ public static function getInfo() { return array( - 'name' => 'Flagging CRUD', + 'name' => 'CRUD API', 'description' => 'Basic CRUD operations on flagging entities.', 'group' => 'Flag', ); @@ -216,14 +216,14 @@ class FlagFlaggingCRUDTestCase extends FlagTestCaseBase { * Test Flag admin UI. */ class FlagAdminTestCase extends FlagTestCaseBase { - var $_flag = FALSE; + public $_flag = FALSE; /** * Implements getInfo(). */ public static function getInfo() { return array( - 'name' => 'Flag admin tests', + 'name' => 'Admin UI', 'description' => 'Add, edit and delete flags.', 'group' => 'Flag', ); @@ -235,7 +235,7 @@ class FlagAdminTestCase extends FlagTestCaseBase { function setUp() { parent::setUp('flag'); - // Create and login user + // Create and login user. $admin_user = $this->drupalCreateUser(array('access administration pages', 'administer flags')); $this->drupalLogin($admin_user); } @@ -245,6 +245,14 @@ class FlagAdminTestCase extends FlagTestCaseBase { */ function testFlagAdmin() { // Add a new flag using the UI. + $this->drupalGet(FLAG_ADMIN_PATH . '/add/node'); + + // Check the form has the expected defaults. + $this->assertFieldByName('flag_short', 'Flag this item', "The flag message default value shows in the form."); + $this->assertFieldByName('unflag_short', 'Unflag this item', "The unflag message default value shows in the form."); + $this->assertFieldByName('show_in_links[full]', 'full', "The view mode option is set to the node 'full' view mode by default."); + $this->assertFieldByName('show_in_links[teaser]', 'teaser', "The view mode option is set to the node 'teaser' view mode by default."); + $edit = array( 'name' => drupal_strtolower($this->randomName()), 'title' => $this->randomName(), @@ -269,7 +277,13 @@ class FlagAdminTestCase extends FlagTestCaseBase { $saved = $edit; $saved['roles'] = array('flag' => array(2), 'unflag' => array(2)); $saved['types'] = array('page'); - $saved['show_in_links'] = array('full' => 0, 'teaser' => 0, 'rss' => 0, 'search_index' => 0, 'search_result' => 0); + $saved['show_in_links'] = array( + 'full' => 0, + 'teaser' => 0, + 'rss' => 0, + 'search_index' => 0, + 'search_result' => 0, + ); unset($saved['roles[flag][2]'], $saved['roles[unflag][2]'], $saved['types[article]'], $saved['types[page]'], $saved['show_in_links[full]'], $saved['show_in_links[teaser]'], $saved['show_in_links[rss]'], $saved['show_in_links[search_index]'], $saved['show_in_links[search_result]']); $this->drupalPost(FLAG_ADMIN_PATH . '/add/node', $edit, t('Save flag')); @@ -291,7 +305,7 @@ class FlagAdminTestCase extends FlagTestCaseBase { $permissions = user_role_permissions(user_roles()); foreach ($saved['roles'] as $action => $rids) { foreach ($rids as $rid) { - $permission_string = "$action ". $saved['name']; + $permission_string = "$action " . $saved['name']; $this->assertTrue(isset($permissions[$rid][$permission_string]), t('Permission %perm set for flag.', array( '%perm' => $permission_string, ))); @@ -323,7 +337,13 @@ class FlagAdminTestCase extends FlagTestCaseBase { $saved = $edit; $saved['roles'] = array('flag' => array(2), 'unflag' => array(2)); $saved['types'] = array('article'); - $saved['show_in_links'] = array('full' => TRUE, 'teaser' => TRUE, 'rss' => 0, 'search_index' => 0, 'search_result' => 0); + $saved['show_in_links'] = array( + 'full' => TRUE, + 'teaser' => TRUE, + 'rss' => 0, + 'search_index' => 0, + 'search_result' => 0, + ); unset($saved['roles[flag][2]'], $saved['roles[unflag][2]'], $saved['types[article]'], $saved['types[page]'], $saved['show_in_links[full]'], $saved['show_in_links[teaser]'], $saved['show_in_links[rss]'], $saved['show_in_links[search_index]'], $saved['show_in_links[search_result]']); $this->drupalPost(FLAG_ADMIN_PATH . '/manage/' . $flag->name, $edit, t('Save flag')); @@ -350,7 +370,7 @@ class FlagAdminTestCase extends FlagTestCaseBase { foreach ($saved['roles'] as $action => $rids) { foreach ($rids as $rid) { - $permission_string = "$action ". $saved['name']; + $permission_string = "$action " . $saved['name']; $this->assertTrue(isset($permissions[$rid][$permission_string]), t('Permission %perm set for flag.', array( '%perm' => $permission_string, ))); @@ -377,7 +397,7 @@ class FlagAccessFormTestCase extends FlagTestCaseBase { */ public static function getInfo() { return array( - 'name' => 'Flag access: entity forms', + 'name' => 'Access to flags via entity forms', 'description' => 'Access to flag and unflag entities via entity forms.', 'group' => 'Flag', ); @@ -431,7 +451,7 @@ class FlagAccessFormTestCase extends FlagTestCaseBase { $this->drupalGet('node/add/article'); - // Check that the flag form element cannot be seen + // Check that the flag form element cannot be seen. $this->assertNoText('Flag this item', t('Flag form element was not found.')); // Have the user create a node. @@ -463,6 +483,161 @@ class FlagAccessFormTestCase extends FlagTestCaseBase { } +/** + * Tokens we provide on generic entities. + */ +class FlagEntityTokensTestCase extends FlagTestCaseBase { + + /** + * Implements getInfo(). + */ + public static function getInfo() { + return array( + 'name' => 'Entity tokens', + 'description' => 'Tokens for flag count on entities.', + 'group' => 'Flag', + ); + } + + /** + * Implements setUp(). + */ + function setUp() { + // Our entity tokens require token module. + parent::setUp('flag', 'token'); + } + + /** + * Test tokens on nodes. + */ + function testNodeFlagToken() { + // Create a flag on article nodes. + $flag_data = array( + 'entity_type' => 'node', + 'name' => 'node_flag', + 'title' => 'Node Flag', + 'global' => 0, + 'types' => array( + 0 => 'article', + ), + 'flag_short' => 'Flag this item', + 'flag_long' => '', + 'flag_message' => '', + 'unflag_short' => 'Unflag this item', + 'unflag_long' => '', + 'unflag_message' => '', + 'unflag_denied_text' => 'You may not unflag this item', + 'link_type' => 'normal', + 'weight' => 0, + // Show the flag on the form. + 'show_on_form' => 1, + 'access_author' => '', + 'show_contextual_link' => 0, + 'show_in_links' => array( + 'full' => 1, + 'teaser' => 1, + ), + 'i18n' => 0, + 'api_version' => 3, + ); + $flag = $this->createFlag($flag_data); + + // Create a node to flag. + $node = (object) array( + 'type' => 'article', + 'title' => $this->randomName(), + ); + node_save($node); + + // Flag it by several users. + $flag_user_1 = $this->drupalCreateUser(array('flag node_flag',)); + + // Flag the node as the user. + $flag = flag_get_flag('node_flag'); + $flag->flag('flag', $node->nid, $flag_user_1); + + $flag_user_2 = $this->drupalCreateUser(array('flag node_flag',)); + + // Flag the node as the user. + $flag->flag('flag', $node->nid, $flag_user_2); + + $text = '[node:flag-node-flag-count]'; + + $replaced_text = token_replace($text, array('node' => $node)); + + $this->assertEqual($replaced_text, 2, "The flag count token for the node is correct."); + } + + /** + * Test tokens on taxonomy terms. + * + * These are worthy of a separate test, as the token type is a special case. + */ + function testTaxonomyTermFlagToken() { + // Create a flag on tag terms. + $flag_data = array( + 'entity_type' => 'taxonomy_term', + 'name' => 'term_flag', + 'title' => 'Term Flag', + 'global' => 0, + 'types' => array( + 0 => 'tags', + ), + 'flag_short' => 'Flag this item', + 'flag_long' => '', + 'flag_message' => '', + 'unflag_short' => 'Unflag this item', + 'unflag_long' => '', + 'unflag_message' => '', + 'unflag_denied_text' => 'You may not unflag this item', + 'link_type' => 'normal', + 'weight' => 0, + // Show the flag on the form. + 'show_on_form' => 1, + 'access_author' => '', + 'show_contextual_link' => 0, + 'show_in_links' => array( + 'full' => 1, + 'teaser' => 1, + ), + 'i18n' => 0, + 'api_version' => 3, + ); + $flag = $this->createFlag($flag_data); + + $vocabulary = taxonomy_vocabulary_load(1); + + // Create a term to flag. + $term = (object) array( + 'name' => $this->randomName(), + 'vid' => 1, + ); + taxonomy_term_save($term); + + // Flag it by several users. + $flag_user_1 = $this->drupalCreateUser(array('flag term_flag',)); + + // Flag the term as the user. + $flag = flag_get_flag('term_flag'); + $flag->flag('flag', $term->tid, $flag_user_1); + + $flag_user_2 = $this->drupalCreateUser(array('flag term_flag',)); + + // Flag the term as the user. + $flag = flag_get_flag('term_flag'); + $flag->flag('flag', $term->tid, $flag_user_2); + + $text = '[term:flag-term-flag-count]'; + + $replaced_text = token_replace($text, array('term' => $term)); + + debug($replaced_text); + + $this->assertEqual($replaced_text, 2, "The flag count token for the term is correct."); + } + +} + /** * Access to flags using the basic flag link. */ @@ -473,7 +648,7 @@ class FlagAccessLinkTestCase extends FlagTestCaseBase { */ public static function getInfo() { return array( - 'name' => 'Flag access tests', + 'name' => 'Access to flags via basic link', 'description' => 'Access to flag and unflag entities using the basic link.', 'group' => 'Flag', ); @@ -599,7 +774,7 @@ class FlagLinkTypeConfirmTestCase extends DrupalWebTestCase { */ public static function getInfo() { return array( - 'name' => 'Flag confirm link tests', + 'name' => 'Confirm form', 'description' => 'Flag confirm form link type.', 'group' => 'Flag', ); @@ -621,7 +796,7 @@ class FlagLinkTypeConfirmTestCase extends DrupalWebTestCase { 'types' => array( 0 => 'article', ), - 'flag_short' => 'Flag this item', + 'flag_short' => 'Flag this item', 'flag_long' => '', 'flag_message' => 'You have flagged this item.', 'unflag_short' => 'Unflag this item', @@ -642,8 +817,8 @@ class FlagLinkTypeConfirmTestCase extends DrupalWebTestCase { 'i18n' => 0, 'api_version' => 3, ); - $flag = flag_flag::factory_by_array($this->flag_data); - $flag->save(); + $this->flag = flag_flag::factory_by_array($this->flag_data); + $this->flag->save(); // Reset our cache so our permissions show up. drupal_static_reset('flag_get_flags'); @@ -651,8 +826,8 @@ class FlagLinkTypeConfirmTestCase extends DrupalWebTestCase { $this->checkPermissions(array(), TRUE); // Create test user who can flag and unflag. - $flag_unflag_user = $this->drupalCreateUser(array('flag test_flag', 'unflag test_flag')); - $this->drupalLogin($flag_unflag_user); + $this->flag_unflag_user = $this->drupalCreateUser(array('flag test_flag', 'unflag test_flag')); + $this->drupalLogin($this->flag_unflag_user); // Create an article node to flag and unflag. $title = $this->randomName(8); @@ -669,16 +844,27 @@ class FlagLinkTypeConfirmTestCase extends DrupalWebTestCase { } /** - * Test that a user sees the flag confirm form. + * Test usage of the flag confirm form. */ function testFlag() { // Look at our node. $this->drupalGet('node/' . $this->nid); - $this->assertLink($this->flag_data['flag_short'], 0, 'The flag link appears on the page'); + $flag_short_label = strip_tags($this->flag_data['flag_short']); + + $this->assertRaw($this->flag_data['flag_short'], 'The flag text, including HTML, appears on the page.'); + + // assertLink() appears to have interesting problems dealing with an A + // element which contains other tags. However, the xpath it uses appears to + // be fine with being given just the portion of the link text that comes + // before the interior tag. + // Fortunately, there will be no other text on the page that matches 'Flag'. + $this->assertLink('Flag', 0, 'The flag link appears on the page.'); // Click the link to flag the node. - $this->clickLink($this->flag_data['flag_short']); + // clickLink() has the same problem, as it uses the same xpath expression as + // assertLink(). + $this->clickLink('Flag'); $this->assertUrl('flag/confirm/flag/test_flag/' . $this->nid, array( 'query' => array( @@ -688,12 +874,18 @@ class FlagLinkTypeConfirmTestCase extends DrupalWebTestCase { $this->assertText($this->flag_data['flag_confirmation'], 'The flag confirmation text appears as the confirmation page title.'); + $this->assertPattern('@]* value="' . $flag_short_label . '" [^>]*>@', 'The flag text, excluding HTML, is shown in the button.'); + // Click the button to confirm the flagging. - $this->drupalPost(NULL, array(), $this->flag_data['flag_short']); + $this->drupalPost(NULL, array(), $flag_short_label); $this->assertText($this->flag_data['flag_message'], 'The flag message appears once the item has been flagged.'); $this->assertLink($this->flag_data['unflag_short'], 0, 'The unflag link appears once the item has been flagged.'); + // Reset the static cache before we get data from it. + drupal_static_reset('flag_get_user_flags'); + $this->assertTrue($this->flag->is_flagged($this->nid, $this->flag_unflag_user->uid), "The node is recorded as flagged by the user."); + // Click the link to unflag the node. $this->clickLink($this->flag_data['unflag_short']); @@ -709,6 +901,10 @@ class FlagLinkTypeConfirmTestCase extends DrupalWebTestCase { $this->drupalPost(NULL, array(), $this->flag_data['unflag_short']); $this->assertText($this->flag_data['unflag_message'], 'The unflag message appears once the item has been flagged.'); + + // Reset the static cache before we get data from it. + drupal_static_reset('flag_get_user_flags'); + $this->assertFalse($this->flag->is_flagged($this->nid, $this->flag_unflag_user->uid), "The node is recorded as not flagged by the user."); } } @@ -723,7 +919,7 @@ class FlagHookFlagAccessTestCase extends FlagTestCaseBase { */ public static function getInfo() { return array( - 'name' => 'Flag hook_flag_access() tests', + 'name' => 'hook_flag_access()', 'description' => 'Checks the ability of modules to use hook_flag_access().', 'group' => 'Flag', ); @@ -831,7 +1027,8 @@ class FlagHookFlagAccessTestCase extends FlagTestCaseBase { } /** - * Verifies that the user sees the flag if a module returns TRUE (Allow) to override default access check. + * Verifies that the user sees the flag if a module returns TRUE (Allow) to + * override default access check. */ function testFlagAccessAllowOverride() { variable_set('FlagHookFlagAccessTestCaseMode', 'allow'); @@ -855,7 +1052,8 @@ class FlagHookFlagAccessTestCase extends FlagTestCaseBase { } /** - * Verifies that the user does not see the flag if a module returns FALSE (Deny). + * Verifies that the user does not see the flag if a module returns FALSE + * (Deny). */ function testFlagAccessDeny() { variable_set('FlagHookFlagAccessTestCaseMode', 'deny'); @@ -870,6 +1068,83 @@ class FlagHookFlagAccessTestCase extends FlagTestCaseBase { } +/** + * Test use of fields on flagging entities. + */ +class FlagFlaggingFieldTestCase extends FlagTestCaseBase { + + /** + * Implements getInfo(). + */ + public static function getInfo() { + return array( + 'name' => 'Flagging fields', + 'description' => 'Fields on Flagging entities.', + 'group' => 'Flag', + ); + } + + /** + * Implements setUp(). + */ + function setUp() { + parent::setUp('flag', 'flag_fields_test'); + } + + function testFlaggingFields() { + $this->assertTrue(1); + + $flag_user = $this->drupalCreateUser(array( + 'flag flag_fields_test_flag', + 'unflag flag_fields_test_flag', + )); + $this->drupalLogin($flag_user); + + $node = $this->drupalCreateNode(); + + $this->drupalGet('node/' . $node->nid); + + $this->clickLink('Flag with the test flag'); + + // Try to fail the form validation by providing something non-numeric. + // This validation is only present in the widget validation: this is a core + // bug, but lets us test widget validation works correctly until it's fixed. + $edit = array( + 'flag_fields_test_integer[und][0][value]' => 'banana', + ); + $this->drupalPost(NULL, $edit, 'Flag with the test flag'); + + $this->assertText("Only numbers are allowed in Test integer.", "Form validation correctly failed the input."); + + // Try to fail the form validation by a number that's out of bounds. + $edit = array( + 'flag_fields_test_integer[und][0][value]' => 12, + ); + $this->drupalPost(NULL, $edit, 'Flag with the test flag'); + + $this->assertText("Test integer: the value may be no greater than 11.", "Form validation correctly failed the input."); + + $edit = array( + 'flag_fields_test_integer[und][0][value]' => 6, + ); + $this->drupalPost(NULL, $edit, 'Flag with the test flag'); + + $this->assertUrl('node/' . $node->nid, array(), "The flagging form submission succeeded."); + + // Try to load the flagging, querying for the field value. + $query = new EntityFieldQuery(); + $query->entityCondition('entity_type', 'flagging') + ->entityCondition('bundle', 'flag_fields_test_flag') + ->propertyCondition('entity_id', $node->nid) + ->fieldCondition('flag_fields_test_integer', 'value', 6); + + $result = $query->execute(); + + $this->assertEqual(count($result['flagging']), 1, "The Flagging entity was found with the correct field values."); + } + +} + /** * Test use of EntityFieldQueries with flagging entities. */ @@ -879,8 +1154,8 @@ class FlagEntityFieldQueryTestCase extends FlagTestCaseBase { * Implements getInfo(). */ public static function getInfo() { - return array( - 'name' => 'Flagging Entity Field Query Extension', + return array( + 'name' => 'Entity Field Query', 'description' => 'Entity Field Query for flagging entities.', 'group' => 'Flag', ); @@ -928,7 +1203,12 @@ class FlagEntityFieldQueryTestCase extends FlagTestCaseBase { $this->flag3 = $this->createFlag($flag_data); // Create test user who can flag and unflag. - $this->flag_unflag_user = $this->drupalCreateUser(array('flag test_flag_1', 'unflag test_flag_1', 'flag test_flag_2', 'unflag test_flag_2')); + $this->flag_unflag_user = $this->drupalCreateUser(array( + 'flag test_flag_1', + 'unflag test_flag_1', + 'flag test_flag_2', + 'unflag test_flag_2', + )); $this->drupalLogin($this->flag_unflag_user); } @@ -937,7 +1217,7 @@ class FlagEntityFieldQueryTestCase extends FlagTestCaseBase { * Test use of EntityFieldQuery with flagging entities. */ function testEntityFieldQuery() { - $node_settings = array( + $node_settings = array( 'title' => $this->randomName(), 'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(32)))), 'uid' => 1, @@ -969,3 +1249,410 @@ class FlagEntityFieldQueryTestCase extends FlagTestCaseBase { } } + +/** + * Verifies the invocation of hooks when performing flagging and unflagging. + */ +class FlagHookInvocationsTestCase extends FlagTestCaseBase { + + /** + * Implements getInfo(). + */ + public static function getInfo() { + return array( + 'name' => 'Hook invocations', + 'description' => 'Invocation of flag and entity hooks and rules during flagging and unflagging.', + 'group' => 'Flag', + ); + } + + /** + * Implements setUp(). + */ + function setUp() { + parent::setUp('flag', 'rules', 'flag_hook_test'); + + // Note the test module contains our test flag. + + // Create test user who can flag and unflag. + $this->flag_unflag_user = $this->drupalCreateUser(array('flag flag_hook_test_flag', 'unflag flag_hook_test_flag')); + $this->drupalLogin($this->flag_unflag_user); + } + + /** + * Test invocation of hooks and their data during flagging and unflagging. + * + * For each operation (flagging, re-flagging, unflagging) we test: + * - the order in which Flag hooks, entity hooks, and rules are invoked. + * - the parameters each hook receives + * - the data that a hook implementation obtains when it calls the Flag data + * API functions. + */ + function testHookInvocation() { + // Create an article node that we try to create a flagging entity for. + $title = $this->randomName(8); + $node = array( + 'title' => $title, + 'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(32)))), + 'uid' => 1, + 'type' => 'article', + 'is_new' => TRUE, + ); + $node = node_submit((object) $node); + node_save($node); + + // Initialize a tracking variable. The test module will update this when + // its hooks are invoked. + variable_set('flag_hook_test_hook_tracking', array()); + + // Flag the node as the user. + $flag = flag_get_flag('flag_hook_test_flag'); + $flag->flag('flag', $node->nid, $this->flag_unflag_user); + + // Get the variable the test module sets the hook order into. + $hook_data_variable = variable_get('flag_hook_test_hook_tracking', array()); + //debug($hook_data_variable['hook_entity_presave']); + //debug($hook_data_variable['hook_entity_insert']); + + $expected_hook_order = array( + 'hook_entity_presave', + 'hook_entity_insert', + 'hook_flag_flag', + 'rules_event', + ); + + // Check the hooks are invoked in the correct order. + $this->assertIdentical($expected_hook_order, array_keys($hook_data_variable), "The hooks are invoked in the correct order when flagging a node."); + + // Check the parameters received by hook_entity_presave(). + // Param 0: $flagging. + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][0]->flag_name, $flag->name, "The Flagging entity passed to hook_entity_presave() has the expected flag name property."); + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][0]->fid, $flag->fid, "The Flagging entity passed to hook_entity_presave() has the expected fid property."); + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][0]->entity_type, 'node', "The Flagging entity passed to hook_entity_presave() has the expected entity type property."); + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][0]->entity_id, $node->nid, "The Flagging entity passed to hook_entity_presave() has the expected entity ID property."); + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][0]->uid, $this->flag_unflag_user->uid, "The Flagging entity passed to hook_entity_presave() has the expected uid property."); + // Param 1: $entity_type. + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][1], 'flagging', "hook_entity_presave() is passed the correct entity type."); + + // Check the API data available to hook_entity_presave(). + //debug($hook_data_variable['hook_entity_presave']['api_calls']); + $this->assertEqual($hook_data_variable['hook_entity_presave']['api_calls']['flag_get_entity_flags'], array(), "hook_entity_presave() gets no data from from flag_get_entity_flags(), as the flagging has not yet taken place."); + $this->assertEqual($hook_data_variable['hook_entity_presave']['api_calls']['flag_get_user_flags'], array(), "hook_entity_presave() gets no data from from flag_get_user_flags(), as the flagging has not yet taken place."); + // The flag counts have not yet been increased. + $this->assertEqual($hook_data_variable['hook_entity_presave']['api_calls']['flag_get_counts'], array(), "hook_entity_presave() gets no data from from flag_get_counts(), as the flagging has not yet taken place."); + $this->assertEqual($hook_data_variable['hook_entity_presave']['api_calls']['flag_get_flag_counts'], 0, "hook_entity_presave() gets no data from from flag_get_flag_counts(), as the flagging has not yet taken place."); + $this->assertEqual($hook_data_variable['hook_entity_presave']['api_calls']['flag_get_entity_flag_counts'], 0, "hook_entity_presave() gets no data from from flag_get_entity_flag_counts(), as the flagging has not yet taken place."); + $this->assertEqual($hook_data_variable['hook_entity_presave']['api_calls']['flag_get_user_flag_counts'], 0, "hook_entity_presave() gets no data from from flag_get_user_flag_counts(), as the flagging has not yet taken place."); + + // Check the parameters received by hook_entity_insert(). + // Param 0: $flagging. + $this->assertEqual($hook_data_variable['hook_entity_insert']['parameters'][0]->flag_name, $flag->name, "The Flagging entity passed to hook_entity_insert() has the expected flag name property."); + $this->assertEqual($hook_data_variable['hook_entity_insert']['parameters'][0]->fid, $flag->fid, "The Flagging entity passed to hook_entity_insert() has the expected fid property."); + $this->assertEqual($hook_data_variable['hook_entity_insert']['parameters'][0]->entity_type, 'node', "The Flagging entity passed to hook_entity_insert() has the expected entity type property."); + $this->assertEqual($hook_data_variable['hook_entity_insert']['parameters'][0]->entity_id, $node->nid, "The Flagging entity passed to hook_entity_insert() has the expected entity ID property."); + $this->assertEqual($hook_data_variable['hook_entity_insert']['parameters'][0]->uid, $this->flag_unflag_user->uid, "The Flagging entity passed to hook_entity_insert() has the expected uid property."); + $this->assertTrue(!empty($hook_data_variable['hook_entity_insert']['parameters'][0]->flagging_id), "The Flagging entity passed to hook_entity_insert() has the flagging ID set."); + // Param 1: $entity_type. + $this->assertEqual($hook_data_variable['hook_entity_insert']['parameters'][1], 'flagging', "hook_entity_insert() is passed the correct entity type."); + + // Check the API data available to hook_entity_insert(). + //debug($hook_data_variable['hook_entity_insert']['api_calls']); + $flag_get_entity_flags = $hook_data_variable['hook_entity_insert']['api_calls']['flag_get_entity_flags']; + $flag_get_entity_flags_uids = array_keys($flag_get_entity_flags); + $this->assertEqual($flag_get_entity_flags_uids, array($this->flag_unflag_user->uid), "hook_entity_insert() gets correct data for flagging users from flag_get_entity_flags()"); + $flag_get_entity_flags_flagging = $flag_get_entity_flags[$this->flag_unflag_user->uid]; + $this->assertEqual($flag_get_entity_flags_flagging->fid, $flag->fid, "hook_entity_insert() gets a correct fid on the Flagging obtained from flag_get_entity_flags()"); + $this->assertEqual($flag_get_entity_flags_flagging->entity_type, 'node', "hook_entity_insert() gets a correct entity type on the Flagging obtained from flag_get_entity_flags()"); + $this->assertEqual($flag_get_entity_flags_flagging->entity_id, $node->nid, "hook_entity_insert() gets a correct entity ID on the Flagging obtained from flag_get_entity_flags()"); + + $flag_get_user_flags = $hook_data_variable['hook_entity_insert']['api_calls']['flag_get_user_flags']; + $flag_get_user_flags_flagging = $flag_get_user_flags[$flag->name]; + $this->assertEqual($flag_get_user_flags_flagging->fid, $flag->fid, "hook_entity_insert() gets a correct fid on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_type, 'node', "hook_entity_insert() gets a correct entity type on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_id, $node->nid, "hook_entity_insert() gets a correct entity ID on the Flagging obtained from flag_get_user_flags()"); + + // The flag counts have been increased. + $flag_get_counts = $hook_data_variable['hook_entity_insert']['api_calls']['flag_get_counts']; + $this->assertEqual($flag_get_counts[$flag->name], 1, "hook_entity_insert() gets a correct flag count from flag_get_counts()."); + + $flag_get_flag_counts = $hook_data_variable['hook_entity_insert']['api_calls']['flag_get_flag_counts']; + $this->assertEqual($flag_get_flag_counts, 1, "hook_entity_insert() gets a correct flag count from flag_get_flag_counts()."); + + $flag_get_entity_flag_counts = $hook_data_variable['hook_entity_insert']['api_calls']['flag_get_entity_flag_counts']; + $this->assertEqual($flag_get_entity_flag_counts, 1, "hook_entity_insert() gets a correct flag count from flag_get_entity_flag_counts()."); + + $flag_get_user_flag_counts = $hook_data_variable['hook_entity_insert']['api_calls']['flag_get_user_flag_counts']; + $this->assertEqual($flag_get_user_flag_counts, 1, "hook_entity_insert() gets a correct flag count from flag_get_user_flag_counts()."); + + // Check the parameters received by hook_flag_flag(). + // Param 0: $flag. + $this->assertEqual($hook_data_variable['hook_flag_flag']['parameters'][0], $flag, "The flag object is passed to hook_flag_flag()."); + // Param 1: $entity_id. + $this->assertEqual($hook_data_variable['hook_flag_flag']['parameters'][1], $node->nid, "The entity ID is passed to hook_flag_flag()."); + // Param 2: $account. + $this->assertEqual($hook_data_variable['hook_flag_flag']['parameters'][2]->uid, $this->flag_unflag_user->uid, "The user account is passed to hook_flag_flag()."); + // Param 3: $flagging. + $this->assertEqual($hook_data_variable['hook_flag_flag']['parameters'][3]->flag_name, $flag->name, "The Flagging entity passed to hook_flag_flag() has the expected flag name property."); + $this->assertEqual($hook_data_variable['hook_flag_flag']['parameters'][3]->fid, $flag->fid, "The Flagging entity passed to hook_flag_flag() has the expected fid property."); + $this->assertEqual($hook_data_variable['hook_flag_flag']['parameters'][3]->entity_type, 'node', "The Flagging entity passed to hook_flag_flag() has the expected entity type property."); + $this->assertEqual($hook_data_variable['hook_flag_flag']['parameters'][3]->entity_id, $node->nid, "The Flagging entity passed to hook_flag_flag() has the expected entity ID property."); + $this->assertEqual($hook_data_variable['hook_flag_flag']['parameters'][3]->uid, $this->flag_unflag_user->uid, "The Flagging entity passed to hook_flag_flag() has the expected uid property."); + + // Check the API data available to hook_flag_flag(). + //debug($hook_data_variable['hook_flag_flag']['api_calls']); + $flag_get_entity_flags = $hook_data_variable['hook_flag_flag']['api_calls']['flag_get_entity_flags']; + $flag_get_entity_flags_uids = array_keys($flag_get_entity_flags); + $this->assertEqual($flag_get_entity_flags_uids, array($this->flag_unflag_user->uid), "hook_flag_flag() gets correct data for flagging users from flag_get_entity_flags()"); + $flag_get_entity_flags_flagging = $flag_get_entity_flags[$this->flag_unflag_user->uid]; + $this->assertEqual($flag_get_entity_flags_flagging->fid, $flag->fid, "hook_flag_flag() gets a correct fid on the Flagging obtained from flag_get_entity_flags()"); + $this->assertEqual($flag_get_entity_flags_flagging->entity_type, 'node', "hook_flag_flag() gets a correct entity type on the Flagging obtained from flag_get_entity_flags()"); + $this->assertEqual($flag_get_entity_flags_flagging->entity_id, $node->nid, "hook_flag_flag() gets a correct entity ID on the Flagging obtained from flag_get_entity_flags()"); + + $flag_get_user_flags = $hook_data_variable['hook_flag_flag']['api_calls']['flag_get_user_flags']; + $flag_get_user_flags_flagging = $flag_get_user_flags[$flag->name]; + $this->assertEqual($flag_get_user_flags_flagging->fid, $flag->fid, "hook_flag_flag() gets a correct fid on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_type, 'node', "hook_flag_flag() gets a correct entity type on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_id, $node->nid, "hook_flag_flag() gets a correct entity ID on the Flagging obtained from flag_get_user_flags()"); + + // The flag counts have been increased. + $flag_get_counts = $hook_data_variable['hook_flag_flag']['api_calls']['flag_get_counts']; + $this->assertEqual($flag_get_counts[$flag->name], 1, "hook_flag_flag() gets a correct flag count from flag_get_counts()."); + + $flag_get_flag_counts = $hook_data_variable['hook_flag_flag']['api_calls']['flag_get_flag_counts']; + $this->assertEqual($flag_get_flag_counts, 1, "hook_flag_flag() gets a correct flag count from flag_get_flag_counts()."); + + $flag_get_entity_flag_counts = $hook_data_variable['hook_flag_flag']['api_calls']['flag_get_entity_flag_counts']; + $this->assertEqual($flag_get_entity_flag_counts, 1, "hook_flag_flag() gets a correct flag count from flag_get_entity_flag_counts()."); + + $flag_get_user_flag_counts = $hook_data_variable['hook_flag_flag']['api_calls']['flag_get_user_flag_counts']; + $this->assertEqual($flag_get_user_flag_counts, 1, "hook_flag_flag() gets a correct flag count from flag_get_user_flag_counts()."); + + // Clear the tracking variable. + variable_set('flag_hook_test_hook_tracking', array()); + + // Get the Flagging, and re-flag the node. + // This does nothing in our case, but is the API for updating a Flagging + // entity with changes to its Field API fields. + // Query the database to get the Flagging ID rather than Flag API so we + // don't interefere with any caches. + $query = db_select('flagging', 'f'); + $query->addField('f', 'flagging_id'); + $query->condition('fid', $flag->fid) + ->condition('entity_id', $node->nid); + $flagging_id = $query + ->execute() + ->fetchField(); + $flagging = flagging_load($flagging_id); + + // Re-flag the node passing in the flagging entity. + $flag->flag('flag', $node->nid, $this->flag_unflag_user, FALSE, $flagging); + + // Get the variable the test module sets the hook order into. + $hook_data_variable = variable_get('flag_hook_test_hook_tracking', array()); + //debug($hook_data_variable); + + $expected_hook_order = array( + 'hook_entity_presave', + 'hook_entity_update', + // Note that hook_flag() and the rule are not invoked, as this is not a + // new act of flagging. + ); + + // Check the hooks are invoked in the correct order. + $this->assertIdentical($expected_hook_order, array_keys($hook_data_variable), "The hooks are invoked in the correct order when re-flagging a node."); + + // Check the parameters received by hook_entity_presave(). + // Param 0: $flagging. + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][0]->flag_name, $flag->name, "The Flagging entity passed to hook_entity_presave() has the expected flag name property."); + //$this->assertEqual($hook_data_variable['hook_entity_insert']['parameters'][0]->fid, $flag->fid); + //$this->assertEqual($hook_data_variable['hook_entity_insert']['parameters'][0]->entity_type, 'node'); + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][0]->entity_id, $node->nid, "The Flagging entity passed to hook_entity_presave() has the expected entity ID property."); + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][0]->uid, $this->flag_unflag_user->uid, "The Flagging entity passed to hook_entity_presave() has the expected uid property."); + // Param 1: $entity_type. + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][1], 'flagging', "hook_entity_presave() is passed the correct entity type."); + + // Check the API data available to hook_entity_presave(). + //debug($hook_data_variable['hook_entity_presave']['api_calls']); + $flag_get_entity_flags = $hook_data_variable['hook_entity_presave']['api_calls']['flag_get_entity_flags']; + $flag_get_entity_flags_uids = array_keys($flag_get_entity_flags); + $this->assertEqual($flag_get_entity_flags_uids, array($this->flag_unflag_user->uid), "hook_entity_presave() gets correct data for flagging users from flag_get_entity_flags()"); + $flag_get_entity_flags_flagging = $flag_get_entity_flags[$this->flag_unflag_user->uid]; + $this->assertEqual($flag_get_entity_flags_flagging->fid, $flag->fid, "hook_entity_presave() gets a correct fid on the Flagging obtained from flag_get_entity_flags()"); + $this->assertEqual($flag_get_entity_flags_flagging->entity_type, 'node', "hook_entity_presave() gets a correct entity type on the Flagging obtained from flag_get_entity_flags()"); + $this->assertEqual($flag_get_entity_flags_flagging->entity_id, $node->nid, "hook_entity_presave() gets a correct entity ID on the Flagging obtained from flag_get_entity_flags()"); + + $flag_get_user_flags = $hook_data_variable['hook_entity_presave']['api_calls']['flag_get_user_flags']; + $flag_get_user_flags_flagging = $flag_get_user_flags[$flag->name]; + $this->assertEqual($flag_get_user_flags_flagging->fid, $flag->fid, "hook_entity_presave() gets a correct fid on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_type, 'node', "hook_entity_presave() gets a correct entity type on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_id, $node->nid, "hook_entity_presave() gets a correct entity ID on the Flagging obtained from flag_get_user_flags()"); + + // The flag counts have not changed. + $flag_get_counts = $hook_data_variable['hook_entity_presave']['api_calls']['flag_get_counts']; + $this->assertEqual($flag_get_counts[$flag->name], 1, "hook_entity_presave() gets a correct flag count from flag_get_counts()."); + + $flag_get_flag_counts = $hook_data_variable['hook_entity_presave']['api_calls']['flag_get_flag_counts']; + $this->assertEqual($flag_get_flag_counts, 1, "hook_entity_presave() gets a correct flag count from flag_get_flag_counts()."); + + $flag_get_entity_flag_counts = $hook_data_variable['hook_entity_presave']['api_calls']['flag_get_entity_flag_counts']; + $this->assertEqual($flag_get_entity_flag_counts, 1, "hook_entity_presave() gets a correct flag count from flag_get_entity_flag_counts()."); + + $flag_get_user_flag_counts = $hook_data_variable['hook_entity_presave']['api_calls']['flag_get_user_flag_counts']; + $this->assertEqual($flag_get_user_flag_counts, 1, "hook_entity_presave() gets a correct flag count from flag_get_user_flag_counts()."); + + // Check the parameters received by hook_entity_update(). + // Param 0: $flagging. + $this->assertEqual($hook_data_variable['hook_entity_update']['parameters'][0]->flag_name, $flag->name, "The Flagging entity passed to hook_entity_update() has the expected flag name property."); + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][0]->fid, $flag->fid, "The Flagging entity passed to hook_entity_presave() has the expected fid property."); + $this->assertEqual($hook_data_variable['hook_entity_presave']['parameters'][0]->entity_type, 'node', "The Flagging entity passed to hook_entity_presave() has the expected entity type property."); + $this->assertEqual($hook_data_variable['hook_entity_update']['parameters'][0]->entity_id, $node->nid, "The Flagging entity passed to hook_entity_update() has the expected entity ID property."); + $this->assertEqual($hook_data_variable['hook_entity_update']['parameters'][0]->uid, $this->flag_unflag_user->uid, "The Flagging entity passed to hook_entity_update() has the expected uid property."); + $this->assertTrue(!empty($hook_data_variable['hook_entity_update']['parameters'][0]->flagging_id), "The Flagging entity passed to hook_entity_update() has the flagging ID set."); + // Param 1: $entity_type. + $this->assertEqual($hook_data_variable['hook_entity_update']['parameters'][1], 'flagging', "hook_entity_update() is passed the correct entity type."); + + // Check the API data available to hook_entity_update(). + //debug($hook_data_variable['hook_entity_update']['api_calls']); + $flag_get_entity_flags = $hook_data_variable['hook_entity_update']['api_calls']['flag_get_entity_flags']; + $flag_get_entity_flags_uids = array_keys($flag_get_entity_flags); + $this->assertEqual($flag_get_entity_flags_uids, array($this->flag_unflag_user->uid), "hook_entity_update() gets correct data for flagging users from flag_get_entity_flags()"); + $flag_get_entity_flags_flagging = $flag_get_entity_flags[$this->flag_unflag_user->uid]; + $this->assertEqual($flag_get_entity_flags_flagging->fid, $flag->fid, "hook_entity_update() gets a correct fid on the Flagging obtained from flag_get_entity_flags()"); + $this->assertEqual($flag_get_entity_flags_flagging->entity_type, 'node', "hook_entity_update() gets a correct entity type on the Flagging obtained from flag_get_entity_flags()"); + $this->assertEqual($flag_get_entity_flags_flagging->entity_id, $node->nid, "hook_entity_update() gets a correct entity ID on the Flagging obtained from flag_get_entity_flags()"); + + $flag_get_user_flags = $hook_data_variable['hook_entity_update']['api_calls']['flag_get_user_flags']; + $flag_get_user_flags_flagging = $flag_get_user_flags[$flag->name]; + $this->assertEqual($flag_get_user_flags_flagging->fid, $flag->fid, "hook_entity_update() gets a correct fid on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_type, 'node', "hook_entity_update() gets a correct entity type on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_id, $node->nid, "hook_entity_update() gets a correct entity ID on the Flagging obtained from flag_get_user_flags()"); + + // The flag counts have not changed. + $flag_get_counts = $hook_data_variable['hook_entity_update']['api_calls']['flag_get_counts']; + $this->assertEqual($flag_get_counts[$flag->name], 1, "hook_entity_update() gets a correct flag count from flag_get_counts()."); + + $flag_get_flag_counts = $hook_data_variable['hook_entity_update']['api_calls']['flag_get_flag_counts']; + $this->assertEqual($flag_get_flag_counts, 1, "hook_entity_update() gets a correct flag count from flag_get_flag_counts()."); + + $flag_get_entity_flag_counts = $hook_data_variable['hook_entity_update']['api_calls']['flag_get_entity_flag_counts']; + $this->assertEqual($flag_get_entity_flag_counts, 1, "hook_entity_update() gets a correct flag count from flag_get_entity_flag_counts()."); + + $flag_get_user_flag_counts = $hook_data_variable['hook_entity_update']['api_calls']['flag_get_user_flag_counts']; + $this->assertEqual($flag_get_user_flag_counts, 1, "hook_entity_update() gets a correct flag count from flag_get_user_flag_counts()."); + + // Clear the tracking variable. + variable_set('flag_hook_test_hook_tracking', array()); + + // Unflag the node as the user. + $flag->flag('unflag', $node->nid, $this->flag_unflag_user); + + // Get the variable the test module sets the hook order into. + $hook_data_variable = variable_get('flag_hook_test_hook_tracking', array()); + //debug($hook_data_variable); + + $expected_hook_order = array( + 'hook_flag_unflag', + 'rules_event', + 'hook_entity_delete', + ); + + // Check the hooks are invoked in the correct order. + $this->assertIdentical($expected_hook_order, array_keys($hook_data_variable), "The hooks are invoked in the correct order when unflagging a node."); + + // Check the parameters received by hook_flag_unflag(). + // Param 0: $flag. + $this->assertEqual($hook_data_variable['hook_flag_unflag']['parameters'][0], $flag, "The flag object is passed to hook_flag_unflag()."); + // Param 1: $entity_id. + $this->assertEqual($hook_data_variable['hook_flag_unflag']['parameters'][1], $node->nid, "The entity ID is passed to hook_flag_unflag()."); + // Param 2: $account. + $this->assertEqual($hook_data_variable['hook_flag_unflag']['parameters'][2]->uid, $this->flag_unflag_user->uid, "The user account is passed to hook_flag_unflag()."); + // Param 3: $flagging. + $this->assertEqual($hook_data_variable['hook_flag_unflag']['parameters'][3]->flag_name, $flag->name, "The Flagging entity passed to hook_flag_unflag() has the expected flag name property."); + $this->assertEqual($hook_data_variable['hook_flag_unflag']['parameters'][3]->fid, $flag->fid, "The Flagging entity passed to hook_entity_presave() has the expected fid property."); + $this->assertEqual($hook_data_variable['hook_flag_unflag']['parameters'][3]->entity_type, 'node', "The Flagging entity passed to hook_entity_presave() has the expected entity type property."); + $this->assertEqual($hook_data_variable['hook_flag_unflag']['parameters'][3]->entity_id, $node->nid, "The Flagging entity passed to hook_flag_unflag() has the expected entity ID property."); + $this->assertEqual($hook_data_variable['hook_flag_unflag']['parameters'][3]->uid, $this->flag_unflag_user->uid, "The Flagging entity passed to hook_flag_unflag() has the expected uid property."); + + // Check the API data available to hook_flag_unflag(). + //debug($hook_data_variable['hook_flag_unflag']['api_calls']); + // The unflagging is not yet done, so flag_get_entity_flags() will find the + // flagging data. + $flag_get_entity_flags = $hook_data_variable['hook_flag_unflag']['api_calls']['flag_get_entity_flags']; + $flag_get_entity_flags_uids = array_keys($flag_get_entity_flags); + $this->assertEqual($flag_get_entity_flags_uids, array($this->flag_unflag_user->uid), "hook_flag_unflag() gets correct data for flagging users from flag_get_entity_flags()"); + $flag_get_entity_flags_flagging = $flag_get_entity_flags[$this->flag_unflag_user->uid]; + $this->assertEqual($flag_get_entity_flags_flagging->fid, $flag->fid, "hook_flag_unflag() gets a correct fid on the Flagging obtained from flag_get_entity_flags(): the Flagging has not yet been deleted."); + $this->assertEqual($flag_get_entity_flags_flagging->entity_type, 'node', "hook_flag_unflag() gets a correct entity type on the Flagging obtained from flag_get_entity_flags()"); + $this->assertEqual($flag_get_entity_flags_flagging->entity_id, $node->nid, "hook_flag_unflag() gets a correct entity ID on the Flagging obtained from flag_get_entity_flags()"); + + $flag_get_user_flags = $hook_data_variable['hook_flag_unflag']['api_calls']['flag_get_user_flags']; + $flag_get_user_flags_flagging = $flag_get_user_flags[$flag->name]; + $this->assertEqual($flag_get_user_flags_flagging->fid, $flag->fid, "hook_flag_unflag() gets a correct fid on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_type, 'node', "hook_flag_unflag() gets a correct entity type on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_id, $node->nid, "hook_flag_unflag() gets a correct entity ID on the Flagging obtained from flag_get_user_flags()"); + + // The flag counts have already been decreased. + $flag_get_counts = $hook_data_variable['hook_flag_unflag']['api_calls']['flag_get_counts']; + $this->assertEqual($flag_get_counts, array(), "hook_flag_unflag() gets a correct flag count from flag_get_counts()."); + + $flag_get_flag_counts = $hook_data_variable['hook_flag_unflag']['api_calls']['flag_get_flag_counts']; + $this->assertEqual($flag_get_flag_counts, 0, "hook_flag_unflag() gets a correct flag count from flag_get_flag_counts()."); + + // flag_get_entity_flag_counts() queries the {flagging} table, so is not + // updated yet. + $flag_get_entity_flag_counts = $hook_data_variable['hook_flag_unflag']['api_calls']['flag_get_entity_flag_counts']; + $this->assertEqual($flag_get_entity_flag_counts, 1, "hook_flag_unflag() gets a correct flag count from flag_get_entity_flag_counts()."); + + // flag_get_user_flag_counts() queries the {flagging} table, so is not + // updated yet. + $flag_get_user_flag_counts = $hook_data_variable['hook_flag_unflag']['api_calls']['flag_get_user_flag_counts']; + $this->assertEqual($flag_get_user_flag_counts, 1, "hook_flag_unflag() gets a correct flag count from flag_get_user_flag_counts()."); + + // Check the parameters received by hook_entity_delete(). + // Param 0: $flagging. + $this->assertEqual($hook_data_variable['hook_entity_delete']['parameters'][0]->flag_name, $flag->name, "The Flagging entity passed to hook_entity_delete() has the expected flag name property."); + $this->assertEqual($hook_data_variable['hook_entity_delete']['parameters'][0]->fid, $flag->fid, "The Flagging entity passed to hook_entity_presave() has the expected fid property."); + $this->assertEqual($hook_data_variable['hook_entity_delete']['parameters'][0]->entity_type, 'node', "The Flagging entity passed to hook_entity_presave() has the expected entity type property."); + $this->assertEqual($hook_data_variable['hook_entity_delete']['parameters'][0]->entity_id, $node->nid, "The Flagging entity passed to hook_entity_delete() has the expected entity ID property."); + $this->assertEqual($hook_data_variable['hook_entity_delete']['parameters'][0]->uid, $this->flag_unflag_user->uid, "The Flagging entity passed to hook_entity_delete() has the expected uid property."); + $this->assertTrue(!empty($hook_data_variable['hook_entity_delete']['parameters'][0]->flagging_id), "The Flagging entity passed to hook_entity_delete() has the flagging ID set."); + // Param 1: $entity_type. + $this->assertEqual($hook_data_variable['hook_entity_delete']['parameters'][1], 'flagging', "hook_entity_delete() is passed the correct entity type."); + + // Check the API data available to hook_entity_delete(). + //debug($hook_data_variable['hook_entity_delete']['api_calls']); + // The unflagging is not yet done, so hook_entity_delete() will find the + // flagging data. + $flag_get_entity_flags = $hook_data_variable['hook_entity_delete']['api_calls']['flag_get_entity_flags']; + $flag_get_entity_flags_uids = array_keys($flag_get_entity_flags); + $this->assertEqual($flag_get_entity_flags_uids, array($this->flag_unflag_user->uid), "hook_entity_delete() gets correct data for flagging users from flag_get_entity_flags()"); + $flag_get_entity_flags_flagging = $flag_get_entity_flags[$this->flag_unflag_user->uid]; + $this->assertEqual($flag_get_entity_flags_flagging->fid, $flag->fid, "hook_entity_delete() gets a correct fid on the Flagging obtained from flag_get_entity_flags()"); + $this->assertEqual($flag_get_entity_flags_flagging->entity_type, 'node', "hook_entity_delete() gets a correct entity type on the Flagging obtained from flag_get_entity_flags()"); + $this->assertEqual($flag_get_entity_flags_flagging->entity_id, $node->nid, "hook_entity_delete() gets a correct entity ID on the Flagging obtained from flag_get_entity_flags()"); + + $flag_get_user_flags = $hook_data_variable['hook_entity_delete']['api_calls']['flag_get_user_flags']; + $flag_get_user_flags_flagging = $flag_get_user_flags[$flag->name]; + $this->assertEqual($flag_get_user_flags_flagging->fid, $flag->fid, "hook_entity_delete() gets a correct fid on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_type, 'node', "hook_entity_delete() gets a correct entity type on the Flagging obtained from flag_get_user_flags()"); + $this->assertEqual($flag_get_user_flags_flagging->entity_id, $node->nid, "hook_entity_delete() gets a correct entity ID on the Flagging obtained from flag_get_user_flags()"); + + // The flag counts have already been decreased. + $flag_get_counts = $hook_data_variable['hook_entity_delete']['api_calls']['flag_get_counts']; + $this->assertEqual($flag_get_counts, array(), "hook_entity_delete() gets a correct flag count from flag_get_counts()."); + + $flag_get_flag_counts = $hook_data_variable['hook_entity_delete']['api_calls']['flag_get_flag_counts']; + $this->assertEqual($flag_get_flag_counts, 0, "hook_entity_delete() gets a correct flag count from flag_get_flag_counts()."); + + // flag_get_entity_flag_counts() queries the {flagging} table, so is not + // updated yet. + $flag_get_entity_flag_counts = $hook_data_variable['hook_entity_delete']['api_calls']['flag_get_entity_flag_counts']; + $this->assertEqual($flag_get_entity_flag_counts, 1, "hook_entity_delete() gets a correct flag count from flag_get_entity_flag_counts()."); + + // flag_get_user_flag_counts() queries the {flagging} table, so is not + // updated yet. + $flag_get_user_flag_counts = $hook_data_variable['hook_entity_delete']['api_calls']['flag_get_user_flag_counts']; + $this->assertEqual($flag_get_user_flag_counts, 1, "hook_entity_delete() gets a correct flag count from flag_get_user_flag_counts()."); + } + +} diff --git a/sites/all/modules/contrib/flag/flag/tests/flag_fields_test/flag_fields_test.info b/sites/all/modules/contrib/flag/flag/tests/flag_fields_test/flag_fields_test.info new file mode 100644 index 00000000..d2d49887 --- /dev/null +++ b/sites/all/modules/contrib/flag/flag/tests/flag_fields_test/flag_fields_test.info @@ -0,0 +1,12 @@ +name = Flag Fields Test +description = Test module for fields on Flagging entities. +dependencies[] = flag +core = 7.x +hidden = TRUE + +; Information added by Drupal.org packaging script on 2015-03-02 +version = "7.x-3.6" +core = "7.x" +project = "flag" +datestamp = "1425327793" + diff --git a/sites/all/modules/contrib/flag/flag/tests/flag_fields_test/flag_fields_test.install b/sites/all/modules/contrib/flag/flag/tests/flag_fields_test/flag_fields_test.install new file mode 100644 index 00000000..ee4376c6 --- /dev/null +++ b/sites/all/modules/contrib/flag/flag/tests/flag_fields_test/flag_fields_test.install @@ -0,0 +1,67 @@ + 'flag_fields_test_integer', + 'type' => 'number_integer', + 'cardinality' => '1', + 'settings' => array(), + ); + field_create_field($field); + + $instance = array( + 'field_name' => 'flag_fields_test_integer', + 'entity_type' => 'flagging', + 'bundle' => 'flag_fields_test_flag', + 'label' => 'Test integer', + 'widget' => array( + 'weight' => 0, + 'type' => 'number', + 'module' => 'number', + 'active' => 0, + 'settings' => array(), + ), + 'settings' => array( + 'min' => '', + 'max' => '11', + 'prefix' => '', + 'suffix' => '', + 'user_register_form' => FALSE, + ), + 'display' => array( + 'default' => array( + 'label' => 'above', + 'type' => 'number_integer', + 'settings' => array( + 'thousand_separator' => ' ', + 'decimal_separator' => '.', + 'scale' => 0, + 'prefix_suffix' => TRUE, + ), + 'module' => 'number', + 'weight' => 1, + ), + ), + ); + field_create_instance($instance); +} + +/** + * Implements hook_uninstall(). + * + * Not needed for testing, but useful for when developing tests as it allows + * use of Devel module's reinstall tool. + */ +function flag_fields_test_uninstall() { + // Delete our fields. + field_delete_field('flag_fields_test_integer'); +} diff --git a/sites/all/modules/contrib/flag/flag/tests/flag_fields_test/flag_fields_test.module b/sites/all/modules/contrib/flag/flag/tests/flag_fields_test/flag_fields_test.module new file mode 100644 index 00000000..cf64a80d --- /dev/null +++ b/sites/all/modules/contrib/flag/flag/tests/flag_fields_test/flag_fields_test.module @@ -0,0 +1,45 @@ + 'node', + 'title' => 'Flag fields test', + 'global' => 1, + 'types' => array(), + 'flag_short' => 'Flag with the test flag', + 'flag_long' => '', + 'flag_message' => '', + 'unflag_short' => 'Unflag', + 'unflag_long' => '', + 'unflag_message' => '', + 'unflag_denied_text' => '', + 'link_type' => 'confirm', + 'weight' => -15, + 'show_in_links' => array( + 'full' => 'full', + 'teaser' => 'teaser', + 'rss' => 0, + 'token' => 0, + 'revision' => 0, + ), + 'show_as_field' => 0, + 'show_on_form' => 0, + 'access_author' => '', + 'show_contextual_link' => 0, + 'i18n' => 0, + 'flag_confirmation' => 'Confirm flagging this node', + 'unflag_confirmation' => 'Confirm unflagging this node', + 'api_version' => 3, + ); + return $flags; +} diff --git a/sites/all/modules/contrib/flag/flag/tests/flag_hook_test/flag_hook_test.info b/sites/all/modules/contrib/flag/flag/tests/flag_hook_test/flag_hook_test.info new file mode 100644 index 00000000..942cc637 --- /dev/null +++ b/sites/all/modules/contrib/flag/flag/tests/flag_hook_test/flag_hook_test.info @@ -0,0 +1,13 @@ +name = Flag Hooks Test +description = Test module for invocation of flag hooks. +dependencies[] = flag +dependencies[] = rules +core = 7.x +hidden = TRUE + +; Information added by Drupal.org packaging script on 2015-03-02 +version = "7.x-3.6" +core = "7.x" +project = "flag" +datestamp = "1425327793" + diff --git a/sites/all/modules/contrib/flag/flag/tests/flag_hook_test/flag_hook_test.module b/sites/all/modules/contrib/flag/flag/tests/flag_hook_test/flag_hook_test.module new file mode 100644 index 00000000..732af512 --- /dev/null +++ b/sites/all/modules/contrib/flag/flag/tests/flag_hook_test/flag_hook_test.module @@ -0,0 +1,184 @@ +fid); + + $variable[$hook_name]['api_calls'] = array(); + + $variable[$hook_name]['api_calls']['flag_get_entity_flags'] = flag_get_entity_flags('node', $flagging->entity_id, $flag->name); + + $variable[$hook_name]['api_calls']['flag_get_user_flags'] = flag_get_user_flags('node', $flagging->entity_id, $flagging->uid); + + $variable[$hook_name]['api_calls']['flag_get_counts'] = flag_get_counts('node', $flagging->entity_id); + + $variable[$hook_name]['api_calls']['flag_get_flag_counts'] = flag_get_flag_counts($flag->name); + + $variable[$hook_name]['api_calls']['flag_get_entity_flag_counts'] = flag_get_entity_flag_counts($flag, 'node'); + + $account = user_load($flagging->uid); + $variable[$hook_name]['api_calls']['flag_get_user_flag_counts'] = flag_get_user_flag_counts($flag, $account); + } + + variable_set('flag_hook_test_hook_tracking', $variable); +} + +/** + * Implements hook_flag_flag(). + */ +function flag_hook_test_flag_flag($flag, $entity_id, $account, $flagging) { + _flag_hook_test_record_invocation('hook_flag_flag', func_get_args(), $flagging); +} + +/** + * Implements hook_flag_unflag(). + */ +function flag_hook_test_flag_unflag($flag, $entity_id, $account, $flagging) { + _flag_hook_test_record_invocation('hook_flag_unflag', func_get_args(), $flagging); +} + +/** + * Implements hook_entity_presave(). + */ +function flag_hook_test_entity_presave($entity, $type) { + if ($type == 'flagging') { + _flag_hook_test_record_invocation('hook_entity_presave', func_get_args(), $entity); + } +} + +/** + * Implements hook_entity_insert(). + */ +function flag_hook_test_entity_insert($entity, $type) { + if ($type == 'flagging') { + _flag_hook_test_record_invocation('hook_entity_insert', func_get_args(), $entity); + } +} + +/** + * Implements hook_entity_update(). + */ +function flag_hook_test_entity_update($entity, $type) { + if ($type == 'flagging') { + _flag_hook_test_record_invocation('hook_entity_update', func_get_args(), $entity); + } +} + +/** + * Implements hook_entity_delete(). + */ +function flag_hook_test_entity_delete($entity, $type) { + if ($type == 'flagging') { + _flag_hook_test_record_invocation('hook_entity_delete', func_get_args(), $entity); + } +} + +// ========================================================= Configuration + +/** + * Implements hook_flag_default_flags(). + */ +function flag_hook_test_flag_default_flags() { + $flags = array(); + $flags['flag_hook_test_flag'] = array( + 'entity_type' => 'node', + 'title' => 'Test Flag', + 'global' => FALSE, + 'types' => array( + 0 => 'article', + ), + 'flag_short' => 'Flag this', + 'flag_long' => 'Flag this post', + 'flag_message' => 'This post has been flagged', + 'unflag_short' => 'Unflag this', + 'unflag_long' => 'Remove this post from your flagged items', + 'unflag_message' => 'This post has been unflagged', + 'unflag_denied_text' => 'You may not unflag this item', + 'link_type' => 'normal', + 'weight' => 0, + 'show_in_links' => array( + 'full' => TRUE, + 'teaser' => TRUE, + ), + 'show_as_field' => FALSE, + 'show_on_form' => FALSE, + 'access_author' => '', + 'show_contextual_link' => TRUE, + 'show_on_profile' => FALSE, + 'access_uid' => '', + 'api_version' => 3, + ); + return $flags; +} + +/** + * Implements hook_rules_action_info(). + */ +function flag_hook_test_rules_action_info() { + return array( + 'flag_test_action' => array( + 'label' => t('Flag test action'), + 'group' => t('Flag test'), + ), + ); +} + +/** + * Test action for flagging. + */ +function flag_test_action() { + _flag_hook_test_record_invocation('rules_event', func_get_args()); +} + +/** + * Implements hook_default_rules_configuration(). + */ +function flag_hook_test_default_rules_configuration() { + $configs['flag_test_rule_flag'] = rules_import('{ "flag_test_rule" : { + "LABEL" : "Flag test rule", + "PLUGIN" : "reaction rule", + "OWNER" : "rules", + "REQUIRES" : [ "flag_hook_test", "flag" ], + "ON" : { "flag_flagged_flag_hook_test_flag" : [] }, + "DO" : [ { "flag_test_action" : [] } ] + } + }'); + + $configs['flag_test_rule_unflag'] = rules_import('{ "flag_test_rule" : { + "LABEL" : "Flag test rule", + "PLUGIN" : "reaction rule", + "OWNER" : "rules", + "REQUIRES" : [ "flag_hook_test", "flag" ], + "ON" : { "flag_unflagged_flag_hook_test_flag" : [] }, + "DO" : [ { "flag_test_action" : [] } ] + } + }'); + + return $configs; +} diff --git a/sites/all/modules/contrib/flag/flag/tests/flagaccesstest/flagaccesstest.info b/sites/all/modules/contrib/flag/flag/tests/flagaccesstest/flagaccesstest.info index a8a00282..a5a2560f 100644 --- a/sites/all/modules/contrib/flag/flag/tests/flagaccesstest/flagaccesstest.info +++ b/sites/all/modules/contrib/flag/flag/tests/flagaccesstest/flagaccesstest.info @@ -5,9 +5,9 @@ dependencies[] = flag package = Flags hidden = TRUE -; Information added by drupal.org packaging script on 2013-09-13 -version = "7.x-3.2" +; Information added by Drupal.org packaging script on 2015-03-02 +version = "7.x-3.6" core = "7.x" project = "flag" -datestamp = "1379063829" +datestamp = "1425327793" diff --git a/sites/all/modules/contrib/flag/flag/theme/flag.js b/sites/all/modules/contrib/flag/flag/theme/flag.js index add009a3..3f1aedcf 100644 --- a/sites/all/modules/contrib/flag/flag/theme/flag.js +++ b/sites/all/modules/contrib/flag/flag/theme/flag.js @@ -98,7 +98,7 @@ Drupal.flagLink = function(context) { $wrapper.removeClass('flag-waiting'); } }); - }; + } $('a.flag-link-toggle:not(.flag-processed)', context).addClass('flag-processed').click(flagClick); }; diff --git a/sites/all/modules/contrib/flag/flag/theme/flag.tpl.php b/sites/all/modules/contrib/flag/flag/theme/flag.tpl.php index 60a31139..070ed504 100644 --- a/sites/all/modules/contrib/flag/flag/theme/flag.tpl.php +++ b/sites/all/modules/contrib/flag/flag/theme/flag.tpl.php @@ -2,41 +2,50 @@ /** * @file - * Default theme implementation to display a flag link, and a message after the action - * is carried out. + * Default theme implementation to display a flag link, and a message after the + * action is carried out. * * Available variables: * * - $flag: The flag object itself. You will only need to use it when the * following variables don't suffice. - * - $flag_name_css: The flag name, with all "_" replaced with "-". For use in 'class' - * attributes. - * - $flag_classes: A space-separated list of CSS classes that should be applied to the link. + * - $flag_name_css: The flag name, with all "_" replaced with "-". For use in + * 'class' attributes. + * - $flag_classes: A space-separated list of CSS classes that should be applied + * to the link. * - * - $action: The action the link is about to carry out, either "flag" or "unflag". + * - $action: The action the link is about to carry out, either "flag" or + * "unflag". * - $status: The status of the item; either "flagged" or "unflagged". + * - $entity_id: The id of the entity item. * - * - $link_href: The URL for the flag link. + * - $link['href']: The path for the flag link. + * - $link['query']: Array of query string parameters, such as "destination". + * - $link_href: The URL for the flag link, query string included. * - $link_text: The text to show for the link. * - $link_title: The title attribute for the link. * - * - $message_text: The long message to show after a flag action has been carried out. - * - $message_classes: A space-separated list of CSS classes that should be applied to + * - $message_text: The long message to show after a flag action has been + * carried out. + * - $message_classes: A space-separated list of CSS classes that should be + * applied to * the message. - * - $after_flagging: This template is called for the link both before and after being + * - $after_flagging: This template is called for the link both before and after + * being * flagged. If displaying to the user immediately after flagging, this value * will be boolean TRUE. This is usually used in conjunction with immedate * JavaScript-based toggling of flags. * - $needs_wrapping_element: Determines whether the flag displays a wrapping * HTML DIV element. + * - $errors: An array of error messages. * * Template suggestions available, listed from the most specific template to * the least. Drupal will use the most specific template it finds: * - flag--name.tpl.php * - flag--link-type.tpl.php * - * NOTE: This template spaces out the tags for clarity only. When doing some - * advanced theming you may have to remove all the whitespace. + * NOTE: This template spaces out the tags for clarity only. When doing + * some advanced theming you may have to remove all the whitespace. */ ?>