##// END OF EJS Templates
Adds a css class on menu items in order to apply item specific styles (eg. icons)....
Jean-Philippe Lang -
r2057:546b98a1186d
parent child
Show More
@@ -1,163 +1,163
1 1 require 'redmine/access_control'
2 2 require 'redmine/menu_manager'
3 3 require 'redmine/activity'
4 4 require 'redmine/mime_type'
5 5 require 'redmine/core_ext'
6 6 require 'redmine/themes'
7 7 require 'redmine/hook'
8 8 require 'redmine/plugin'
9 9 require 'redmine/wiki_formatting'
10 10
11 11 begin
12 12 require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick)
13 13 rescue LoadError
14 14 # RMagick is not available
15 15 end
16 16
17 17 REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar Git Filesystem )
18 18
19 19 # Permissions
20 20 Redmine::AccessControl.map do |map|
21 21 map.permission :view_project, {:projects => [:show, :activity]}, :public => true
22 22 map.permission :search_project, {:search => :index}, :public => true
23 23 map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member
24 24 map.permission :select_project_modules, {:projects => :modules}, :require => :member
25 25 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy]}, :require => :member
26 26 map.permission :manage_versions, {:projects => [:settings, :add_version], :versions => [:edit, :destroy]}, :require => :member
27 27
28 28 map.project_module :issue_tracking do |map|
29 29 # Issue categories
30 30 map.permission :manage_categories, {:projects => [:settings, :add_issue_category], :issue_categories => [:edit, :destroy]}, :require => :member
31 31 # Issues
32 32 map.permission :view_issues, {:projects => [:changelog, :roadmap],
33 33 :issues => [:index, :changes, :show, :context_menu],
34 34 :versions => [:show, :status_by],
35 35 :queries => :index,
36 36 :reports => :issue_report}, :public => true
37 37 map.permission :add_issues, {:issues => :new}
38 38 map.permission :edit_issues, {:issues => [:edit, :reply, :bulk_edit, :destroy_attachment]}
39 39 map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
40 40 map.permission :add_issue_notes, {:issues => [:edit, :reply]}
41 41 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
42 42 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
43 43 map.permission :move_issues, {:issues => :move}, :require => :loggedin
44 44 map.permission :delete_issues, {:issues => :destroy}, :require => :member
45 45 # Queries
46 46 map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member
47 47 map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin
48 48 # Gantt & calendar
49 49 map.permission :view_gantt, :issues => :gantt
50 50 map.permission :view_calendar, :issues => :calendar
51 51 # Watchers
52 52 map.permission :view_issue_watchers, {}
53 53 map.permission :add_issue_watchers, {:watchers => :new}
54 54 end
55 55
56 56 map.project_module :time_tracking do |map|
57 57 map.permission :log_time, {:timelog => :edit}, :require => :loggedin
58 58 map.permission :view_time_entries, :timelog => [:details, :report]
59 59 map.permission :edit_time_entries, {:timelog => [:edit, :destroy]}, :require => :member
60 60 map.permission :edit_own_time_entries, {:timelog => [:edit, :destroy]}, :require => :loggedin
61 61 end
62 62
63 63 map.project_module :news do |map|
64 64 map.permission :manage_news, {:news => [:new, :edit, :destroy, :destroy_comment]}, :require => :member
65 65 map.permission :view_news, {:news => [:index, :show]}, :public => true
66 66 map.permission :comment_news, {:news => :add_comment}
67 67 end
68 68
69 69 map.project_module :documents do |map|
70 70 map.permission :manage_documents, {:documents => [:new, :edit, :destroy, :add_attachment, :destroy_attachment]}, :require => :loggedin
71 71 map.permission :view_documents, :documents => [:index, :show, :download]
72 72 end
73 73
74 74 map.project_module :files do |map|
75 75 map.permission :manage_files, {:projects => :add_file, :versions => :destroy_file}, :require => :loggedin
76 76 map.permission :view_files, :projects => :list_files, :versions => :download
77 77 end
78 78
79 79 map.project_module :wiki do |map|
80 80 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
81 81 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
82 82 map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
83 83 map.permission :view_wiki_pages, :wiki => [:index, :special]
84 84 map.permission :view_wiki_edits, :wiki => [:history, :diff, :annotate]
85 85 map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment]
86 86 map.permission :delete_wiki_pages_attachments, :wiki => :destroy_attachment
87 87 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
88 88 end
89 89
90 90 map.project_module :repository do |map|
91 91 map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member
92 92 map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph]
93 93 map.permission :view_changesets, :repositories => [:show, :revisions, :revision]
94 94 map.permission :commit_access, {}
95 95 end
96 96
97 97 map.project_module :boards do |map|
98 98 map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member
99 99 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true
100 100 map.permission :add_messages, {:messages => [:new, :reply, :quote]}
101 101 map.permission :edit_messages, {:messages => :edit}, :require => :member
102 102 map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin
103 103 map.permission :delete_messages, {:messages => :destroy}, :require => :member
104 104 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
105 105 end
106 106 end
107 107
108 108 Redmine::MenuManager.map :top_menu do |menu|
109 menu.push :home, :home_path, :html => { :class => 'home' }
110 menu.push :my_page, { :controller => 'my', :action => 'page' }, :html => { :class => 'mypage' }, :if => Proc.new { User.current.logged? }
111 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural, :html => { :class => 'projects' }
112 menu.push :administration, { :controller => 'admin', :action => 'index' }, :html => { :class => 'admin' }, :if => Proc.new { User.current.admin? }, :last => true
113 menu.push :help, Redmine::Info.help_url, :html => { :class => 'help' }, :last => true
109 menu.push :home, :home_path
110 menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
111 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
112 menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
113 menu.push :help, Redmine::Info.help_url, :last => true
114 114 end
115 115
116 116 Redmine::MenuManager.map :account_menu do |menu|
117 menu.push :login, :signin_path, :html => { :class => 'login' }, :if => Proc.new { !User.current.logged? }
118 menu.push :register, { :controller => 'account', :action => 'register' }, :html => { :class => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
119 menu.push :my_account, { :controller => 'my', :action => 'account' }, :html => { :class => 'myaccount' }, :if => Proc.new { User.current.logged? }
120 menu.push :logout, :signout_path, :html => { :class => 'logout' }, :if => Proc.new { User.current.logged? }
117 menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
118 menu.push :register, { :controller => 'account', :action => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
119 menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? }
120 menu.push :logout, :signout_path, :if => Proc.new { User.current.logged? }
121 121 end
122 122
123 123 Redmine::MenuManager.map :application_menu do |menu|
124 124 # Empty
125 125 end
126 126
127 127 Redmine::MenuManager.map :admin_menu do |menu|
128 128 # Empty
129 129 end
130 130
131 131 Redmine::MenuManager.map :project_menu do |menu|
132 132 menu.push :overview, { :controller => 'projects', :action => 'show' }
133 133 menu.push :activity, { :controller => 'projects', :action => 'activity' }
134 134 menu.push :roadmap, { :controller => 'projects', :action => 'roadmap' },
135 135 :if => Proc.new { |p| p.versions.any? }
136 136 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
137 137 menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new,
138 138 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
139 139 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
140 140 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
141 141 menu.push :wiki, { :controller => 'wiki', :action => 'index', :page => nil },
142 142 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
143 143 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
144 144 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
145 145 menu.push :files, { :controller => 'projects', :action => 'list_files' }, :caption => :label_attachment_plural
146 146 menu.push :repository, { :controller => 'repositories', :action => 'show' },
147 147 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
148 148 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
149 149 end
150 150
151 151 Redmine::Activity.map do |activity|
152 152 activity.register :issues, :class_name => %w(Issue Journal)
153 153 activity.register :changesets
154 154 activity.register :news
155 155 activity.register :documents, :class_name => %w(Document Attachment)
156 156 activity.register :files, :class_name => 'Attachment'
157 157 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
158 158 activity.register :messages, :default => false
159 159 end
160 160
161 161 Redmine::WikiFormatting.map do |format|
162 162 format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper
163 163 end
@@ -1,196 +1,208
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'gloc'
19 19
20 20 module Redmine
21 21 module MenuManager
22 22 module MenuController
23 23 def self.included(base)
24 24 base.extend(ClassMethods)
25 25 end
26 26
27 27 module ClassMethods
28 28 @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}}
29 29 mattr_accessor :menu_items
30 30
31 31 # Set the menu item name for a controller or specific actions
32 32 # Examples:
33 33 # * menu_item :tickets # => sets the menu name to :tickets for the whole controller
34 34 # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only
35 35 # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only
36 36 #
37 37 # The default menu item name for a controller is controller_name by default
38 38 # Eg. the default menu item name for ProjectsController is :projects
39 39 def menu_item(id, options = {})
40 40 if actions = options[:only]
41 41 actions = [] << actions unless actions.is_a?(Array)
42 42 actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id}
43 43 else
44 44 menu_items[controller_name.to_sym][:default] = id
45 45 end
46 46 end
47 47 end
48 48
49 49 def menu_items
50 50 self.class.menu_items
51 51 end
52 52
53 53 # Returns the menu item name according to the current action
54 54 def current_menu_item
55 55 menu_items[controller_name.to_sym][:actions][action_name.to_sym] ||
56 56 menu_items[controller_name.to_sym][:default]
57 57 end
58 58 end
59 59
60 60 module MenuHelper
61 61 # Returns the current menu item name
62 62 def current_menu_item
63 63 @controller.current_menu_item
64 64 end
65 65
66 66 # Renders the application main menu
67 67 def render_main_menu(project)
68 68 render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project)
69 69 end
70 70
71 71 def render_menu(menu, project=nil)
72 72 links = []
73 73 menu_items_for(menu, project) do |item, caption, url, selected|
74 74 links << content_tag('li',
75 link_to(h(caption), url, (selected ? item.html_options.merge(:class => 'selected') : item.html_options)))
75 link_to(h(caption), url, item.html_options(:selected => selected)))
76 76 end
77 77 links.empty? ? nil : content_tag('ul', links.join("\n"))
78 78 end
79 79
80 80 def menu_items_for(menu, project=nil)
81 81 items = []
82 82 Redmine::MenuManager.allowed_items(menu, User.current, project).each do |item|
83 83 unless item.condition && !item.condition.call(project)
84 84 url = case item.url
85 85 when Hash
86 86 project.nil? ? item.url : {item.param => project}.merge(item.url)
87 87 when Symbol
88 88 send(item.url)
89 89 else
90 90 item.url
91 91 end
92 92 caption = item.caption(project)
93 93 caption = l(caption) if caption.is_a?(Symbol)
94 94 if block_given?
95 95 yield item, caption, url, (current_menu_item == item.name)
96 96 else
97 97 items << [item, caption, url, (current_menu_item == item.name)]
98 98 end
99 99 end
100 100 end
101 101 return block_given? ? nil : items
102 102 end
103 103 end
104 104
105 105 class << self
106 106 def map(menu_name)
107 107 @items ||= {}
108 108 mapper = Mapper.new(menu_name.to_sym, @items)
109 109 if block_given?
110 110 yield mapper
111 111 else
112 112 mapper
113 113 end
114 114 end
115 115
116 116 def items(menu_name)
117 117 @items[menu_name.to_sym] || []
118 118 end
119 119
120 120 def allowed_items(menu_name, user, project)
121 121 project ? items(menu_name).select {|item| user && user.allowed_to?(item.url, project)} : items(menu_name)
122 122 end
123 123 end
124 124
125 125 class Mapper
126 126 def initialize(menu, items)
127 127 items[menu] ||= []
128 128 @menu = menu
129 129 @menu_items = items[menu]
130 130 end
131 131
132 132 @@last_items_count = Hash.new {|h,k| h[k] = 0}
133 133
134 134 # Adds an item at the end of the menu. Available options:
135 135 # * param: the parameter name that is used for the project id (default is :id)
136 136 # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true
137 137 # * caption that can be:
138 138 # * a localized string Symbol
139 139 # * a String
140 140 # * a Proc that can take the project as argument
141 141 # * before, after: specify where the menu item should be inserted (eg. :after => :activity)
142 142 # * last: menu item will stay at the end (eg. :last => true)
143 143 # * html_options: a hash of html options that are passed to link_to
144 144 def push(name, url, options={})
145 145 options = options.dup
146 146
147 147 # menu item position
148 148 if before = options.delete(:before)
149 149 position = @menu_items.collect(&:name).index(before)
150 150 elsif after = options.delete(:after)
151 151 position = @menu_items.collect(&:name).index(after)
152 152 position += 1 unless position.nil?
153 153 elsif options.delete(:last)
154 154 position = @menu_items.size
155 155 @@last_items_count[@menu] += 1
156 156 end
157 157 # default position
158 158 position ||= @menu_items.size - @@last_items_count[@menu]
159 159
160 160 @menu_items.insert(position, MenuItem.new(name, url, options))
161 161 end
162 162
163 163 # Removes a menu item
164 164 def delete(name)
165 165 @menu_items.delete_if {|i| i.name == name}
166 166 end
167 167 end
168 168
169 169 class MenuItem
170 170 include GLoc
171 attr_reader :name, :url, :param, :condition, :html_options
171 attr_reader :name, :url, :param, :condition
172 172
173 173 def initialize(name, url, options)
174 174 raise "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
175 175 raise "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
176 176 @name = name
177 177 @url = url
178 178 @condition = options[:if]
179 179 @param = options[:param] || :id
180 180 @caption = options[:caption]
181 181 @html_options = options[:html] || {}
182 # Adds a unique class to each menu item based on its name
183 @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
182 184 end
183 185
184 186 def caption(project=nil)
185 187 if @caption.is_a?(Proc)
186 188 c = @caption.call(project).to_s
187 189 c = @name.to_s.humanize if c.blank?
188 190 c
189 191 else
190 192 # check if localized string exists on first render (after GLoc strings are loaded)
191 193 @caption_key ||= (@caption || (l_has_string?("label_#{@name}".to_sym) ? "label_#{@name}".to_sym : @name.to_s.humanize))
192 194 end
193 195 end
196
197 def html_options(options={})
198 if options[:selected]
199 o = @html_options.dup
200 o[:class] += ' selected'
201 o
202 else
203 @html_options
204 end
205 end
194 206 end
195 207 end
196 208 end
@@ -1,41 +1,41
1 1 @import url(../../../stylesheets/application.css);
2 2
3 3 body{ color:#303030; background:#e8eaec; }
4 4
5 5 #top-menu { font-size: 80%; height: 2em; padding-top: 0.5em; background-color: #578bb8; }
6 6 #top-menu a { font-weight: bold; }
7 7 #header { background: #467aa7; height:5.8em; padding: 10px 0 0 0; }
8 8 #header h1 { margin-left: 6px; }
9 9 #quick-search { margin-right: 6px; }
10 10 #main-menu { background-color: #578bb8; left: 0; border-top: 1px solid #fff; width: 100%; }
11 11 #main-menu li { margin: 0; padding: 0; }
12 12 #main-menu li a { background-color: #578bb8; border-right: 1px solid #fff; font-size: 90%; padding: 4px 8px 4px 8px; font-weight: bold; }
13 13 #main-menu li a:hover { background-color: #80b0da; color: #ffffff; }
14 14 #main-menu li a.selected, #main-menu li a.selected:hover { background-color: #80b0da; color: #ffffff; }
15 15
16 16 #footer { background-color: #578bb8; border: 0; color: #fff;}
17 17 #footer a { color: #fff; font-weight: bold; }
18 18
19 19 #main { font:90% Verdana,Tahoma,Arial,sans-serif; background: #e8eaec; }
20 20 #main a { font-weight: bold; color: #467aa7;}
21 21 #main a:hover { color: #2a5a8a; text-decoration: underline; }
22 22 #content { background: #fff; }
23 23 #content .tabs ul { bottom:-1px; }
24 24
25 25 h2, h3, h4, .wiki h1, .wiki h2, .wiki h3 { border-bottom: 0px; color:#606060; font-family: Trebuchet MS,Georgia,"Times New Roman",serif; }
26 26 h2, .wiki h1 { letter-spacing:-1px; }
27 27 h4 { border-bottom: dotted 1px #c0c0c0; }
28 28
29 #top-menu a.home, #top-menu a.mypage, #top-menu a.projects, #top-menu a.admin, #top-menu a.help {
29 #top-menu a.home, #top-menu a.my-page, #top-menu a.projects, #top-menu a.administration, #top-menu a.help {
30 30 background-position: 0% 40%;
31 31 background-repeat: no-repeat;
32 32 padding-left: 20px;
33 33 padding-top: 2px;
34 34 padding-bottom: 3px;
35 35 }
36 36
37 37 #top-menu a.home { background-image: url(../../../images/home.png); }
38 #top-menu a.mypage { background-image: url(../../../images/user_page.png); }
38 #top-menu a.my-page { background-image: url(../../../images/user_page.png); }
39 39 #top-menu a.projects { background-image: url(../../../images/projects.png); }
40 #top-menu a.admin { background-image: url(../../../images/admin.png); }
40 #top-menu a.administration { background-image: url(../../../images/admin.png); }
41 41 #top-menu a.help { background-image: url(../../../images/help.png); }
@@ -1,274 +1,277
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.dirname(__FILE__) + '/../test_helper'
19 19 require 'projects_controller'
20 20
21 21 # Re-raise errors caught by the controller.
22 22 class ProjectsController; def rescue_action(e) raise e end; end
23 23
24 24 class ProjectsControllerTest < Test::Unit::TestCase
25 25 fixtures :projects, :versions, :users, :roles, :members, :issues, :journals, :journal_details,
26 26 :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages
27 27
28 28 def setup
29 29 @controller = ProjectsController.new
30 30 @request = ActionController::TestRequest.new
31 31 @response = ActionController::TestResponse.new
32 32 @request.session[:user_id] = nil
33 33 Setting.default_language = 'en'
34 34 end
35 35
36 36 def test_index
37 37 get :index
38 38 assert_response :success
39 39 assert_template 'index'
40 40 assert_not_nil assigns(:project_tree)
41 41 # Root project as hash key
42 42 assert assigns(:project_tree).keys.include?(Project.find(1))
43 43 # Subproject in corresponding value
44 44 assert assigns(:project_tree)[Project.find(1)].include?(Project.find(3))
45 45 end
46 46
47 47 def test_index_atom
48 48 get :index, :format => 'atom'
49 49 assert_response :success
50 50 assert_template 'common/feed.atom.rxml'
51 51 assert_select 'feed>title', :text => 'Redmine: Latest projects'
52 52 assert_select 'feed>entry', :count => Project.count(:conditions => Project.visible_by(User.current))
53 53 end
54 54
55 55 def test_show_by_id
56 56 get :show, :id => 1
57 57 assert_response :success
58 58 assert_template 'show'
59 59 assert_not_nil assigns(:project)
60 60 end
61 61
62 62 def test_show_by_identifier
63 63 get :show, :id => 'ecookbook'
64 64 assert_response :success
65 65 assert_template 'show'
66 66 assert_not_nil assigns(:project)
67 67 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
68 68 end
69 69
70 70 def test_private_subprojects_hidden
71 71 get :show, :id => 'ecookbook'
72 72 assert_response :success
73 73 assert_template 'show'
74 74 assert_no_tag :tag => 'a', :content => /Private child/
75 75 end
76 76
77 77 def test_private_subprojects_visible
78 78 @request.session[:user_id] = 2 # manager who is a member of the private subproject
79 79 get :show, :id => 'ecookbook'
80 80 assert_response :success
81 81 assert_template 'show'
82 82 assert_tag :tag => 'a', :content => /Private child/
83 83 end
84 84
85 85 def test_settings
86 86 @request.session[:user_id] = 2 # manager
87 87 get :settings, :id => 1
88 88 assert_response :success
89 89 assert_template 'settings'
90 90 end
91 91
92 92 def test_edit
93 93 @request.session[:user_id] = 2 # manager
94 94 post :edit, :id => 1, :project => {:name => 'Test changed name',
95 95 :issue_custom_field_ids => ['']}
96 96 assert_redirected_to 'projects/settings/ecookbook'
97 97 project = Project.find(1)
98 98 assert_equal 'Test changed name', project.name
99 99 end
100 100
101 101 def test_get_destroy
102 102 @request.session[:user_id] = 1 # admin
103 103 get :destroy, :id => 1
104 104 assert_response :success
105 105 assert_template 'destroy'
106 106 assert_not_nil Project.find_by_id(1)
107 107 end
108 108
109 109 def test_post_destroy
110 110 @request.session[:user_id] = 1 # admin
111 111 post :destroy, :id => 1, :confirm => 1
112 112 assert_redirected_to 'admin/projects'
113 113 assert_nil Project.find_by_id(1)
114 114 end
115 115
116 116 def test_list_files
117 117 get :list_files, :id => 1
118 118 assert_response :success
119 119 assert_template 'list_files'
120 120 assert_not_nil assigns(:versions)
121 121 end
122 122
123 123 def test_changelog
124 124 get :changelog, :id => 1
125 125 assert_response :success
126 126 assert_template 'changelog'
127 127 assert_not_nil assigns(:versions)
128 128 end
129 129
130 130 def test_roadmap
131 131 get :roadmap, :id => 1
132 132 assert_response :success
133 133 assert_template 'roadmap'
134 134 assert_not_nil assigns(:versions)
135 135 # Version with no date set appears
136 136 assert assigns(:versions).include?(Version.find(3))
137 137 # Completed version doesn't appear
138 138 assert !assigns(:versions).include?(Version.find(1))
139 139 end
140 140
141 141 def test_roadmap_with_completed_versions
142 142 get :roadmap, :id => 1, :completed => 1
143 143 assert_response :success
144 144 assert_template 'roadmap'
145 145 assert_not_nil assigns(:versions)
146 146 # Version with no date set appears
147 147 assert assigns(:versions).include?(Version.find(3))
148 148 # Completed version appears
149 149 assert assigns(:versions).include?(Version.find(1))
150 150 end
151 151
152 152 def test_project_activity
153 153 get :activity, :id => 1, :with_subprojects => 0
154 154 assert_response :success
155 155 assert_template 'activity'
156 156 assert_not_nil assigns(:events_by_day)
157 157
158 158 assert_tag :tag => "h3",
159 159 :content => /#{2.days.ago.to_date.day}/,
160 160 :sibling => { :tag => "dl",
161 161 :child => { :tag => "dt",
162 162 :attributes => { :class => /issue-edit/ },
163 163 :child => { :tag => "a",
164 164 :content => /(#{IssueStatus.find(2).name})/,
165 165 }
166 166 }
167 167 }
168 168 end
169 169
170 170 def test_previous_project_activity
171 171 get :activity, :id => 1, :from => 3.days.ago.to_date
172 172 assert_response :success
173 173 assert_template 'activity'
174 174 assert_not_nil assigns(:events_by_day)
175 175
176 176 assert_tag :tag => "h3",
177 177 :content => /#{3.day.ago.to_date.day}/,
178 178 :sibling => { :tag => "dl",
179 179 :child => { :tag => "dt",
180 180 :attributes => { :class => /issue/ },
181 181 :child => { :tag => "a",
182 182 :content => /#{Issue.find(1).subject}/,
183 183 }
184 184 }
185 185 }
186 186 end
187 187
188 188 def test_global_activity
189 189 get :activity
190 190 assert_response :success
191 191 assert_template 'activity'
192 192 assert_not_nil assigns(:events_by_day)
193 193
194 194 assert_tag :tag => "h3",
195 195 :content => /#{5.day.ago.to_date.day}/,
196 196 :sibling => { :tag => "dl",
197 197 :child => { :tag => "dt",
198 198 :attributes => { :class => /issue/ },
199 199 :child => { :tag => "a",
200 200 :content => /#{Issue.find(5).subject}/,
201 201 }
202 202 }
203 203 }
204 204 end
205 205
206 206 def test_activity_atom_feed
207 207 get :activity, :format => 'atom'
208 208 assert_response :success
209 209 assert_template 'common/feed.atom.rxml'
210 210 end
211 211
212 212 def test_archive
213 213 @request.session[:user_id] = 1 # admin
214 214 post :archive, :id => 1
215 215 assert_redirected_to 'admin/projects'
216 216 assert !Project.find(1).active?
217 217 end
218 218
219 219 def test_unarchive
220 220 @request.session[:user_id] = 1 # admin
221 221 Project.find(1).archive
222 222 post :unarchive, :id => 1
223 223 assert_redirected_to 'admin/projects'
224 224 assert Project.find(1).active?
225 225 end
226 226
227 227 def test_project_menu
228 228 assert_no_difference 'Redmine::MenuManager.items(:project_menu).size' do
229 229 Redmine::MenuManager.map :project_menu do |menu|
230 230 menu.push :foo, { :controller => 'projects', :action => 'show' }, :cation => 'Foo'
231 231 menu.push :bar, { :controller => 'projects', :action => 'show' }, :before => :activity
232 232 menu.push :hello, { :controller => 'projects', :action => 'show' }, :caption => Proc.new {|p| p.name.upcase }, :after => :bar
233 233 end
234 234
235 235 get :show, :id => 1
236 236 assert_tag :div, :attributes => { :id => 'main-menu' },
237 :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Foo' } }
237 :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Foo',
238 :attributes => { :class => 'foo' } } }
238 239
239 240 assert_tag :div, :attributes => { :id => 'main-menu' },
240 :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Bar' },
241 :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Bar',
242 :attributes => { :class => 'bar' } },
241 243 :before => { :tag => 'li', :child => { :tag => 'a', :content => 'ECOOKBOOK' } } }
242 244
243 245 assert_tag :div, :attributes => { :id => 'main-menu' },
244 :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'ECOOKBOOK' },
246 :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'ECOOKBOOK',
247 :attributes => { :class => 'hello' } },
245 248 :before => { :tag => 'li', :child => { :tag => 'a', :content => 'Activity' } } }
246 249
247 250 # Remove the menu items
248 251 Redmine::MenuManager.map :project_menu do |menu|
249 252 menu.delete :foo
250 253 menu.delete :bar
251 254 menu.delete :hello
252 255 end
253 256 end
254 257 end
255 258
256 259 # A hook that is manually registered later
257 260 class ProjectBasedTemplate < Redmine::Hook::ViewListener
258 261 def view_layouts_base_html_head(context)
259 262 # Adds a project stylesheet
260 263 stylesheet_link_tag(context[:project].identifier) if context[:project]
261 264 end
262 265 end
263 266 # Don't use this hook now
264 267 Redmine::Hook.clear_listeners
265 268
266 269 def test_hook_response
267 270 Redmine::Hook.add_listener(ProjectBasedTemplate)
268 271 get :show, :id => 1
269 272 assert_tag :tag => 'link', :attributes => {:href => '/stylesheets/ecookbook.css'},
270 273 :parent => {:tag => 'head'}
271 274
272 275 Redmine::Hook.clear_listeners
273 276 end
274 277 end
General Comments 0
You need to be logged in to leave comments. Login now