##// END OF EJS Templates
Makes enumerations available through the REST API....
Jean-Philippe Lang -
r10453:d62b90db7327
parent child
Show More
@@ -0,0 +1,9
1 api.array @klass.name.underscore.pluralize do
2 @enumerations.each do |enumeration|
3 api.__send__ @klass.name.underscore do
4 api.id enumeration.id
5 api.name enumeration.name
6 api.is_default enumeration.is_default
7 end
8 end
9 end
@@ -0,0 +1,44
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 require File.expand_path('../../../test_helper', __FILE__)
19
20 class ApiTest::EnumerationsTest < ActionController::IntegrationTest
21 fixtures :enumerations
22
23 def setup
24 Setting.rest_api_enabled = '1'
25 end
26
27 context "/enumerations/issue_priorities" do
28 context "GET" do
29
30 should "return priorities" do
31 get '/enumerations/issue_priorities.xml'
32
33 assert_response :success
34 assert_equal 'application/xml', response.content_type
35 assert_select 'issue_priorities[type=array]' do
36 assert_select 'issue_priority' do
37 assert_select 'id', :text => '6'
38 assert_select 'name', :text => 'High'
39 end
40 end
41 end
42 end
43 end
44 end
@@ -1,85 +1,98
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 EnumerationsController < ApplicationController
18 class EnumerationsController < ApplicationController
19 layout 'admin'
19 layout 'admin'
20
20
21 before_filter :require_admin
21 before_filter :require_admin, :except => :index
22 before_filter :require_admin_or_api_request, :only => :index
22 before_filter :build_new_enumeration, :only => [:new, :create]
23 before_filter :build_new_enumeration, :only => [:new, :create]
23 before_filter :find_enumeration, :only => [:edit, :update, :destroy]
24 before_filter :find_enumeration, :only => [:edit, :update, :destroy]
25 accept_api_auth :index
24
26
25 helper :custom_fields
27 helper :custom_fields
26
28
27 def index
29 def index
30 respond_to do |format|
31 format.html
32 format.api {
33 @klass = Enumeration.get_subclass(params[:type])
34 if @klass
35 @enumerations = @klass.shared.sorted.all
36 else
37 render_404
38 end
39 }
40 end
28 end
41 end
29
42
30 def new
43 def new
31 end
44 end
32
45
33 def create
46 def create
34 if request.post? && @enumeration.save
47 if request.post? && @enumeration.save
35 flash[:notice] = l(:notice_successful_create)
48 flash[:notice] = l(:notice_successful_create)
36 redirect_to :action => 'index', :type => @enumeration.type
49 redirect_to :action => 'index'
37 else
50 else
38 render :action => 'new'
51 render :action => 'new'
39 end
52 end
40 end
53 end
41
54
42 def edit
55 def edit
43 end
56 end
44
57
45 def update
58 def update
46 if request.put? && @enumeration.update_attributes(params[:enumeration])
59 if request.put? && @enumeration.update_attributes(params[:enumeration])
47 flash[:notice] = l(:notice_successful_update)
60 flash[:notice] = l(:notice_successful_update)
48 redirect_to :action => 'index', :type => @enumeration.type
61 redirect_to :action => 'index'
49 else
62 else
50 render :action => 'edit'
63 render :action => 'edit'
51 end
64 end
52 end
65 end
53
66
54 def destroy
67 def destroy
55 if !@enumeration.in_use?
68 if !@enumeration.in_use?
56 # No associated objects
69 # No associated objects
57 @enumeration.destroy
70 @enumeration.destroy
58 redirect_to :action => 'index'
71 redirect_to :action => 'index'
59 return
72 return
60 elsif params[:reassign_to_id]
73 elsif params[:reassign_to_id]
61 if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id])
74 if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id])
62 @enumeration.destroy(reassign_to)
75 @enumeration.destroy(reassign_to)
63 redirect_to :action => 'index'
76 redirect_to :action => 'index'
64 return
77 return
65 end
78 end
66 end
79 end
67 @enumerations = @enumeration.class.all - [@enumeration]
80 @enumerations = @enumeration.class.all - [@enumeration]
68 end
81 end
69
82
70 private
83 private
71
84
72 def build_new_enumeration
85 def build_new_enumeration
73 class_name = params[:enumeration] && params[:enumeration][:type] || params[:type]
86 class_name = params[:enumeration] && params[:enumeration][:type] || params[:type]
74 @enumeration = Enumeration.new_subclass_instance(class_name, params[:enumeration])
87 @enumeration = Enumeration.new_subclass_instance(class_name, params[:enumeration])
75 if @enumeration.nil?
88 if @enumeration.nil?
76 render_404
89 render_404
77 end
90 end
78 end
91 end
79
92
80 def find_enumeration
93 def find_enumeration
81 @enumeration = Enumeration.find(params[:id])
94 @enumeration = Enumeration.find(params[:id])
82 rescue ActiveRecord::RecordNotFound
95 rescue ActiveRecord::RecordNotFound
83 render_404
96 render_404
84 end
97 end
85 end
98 end
@@ -1,140 +1,141
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 Enumeration < ActiveRecord::Base
18 class Enumeration < ActiveRecord::Base
19 include Redmine::SubclassFactory
19 include Redmine::SubclassFactory
20
20
21 default_scope :order => "#{Enumeration.table_name}.position ASC"
21 default_scope :order => "#{Enumeration.table_name}.position ASC"
22
22
23 belongs_to :project
23 belongs_to :project
24
24
25 acts_as_list :scope => 'type = \'#{type}\''
25 acts_as_list :scope => 'type = \'#{type}\''
26 acts_as_customizable
26 acts_as_customizable
27 acts_as_tree :order => 'position ASC'
27 acts_as_tree :order => 'position ASC'
28
28
29 before_destroy :check_integrity
29 before_destroy :check_integrity
30 before_save :check_default
30 before_save :check_default
31
31
32 attr_protected :type
32 attr_protected :type
33
33
34 validates_presence_of :name
34 validates_presence_of :name
35 validates_uniqueness_of :name, :scope => [:type, :project_id]
35 validates_uniqueness_of :name, :scope => [:type, :project_id]
36 validates_length_of :name, :maximum => 30
36 validates_length_of :name, :maximum => 30
37
37
38 scope :shared, where(:project_id => nil)
38 scope :shared, where(:project_id => nil)
39 scope :sorted, order("#{table_name}.position ASC")
39 scope :active, where(:active => true)
40 scope :active, where(:active => true)
40 scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
41 scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
41
42
42 def self.default
43 def self.default
43 # Creates a fake default scope so Enumeration.default will check
44 # Creates a fake default scope so Enumeration.default will check
44 # it's type. STI subclasses will automatically add their own
45 # it's type. STI subclasses will automatically add their own
45 # types to the finder.
46 # types to the finder.
46 if self.descends_from_active_record?
47 if self.descends_from_active_record?
47 where(:is_default => true, :type => 'Enumeration').first
48 where(:is_default => true, :type => 'Enumeration').first
48 else
49 else
49 # STI classes are
50 # STI classes are
50 where(:is_default => true).first
51 where(:is_default => true).first
51 end
52 end
52 end
53 end
53
54
54 # Overloaded on concrete classes
55 # Overloaded on concrete classes
55 def option_name
56 def option_name
56 nil
57 nil
57 end
58 end
58
59
59 def check_default
60 def check_default
60 if is_default? && is_default_changed?
61 if is_default? && is_default_changed?
61 Enumeration.update_all({:is_default => false}, {:type => type})
62 Enumeration.update_all({:is_default => false}, {:type => type})
62 end
63 end
63 end
64 end
64
65
65 # Overloaded on concrete classes
66 # Overloaded on concrete classes
66 def objects_count
67 def objects_count
67 0
68 0
68 end
69 end
69
70
70 def in_use?
71 def in_use?
71 self.objects_count != 0
72 self.objects_count != 0
72 end
73 end
73
74
74 # Is this enumeration overiding a system level enumeration?
75 # Is this enumeration overiding a system level enumeration?
75 def is_override?
76 def is_override?
76 !self.parent.nil?
77 !self.parent.nil?
77 end
78 end
78
79
79 alias :destroy_without_reassign :destroy
80 alias :destroy_without_reassign :destroy
80
81
81 # Destroy the enumeration
82 # Destroy the enumeration
82 # If a enumeration is specified, objects are reassigned
83 # If a enumeration is specified, objects are reassigned
83 def destroy(reassign_to = nil)
84 def destroy(reassign_to = nil)
84 if reassign_to && reassign_to.is_a?(Enumeration)
85 if reassign_to && reassign_to.is_a?(Enumeration)
85 self.transfer_relations(reassign_to)
86 self.transfer_relations(reassign_to)
86 end
87 end
87 destroy_without_reassign
88 destroy_without_reassign
88 end
89 end
89
90
90 def <=>(enumeration)
91 def <=>(enumeration)
91 position <=> enumeration.position
92 position <=> enumeration.position
92 end
93 end
93
94
94 def to_s; name end
95 def to_s; name end
95
96
96 # Returns the Subclasses of Enumeration. Each Subclass needs to be
97 # Returns the Subclasses of Enumeration. Each Subclass needs to be
97 # required in development mode.
98 # required in development mode.
98 #
99 #
99 # Note: subclasses is protected in ActiveRecord
100 # Note: subclasses is protected in ActiveRecord
100 def self.get_subclasses
101 def self.get_subclasses
101 subclasses
102 subclasses
102 end
103 end
103
104
104 # Does the +new+ Hash override the previous Enumeration?
105 # Does the +new+ Hash override the previous Enumeration?
105 def self.overridding_change?(new, previous)
106 def self.overridding_change?(new, previous)
106 if (same_active_state?(new['active'], previous.active)) && same_custom_values?(new,previous)
107 if (same_active_state?(new['active'], previous.active)) && same_custom_values?(new,previous)
107 return false
108 return false
108 else
109 else
109 return true
110 return true
110 end
111 end
111 end
112 end
112
113
113 # Does the +new+ Hash have the same custom values as the previous Enumeration?
114 # Does the +new+ Hash have the same custom values as the previous Enumeration?
114 def self.same_custom_values?(new, previous)
115 def self.same_custom_values?(new, previous)
115 previous.custom_field_values.each do |custom_value|
116 previous.custom_field_values.each do |custom_value|
116 if custom_value.value != new["custom_field_values"][custom_value.custom_field_id.to_s]
117 if custom_value.value != new["custom_field_values"][custom_value.custom_field_id.to_s]
117 return false
118 return false
118 end
119 end
119 end
120 end
120
121
121 return true
122 return true
122 end
123 end
123
124
124 # Are the new and previous fields equal?
125 # Are the new and previous fields equal?
125 def self.same_active_state?(new, previous)
126 def self.same_active_state?(new, previous)
126 new = (new == "1" ? true : false)
127 new = (new == "1" ? true : false)
127 return new == previous
128 return new == previous
128 end
129 end
129
130
130 private
131 private
131 def check_integrity
132 def check_integrity
132 raise "Can't delete enumeration" if self.in_use?
133 raise "Can't delete enumeration" if self.in_use?
133 end
134 end
134
135
135 end
136 end
136
137
137 # Force load the subclasses in development mode
138 # Force load the subclasses in development mode
138 require_dependency 'time_entry_activity'
139 require_dependency 'time_entry_activity'
139 require_dependency 'document_category'
140 require_dependency 'document_category'
140 require_dependency 'issue_priority'
141 require_dependency 'issue_priority'
@@ -1,344 +1,345
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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'
21 match 'login', :to => 'account#login', :as => 'signin'
22 match 'logout', :to => 'account#logout', :as => 'signout'
22 match 'logout', :to => 'account#logout', :as => 'signout'
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'
27 match '/news/preview', :controller => 'previews', :action => 'news', :as => 'preview_news'
28 match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue'
28 match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue'
29 match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue'
29 match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue'
30 match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue'
30 match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue'
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]
35 match 'boards/:board_id/topics/new', :to => 'messages#new', :via => [:get, :post]
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'
40 post 'boards/:board_id/topics/preview', :to => 'messages#preview'
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'
47 match '/issues/context_menu', :to => 'context_menus#issues', :as => 'issues_context_menu'
48 match '/issues/changes', :to => 'journals#index', :as => 'issue_changes'
48 match '/issues/changes', :to => 'journals#index', :as => 'issue_changes'
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 match '/projects/:project_id/issues/gantt', :to => 'gantts#show'
54 match '/projects/:project_id/issues/gantt', :to => 'gantts#show'
55 match '/issues/gantt', :to => 'gantts#show'
55 match '/issues/gantt', :to => 'gantts#show'
56
56
57 match '/projects/:project_id/issues/calendar', :to => 'calendars#show'
57 match '/projects/:project_id/issues/calendar', :to => 'calendars#show'
58 match '/issues/calendar', :to => 'calendars#show'
58 match '/issues/calendar', :to => 'calendars#show'
59
59
60 match 'projects/:id/issues/report', :to => 'reports#issue_report', :via => :get
60 match 'projects/:id/issues/report', :to => 'reports#issue_report', :via => :get
61 match 'projects/:id/issues/report/:detail', :to => 'reports#issue_report_details', :via => :get
61 match 'projects/:id/issues/report/:detail', :to => 'reports#issue_report_details', :via => :get
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 match 'watchers/new', :controller=> 'watchers', :action => 'new', :via => :get
80 match 'watchers/new', :controller=> 'watchers', :action => 'new', :via => :get
81 match 'watchers', :controller=> 'watchers', :action => 'create', :via => :post
81 match 'watchers', :controller=> 'watchers', :action => 'create', :via => :post
82 match 'watchers/append', :controller=> 'watchers', :action => 'append', :via => :post
82 match 'watchers/append', :controller=> 'watchers', :action => 'append', :via => :post
83 match 'watchers/destroy', :controller=> 'watchers', :action => 'destroy', :via => :post
83 match 'watchers/destroy', :controller=> 'watchers', :action => 'destroy', :via => :post
84 match 'watchers/watch', :controller=> 'watchers', :action => 'watch', :via => :post
84 match 'watchers/watch', :controller=> 'watchers', :action => 'watch', :via => :post
85 match 'watchers/unwatch', :controller=> 'watchers', :action => 'unwatch', :via => :post
85 match 'watchers/unwatch', :controller=> 'watchers', :action => 'unwatch', :via => :post
86 match 'watchers/autocomplete_for_user', :controller=> 'watchers', :action => 'autocomplete_for_user', :via => :get
86 match 'watchers/autocomplete_for_user', :controller=> 'watchers', :action => 'autocomplete_for_user', :via => :get
87
87
88 match 'projects/:id/settings/:tab', :to => "projects#settings"
88 match 'projects/:id/settings/:tab', :to => "projects#settings"
89
89
90 resources :projects do
90 resources :projects do
91 member do
91 member do
92 get 'settings'
92 get 'settings'
93 post 'modules'
93 post 'modules'
94 post 'archive'
94 post 'archive'
95 post 'unarchive'
95 post 'unarchive'
96 post 'close'
96 post 'close'
97 post 'reopen'
97 post 'reopen'
98 match 'copy', :via => [:get, :post]
98 match 'copy', :via => [:get, :post]
99 end
99 end
100
100
101 resources :memberships, :shallow => true, :controller => 'members', :only => [:index, :show, :create, :update, :destroy] do
101 resources :memberships, :shallow => true, :controller => 'members', :only => [:index, :show, :new, :create, :update, :destroy] do
102 collection do
102 collection do
103 get 'autocomplete'
103 get 'autocomplete'
104 end
104 end
105 end
105 end
106
106
107 resource :enumerations, :controller => 'project_enumerations', :only => [:update, :destroy]
107 resource :enumerations, :controller => 'project_enumerations', :only => [:update, :destroy]
108
108
109 match 'issues/:copy_from/copy', :to => 'issues#new'
109 match 'issues/:copy_from/copy', :to => 'issues#new'
110 resources :issues, :only => [:index, :new, :create] do
110 resources :issues, :only => [:index, :new, :create] do
111 resources :time_entries, :controller => 'timelog' do
111 resources :time_entries, :controller => 'timelog' do
112 collection do
112 collection do
113 get 'report'
113 get 'report'
114 end
114 end
115 end
115 end
116 end
116 end
117 # issue form update
117 # issue form update
118 match 'issues/new', :controller => 'issues', :action => 'new', :via => [:put, :post], :as => 'issue_form'
118 match 'issues/new', :controller => 'issues', :action => 'new', :via => [:put, :post], :as => 'issue_form'
119
119
120 resources :files, :only => [:index, :new, :create]
120 resources :files, :only => [:index, :new, :create]
121
121
122 resources :versions, :except => [:index, :show, :edit, :update, :destroy] do
122 resources :versions, :except => [:index, :show, :edit, :update, :destroy] do
123 collection do
123 collection do
124 put 'close_completed'
124 put 'close_completed'
125 end
125 end
126 end
126 end
127 match 'versions.:format', :to => 'versions#index'
127 match 'versions.:format', :to => 'versions#index'
128 match 'roadmap', :to => 'versions#index', :format => false
128 match 'roadmap', :to => 'versions#index', :format => false
129 match 'versions', :to => 'versions#index'
129 match 'versions', :to => 'versions#index'
130
130
131 resources :news, :except => [:show, :edit, :update, :destroy]
131 resources :news, :except => [:show, :edit, :update, :destroy]
132 resources :time_entries, :controller => 'timelog' do
132 resources :time_entries, :controller => 'timelog' do
133 get 'report', :on => :collection
133 get 'report', :on => :collection
134 end
134 end
135 resources :queries, :only => [:new, :create]
135 resources :queries, :only => [:new, :create]
136 resources :issue_categories, :shallow => true
136 resources :issue_categories, :shallow => true
137 resources :documents, :except => [:show, :edit, :update, :destroy]
137 resources :documents, :except => [:show, :edit, :update, :destroy]
138 resources :boards
138 resources :boards
139 resources :repositories, :shallow => true, :except => [:index, :show] do
139 resources :repositories, :shallow => true, :except => [:index, :show] do
140 member do
140 member do
141 match 'committers', :via => [:get, :post]
141 match 'committers', :via => [:get, :post]
142 end
142 end
143 end
143 end
144
144
145 match 'wiki/index', :controller => 'wiki', :action => 'index', :via => :get
145 match 'wiki/index', :controller => 'wiki', :action => 'index', :via => :get
146 match 'wiki/:id/diff/:version/vs/:version_from', :controller => 'wiki', :action => 'diff'
146 match 'wiki/:id/diff/:version/vs/:version_from', :controller => 'wiki', :action => 'diff'
147 match 'wiki/:id/diff/:version', :controller => 'wiki', :action => 'diff'
147 match 'wiki/:id/diff/:version', :controller => 'wiki', :action => 'diff'
148 resources :wiki, :except => [:index, :new, :create] do
148 resources :wiki, :except => [:index, :new, :create] do
149 member do
149 member do
150 get 'rename'
150 get 'rename'
151 post 'rename'
151 post 'rename'
152 get 'history'
152 get 'history'
153 get 'diff'
153 get 'diff'
154 match 'preview', :via => [:post, :put]
154 match 'preview', :via => [:post, :put]
155 post 'protect'
155 post 'protect'
156 post 'add_attachment'
156 post 'add_attachment'
157 end
157 end
158 collection do
158 collection do
159 get 'export'
159 get 'export'
160 get 'date_index'
160 get 'date_index'
161 end
161 end
162 end
162 end
163 match 'wiki', :controller => 'wiki', :action => 'show', :via => :get
163 match 'wiki', :controller => 'wiki', :action => 'show', :via => :get
164 match 'wiki/:id/annotate/:version', :controller => 'wiki', :action => 'annotate'
164 match 'wiki/:id/annotate/:version', :controller => 'wiki', :action => 'annotate'
165 end
165 end
166
166
167 resources :issues do
167 resources :issues do
168 collection do
168 collection do
169 match 'bulk_edit', :via => [:get, :post]
169 match 'bulk_edit', :via => [:get, :post]
170 post 'bulk_update'
170 post 'bulk_update'
171 end
171 end
172 resources :time_entries, :controller => 'timelog' do
172 resources :time_entries, :controller => 'timelog' do
173 collection do
173 collection do
174 get 'report'
174 get 'report'
175 end
175 end
176 end
176 end
177 resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
177 resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
178 end
178 end
179 match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete
179 match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete
180
180
181 resources :queries, :except => [:show]
181 resources :queries, :except => [:show]
182
182
183 resources :news, :only => [:index, :show, :edit, :update, :destroy]
183 resources :news, :only => [:index, :show, :edit, :update, :destroy]
184 match '/news/:id/comments', :to => 'comments#create', :via => :post
184 match '/news/:id/comments', :to => 'comments#create', :via => :post
185 match '/news/:id/comments/:comment_id', :to => 'comments#destroy', :via => :delete
185 match '/news/:id/comments/:comment_id', :to => 'comments#destroy', :via => :delete
186
186
187 resources :versions, :only => [:show, :edit, :update, :destroy] do
187 resources :versions, :only => [:show, :edit, :update, :destroy] do
188 post 'status_by', :on => :member
188 post 'status_by', :on => :member
189 end
189 end
190
190
191 resources :documents, :only => [:show, :edit, :update, :destroy] do
191 resources :documents, :only => [:show, :edit, :update, :destroy] do
192 post 'add_attachment', :on => :member
192 post 'add_attachment', :on => :member
193 end
193 end
194
194
195 match '/time_entries/context_menu', :to => 'context_menus#time_entries', :as => :time_entries_context_menu
195 match '/time_entries/context_menu', :to => 'context_menus#time_entries', :as => :time_entries_context_menu
196
196
197 resources :time_entries, :controller => 'timelog', :except => :destroy do
197 resources :time_entries, :controller => 'timelog', :except => :destroy do
198 collection do
198 collection do
199 get 'report'
199 get 'report'
200 get 'bulk_edit'
200 get 'bulk_edit'
201 post 'bulk_update'
201 post 'bulk_update'
202 end
202 end
203 end
203 end
204 match '/time_entries/:id', :to => 'timelog#destroy', :via => :delete, :id => /\d+/
204 match '/time_entries/:id', :to => 'timelog#destroy', :via => :delete, :id => /\d+/
205 # TODO: delete /time_entries for bulk deletion
205 # TODO: delete /time_entries for bulk deletion
206 match '/time_entries/destroy', :to => 'timelog#destroy', :via => :delete
206 match '/time_entries/destroy', :to => 'timelog#destroy', :via => :delete
207
207
208 # TODO: port to be part of the resources route(s)
208 # TODO: port to be part of the resources route(s)
209 match 'projects/:id/settings/:tab', :to => 'projects#settings', :via => :get
209 match 'projects/:id/settings/:tab', :to => 'projects#settings', :via => :get
210
210
211 get 'projects/:id/activity', :to => 'activities#index'
211 get 'projects/:id/activity', :to => 'activities#index'
212 get 'projects/:id/activity.:format', :to => 'activities#index'
212 get 'projects/:id/activity.:format', :to => 'activities#index'
213 get 'activity', :to => 'activities#index'
213 get 'activity', :to => 'activities#index'
214
214
215 # repositories routes
215 # repositories routes
216 get 'projects/:id/repository/:repository_id/statistics', :to => 'repositories#stats'
216 get 'projects/:id/repository/:repository_id/statistics', :to => 'repositories#stats'
217 get 'projects/:id/repository/:repository_id/graph', :to => 'repositories#graph'
217 get 'projects/:id/repository/:repository_id/graph', :to => 'repositories#graph'
218
218
219 get 'projects/:id/repository/:repository_id/changes(/*path(.:ext))',
219 get 'projects/:id/repository/:repository_id/changes(/*path(.:ext))',
220 :to => 'repositories#changes'
220 :to => 'repositories#changes'
221
221
222 get 'projects/:id/repository/:repository_id/revisions/:rev', :to => 'repositories#revision'
222 get 'projects/:id/repository/:repository_id/revisions/:rev', :to => 'repositories#revision'
223 get 'projects/:id/repository/:repository_id/revision', :to => 'repositories#revision'
223 get 'projects/:id/repository/:repository_id/revision', :to => 'repositories#revision'
224 post 'projects/:id/repository/:repository_id/revisions/:rev/issues', :to => 'repositories#add_related_issue'
224 post 'projects/:id/repository/:repository_id/revisions/:rev/issues', :to => 'repositories#add_related_issue'
225 delete 'projects/:id/repository/:repository_id/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
225 delete 'projects/:id/repository/:repository_id/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
226 get 'projects/:id/repository/:repository_id/revisions', :to => 'repositories#revisions'
226 get 'projects/:id/repository/:repository_id/revisions', :to => 'repositories#revisions'
227 get 'projects/:id/repository/:repository_id/revisions/:rev/:action(/*path(.:ext))',
227 get 'projects/:id/repository/:repository_id/revisions/:rev/:action(/*path(.:ext))',
228 :controller => 'repositories',
228 :controller => 'repositories',
229 :format => false,
229 :format => false,
230 :constraints => {
230 :constraints => {
231 :action => /(browse|show|entry|raw|annotate|diff)/,
231 :action => /(browse|show|entry|raw|annotate|diff)/,
232 :rev => /[a-z0-9\.\-_]+/
232 :rev => /[a-z0-9\.\-_]+/
233 }
233 }
234
234
235 get 'projects/:id/repository/statistics', :to => 'repositories#stats'
235 get 'projects/:id/repository/statistics', :to => 'repositories#stats'
236 get 'projects/:id/repository/graph', :to => 'repositories#graph'
236 get 'projects/:id/repository/graph', :to => 'repositories#graph'
237
237
238 get 'projects/:id/repository/changes(/*path(.:ext))',
238 get 'projects/:id/repository/changes(/*path(.:ext))',
239 :to => 'repositories#changes'
239 :to => 'repositories#changes'
240
240
241 get 'projects/:id/repository/revisions', :to => 'repositories#revisions'
241 get 'projects/:id/repository/revisions', :to => 'repositories#revisions'
242 get 'projects/:id/repository/revisions/:rev', :to => 'repositories#revision'
242 get 'projects/:id/repository/revisions/:rev', :to => 'repositories#revision'
243 get 'projects/:id/repository/revision', :to => 'repositories#revision'
243 get 'projects/:id/repository/revision', :to => 'repositories#revision'
244 post 'projects/:id/repository/revisions/:rev/issues', :to => 'repositories#add_related_issue'
244 post 'projects/:id/repository/revisions/:rev/issues', :to => 'repositories#add_related_issue'
245 delete 'projects/:id/repository/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
245 delete 'projects/:id/repository/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
246 get 'projects/:id/repository/revisions/:rev/:action(/*path(.:ext))',
246 get 'projects/:id/repository/revisions/:rev/:action(/*path(.:ext))',
247 :controller => 'repositories',
247 :controller => 'repositories',
248 :format => false,
248 :format => false,
249 :constraints => {
249 :constraints => {
250 :action => /(browse|show|entry|raw|annotate|diff)/,
250 :action => /(browse|show|entry|raw|annotate|diff)/,
251 :rev => /[a-z0-9\.\-_]+/
251 :rev => /[a-z0-9\.\-_]+/
252 }
252 }
253 get 'projects/:id/repository/:repository_id/:action(/*path(.:ext))',
253 get 'projects/:id/repository/:repository_id/:action(/*path(.:ext))',
254 :controller => 'repositories',
254 :controller => 'repositories',
255 :action => /(browse|show|entry|raw|changes|annotate|diff)/
255 :action => /(browse|show|entry|raw|changes|annotate|diff)/
256 get 'projects/:id/repository/:action(/*path(.:ext))',
256 get 'projects/:id/repository/:action(/*path(.:ext))',
257 :controller => 'repositories',
257 :controller => 'repositories',
258 :action => /(browse|show|entry|raw|changes|annotate|diff)/
258 :action => /(browse|show|entry|raw|changes|annotate|diff)/
259
259
260 get 'projects/:id/repository/:repository_id', :to => 'repositories#show', :path => nil
260 get 'projects/:id/repository/:repository_id', :to => 'repositories#show', :path => nil
261 get 'projects/:id/repository', :to => 'repositories#show', :path => nil
261 get 'projects/:id/repository', :to => 'repositories#show', :path => nil
262
262
263 # additional routes for having the file name at the end of url
263 # additional routes for having the file name at the end of url
264 match 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/, :via => :get
264 match 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/, :via => :get
265 match 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/, :via => :get
265 match 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/, :via => :get
266 match 'attachments/download/:id', :controller => 'attachments', :action => 'download', :id => /\d+/, :via => :get
266 match 'attachments/download/:id', :controller => 'attachments', :action => 'download', :id => /\d+/, :via => :get
267 match 'attachments/thumbnail/:id(/:size)', :controller => 'attachments', :action => 'thumbnail', :id => /\d+/, :via => :get, :size => /\d+/
267 match 'attachments/thumbnail/:id(/:size)', :controller => 'attachments', :action => 'thumbnail', :id => /\d+/, :via => :get, :size => /\d+/
268 resources :attachments, :only => [:show, :destroy]
268 resources :attachments, :only => [:show, :destroy]
269
269
270 resources :groups do
270 resources :groups do
271 member do
271 member do
272 get 'autocomplete_for_user'
272 get 'autocomplete_for_user'
273 end
273 end
274 end
274 end
275
275
276 match 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :via => :post, :as => 'group_users'
276 match 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :via => :post, :as => 'group_users'
277 match 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :via => :delete, :as => 'group_user'
277 match 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :via => :delete, :as => 'group_user'
278 match 'groups/destroy_membership/:id', :controller => 'groups', :action => 'destroy_membership', :id => /\d+/, :via => :post
278 match 'groups/destroy_membership/:id', :controller => 'groups', :action => 'destroy_membership', :id => /\d+/, :via => :post
279 match 'groups/edit_membership/:id', :controller => 'groups', :action => 'edit_membership', :id => /\d+/, :via => :post
279 match 'groups/edit_membership/:id', :controller => 'groups', :action => 'edit_membership', :id => /\d+/, :via => :post
280
280
281 resources :trackers, :except => :show do
281 resources :trackers, :except => :show do
282 collection do
282 collection do
283 match 'fields', :via => [:get, :post]
283 match 'fields', :via => [:get, :post]
284 end
284 end
285 end
285 end
286 resources :issue_statuses, :except => :show do
286 resources :issue_statuses, :except => :show do
287 collection do
287 collection do
288 post 'update_issue_done_ratio'
288 post 'update_issue_done_ratio'
289 end
289 end
290 end
290 end
291 resources :custom_fields, :except => :show
291 resources :custom_fields, :except => :show
292 resources :roles do
292 resources :roles do
293 collection do
293 collection do
294 match 'permissions', :via => [:get, :post]
294 match 'permissions', :via => [:get, :post]
295 end
295 end
296 end
296 end
297 resources :enumerations, :except => :show
297 resources :enumerations, :except => :show
298 match 'enumerations/:type', :to => 'enumerations#index', :via => :get
298
299
299 get 'projects/:id/search', :controller => 'search', :action => 'index'
300 get 'projects/:id/search', :controller => 'search', :action => 'index'
300 get 'search', :controller => 'search', :action => 'index'
301 get 'search', :controller => 'search', :action => 'index'
301
302
302 match 'mail_handler', :controller => 'mail_handler', :action => 'index', :via => :post
303 match 'mail_handler', :controller => 'mail_handler', :action => 'index', :via => :post
303
304
304 match 'admin', :controller => 'admin', :action => 'index', :via => :get
305 match 'admin', :controller => 'admin', :action => 'index', :via => :get
305 match 'admin/projects', :controller => 'admin', :action => 'projects', :via => :get
306 match 'admin/projects', :controller => 'admin', :action => 'projects', :via => :get
306 match 'admin/plugins', :controller => 'admin', :action => 'plugins', :via => :get
307 match 'admin/plugins', :controller => 'admin', :action => 'plugins', :via => :get
307 match 'admin/info', :controller => 'admin', :action => 'info', :via => :get
308 match 'admin/info', :controller => 'admin', :action => 'info', :via => :get
308 match 'admin/test_email', :controller => 'admin', :action => 'test_email', :via => :get
309 match 'admin/test_email', :controller => 'admin', :action => 'test_email', :via => :get
309 match 'admin/default_configuration', :controller => 'admin', :action => 'default_configuration', :via => :post
310 match 'admin/default_configuration', :controller => 'admin', :action => 'default_configuration', :via => :post
310
311
311 resources :auth_sources do
312 resources :auth_sources do
312 member do
313 member do
313 get 'test_connection'
314 get 'test_connection'
314 end
315 end
315 end
316 end
316
317
317 match 'workflows', :controller => 'workflows', :action => 'index', :via => :get
318 match 'workflows', :controller => 'workflows', :action => 'index', :via => :get
318 match 'workflows/edit', :controller => 'workflows', :action => 'edit', :via => [:get, :post]
319 match 'workflows/edit', :controller => 'workflows', :action => 'edit', :via => [:get, :post]
319 match 'workflows/permissions', :controller => 'workflows', :action => 'permissions', :via => [:get, :post]
320 match 'workflows/permissions', :controller => 'workflows', :action => 'permissions', :via => [:get, :post]
320 match 'workflows/copy', :controller => 'workflows', :action => 'copy', :via => [:get, :post]
321 match 'workflows/copy', :controller => 'workflows', :action => 'copy', :via => [:get, :post]
321 match 'settings', :controller => 'settings', :action => 'index', :via => :get
322 match 'settings', :controller => 'settings', :action => 'index', :via => :get
322 match 'settings/edit', :controller => 'settings', :action => 'edit', :via => [:get, :post]
323 match 'settings/edit', :controller => 'settings', :action => 'edit', :via => [:get, :post]
323 match 'settings/plugin/:id', :controller => 'settings', :action => 'plugin', :via => [:get, :post]
324 match 'settings/plugin/:id', :controller => 'settings', :action => 'plugin', :via => [:get, :post]
324
325
325 match 'sys/projects', :to => 'sys#projects', :via => :get
326 match 'sys/projects', :to => 'sys#projects', :via => :get
326 match 'sys/projects/:id/repository', :to => 'sys#create_project_repository', :via => :post
327 match 'sys/projects/:id/repository', :to => 'sys#create_project_repository', :via => :post
327 match 'sys/fetch_changesets', :to => 'sys#fetch_changesets', :via => :get
328 match 'sys/fetch_changesets', :to => 'sys#fetch_changesets', :via => :get
328
329
329 match 'uploads', :to => 'attachments#upload', :via => :post
330 match 'uploads', :to => 'attachments#upload', :via => :post
330
331
331 get 'robots.txt', :to => 'welcome#robots'
332 get 'robots.txt', :to => 'welcome#robots'
332
333
333 Dir.glob File.expand_path("plugins/*", Rails.root) do |plugin_dir|
334 Dir.glob File.expand_path("plugins/*", Rails.root) do |plugin_dir|
334 file = File.join(plugin_dir, "config/routes.rb")
335 file = File.join(plugin_dir, "config/routes.rb")
335 if File.exists?(file)
336 if File.exists?(file)
336 begin
337 begin
337 instance_eval File.read(file)
338 instance_eval File.read(file)
338 rescue Exception => e
339 rescue Exception => e
339 puts "An error occurred while loading the routes definition of #{File.basename(plugin_dir)} plugin (#{file}): #{e.message}."
340 puts "An error occurred while loading the routes definition of #{File.basename(plugin_dir)} plugin (#{file}): #{e.message}."
340 exit 1
341 exit 1
341 end
342 end
342 end
343 end
343 end
344 end
344 end
345 end
@@ -1,42 +1,47
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 module Redmine
18 module Redmine
19 module SubclassFactory
19 module SubclassFactory
20 def self.included(base)
20 def self.included(base)
21 base.extend ClassMethods
21 base.extend ClassMethods
22 end
22 end
23
23
24 module ClassMethods
24 module ClassMethods
25 # Returns an instance of the given subclass name
25 def get_subclass(class_name)
26 def new_subclass_instance(class_name, *args)
27 klass = nil
26 klass = nil
28 begin
27 begin
29 klass = class_name.to_s.classify.constantize
28 klass = class_name.to_s.classify.constantize
30 rescue
29 rescue
31 # invalid class name
30 # invalid class name
32 end
31 end
33 unless subclasses.include? klass
32 unless subclasses.include? klass
34 klass = nil
33 klass = nil
35 end
34 end
35 klass
36 end
37
38 # Returns an instance of the given subclass name
39 def new_subclass_instance(class_name, *args)
40 klass = get_subclass(class_name)
36 if klass
41 if klass
37 klass.new(*args)
42 klass.new(*args)
38 end
43 end
39 end
44 end
40 end
45 end
41 end
46 end
42 end
47 end
@@ -1,123 +1,129
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 EnumerationsControllerTest < ActionController::TestCase
20 class EnumerationsControllerTest < ActionController::TestCase
21 fixtures :enumerations, :issues, :users
21 fixtures :enumerations, :issues, :users
22
22
23 def setup
23 def setup
24 @request.session[:user_id] = 1 # admin
24 @request.session[:user_id] = 1 # admin
25 end
25 end
26
26
27 def test_index
27 def test_index
28 get :index
28 get :index
29 assert_response :success
29 assert_response :success
30 assert_template 'index'
30 assert_template 'index'
31 end
31 end
32
32
33 def test_index_should_require_admin
34 @request.session[:user_id] = nil
35 get :index
36 assert_response 302
37 end
38
33 def test_new
39 def test_new
34 get :new, :type => 'IssuePriority'
40 get :new, :type => 'IssuePriority'
35 assert_response :success
41 assert_response :success
36 assert_template 'new'
42 assert_template 'new'
37 assert_kind_of IssuePriority, assigns(:enumeration)
43 assert_kind_of IssuePriority, assigns(:enumeration)
38 assert_tag 'input', :attributes => {:name => 'enumeration[type]', :value => 'IssuePriority'}
44 assert_tag 'input', :attributes => {:name => 'enumeration[type]', :value => 'IssuePriority'}
39 assert_tag 'input', :attributes => {:name => 'enumeration[name]'}
45 assert_tag 'input', :attributes => {:name => 'enumeration[name]'}
40 end
46 end
41
47
42 def test_new_with_invalid_type_should_respond_with_404
48 def test_new_with_invalid_type_should_respond_with_404
43 get :new, :type => 'UnknownType'
49 get :new, :type => 'UnknownType'
44 assert_response 404
50 assert_response 404
45 end
51 end
46
52
47 def test_create
53 def test_create
48 assert_difference 'IssuePriority.count' do
54 assert_difference 'IssuePriority.count' do
49 post :create, :enumeration => {:type => 'IssuePriority', :name => 'Lowest'}
55 post :create, :enumeration => {:type => 'IssuePriority', :name => 'Lowest'}
50 end
56 end
51 assert_redirected_to '/enumerations?type=IssuePriority'
57 assert_redirected_to '/enumerations'
52 e = IssuePriority.find_by_name('Lowest')
58 e = IssuePriority.find_by_name('Lowest')
53 assert_not_nil e
59 assert_not_nil e
54 end
60 end
55
61
56 def test_create_with_failure
62 def test_create_with_failure
57 assert_no_difference 'IssuePriority.count' do
63 assert_no_difference 'IssuePriority.count' do
58 post :create, :enumeration => {:type => 'IssuePriority', :name => ''}
64 post :create, :enumeration => {:type => 'IssuePriority', :name => ''}
59 end
65 end
60 assert_response :success
66 assert_response :success
61 assert_template 'new'
67 assert_template 'new'
62 end
68 end
63
69
64 def test_edit
70 def test_edit
65 get :edit, :id => 6
71 get :edit, :id => 6
66 assert_response :success
72 assert_response :success
67 assert_template 'edit'
73 assert_template 'edit'
68 assert_tag 'input', :attributes => {:name => 'enumeration[name]', :value => 'High'}
74 assert_tag 'input', :attributes => {:name => 'enumeration[name]', :value => 'High'}
69 end
75 end
70
76
71 def test_edit_invalid_should_respond_with_404
77 def test_edit_invalid_should_respond_with_404
72 get :edit, :id => 999
78 get :edit, :id => 999
73 assert_response 404
79 assert_response 404
74 end
80 end
75
81
76 def test_update
82 def test_update
77 assert_no_difference 'IssuePriority.count' do
83 assert_no_difference 'IssuePriority.count' do
78 put :update, :id => 6, :enumeration => {:type => 'IssuePriority', :name => 'New name'}
84 put :update, :id => 6, :enumeration => {:type => 'IssuePriority', :name => 'New name'}
79 end
85 end
80 assert_redirected_to '/enumerations?type=IssuePriority'
86 assert_redirected_to '/enumerations'
81 e = IssuePriority.find(6)
87 e = IssuePriority.find(6)
82 assert_equal 'New name', e.name
88 assert_equal 'New name', e.name
83 end
89 end
84
90
85 def test_update_with_failure
91 def test_update_with_failure
86 assert_no_difference 'IssuePriority.count' do
92 assert_no_difference 'IssuePriority.count' do
87 put :update, :id => 6, :enumeration => {:type => 'IssuePriority', :name => ''}
93 put :update, :id => 6, :enumeration => {:type => 'IssuePriority', :name => ''}
88 end
94 end
89 assert_response :success
95 assert_response :success
90 assert_template 'edit'
96 assert_template 'edit'
91 end
97 end
92
98
93 def test_destroy_enumeration_not_in_use
99 def test_destroy_enumeration_not_in_use
94 assert_difference 'IssuePriority.count', -1 do
100 assert_difference 'IssuePriority.count', -1 do
95 delete :destroy, :id => 7
101 delete :destroy, :id => 7
96 end
102 end
97 assert_redirected_to :controller => 'enumerations', :action => 'index'
103 assert_redirected_to :controller => 'enumerations', :action => 'index'
98 assert_nil Enumeration.find_by_id(7)
104 assert_nil Enumeration.find_by_id(7)
99 end
105 end
100
106
101 def test_destroy_enumeration_in_use
107 def test_destroy_enumeration_in_use
102 assert_no_difference 'IssuePriority.count' do
108 assert_no_difference 'IssuePriority.count' do
103 delete :destroy, :id => 4
109 delete :destroy, :id => 4
104 end
110 end
105 assert_response :success
111 assert_response :success
106 assert_template 'destroy'
112 assert_template 'destroy'
107 assert_not_nil Enumeration.find_by_id(4)
113 assert_not_nil Enumeration.find_by_id(4)
108 assert_select 'select[name=reassign_to_id]' do
114 assert_select 'select[name=reassign_to_id]' do
109 assert_select 'option[value=6]', :text => 'High'
115 assert_select 'option[value=6]', :text => 'High'
110 end
116 end
111 end
117 end
112
118
113 def test_destroy_enumeration_in_use_with_reassignment
119 def test_destroy_enumeration_in_use_with_reassignment
114 issue = Issue.find(:first, :conditions => {:priority_id => 4})
120 issue = Issue.find(:first, :conditions => {:priority_id => 4})
115 assert_difference 'IssuePriority.count', -1 do
121 assert_difference 'IssuePriority.count', -1 do
116 delete :destroy, :id => 4, :reassign_to_id => 6
122 delete :destroy, :id => 4, :reassign_to_id => 6
117 end
123 end
118 assert_redirected_to :controller => 'enumerations', :action => 'index'
124 assert_redirected_to :controller => 'enumerations', :action => 'index'
119 assert_nil Enumeration.find_by_id(4)
125 assert_nil Enumeration.find_by_id(4)
120 # check that the issue was reassign
126 # check that the issue was reassign
121 assert_equal 6, issue.reload.priority_id
127 assert_equal 6, issue.reload.priority_id
122 end
128 end
123 end
129 end
@@ -1,47 +1,51
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 RoutingEnumerationsTest < ActionController::IntegrationTest
20 class RoutingEnumerationsTest < ActionController::IntegrationTest
21 def test_enumerations
21 def test_enumerations
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/enumerations" },
23 { :method => 'get', :path => "/enumerations" },
24 { :controller => 'enumerations', :action => 'index' }
24 { :controller => 'enumerations', :action => 'index' }
25 )
25 )
26 assert_routing(
26 assert_routing(
27 { :method => 'get', :path => "/enumerations/new" },
27 { :method => 'get', :path => "/enumerations/new" },
28 { :controller => 'enumerations', :action => 'new' }
28 { :controller => 'enumerations', :action => 'new' }
29 )
29 )
30 assert_routing(
30 assert_routing(
31 { :method => 'post', :path => "/enumerations" },
31 { :method => 'post', :path => "/enumerations" },
32 { :controller => 'enumerations', :action => 'create' }
32 { :controller => 'enumerations', :action => 'create' }
33 )
33 )
34 assert_routing(
34 assert_routing(
35 { :method => 'get', :path => "/enumerations/2/edit" },
35 { :method => 'get', :path => "/enumerations/2/edit" },
36 { :controller => 'enumerations', :action => 'edit', :id => '2' }
36 { :controller => 'enumerations', :action => 'edit', :id => '2' }
37 )
37 )
38 assert_routing(
38 assert_routing(
39 { :method => 'put', :path => "/enumerations/2" },
39 { :method => 'put', :path => "/enumerations/2" },
40 { :controller => 'enumerations', :action => 'update', :id => '2' }
40 { :controller => 'enumerations', :action => 'update', :id => '2' }
41 )
41 )
42 assert_routing(
42 assert_routing(
43 { :method => 'delete', :path => "/enumerations/2" },
43 { :method => 'delete', :path => "/enumerations/2" },
44 { :controller => 'enumerations', :action => 'destroy', :id => '2' }
44 { :controller => 'enumerations', :action => 'destroy', :id => '2' }
45 )
45 )
46 assert_routing(
47 { :method => 'get', :path => "/enumerations/issue_priorities.xml" },
48 { :controller => 'enumerations', :action => 'index', :type => 'issue_priorities', :format => 'xml' }
49 )
46 end
50 end
47 end
51 end
General Comments 0
You need to be logged in to leave comments. Login now