diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb index 5c3511fb5..ec8775aae 100644 --- a/lib/redmine/wiki_formatting/macros.rb +++ b/lib/redmine/wiki_formatting/macros.rb @@ -225,10 +225,11 @@ module Redmine "{{recent_pages(days=3)}} -- displays pages updated within the last 3 days\n" + "{{recent_pages(limit=5)}} -- limits the maximum number of pages to display to 5\n" + "{{recent_pages(time=true)}} -- displays pages updated within the last 7 days with updated time\n" + - "{{recent_pages(project=identifier)}} -- displays pages updated within the last 7 days from a specific project" + "{{recent_pages(project=identifier)}} -- displays pages updated within the last 7 days from a specific project\n" + + "{{recent_pages(include_subprojects=true)}} -- displays pages updated within the last 7 days from a specific project and all subprojects" macro :recent_pages do |obj, args| - args, options = extract_macro_options(args, :days, :limit, :time, :project) + args, options = extract_macro_options(args, :days, :limit, :time, :project, :include_subprojects) if options[:project].presence project = Project.find_by_identifier(options[:project].to_s) if options[:project].present? @@ -237,16 +238,23 @@ module Redmine end return '' if project.nil? - return '' unless User.current.allowed_to?(:view_wiki_pages, project) days_to_list = (options[:days].presence || 7).to_i limit = options[:limit].to_i if options[:limit].present? is_show_time = options[:time].to_s == 'true' + if options[:include_subprojects].to_s == 'true' + project_ids = project.self_and_descendants.allowed_to(User.current, :view_wiki_pages).pluck(:id) + elsif User.current.allowed_to?(:view_wiki_pages, project) + project_ids = [project.id] + end + + return '' if project_ids.blank? pages = WikiPage. - joins(:content, :wiki). - where(["#{Wiki.table_name}.project_id = ? AND #{WikiContent.table_name}.updated_on >= ?", project.id, days_to_list.days.ago]). - order("#{WikiContent.table_name}.updated_on desc, id"). + joins(:wiki, :content). + where(:wikis => {:project_id => project_ids}). + where("#{WikiContent.table_name}.updated_on >= ?", days_to_list.days.ago). + order("#{WikiContent.table_name}.updated_on DESC, #{WikiPage.table_name}.id DESC"). limit(limit) tag.ul do diff --git a/test/unit/lib/redmine/wiki_formatting/macros_test.rb b/test/unit/lib/redmine/wiki_formatting/macros_test.rb index 6b1b6ccf5..cd51ddfcb 100644 --- a/test/unit/lib/redmine/wiki_formatting/macros_test.rb +++ b/test/unit/lib/redmine/wiki_formatting/macros_test.rb @@ -633,4 +633,75 @@ class Redmine::WikiFormatting::MacrosTest < Redmine::HelperTest end end end + + def test_recent_pages_macro_with_include_subprojects_option + project = Project.find(1) + subproject = Project.find(3) + @project = project + + # Ensure subproject has a wiki + subproject.create_wiki(start_page: 'Wiki') + + # Add a wiki page to the subproject and update its content + page = WikiPage.create!(wiki: subproject.wiki, title: 'Subproject Page') + WikiContent.create!(page: page, text: 'content', author_id: 1, updated_on: 1.day.ago) + + # Without include_subprojects=true + result = textilizable('{{recent_pages}}') + assert_select_in result, 'ul>li', :text => /Subproject Page/, :count => 0 + + # With include_subprojects=true + result = textilizable('{{recent_pages(include_subprojects=true)}}') + assert_select_in result, 'ul>li', :text => /Subproject Page/, :count => 1 + end + + def test_recent_pages_macro_should_not_include_projects_with_wiki_module_disabled + project = Project.find(1) + subproject = Project.find(3) + @project = project + + # Ensure subproject has a wiki + subproject.create_wiki(start_page: 'Wiki') + # Ensure wiki module is not enabled + subproject.enabled_module_names = ["issue_tracking", "calendar", "gantt"] + + # Add a wiki page to the subproject and update its content + page = WikiPage.create!(wiki: subproject.wiki, title: 'Subproject Page') + WikiContent.create!(page: page, text: 'content', author_id: 1, updated_on: 1.day.ago) + + # With include_subprojects=true + result = textilizable('{{recent_pages(include_subprojects=true)}}') + assert_select_in result, 'ul>li', :text => /Subproject Page/, :count => 0 + end + + def test_recent_pages_macro_should_not_disclose_private_projects + project = Project.find(1) + private_subproject = Project.find(5) # Private child of project 1 in fixtures + @project = project + + # Ensure project 5 is private + private_subproject.update_attribute(:is_public, false) + private_subproject.enabled_module_names = ["issue_tracking", "calendar", "gantt", "wiki"] + + # Add a wiki page to the private subproject + page = WikiPage.create!(wiki: private_subproject.wiki, title: 'Private Page') + WikiContent.create!(page: page, text: 'content', author_id: 1, updated_on: 1.day.ago) + + # Anonymous user should not see the private page even with include_subprojects=true + User.current = User.anonymous + result = textilizable('{{recent_pages(include_subprojects=true)}}') + assert_select_in result, 'ul>li', :text => /Private Page/, :count => 0 + + role = Role.find(1) + role.remove_permission! :view_wiki_pages + # User without view wiki page permissions + User.current = User.find(2) # Member of eCookbook + result = textilizable('{{recent_pages(include_subprojects=true)}}') + assert_select_in result, 'ul>li', :text => /Private Page/, :count => 0 + + # User with access should see it + User.current = User.find(8) # Member of eCookbook + result = textilizable('{{recent_pages(include_subprojects=true)}}') + assert_select_in result, 'ul>li', :text => /Private Page/, :count => 1 + end end