##// END OF EJS Templates
Split "Manage documents" permission into create, edit and delete permissions (#12401)....
Jean-Philippe Lang -
r10976:48fb02e3839c
parent child
Show More
@@ -0,0 +1,23
1 class SplitDocumentsPermissions < ActiveRecord::Migration
2 def up
3 # :manage_documents permission split into 3 permissions:
4 # :add_documents, :edit_documents and :delete_documents
5 Role.all.each do |role|
6 if role.has_permission?(:manage_documents)
7 role.add_permission! :add_documents, :edit_documents, :delete_documents
8 role.remove_permission! :manage_documents
9 end
10 end
11 end
12
13 def down
14 Role.all.each do |role|
15 if role.has_permission?(:add_documents) ||
16 role.has_permission?(:edit_documents) ||
17 role.has_permission?(:delete_documents)
18 role.remove_permission! :add_documents, :edit_documents, :delete_documents
19 role.add_permission! :manage_documents
20 end
21 end
22 end
23 end
@@ -1,57 +1,57
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 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 class Document < ActiveRecord::Base
19 19 include Redmine::SafeAttributes
20 20 belongs_to :project
21 21 belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
22 acts_as_attachable :delete_permission => :manage_documents
22 acts_as_attachable :delete_permission => :delete_documents
23 23
24 24 acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
25 25 acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
26 26 :author => Proc.new {|o| o.attachments.reorder("#{Attachment.table_name}.created_on ASC").first.try(:author) },
27 27 :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
28 28 acts_as_activity_provider :find_options => {:include => :project}
29 29
30 30 validates_presence_of :project, :title, :category
31 31 validates_length_of :title, :maximum => 60
32 32
33 33 scope :visible, lambda {|*args|
34 34 includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_documents, *args))
35 35 }
36 36
37 37 safe_attributes 'category_id', 'title', 'description'
38 38
39 39 def visible?(user=User.current)
40 40 !user.nil? && user.allowed_to?(:view_documents, project)
41 41 end
42 42
43 43 def initialize(attributes=nil, *args)
44 44 super
45 45 if new_record?
46 46 self.category ||= DocumentCategory.default
47 47 end
48 48 end
49 49
50 50 def updated_on
51 51 unless @updated_on
52 52 a = attachments.last
53 53 @updated_on = (a && a.created_on) || created_on
54 54 end
55 55 @updated_on
56 56 end
57 57 end
@@ -1,34 +1,34
1 1 <div class="contextual">
2 2 <%= link_to l(:label_document_new), new_project_document_path(@project), :class => 'icon icon-add',
3 :onclick => 'showAndScrollTo("add-document", "document_title"); return false;' if User.current.allowed_to?(:manage_documents, @project) %>
3 :onclick => 'showAndScrollTo("add-document", "document_title"); return false;' if User.current.allowed_to?(:add_documents, @project) %>
4 4 </div>
5 5
6 6 <div id="add-document" style="display:none;">
7 7 <h2><%=l(:label_document_new)%></h2>
8 8 <%= labelled_form_for @document, :url => project_documents_path(@project), :html => {:multipart => true} do |f| %>
9 9 <%= render :partial => 'form', :locals => {:f => f} %>
10 10 <p>
11 11 <%= submit_tag l(:button_create) %>
12 12 <%= link_to l(:button_cancel), "#", :onclick => '$("#add-document").hide(); return false;' %>
13 13 </p>
14 14 <% end %>
15 15 </div>
16 16
17 17 <h2><%=l(:label_document_plural)%></h2>
18 18
19 19 <% if @grouped.empty? %><p class="nodata"><%= l(:label_no_data) %></p><% end %>
20 20
21 21 <% @grouped.keys.sort.each do |group| %>
22 22 <h3><%= group %></h3>
23 23 <%= render :partial => 'documents/document', :collection => @grouped[group] %>
24 24 <% end %>
25 25
26 26 <% content_for :sidebar do %>
27 27 <h3><%= l(:label_sort_by, '') %></h3>
28 28 <%= link_to l(:field_category), {:sort_by => 'category'}, :class => (@sort_by == 'category' ? 'selected' :nil) %><br />
29 29 <%= link_to l(:label_date), {:sort_by => 'date'}, :class => (@sort_by == 'date' ? 'selected' :nil) %><br />
30 30 <%= link_to l(:field_title), {:sort_by => 'title'}, :class => (@sort_by == 'title' ? 'selected' :nil) %><br />
31 31 <%= link_to l(:field_author), {:sort_by => 'author'}, :class => (@sort_by == 'author' ? 'selected' :nil) %>
32 32 <% end %>
33 33
34 34 <% html_title(l(:label_document_plural)) -%>
@@ -1,30 +1,32
1 1 <div class="contextual">
2 <% if User.current.allowed_to?(:manage_documents, @project) %>
2 <% if User.current.allowed_to?(:edit_documents, @project) %>
3 3 <%= link_to l(:button_edit), edit_document_path(@document), :class => 'icon icon-edit', :accesskey => accesskey(:edit) %>
4 <% end %>
5 <% if User.current.allowed_to?(:delete_documents, @project) %>
4 6 <%= delete_link document_path(@document) %>
5 7 <% end %>
6 8 </div>
7 9
8 10 <h2><%=h @document.title %></h2>
9 11
10 12 <p><em><%=h @document.category.name %><br />
11 13 <%= format_date @document.created_on %></em></p>
12 14 <div class="wiki">
13 15 <%= textilizable @document.description, :attachments => @document.attachments %>
14 16 </div>
15 17
16 18 <h3><%= l(:label_attachment_plural) %></h3>
17 19 <%= link_to_attachments @document %>
18 20
19 21 <% if authorize_for('documents', 'add_attachment') %>
20 22 <p><%= link_to l(:label_attachment_new), {}, :onclick => "$('#add_attachment_form').show(); return false;",
21 23 :id => 'attach_files_link' %></p>
22 24 <%= form_tag({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %>
23 25 <div class="box">
24 26 <p><%= render :partial => 'attachments/form' %></p>
25 27 </div>
26 28 <%= submit_tag l(:button_add) %>
27 29 <% end %>
28 30 <% end %>
29 31
30 32 <% html_title @document.title -%>
@@ -1,282 +1,284
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 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 'redmine/core_ext'
19 19
20 20 begin
21 21 require 'RMagick' unless Object.const_defined?(:Magick)
22 22 rescue LoadError
23 23 # RMagick is not available
24 24 end
25 25
26 26 require 'redmine/scm/base'
27 27 require 'redmine/access_control'
28 28 require 'redmine/access_keys'
29 29 require 'redmine/activity'
30 30 require 'redmine/activity/fetcher'
31 31 require 'redmine/ciphering'
32 32 require 'redmine/codeset_util'
33 33 require 'redmine/custom_field_format'
34 34 require 'redmine/i18n'
35 35 require 'redmine/menu_manager'
36 36 require 'redmine/notifiable'
37 37 require 'redmine/platform'
38 38 require 'redmine/mime_type'
39 39 require 'redmine/notifiable'
40 40 require 'redmine/search'
41 41 require 'redmine/syntax_highlighting'
42 42 require 'redmine/thumbnail'
43 43 require 'redmine/unified_diff'
44 44 require 'redmine/utils'
45 45 require 'redmine/version'
46 46 require 'redmine/wiki_formatting'
47 47
48 48 require 'redmine/default_data/loader'
49 49 require 'redmine/helpers/calendar'
50 50 require 'redmine/helpers/diff'
51 51 require 'redmine/helpers/gantt'
52 52 require 'redmine/helpers/time_report'
53 53 require 'redmine/views/other_formats_builder'
54 54 require 'redmine/views/labelled_form_builder'
55 55 require 'redmine/views/builders'
56 56
57 57 require 'redmine/themes'
58 58 require 'redmine/hook'
59 59 require 'redmine/plugin'
60 60
61 61 if RUBY_VERSION < '1.9'
62 62 require 'fastercsv'
63 63 else
64 64 require 'csv'
65 65 FCSV = CSV
66 66 end
67 67
68 68 Redmine::Scm::Base.add "Subversion"
69 69 Redmine::Scm::Base.add "Darcs"
70 70 Redmine::Scm::Base.add "Mercurial"
71 71 Redmine::Scm::Base.add "Cvs"
72 72 Redmine::Scm::Base.add "Bazaar"
73 73 Redmine::Scm::Base.add "Git"
74 74 Redmine::Scm::Base.add "Filesystem"
75 75
76 76 Redmine::CustomFieldFormat.map do |fields|
77 77 fields.register 'string'
78 78 fields.register 'text'
79 79 fields.register 'int', :label => :label_integer
80 80 fields.register 'float'
81 81 fields.register 'list'
82 82 fields.register 'date'
83 83 fields.register 'bool', :label => :label_boolean
84 84 fields.register 'user', :only => %w(Issue TimeEntry Version Project), :edit_as => 'list'
85 85 fields.register 'version', :only => %w(Issue TimeEntry Version Project), :edit_as => 'list'
86 86 end
87 87
88 88 # Permissions
89 89 Redmine::AccessControl.map do |map|
90 90 map.permission :view_project, {:projects => [:show], :activities => [:index]}, :public => true, :read => true
91 91 map.permission :search_project, {:search => :index}, :public => true, :read => true
92 92 map.permission :add_project, {:projects => [:new, :create]}, :require => :loggedin
93 93 map.permission :edit_project, {:projects => [:settings, :edit, :update]}, :require => :member
94 94 map.permission :close_project, {:projects => [:close, :reopen]}, :require => :member, :read => true
95 95 map.permission :select_project_modules, {:projects => :modules}, :require => :member
96 96 map.permission :manage_members, {:projects => :settings, :members => [:index, :show, :create, :update, :destroy, :autocomplete]}, :require => :member
97 97 map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member
98 98 map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member
99 99
100 100 map.project_module :issue_tracking do |map|
101 101 # Issue categories
102 102 map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member
103 103 # Issues
104 104 map.permission :view_issues, {:issues => [:index, :show],
105 105 :auto_complete => [:issues],
106 106 :context_menus => [:issues],
107 107 :versions => [:index, :show, :status_by],
108 108 :journals => [:index, :diff],
109 109 :queries => :index,
110 110 :reports => [:issue_report, :issue_report_details]},
111 111 :read => true
112 112 map.permission :add_issues, {:issues => [:new, :create, :update_form], :attachments => :upload}
113 113 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new], :attachments => :upload}
114 114 map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]}
115 115 map.permission :manage_subtasks, {}
116 116 map.permission :set_issues_private, {}
117 117 map.permission :set_own_issues_private, {}, :require => :loggedin
118 118 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new], :attachments => :upload}
119 119 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
120 120 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
121 121 map.permission :view_private_notes, {}, :read => true, :require => :member
122 122 map.permission :set_notes_private, {}, :require => :member
123 123 map.permission :move_issues, {:issues => [:bulk_edit, :bulk_update]}, :require => :loggedin
124 124 map.permission :delete_issues, {:issues => :destroy}, :require => :member
125 125 # Queries
126 126 map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member
127 127 map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin
128 128 # Watchers
129 129 map.permission :view_issue_watchers, {}, :read => true
130 130 map.permission :add_issue_watchers, {:watchers => :new}
131 131 map.permission :delete_issue_watchers, {:watchers => :destroy}
132 132 end
133 133
134 134 map.project_module :time_tracking do |map|
135 135 map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
136 136 map.permission :view_time_entries, {:timelog => [:index, :report, :show]}, :read => true
137 137 map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
138 138 map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
139 139 map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
140 140 end
141 141
142 142 map.project_module :news do |map|
143 143 map.permission :manage_news, {:news => [:new, :create, :edit, :update, :destroy], :comments => [:destroy]}, :require => :member
144 144 map.permission :view_news, {:news => [:index, :show]}, :public => true, :read => true
145 145 map.permission :comment_news, {:comments => :create}
146 146 end
147 147
148 148 map.project_module :documents do |map|
149 map.permission :manage_documents, {:documents => [:new, :create, :edit, :update, :destroy, :add_attachment]}, :require => :loggedin
149 map.permission :add_documents, {:documents => [:new, :create, :add_attachment]}, :require => :loggedin
150 map.permission :edit_documents, {:documents => [:edit, :update, :add_attachment]}, :require => :loggedin
151 map.permission :delete_documents, {:documents => [:destroy]}, :require => :loggedin
150 152 map.permission :view_documents, {:documents => [:index, :show, :download]}, :read => true
151 153 end
152 154
153 155 map.project_module :files do |map|
154 156 map.permission :manage_files, {:files => [:new, :create]}, :require => :loggedin
155 157 map.permission :view_files, {:files => :index, :versions => :download}, :read => true
156 158 end
157 159
158 160 map.project_module :wiki do |map|
159 161 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
160 162 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
161 163 map.permission :delete_wiki_pages, {:wiki => [:destroy, :destroy_version]}, :require => :member
162 164 map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index]}, :read => true
163 165 map.permission :export_wiki_pages, {:wiki => [:export]}, :read => true
164 166 map.permission :view_wiki_edits, {:wiki => [:history, :diff, :annotate]}, :read => true
165 167 map.permission :edit_wiki_pages, :wiki => [:edit, :update, :preview, :add_attachment]
166 168 map.permission :delete_wiki_pages_attachments, {}
167 169 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
168 170 end
169 171
170 172 map.project_module :repository do |map|
171 173 map.permission :manage_repository, {:repositories => [:new, :create, :edit, :update, :committers, :destroy]}, :require => :member
172 174 map.permission :browse_repository, {:repositories => [:show, :browse, :entry, :raw, :annotate, :changes, :diff, :stats, :graph]}, :read => true
173 175 map.permission :view_changesets, {:repositories => [:show, :revisions, :revision]}, :read => true
174 176 map.permission :commit_access, {}
175 177 map.permission :manage_related_issues, {:repositories => [:add_related_issue, :remove_related_issue]}
176 178 end
177 179
178 180 map.project_module :boards do |map|
179 181 map.permission :manage_boards, {:boards => [:new, :create, :edit, :update, :destroy]}, :require => :member
180 182 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true, :read => true
181 183 map.permission :add_messages, {:messages => [:new, :reply, :quote]}
182 184 map.permission :edit_messages, {:messages => :edit}, :require => :member
183 185 map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin
184 186 map.permission :delete_messages, {:messages => :destroy}, :require => :member
185 187 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
186 188 end
187 189
188 190 map.project_module :calendar do |map|
189 191 map.permission :view_calendar, {:calendars => [:show, :update]}, :read => true
190 192 end
191 193
192 194 map.project_module :gantt do |map|
193 195 map.permission :view_gantt, {:gantts => [:show, :update]}, :read => true
194 196 end
195 197 end
196 198
197 199 Redmine::MenuManager.map :top_menu do |menu|
198 200 menu.push :home, :home_path
199 201 menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
200 202 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
201 203 menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
202 204 menu.push :help, Redmine::Info.help_url, :last => true
203 205 end
204 206
205 207 Redmine::MenuManager.map :account_menu do |menu|
206 208 menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
207 209 menu.push :register, :register_path, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
208 210 menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? }
209 211 menu.push :logout, :signout_path, :if => Proc.new { User.current.logged? }
210 212 end
211 213
212 214 Redmine::MenuManager.map :application_menu do |menu|
213 215 # Empty
214 216 end
215 217
216 218 Redmine::MenuManager.map :admin_menu do |menu|
217 219 menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural
218 220 menu.push :users, {:controller => 'users'}, :caption => :label_user_plural
219 221 menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural
220 222 menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions
221 223 menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural
222 224 menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural,
223 225 :html => {:class => 'issue_statuses'}
224 226 menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow
225 227 menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural,
226 228 :html => {:class => 'custom_fields'}
227 229 menu.push :enumerations, {:controller => 'enumerations'}
228 230 menu.push :settings, {:controller => 'settings'}
229 231 menu.push :ldap_authentication, {:controller => 'auth_sources', :action => 'index'},
230 232 :html => {:class => 'server_authentication'}
231 233 menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true
232 234 menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true
233 235 end
234 236
235 237 Redmine::MenuManager.map :project_menu do |menu|
236 238 menu.push :overview, { :controller => 'projects', :action => 'show' }
237 239 menu.push :activity, { :controller => 'activities', :action => 'index' }
238 240 menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id,
239 241 :if => Proc.new { |p| p.shared_versions.any? }
240 242 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
241 243 menu.push :new_issue, { :controller => 'issues', :action => 'new', :copy_from => nil }, :param => :project_id, :caption => :label_issue_new,
242 244 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
243 245 menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt
244 246 menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar
245 247 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
246 248 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
247 249 menu.push :wiki, { :controller => 'wiki', :action => 'show', :id => nil }, :param => :project_id,
248 250 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
249 251 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
250 252 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
251 253 menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id
252 254 menu.push :repository, { :controller => 'repositories', :action => 'show', :repository_id => nil, :path => nil, :rev => nil },
253 255 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
254 256 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
255 257 end
256 258
257 259 Redmine::Activity.map do |activity|
258 260 activity.register :issues, :class_name => %w(Issue Journal)
259 261 activity.register :changesets
260 262 activity.register :news
261 263 activity.register :documents, :class_name => %w(Document Attachment)
262 264 activity.register :files, :class_name => 'Attachment'
263 265 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
264 266 activity.register :messages, :default => false
265 267 activity.register :time_entries, :default => false
266 268 end
267 269
268 270 Redmine::Search.map do |search|
269 271 search.register :issues
270 272 search.register :news
271 273 search.register :documents
272 274 search.register :changesets
273 275 search.register :wiki_pages
274 276 search.register :messages
275 277 search.register :projects
276 278 end
277 279
278 280 Redmine::WikiFormatting.map do |format|
279 281 format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper
280 282 end
281 283
282 284 ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler
@@ -1,197 +1,202
1 1 ---
2 2 roles_001:
3 3 name: Manager
4 4 id: 1
5 5 builtin: 0
6 6 issues_visibility: all
7 7 permissions: |
8 8 ---
9 9 - :add_project
10 10 - :edit_project
11 11 - :close_project
12 12 - :select_project_modules
13 13 - :manage_members
14 14 - :manage_versions
15 15 - :manage_categories
16 16 - :view_issues
17 17 - :add_issues
18 18 - :edit_issues
19 19 - :manage_issue_relations
20 20 - :manage_subtasks
21 21 - :add_issue_notes
22 22 - :move_issues
23 23 - :delete_issues
24 24 - :view_issue_watchers
25 25 - :add_issue_watchers
26 26 - :set_issues_private
27 27 - :set_notes_private
28 28 - :view_private_notes
29 29 - :delete_issue_watchers
30 30 - :manage_public_queries
31 31 - :save_queries
32 32 - :view_gantt
33 33 - :view_calendar
34 34 - :log_time
35 35 - :view_time_entries
36 36 - :edit_time_entries
37 37 - :delete_time_entries
38 38 - :manage_news
39 39 - :comment_news
40 40 - :view_documents
41 - :manage_documents
41 - :add_documents
42 - :edit_documents
43 - :delete_documents
42 44 - :view_wiki_pages
43 45 - :export_wiki_pages
44 46 - :view_wiki_edits
45 47 - :edit_wiki_pages
46 48 - :delete_wiki_pages_attachments
47 49 - :protect_wiki_pages
48 50 - :delete_wiki_pages
49 51 - :rename_wiki_pages
50 52 - :add_messages
51 53 - :edit_messages
52 54 - :delete_messages
53 55 - :manage_boards
54 56 - :view_files
55 57 - :manage_files
56 58 - :browse_repository
57 59 - :manage_repository
58 60 - :view_changesets
59 61 - :manage_related_issues
60 62 - :manage_project_activities
61 63
62 64 position: 1
63 65 roles_002:
64 66 name: Developer
65 67 id: 2
66 68 builtin: 0
67 69 issues_visibility: default
68 70 permissions: |
69 71 ---
70 72 - :edit_project
71 73 - :manage_members
72 74 - :manage_versions
73 75 - :manage_categories
74 76 - :view_issues
75 77 - :add_issues
76 78 - :edit_issues
77 79 - :manage_issue_relations
78 80 - :manage_subtasks
79 81 - :add_issue_notes
80 82 - :move_issues
81 83 - :delete_issues
82 84 - :view_issue_watchers
83 85 - :save_queries
84 86 - :view_gantt
85 87 - :view_calendar
86 88 - :log_time
87 89 - :view_time_entries
88 90 - :edit_own_time_entries
89 91 - :manage_news
90 92 - :comment_news
91 93 - :view_documents
92 - :manage_documents
94 - :add_documents
95 - :edit_documents
96 - :delete_documents
93 97 - :view_wiki_pages
94 98 - :view_wiki_edits
95 99 - :edit_wiki_pages
96 100 - :protect_wiki_pages
97 101 - :delete_wiki_pages
98 102 - :add_messages
99 103 - :edit_own_messages
100 104 - :delete_own_messages
101 105 - :manage_boards
102 106 - :view_files
103 107 - :manage_files
104 108 - :browse_repository
105 109 - :view_changesets
106 110
107 111 position: 2
108 112 roles_003:
109 113 name: Reporter
110 114 id: 3
111 115 builtin: 0
112 116 issues_visibility: default
113 117 permissions: |
114 118 ---
115 119 - :edit_project
116 120 - :manage_members
117 121 - :manage_versions
118 122 - :manage_categories
119 123 - :view_issues
120 124 - :add_issues
121 125 - :edit_issues
122 126 - :manage_issue_relations
123 127 - :add_issue_notes
124 128 - :move_issues
125 129 - :view_issue_watchers
126 130 - :save_queries
127 131 - :view_gantt
128 132 - :view_calendar
129 133 - :log_time
130 134 - :view_time_entries
131 135 - :manage_news
132 136 - :comment_news
133 137 - :view_documents
134 - :manage_documents
138 - :add_documents
139 - :edit_documents
140 - :delete_documents
135 141 - :view_wiki_pages
136 142 - :view_wiki_edits
137 143 - :edit_wiki_pages
138 144 - :delete_wiki_pages
139 145 - :add_messages
140 146 - :manage_boards
141 147 - :view_files
142 148 - :manage_files
143 149 - :browse_repository
144 150 - :view_changesets
145 151
146 152 position: 3
147 153 roles_004:
148 154 name: Non member
149 155 id: 4
150 156 builtin: 1
151 157 issues_visibility: default
152 158 permissions: |
153 159 ---
154 160 - :view_issues
155 161 - :add_issues
156 162 - :edit_issues
157 163 - :manage_issue_relations
158 164 - :add_issue_notes
159 165 - :save_queries
160 166 - :view_gantt
161 167 - :view_calendar
162 168 - :log_time
163 169 - :view_time_entries
164 170 - :comment_news
165 171 - :view_documents
166 - :manage_documents
167 172 - :view_wiki_pages
168 173 - :view_wiki_edits
169 174 - :edit_wiki_pages
170 175 - :add_messages
171 176 - :view_files
172 177 - :manage_files
173 178 - :browse_repository
174 179 - :view_changesets
175 180
176 181 position: 4
177 182 roles_005:
178 183 name: Anonymous
179 184 id: 5
180 185 builtin: 2
181 186 issues_visibility: default
182 187 permissions: |
183 188 ---
184 189 - :view_issues
185 190 - :add_issue_notes
186 191 - :view_gantt
187 192 - :view_calendar
188 193 - :view_time_entries
189 194 - :view_documents
190 195 - :view_wiki_pages
191 196 - :view_wiki_edits
192 197 - :view_files
193 198 - :browse_repository
194 199 - :view_changesets
195 200
196 201 position: 5
197 202
@@ -1,1075 +1,1075
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 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.expand_path('../../test_helper', __FILE__)
19 19
20 20 class UserTest < ActiveSupport::TestCase
21 21 fixtures :users, :members, :projects, :roles, :member_roles, :auth_sources,
22 22 :trackers, :issue_statuses,
23 23 :projects_trackers,
24 24 :watchers,
25 25 :issue_categories, :enumerations, :issues,
26 26 :journals, :journal_details,
27 27 :groups_users,
28 28 :enabled_modules,
29 29 :workflows
30 30
31 31 def setup
32 32 @admin = User.find(1)
33 33 @jsmith = User.find(2)
34 34 @dlopper = User.find(3)
35 35 end
36 36
37 37 def test_generate
38 38 User.generate!(:firstname => 'Testing connection')
39 39 User.generate!(:firstname => 'Testing connection')
40 40 assert_equal 2, User.count(:all, :conditions => {:firstname => 'Testing connection'})
41 41 end
42 42
43 43 def test_truth
44 44 assert_kind_of User, @jsmith
45 45 end
46 46
47 47 def test_mail_should_be_stripped
48 48 u = User.new
49 49 u.mail = " foo@bar.com "
50 50 assert_equal "foo@bar.com", u.mail
51 51 end
52 52
53 53 def test_mail_validation
54 54 u = User.new
55 55 u.mail = ''
56 56 assert !u.valid?
57 57 assert_include I18n.translate('activerecord.errors.messages.blank'), u.errors[:mail]
58 58 end
59 59
60 60 def test_login_length_validation
61 61 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
62 62 user.login = "x" * (User::LOGIN_LENGTH_LIMIT+1)
63 63 assert !user.valid?
64 64
65 65 user.login = "x" * (User::LOGIN_LENGTH_LIMIT)
66 66 assert user.valid?
67 67 assert user.save
68 68 end
69 69
70 70 def test_create
71 71 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
72 72
73 73 user.login = "jsmith"
74 74 user.password, user.password_confirmation = "password", "password"
75 75 # login uniqueness
76 76 assert !user.save
77 77 assert_equal 1, user.errors.count
78 78
79 79 user.login = "newuser"
80 80 user.password, user.password_confirmation = "password", "pass"
81 81 # password confirmation
82 82 assert !user.save
83 83 assert_equal 1, user.errors.count
84 84
85 85 user.password, user.password_confirmation = "password", "password"
86 86 assert user.save
87 87 end
88 88
89 89 def test_user_before_create_should_set_the_mail_notification_to_the_default_setting
90 90 @user1 = User.generate!
91 91 assert_equal 'only_my_events', @user1.mail_notification
92 92 with_settings :default_notification_option => 'all' do
93 93 @user2 = User.generate!
94 94 assert_equal 'all', @user2.mail_notification
95 95 end
96 96 end
97 97
98 98 def test_user_login_should_be_case_insensitive
99 99 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
100 100 u.login = 'newuser'
101 101 u.password, u.password_confirmation = "password", "password"
102 102 assert u.save
103 103 u = User.new(:firstname => "Similar", :lastname => "User", :mail => "similaruser@somenet.foo")
104 104 u.login = 'NewUser'
105 105 u.password, u.password_confirmation = "password", "password"
106 106 assert !u.save
107 107 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:login]
108 108 end
109 109
110 110 def test_mail_uniqueness_should_not_be_case_sensitive
111 111 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
112 112 u.login = 'newuser1'
113 113 u.password, u.password_confirmation = "password", "password"
114 114 assert u.save
115 115
116 116 u = User.new(:firstname => "new", :lastname => "user", :mail => "newUser@Somenet.foo")
117 117 u.login = 'newuser2'
118 118 u.password, u.password_confirmation = "password", "password"
119 119 assert !u.save
120 120 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:mail]
121 121 end
122 122
123 123 def test_update
124 124 assert_equal "admin", @admin.login
125 125 @admin.login = "john"
126 126 assert @admin.save, @admin.errors.full_messages.join("; ")
127 127 @admin.reload
128 128 assert_equal "john", @admin.login
129 129 end
130 130
131 131 def test_update_should_not_fail_for_legacy_user_with_different_case_logins
132 132 u1 = User.new(:firstname => "new", :lastname => "user", :mail => "newuser1@somenet.foo")
133 133 u1.login = 'newuser1'
134 134 assert u1.save
135 135
136 136 u2 = User.new(:firstname => "new", :lastname => "user", :mail => "newuser2@somenet.foo")
137 137 u2.login = 'newuser1'
138 138 assert u2.save(:validate => false)
139 139
140 140 user = User.find(u2.id)
141 141 user.firstname = "firstname"
142 142 assert user.save, "Save failed"
143 143 end
144 144
145 145 def test_destroy_should_delete_members_and_roles
146 146 members = Member.find_all_by_user_id(2)
147 147 ms = members.size
148 148 rs = members.collect(&:roles).flatten.size
149 149
150 150 assert_difference 'Member.count', - ms do
151 151 assert_difference 'MemberRole.count', - rs do
152 152 User.find(2).destroy
153 153 end
154 154 end
155 155
156 156 assert_nil User.find_by_id(2)
157 157 assert Member.find_all_by_user_id(2).empty?
158 158 end
159 159
160 160 def test_destroy_should_update_attachments
161 161 attachment = Attachment.create!(:container => Project.find(1),
162 162 :file => uploaded_test_file("testfile.txt", "text/plain"),
163 163 :author_id => 2)
164 164
165 165 User.find(2).destroy
166 166 assert_nil User.find_by_id(2)
167 167 assert_equal User.anonymous, attachment.reload.author
168 168 end
169 169
170 170 def test_destroy_should_update_comments
171 171 comment = Comment.create!(
172 172 :commented => News.create!(:project_id => 1, :author_id => 1, :title => 'foo', :description => 'foo'),
173 173 :author => User.find(2),
174 174 :comments => 'foo'
175 175 )
176 176
177 177 User.find(2).destroy
178 178 assert_nil User.find_by_id(2)
179 179 assert_equal User.anonymous, comment.reload.author
180 180 end
181 181
182 182 def test_destroy_should_update_issues
183 183 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
184 184
185 185 User.find(2).destroy
186 186 assert_nil User.find_by_id(2)
187 187 assert_equal User.anonymous, issue.reload.author
188 188 end
189 189
190 190 def test_destroy_should_unassign_issues
191 191 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
192 192
193 193 User.find(2).destroy
194 194 assert_nil User.find_by_id(2)
195 195 assert_nil issue.reload.assigned_to
196 196 end
197 197
198 198 def test_destroy_should_update_journals
199 199 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
200 200 issue.init_journal(User.find(2), "update")
201 201 issue.save!
202 202
203 203 User.find(2).destroy
204 204 assert_nil User.find_by_id(2)
205 205 assert_equal User.anonymous, issue.journals.first.reload.user
206 206 end
207 207
208 208 def test_destroy_should_update_journal_details_old_value
209 209 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
210 210 issue.init_journal(User.find(1), "update")
211 211 issue.assigned_to_id = nil
212 212 assert_difference 'JournalDetail.count' do
213 213 issue.save!
214 214 end
215 215 journal_detail = JournalDetail.first(:order => 'id DESC')
216 216 assert_equal '2', journal_detail.old_value
217 217
218 218 User.find(2).destroy
219 219 assert_nil User.find_by_id(2)
220 220 assert_equal User.anonymous.id.to_s, journal_detail.reload.old_value
221 221 end
222 222
223 223 def test_destroy_should_update_journal_details_value
224 224 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
225 225 issue.init_journal(User.find(1), "update")
226 226 issue.assigned_to_id = 2
227 227 assert_difference 'JournalDetail.count' do
228 228 issue.save!
229 229 end
230 230 journal_detail = JournalDetail.first(:order => 'id DESC')
231 231 assert_equal '2', journal_detail.value
232 232
233 233 User.find(2).destroy
234 234 assert_nil User.find_by_id(2)
235 235 assert_equal User.anonymous.id.to_s, journal_detail.reload.value
236 236 end
237 237
238 238 def test_destroy_should_update_messages
239 239 board = Board.create!(:project_id => 1, :name => 'Board', :description => 'Board')
240 240 message = Message.create!(:board_id => board.id, :author_id => 2, :subject => 'foo', :content => 'foo')
241 241
242 242 User.find(2).destroy
243 243 assert_nil User.find_by_id(2)
244 244 assert_equal User.anonymous, message.reload.author
245 245 end
246 246
247 247 def test_destroy_should_update_news
248 248 news = News.create!(:project_id => 1, :author_id => 2, :title => 'foo', :description => 'foo')
249 249
250 250 User.find(2).destroy
251 251 assert_nil User.find_by_id(2)
252 252 assert_equal User.anonymous, news.reload.author
253 253 end
254 254
255 255 def test_destroy_should_delete_private_queries
256 256 query = Query.new(:name => 'foo', :is_public => false)
257 257 query.project_id = 1
258 258 query.user_id = 2
259 259 query.save!
260 260
261 261 User.find(2).destroy
262 262 assert_nil User.find_by_id(2)
263 263 assert_nil Query.find_by_id(query.id)
264 264 end
265 265
266 266 def test_destroy_should_update_public_queries
267 267 query = Query.new(:name => 'foo', :is_public => true)
268 268 query.project_id = 1
269 269 query.user_id = 2
270 270 query.save!
271 271
272 272 User.find(2).destroy
273 273 assert_nil User.find_by_id(2)
274 274 assert_equal User.anonymous, query.reload.user
275 275 end
276 276
277 277 def test_destroy_should_update_time_entries
278 278 entry = TimeEntry.new(:hours => '2', :spent_on => Date.today, :activity => TimeEntryActivity.create!(:name => 'foo'))
279 279 entry.project_id = 1
280 280 entry.user_id = 2
281 281 entry.save!
282 282
283 283 User.find(2).destroy
284 284 assert_nil User.find_by_id(2)
285 285 assert_equal User.anonymous, entry.reload.user
286 286 end
287 287
288 288 def test_destroy_should_delete_tokens
289 289 token = Token.create!(:user_id => 2, :value => 'foo')
290 290
291 291 User.find(2).destroy
292 292 assert_nil User.find_by_id(2)
293 293 assert_nil Token.find_by_id(token.id)
294 294 end
295 295
296 296 def test_destroy_should_delete_watchers
297 297 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
298 298 watcher = Watcher.create!(:user_id => 2, :watchable => issue)
299 299
300 300 User.find(2).destroy
301 301 assert_nil User.find_by_id(2)
302 302 assert_nil Watcher.find_by_id(watcher.id)
303 303 end
304 304
305 305 def test_destroy_should_update_wiki_contents
306 306 wiki_content = WikiContent.create!(
307 307 :text => 'foo',
308 308 :author_id => 2,
309 309 :page => WikiPage.create!(:title => 'Foo', :wiki => Wiki.create!(:project_id => 1, :start_page => 'Start'))
310 310 )
311 311 wiki_content.text = 'bar'
312 312 assert_difference 'WikiContent::Version.count' do
313 313 wiki_content.save!
314 314 end
315 315
316 316 User.find(2).destroy
317 317 assert_nil User.find_by_id(2)
318 318 assert_equal User.anonymous, wiki_content.reload.author
319 319 wiki_content.versions.each do |version|
320 320 assert_equal User.anonymous, version.reload.author
321 321 end
322 322 end
323 323
324 324 def test_destroy_should_nullify_issue_categories
325 325 category = IssueCategory.create!(:project_id => 1, :assigned_to_id => 2, :name => 'foo')
326 326
327 327 User.find(2).destroy
328 328 assert_nil User.find_by_id(2)
329 329 assert_nil category.reload.assigned_to_id
330 330 end
331 331
332 332 def test_destroy_should_nullify_changesets
333 333 changeset = Changeset.create!(
334 334 :repository => Repository::Subversion.create!(
335 335 :project_id => 1,
336 336 :url => 'file:///tmp',
337 337 :identifier => 'tmp'
338 338 ),
339 339 :revision => '12',
340 340 :committed_on => Time.now,
341 341 :committer => 'jsmith'
342 342 )
343 343 assert_equal 2, changeset.user_id
344 344
345 345 User.find(2).destroy
346 346 assert_nil User.find_by_id(2)
347 347 assert_nil changeset.reload.user_id
348 348 end
349 349
350 350 def test_anonymous_user_should_not_be_destroyable
351 351 assert_no_difference 'User.count' do
352 352 assert_equal false, User.anonymous.destroy
353 353 end
354 354 end
355 355
356 356 def test_validate_login_presence
357 357 @admin.login = ""
358 358 assert !@admin.save
359 359 assert_equal 1, @admin.errors.count
360 360 end
361 361
362 362 def test_validate_mail_notification_inclusion
363 363 u = User.new
364 364 u.mail_notification = 'foo'
365 365 u.save
366 366 assert_not_nil u.errors[:mail_notification]
367 367 end
368 368
369 369 context "User#try_to_login" do
370 370 should "fall-back to case-insensitive if user login is not found as-typed." do
371 371 user = User.try_to_login("AdMin", "admin")
372 372 assert_kind_of User, user
373 373 assert_equal "admin", user.login
374 374 end
375 375
376 376 should "select the exact matching user first" do
377 377 case_sensitive_user = User.generate! do |user|
378 378 user.password = "admin123"
379 379 end
380 380 # bypass validations to make it appear like existing data
381 381 case_sensitive_user.update_attribute(:login, 'ADMIN')
382 382
383 383 user = User.try_to_login("ADMIN", "admin123")
384 384 assert_kind_of User, user
385 385 assert_equal "ADMIN", user.login
386 386
387 387 end
388 388 end
389 389
390 390 def test_password
391 391 user = User.try_to_login("admin", "admin")
392 392 assert_kind_of User, user
393 393 assert_equal "admin", user.login
394 394 user.password = "hello123"
395 395 assert user.save
396 396
397 397 user = User.try_to_login("admin", "hello123")
398 398 assert_kind_of User, user
399 399 assert_equal "admin", user.login
400 400 end
401 401
402 402 def test_validate_password_length
403 403 with_settings :password_min_length => '100' do
404 404 user = User.new(:firstname => "new100", :lastname => "user100", :mail => "newuser100@somenet.foo")
405 405 user.login = "newuser100"
406 406 user.password, user.password_confirmation = "password100", "password100"
407 407 assert !user.save
408 408 assert_equal 1, user.errors.count
409 409 end
410 410 end
411 411
412 412 def test_name_format
413 413 assert_equal 'John S.', @jsmith.name(:firstname_lastinitial)
414 414 assert_equal 'Smith, John', @jsmith.name(:lastname_coma_firstname)
415 415 with_settings :user_format => :firstname_lastname do
416 416 assert_equal 'John Smith', @jsmith.reload.name
417 417 end
418 418 with_settings :user_format => :username do
419 419 assert_equal 'jsmith', @jsmith.reload.name
420 420 end
421 421 with_settings :user_format => :lastname do
422 422 assert_equal 'Smith', @jsmith.reload.name
423 423 end
424 424 end
425 425
426 426 def test_today_should_return_the_day_according_to_user_time_zone
427 427 preference = User.find(1).pref
428 428 date = Date.new(2012, 05, 15)
429 429 time = Time.gm(2012, 05, 15, 23, 30).utc # 2012-05-15 23:30 UTC
430 430 Date.stubs(:today).returns(date)
431 431 Time.stubs(:now).returns(time)
432 432
433 433 preference.update_attribute :time_zone, 'Baku' # UTC+4
434 434 assert_equal '2012-05-16', User.find(1).today.to_s
435 435
436 436 preference.update_attribute :time_zone, 'La Paz' # UTC-4
437 437 assert_equal '2012-05-15', User.find(1).today.to_s
438 438
439 439 preference.update_attribute :time_zone, ''
440 440 assert_equal '2012-05-15', User.find(1).today.to_s
441 441 end
442 442
443 443 def test_time_to_date_should_return_the_date_according_to_user_time_zone
444 444 preference = User.find(1).pref
445 445 time = Time.gm(2012, 05, 15, 23, 30).utc # 2012-05-15 23:30 UTC
446 446
447 447 preference.update_attribute :time_zone, 'Baku' # UTC+4
448 448 assert_equal '2012-05-16', User.find(1).time_to_date(time).to_s
449 449
450 450 preference.update_attribute :time_zone, 'La Paz' # UTC-4
451 451 assert_equal '2012-05-15', User.find(1).time_to_date(time).to_s
452 452
453 453 preference.update_attribute :time_zone, ''
454 454 assert_equal '2012-05-15', User.find(1).time_to_date(time).to_s
455 455 end
456 456
457 457 def test_fields_for_order_statement_should_return_fields_according_user_format_setting
458 458 with_settings :user_format => 'lastname_coma_firstname' do
459 459 assert_equal ['users.lastname', 'users.firstname', 'users.id'], User.fields_for_order_statement
460 460 end
461 461 end
462 462
463 463 def test_fields_for_order_statement_width_table_name_should_prepend_table_name
464 464 with_settings :user_format => 'lastname_firstname' do
465 465 assert_equal ['authors.lastname', 'authors.firstname', 'authors.id'], User.fields_for_order_statement('authors')
466 466 end
467 467 end
468 468
469 469 def test_fields_for_order_statement_with_blank_format_should_return_default
470 470 with_settings :user_format => '' do
471 471 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
472 472 end
473 473 end
474 474
475 475 def test_fields_for_order_statement_with_invalid_format_should_return_default
476 476 with_settings :user_format => 'foo' do
477 477 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
478 478 end
479 479 end
480 480
481 481 def test_lock
482 482 user = User.try_to_login("jsmith", "jsmith")
483 483 assert_equal @jsmith, user
484 484
485 485 @jsmith.status = User::STATUS_LOCKED
486 486 assert @jsmith.save
487 487
488 488 user = User.try_to_login("jsmith", "jsmith")
489 489 assert_equal nil, user
490 490 end
491 491
492 492 context ".try_to_login" do
493 493 context "with good credentials" do
494 494 should "return the user" do
495 495 user = User.try_to_login("admin", "admin")
496 496 assert_kind_of User, user
497 497 assert_equal "admin", user.login
498 498 end
499 499 end
500 500
501 501 context "with wrong credentials" do
502 502 should "return nil" do
503 503 assert_nil User.try_to_login("admin", "foo")
504 504 end
505 505 end
506 506 end
507 507
508 508 if ldap_configured?
509 509 context "#try_to_login using LDAP" do
510 510 context "with failed connection to the LDAP server" do
511 511 should "return nil" do
512 512 @auth_source = AuthSourceLdap.find(1)
513 513 AuthSource.any_instance.stubs(:initialize_ldap_con).raises(Net::LDAP::LdapError, 'Cannot connect')
514 514
515 515 assert_equal nil, User.try_to_login('edavis', 'wrong')
516 516 end
517 517 end
518 518
519 519 context "with an unsuccessful authentication" do
520 520 should "return nil" do
521 521 assert_equal nil, User.try_to_login('edavis', 'wrong')
522 522 end
523 523 end
524 524
525 525 context "binding with user's account" do
526 526 setup do
527 527 @auth_source = AuthSourceLdap.find(1)
528 528 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
529 529 @auth_source.account_password = ''
530 530 @auth_source.save!
531 531
532 532 @ldap_user = User.new(:mail => 'example1@redmine.org', :firstname => 'LDAP', :lastname => 'user', :auth_source_id => 1)
533 533 @ldap_user.login = 'example1'
534 534 @ldap_user.save!
535 535 end
536 536
537 537 context "with a successful authentication" do
538 538 should "return the user" do
539 539 assert_equal @ldap_user, User.try_to_login('example1', '123456')
540 540 end
541 541 end
542 542
543 543 context "with an unsuccessful authentication" do
544 544 should "return nil" do
545 545 assert_nil User.try_to_login('example1', '11111')
546 546 end
547 547 end
548 548 end
549 549
550 550 context "on the fly registration" do
551 551 setup do
552 552 @auth_source = AuthSourceLdap.find(1)
553 553 @auth_source.update_attribute :onthefly_register, true
554 554 end
555 555
556 556 context "with a successful authentication" do
557 557 should "create a new user account if it doesn't exist" do
558 558 assert_difference('User.count') do
559 559 user = User.try_to_login('edavis', '123456')
560 560 assert !user.admin?
561 561 end
562 562 end
563 563
564 564 should "retrieve existing user" do
565 565 user = User.try_to_login('edavis', '123456')
566 566 user.admin = true
567 567 user.save!
568 568
569 569 assert_no_difference('User.count') do
570 570 user = User.try_to_login('edavis', '123456')
571 571 assert user.admin?
572 572 end
573 573 end
574 574 end
575 575
576 576 context "binding with user's account" do
577 577 setup do
578 578 @auth_source = AuthSourceLdap.find(1)
579 579 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
580 580 @auth_source.account_password = ''
581 581 @auth_source.save!
582 582 end
583 583
584 584 context "with a successful authentication" do
585 585 should "create a new user account if it doesn't exist" do
586 586 assert_difference('User.count') do
587 587 user = User.try_to_login('example1', '123456')
588 588 assert_kind_of User, user
589 589 end
590 590 end
591 591 end
592 592
593 593 context "with an unsuccessful authentication" do
594 594 should "return nil" do
595 595 assert_nil User.try_to_login('example1', '11111')
596 596 end
597 597 end
598 598 end
599 599 end
600 600 end
601 601
602 602 else
603 603 puts "Skipping LDAP tests."
604 604 end
605 605
606 606 def test_create_anonymous
607 607 AnonymousUser.delete_all
608 608 anon = User.anonymous
609 609 assert !anon.new_record?
610 610 assert_kind_of AnonymousUser, anon
611 611 end
612 612
613 613 def test_ensure_single_anonymous_user
614 614 AnonymousUser.delete_all
615 615 anon1 = User.anonymous
616 616 assert !anon1.new_record?
617 617 assert_kind_of AnonymousUser, anon1
618 618 anon2 = AnonymousUser.create(
619 619 :lastname => 'Anonymous', :firstname => '',
620 620 :mail => '', :login => '', :status => 0)
621 621 assert_equal 1, anon2.errors.count
622 622 end
623 623
624 624 def test_rss_key
625 625 assert_nil @jsmith.rss_token
626 626 key = @jsmith.rss_key
627 627 assert_equal 40, key.length
628 628
629 629 @jsmith.reload
630 630 assert_equal key, @jsmith.rss_key
631 631 end
632 632
633 633 def test_rss_key_should_not_be_generated_twice
634 634 assert_difference 'Token.count', 1 do
635 635 key1 = @jsmith.rss_key
636 636 key2 = @jsmith.rss_key
637 637 assert_equal key1, key2
638 638 end
639 639 end
640 640
641 641 def test_api_key_should_not_be_generated_twice
642 642 assert_difference 'Token.count', 1 do
643 643 key1 = @jsmith.api_key
644 644 key2 = @jsmith.api_key
645 645 assert_equal key1, key2
646 646 end
647 647 end
648 648
649 649 context "User#api_key" do
650 650 should "generate a new one if the user doesn't have one" do
651 651 user = User.generate!(:api_token => nil)
652 652 assert_nil user.api_token
653 653
654 654 key = user.api_key
655 655 assert_equal 40, key.length
656 656 user.reload
657 657 assert_equal key, user.api_key
658 658 end
659 659
660 660 should "return the existing api token value" do
661 661 user = User.generate!
662 662 token = Token.create!(:action => 'api')
663 663 user.api_token = token
664 664 assert user.save
665 665
666 666 assert_equal token.value, user.api_key
667 667 end
668 668 end
669 669
670 670 context "User#find_by_api_key" do
671 671 should "return nil if no matching key is found" do
672 672 assert_nil User.find_by_api_key('zzzzzzzzz')
673 673 end
674 674
675 675 should "return nil if the key is found for an inactive user" do
676 676 user = User.generate!
677 677 user.status = User::STATUS_LOCKED
678 678 token = Token.create!(:action => 'api')
679 679 user.api_token = token
680 680 user.save
681 681
682 682 assert_nil User.find_by_api_key(token.value)
683 683 end
684 684
685 685 should "return the user if the key is found for an active user" do
686 686 user = User.generate!
687 687 token = Token.create!(:action => 'api')
688 688 user.api_token = token
689 689 user.save
690 690
691 691 assert_equal user, User.find_by_api_key(token.value)
692 692 end
693 693 end
694 694
695 695 def test_default_admin_account_changed_should_return_false_if_account_was_not_changed
696 696 user = User.find_by_login("admin")
697 697 user.password = "admin"
698 698 assert user.save(:validate => false)
699 699
700 700 assert_equal false, User.default_admin_account_changed?
701 701 end
702 702
703 703 def test_default_admin_account_changed_should_return_true_if_password_was_changed
704 704 user = User.find_by_login("admin")
705 705 user.password = "newpassword"
706 706 user.save!
707 707
708 708 assert_equal true, User.default_admin_account_changed?
709 709 end
710 710
711 711 def test_default_admin_account_changed_should_return_true_if_account_is_disabled
712 712 user = User.find_by_login("admin")
713 713 user.password = "admin"
714 714 user.status = User::STATUS_LOCKED
715 715 assert user.save(:validate => false)
716 716
717 717 assert_equal true, User.default_admin_account_changed?
718 718 end
719 719
720 720 def test_default_admin_account_changed_should_return_true_if_account_does_not_exist
721 721 user = User.find_by_login("admin")
722 722 user.destroy
723 723
724 724 assert_equal true, User.default_admin_account_changed?
725 725 end
726 726
727 727 def test_roles_for_project
728 728 # user with a role
729 729 roles = @jsmith.roles_for_project(Project.find(1))
730 730 assert_kind_of Role, roles.first
731 731 assert_equal "Manager", roles.first.name
732 732
733 733 # user with no role
734 734 assert_nil @dlopper.roles_for_project(Project.find(2)).detect {|role| role.member?}
735 735 end
736 736
737 737 def test_projects_by_role_for_user_with_role
738 738 user = User.find(2)
739 739 assert_kind_of Hash, user.projects_by_role
740 740 assert_equal 2, user.projects_by_role.size
741 741 assert_equal [1,5], user.projects_by_role[Role.find(1)].collect(&:id).sort
742 742 assert_equal [2], user.projects_by_role[Role.find(2)].collect(&:id).sort
743 743 end
744 744
745 745 def test_accessing_projects_by_role_with_no_projects_should_return_an_empty_array
746 746 user = User.find(2)
747 747 assert_equal [], user.projects_by_role[Role.find(3)]
748 748 # should not update the hash
749 749 assert_nil user.projects_by_role.values.detect(&:blank?)
750 750 end
751 751
752 752 def test_projects_by_role_for_user_with_no_role
753 753 user = User.generate!
754 754 assert_equal({}, user.projects_by_role)
755 755 end
756 756
757 757 def test_projects_by_role_for_anonymous
758 758 assert_equal({}, User.anonymous.projects_by_role)
759 759 end
760 760
761 761 def test_valid_notification_options
762 762 # without memberships
763 763 assert_equal 5, User.find(7).valid_notification_options.size
764 764 # with memberships
765 765 assert_equal 6, User.find(2).valid_notification_options.size
766 766 end
767 767
768 768 def test_valid_notification_options_class_method
769 769 assert_equal 5, User.valid_notification_options.size
770 770 assert_equal 5, User.valid_notification_options(User.find(7)).size
771 771 assert_equal 6, User.valid_notification_options(User.find(2)).size
772 772 end
773 773
774 774 def test_mail_notification_all
775 775 @jsmith.mail_notification = 'all'
776 776 @jsmith.notified_project_ids = []
777 777 @jsmith.save
778 778 @jsmith.reload
779 779 assert @jsmith.projects.first.recipients.include?(@jsmith.mail)
780 780 end
781 781
782 782 def test_mail_notification_selected
783 783 @jsmith.mail_notification = 'selected'
784 784 @jsmith.notified_project_ids = [1]
785 785 @jsmith.save
786 786 @jsmith.reload
787 787 assert Project.find(1).recipients.include?(@jsmith.mail)
788 788 end
789 789
790 790 def test_mail_notification_only_my_events
791 791 @jsmith.mail_notification = 'only_my_events'
792 792 @jsmith.notified_project_ids = []
793 793 @jsmith.save
794 794 @jsmith.reload
795 795 assert !@jsmith.projects.first.recipients.include?(@jsmith.mail)
796 796 end
797 797
798 798 def test_comments_sorting_preference
799 799 assert !@jsmith.wants_comments_in_reverse_order?
800 800 @jsmith.pref.comments_sorting = 'asc'
801 801 assert !@jsmith.wants_comments_in_reverse_order?
802 802 @jsmith.pref.comments_sorting = 'desc'
803 803 assert @jsmith.wants_comments_in_reverse_order?
804 804 end
805 805
806 806 def test_find_by_mail_should_be_case_insensitive
807 807 u = User.find_by_mail('JSmith@somenet.foo')
808 808 assert_not_nil u
809 809 assert_equal 'jsmith@somenet.foo', u.mail
810 810 end
811 811
812 812 def test_random_password
813 813 u = User.new
814 814 u.random_password
815 815 assert !u.password.blank?
816 816 assert !u.password_confirmation.blank?
817 817 end
818 818
819 819 context "#change_password_allowed?" do
820 820 should "be allowed if no auth source is set" do
821 821 user = User.generate!
822 822 assert user.change_password_allowed?
823 823 end
824 824
825 825 should "delegate to the auth source" do
826 826 user = User.generate!
827 827
828 828 allowed_auth_source = AuthSource.generate!
829 829 def allowed_auth_source.allow_password_changes?; true; end
830 830
831 831 denied_auth_source = AuthSource.generate!
832 832 def denied_auth_source.allow_password_changes?; false; end
833 833
834 834 assert user.change_password_allowed?
835 835
836 836 user.auth_source = allowed_auth_source
837 837 assert user.change_password_allowed?, "User not allowed to change password, though auth source does"
838 838
839 839 user.auth_source = denied_auth_source
840 840 assert !user.change_password_allowed?, "User allowed to change password, though auth source does not"
841 841 end
842 842 end
843 843
844 844 def test_own_account_deletable_should_be_true_with_unsubscrive_enabled
845 845 with_settings :unsubscribe => '1' do
846 846 assert_equal true, User.find(2).own_account_deletable?
847 847 end
848 848 end
849 849
850 850 def test_own_account_deletable_should_be_false_with_unsubscrive_disabled
851 851 with_settings :unsubscribe => '0' do
852 852 assert_equal false, User.find(2).own_account_deletable?
853 853 end
854 854 end
855 855
856 856 def test_own_account_deletable_should_be_false_for_a_single_admin
857 857 User.delete_all(["admin = ? AND id <> ?", true, 1])
858 858
859 859 with_settings :unsubscribe => '1' do
860 860 assert_equal false, User.find(1).own_account_deletable?
861 861 end
862 862 end
863 863
864 864 def test_own_account_deletable_should_be_true_for_an_admin_if_other_admin_exists
865 865 User.generate! do |user|
866 866 user.admin = true
867 867 end
868 868
869 869 with_settings :unsubscribe => '1' do
870 870 assert_equal true, User.find(1).own_account_deletable?
871 871 end
872 872 end
873 873
874 874 context "#allowed_to?" do
875 875 context "with a unique project" do
876 876 should "return false if project is archived" do
877 877 project = Project.find(1)
878 878 Project.any_instance.stubs(:status).returns(Project::STATUS_ARCHIVED)
879 879 assert_equal false, @admin.allowed_to?(:view_issues, Project.find(1))
880 880 end
881 881
882 882 should "return false for write action if project is closed" do
883 883 project = Project.find(1)
884 884 Project.any_instance.stubs(:status).returns(Project::STATUS_CLOSED)
885 885 assert_equal false, @admin.allowed_to?(:edit_project, Project.find(1))
886 886 end
887 887
888 888 should "return true for read action if project is closed" do
889 889 project = Project.find(1)
890 890 Project.any_instance.stubs(:status).returns(Project::STATUS_CLOSED)
891 891 assert_equal true, @admin.allowed_to?(:view_project, Project.find(1))
892 892 end
893 893
894 894 should "return false if related module is disabled" do
895 895 project = Project.find(1)
896 896 project.enabled_module_names = ["issue_tracking"]
897 897 assert_equal true, @admin.allowed_to?(:add_issues, project)
898 898 assert_equal false, @admin.allowed_to?(:view_wiki_pages, project)
899 899 end
900 900
901 901 should "authorize nearly everything for admin users" do
902 902 project = Project.find(1)
903 903 assert ! @admin.member_of?(project)
904 %w(edit_issues delete_issues manage_news manage_documents manage_wiki).each do |p|
904 %w(edit_issues delete_issues manage_news add_documents manage_wiki).each do |p|
905 905 assert_equal true, @admin.allowed_to?(p.to_sym, project)
906 906 end
907 907 end
908 908
909 909 should "authorize normal users depending on their roles" do
910 910 project = Project.find(1)
911 911 assert_equal true, @jsmith.allowed_to?(:delete_messages, project) #Manager
912 912 assert_equal false, @dlopper.allowed_to?(:delete_messages, project) #Developper
913 913 end
914 914 end
915 915
916 916 context "with multiple projects" do
917 917 should "return false if array is empty" do
918 918 assert_equal false, @admin.allowed_to?(:view_project, [])
919 919 end
920 920
921 921 should "return true only if user has permission on all these projects" do
922 922 assert_equal true, @admin.allowed_to?(:view_project, Project.all)
923 923 assert_equal false, @dlopper.allowed_to?(:view_project, Project.all) #cannot see Project(2)
924 924 assert_equal true, @jsmith.allowed_to?(:edit_issues, @jsmith.projects) #Manager or Developer everywhere
925 925 assert_equal false, @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects) #Dev cannot delete_issue_watchers
926 926 end
927 927
928 928 should "behave correctly with arrays of 1 project" do
929 929 assert_equal false, User.anonymous.allowed_to?(:delete_issues, [Project.first])
930 930 end
931 931 end
932 932
933 933 context "with options[:global]" do
934 934 should "authorize if user has at least one role that has this permission" do
935 935 @dlopper2 = User.find(5) #only Developper on a project, not Manager anywhere
936 936 @anonymous = User.find(6)
937 937 assert_equal true, @jsmith.allowed_to?(:delete_issue_watchers, nil, :global => true)
938 938 assert_equal false, @dlopper2.allowed_to?(:delete_issue_watchers, nil, :global => true)
939 939 assert_equal true, @dlopper2.allowed_to?(:add_issues, nil, :global => true)
940 940 assert_equal false, @anonymous.allowed_to?(:add_issues, nil, :global => true)
941 941 assert_equal true, @anonymous.allowed_to?(:view_issues, nil, :global => true)
942 942 end
943 943 end
944 944 end
945 945
946 946 context "User#notify_about?" do
947 947 context "Issues" do
948 948 setup do
949 949 @project = Project.find(1)
950 950 @author = User.generate!
951 951 @assignee = User.generate!
952 952 @issue = Issue.generate!(:project => @project, :assigned_to => @assignee, :author => @author)
953 953 end
954 954
955 955 should "be true for a user with :all" do
956 956 @author.update_attribute(:mail_notification, 'all')
957 957 assert @author.notify_about?(@issue)
958 958 end
959 959
960 960 should "be false for a user with :none" do
961 961 @author.update_attribute(:mail_notification, 'none')
962 962 assert ! @author.notify_about?(@issue)
963 963 end
964 964
965 965 should "be false for a user with :only_my_events and isn't an author, creator, or assignee" do
966 966 @user = User.generate!(:mail_notification => 'only_my_events')
967 967 Member.create!(:user => @user, :project => @project, :role_ids => [1])
968 968 assert ! @user.notify_about?(@issue)
969 969 end
970 970
971 971 should "be true for a user with :only_my_events and is the author" do
972 972 @author.update_attribute(:mail_notification, 'only_my_events')
973 973 assert @author.notify_about?(@issue)
974 974 end
975 975
976 976 should "be true for a user with :only_my_events and is the assignee" do
977 977 @assignee.update_attribute(:mail_notification, 'only_my_events')
978 978 assert @assignee.notify_about?(@issue)
979 979 end
980 980
981 981 should "be true for a user with :only_assigned and is the assignee" do
982 982 @assignee.update_attribute(:mail_notification, 'only_assigned')
983 983 assert @assignee.notify_about?(@issue)
984 984 end
985 985
986 986 should "be false for a user with :only_assigned and is not the assignee" do
987 987 @author.update_attribute(:mail_notification, 'only_assigned')
988 988 assert ! @author.notify_about?(@issue)
989 989 end
990 990
991 991 should "be true for a user with :only_owner and is the author" do
992 992 @author.update_attribute(:mail_notification, 'only_owner')
993 993 assert @author.notify_about?(@issue)
994 994 end
995 995
996 996 should "be false for a user with :only_owner and is not the author" do
997 997 @assignee.update_attribute(:mail_notification, 'only_owner')
998 998 assert ! @assignee.notify_about?(@issue)
999 999 end
1000 1000
1001 1001 should "be true for a user with :selected and is the author" do
1002 1002 @author.update_attribute(:mail_notification, 'selected')
1003 1003 assert @author.notify_about?(@issue)
1004 1004 end
1005 1005
1006 1006 should "be true for a user with :selected and is the assignee" do
1007 1007 @assignee.update_attribute(:mail_notification, 'selected')
1008 1008 assert @assignee.notify_about?(@issue)
1009 1009 end
1010 1010
1011 1011 should "be false for a user with :selected and is not the author or assignee" do
1012 1012 @user = User.generate!(:mail_notification => 'selected')
1013 1013 Member.create!(:user => @user, :project => @project, :role_ids => [1])
1014 1014 assert ! @user.notify_about?(@issue)
1015 1015 end
1016 1016 end
1017 1017
1018 1018 context "other events" do
1019 1019 should 'be added and tested'
1020 1020 end
1021 1021 end
1022 1022
1023 1023 def test_salt_unsalted_passwords
1024 1024 # Restore a user with an unsalted password
1025 1025 user = User.find(1)
1026 1026 user.salt = nil
1027 1027 user.hashed_password = User.hash_password("unsalted")
1028 1028 user.save!
1029 1029
1030 1030 User.salt_unsalted_passwords!
1031 1031
1032 1032 user.reload
1033 1033 # Salt added
1034 1034 assert !user.salt.blank?
1035 1035 # Password still valid
1036 1036 assert user.check_password?("unsalted")
1037 1037 assert_equal user, User.try_to_login(user.login, "unsalted")
1038 1038 end
1039 1039
1040 1040 if Object.const_defined?(:OpenID)
1041 1041
1042 1042 def test_setting_identity_url
1043 1043 normalized_open_id_url = 'http://example.com/'
1044 1044 u = User.new( :identity_url => 'http://example.com/' )
1045 1045 assert_equal normalized_open_id_url, u.identity_url
1046 1046 end
1047 1047
1048 1048 def test_setting_identity_url_without_trailing_slash
1049 1049 normalized_open_id_url = 'http://example.com/'
1050 1050 u = User.new( :identity_url => 'http://example.com' )
1051 1051 assert_equal normalized_open_id_url, u.identity_url
1052 1052 end
1053 1053
1054 1054 def test_setting_identity_url_without_protocol
1055 1055 normalized_open_id_url = 'http://example.com/'
1056 1056 u = User.new( :identity_url => 'example.com' )
1057 1057 assert_equal normalized_open_id_url, u.identity_url
1058 1058 end
1059 1059
1060 1060 def test_setting_blank_identity_url
1061 1061 u = User.new( :identity_url => 'example.com' )
1062 1062 u.identity_url = ''
1063 1063 assert u.identity_url.blank?
1064 1064 end
1065 1065
1066 1066 def test_setting_invalid_identity_url
1067 1067 u = User.new( :identity_url => 'this is not an openid url' )
1068 1068 assert u.identity_url.blank?
1069 1069 end
1070 1070
1071 1071 else
1072 1072 puts "Skipping openid tests."
1073 1073 end
1074 1074
1075 1075 end
General Comments 0
You need to be logged in to leave comments. Login now