##// END OF EJS Templates
Moves blocks definition to Redmine::MyPage....
Jean-Philippe Lang -
r15548:8b86d5158e50
parent child
Show More
@@ -1,211 +1,192
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 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 MyController < ApplicationController
19 19 before_action :require_login
20 20 # let user change user's password when user has to
21 21 skip_before_action :check_password_change, :only => :password
22 22
23 23 require_sudo_mode :account, only: :post
24 24 require_sudo_mode :reset_rss_key, :reset_api_key, :show_api_key, :destroy
25 25
26 26 helper :issues
27 27 helper :users
28 28 helper :custom_fields
29 29
30 BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues,
31 'issuesreportedbyme' => :label_reported_issues,
32 'issueswatched' => :label_watched_issues,
33 'news' => :label_news_latest,
34 'calendar' => :label_calendar,
35 'documents' => :label_document_plural,
36 'timelog' => :label_spent_time
37 }.merge(Redmine::Views::MyPage::Block.additional_blocks).freeze
38
39 DEFAULT_LAYOUT = { 'left' => ['issuesassignedtome'],
40 'right' => ['issuesreportedbyme']
41 }.freeze
42
43 30 def index
44 31 page
45 32 render :action => 'page'
46 33 end
47 34
48 35 # Show user's page
49 36 def page
50 37 @user = User.current
51 @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT
38 @blocks = @user.pref.my_page_layout
52 39 end
53 40
54 41 # Edit user's account
55 42 def account
56 43 @user = User.current
57 44 @pref = @user.pref
58 45 if request.post?
59 46 @user.safe_attributes = params[:user]
60 47 @user.pref.safe_attributes = params[:pref]
61 48 if @user.save
62 49 @user.pref.save
63 50 set_language_if_valid @user.language
64 51 flash[:notice] = l(:notice_account_updated)
65 52 redirect_to my_account_path
66 53 return
67 54 end
68 55 end
69 56 end
70 57
71 58 # Destroys user's account
72 59 def destroy
73 60 @user = User.current
74 61 unless @user.own_account_deletable?
75 62 redirect_to my_account_path
76 63 return
77 64 end
78 65
79 66 if request.post? && params[:confirm]
80 67 @user.destroy
81 68 if @user.destroyed?
82 69 logout_user
83 70 flash[:notice] = l(:notice_account_deleted)
84 71 end
85 72 redirect_to home_path
86 73 end
87 74 end
88 75
89 76 # Manage user's password
90 77 def password
91 78 @user = User.current
92 79 unless @user.change_password_allowed?
93 80 flash[:error] = l(:notice_can_t_change_password)
94 81 redirect_to my_account_path
95 82 return
96 83 end
97 84 if request.post?
98 85 if !@user.check_password?(params[:password])
99 86 flash.now[:error] = l(:notice_account_wrong_password)
100 87 elsif params[:password] == params[:new_password]
101 88 flash.now[:error] = l(:notice_new_password_must_be_different)
102 89 else
103 90 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
104 91 @user.must_change_passwd = false
105 92 if @user.save
106 93 # The session token was destroyed by the password change, generate a new one
107 94 session[:tk] = @user.generate_session_token
108 95 Mailer.password_updated(@user)
109 96 flash[:notice] = l(:notice_account_password_updated)
110 97 redirect_to my_account_path
111 98 end
112 99 end
113 100 end
114 101 end
115 102
116 103 # Create a new feeds key
117 104 def reset_rss_key
118 105 if request.post?
119 106 if User.current.rss_token
120 107 User.current.rss_token.destroy
121 108 User.current.reload
122 109 end
123 110 User.current.rss_key
124 111 flash[:notice] = l(:notice_feeds_access_key_reseted)
125 112 end
126 113 redirect_to my_account_path
127 114 end
128 115
129 116 def show_api_key
130 117 @user = User.current
131 118 end
132 119
133 120 # Create a new API key
134 121 def reset_api_key
135 122 if request.post?
136 123 if User.current.api_token
137 124 User.current.api_token.destroy
138 125 User.current.reload
139 126 end
140 127 User.current.api_key
141 128 flash[:notice] = l(:notice_api_access_key_reseted)
142 129 end
143 130 redirect_to my_account_path
144 131 end
145 132
146 133 # User's page layout configuration
147 134 def page_layout
148 135 @user = User.current
149 @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT.dup
150 @block_options = []
151 BLOCKS.each do |k, v|
152 unless @blocks.values.flatten.include?(k)
153 @block_options << [l("my.blocks.#{v}", :default => [v, v.to_s.humanize]), k.dasherize]
154 end
155 end
136 @blocks = @user.pref.my_page_layout
156 137 end
157 138
158 139 # Add a block to user's page
159 140 # The block is added on top of the page
160 141 # params[:block] : id of the block to add
161 142 def add_block
162 143 block = params[:block].to_s.underscore
163 if block.present? && BLOCKS.key?(block)
144 if block.present? && Redmine::MyPage.blocks.key?(block)
164 145 @user = User.current
165 layout = @user.pref[:my_page_layout] || {}
146 layout = @user.pref.my_page_layout
166 147 # remove if already present in a group
167 148 %w(top left right).each {|f| (layout[f] ||= []).delete block }
168 149 # add it on top
169 150 layout['top'].unshift block
170 @user.pref[:my_page_layout] = layout
151 @user.pref.my_page_layout = layout
171 152 @user.pref.save
172 153 end
173 154 redirect_to my_page_layout_path
174 155 end
175 156
176 157 # Remove a block to user's page
177 158 # params[:block] : id of the block to remove
178 159 def remove_block
179 160 block = params[:block].to_s.underscore
180 161 @user = User.current
181 162 # remove block in all groups
182 layout = @user.pref[:my_page_layout] || {}
163 layout = @user.pref.my_page_layout
183 164 %w(top left right).each {|f| (layout[f] ||= []).delete block }
184 @user.pref[:my_page_layout] = layout
165 @user.pref.my_page_layout = layout
185 166 @user.pref.save
186 167 redirect_to my_page_layout_path
187 168 end
188 169
189 170 # Change blocks order on user's page
190 171 # params[:group] : group to order (top, left or right)
191 172 # params[:list-(top|left|right)] : array of block ids of the group
192 173 def order_blocks
193 174 group = params[:group]
194 175 @user = User.current
195 176 if group.is_a?(String)
196 177 group_items = (params["blocks"] || []).collect(&:underscore)
197 178 group_items.each {|s| s.sub!(/^block_/, '')}
198 179 if group_items and group_items.is_a? Array
199 layout = @user.pref[:my_page_layout] || {}
180 layout = @user.pref.my_page_layout
200 181 # remove group blocks if they are presents in other groups
201 182 %w(top left right).each {|f|
202 183 layout[f] = (layout[f] || []) - group_items
203 184 }
204 185 layout[group] = group_items
205 @user.pref[:my_page_layout] = layout
186 @user.pref.my_page_layout = layout
206 187 @user.pref.save
207 188 end
208 189 end
209 190 head 200
210 191 end
211 192 end
@@ -1,110 +1,119
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2016 Jean-Philippe Lang
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; either version 2
9 9 # of the License, or (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
20 20 module MyHelper
21 21 # Renders the blocks
22 22 def render_blocks(blocks, user, options={})
23 23 s = ''.html_safe
24 24
25 25 if blocks.present?
26 26 blocks.each do |block|
27 27 content = render_block_content(block, user)
28 28 if content.present?
29 29 if options[:edit]
30 30 close = link_to(l(:button_delete), {:action => "remove_block", :block => block}, :method => 'post', :class => "icon-only icon-close")
31 31 content = close + content_tag('div', content, :class => 'handle')
32 32 end
33 33
34 34 s << content_tag('div', content, :class => "mypage-box", :id => "block-#{block}")
35 35 end
36 36 end
37 37 end
38 38 s
39 39 end
40 40
41 41 # Renders a single block content
42 42 def render_block_content(block, user)
43 unless MyController::BLOCKS.keys.include?(block)
43 unless Redmine::MyPage.blocks.key?(block)
44 44 Rails.logger.warn("Unknown block \"#{block}\" found in #{user.login} (id=#{user.id}) preferences")
45 45 return
46 46 end
47 47
48 48 begin
49 49 render(:partial => "my/blocks/#{block}", :locals => {:user => user})
50 50 rescue ActionView::MissingTemplate
51 51 Rails.logger.warn("Template missing for block \"#{block}\" found in #{user.login} (id=#{user.id}) preferences")
52 52 return nil
53 53 end
54 54 end
55 55
56 def block_select_tag(user)
57 disabled = user.pref.my_page_layout.values.flatten
58 options = content_tag('option')
59 Redmine::MyPage.block_options.each do |label, block|
60 options << content_tag('option', label, :value => block, :disabled => disabled.include?(block))
61 end
62 content_tag('select', options, :id => "block-select")
63 end
64
56 65 def calendar_items(startdt, enddt)
57 66 Issue.visible.
58 67 where(:project_id => User.current.projects.map(&:id)).
59 68 where("(start_date>=? and start_date<=?) or (due_date>=? and due_date<=?)", startdt, enddt, startdt, enddt).
60 69 includes(:project, :tracker, :priority, :assigned_to).
61 70 references(:project, :tracker, :priority, :assigned_to).
62 71 to_a
63 72 end
64 73
65 74 def documents_items
66 75 Document.visible.order("#{Document.table_name}.created_on DESC").limit(10).to_a
67 76 end
68 77
69 78 def issuesassignedtome_items
70 79 Issue.visible.open.
71 80 assigned_to(User.current).
72 81 limit(10).
73 82 includes(:status, :project, :tracker, :priority).
74 83 references(:status, :project, :tracker, :priority).
75 84 order("#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC")
76 85 end
77 86
78 87 def issuesreportedbyme_items
79 88 Issue.visible.open.
80 89 where(:author_id => User.current.id).
81 90 limit(10).
82 91 includes(:status, :project, :tracker).
83 92 references(:status, :project, :tracker).
84 93 order("#{Issue.table_name}.updated_on DESC")
85 94 end
86 95
87 96 def issueswatched_items
88 97 Issue.visible.open.on_active_project.watched_by(User.current.id).recently_updated.limit(10)
89 98 end
90 99
91 100 def news_items
92 101 News.visible.
93 102 where(:project_id => User.current.projects.map(&:id)).
94 103 limit(10).
95 104 includes(:project, :author).
96 105 references(:project, :author).
97 106 order("#{News.table_name}.created_on DESC").
98 107 to_a
99 108 end
100 109
101 110 def timelog_items
102 111 TimeEntry.
103 112 where("#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", User.current.id, User.current.today - 6, User.current.today).
104 113 joins(:activity, :project).
105 114 references(:issue => [:tracker, :status]).
106 115 includes(:issue => [:tracker, :status]).
107 116 order("#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC").
108 117 to_a
109 118 end
110 119 end
@@ -1,85 +1,93
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 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 UserPreference < ActiveRecord::Base
19 19 include Redmine::SafeAttributes
20 20
21 21 belongs_to :user
22 22 serialize :others
23 23
24 24 attr_protected :others, :user_id
25 25
26 26 before_save :set_others_hash
27 27
28 28 safe_attributes 'hide_mail',
29 29 'time_zone',
30 30 'comments_sorting',
31 31 'warn_on_leaving_unsaved',
32 32 'no_self_notified',
33 33 'textarea_font'
34 34
35 35 TEXTAREA_FONT_OPTIONS = ['monospace', 'proportional']
36 36
37 37 def initialize(attributes=nil, *args)
38 38 super
39 39 if new_record? && !(attributes && attributes.key?(:hide_mail))
40 40 self.hide_mail = Setting.default_users_hide_mail?
41 41 end
42 42 if new_record? && !(attributes && attributes.key?(:no_self_notified))
43 43 self.no_self_notified = true
44 44 end
45 45 self.others ||= {}
46 46 end
47 47
48 48 def set_others_hash
49 49 self.others ||= {}
50 50 end
51 51
52 52 def [](attr_name)
53 53 if has_attribute? attr_name
54 54 super
55 55 else
56 56 others ? others[attr_name] : nil
57 57 end
58 58 end
59 59
60 60 def []=(attr_name, value)
61 61 if has_attribute? attr_name
62 62 super
63 63 else
64 64 h = (read_attribute(:others) || {}).dup
65 65 h.update(attr_name => value)
66 66 write_attribute(:others, h)
67 67 value
68 68 end
69 69 end
70 70
71 71 def comments_sorting; self[:comments_sorting] end
72 72 def comments_sorting=(order); self[:comments_sorting]=order end
73 73
74 74 def warn_on_leaving_unsaved; self[:warn_on_leaving_unsaved] || '1'; end
75 75 def warn_on_leaving_unsaved=(value); self[:warn_on_leaving_unsaved]=value; end
76 76
77 77 def no_self_notified; (self[:no_self_notified] == true || self[:no_self_notified] == '1'); end
78 78 def no_self_notified=(value); self[:no_self_notified]=value; end
79 79
80 80 def activity_scope; Array(self[:activity_scope]) ; end
81 81 def activity_scope=(value); self[:activity_scope]=value ; end
82 82
83 83 def textarea_font; self[:textarea_font] end
84 84 def textarea_font=(value); self[:textarea_font]=value; end
85
86 def my_page_layout
87 self[:my_page_layout] ||= Redmine::MyPage.default_layout.deep_dup
88 end
89
90 def my_page_layout=(arg)
91 self[:my_page_layout] = arg
92 end
85 93 end
@@ -1,32 +1,29
1 1 <div class="contextual">
2 <% if @block_options.present? %>
3 <%= form_tag({:action => "add_block"}, :id => "block-form") do %>
2
3 <%= form_tag({:action => "add_block"}, :id => "block-form") do %>
4 4 <%= label_tag('block-select', l(:label_my_page_block)) %>:
5 <%= select_tag 'block',
6 content_tag('option') + options_for_select(@block_options),
7 :id => "block-select" %>
5 <%= block_select_tag(@user) %>
8 6 <%= link_to l(:button_add), '#', :onclick => '$("#block-form").submit()', :class => 'icon icon-add' %>
9 <% end %>
10 7 <% end %>
11 8 <%= link_to l(:button_back), {:action => 'page'}, :class => 'icon icon-cancel' %>
12 9 </div>
13 10
14 11 <h2><%=l(:label_my_page)%></h2>
15 12
16 13 <div id="list-top" class="block-receiver">
17 14 <%= render_blocks(@blocks['top'], @user, :edit => true) %>
18 15 </div>
19 16
20 17 <div id="list-left" class="splitcontentleft block-receiver">
21 18 <%= render_blocks(@blocks['left'], @user, :edit => true) %>
22 19 </div>
23 20
24 21 <div id="list-right" class="splitcontentright block-receiver">
25 22 <%= render_blocks(@blocks['right'], @user, :edit => true) %>
26 23 </div>
27 24
28 25 <%= javascript_tag "initMyPageSortable('top', '#{ escape_javascript url_for(:action => "order_blocks", :group => "top") }');" %>
29 26 <%= javascript_tag "initMyPageSortable('left', '#{ escape_javascript url_for(:action => "order_blocks", :group => "left") }');" %>
30 27 <%= javascript_tag "initMyPageSortable('right', '#{ escape_javascript url_for(:action => "order_blocks", :group => "right") }');" %>
31 28
32 29 <% html_title(l(:label_my_page)) -%>
@@ -1,32 +1,62
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 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 module Redmine
19 module Views
20 module MyPage
21 module Block
22 def self.additional_blocks
23 @@additional_blocks ||= Dir.glob("#{Redmine::Plugin.directory}/*/app/views/my/blocks/_*.{rhtml,erb}").inject({}) do |h,file|
24 name = File.basename(file).split('.').first.gsub(/^_/, '')
25 h[name] = name.to_sym
26 h
27 end
28 end
19 module MyPage
20 include Redmine::I18n
21
22 CORE_BLOCKS = {
23 'issuesassignedtome' => :label_assigned_to_me_issues,
24 'issuesreportedbyme' => :label_reported_issues,
25 'issueswatched' => :label_watched_issues,
26 'news' => :label_news_latest,
27 'calendar' => :label_calendar,
28 'documents' => :label_document_plural,
29 'timelog' => :label_spent_time
30 }
31
32 # Returns the available blocks
33 def self.blocks
34 CORE_BLOCKS.merge(additional_blocks).freeze
35 end
36
37 def self.block_options
38 options = []
39 blocks.each do |k, v|
40 options << [l("my.blocks.#{v}", :default => [v, v.to_s.humanize]), k.dasherize]
29 41 end
42 options
43 end
44
45 # Returns the additional blocks that are defined by plugin partials
46 def self.additional_blocks
47 @@additional_blocks ||= Dir.glob("#{Redmine::Plugin.directory}/*/app/views/my/blocks/_*.{rhtml,erb}").inject({}) do |h,file|
48 name = File.basename(file).split('.').first.gsub(/^_/, '')
49 h[name] = name.to_sym
50 h
51 end
52 end
53
54 # Returns the default layout for My Page
55 def self.default_layout
56 {
57 'left' => ['issuesassignedtome'],
58 'right' => ['issuesreportedbyme']
59 }
30 60 end
31 61 end
32 62 end
@@ -1,295 +1,295
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 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 MyControllerTest < Redmine::ControllerTest
21 21 fixtures :users, :email_addresses, :user_preferences, :roles, :projects, :members, :member_roles,
22 22 :issues, :issue_statuses, :trackers, :enumerations, :custom_fields, :auth_sources
23 23
24 24 def setup
25 25 @request.session[:user_id] = 2
26 26 end
27 27
28 28 def test_index
29 29 get :index
30 30 assert_response :success
31 31 assert_select 'h2', 'My page'
32 32 end
33 33
34 34 def test_page
35 35 get :page
36 36 assert_response :success
37 37 assert_select 'h2', 'My page'
38 38 end
39 39
40 40 def test_page_with_timelog_block
41 41 preferences = User.find(2).pref
42 42 preferences[:my_page_layout] = {'top' => ['timelog']}
43 43 preferences.save!
44 44 TimeEntry.create!(:user => User.find(2), :spent_on => Date.yesterday, :issue_id => 1, :hours => 2.5, :activity_id => 10)
45 45
46 46 get :page
47 47 assert_response :success
48 48 assert_select 'tr.time-entry' do
49 49 assert_select 'td.subject a[href="/issues/1"]'
50 50 assert_select 'td.hours', :text => '2.50'
51 51 end
52 52 end
53 53
54 54 def test_page_with_all_blocks
55 blocks = MyController::BLOCKS.keys
55 blocks = Redmine::MyPage.blocks.keys
56 56 preferences = User.find(2).pref
57 57 preferences[:my_page_layout] = {'top' => blocks}
58 58 preferences.save!
59 59
60 60 get :page
61 61 assert_response :success
62 62 assert_select 'div.mypage-box', blocks.size
63 63 end
64 64
65 65 def test_my_account_should_show_editable_custom_fields
66 66 get :account
67 67 assert_response :success
68 68 assert_select 'input[name=?]', 'user[custom_field_values][4]'
69 69 end
70 70
71 71 def test_my_account_should_not_show_non_editable_custom_fields
72 72 UserCustomField.find(4).update_attribute :editable, false
73 73
74 74 get :account
75 75 assert_response :success
76 76 assert_select 'input[name=?]', 'user[custom_field_values][4]', 0
77 77 end
78 78
79 79 def test_my_account_should_show_language_select
80 80 get :account
81 81 assert_response :success
82 82 assert_select 'select[name=?]', 'user[language]'
83 83 end
84 84
85 85 def test_my_account_should_not_show_language_select_with_force_default_language_for_loggedin
86 86 with_settings :force_default_language_for_loggedin => '1' do
87 87 get :account
88 88 assert_response :success
89 89 assert_select 'select[name=?]', 'user[language]', 0
90 90 end
91 91 end
92 92
93 93 def test_update_account
94 94 post :account,
95 95 :user => {
96 96 :firstname => "Joe",
97 97 :login => "root",
98 98 :admin => 1,
99 99 :group_ids => ['10'],
100 100 :custom_field_values => {"4" => "0100562500"}
101 101 }
102 102
103 103 assert_redirected_to '/my/account'
104 104 user = User.find(2)
105 105 assert_equal "Joe", user.firstname
106 106 assert_equal "jsmith", user.login
107 107 assert_equal "0100562500", user.custom_value_for(4).value
108 108 # ignored
109 109 assert !user.admin?
110 110 assert user.groups.empty?
111 111 end
112 112
113 113 def test_update_account_should_send_security_notification
114 114 ActionMailer::Base.deliveries.clear
115 115 post :account,
116 116 :user => {
117 117 :mail => 'foobar@example.com'
118 118 }
119 119
120 120 assert_not_nil (mail = ActionMailer::Base.deliveries.last)
121 121 assert_mail_body_match '0.0.0.0', mail
122 122 assert_mail_body_match I18n.t(:mail_body_security_notification_change_to, field: I18n.t(:field_mail), value: 'foobar@example.com'), mail
123 123 assert_select_email do
124 124 assert_select 'a[href^=?]', 'http://localhost:3000/my/account', :text => 'My account'
125 125 end
126 126 # The old email address should be notified about the change for security purposes
127 127 assert [mail.bcc, mail.cc].flatten.include?(User.find(2).mail)
128 128 assert [mail.bcc, mail.cc].flatten.include?('foobar@example.com')
129 129 end
130 130
131 131 def test_my_account_should_show_destroy_link
132 132 get :account
133 133 assert_select 'a[href="/my/account/destroy"]'
134 134 end
135 135
136 136 def test_get_destroy_should_display_the_destroy_confirmation
137 137 get :destroy
138 138 assert_response :success
139 139 assert_select 'form[action="/my/account/destroy"]' do
140 140 assert_select 'input[name=confirm]'
141 141 end
142 142 end
143 143
144 144 def test_post_destroy_without_confirmation_should_not_destroy_account
145 145 assert_no_difference 'User.count' do
146 146 post :destroy
147 147 end
148 148 assert_response :success
149 149 end
150 150
151 151 def test_post_destroy_without_confirmation_should_destroy_account
152 152 assert_difference 'User.count', -1 do
153 153 post :destroy, :confirm => '1'
154 154 end
155 155 assert_redirected_to '/'
156 156 assert_match /deleted/i, flash[:notice]
157 157 end
158 158
159 159 def test_post_destroy_with_unsubscribe_not_allowed_should_not_destroy_account
160 160 User.any_instance.stubs(:own_account_deletable?).returns(false)
161 161
162 162 assert_no_difference 'User.count' do
163 163 post :destroy, :confirm => '1'
164 164 end
165 165 assert_redirected_to '/my/account'
166 166 end
167 167
168 168 def test_change_password
169 169 get :password
170 170 assert_response :success
171 171 assert_select 'input[type=password][name=password]'
172 172 assert_select 'input[type=password][name=new_password]'
173 173 assert_select 'input[type=password][name=new_password_confirmation]'
174 174 end
175 175
176 176 def test_update_password
177 177 post :password, :password => 'jsmith',
178 178 :new_password => 'secret123',
179 179 :new_password_confirmation => 'secret123'
180 180 assert_redirected_to '/my/account'
181 181 assert User.try_to_login('jsmith', 'secret123')
182 182 end
183 183
184 184 def test_update_password_with_non_matching_confirmation
185 185 post :password, :password => 'jsmith',
186 186 :new_password => 'secret123',
187 187 :new_password_confirmation => 'secret1234'
188 188 assert_response :success
189 189 assert_select_error /Password doesn.*t match confirmation/
190 190 assert User.try_to_login('jsmith', 'jsmith')
191 191 end
192 192
193 193 def test_update_password_with_wrong_password
194 194 # wrong password
195 195 post :password, :password => 'wrongpassword',
196 196 :new_password => 'secret123',
197 197 :new_password_confirmation => 'secret123'
198 198 assert_response :success
199 199 assert_equal 'Wrong password', flash[:error]
200 200 assert User.try_to_login('jsmith', 'jsmith')
201 201 end
202 202
203 203 def test_change_password_should_redirect_if_user_cannot_change_its_password
204 204 User.find(2).update_attribute(:auth_source_id, 1)
205 205
206 206 get :password
207 207 assert_not_nil flash[:error]
208 208 assert_redirected_to '/my/account'
209 209 end
210 210
211 211 def test_update_password_should_send_security_notification
212 212 ActionMailer::Base.deliveries.clear
213 213 post :password, :password => 'jsmith',
214 214 :new_password => 'secret123',
215 215 :new_password_confirmation => 'secret123'
216 216
217 217 assert_not_nil (mail = ActionMailer::Base.deliveries.last)
218 218 assert_mail_body_no_match 'secret123', mail # just to be sure: pw should never be sent!
219 219 assert_select_email do
220 220 assert_select 'a[href^=?]', 'http://localhost:3000/my/password', :text => 'Change password'
221 221 end
222 222 end
223 223
224 224 def test_page_layout
225 225 get :page_layout
226 226 assert_response :success
227 227 end
228 228
229 229 def test_add_block
230 230 post :add_block, :block => 'issuesreportedbyme'
231 231 assert_redirected_to '/my/page_layout'
232 232 assert User.find(2).pref[:my_page_layout]['top'].include?('issuesreportedbyme')
233 233 end
234 234
235 235 def test_add_invalid_block_should_redirect
236 236 post :add_block, :block => 'invalid'
237 237 assert_redirected_to '/my/page_layout'
238 238 end
239 239
240 240 def test_remove_block
241 241 post :remove_block, :block => 'issuesassignedtome'
242 242 assert_redirected_to '/my/page_layout'
243 243 assert !User.find(2).pref[:my_page_layout].values.flatten.include?('issuesassignedtome')
244 244 end
245 245
246 246 def test_order_blocks
247 247 xhr :post, :order_blocks, :group => 'left', 'blocks' => ['documents', 'calendar', 'latestnews']
248 248 assert_response :success
249 249 assert_equal ['documents', 'calendar', 'latestnews'], User.find(2).pref[:my_page_layout]['left']
250 250 end
251 251
252 252 def test_reset_rss_key_with_existing_key
253 253 @previous_token_value = User.find(2).rss_key # Will generate one if it's missing
254 254 post :reset_rss_key
255 255
256 256 assert_not_equal @previous_token_value, User.find(2).rss_key
257 257 assert User.find(2).rss_token
258 258 assert_match /reset/, flash[:notice]
259 259 assert_redirected_to '/my/account'
260 260 end
261 261
262 262 def test_reset_rss_key_without_existing_key
263 263 assert_nil User.find(2).rss_token
264 264 post :reset_rss_key
265 265
266 266 assert User.find(2).rss_token
267 267 assert_match /reset/, flash[:notice]
268 268 assert_redirected_to '/my/account'
269 269 end
270 270
271 271 def test_show_api_key
272 272 get :show_api_key
273 273 assert_response :success
274 274 assert_select 'pre', User.find(2).api_key
275 275 end
276 276
277 277 def test_reset_api_key_with_existing_key
278 278 @previous_token_value = User.find(2).api_key # Will generate one if it's missing
279 279 post :reset_api_key
280 280
281 281 assert_not_equal @previous_token_value, User.find(2).api_key
282 282 assert User.find(2).api_token
283 283 assert_match /reset/, flash[:notice]
284 284 assert_redirected_to '/my/account'
285 285 end
286 286
287 287 def test_reset_api_key_without_existing_key
288 288 assert_nil User.find(2).api_token
289 289 post :reset_api_key
290 290
291 291 assert User.find(2).api_token
292 292 assert_match /reset/, flash[:notice]
293 293 assert_redirected_to '/my/account'
294 294 end
295 295 end
General Comments 0
You need to be logged in to leave comments. Login now