Index: INSTALL.txt =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/INSTALL.txt,v retrieving revision 1.6 diff -u -p -r1.6 INSTALL.txt --- INSTALL.txt 2 Nov 2007 01:47:16 -0000 1.6 +++ INSTALL.txt 28 Dec 2007 19:24:32 -0000 @@ -24,6 +24,18 @@ New Installation 8. Grant the proper access to users under admin/user/access +9. Enable the project issue to link filter in proper input formats at + admin/settings/filters. If your site uses ANY node access + control modules (including, but not limited to, Organic + Groups, Simple Access, and Node Access), you should not enable + this filter. Furthermore, if your site does not give the + 'access project issues' permission to all users (including + anonymous users), you should not use this filter. In both cases + this is because the output of the project issue to link filter + is cached, and it is not possible to ensure that the user who initially + viewed the content and set the cache has the same access permissions as + another user that might view the (now cached) content. + -------------------------------------------------------------- Upgrading Index: README.txt =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/README.txt,v retrieving revision 1.3 diff -u -p -r1.3 README.txt --- README.txt 7 Aug 2007 20:02:27 -0000 1.3 +++ README.txt 28 Dec 2007 19:24:32 -0000 @@ -1,6 +1,10 @@ This module allows teams to track outstanding items which need resolution. It provides e-mail notifications to members about updates to items. Similar to many issue tracking systems. +The filter which automatically turns references to project issues into +links conflicts with some access settings when cache is enabled. Users +may be able to see cached titles of project issues they should not have +access to - in case of such conflict it is advised not to enable the filter. For installation instructions, see INSTALL.txt. Index: project_issue.css =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/project_issue.css,v retrieving revision 1.17 diff -u -p -r1.17 project_issue.css --- project_issue.css 14 Nov 2007 05:57:42 -0000 1.17 +++ project_issue.css 28 Dec 2007 19:24:32 -0000 @@ -156,3 +156,12 @@ table.projects .project-project-links { text-align: right; color: #999; } + +/* Automatic issue links */ +.project-issue-status-2, +.project-issue-status-3, +.project-issue-status-5, +.project-issue-status-6, +.project-issue-status-7 { + text-decoration: line-through; +} Index: project_issue.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/project_issue.module,v retrieving revision 1.74 diff -u -p -r1.74 project_issue.module --- project_issue.module 9 Dec 2007 03:17:19 -0000 1.74 +++ project_issue.module 28 Dec 2007 19:24:35 -0000 @@ -970,3 +970,155 @@ function project_issue_link_alter(&$node unset($links['comment_add']); } } + + +/** + * @defgroup project_issue_filter Project Issue number to link filter + */ + +/** + * Theme automatic Project Issue links + * @ingroup project_issue_filter themeable + * + * @param $node + * The issue node object to be linked + * @param $comment_id + * The comment id to be appended to the link, optional + * @param $comment_number + * The comment's number, as visible to users, optional + */ +function theme_project_issue_issue_link($node, $comment_id = NULL, $comment_number = NULL) { + $path = "node/$node->nid"; + $attributes = array('title' => project_issue_state($node->sid)); + if ($comment_id) { + $title = check_plain("#$node->nid-$comment_number: $node->title"); + $link = l($title, $path, $attributes, NULL, "comment-$comment_id"); + } + else { + $title = check_plain("#$node->nid: $node->title"); + $link = l($title, $path, $attributes); + } + $output = "sid\">$link"; + return $output; +} + +/** + * Implementation of hook_form_filter_tips() + * @ingroup project_issue_filter + */ +function project_issue_filter_tips($delta, $format, $long = FALSE) { + if ($long) { + return t('References to project issues in the form of [#1234] (or [#1234-2] for comments) turn into links automatically, with the title of the issue appended. The status of the issue is shown on hover.'); + } + else { + return t('Project issue numbers (ex. [#12345]) turn into links automatically.'); + } +} + +/** + * Implementation of hook_form_filter() + * @ingroup project_issue_filter + */ +function project_issue_filter($op, $delta = 0, $format = -1, $text = '') { + switch ($op) { + case 'list': + return array(0 => t('Project Issue to link filter')); + case 'description': + return t('Converts references to project issues (in the form of [#12345]) into links. Caching should be disabled if node access control modules are used.'); + case 'no cache': + return FALSE; + case 'prepare': + return $text; + case 'process': + $regex = '(?|([^<]|(<(?!code)))*<\/code>|([^<]|(<(?!pre)))*<\/pre>|\w)'; + $offset = 0; + while(preg_match("/$regex/", $text, $preg_matches, PREG_OFFSET_CAPTURE, $offset)) { + $offset++; + $match = $preg_matches[1]; + $nid = $preg_matches[2][0]; + $comment_number = $preg_matches[4][0]; + $node = node_load($nid); + if (is_object($node) && node_access('view', $node) && $node->type == 'project_issue') { + if (!is_null($comment_number)) { + $comment_id = db_result(db_query("SELECT cid FROM {comments} WHERE nid = %d AND thread = '%s'", $nid, int2vancode($comment_number) .'/')); + $link = theme('project_issue_issue_link', $node, $comment_id, $comment_number); + } + else { + $link = theme('project_issue_issue_link', $node); + } + $text = substr_replace($text, $link, $match[1], strlen($match[0])); + $offset = max($offset, $match[1] + strlen($link)); + } + else { + $offset = max($offset, $match[1] + strlen($match[0])); + } + } + return $text; + } +} + +/** + * Implementation of hook_requirements() + * @ingroup project_issue_filter + * + * Check for conflicts with: + * installed node access control modules, + * 'access project issues' restrictions, + * filters escaping code with higher weight + */ +function project_issue_requirements($phase) { + $requirements = array(); + $input_formats = array(); + if ($phase == 'runtime') { + + $grants = module_implements('node_grants'); + if (!empty($grants)) { + $conflict_grants = TRUE; + } + $allowed_roles = user_roles(FALSE, 'access project issues'); + if (!isset($allowed_roles[DRUPAL_ANONYMOUS_RID])) { + $conflict_anonymous = TRUE; + } + + foreach (filter_formats() as $format => $input_format) { + $filters = filter_list_format($format); + if (isset($filters['project_issue/0'])) { + if ($conflict_grants && filter_format_allowcache($format)) { + $requirements[] = array( + 'title' => t('Project Issue to link filter'), + 'value' => t('Some module conflicts were detected.'), + 'description' => t('%issuefilter should not be enabled when a node access control is also in use. Users may be able to see cached titles of project issues they would otherwise not have access to. You should disable this filter in !inputformat input format.', array('%issuefilter' => t('Project Issue to link filter'), '!inputformat' => l($input_format->name, "admin/settings/filters/$format"))), + 'severity' => REQUIREMENT_ERROR, + ); + } + + if ($conflict_anonymous && filter_format_allowcache($format)) { + $requirements[] = array( + 'title' => t('Project Issue to link filter'), + 'value' => t('Some security conflicts were detected.'), + 'description' => t('%issuefilter conflicts with project issue access settings. Users who do not have access to all project issues may be able to see titles of project issues. You should disable this filter in !inputformat input format.', array('%issuefilter' => t('Project Issue to link filter'), '!inputformat' => l($input_format->name, "admin/settings/filters/$format"))), + 'severity' => REQUIREMENT_ERROR, + ); + } + + //Put up an error when some code escaping filter's weight is higher. + $low_filters = array('filter/0', 'filter/1', 'bbcode/0', 'codefilter/0', 'geshifilter/0'); + foreach ($low_filters as $lfilter) { + if (isset($filters[$lfilter]) && $filters['project_issue/0']->weight <= $filters[$lfilter]->weight) { + $description_names['%issuefilter'] = $filters['project_issue/0']->name; + $description_names['%lowfilter'] = $filters[$lfilter]->name; + $requirements[] = array( + 'title' => t('Project Issue to link filter'), + 'value' => t('Some filter conflicts were detected.'), + 'description' => t('%issuefilter should come after %lowfilter to prevent loss of layout and highlighting.', $description_names) .' '. l(t('Please rearrange the filters.'), "admin/settings/filters/$format/order"), + 'severity' => REQUIREMENT_ERROR, + ); + } + } + + } + } + + } + return $requirements; +}