##// END OF EJS Templates
Use POST/DELETE to watch/unwatch an item....
Jean-Philippe Lang -
r11113:deffd81ada71
parent child
Show More
@@ -1,83 +1,82
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2013 Jean-Philippe Lang
4 # Copyright (C) 2006-2013 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 module WatchersHelper
20 module WatchersHelper
21
21
22 def watcher_tag(object, user, options={})
22 def watcher_tag(object, user, options={})
23 ActiveSupport::Deprecation.warn "#watcher_tag is deprecated and will be removed in Redmine 3.0. Use #watcher_link instead."
23 ActiveSupport::Deprecation.warn "#watcher_tag is deprecated and will be removed in Redmine 3.0. Use #watcher_link instead."
24 watcher_link(object, user)
24 watcher_link(object, user)
25 end
25 end
26
26
27 def watcher_link(objects, user)
27 def watcher_link(objects, user)
28 return '' unless user && user.logged?
28 return '' unless user && user.logged?
29 objects = Array.wrap(objects)
29 objects = Array.wrap(objects)
30
30
31 watched = objects.any? {|object| object.watched_by?(user)}
31 watched = objects.any? {|object| object.watched_by?(user)}
32 css = [watcher_css(objects), watched ? 'icon icon-fav' : 'icon icon-fav-off'].join(' ')
32 css = [watcher_css(objects), watched ? 'icon icon-fav' : 'icon icon-fav-off'].join(' ')
33 text = watched ? l(:button_unwatch) : l(:button_watch)
33 text = watched ? l(:button_unwatch) : l(:button_watch)
34 url = {
34 url = watch_path(
35 :controller => 'watchers',
36 :action => (watched ? 'unwatch' : 'watch'),
37 :object_type => objects.first.class.to_s.underscore,
35 :object_type => objects.first.class.to_s.underscore,
38 :object_id => (objects.size == 1 ? objects.first.id : objects.map(&:id).sort)
36 :object_id => (objects.size == 1 ? objects.first.id : objects.map(&:id).sort)
39 }
37 )
38 method = watched ? 'delete' : 'post'
40
39
41 link_to text, url, :remote => true, :method => 'post', :class => css
40 link_to text, url, :remote => true, :method => method, :class => css
42 end
41 end
43
42
44 # Returns the css class used to identify watch links for a given +object+
43 # Returns the css class used to identify watch links for a given +object+
45 def watcher_css(objects)
44 def watcher_css(objects)
46 objects = Array.wrap(objects)
45 objects = Array.wrap(objects)
47 id = (objects.size == 1 ? objects.first.id : 'bulk')
46 id = (objects.size == 1 ? objects.first.id : 'bulk')
48 "#{objects.first.class.to_s.underscore}-#{id}-watcher"
47 "#{objects.first.class.to_s.underscore}-#{id}-watcher"
49 end
48 end
50
49
51 # Returns a comma separated list of users watching the given object
50 # Returns a comma separated list of users watching the given object
52 def watchers_list(object)
51 def watchers_list(object)
53 remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project)
52 remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project)
54 content = ''.html_safe
53 content = ''.html_safe
55 lis = object.watcher_users.collect do |user|
54 lis = object.watcher_users.collect do |user|
56 s = ''.html_safe
55 s = ''.html_safe
57 s << avatar(user, :size => "16").to_s
56 s << avatar(user, :size => "16").to_s
58 s << link_to_user(user, :class => 'user')
57 s << link_to_user(user, :class => 'user')
59 if remove_allowed
58 if remove_allowed
60 url = {:controller => 'watchers',
59 url = {:controller => 'watchers',
61 :action => 'destroy',
60 :action => 'destroy',
62 :object_type => object.class.to_s.underscore,
61 :object_type => object.class.to_s.underscore,
63 :object_id => object.id,
62 :object_id => object.id,
64 :user_id => user}
63 :user_id => user}
65 s << ' '
64 s << ' '
66 s << link_to(image_tag('delete.png'), url,
65 s << link_to(image_tag('delete.png'), url,
67 :remote => true, :method => 'post', :style => "vertical-align: middle", :class => "delete")
66 :remote => true, :method => 'post', :style => "vertical-align: middle", :class => "delete")
68 end
67 end
69 content << content_tag('li', s)
68 content << content_tag('li', s)
70 end
69 end
71 content.present? ? content_tag('ul', content) : content
70 content.present? ? content_tag('ul', content) : content
72 end
71 end
73
72
74 def watchers_checkboxes(object, users, checked=nil)
73 def watchers_checkboxes(object, users, checked=nil)
75 users.map do |user|
74 users.map do |user|
76 c = checked.nil? ? object.watched_by?(user) : checked
75 c = checked.nil? ? object.watched_by?(user) : checked
77 tag = check_box_tag 'issue[watcher_user_ids][]', user.id, c, :id => nil
76 tag = check_box_tag 'issue[watcher_user_ids][]', user.id, c, :id => nil
78 content_tag 'label', "#{tag} #{h(user)}".html_safe,
77 content_tag 'label', "#{tag} #{h(user)}".html_safe,
79 :id => "issue_watcher_user_ids_#{user.id}",
78 :id => "issue_watcher_user_ids_#{user.id}",
80 :class => "floating"
79 :class => "floating"
81 end.join.html_safe
80 end.join.html_safe
82 end
81 end
83 end
82 end
@@ -1,347 +1,347
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 RedmineApp::Application.routes.draw do
18 RedmineApp::Application.routes.draw do
19 root :to => 'welcome#index', :as => 'home'
19 root :to => 'welcome#index', :as => 'home'
20
20
21 match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post]
21 match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post]
22 match 'logout', :to => 'account#logout', :as => 'signout', :via => [:get, :post]
22 match 'logout', :to => 'account#logout', :as => 'signout', :via => [:get, :post]
23 match 'account/register', :to => 'account#register', :via => [:get, :post], :as => 'register'
23 match 'account/register', :to => 'account#register', :via => [:get, :post], :as => 'register'
24 match 'account/lost_password', :to => 'account#lost_password', :via => [:get, :post], :as => 'lost_password'
24 match 'account/lost_password', :to => 'account#lost_password', :via => [:get, :post], :as => 'lost_password'
25 match 'account/activate', :to => 'account#activate', :via => :get
25 match 'account/activate', :to => 'account#activate', :via => :get
26
26
27 match '/news/preview', :controller => 'previews', :action => 'news', :as => 'preview_news', :via => [:get, :post, :put]
27 match '/news/preview', :controller => 'previews', :action => 'news', :as => 'preview_news', :via => [:get, :post, :put]
28 match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue', :via => [:get, :post, :put]
28 match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue', :via => [:get, :post, :put]
29 match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue', :via => [:get, :post, :put]
29 match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue', :via => [:get, :post, :put]
30 match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue', :via => [:get, :post, :put]
30 match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue', :via => [:get, :post, :put]
31
31
32 match 'projects/:id/wiki', :to => 'wikis#edit', :via => :post
32 match 'projects/:id/wiki', :to => 'wikis#edit', :via => :post
33 match 'projects/:id/wiki/destroy', :to => 'wikis#destroy', :via => [:get, :post]
33 match 'projects/:id/wiki/destroy', :to => 'wikis#destroy', :via => [:get, :post]
34
34
35 match 'boards/:board_id/topics/new', :to => 'messages#new', :via => [:get, :post], :as => 'new_board_message'
35 match 'boards/:board_id/topics/new', :to => 'messages#new', :via => [:get, :post], :as => 'new_board_message'
36 get 'boards/:board_id/topics/:id', :to => 'messages#show', :as => 'board_message'
36 get 'boards/:board_id/topics/:id', :to => 'messages#show', :as => 'board_message'
37 match 'boards/:board_id/topics/quote/:id', :to => 'messages#quote', :via => [:get, :post]
37 match 'boards/:board_id/topics/quote/:id', :to => 'messages#quote', :via => [:get, :post]
38 get 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
38 get 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
39
39
40 post 'boards/:board_id/topics/preview', :to => 'messages#preview', :as => 'preview_board_message'
40 post 'boards/:board_id/topics/preview', :to => 'messages#preview', :as => 'preview_board_message'
41 post 'boards/:board_id/topics/:id/replies', :to => 'messages#reply'
41 post 'boards/:board_id/topics/:id/replies', :to => 'messages#reply'
42 post 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
42 post 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
43 post 'boards/:board_id/topics/:id/destroy', :to => 'messages#destroy'
43 post 'boards/:board_id/topics/:id/destroy', :to => 'messages#destroy'
44
44
45 # Misc issue routes. TODO: move into resources
45 # Misc issue routes. TODO: move into resources
46 match '/issues/auto_complete', :to => 'auto_completes#issues', :via => :get, :as => 'auto_complete_issues'
46 match '/issues/auto_complete', :to => 'auto_completes#issues', :via => :get, :as => 'auto_complete_issues'
47 match '/issues/context_menu', :to => 'context_menus#issues', :as => 'issues_context_menu', :via => [:get, :post]
47 match '/issues/context_menu', :to => 'context_menus#issues', :as => 'issues_context_menu', :via => [:get, :post]
48 match '/issues/changes', :to => 'journals#index', :as => 'issue_changes', :via => :get
48 match '/issues/changes', :to => 'journals#index', :as => 'issue_changes', :via => :get
49 match '/issues/:id/quoted', :to => 'journals#new', :id => /\d+/, :via => :post, :as => 'quoted_issue'
49 match '/issues/:id/quoted', :to => 'journals#new', :id => /\d+/, :via => :post, :as => 'quoted_issue'
50
50
51 match '/journals/diff/:id', :to => 'journals#diff', :id => /\d+/, :via => :get
51 match '/journals/diff/:id', :to => 'journals#diff', :id => /\d+/, :via => :get
52 match '/journals/edit/:id', :to => 'journals#edit', :id => /\d+/, :via => [:get, :post]
52 match '/journals/edit/:id', :to => 'journals#edit', :id => /\d+/, :via => [:get, :post]
53
53
54 get '/projects/:project_id/issues/gantt', :to => 'gantts#show', :as => 'project_gantt'
54 get '/projects/:project_id/issues/gantt', :to => 'gantts#show', :as => 'project_gantt'
55 get '/issues/gantt', :to => 'gantts#show'
55 get '/issues/gantt', :to => 'gantts#show'
56
56
57 get '/projects/:project_id/issues/calendar', :to => 'calendars#show', :as => 'project_calendar'
57 get '/projects/:project_id/issues/calendar', :to => 'calendars#show', :as => 'project_calendar'
58 get '/issues/calendar', :to => 'calendars#show'
58 get '/issues/calendar', :to => 'calendars#show'
59
59
60 get 'projects/:id/issues/report', :to => 'reports#issue_report', :as => 'project_issues_report'
60 get 'projects/:id/issues/report', :to => 'reports#issue_report', :as => 'project_issues_report'
61 get 'projects/:id/issues/report/:detail', :to => 'reports#issue_report_details', :as => 'project_issues_report_details'
61 get 'projects/:id/issues/report/:detail', :to => 'reports#issue_report_details', :as => 'project_issues_report_details'
62
62
63 match 'my/account', :controller => 'my', :action => 'account', :via => [:get, :post]
63 match 'my/account', :controller => 'my', :action => 'account', :via => [:get, :post]
64 match 'my/account/destroy', :controller => 'my', :action => 'destroy', :via => [:get, :post]
64 match 'my/account/destroy', :controller => 'my', :action => 'destroy', :via => [:get, :post]
65 match 'my/page', :controller => 'my', :action => 'page', :via => :get
65 match 'my/page', :controller => 'my', :action => 'page', :via => :get
66 match 'my', :controller => 'my', :action => 'index', :via => :get # Redirects to my/page
66 match 'my', :controller => 'my', :action => 'index', :via => :get # Redirects to my/page
67 match 'my/reset_rss_key', :controller => 'my', :action => 'reset_rss_key', :via => :post
67 match 'my/reset_rss_key', :controller => 'my', :action => 'reset_rss_key', :via => :post
68 match 'my/reset_api_key', :controller => 'my', :action => 'reset_api_key', :via => :post
68 match 'my/reset_api_key', :controller => 'my', :action => 'reset_api_key', :via => :post
69 match 'my/password', :controller => 'my', :action => 'password', :via => [:get, :post]
69 match 'my/password', :controller => 'my', :action => 'password', :via => [:get, :post]
70 match 'my/page_layout', :controller => 'my', :action => 'page_layout', :via => :get
70 match 'my/page_layout', :controller => 'my', :action => 'page_layout', :via => :get
71 match 'my/add_block', :controller => 'my', :action => 'add_block', :via => :post
71 match 'my/add_block', :controller => 'my', :action => 'add_block', :via => :post
72 match 'my/remove_block', :controller => 'my', :action => 'remove_block', :via => :post
72 match 'my/remove_block', :controller => 'my', :action => 'remove_block', :via => :post
73 match 'my/order_blocks', :controller => 'my', :action => 'order_blocks', :via => :post
73 match 'my/order_blocks', :controller => 'my', :action => 'order_blocks', :via => :post
74
74
75 resources :users
75 resources :users
76 match 'users/:id/memberships/:membership_id', :to => 'users#edit_membership', :via => :put, :as => 'user_membership'
76 match 'users/:id/memberships/:membership_id', :to => 'users#edit_membership', :via => :put, :as => 'user_membership'
77 match 'users/:id/memberships/:membership_id', :to => 'users#destroy_membership', :via => :delete
77 match 'users/:id/memberships/:membership_id', :to => 'users#destroy_membership', :via => :delete
78 match 'users/:id/memberships', :to => 'users#edit_membership', :via => :post, :as => 'user_memberships'
78 match 'users/:id/memberships', :to => 'users#edit_membership', :via => :post, :as => 'user_memberships'
79
79
80 post 'watchers/watch', :to => 'watchers#watch', :as => 'watch'
81 delete 'watchers/watch', :to => 'watchers#unwatch'
80 get 'watchers/new', :to => 'watchers#new'
82 get 'watchers/new', :to => 'watchers#new'
81 post 'watchers', :to => 'watchers#create'
83 post 'watchers', :to => 'watchers#create'
82 post 'watchers/append', :to => 'watchers#append'
84 post 'watchers/append', :to => 'watchers#append'
83 post 'watchers/destroy', :to => 'watchers#destroy'
85 post 'watchers/destroy', :to => 'watchers#destroy'
84 post 'watchers/watch', :to => 'watchers#watch'
85 post 'watchers/unwatch', :to => 'watchers#unwatch'
86 get 'watchers/autocomplete_for_user', :to => 'watchers#autocomplete_for_user'
86 get 'watchers/autocomplete_for_user', :to => 'watchers#autocomplete_for_user'
87 # Specific routes for issue watchers API
87 # Specific routes for issue watchers API
88 post 'issues/:object_id/watchers', :to => 'watchers#create', :object_type => 'issue'
88 post 'issues/:object_id/watchers', :to => 'watchers#create', :object_type => 'issue'
89 delete 'issues/:object_id/watchers/:user_id' => 'watchers#destroy', :object_type => 'issue'
89 delete 'issues/:object_id/watchers/:user_id' => 'watchers#destroy', :object_type => 'issue'
90
90
91 resources :projects do
91 resources :projects do
92 member do
92 member do
93 get 'settings(/:tab)', :action => 'settings', :as => 'settings'
93 get 'settings(/:tab)', :action => 'settings', :as => 'settings'
94 post 'modules'
94 post 'modules'
95 post 'archive'
95 post 'archive'
96 post 'unarchive'
96 post 'unarchive'
97 post 'close'
97 post 'close'
98 post 'reopen'
98 post 'reopen'
99 match 'copy', :via => [:get, :post]
99 match 'copy', :via => [:get, :post]
100 end
100 end
101
101
102 resources :memberships, :shallow => true, :controller => 'members', :only => [:index, :show, :new, :create, :update, :destroy] do
102 resources :memberships, :shallow => true, :controller => 'members', :only => [:index, :show, :new, :create, :update, :destroy] do
103 collection do
103 collection do
104 get 'autocomplete'
104 get 'autocomplete'
105 end
105 end
106 end
106 end
107
107
108 resource :enumerations, :controller => 'project_enumerations', :only => [:update, :destroy]
108 resource :enumerations, :controller => 'project_enumerations', :only => [:update, :destroy]
109
109
110 get 'issues/:copy_from/copy', :to => 'issues#new', :as => 'copy_issue'
110 get 'issues/:copy_from/copy', :to => 'issues#new', :as => 'copy_issue'
111 resources :issues, :only => [:index, :new, :create] do
111 resources :issues, :only => [:index, :new, :create] do
112 resources :time_entries, :controller => 'timelog' do
112 resources :time_entries, :controller => 'timelog' do
113 collection do
113 collection do
114 get 'report'
114 get 'report'
115 end
115 end
116 end
116 end
117 end
117 end
118 # issue form update
118 # issue form update
119 match 'issues/new', :controller => 'issues', :action => 'new', :via => [:put, :post], :as => 'issue_form'
119 match 'issues/new', :controller => 'issues', :action => 'new', :via => [:put, :post], :as => 'issue_form'
120
120
121 resources :files, :only => [:index, :new, :create]
121 resources :files, :only => [:index, :new, :create]
122
122
123 resources :versions, :except => [:index, :show, :edit, :update, :destroy] do
123 resources :versions, :except => [:index, :show, :edit, :update, :destroy] do
124 collection do
124 collection do
125 put 'close_completed'
125 put 'close_completed'
126 end
126 end
127 end
127 end
128 get 'versions.:format', :to => 'versions#index'
128 get 'versions.:format', :to => 'versions#index'
129 get 'roadmap', :to => 'versions#index', :format => false
129 get 'roadmap', :to => 'versions#index', :format => false
130 get 'versions', :to => 'versions#index'
130 get 'versions', :to => 'versions#index'
131
131
132 resources :news, :except => [:show, :edit, :update, :destroy]
132 resources :news, :except => [:show, :edit, :update, :destroy]
133 resources :time_entries, :controller => 'timelog' do
133 resources :time_entries, :controller => 'timelog' do
134 get 'report', :on => :collection
134 get 'report', :on => :collection
135 end
135 end
136 resources :queries, :only => [:new, :create]
136 resources :queries, :only => [:new, :create]
137 resources :issue_categories, :shallow => true
137 resources :issue_categories, :shallow => true
138 resources :documents, :except => [:show, :edit, :update, :destroy]
138 resources :documents, :except => [:show, :edit, :update, :destroy]
139 resources :boards
139 resources :boards
140 resources :repositories, :shallow => true, :except => [:index, :show] do
140 resources :repositories, :shallow => true, :except => [:index, :show] do
141 member do
141 member do
142 match 'committers', :via => [:get, :post]
142 match 'committers', :via => [:get, :post]
143 end
143 end
144 end
144 end
145
145
146 match 'wiki/index', :controller => 'wiki', :action => 'index', :via => :get
146 match 'wiki/index', :controller => 'wiki', :action => 'index', :via => :get
147 resources :wiki, :except => [:index, :new, :create], :as => 'wiki_page' do
147 resources :wiki, :except => [:index, :new, :create], :as => 'wiki_page' do
148 member do
148 member do
149 get 'rename'
149 get 'rename'
150 post 'rename'
150 post 'rename'
151 get 'history'
151 get 'history'
152 get 'diff'
152 get 'diff'
153 match 'preview', :via => [:post, :put]
153 match 'preview', :via => [:post, :put]
154 post 'protect'
154 post 'protect'
155 post 'add_attachment'
155 post 'add_attachment'
156 end
156 end
157 collection do
157 collection do
158 get 'export'
158 get 'export'
159 get 'date_index'
159 get 'date_index'
160 end
160 end
161 end
161 end
162 match 'wiki', :controller => 'wiki', :action => 'show', :via => :get
162 match 'wiki', :controller => 'wiki', :action => 'show', :via => :get
163 get 'wiki/:id/:version', :to => 'wiki#show', :constraints => {:version => /\d+/}
163 get 'wiki/:id/:version', :to => 'wiki#show', :constraints => {:version => /\d+/}
164 delete 'wiki/:id/:version', :to => 'wiki#destroy_version'
164 delete 'wiki/:id/:version', :to => 'wiki#destroy_version'
165 get 'wiki/:id/:version/annotate', :to => 'wiki#annotate'
165 get 'wiki/:id/:version/annotate', :to => 'wiki#annotate'
166 get 'wiki/:id/:version/diff', :to => 'wiki#diff'
166 get 'wiki/:id/:version/diff', :to => 'wiki#diff'
167 end
167 end
168
168
169 resources :issues do
169 resources :issues do
170 collection do
170 collection do
171 match 'bulk_edit', :via => [:get, :post]
171 match 'bulk_edit', :via => [:get, :post]
172 post 'bulk_update'
172 post 'bulk_update'
173 end
173 end
174 resources :time_entries, :controller => 'timelog' do
174 resources :time_entries, :controller => 'timelog' do
175 collection do
175 collection do
176 get 'report'
176 get 'report'
177 end
177 end
178 end
178 end
179 resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
179 resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
180 end
180 end
181 match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete
181 match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete
182
182
183 resources :queries, :except => [:show]
183 resources :queries, :except => [:show]
184
184
185 resources :news, :only => [:index, :show, :edit, :update, :destroy]
185 resources :news, :only => [:index, :show, :edit, :update, :destroy]
186 match '/news/:id/comments', :to => 'comments#create', :via => :post
186 match '/news/:id/comments', :to => 'comments#create', :via => :post
187 match '/news/:id/comments/:comment_id', :to => 'comments#destroy', :via => :delete
187 match '/news/:id/comments/:comment_id', :to => 'comments#destroy', :via => :delete
188
188
189 resources :versions, :only => [:show, :edit, :update, :destroy] do
189 resources :versions, :only => [:show, :edit, :update, :destroy] do
190 post 'status_by', :on => :member
190 post 'status_by', :on => :member
191 end
191 end
192
192
193 resources :documents, :only => [:show, :edit, :update, :destroy] do
193 resources :documents, :only => [:show, :edit, :update, :destroy] do
194 post 'add_attachment', :on => :member
194 post 'add_attachment', :on => :member
195 end
195 end
196
196
197 match '/time_entries/context_menu', :to => 'context_menus#time_entries', :as => :time_entries_context_menu, :via => [:get, :post]
197 match '/time_entries/context_menu', :to => 'context_menus#time_entries', :as => :time_entries_context_menu, :via => [:get, :post]
198
198
199 resources :time_entries, :controller => 'timelog', :except => :destroy do
199 resources :time_entries, :controller => 'timelog', :except => :destroy do
200 collection do
200 collection do
201 get 'report'
201 get 'report'
202 get 'bulk_edit'
202 get 'bulk_edit'
203 post 'bulk_update'
203 post 'bulk_update'
204 end
204 end
205 end
205 end
206 match '/time_entries/:id', :to => 'timelog#destroy', :via => :delete, :id => /\d+/
206 match '/time_entries/:id', :to => 'timelog#destroy', :via => :delete, :id => /\d+/
207 # TODO: delete /time_entries for bulk deletion
207 # TODO: delete /time_entries for bulk deletion
208 match '/time_entries/destroy', :to => 'timelog#destroy', :via => :delete
208 match '/time_entries/destroy', :to => 'timelog#destroy', :via => :delete
209
209
210 get 'projects/:id/activity', :to => 'activities#index'
210 get 'projects/:id/activity', :to => 'activities#index'
211 get 'projects/:id/activity.:format', :to => 'activities#index'
211 get 'projects/:id/activity.:format', :to => 'activities#index'
212 get 'activity', :to => 'activities#index'
212 get 'activity', :to => 'activities#index'
213
213
214 # repositories routes
214 # repositories routes
215 get 'projects/:id/repository/:repository_id/statistics', :to => 'repositories#stats'
215 get 'projects/:id/repository/:repository_id/statistics', :to => 'repositories#stats'
216 get 'projects/:id/repository/:repository_id/graph', :to => 'repositories#graph'
216 get 'projects/:id/repository/:repository_id/graph', :to => 'repositories#graph'
217
217
218 get 'projects/:id/repository/:repository_id/changes(/*path(.:ext))',
218 get 'projects/:id/repository/:repository_id/changes(/*path(.:ext))',
219 :to => 'repositories#changes'
219 :to => 'repositories#changes'
220
220
221 get 'projects/:id/repository/:repository_id/revisions/:rev', :to => 'repositories#revision'
221 get 'projects/:id/repository/:repository_id/revisions/:rev', :to => 'repositories#revision'
222 get 'projects/:id/repository/:repository_id/revision', :to => 'repositories#revision'
222 get 'projects/:id/repository/:repository_id/revision', :to => 'repositories#revision'
223 post 'projects/:id/repository/:repository_id/revisions/:rev/issues', :to => 'repositories#add_related_issue'
223 post 'projects/:id/repository/:repository_id/revisions/:rev/issues', :to => 'repositories#add_related_issue'
224 delete 'projects/:id/repository/:repository_id/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
224 delete 'projects/:id/repository/:repository_id/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
225 get 'projects/:id/repository/:repository_id/revisions', :to => 'repositories#revisions'
225 get 'projects/:id/repository/:repository_id/revisions', :to => 'repositories#revisions'
226 get 'projects/:id/repository/:repository_id/revisions/:rev/:action(/*path(.:ext))',
226 get 'projects/:id/repository/:repository_id/revisions/:rev/:action(/*path(.:ext))',
227 :controller => 'repositories',
227 :controller => 'repositories',
228 :format => false,
228 :format => false,
229 :constraints => {
229 :constraints => {
230 :action => /(browse|show|entry|raw|annotate|diff)/,
230 :action => /(browse|show|entry|raw|annotate|diff)/,
231 :rev => /[a-z0-9\.\-_]+/
231 :rev => /[a-z0-9\.\-_]+/
232 }
232 }
233
233
234 get 'projects/:id/repository/statistics', :to => 'repositories#stats'
234 get 'projects/:id/repository/statistics', :to => 'repositories#stats'
235 get 'projects/:id/repository/graph', :to => 'repositories#graph'
235 get 'projects/:id/repository/graph', :to => 'repositories#graph'
236
236
237 get 'projects/:id/repository/changes(/*path(.:ext))',
237 get 'projects/:id/repository/changes(/*path(.:ext))',
238 :to => 'repositories#changes'
238 :to => 'repositories#changes'
239
239
240 get 'projects/:id/repository/revisions', :to => 'repositories#revisions'
240 get 'projects/:id/repository/revisions', :to => 'repositories#revisions'
241 get 'projects/:id/repository/revisions/:rev', :to => 'repositories#revision'
241 get 'projects/:id/repository/revisions/:rev', :to => 'repositories#revision'
242 get 'projects/:id/repository/revision', :to => 'repositories#revision'
242 get 'projects/:id/repository/revision', :to => 'repositories#revision'
243 post 'projects/:id/repository/revisions/:rev/issues', :to => 'repositories#add_related_issue'
243 post 'projects/:id/repository/revisions/:rev/issues', :to => 'repositories#add_related_issue'
244 delete 'projects/:id/repository/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
244 delete 'projects/:id/repository/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
245 get 'projects/:id/repository/revisions/:rev/:action(/*path(.:ext))',
245 get 'projects/:id/repository/revisions/:rev/:action(/*path(.:ext))',
246 :controller => 'repositories',
246 :controller => 'repositories',
247 :format => false,
247 :format => false,
248 :constraints => {
248 :constraints => {
249 :action => /(browse|show|entry|raw|annotate|diff)/,
249 :action => /(browse|show|entry|raw|annotate|diff)/,
250 :rev => /[a-z0-9\.\-_]+/
250 :rev => /[a-z0-9\.\-_]+/
251 }
251 }
252 get 'projects/:id/repository/:repository_id/:action(/*path(.:ext))',
252 get 'projects/:id/repository/:repository_id/:action(/*path(.:ext))',
253 :controller => 'repositories',
253 :controller => 'repositories',
254 :action => /(browse|show|entry|raw|changes|annotate|diff)/
254 :action => /(browse|show|entry|raw|changes|annotate|diff)/
255 get 'projects/:id/repository/:action(/*path(.:ext))',
255 get 'projects/:id/repository/:action(/*path(.:ext))',
256 :controller => 'repositories',
256 :controller => 'repositories',
257 :action => /(browse|show|entry|raw|changes|annotate|diff)/
257 :action => /(browse|show|entry|raw|changes|annotate|diff)/
258
258
259 get 'projects/:id/repository/:repository_id', :to => 'repositories#show', :path => nil
259 get 'projects/:id/repository/:repository_id', :to => 'repositories#show', :path => nil
260 get 'projects/:id/repository', :to => 'repositories#show', :path => nil
260 get 'projects/:id/repository', :to => 'repositories#show', :path => nil
261
261
262 # additional routes for having the file name at the end of url
262 # additional routes for having the file name at the end of url
263 get 'attachments/:id/:filename', :to => 'attachments#show', :id => /\d+/, :filename => /.*/, :as => 'named_attachment'
263 get 'attachments/:id/:filename', :to => 'attachments#show', :id => /\d+/, :filename => /.*/, :as => 'named_attachment'
264 get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment'
264 get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment'
265 get 'attachments/download/:id', :to => 'attachments#download', :id => /\d+/
265 get 'attachments/download/:id', :to => 'attachments#download', :id => /\d+/
266 get 'attachments/thumbnail/:id(/:size)', :to => 'attachments#thumbnail', :id => /\d+/, :size => /\d+/, :as => 'thumbnail'
266 get 'attachments/thumbnail/:id(/:size)', :to => 'attachments#thumbnail', :id => /\d+/, :size => /\d+/, :as => 'thumbnail'
267 resources :attachments, :only => [:show, :destroy]
267 resources :attachments, :only => [:show, :destroy]
268
268
269 resources :groups do
269 resources :groups do
270 member do
270 member do
271 get 'autocomplete_for_user'
271 get 'autocomplete_for_user'
272 end
272 end
273 end
273 end
274
274
275 match 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :via => :post, :as => 'group_users'
275 match 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :via => :post, :as => 'group_users'
276 match 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :via => :delete, :as => 'group_user'
276 match 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :via => :delete, :as => 'group_user'
277 match 'groups/destroy_membership/:id', :controller => 'groups', :action => 'destroy_membership', :id => /\d+/, :via => :post
277 match 'groups/destroy_membership/:id', :controller => 'groups', :action => 'destroy_membership', :id => /\d+/, :via => :post
278 match 'groups/edit_membership/:id', :controller => 'groups', :action => 'edit_membership', :id => /\d+/, :via => :post
278 match 'groups/edit_membership/:id', :controller => 'groups', :action => 'edit_membership', :id => /\d+/, :via => :post
279
279
280 resources :trackers, :except => :show do
280 resources :trackers, :except => :show do
281 collection do
281 collection do
282 match 'fields', :via => [:get, :post]
282 match 'fields', :via => [:get, :post]
283 end
283 end
284 end
284 end
285 resources :issue_statuses, :except => :show do
285 resources :issue_statuses, :except => :show do
286 collection do
286 collection do
287 post 'update_issue_done_ratio'
287 post 'update_issue_done_ratio'
288 end
288 end
289 end
289 end
290 resources :custom_fields, :except => :show
290 resources :custom_fields, :except => :show
291 resources :roles do
291 resources :roles do
292 collection do
292 collection do
293 match 'permissions', :via => [:get, :post]
293 match 'permissions', :via => [:get, :post]
294 end
294 end
295 end
295 end
296 resources :enumerations, :except => :show
296 resources :enumerations, :except => :show
297 match 'enumerations/:type', :to => 'enumerations#index', :via => :get
297 match 'enumerations/:type', :to => 'enumerations#index', :via => :get
298
298
299 get 'projects/:id/search', :controller => 'search', :action => 'index'
299 get 'projects/:id/search', :controller => 'search', :action => 'index'
300 get 'search', :controller => 'search', :action => 'index'
300 get 'search', :controller => 'search', :action => 'index'
301
301
302 match 'mail_handler', :controller => 'mail_handler', :action => 'index', :via => :post
302 match 'mail_handler', :controller => 'mail_handler', :action => 'index', :via => :post
303
303
304 match 'admin', :controller => 'admin', :action => 'index', :via => :get
304 match 'admin', :controller => 'admin', :action => 'index', :via => :get
305 match 'admin/projects', :controller => 'admin', :action => 'projects', :via => :get
305 match 'admin/projects', :controller => 'admin', :action => 'projects', :via => :get
306 match 'admin/plugins', :controller => 'admin', :action => 'plugins', :via => :get
306 match 'admin/plugins', :controller => 'admin', :action => 'plugins', :via => :get
307 match 'admin/info', :controller => 'admin', :action => 'info', :via => :get
307 match 'admin/info', :controller => 'admin', :action => 'info', :via => :get
308 match 'admin/test_email', :controller => 'admin', :action => 'test_email', :via => :get
308 match 'admin/test_email', :controller => 'admin', :action => 'test_email', :via => :get
309 match 'admin/default_configuration', :controller => 'admin', :action => 'default_configuration', :via => :post
309 match 'admin/default_configuration', :controller => 'admin', :action => 'default_configuration', :via => :post
310
310
311 resources :auth_sources do
311 resources :auth_sources do
312 member do
312 member do
313 get 'test_connection', :as => 'try_connection'
313 get 'test_connection', :as => 'try_connection'
314 end
314 end
315 collection do
315 collection do
316 get 'autocomplete_for_new_user'
316 get 'autocomplete_for_new_user'
317 end
317 end
318 end
318 end
319
319
320 match 'workflows', :controller => 'workflows', :action => 'index', :via => :get
320 match 'workflows', :controller => 'workflows', :action => 'index', :via => :get
321 match 'workflows/edit', :controller => 'workflows', :action => 'edit', :via => [:get, :post]
321 match 'workflows/edit', :controller => 'workflows', :action => 'edit', :via => [:get, :post]
322 match 'workflows/permissions', :controller => 'workflows', :action => 'permissions', :via => [:get, :post]
322 match 'workflows/permissions', :controller => 'workflows', :action => 'permissions', :via => [:get, :post]
323 match 'workflows/copy', :controller => 'workflows', :action => 'copy', :via => [:get, :post]
323 match 'workflows/copy', :controller => 'workflows', :action => 'copy', :via => [:get, :post]
324 match 'settings', :controller => 'settings', :action => 'index', :via => :get
324 match 'settings', :controller => 'settings', :action => 'index', :via => :get
325 match 'settings/edit', :controller => 'settings', :action => 'edit', :via => [:get, :post]
325 match 'settings/edit', :controller => 'settings', :action => 'edit', :via => [:get, :post]
326 match 'settings/plugin/:id', :controller => 'settings', :action => 'plugin', :via => [:get, :post], :as => 'plugin_settings'
326 match 'settings/plugin/:id', :controller => 'settings', :action => 'plugin', :via => [:get, :post], :as => 'plugin_settings'
327
327
328 match 'sys/projects', :to => 'sys#projects', :via => :get
328 match 'sys/projects', :to => 'sys#projects', :via => :get
329 match 'sys/projects/:id/repository', :to => 'sys#create_project_repository', :via => :post
329 match 'sys/projects/:id/repository', :to => 'sys#create_project_repository', :via => :post
330 match 'sys/fetch_changesets', :to => 'sys#fetch_changesets', :via => :get
330 match 'sys/fetch_changesets', :to => 'sys#fetch_changesets', :via => :get
331
331
332 match 'uploads', :to => 'attachments#upload', :via => :post
332 match 'uploads', :to => 'attachments#upload', :via => :post
333
333
334 get 'robots.txt', :to => 'welcome#robots'
334 get 'robots.txt', :to => 'welcome#robots'
335
335
336 Dir.glob File.expand_path("plugins/*", Rails.root) do |plugin_dir|
336 Dir.glob File.expand_path("plugins/*", Rails.root) do |plugin_dir|
337 file = File.join(plugin_dir, "config/routes.rb")
337 file = File.join(plugin_dir, "config/routes.rb")
338 if File.exists?(file)
338 if File.exists?(file)
339 begin
339 begin
340 instance_eval File.read(file)
340 instance_eval File.read(file)
341 rescue Exception => e
341 rescue Exception => e
342 puts "An error occurred while loading the routes definition of #{File.basename(plugin_dir)} plugin (#{file}): #{e.message}."
342 puts "An error occurred while loading the routes definition of #{File.basename(plugin_dir)} plugin (#{file}): #{e.message}."
343 exit 1
343 exit 1
344 end
344 end
345 end
345 end
346 end
346 end
347 end
347 end
@@ -1,195 +1,195
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 WatchersControllerTest < ActionController::TestCase
20 class WatchersControllerTest < ActionController::TestCase
21 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules,
21 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules,
22 :issues, :trackers, :projects_trackers, :issue_statuses, :enumerations, :watchers
22 :issues, :trackers, :projects_trackers, :issue_statuses, :enumerations, :watchers
23
23
24 def setup
24 def setup
25 User.current = nil
25 User.current = nil
26 end
26 end
27
27
28 def test_watch_a_single_object
28 def test_watch_a_single_object
29 @request.session[:user_id] = 3
29 @request.session[:user_id] = 3
30 assert_difference('Watcher.count') do
30 assert_difference('Watcher.count') do
31 xhr :post, :watch, :object_type => 'issue', :object_id => '1'
31 xhr :post, :watch, :object_type => 'issue', :object_id => '1'
32 assert_response :success
32 assert_response :success
33 assert_include '$(".issue-1-watcher")', response.body
33 assert_include '$(".issue-1-watcher")', response.body
34 end
34 end
35 assert Issue.find(1).watched_by?(User.find(3))
35 assert Issue.find(1).watched_by?(User.find(3))
36 end
36 end
37
37
38 def test_watch_a_collection_with_a_single_object
38 def test_watch_a_collection_with_a_single_object
39 @request.session[:user_id] = 3
39 @request.session[:user_id] = 3
40 assert_difference('Watcher.count') do
40 assert_difference('Watcher.count') do
41 xhr :post, :watch, :object_type => 'issue', :object_id => ['1']
41 xhr :post, :watch, :object_type => 'issue', :object_id => ['1']
42 assert_response :success
42 assert_response :success
43 assert_include '$(".issue-1-watcher")', response.body
43 assert_include '$(".issue-1-watcher")', response.body
44 end
44 end
45 assert Issue.find(1).watched_by?(User.find(3))
45 assert Issue.find(1).watched_by?(User.find(3))
46 end
46 end
47
47
48 def test_watch_a_collection_with_multiple_objects
48 def test_watch_a_collection_with_multiple_objects
49 @request.session[:user_id] = 3
49 @request.session[:user_id] = 3
50 assert_difference('Watcher.count', 2) do
50 assert_difference('Watcher.count', 2) do
51 xhr :post, :watch, :object_type => 'issue', :object_id => ['1', '3']
51 xhr :post, :watch, :object_type => 'issue', :object_id => ['1', '3']
52 assert_response :success
52 assert_response :success
53 assert_include '$(".issue-bulk-watcher")', response.body
53 assert_include '$(".issue-bulk-watcher")', response.body
54 end
54 end
55 assert Issue.find(1).watched_by?(User.find(3))
55 assert Issue.find(1).watched_by?(User.find(3))
56 assert Issue.find(3).watched_by?(User.find(3))
56 assert Issue.find(3).watched_by?(User.find(3))
57 end
57 end
58
58
59 def test_watch_should_be_denied_without_permission
59 def test_watch_should_be_denied_without_permission
60 Role.find(2).remove_permission! :view_issues
60 Role.find(2).remove_permission! :view_issues
61 @request.session[:user_id] = 3
61 @request.session[:user_id] = 3
62 assert_no_difference('Watcher.count') do
62 assert_no_difference('Watcher.count') do
63 xhr :post, :watch, :object_type => 'issue', :object_id => '1'
63 xhr :post, :watch, :object_type => 'issue', :object_id => '1'
64 assert_response 403
64 assert_response 403
65 end
65 end
66 end
66 end
67
67
68 def test_watch_invalid_class_should_respond_with_404
68 def test_watch_invalid_class_should_respond_with_404
69 @request.session[:user_id] = 3
69 @request.session[:user_id] = 3
70 assert_no_difference('Watcher.count') do
70 assert_no_difference('Watcher.count') do
71 xhr :post, :watch, :object_type => 'foo', :object_id => '1'
71 xhr :post, :watch, :object_type => 'foo', :object_id => '1'
72 assert_response 404
72 assert_response 404
73 end
73 end
74 end
74 end
75
75
76 def test_watch_invalid_object_should_respond_with_404
76 def test_watch_invalid_object_should_respond_with_404
77 @request.session[:user_id] = 3
77 @request.session[:user_id] = 3
78 assert_no_difference('Watcher.count') do
78 assert_no_difference('Watcher.count') do
79 xhr :post, :watch, :object_type => 'issue', :object_id => '999'
79 xhr :post, :watch, :object_type => 'issue', :object_id => '999'
80 assert_response 404
80 assert_response 404
81 end
81 end
82 end
82 end
83
83
84 def test_unwatch
84 def test_unwatch
85 @request.session[:user_id] = 3
85 @request.session[:user_id] = 3
86 assert_difference('Watcher.count', -1) do
86 assert_difference('Watcher.count', -1) do
87 xhr :post, :unwatch, :object_type => 'issue', :object_id => '2'
87 xhr :delete, :unwatch, :object_type => 'issue', :object_id => '2'
88 assert_response :success
88 assert_response :success
89 assert_include '$(".issue-2-watcher")', response.body
89 assert_include '$(".issue-2-watcher")', response.body
90 end
90 end
91 assert !Issue.find(1).watched_by?(User.find(3))
91 assert !Issue.find(1).watched_by?(User.find(3))
92 end
92 end
93
93
94 def test_unwatch_a_collection_with_multiple_objects
94 def test_unwatch_a_collection_with_multiple_objects
95 @request.session[:user_id] = 3
95 @request.session[:user_id] = 3
96 Watcher.create!(:user_id => 3, :watchable => Issue.find(1))
96 Watcher.create!(:user_id => 3, :watchable => Issue.find(1))
97 Watcher.create!(:user_id => 3, :watchable => Issue.find(3))
97 Watcher.create!(:user_id => 3, :watchable => Issue.find(3))
98
98
99 assert_difference('Watcher.count', -2) do
99 assert_difference('Watcher.count', -2) do
100 xhr :post, :unwatch, :object_type => 'issue', :object_id => ['1', '3']
100 xhr :delete, :unwatch, :object_type => 'issue', :object_id => ['1', '3']
101 assert_response :success
101 assert_response :success
102 assert_include '$(".issue-bulk-watcher")', response.body
102 assert_include '$(".issue-bulk-watcher")', response.body
103 end
103 end
104 assert !Issue.find(1).watched_by?(User.find(3))
104 assert !Issue.find(1).watched_by?(User.find(3))
105 assert !Issue.find(3).watched_by?(User.find(3))
105 assert !Issue.find(3).watched_by?(User.find(3))
106 end
106 end
107
107
108 def test_new
108 def test_new
109 @request.session[:user_id] = 2
109 @request.session[:user_id] = 2
110 xhr :get, :new, :object_type => 'issue', :object_id => '2'
110 xhr :get, :new, :object_type => 'issue', :object_id => '2'
111 assert_response :success
111 assert_response :success
112 assert_match /ajax-modal/, response.body
112 assert_match /ajax-modal/, response.body
113 end
113 end
114
114
115 def test_new_for_new_record_with_project_id
115 def test_new_for_new_record_with_project_id
116 @request.session[:user_id] = 2
116 @request.session[:user_id] = 2
117 xhr :get, :new, :project_id => 1
117 xhr :get, :new, :project_id => 1
118 assert_response :success
118 assert_response :success
119 assert_equal Project.find(1), assigns(:project)
119 assert_equal Project.find(1), assigns(:project)
120 assert_match /ajax-modal/, response.body
120 assert_match /ajax-modal/, response.body
121 end
121 end
122
122
123 def test_new_for_new_record_with_project_identifier
123 def test_new_for_new_record_with_project_identifier
124 @request.session[:user_id] = 2
124 @request.session[:user_id] = 2
125 xhr :get, :new, :project_id => 'ecookbook'
125 xhr :get, :new, :project_id => 'ecookbook'
126 assert_response :success
126 assert_response :success
127 assert_equal Project.find(1), assigns(:project)
127 assert_equal Project.find(1), assigns(:project)
128 assert_match /ajax-modal/, response.body
128 assert_match /ajax-modal/, response.body
129 end
129 end
130
130
131 def test_create
131 def test_create
132 @request.session[:user_id] = 2
132 @request.session[:user_id] = 2
133 assert_difference('Watcher.count') do
133 assert_difference('Watcher.count') do
134 xhr :post, :create, :object_type => 'issue', :object_id => '2', :watcher => {:user_id => '4'}
134 xhr :post, :create, :object_type => 'issue', :object_id => '2', :watcher => {:user_id => '4'}
135 assert_response :success
135 assert_response :success
136 assert_match /watchers/, response.body
136 assert_match /watchers/, response.body
137 assert_match /ajax-modal/, response.body
137 assert_match /ajax-modal/, response.body
138 end
138 end
139 assert Issue.find(2).watched_by?(User.find(4))
139 assert Issue.find(2).watched_by?(User.find(4))
140 end
140 end
141
141
142 def test_create_multiple
142 def test_create_multiple
143 @request.session[:user_id] = 2
143 @request.session[:user_id] = 2
144 assert_difference('Watcher.count', 2) do
144 assert_difference('Watcher.count', 2) do
145 xhr :post, :create, :object_type => 'issue', :object_id => '2', :watcher => {:user_ids => ['4', '7']}
145 xhr :post, :create, :object_type => 'issue', :object_id => '2', :watcher => {:user_ids => ['4', '7']}
146 assert_response :success
146 assert_response :success
147 assert_match /watchers/, response.body
147 assert_match /watchers/, response.body
148 assert_match /ajax-modal/, response.body
148 assert_match /ajax-modal/, response.body
149 end
149 end
150 assert Issue.find(2).watched_by?(User.find(4))
150 assert Issue.find(2).watched_by?(User.find(4))
151 assert Issue.find(2).watched_by?(User.find(7))
151 assert Issue.find(2).watched_by?(User.find(7))
152 end
152 end
153
153
154 def test_autocomplete_on_watchable_creation
154 def test_autocomplete_on_watchable_creation
155 @request.session[:user_id] = 2
155 @request.session[:user_id] = 2
156 xhr :get, :autocomplete_for_user, :q => 'mi', :project_id => 'ecookbook'
156 xhr :get, :autocomplete_for_user, :q => 'mi', :project_id => 'ecookbook'
157 assert_response :success
157 assert_response :success
158 assert_select 'input', :count => 4
158 assert_select 'input', :count => 4
159 assert_select 'input[name=?][value=1]', 'watcher[user_ids][]'
159 assert_select 'input[name=?][value=1]', 'watcher[user_ids][]'
160 assert_select 'input[name=?][value=2]', 'watcher[user_ids][]'
160 assert_select 'input[name=?][value=2]', 'watcher[user_ids][]'
161 assert_select 'input[name=?][value=8]', 'watcher[user_ids][]'
161 assert_select 'input[name=?][value=8]', 'watcher[user_ids][]'
162 assert_select 'input[name=?][value=9]', 'watcher[user_ids][]'
162 assert_select 'input[name=?][value=9]', 'watcher[user_ids][]'
163 end
163 end
164
164
165 def test_autocomplete_on_watchable_update
165 def test_autocomplete_on_watchable_update
166 @request.session[:user_id] = 2
166 @request.session[:user_id] = 2
167 xhr :get, :autocomplete_for_user, :q => 'mi', :object_id => '2' , :object_type => 'issue', :project_id => 'ecookbook'
167 xhr :get, :autocomplete_for_user, :q => 'mi', :object_id => '2' , :object_type => 'issue', :project_id => 'ecookbook'
168 assert_response :success
168 assert_response :success
169 assert_select 'input', :count => 3
169 assert_select 'input', :count => 3
170 assert_select 'input[name=?][value=2]', 'watcher[user_ids][]'
170 assert_select 'input[name=?][value=2]', 'watcher[user_ids][]'
171 assert_select 'input[name=?][value=8]', 'watcher[user_ids][]'
171 assert_select 'input[name=?][value=8]', 'watcher[user_ids][]'
172 assert_select 'input[name=?][value=9]', 'watcher[user_ids][]'
172 assert_select 'input[name=?][value=9]', 'watcher[user_ids][]'
173
173
174 end
174 end
175
175
176 def test_append
176 def test_append
177 @request.session[:user_id] = 2
177 @request.session[:user_id] = 2
178 assert_no_difference 'Watcher.count' do
178 assert_no_difference 'Watcher.count' do
179 xhr :post, :append, :watcher => {:user_ids => ['4', '7']}, :project_id => 'ecookbook'
179 xhr :post, :append, :watcher => {:user_ids => ['4', '7']}, :project_id => 'ecookbook'
180 assert_response :success
180 assert_response :success
181 assert_include 'watchers_inputs', response.body
181 assert_include 'watchers_inputs', response.body
182 assert_include 'issue[watcher_user_ids][]', response.body
182 assert_include 'issue[watcher_user_ids][]', response.body
183 end
183 end
184 end
184 end
185
185
186 def test_remove_watcher
186 def test_remove_watcher
187 @request.session[:user_id] = 2
187 @request.session[:user_id] = 2
188 assert_difference('Watcher.count', -1) do
188 assert_difference('Watcher.count', -1) do
189 xhr :post, :destroy, :object_type => 'issue', :object_id => '2', :user_id => '3'
189 xhr :post, :destroy, :object_type => 'issue', :object_id => '2', :user_id => '3'
190 assert_response :success
190 assert_response :success
191 assert_match /watchers/, response.body
191 assert_match /watchers/, response.body
192 end
192 end
193 assert !Issue.find(2).watched_by?(User.find(3))
193 assert !Issue.find(2).watched_by?(User.find(3))
194 end
194 end
195 end
195 end
@@ -1,61 +1,61
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 RoutingWatchersTest < ActionController::IntegrationTest
20 class RoutingWatchersTest < ActionController::IntegrationTest
21 def test_watchers
21 def test_watchers
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/watchers/new" },
23 { :method => 'get', :path => "/watchers/new" },
24 { :controller => 'watchers', :action => 'new' }
24 { :controller => 'watchers', :action => 'new' }
25 )
25 )
26 assert_routing(
26 assert_routing(
27 { :method => 'post', :path => "/watchers/append" },
27 { :method => 'post', :path => "/watchers/append" },
28 { :controller => 'watchers', :action => 'append' }
28 { :controller => 'watchers', :action => 'append' }
29 )
29 )
30 assert_routing(
30 assert_routing(
31 { :method => 'post', :path => "/watchers" },
31 { :method => 'post', :path => "/watchers" },
32 { :controller => 'watchers', :action => 'create' }
32 { :controller => 'watchers', :action => 'create' }
33 )
33 )
34 assert_routing(
34 assert_routing(
35 { :method => 'post', :path => "/watchers/destroy" },
35 { :method => 'post', :path => "/watchers/destroy" },
36 { :controller => 'watchers', :action => 'destroy' }
36 { :controller => 'watchers', :action => 'destroy' }
37 )
37 )
38 assert_routing(
38 assert_routing(
39 { :method => 'get', :path => "/watchers/autocomplete_for_user" },
39 { :method => 'get', :path => "/watchers/autocomplete_for_user" },
40 { :controller => 'watchers', :action => 'autocomplete_for_user' }
40 { :controller => 'watchers', :action => 'autocomplete_for_user' }
41 )
41 )
42 assert_routing(
42 assert_routing(
43 { :method => 'post', :path => "/watchers/watch" },
43 { :method => 'post', :path => "/watchers/watch" },
44 { :controller => 'watchers', :action => 'watch' }
44 { :controller => 'watchers', :action => 'watch' }
45 )
45 )
46 assert_routing(
46 assert_routing(
47 { :method => 'post', :path => "/watchers/unwatch" },
47 { :method => 'delete', :path => "/watchers/watch" },
48 { :controller => 'watchers', :action => 'unwatch' }
48 { :controller => 'watchers', :action => 'unwatch' }
49 )
49 )
50 assert_routing(
50 assert_routing(
51 { :method => 'post', :path => "/issues/12/watchers.xml" },
51 { :method => 'post', :path => "/issues/12/watchers.xml" },
52 { :controller => 'watchers', :action => 'create',
52 { :controller => 'watchers', :action => 'create',
53 :object_type => 'issue', :object_id => '12', :format => 'xml' }
53 :object_type => 'issue', :object_id => '12', :format => 'xml' }
54 )
54 )
55 assert_routing(
55 assert_routing(
56 { :method => 'delete', :path => "/issues/12/watchers/3.xml" },
56 { :method => 'delete', :path => "/issues/12/watchers/3.xml" },
57 { :controller => 'watchers', :action => 'destroy',
57 { :controller => 'watchers', :action => 'destroy',
58 :object_type => 'issue', :object_id => '12', :user_id => '3', :format => 'xml'}
58 :object_type => 'issue', :object_id => '12', :user_id => '3', :format => 'xml'}
59 )
59 )
60 end
60 end
61 end
61 end
General Comments 0
You need to be logged in to leave comments. Login now