##// END OF EJS Templates
Fixed that the proposed users list may be empty when adding a project member (#10374)....
Jean-Philippe Lang -
r9008:6aad82e524c1
parent child
Show More
@@ -1,142 +1,142
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class MembersController < ApplicationController
18 class MembersController < ApplicationController
19 model_object Member
19 model_object Member
20 before_filter :find_model_object, :except => [:index, :create, :autocomplete]
20 before_filter :find_model_object, :except => [:index, :create, :autocomplete]
21 before_filter :find_project_from_association, :except => [:index, :create, :autocomplete]
21 before_filter :find_project_from_association, :except => [:index, :create, :autocomplete]
22 before_filter :find_project_by_project_id, :only => [:index, :create, :autocomplete]
22 before_filter :find_project_by_project_id, :only => [:index, :create, :autocomplete]
23 before_filter :authorize
23 before_filter :authorize
24 accept_api_auth :index, :show, :create, :update, :destroy
24 accept_api_auth :index, :show, :create, :update, :destroy
25
25
26 def index
26 def index
27 @offset, @limit = api_offset_and_limit
27 @offset, @limit = api_offset_and_limit
28 @member_count = @project.member_principals.count
28 @member_count = @project.member_principals.count
29 @member_pages = Paginator.new self, @member_count, @limit, params['page']
29 @member_pages = Paginator.new self, @member_count, @limit, params['page']
30 @offset ||= @member_pages.current.offset
30 @offset ||= @member_pages.current.offset
31 @members = @project.member_principals.all(
31 @members = @project.member_principals.all(
32 :order => "#{Member.table_name}.id",
32 :order => "#{Member.table_name}.id",
33 :limit => @limit,
33 :limit => @limit,
34 :offset => @offset
34 :offset => @offset
35 )
35 )
36
36
37 respond_to do |format|
37 respond_to do |format|
38 format.html { head 406 }
38 format.html { head 406 }
39 format.api
39 format.api
40 end
40 end
41 end
41 end
42
42
43 def show
43 def show
44 respond_to do |format|
44 respond_to do |format|
45 format.html { head 406 }
45 format.html { head 406 }
46 format.api
46 format.api
47 end
47 end
48 end
48 end
49
49
50 def create
50 def create
51 members = []
51 members = []
52 if params[:membership] && params[:membership][:user_ids]
52 if params[:membership] && params[:membership][:user_ids]
53 attrs = params[:membership].dup
53 attrs = params[:membership].dup
54 user_ids = attrs.delete(:user_ids)
54 user_ids = attrs.delete(:user_ids)
55 user_ids.each do |user_id|
55 user_ids.each do |user_id|
56 members << Member.new(attrs.merge(:user_id => user_id))
56 members << Member.new(attrs.merge(:user_id => user_id))
57 end
57 end
58 else
58 else
59 members << Member.new(params[:membership])
59 members << Member.new(params[:membership])
60 end
60 end
61 @project.members << members
61 @project.members << members
62
62
63 respond_to do |format|
63 respond_to do |format|
64 if members.present? && members.all? {|m| m.valid? }
64 if members.present? && members.all? {|m| m.valid? }
65 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
65 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
66 format.js {
66 format.js {
67 render(:update) {|page|
67 render(:update) {|page|
68 page.replace_html "tab-content-members", :partial => 'projects/settings/members'
68 page.replace_html "tab-content-members", :partial => 'projects/settings/members'
69 page << 'hideOnLoad()'
69 page << 'hideOnLoad()'
70 members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") }
70 members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") }
71 }
71 }
72 }
72 }
73 format.api {
73 format.api {
74 @member = members.first
74 @member = members.first
75 render :action => 'show', :status => :created, :location => membership_url(@member)
75 render :action => 'show', :status => :created, :location => membership_url(@member)
76 }
76 }
77 else
77 else
78 format.js {
78 format.js {
79 render(:update) {|page|
79 render(:update) {|page|
80 errors = members.collect {|m|
80 errors = members.collect {|m|
81 m.errors.full_messages
81 m.errors.full_messages
82 }.flatten.uniq
82 }.flatten.uniq
83
83
84 page.alert(l(:notice_failed_to_save_members, :errors => errors.join(', ')))
84 page.alert(l(:notice_failed_to_save_members, :errors => errors.join(', ')))
85 }
85 }
86 }
86 }
87 format.api { render_validation_errors(members.first) }
87 format.api { render_validation_errors(members.first) }
88 end
88 end
89 end
89 end
90 end
90 end
91
91
92 def update
92 def update
93 if params[:membership]
93 if params[:membership]
94 @member.role_ids = params[:membership][:role_ids]
94 @member.role_ids = params[:membership][:role_ids]
95 end
95 end
96 saved = @member.save
96 saved = @member.save
97 respond_to do |format|
97 respond_to do |format|
98 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
98 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
99 format.js {
99 format.js {
100 render(:update) {|page|
100 render(:update) {|page|
101 page.replace_html "tab-content-members", :partial => 'projects/settings/members'
101 page.replace_html "tab-content-members", :partial => 'projects/settings/members'
102 page << 'hideOnLoad()'
102 page << 'hideOnLoad()'
103 page.visual_effect(:highlight, "member-#{@member.id}")
103 page.visual_effect(:highlight, "member-#{@member.id}")
104 }
104 }
105 }
105 }
106 format.api {
106 format.api {
107 if saved
107 if saved
108 head :ok
108 head :ok
109 else
109 else
110 render_validation_errors(@member)
110 render_validation_errors(@member)
111 end
111 end
112 }
112 }
113 end
113 end
114 end
114 end
115
115
116 def destroy
116 def destroy
117 if request.delete? && @member.deletable?
117 if request.delete? && @member.deletable?
118 @member.destroy
118 @member.destroy
119 end
119 end
120 respond_to do |format|
120 respond_to do |format|
121 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
121 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
122 format.js { render(:update) {|page|
122 format.js { render(:update) {|page|
123 page.replace_html "tab-content-members", :partial => 'projects/settings/members'
123 page.replace_html "tab-content-members", :partial => 'projects/settings/members'
124 page << 'hideOnLoad()'
124 page << 'hideOnLoad()'
125 }
125 }
126 }
126 }
127 format.api {
127 format.api {
128 if @member.destroyed?
128 if @member.destroyed?
129 head :ok
129 head :ok
130 else
130 else
131 head :unprocessable_entity
131 head :unprocessable_entity
132 end
132 end
133 }
133 }
134 end
134 end
135 end
135 end
136
136
137 def autocomplete
137 def autocomplete
138 @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals
138 @principals = Principal.active.not_member_of(@project).like(params[:q]).all(:limit => 100)
139 render :layout => false
139 render :layout => false
140 end
140 end
141
141
142 end
142 end
@@ -1,84 +1,95
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Principal < ActiveRecord::Base
18 class Principal < ActiveRecord::Base
19 set_table_name "#{table_name_prefix}users#{table_name_suffix}"
19 set_table_name "#{table_name_prefix}users#{table_name_suffix}"
20
20
21 has_many :members, :foreign_key => 'user_id', :dependent => :destroy
21 has_many :members, :foreign_key => 'user_id', :dependent => :destroy
22 has_many :memberships, :class_name => 'Member', :foreign_key => 'user_id', :include => [ :project, :roles ], :conditions => "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}", :order => "#{Project.table_name}.name"
22 has_many :memberships, :class_name => 'Member', :foreign_key => 'user_id', :include => [ :project, :roles ], :conditions => "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}", :order => "#{Project.table_name}.name"
23 has_many :projects, :through => :memberships
23 has_many :projects, :through => :memberships
24 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
24 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
25
25
26 # Groups and active users
26 # Groups and active users
27 named_scope :active, :conditions => "#{Principal.table_name}.status = 1"
27 named_scope :active, :conditions => "#{Principal.table_name}.status = 1"
28
28
29 named_scope :like, lambda {|q|
29 named_scope :like, lambda {|q|
30 if q.blank?
30 if q.blank?
31 {}
31 {}
32 else
32 else
33 q = q.to_s.downcase
33 q = q.to_s.downcase
34 pattern = "%#{q}%"
34 pattern = "%#{q}%"
35 sql = "LOWER(login) LIKE :p OR LOWER(firstname) LIKE :p OR LOWER(lastname) LIKE :p OR LOWER(mail) LIKE :p"
35 sql = "LOWER(login) LIKE :p OR LOWER(firstname) LIKE :p OR LOWER(lastname) LIKE :p OR LOWER(mail) LIKE :p"
36 params = {:p => pattern}
36 params = {:p => pattern}
37 if q =~ /^(.+)\s+(.+)$/
37 if q =~ /^(.+)\s+(.+)$/
38 a, b = "#{$1}%", "#{$2}%"
38 a, b = "#{$1}%", "#{$2}%"
39 sql << " OR (LOWER(firstname) LIKE :a AND LOWER(lastname) LIKE :b) OR (LOWER(firstname) LIKE :b AND LOWER(lastname) LIKE :a)"
39 sql << " OR (LOWER(firstname) LIKE :a AND LOWER(lastname) LIKE :b) OR (LOWER(firstname) LIKE :b AND LOWER(lastname) LIKE :a)"
40 params.merge!(:a => a, :b => b)
40 params.merge!(:a => a, :b => b)
41 end
41 end
42 {:conditions => [sql, params]}
42 {:conditions => [sql, params]}
43 end
43 end
44 }
44 }
45
45
46 # Principals that are members of a collection of projects
46 # Principals that are members of a collection of projects
47 named_scope :member_of, lambda {|projects|
47 named_scope :member_of, lambda {|projects|
48 projects = [projects] unless projects.is_a?(Array)
48 if projects.empty?
49 if projects.empty?
49 {:conditions => "1=0"}
50 {:conditions => "1=0"}
50 else
51 else
51 ids = projects.map(&:id)
52 ids = projects.map(&:id)
52 {:conditions => ["#{Principal.table_name}.status = 1 AND #{Principal.table_name}.id IN (SELECT DISTINCT user_id FROM #{Member.table_name} WHERE project_id IN (?))", ids]}
53 {:conditions => ["#{Principal.table_name}.status = 1 AND #{Principal.table_name}.id IN (SELECT DISTINCT user_id FROM #{Member.table_name} WHERE project_id IN (?))", ids]}
53 end
54 end
54 }
55 }
56 # Principals that are not members of projects
57 named_scope :not_member_of, lambda {|projects|
58 projects = [projects] unless projects.is_a?(Array)
59 if projects.empty?
60 {:conditions => "1=0"}
61 else
62 ids = projects.map(&:id)
63 {:conditions => ["#{Principal.table_name}.id NOT IN (SELECT DISTINCT user_id FROM #{Member.table_name} WHERE project_id IN (?))", ids]}
64 end
65 }
55
66
56 before_create :set_default_empty_values
67 before_create :set_default_empty_values
57
68
58 def name(formatter = nil)
69 def name(formatter = nil)
59 to_s
70 to_s
60 end
71 end
61
72
62 def <=>(principal)
73 def <=>(principal)
63 if principal.nil?
74 if principal.nil?
64 -1
75 -1
65 elsif self.class.name == principal.class.name
76 elsif self.class.name == principal.class.name
66 self.to_s.downcase <=> principal.to_s.downcase
77 self.to_s.downcase <=> principal.to_s.downcase
67 else
78 else
68 # groups after users
79 # groups after users
69 principal.class.name <=> self.class.name
80 principal.class.name <=> self.class.name
70 end
81 end
71 end
82 end
72
83
73 protected
84 protected
74
85
75 # Make sure we don't try to insert NULL values (see #4632)
86 # Make sure we don't try to insert NULL values (see #4632)
76 def set_default_empty_values
87 def set_default_empty_values
77 self.login ||= ''
88 self.login ||= ''
78 self.hashed_password ||= ''
89 self.hashed_password ||= ''
79 self.firstname ||= ''
90 self.firstname ||= ''
80 self.lastname ||= ''
91 self.lastname ||= ''
81 self.mail ||= ''
92 self.mail ||= ''
82 true
93 true
83 end
94 end
84 end
95 end
@@ -1,91 +1,91
1 <%= error_messages_for 'member' %>
1 <%= error_messages_for 'member' %>
2 <% roles = Role.find_all_givable
2 <% roles = Role.find_all_givable
3 members = @project.member_principals.find(:all, :include => [:roles, :principal]).sort %>
3 members = @project.member_principals.find(:all, :include => [:roles, :principal]).sort %>
4
4
5 <div class="splitcontentleft">
5 <div class="splitcontentleft">
6 <% if members.any? %>
6 <% if members.any? %>
7 <table class="list members">
7 <table class="list members">
8 <thead><tr>
8 <thead><tr>
9 <th><%= l(:label_user) %> / <%= l(:label_group) %></th>
9 <th><%= l(:label_user) %> / <%= l(:label_group) %></th>
10 <th><%= l(:label_role_plural) %></th>
10 <th><%= l(:label_role_plural) %></th>
11 <th style="width:15%"></th>
11 <th style="width:15%"></th>
12 <%= call_hook(:view_projects_settings_members_table_header, :project => @project) %>
12 <%= call_hook(:view_projects_settings_members_table_header, :project => @project) %>
13 </tr></thead>
13 </tr></thead>
14 <tbody>
14 <tbody>
15 <% members.each do |member| %>
15 <% members.each do |member| %>
16 <% next if member.new_record? %>
16 <% next if member.new_record? %>
17 <tr id="member-<%= member.id %>" class="<%= cycle 'odd', 'even' %> member">
17 <tr id="member-<%= member.id %>" class="<%= cycle 'odd', 'even' %> member">
18 <td class="<%= member.principal.class.name.downcase %>"><%= link_to_user member.principal %></td>
18 <td class="<%= member.principal.class.name.downcase %>"><%= link_to_user member.principal %></td>
19 <td class="roles">
19 <td class="roles">
20 <span id="member-<%= member.id %>-roles"><%=h member.roles.sort.collect(&:to_s).join(', ') %></span>
20 <span id="member-<%= member.id %>-roles"><%=h member.roles.sort.collect(&:to_s).join(', ') %></span>
21 <% remote_form_for(:membership, member, :url => membership_path(member),
21 <% remote_form_for(:membership, member, :url => membership_path(member),
22 :method => :put,
22 :method => :put,
23 :html => { :id => "member-#{member.id}-roles-form", :class => 'hol' }) do |f| %>
23 :html => { :id => "member-#{member.id}-roles-form", :class => 'hol' }) do |f| %>
24 <p><% roles.each do |role| %>
24 <p><% roles.each do |role| %>
25 <label><%= check_box_tag 'membership[role_ids][]', role.id, member.roles.include?(role),
25 <label><%= check_box_tag 'membership[role_ids][]', role.id, member.roles.include?(role),
26 :disabled => member.member_roles.detect {|mr| mr.role_id == role.id && !mr.inherited_from.nil?} %> <%=h role %></label><br />
26 :disabled => member.member_roles.detect {|mr| mr.role_id == role.id && !mr.inherited_from.nil?} %> <%=h role %></label><br />
27 <% end %></p>
27 <% end %></p>
28 <%= hidden_field_tag 'membership[role_ids][]', '' %>
28 <%= hidden_field_tag 'membership[role_ids][]', '' %>
29 <p><%= submit_tag l(:button_change), :class => "small" %>
29 <p><%= submit_tag l(:button_change), :class => "small" %>
30 <%= link_to_function l(:button_cancel),
30 <%= link_to_function l(:button_cancel),
31 "$('member-#{member.id}-roles').show(); $('member-#{member.id}-roles-form').hide(); return false;"
31 "$('member-#{member.id}-roles').show(); $('member-#{member.id}-roles-form').hide(); return false;"
32 %></p>
32 %></p>
33 <% end %>
33 <% end %>
34 </td>
34 </td>
35 <td class="buttons">
35 <td class="buttons">
36 <%= link_to_function l(:button_edit),
36 <%= link_to_function l(:button_edit),
37 "$('member-#{member.id}-roles').hide(); $('member-#{member.id}-roles-form').show(); return false;",
37 "$('member-#{member.id}-roles').hide(); $('member-#{member.id}-roles-form').show(); return false;",
38 :class => 'icon icon-edit' %>
38 :class => 'icon icon-edit' %>
39 <%= link_to_remote(
39 <%= link_to_remote(
40 l(:button_delete),
40 l(:button_delete),
41 { :url => membership_path(member),
41 { :url => membership_path(member),
42 :method => :delete,
42 :method => :delete,
43 :confirm => (!User.current.admin? && member.include?(User.current) ? l(:text_own_membership_delete_confirmation) : nil) },
43 :confirm => (!User.current.admin? && member.include?(User.current) ? l(:text_own_membership_delete_confirmation) : nil) },
44 :title => l(:button_delete),
44 :title => l(:button_delete),
45 :class => 'icon icon-del'
45 :class => 'icon icon-del'
46 ) if member.deletable? %>
46 ) if member.deletable? %>
47 </td>
47 </td>
48 <%= call_hook(:view_projects_settings_members_table_row, { :project => @project, :member => member}) %>
48 <%= call_hook(:view_projects_settings_members_table_row, { :project => @project, :member => member}) %>
49 </tr>
49 </tr>
50 <% end; reset_cycle %>
50 <% end; reset_cycle %>
51 </tbody>
51 </tbody>
52 </table>
52 </table>
53 <% else %>
53 <% else %>
54 <p class="nodata"><%= l(:label_no_data) %></p>
54 <p class="nodata"><%= l(:label_no_data) %></p>
55 <% end %>
55 <% end %>
56 </div>
56 </div>
57
57
58 <% principals = Principal.active.find(:all, :limit => 100, :order => 'type, login, lastname ASC') - @project.principals %>
58 <% principals = Principal.active.not_member_of(@project).all(:limit => 100, :order => 'type, login, lastname ASC') %>
59
59
60 <div class="splitcontentright">
60 <div class="splitcontentright">
61 <% if roles.any? && principals.any? %>
61 <% if roles.any? && principals.any? %>
62 <% remote_form_for(:membership, @member, :url => project_memberships_path(@project), :method => :post,
62 <% remote_form_for(:membership, @member, :url => project_memberships_path(@project), :method => :post,
63 :loading => '$(\'member-add-submit\').disable();',
63 :loading => '$(\'member-add-submit\').disable();',
64 :complete => 'if($(\'member-add-submit\')) $(\'member-add-submit\').enable();') do |f| %>
64 :complete => 'if($(\'member-add-submit\')) $(\'member-add-submit\').enable();') do |f| %>
65 <fieldset><legend><%=l(:label_member_new)%></legend>
65 <fieldset><legend><%=l(:label_member_new)%></legend>
66
66
67 <p><%= label_tag "principal_search", l(:label_principal_search) %><%= text_field_tag 'principal_search', nil %></p>
67 <p><%= label_tag "principal_search", l(:label_principal_search) %><%= text_field_tag 'principal_search', nil %></p>
68 <%= observe_field(:principal_search,
68 <%= observe_field(:principal_search,
69 :frequency => 0.5,
69 :frequency => 0.5,
70 :update => :principals,
70 :update => :principals,
71 :url => autocomplete_project_memberships_path(@project),
71 :url => autocomplete_project_memberships_path(@project),
72 :method => :get,
72 :method => :get,
73 :before => '$("principal_search").addClassName("ajax-loading")',
73 :before => '$("principal_search").addClassName("ajax-loading")',
74 :complete => '$("principal_search").removeClassName("ajax-loading")',
74 :complete => '$("principal_search").removeClassName("ajax-loading")',
75 :with => 'q')
75 :with => 'q')
76 %>
76 %>
77
77
78 <div id="principals">
78 <div id="principals">
79 <%= principals_check_box_tags 'membership[user_ids][]', principals %>
79 <%= principals_check_box_tags 'membership[user_ids][]', principals %>
80 </div>
80 </div>
81
81
82 <p><%= l(:label_role_plural) %>:
82 <p><%= l(:label_role_plural) %>:
83 <% roles.each do |role| %>
83 <% roles.each do |role| %>
84 <label><%= check_box_tag 'membership[role_ids][]', role.id %> <%=h role %></label>
84 <label><%= check_box_tag 'membership[role_ids][]', role.id %> <%=h role %></label>
85 <% end %></p>
85 <% end %></p>
86
86
87 <p><%= submit_tag l(:button_add), :id => 'member-add-submit' %></p>
87 <p><%= submit_tag l(:button_add), :id => 'member-add-submit' %></p>
88 </fieldset>
88 </fieldset>
89 <% end %>
89 <% end %>
90 <% end %>
90 <% end %>
91 </div>
91 </div>
@@ -1,94 +1,101
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class PrincipalTest < ActiveSupport::TestCase
20 class PrincipalTest < ActiveSupport::TestCase
21 fixtures :users, :projects, :members, :member_roles
21
22
22 def test_active_scope_should_return_groups_and_active_users
23 def test_active_scope_should_return_groups_and_active_users
23 result = Principal.active.all
24 result = Principal.active.all
24 assert_include Group.first, result
25 assert_include Group.first, result
25 assert_not_nil result.detect {|p| p.is_a?(User)}
26 assert_not_nil result.detect {|p| p.is_a?(User)}
26 assert_nil result.detect {|p| p.is_a?(User) && !p.active?}
27 assert_nil result.detect {|p| p.is_a?(User) && !p.active?}
27 assert_nil result.detect {|p| p.is_a?(AnonymousUser)}
28 assert_nil result.detect {|p| p.is_a?(AnonymousUser)}
28 end
29 end
29
30
30 def test_member_of_scope_should_return_the_union_of_all_members
31 def test_member_of_scope_should_return_the_union_of_all_members
31 projects = Project.find_all_by_id(1, 2)
32 projects = Project.find_all_by_id(1, 2)
32 assert_equal projects.map(&:principals).flatten.sort, Principal.member_of(projects).sort
33 assert_equal projects.map(&:principals).flatten.sort, Principal.member_of(projects).sort
33 end
34 end
34
35
36 def test_not_member_of_scope_should_return_users_that_have_no_memberships
37 projects = Project.find_all_by_id(1, 2)
38 expected = (Principal.all - projects.map(&:memberships).flatten.map(&:principal)).sort
39 assert_equal expected, Principal.not_member_of(projects).sort
40 end
41
35 context "#like" do
42 context "#like" do
36 setup do
43 setup do
37 Principal.generate!(:login => 'login')
44 Principal.generate!(:login => 'login')
38 Principal.generate!(:login => 'login2')
45 Principal.generate!(:login => 'login2')
39
46
40 Principal.generate!(:firstname => 'firstname')
47 Principal.generate!(:firstname => 'firstname')
41 Principal.generate!(:firstname => 'firstname2')
48 Principal.generate!(:firstname => 'firstname2')
42
49
43 Principal.generate!(:lastname => 'lastname')
50 Principal.generate!(:lastname => 'lastname')
44 Principal.generate!(:lastname => 'lastname2')
51 Principal.generate!(:lastname => 'lastname2')
45
52
46 Principal.generate!(:mail => 'mail@example.com')
53 Principal.generate!(:mail => 'mail@example.com')
47 Principal.generate!(:mail => 'mail2@example.com')
54 Principal.generate!(:mail => 'mail2@example.com')
48
55
49 @palmer = Principal.generate!(:firstname => 'David', :lastname => 'Palmer')
56 @palmer = Principal.generate!(:firstname => 'David', :lastname => 'Palmer')
50 end
57 end
51
58
52 should "search login" do
59 should "search login" do
53 results = Principal.like('login')
60 results = Principal.like('login')
54
61
55 assert_equal 2, results.count
62 assert_equal 2, results.count
56 assert results.all? {|u| u.login.match(/login/) }
63 assert results.all? {|u| u.login.match(/login/) }
57 end
64 end
58
65
59 should "search firstname" do
66 should "search firstname" do
60 results = Principal.like('firstname')
67 results = Principal.like('firstname')
61
68
62 assert_equal 2, results.count
69 assert_equal 2, results.count
63 assert results.all? {|u| u.firstname.match(/firstname/) }
70 assert results.all? {|u| u.firstname.match(/firstname/) }
64 end
71 end
65
72
66 should "search lastname" do
73 should "search lastname" do
67 results = Principal.like('lastname')
74 results = Principal.like('lastname')
68
75
69 assert_equal 2, results.count
76 assert_equal 2, results.count
70 assert results.all? {|u| u.lastname.match(/lastname/) }
77 assert results.all? {|u| u.lastname.match(/lastname/) }
71 end
78 end
72
79
73 should "search mail" do
80 should "search mail" do
74 results = Principal.like('mail')
81 results = Principal.like('mail')
75
82
76 assert_equal 2, results.count
83 assert_equal 2, results.count
77 assert results.all? {|u| u.mail.match(/mail/) }
84 assert results.all? {|u| u.mail.match(/mail/) }
78 end
85 end
79
86
80 should "search firstname and lastname" do
87 should "search firstname and lastname" do
81 results = Principal.like('david palm')
88 results = Principal.like('david palm')
82
89
83 assert_equal 1, results.count
90 assert_equal 1, results.count
84 assert_equal @palmer, results.first
91 assert_equal @palmer, results.first
85 end
92 end
86
93
87 should "search lastname and firstname" do
94 should "search lastname and firstname" do
88 results = Principal.like('palmer davi')
95 results = Principal.like('palmer davi')
89
96
90 assert_equal 1, results.count
97 assert_equal 1, results.count
91 assert_equal @palmer, results.first
98 assert_equal @palmer, results.first
92 end
99 end
93 end
100 end
94 end
101 end
General Comments 0
You need to be logged in to leave comments. Login now