##// END OF EJS Templates
ajaxified paginators...
Jean-Philippe Lang -
r31:6a0022d7a146
parent child
Show More
@@ -1,54 +1,56
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 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 AdminController < ApplicationController
18 class AdminController < ApplicationController
19 layout 'base'
19 layout 'base'
20 before_filter :require_admin
20 before_filter :require_admin
21
21
22 helper :sort
22 helper :sort
23 include SortHelper
23 include SortHelper
24
24
25 def index
25 def index
26 end
26 end
27
27
28 def projects
28 def projects
29 sort_init 'name', 'asc'
29 sort_init 'name', 'asc'
30 sort_update
30 sort_update
31 @project_count = Project.count
31 @project_count = Project.count
32 @project_pages = Paginator.new self, @project_count,
32 @project_pages = Paginator.new self, @project_count,
33 15,
33 15,
34 @params['page']
34 @params['page']
35 @projects = Project.find :all, :order => sort_clause,
35 @projects = Project.find :all, :order => sort_clause,
36 :limit => @project_pages.items_per_page,
36 :limit => @project_pages.items_per_page,
37 :offset => @project_pages.current.offset
37 :offset => @project_pages.current.offset
38
39 render :action => "projects", :layout => false if request.xhr?
38 end
40 end
39
41
40 def mail_options
42 def mail_options
41 @actions = Permission.find(:all, :conditions => ["mail_option=?", true]) || []
43 @actions = Permission.find(:all, :conditions => ["mail_option=?", true]) || []
42 if request.post?
44 if request.post?
43 @actions.each { |a|
45 @actions.each { |a|
44 a.mail_enabled = (params[:action_ids] || []).include? a.id.to_s
46 a.mail_enabled = (params[:action_ids] || []).include? a.id.to_s
45 a.save
47 a.save
46 }
48 }
47 flash.now[:notice] = l(:notice_successful_update)
49 flash.now[:notice] = l(:notice_successful_update)
48 end
50 end
49 end
51 end
50
52
51 def info
53 def info
52 @adapter_name = ActiveRecord::Base.connection.adapter_name
54 @adapter_name = ActiveRecord::Base.connection.adapter_name
53 end
55 end
54 end
56 end
@@ -1,82 +1,83
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 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 AuthSourcesController < ApplicationController
18 class AuthSourcesController < ApplicationController
19 layout 'base'
19 layout 'base'
20 before_filter :require_admin
20 before_filter :require_admin
21
21
22 def index
22 def index
23 list
23 list
24 render :action => 'list'
24 render :action => 'list' unless request.xhr?
25 end
25 end
26
26
27 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
27 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
28 verify :method => :post, :only => [ :destroy, :create, :update ],
28 verify :method => :post, :only => [ :destroy, :create, :update ],
29 :redirect_to => { :action => :list }
29 :redirect_to => { :action => :list }
30
30
31 def list
31 def list
32 @auth_source_pages, @auth_sources = paginate :auth_sources, :per_page => 10
32 @auth_source_pages, @auth_sources = paginate :auth_sources, :per_page => 10
33 render :action => "list", :layout => false if request.xhr?
33 end
34 end
34
35
35 def new
36 def new
36 @auth_source = AuthSourceLdap.new
37 @auth_source = AuthSourceLdap.new
37 end
38 end
38
39
39 def create
40 def create
40 @auth_source = AuthSourceLdap.new(params[:auth_source])
41 @auth_source = AuthSourceLdap.new(params[:auth_source])
41 if @auth_source.save
42 if @auth_source.save
42 flash[:notice] = l(:notice_successful_create)
43 flash[:notice] = l(:notice_successful_create)
43 redirect_to :action => 'list'
44 redirect_to :action => 'list'
44 else
45 else
45 render :action => 'new'
46 render :action => 'new'
46 end
47 end
47 end
48 end
48
49
49 def edit
50 def edit
50 @auth_source = AuthSource.find(params[:id])
51 @auth_source = AuthSource.find(params[:id])
51 end
52 end
52
53
53 def update
54 def update
54 @auth_source = AuthSource.find(params[:id])
55 @auth_source = AuthSource.find(params[:id])
55 if @auth_source.update_attributes(params[:auth_source])
56 if @auth_source.update_attributes(params[:auth_source])
56 flash[:notice] = l(:notice_successful_update)
57 flash[:notice] = l(:notice_successful_update)
57 redirect_to :action => 'list'
58 redirect_to :action => 'list'
58 else
59 else
59 render :action => 'edit'
60 render :action => 'edit'
60 end
61 end
61 end
62 end
62
63
63 def test_connection
64 def test_connection
64 @auth_method = AuthSource.find(params[:id])
65 @auth_method = AuthSource.find(params[:id])
65 begin
66 begin
66 @auth_method.test_connection
67 @auth_method.test_connection
67 rescue => text
68 rescue => text
68 flash[:notice] = text
69 flash[:notice] = text
69 end
70 end
70 flash[:notice] ||= l(:notice_successful_connection)
71 flash[:notice] ||= l(:notice_successful_connection)
71 redirect_to :action => 'list'
72 redirect_to :action => 'list'
72 end
73 end
73
74
74 def destroy
75 def destroy
75 @auth_source = AuthSource.find(params[:id])
76 @auth_source = AuthSource.find(params[:id])
76 unless @auth_source.users.find(:first)
77 unless @auth_source.users.find(:first)
77 @auth_source.destroy
78 @auth_source.destroy
78 flash[:notice] = l(:notice_successful_delete)
79 flash[:notice] = l(:notice_successful_delete)
79 end
80 end
80 redirect_to :action => 'list'
81 redirect_to :action => 'list'
81 end
82 end
82 end
83 end
@@ -1,70 +1,71
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 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 CustomFieldsController < ApplicationController
18 class CustomFieldsController < ApplicationController
19 layout 'base'
19 layout 'base'
20 before_filter :require_admin
20 before_filter :require_admin
21
21
22 def index
22 def index
23 list
23 list
24 render :action => 'list'
24 render :action => 'list' unless request.xhr?
25 end
25 end
26
26
27 def list
27 def list
28 @custom_field_pages, @custom_fields = paginate :custom_fields, :per_page => 15
28 @custom_field_pages, @custom_fields = paginate :custom_fields, :per_page => 15
29 render :action => "list", :layout => false if request.xhr?
29 end
30 end
30
31
31 def new
32 def new
32 case params[:type]
33 case params[:type]
33 when "IssueCustomField"
34 when "IssueCustomField"
34 @custom_field = IssueCustomField.new(params[:custom_field])
35 @custom_field = IssueCustomField.new(params[:custom_field])
35 @custom_field.trackers = Tracker.find(params[:tracker_ids]) if params[:tracker_ids]
36 @custom_field.trackers = Tracker.find(params[:tracker_ids]) if params[:tracker_ids]
36 when "UserCustomField"
37 when "UserCustomField"
37 @custom_field = UserCustomField.new(params[:custom_field])
38 @custom_field = UserCustomField.new(params[:custom_field])
38 when "ProjectCustomField"
39 when "ProjectCustomField"
39 @custom_field = ProjectCustomField.new(params[:custom_field])
40 @custom_field = ProjectCustomField.new(params[:custom_field])
40 else
41 else
41 redirect_to :action => 'list'
42 redirect_to :action => 'list'
42 return
43 return
43 end
44 end
44 if request.post? and @custom_field.save
45 if request.post? and @custom_field.save
45 flash[:notice] = l(:notice_successful_create)
46 flash[:notice] = l(:notice_successful_create)
46 redirect_to :action => 'list'
47 redirect_to :action => 'list'
47 end
48 end
48 @trackers = Tracker.find(:all)
49 @trackers = Tracker.find(:all)
49 end
50 end
50
51
51 def edit
52 def edit
52 @custom_field = CustomField.find(params[:id])
53 @custom_field = CustomField.find(params[:id])
53 if request.post? and @custom_field.update_attributes(params[:custom_field])
54 if request.post? and @custom_field.update_attributes(params[:custom_field])
54 if @custom_field.is_a? IssueCustomField
55 if @custom_field.is_a? IssueCustomField
55 @custom_field.trackers = params[:tracker_ids] ? Tracker.find(params[:tracker_ids]) : []
56 @custom_field.trackers = params[:tracker_ids] ? Tracker.find(params[:tracker_ids]) : []
56 end
57 end
57 flash[:notice] = l(:notice_successful_update)
58 flash[:notice] = l(:notice_successful_update)
58 redirect_to :action => 'list'
59 redirect_to :action => 'list'
59 end
60 end
60 @trackers = Tracker.find(:all)
61 @trackers = Tracker.find(:all)
61 end
62 end
62
63
63 def destroy
64 def destroy
64 CustomField.find(params[:id]).destroy
65 CustomField.find(params[:id]).destroy
65 redirect_to :action => 'list'
66 redirect_to :action => 'list'
66 rescue
67 rescue
67 flash[:notice] = "Unable to delete custom field"
68 flash[:notice] = "Unable to delete custom field"
68 redirect_to :action => 'list'
69 redirect_to :action => 'list'
69 end
70 end
70 end
71 end
@@ -1,68 +1,69
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 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 IssueStatusesController < ApplicationController
18 class IssueStatusesController < ApplicationController
19 layout 'base'
19 layout 'base'
20 before_filter :require_admin
20 before_filter :require_admin
21
21
22 def index
22 def index
23 list
23 list
24 render :action => 'list'
24 render :action => 'list' unless request.xhr?
25 end
25 end
26
26
27 def list
27 def list
28 @issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 10
28 @issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 10
29 render :action => "list", :layout => false if request.xhr?
29 end
30 end
30
31
31 def new
32 def new
32 @issue_status = IssueStatus.new
33 @issue_status = IssueStatus.new
33 end
34 end
34
35
35 def create
36 def create
36 @issue_status = IssueStatus.new(params[:issue_status])
37 @issue_status = IssueStatus.new(params[:issue_status])
37 if @issue_status.save
38 if @issue_status.save
38 flash[:notice] = l(:notice_successful_create)
39 flash[:notice] = l(:notice_successful_create)
39 redirect_to :action => 'list'
40 redirect_to :action => 'list'
40 else
41 else
41 render :action => 'new'
42 render :action => 'new'
42 end
43 end
43 end
44 end
44
45
45 def edit
46 def edit
46 @issue_status = IssueStatus.find(params[:id])
47 @issue_status = IssueStatus.find(params[:id])
47 end
48 end
48
49
49 def update
50 def update
50 @issue_status = IssueStatus.find(params[:id])
51 @issue_status = IssueStatus.find(params[:id])
51 if @issue_status.update_attributes(params[:issue_status])
52 if @issue_status.update_attributes(params[:issue_status])
52 flash[:notice] = l(:notice_successful_update)
53 flash[:notice] = l(:notice_successful_update)
53 redirect_to :action => 'list'
54 redirect_to :action => 'list'
54 else
55 else
55 render :action => 'edit'
56 render :action => 'edit'
56 end
57 end
57 end
58 end
58
59
59 def destroy
60 def destroy
60 IssueStatus.find(params[:id]).destroy
61 IssueStatus.find(params[:id]).destroy
61 redirect_to :action => 'list'
62 redirect_to :action => 'list'
62 rescue
63 rescue
63 flash[:notice] = "Unable to delete issue status"
64 flash[:notice] = "Unable to delete issue status"
64 redirect_to :action => 'list'
65 redirect_to :action => 'list'
65 end
66 end
66
67
67
68
68 end
69 end
@@ -1,329 +1,334
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 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 ProjectsController < ApplicationController
18 class ProjectsController < ApplicationController
19 layout 'base'
19 layout 'base'
20 before_filter :find_project, :authorize, :except => [ :index, :list, :add ]
20 before_filter :find_project, :authorize, :except => [ :index, :list, :add ]
21 before_filter :require_admin, :only => [ :add, :destroy ]
21 before_filter :require_admin, :only => [ :add, :destroy ]
22
22
23 helper :sort
23 helper :sort
24 include SortHelper
24 include SortHelper
25 helper :search_filter
25 helper :search_filter
26 include SearchFilterHelper
26 include SearchFilterHelper
27 helper :custom_fields
27 helper :custom_fields
28 include CustomFieldsHelper
28 include CustomFieldsHelper
29
29
30 def index
30 def index
31 list
31 list
32 render :action => 'list'
32 render :action => 'list' unless request.xhr?
33 end
33 end
34
34
35 # Lists public projects
35 # Lists public projects
36 def list
36 def list
37 sort_init 'name', 'asc'
37 sort_init 'name', 'asc'
38 sort_update
38 sort_update
39 @project_count = Project.count(["is_public=?", true])
39 @project_count = Project.count(["is_public=?", true])
40 @project_pages = Paginator.new self, @project_count,
40 @project_pages = Paginator.new self, @project_count,
41 15,
41 15,
42 @params['page']
42 @params['page']
43 @projects = Project.find :all, :order => sort_clause,
43 @projects = Project.find :all, :order => sort_clause,
44 :conditions => ["is_public=?", true],
44 :conditions => ["is_public=?", true],
45 :limit => @project_pages.items_per_page,
45 :limit => @project_pages.items_per_page,
46 :offset => @project_pages.current.offset
46 :offset => @project_pages.current.offset
47
48 render :action => "list", :layout => false if request.xhr?
47 end
49 end
48
50
49 # Add a new project
51 # Add a new project
50 def add
52 def add
51 @custom_fields = IssueCustomField.find(:all)
53 @custom_fields = IssueCustomField.find(:all)
52 @root_projects = Project.find(:all, :conditions => "parent_id is null")
54 @root_projects = Project.find(:all, :conditions => "parent_id is null")
53 @project = Project.new(params[:project])
55 @project = Project.new(params[:project])
54 if request.get?
56 if request.get?
55 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project) }
57 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project) }
56 else
58 else
57 @project.custom_fields = CustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids]
59 @project.custom_fields = CustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids]
58 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
60 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
59 @project.custom_values = @custom_values
61 @project.custom_values = @custom_values
60 if @project.save
62 if @project.save
61 flash[:notice] = l(:notice_successful_create)
63 flash[:notice] = l(:notice_successful_create)
62 redirect_to :controller => 'admin', :action => 'projects'
64 redirect_to :controller => 'admin', :action => 'projects'
63 end
65 end
64 end
66 end
65 end
67 end
66
68
67 # Show @project
69 # Show @project
68 def show
70 def show
69 @custom_values = @project.custom_values.find(:all, :include => :custom_field)
71 @custom_values = @project.custom_values.find(:all, :include => :custom_field)
70 @members = @project.members.find(:all, :include => [:user, :role])
72 @members = @project.members.find(:all, :include => [:user, :role])
71 @subprojects = @project.children if @project.children_count > 0
73 @subprojects = @project.children if @project.children_count > 0
72 @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "news.created_on DESC")
74 @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "news.created_on DESC")
73 @trackers = Tracker.find(:all)
75 @trackers = Tracker.find(:all)
74 end
76 end
75
77
76 def settings
78 def settings
77 @root_projects = Project::find(:all, :conditions => ["parent_id is null and id <> ?", @project.id])
79 @root_projects = Project::find(:all, :conditions => ["parent_id is null and id <> ?", @project.id])
78 @custom_fields = IssueCustomField::find_all
80 @custom_fields = IssueCustomField::find_all
79 @issue_category ||= IssueCategory.new
81 @issue_category ||= IssueCategory.new
80 @member ||= @project.members.new
82 @member ||= @project.members.new
81 @roles = Role.find_all
83 @roles = Role.find_all
82 @users = User.find_all - @project.members.find(:all, :include => :user).collect{|m| m.user }
84 @users = User.find_all - @project.members.find(:all, :include => :user).collect{|m| m.user }
83 @custom_values ||= ProjectCustomField.find(:all).collect { |x| @project.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
85 @custom_values ||= ProjectCustomField.find(:all).collect { |x| @project.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
84 end
86 end
85
87
86 # Edit @project
88 # Edit @project
87 def edit
89 def edit
88 if request.post?
90 if request.post?
89 @project.custom_fields = IssueCustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids]
91 @project.custom_fields = IssueCustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids]
90 if params[:custom_fields]
92 if params[:custom_fields]
91 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
93 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
92 @project.custom_values = @custom_values
94 @project.custom_values = @custom_values
93 end
95 end
94 if @project.update_attributes(params[:project])
96 if @project.update_attributes(params[:project])
95 flash[:notice] = l(:notice_successful_update)
97 flash[:notice] = l(:notice_successful_update)
96 redirect_to :action => 'settings', :id => @project
98 redirect_to :action => 'settings', :id => @project
97 else
99 else
98 settings
100 settings
99 render :action => 'settings'
101 render :action => 'settings'
100 end
102 end
101 end
103 end
102 end
104 end
103
105
104 # Delete @project
106 # Delete @project
105 def destroy
107 def destroy
106 if request.post? and params[:confirm]
108 if request.post? and params[:confirm]
107 @project.destroy
109 @project.destroy
108 redirect_to :controller => 'admin', :action => 'projects'
110 redirect_to :controller => 'admin', :action => 'projects'
109 end
111 end
110 end
112 end
111
113
112 # Add a new issue category to @project
114 # Add a new issue category to @project
113 def add_issue_category
115 def add_issue_category
114 if request.post?
116 if request.post?
115 @issue_category = @project.issue_categories.build(params[:issue_category])
117 @issue_category = @project.issue_categories.build(params[:issue_category])
116 if @issue_category.save
118 if @issue_category.save
117 flash[:notice] = l(:notice_successful_create)
119 flash[:notice] = l(:notice_successful_create)
118 redirect_to :action => 'settings', :id => @project
120 redirect_to :action => 'settings', :id => @project
119 else
121 else
120 settings
122 settings
121 render :action => 'settings'
123 render :action => 'settings'
122 end
124 end
123 end
125 end
124 end
126 end
125
127
126 # Add a new version to @project
128 # Add a new version to @project
127 def add_version
129 def add_version
128 @version = @project.versions.build(params[:version])
130 @version = @project.versions.build(params[:version])
129 if request.post? and @version.save
131 if request.post? and @version.save
130 flash[:notice] = l(:notice_successful_create)
132 flash[:notice] = l(:notice_successful_create)
131 redirect_to :action => 'settings', :id => @project
133 redirect_to :action => 'settings', :id => @project
132 end
134 end
133 end
135 end
134
136
135 # Add a new member to @project
137 # Add a new member to @project
136 def add_member
138 def add_member
137 @member = @project.members.build(params[:member])
139 @member = @project.members.build(params[:member])
138 if request.post?
140 if request.post?
139 if @member.save
141 if @member.save
140 flash[:notice] = l(:notice_successful_create)
142 flash[:notice] = l(:notice_successful_create)
141 redirect_to :action => 'settings', :id => @project
143 redirect_to :action => 'settings', :id => @project
142 else
144 else
143 settings
145 settings
144 render :action => 'settings'
146 render :action => 'settings'
145 end
147 end
146 end
148 end
147 end
149 end
148
150
149 # Show members list of @project
151 # Show members list of @project
150 def list_members
152 def list_members
151 @members = @project.members
153 @members = @project.members
152 end
154 end
153
155
154 # Add a new document to @project
156 # Add a new document to @project
155 def add_document
157 def add_document
156 @categories = Enumeration::get_values('DCAT')
158 @categories = Enumeration::get_values('DCAT')
157 @document = @project.documents.build(params[:document])
159 @document = @project.documents.build(params[:document])
158 if request.post?
160 if request.post?
159 # Save the attachment
161 # Save the attachment
160 if params[:attachment][:file].size > 0
162 if params[:attachment][:file].size > 0
161 @attachment = @document.attachments.build(params[:attachment])
163 @attachment = @document.attachments.build(params[:attachment])
162 @attachment.author_id = self.logged_in_user.id if self.logged_in_user
164 @attachment.author_id = self.logged_in_user.id if self.logged_in_user
163 end
165 end
164 if @document.save
166 if @document.save
165 flash[:notice] = l(:notice_successful_create)
167 flash[:notice] = l(:notice_successful_create)
166 redirect_to :action => 'list_documents', :id => @project
168 redirect_to :action => 'list_documents', :id => @project
167 end
169 end
168 end
170 end
169 end
171 end
170
172
171 # Show documents list of @project
173 # Show documents list of @project
172 def list_documents
174 def list_documents
173 @documents = @project.documents
175 @documents = @project.documents
174 end
176 end
175
177
176 # Add a new issue to @project
178 # Add a new issue to @project
177 def add_issue
179 def add_issue
178 @tracker = Tracker.find(params[:tracker_id])
180 @tracker = Tracker.find(params[:tracker_id])
179 @priorities = Enumeration::get_values('IPRI')
181 @priorities = Enumeration::get_values('IPRI')
180 @issue = Issue.new(:project => @project, :tracker => @tracker)
182 @issue = Issue.new(:project => @project, :tracker => @tracker)
181 if request.get?
183 if request.get?
182 @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue) }
184 @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue) }
183 else
185 else
184 @issue.attributes = params[:issue]
186 @issue.attributes = params[:issue]
185 @issue.author_id = self.logged_in_user.id if self.logged_in_user
187 @issue.author_id = self.logged_in_user.id if self.logged_in_user
186 # Create the document if a file was sent
188 # Create the document if a file was sent
187 if params[:attachment][:file].size > 0
189 if params[:attachment][:file].size > 0
188 @attachment = @issue.attachments.build(params[:attachment])
190 @attachment = @issue.attachments.build(params[:attachment])
189 @attachment.author_id = self.logged_in_user.id if self.logged_in_user
191 @attachment.author_id = self.logged_in_user.id if self.logged_in_user
190 end
192 end
191 @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
193 @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
192 @issue.custom_values = @custom_values
194 @issue.custom_values = @custom_values
193 if @issue.save
195 if @issue.save
194 flash[:notice] = l(:notice_successful_create)
196 flash[:notice] = l(:notice_successful_create)
195 Mailer.deliver_issue_add(@issue) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled?
197 Mailer.deliver_issue_add(@issue) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled?
196 redirect_to :action => 'list_issues', :id => @project
198 redirect_to :action => 'list_issues', :id => @project
197 end
199 end
198 end
200 end
199 end
201 end
200
202
201 # Show filtered/sorted issues list of @project
203 # Show filtered/sorted issues list of @project
202 def list_issues
204 def list_issues
203 sort_init 'issues.id', 'desc'
205 sort_init 'issues.id', 'desc'
204 sort_update
206 sort_update
205
207
206 search_filter_init_list_issues
208 search_filter_init_list_issues
207 search_filter_update if params[:set_filter] or request.post?
209 search_filter_update if params[:set_filter]
208
210
209 @issue_count = Issue.count(:include => [:status, :project], :conditions => search_filter_clause)
211 @issue_count = Issue.count(:include => [:status, :project], :conditions => search_filter_clause)
210 @issue_pages = Paginator.new self, @issue_count, 15, @params['page']
212 @issue_pages = Paginator.new self, @issue_count, 15, @params['page']
211 @issues = Issue.find :all, :order => sort_clause,
213 @issues = Issue.find :all, :order => sort_clause,
212 :include => [ :author, :status, :tracker, :project ],
214 :include => [ :author, :status, :tracker, :project ],
213 :conditions => search_filter_clause,
215 :conditions => search_filter_clause,
214 :limit => @issue_pages.items_per_page,
216 :limit => @issue_pages.items_per_page,
215 :offset => @issue_pages.current.offset
217 :offset => @issue_pages.current.offset
218
219 render :action => "list_issues", :layout => false if request.xhr?
216 end
220 end
217
221
218 # Export filtered/sorted issues list to CSV
222 # Export filtered/sorted issues list to CSV
219 def export_issues_csv
223 def export_issues_csv
220 sort_init 'issues.id', 'desc'
224 sort_init 'issues.id', 'desc'
221 sort_update
225 sort_update
222
226
223 search_filter_init_list_issues
227 search_filter_init_list_issues
224
228
225 @issues = Issue.find :all, :order => sort_clause,
229 @issues = Issue.find :all, :order => sort_clause,
226 :include => [ :author, :status, :tracker, :project ],
230 :include => [ :author, :status, :tracker, :project ],
227 :conditions => search_filter_clause
231 :conditions => search_filter_clause
228
232
229 export = StringIO.new
233 export = StringIO.new
230 CSV::Writer.generate(export, ',') do |csv|
234 CSV::Writer.generate(export, ',') do |csv|
231 csv << %w(Id Status Tracker Subject Author Created Updated)
235 csv << %w(Id Status Tracker Subject Author Created Updated)
232 @issues.each do |issue|
236 @issues.each do |issue|
233 csv << [issue.id, issue.status.name, issue.tracker.name, issue.subject, issue.author.display_name, l_datetime(issue.created_on), l_datetime(issue.updated_on)]
237 csv << [issue.id, issue.status.name, issue.tracker.name, issue.subject, issue.author.display_name, l_datetime(issue.created_on), l_datetime(issue.updated_on)]
234 end
238 end
235 end
239 end
236 export.rewind
240 export.rewind
237 send_data(export.read,
241 send_data(export.read,
238 :type => 'text/csv; charset=utf-8; header=present',
242 :type => 'text/csv; charset=utf-8; header=present',
239 :filename => 'export.csv')
243 :filename => 'export.csv')
240 end
244 end
241
245
242 def move_issues
246 def move_issues
243 @issues = @project.issues.find(params[:issue_ids]) if params[:issue_ids]
247 @issues = @project.issues.find(params[:issue_ids]) if params[:issue_ids]
244 redirect_to :action => 'list_issues', :id => @project and return unless @issues
248 redirect_to :action => 'list_issues', :id => @project and return unless @issues
245 @projects = []
249 @projects = []
246 # find projects to which the user is allowed to move the issue
250 # find projects to which the user is allowed to move the issue
247 @logged_in_user.memberships.each {|m| @projects << m.project if Permission.allowed_to_role("projects/move_issues", m.role_id)}
251 @logged_in_user.memberships.each {|m| @projects << m.project if Permission.allowed_to_role("projects/move_issues", m.role_id)}
248 # issue can be moved to any tracker
252 # issue can be moved to any tracker
249 @trackers = Tracker.find(:all)
253 @trackers = Tracker.find(:all)
250 if request.post? and params[:new_project_id] and params[:new_tracker_id]
254 if request.post? and params[:new_project_id] and params[:new_tracker_id]
251 new_project = Project.find(params[:new_project_id])
255 new_project = Project.find(params[:new_project_id])
252 new_tracker = Tracker.find(params[:new_tracker_id])
256 new_tracker = Tracker.find(params[:new_tracker_id])
253 @issues.each { |i|
257 @issues.each { |i|
254 # category is project dependent
258 # category is project dependent
255 i.category = nil unless i.project_id == new_project.id
259 i.category = nil unless i.project_id == new_project.id
256 # move the issue
260 # move the issue
257 i.project = new_project
261 i.project = new_project
258 i.tracker = new_tracker
262 i.tracker = new_tracker
259 i.save
263 i.save
260 }
264 }
261 flash[:notice] = l(:notice_successful_update)
265 flash[:notice] = l(:notice_successful_update)
262 redirect_to :action => 'list_issues', :id => @project
266 redirect_to :action => 'list_issues', :id => @project
263 end
267 end
264 end
268 end
265
269
266 # Add a news to @project
270 # Add a news to @project
267 def add_news
271 def add_news
268 @news = News.new(:project => @project)
272 @news = News.new(:project => @project)
269 if request.post?
273 if request.post?
270 @news.attributes = params[:news]
274 @news.attributes = params[:news]
271 @news.author_id = self.logged_in_user.id if self.logged_in_user
275 @news.author_id = self.logged_in_user.id if self.logged_in_user
272 if @news.save
276 if @news.save
273 flash[:notice] = l(:notice_successful_create)
277 flash[:notice] = l(:notice_successful_create)
274 redirect_to :action => 'list_news', :id => @project
278 redirect_to :action => 'list_news', :id => @project
275 end
279 end
276 end
280 end
277 end
281 end
278
282
279 # Show news list of @project
283 # Show news list of @project
280 def list_news
284 def list_news
281 @news_pages, @news = paginate :news, :per_page => 10, :conditions => ["project_id=?", @project.id], :include => :author, :order => "news.created_on DESC"
285 @news_pages, @news = paginate :news, :per_page => 10, :conditions => ["project_id=?", @project.id], :include => :author, :order => "news.created_on DESC"
286 render :action => "list_news", :layout => false if request.xhr?
282 end
287 end
283
288
284 def add_file
289 def add_file
285 if request.post?
290 if request.post?
286 # Save the attachment
291 # Save the attachment
287 if params[:attachment][:file].size > 0
292 if params[:attachment][:file].size > 0
288 @attachment = @project.versions.find(params[:version_id]).attachments.build(params[:attachment])
293 @attachment = @project.versions.find(params[:version_id]).attachments.build(params[:attachment])
289 @attachment.author_id = self.logged_in_user.id if self.logged_in_user
294 @attachment.author_id = self.logged_in_user.id if self.logged_in_user
290 if @attachment.save
295 if @attachment.save
291 flash[:notice] = l(:notice_successful_create)
296 flash[:notice] = l(:notice_successful_create)
292 redirect_to :controller => 'projects', :action => 'list_files', :id => @project
297 redirect_to :controller => 'projects', :action => 'list_files', :id => @project
293 end
298 end
294 end
299 end
295 end
300 end
296 @versions = @project.versions
301 @versions = @project.versions
297 end
302 end
298
303
299 def list_files
304 def list_files
300 @versions = @project.versions
305 @versions = @project.versions
301 end
306 end
302
307
303 # Show changelog for @project
308 # Show changelog for @project
304 def changelog
309 def changelog
305 @trackers = Tracker.find(:all, :conditions => ["is_in_chlog=?", true])
310 @trackers = Tracker.find(:all, :conditions => ["is_in_chlog=?", true])
306 if request.get?
311 if request.get?
307 @selected_tracker_ids = @trackers.collect {|t| t.id.to_s }
312 @selected_tracker_ids = @trackers.collect {|t| t.id.to_s }
308 else
313 else
309 @selected_tracker_ids = params[:tracker_ids].collect { |id| id.to_i.to_s } if params[:tracker_ids] and params[:tracker_ids].is_a? Array
314 @selected_tracker_ids = params[:tracker_ids].collect { |id| id.to_i.to_s } if params[:tracker_ids] and params[:tracker_ids].is_a? Array
310 end
315 end
311 @selected_tracker_ids ||= []
316 @selected_tracker_ids ||= []
312 @fixed_issues = @project.issues.find(:all,
317 @fixed_issues = @project.issues.find(:all,
313 :include => [ :fixed_version, :status, :tracker ],
318 :include => [ :fixed_version, :status, :tracker ],
314 :conditions => [ "issue_statuses.is_closed=? and issues.tracker_id in (#{@selected_tracker_ids.join(',')}) and issues.fixed_version_id is not null", true],
319 :conditions => [ "issue_statuses.is_closed=? and issues.tracker_id in (#{@selected_tracker_ids.join(',')}) and issues.fixed_version_id is not null", true],
315 :order => "versions.effective_date DESC, issues.id DESC"
320 :order => "versions.effective_date DESC, issues.id DESC"
316 ) unless @selected_tracker_ids.empty?
321 ) unless @selected_tracker_ids.empty?
317 @fixed_issues ||= []
322 @fixed_issues ||= []
318 end
323 end
319
324
320 private
325 private
321 # Find project of id params[:id]
326 # Find project of id params[:id]
322 # if not found, redirect to project list
327 # if not found, redirect to project list
323 # Used as a before_filter
328 # Used as a before_filter
324 def find_project
329 def find_project
325 @project = Project.find(params[:id])
330 @project = Project.find(params[:id])
326 rescue
331 rescue
327 redirect_to :action => 'list'
332 redirect_to :action => 'list'
328 end
333 end
329 end
334 end
@@ -1,83 +1,84
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 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 RolesController < ApplicationController
18 class RolesController < ApplicationController
19 layout 'base'
19 layout 'base'
20 before_filter :require_admin
20 before_filter :require_admin
21
21
22 def index
22 def index
23 list
23 list
24 render :action => 'list'
24 render :action => 'list' unless request.xhr?
25 end
25 end
26
26
27 def list
27 def list
28 @role_pages, @roles = paginate :roles, :per_page => 10
28 @role_pages, @roles = paginate :roles, :per_page => 10
29 render :action => "list", :layout => false if request.xhr?
29 end
30 end
30
31
31 def new
32 def new
32 @role = Role.new(params[:role])
33 @role = Role.new(params[:role])
33 if request.post?
34 if request.post?
34 @role.permissions = Permission.find(@params[:permission_ids]) if @params[:permission_ids]
35 @role.permissions = Permission.find(@params[:permission_ids]) if @params[:permission_ids]
35 if @role.save
36 if @role.save
36 flash[:notice] = l(:notice_successful_create)
37 flash[:notice] = l(:notice_successful_create)
37 redirect_to :action => 'list'
38 redirect_to :action => 'list'
38 end
39 end
39 end
40 end
40 @permissions = Permission.find(:all, :conditions => ["is_public=?", false], :order => 'sort ASC')
41 @permissions = Permission.find(:all, :conditions => ["is_public=?", false], :order => 'sort ASC')
41 end
42 end
42
43
43 def edit
44 def edit
44 @role = Role.find(params[:id])
45 @role = Role.find(params[:id])
45 if request.post? and @role.update_attributes(params[:role])
46 if request.post? and @role.update_attributes(params[:role])
46 @role.permissions = Permission.find(@params[:permission_ids] || [])
47 @role.permissions = Permission.find(@params[:permission_ids] || [])
47 Permission.allowed_to_role_expired
48 Permission.allowed_to_role_expired
48 flash[:notice] = l(:notice_successful_update)
49 flash[:notice] = l(:notice_successful_update)
49 redirect_to :action => 'list'
50 redirect_to :action => 'list'
50 end
51 end
51 @permissions = Permission.find(:all, :conditions => ["is_public=?", false], :order => 'sort ASC')
52 @permissions = Permission.find(:all, :conditions => ["is_public=?", false], :order => 'sort ASC')
52 end
53 end
53
54
54 def destroy
55 def destroy
55 @role = Role.find(params[:id])
56 @role = Role.find(params[:id])
56 unless @role.members.empty?
57 unless @role.members.empty?
57 flash[:notice] = 'Some members have this role. Can\'t delete it.'
58 flash[:notice] = 'Some members have this role. Can\'t delete it.'
58 else
59 else
59 @role.destroy
60 @role.destroy
60 end
61 end
61 redirect_to :action => 'list'
62 redirect_to :action => 'list'
62 end
63 end
63
64
64 def workflow
65 def workflow
65 @role = Role.find_by_id(params[:role_id])
66 @role = Role.find_by_id(params[:role_id])
66 @tracker = Tracker.find_by_id(params[:tracker_id])
67 @tracker = Tracker.find_by_id(params[:tracker_id])
67
68
68 if request.post?
69 if request.post?
69 Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id])
70 Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id])
70 (params[:issue_status] || []).each { |old, news|
71 (params[:issue_status] || []).each { |old, news|
71 news.each { |new|
72 news.each { |new|
72 @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new)
73 @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new)
73 }
74 }
74 }
75 }
75 if @role.save
76 if @role.save
76 flash[:notice] = l(:notice_successful_update)
77 flash[:notice] = l(:notice_successful_update)
77 end
78 end
78 end
79 end
79 @roles = Role.find_all
80 @roles = Role.find_all
80 @trackers = Tracker.find_all
81 @trackers = Tracker.find_all
81 @statuses = IssueStatus.find(:all, :include => :workflows)
82 @statuses = IssueStatus.find(:all, :include => :workflows)
82 end
83 end
83 end
84 end
@@ -1,60 +1,61
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 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 TrackersController < ApplicationController
18 class TrackersController < ApplicationController
19 layout 'base'
19 layout 'base'
20 before_filter :require_admin
20 before_filter :require_admin
21
21
22 def index
22 def index
23 list
23 list
24 render :action => 'list'
24 render :action => 'list' unless request.xhr?
25 end
25 end
26
26
27 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
27 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
28 verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :list }
28 verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :list }
29
29
30 def list
30 def list
31 @tracker_pages, @trackers = paginate :trackers, :per_page => 10
31 @tracker_pages, @trackers = paginate :trackers, :per_page => 10
32 render :action => "list", :layout => false if request.xhr?
32 end
33 end
33
34
34 def new
35 def new
35 @tracker = Tracker.new(params[:tracker])
36 @tracker = Tracker.new(params[:tracker])
36 if request.post? and @tracker.save
37 if request.post? and @tracker.save
37 flash[:notice] = l(:notice_successful_create)
38 flash[:notice] = l(:notice_successful_create)
38 redirect_to :action => 'list'
39 redirect_to :action => 'list'
39 end
40 end
40 end
41 end
41
42
42 def edit
43 def edit
43 @tracker = Tracker.find(params[:id])
44 @tracker = Tracker.find(params[:id])
44 if request.post? and @tracker.update_attributes(params[:tracker])
45 if request.post? and @tracker.update_attributes(params[:tracker])
45 flash[:notice] = l(:notice_successful_update)
46 flash[:notice] = l(:notice_successful_update)
46 redirect_to :action => 'list'
47 redirect_to :action => 'list'
47 end
48 end
48 end
49 end
49
50
50 def destroy
51 def destroy
51 @tracker = Tracker.find(params[:id])
52 @tracker = Tracker.find(params[:id])
52 unless @tracker.issues.empty?
53 unless @tracker.issues.empty?
53 flash[:notice] = "This tracker contains issues and can\'t be deleted."
54 flash[:notice] = "This tracker contains issues and can\'t be deleted."
54 else
55 else
55 @tracker.destroy
56 @tracker.destroy
56 end
57 end
57 redirect_to :action => 'list'
58 redirect_to :action => 'list'
58 end
59 end
59
60
60 end
61 end
@@ -1,88 +1,90
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 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 UsersController < ApplicationController
18 class UsersController < ApplicationController
19 layout 'base'
19 layout 'base'
20 before_filter :require_admin
20 before_filter :require_admin
21
21
22 helper :sort
22 helper :sort
23 include SortHelper
23 include SortHelper
24 helper :custom_fields
24 helper :custom_fields
25 include CustomFieldsHelper
25 include CustomFieldsHelper
26
26
27 def index
27 def index
28 list
28 list
29 render :action => 'list'
29 render :action => 'list' unless request.xhr?
30 end
30 end
31
31
32 def list
32 def list
33 sort_init 'login', 'asc'
33 sort_init 'login', 'asc'
34 sort_update
34 sort_update
35 @user_count = User.count
35 @user_count = User.count
36 @user_pages = Paginator.new self, @user_count,
36 @user_pages = Paginator.new self, @user_count,
37 15,
37 15,
38 @params['page']
38 @params['page']
39 @users = User.find :all,:order => sort_clause,
39 @users = User.find :all,:order => sort_clause,
40 :limit => @user_pages.items_per_page,
40 :limit => @user_pages.items_per_page,
41 :offset => @user_pages.current.offset
41 :offset => @user_pages.current.offset
42
43 render :action => "list", :layout => false if request.xhr?
42 end
44 end
43
45
44 def add
46 def add
45 if request.get?
47 if request.get?
46 @user = User.new(:language => $RDM_DEFAULT_LANG)
48 @user = User.new(:language => $RDM_DEFAULT_LANG)
47 @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) }
49 @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) }
48 else
50 else
49 @user = User.new(params[:user])
51 @user = User.new(params[:user])
50 @user.admin = params[:user][:admin] || false
52 @user.admin = params[:user][:admin] || false
51 @user.login = params[:user][:login]
53 @user.login = params[:user][:login]
52 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
54 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
53 @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) }
55 @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) }
54 @user.custom_values = @custom_values
56 @user.custom_values = @custom_values
55 if @user.save
57 if @user.save
56 flash[:notice] = l(:notice_successful_create)
58 flash[:notice] = l(:notice_successful_create)
57 redirect_to :action => 'list'
59 redirect_to :action => 'list'
58 end
60 end
59 end
61 end
60 end
62 end
61
63
62 def edit
64 def edit
63 @user = User.find(params[:id])
65 @user = User.find(params[:id])
64 if request.get?
66 if request.get?
65 @custom_values = UserCustomField.find(:all).collect { |x| @user.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
67 @custom_values = UserCustomField.find(:all).collect { |x| @user.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
66 else
68 else
67 @user.admin = params[:user][:admin] if params[:user][:admin]
69 @user.admin = params[:user][:admin] if params[:user][:admin]
68 @user.login = params[:user][:login] if params[:user][:login]
70 @user.login = params[:user][:login] if params[:user][:login]
69 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless params[:password].nil? or params[:password].empty?
71 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless params[:password].nil? or params[:password].empty?
70 if params[:custom_fields]
72 if params[:custom_fields]
71 @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) }
73 @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) }
72 @user.custom_values = @custom_values
74 @user.custom_values = @custom_values
73 end
75 end
74 if @user.update_attributes(params[:user])
76 if @user.update_attributes(params[:user])
75 flash[:notice] = l(:notice_successful_update)
77 flash[:notice] = l(:notice_successful_update)
76 redirect_to :action => 'list'
78 redirect_to :action => 'list'
77 end
79 end
78 end
80 end
79 end
81 end
80
82
81 def destroy
83 def destroy
82 User.find(params[:id]).destroy
84 User.find(params[:id]).destroy
83 redirect_to :action => 'list'
85 redirect_to :action => 'list'
84 rescue
86 rescue
85 flash[:notice] = "Unable to delete user"
87 flash[:notice] = "Unable to delete user"
86 redirect_to :action => 'list'
88 redirect_to :action => 'list'
87 end
89 end
88 end
90 end
@@ -1,161 +1,171
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 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 ApplicationHelper
18 module ApplicationHelper
19
19
20 # Return current logged in user or nil
20 # Return current logged in user or nil
21 def loggedin?
21 def loggedin?
22 @logged_in_user
22 @logged_in_user
23 end
23 end
24
24
25 # Return true if user is logged in and is admin, otherwise false
25 # Return true if user is logged in and is admin, otherwise false
26 def admin_loggedin?
26 def admin_loggedin?
27 @logged_in_user and @logged_in_user.admin?
27 @logged_in_user and @logged_in_user.admin?
28 end
28 end
29
29
30 # Return true if user is authorized for controller/action, otherwise false
30 # Return true if user is authorized for controller/action, otherwise false
31 def authorize_for(controller, action)
31 def authorize_for(controller, action)
32 # check if action is allowed on public projects
32 # check if action is allowed on public projects
33 if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ controller, action ]
33 if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ controller, action ]
34 return true
34 return true
35 end
35 end
36 # check if user is authorized
36 # check if user is authorized
37 if @logged_in_user and (@logged_in_user.admin? or Permission.allowed_to_role( "%s/%s" % [ controller, action ], @logged_in_user.role_for_project(@project.id) ) )
37 if @logged_in_user and (@logged_in_user.admin? or Permission.allowed_to_role( "%s/%s" % [ controller, action ], @logged_in_user.role_for_project(@project.id) ) )
38 return true
38 return true
39 end
39 end
40 return false
40 return false
41 end
41 end
42
42
43 # Display a link if user is authorized
43 # Display a link if user is authorized
44 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
44 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
45 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller], options[:action])
45 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller], options[:action])
46 end
46 end
47
47
48 # Display a link to user's account page
48 # Display a link to user's account page
49 def link_to_user(user)
49 def link_to_user(user)
50 link_to user.display_name, :controller => 'account', :action => 'show', :id => user
50 link_to user.display_name, :controller => 'account', :action => 'show', :id => user
51 end
51 end
52
52
53 def format_date(date)
53 def format_date(date)
54 l_date(date) if date
54 l_date(date) if date
55 end
55 end
56
56
57 def format_time(time)
57 def format_time(time)
58 l_datetime(time) if time
58 l_datetime(time) if time
59 end
59 end
60
60
61 def pagination_links_full(paginator, options={}, html_options={})
61 def pagination_links_full(paginator, options={}, html_options={})
62 html =''
62 html = ''
63 html << link_to(('&#171; ' + l(:label_previous) ), { :page => paginator.current.previous }) + ' ' if paginator.current.previous
63 html << link_to_remote(('&#171; ' + l(:label_previous)),
64 html << (pagination_links(paginator, options, html_options) || '')
64 {:update => "content", :url => { :page => paginator.current.previous }},
65 html << ' ' + link_to((l(:label_next) + ' &#187;'), { :page => paginator.current.next }) if paginator.current.next
65 {:href => url_for(:action => 'list', :params => @params.merge({:page => paginator.current.previous}))}) + ' ' if paginator.current.previous
66
67 html << (pagination_links_each(paginator, options) do |n|
68 link_to_remote(n.to_s,
69 {:url => {:action => 'list', :params => @params.merge({:page => n})}, :update => 'content'},
70 {:href => url_for(:action => 'list', :params => @params.merge({:page => n}))})
71 end || '')
72
73 html << ' ' + link_to_remote((l(:label_next) + ' &#187;'),
74 {:update => "content", :url => { :page => paginator.current.next }},
75 {:href => url_for(:action => 'list', :params => @params.merge({:page => paginator.current.next}))}) if paginator.current.next
66 html
76 html
67 end
77 end
68
78
69 def error_messages_for(object_name, options = {})
79 def error_messages_for(object_name, options = {})
70 options = options.symbolize_keys
80 options = options.symbolize_keys
71 object = instance_variable_get("@#{object_name}")
81 object = instance_variable_get("@#{object_name}")
72 if object && !object.errors.empty?
82 if object && !object.errors.empty?
73 # build full_messages here with controller current language
83 # build full_messages here with controller current language
74 full_messages = []
84 full_messages = []
75 object.errors.each do |attr, msg|
85 object.errors.each do |attr, msg|
76 next if msg.nil?
86 next if msg.nil?
77 if attr == "base"
87 if attr == "base"
78 full_messages << l(msg)
88 full_messages << l(msg)
79 else
89 else
80 full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values"
90 full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values"
81 end
91 end
82 end
92 end
83 # retrieve custom values error messages
93 # retrieve custom values error messages
84 if object.errors[:custom_values]
94 if object.errors[:custom_values]
85 object.custom_values.each do |v|
95 object.custom_values.each do |v|
86 v.errors.each do |attr, msg|
96 v.errors.each do |attr, msg|
87 next if msg.nil?
97 next if msg.nil?
88 full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
98 full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
89 end
99 end
90 end
100 end
91 end
101 end
92 content_tag("div",
102 content_tag("div",
93 content_tag(
103 content_tag(
94 options[:header_tag] || "h2", lwr(:gui_validation_error, full_messages.length) + " :"
104 options[:header_tag] || "h2", lwr(:gui_validation_error, full_messages.length) + " :"
95 ) +
105 ) +
96 content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
106 content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
97 "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
107 "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
98 )
108 )
99 else
109 else
100 ""
110 ""
101 end
111 end
102 end
112 end
103
113
104 def lang_options_for_select
114 def lang_options_for_select
105 (GLoc.valid_languages.sort {|x,y| x.to_s <=> y.to_s }).collect {|lang| [ l_lang_name(lang.to_s, lang), lang.to_s]}
115 (GLoc.valid_languages.sort {|x,y| x.to_s <=> y.to_s }).collect {|lang| [ l_lang_name(lang.to_s, lang), lang.to_s]}
106 end
116 end
107
117
108 def label_tag_for(name, option_tags = nil, options = {})
118 def label_tag_for(name, option_tags = nil, options = {})
109 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
119 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
110 content_tag("label", label_text)
120 content_tag("label", label_text)
111 end
121 end
112
122
113 def labelled_tabular_form_for(name, object, options, &proc)
123 def labelled_tabular_form_for(name, object, options, &proc)
114 options[:html] ||= {}
124 options[:html] ||= {}
115 options[:html].store :class, "tabular"
125 options[:html].store :class, "tabular"
116 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
126 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
117 end
127 end
118
128
119 def check_all_links(form_name)
129 def check_all_links(form_name)
120 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
130 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
121 " | " +
131 " | " +
122 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
132 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
123 end
133 end
124
134
125 def calendar_for(field_id)
135 def calendar_for(field_id)
126 image_tag("calendar", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
136 image_tag("calendar", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
127 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
137 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
128 end
138 end
129 end
139 end
130
140
131 class TabularFormBuilder < ActionView::Helpers::FormBuilder
141 class TabularFormBuilder < ActionView::Helpers::FormBuilder
132 include GLoc
142 include GLoc
133
143
134 def initialize(object_name, object, template, options, proc)
144 def initialize(object_name, object, template, options, proc)
135 set_language_if_valid options.delete(:lang)
145 set_language_if_valid options.delete(:lang)
136 @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
146 @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
137 end
147 end
138
148
139 (field_helpers - %w(radio_button hidden_field) + %w(date_select)).each do |selector|
149 (field_helpers - %w(radio_button hidden_field) + %w(date_select)).each do |selector|
140 src = <<-END_SRC
150 src = <<-END_SRC
141 def #{selector}(field, options = {})
151 def #{selector}(field, options = {})
142 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
152 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
143 label = @template.content_tag("label", label_text,
153 label = @template.content_tag("label", label_text,
144 :class => (@object.errors[field] ? "error" : nil),
154 :class => (@object.errors[field] ? "error" : nil),
145 :for => (@object_name.to_s + "_" + field.to_s))
155 :for => (@object_name.to_s + "_" + field.to_s))
146 label + super
156 label + super
147 end
157 end
148 END_SRC
158 END_SRC
149 class_eval src, __FILE__, __LINE__
159 class_eval src, __FILE__, __LINE__
150 end
160 end
151
161
152 def select(field, choices, options = {})
162 def select(field, choices, options = {})
153 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
163 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
154 label = @template.content_tag("label", label_text,
164 label = @template.content_tag("label", label_text,
155 :class => (@object.errors[field] ? "error" : nil),
165 :class => (@object.errors[field] ? "error" : nil),
156 :for => (@object_name.to_s + "_" + field.to_s))
166 :for => (@object_name.to_s + "_" + field.to_s))
157 label + super
167 label + super
158 end
168 end
159
169
160 end
170 end
161
171
@@ -1,157 +1,160
1 # Helpers to sort tables using clickable column headers.
1 # Helpers to sort tables using clickable column headers.
2 #
2 #
3 # Author: Stuart Rackham <srackham@methods.co.nz>, March 2005.
3 # Author: Stuart Rackham <srackham@methods.co.nz>, March 2005.
4 # License: This source code is released under the MIT license.
4 # License: This source code is released under the MIT license.
5 #
5 #
6 # - Consecutive clicks toggle the column's sort order.
6 # - Consecutive clicks toggle the column's sort order.
7 # - Sort state is maintained by a session hash entry.
7 # - Sort state is maintained by a session hash entry.
8 # - Icon image identifies sort column and state.
8 # - Icon image identifies sort column and state.
9 # - Typically used in conjunction with the Pagination module.
9 # - Typically used in conjunction with the Pagination module.
10 #
10 #
11 # Example code snippets:
11 # Example code snippets:
12 #
12 #
13 # Controller:
13 # Controller:
14 #
14 #
15 # helper :sort
15 # helper :sort
16 # include SortHelper
16 # include SortHelper
17 #
17 #
18 # def list
18 # def list
19 # sort_init 'last_name'
19 # sort_init 'last_name'
20 # sort_update
20 # sort_update
21 # @items = Contact.find_all nil, sort_clause
21 # @items = Contact.find_all nil, sort_clause
22 # end
22 # end
23 #
23 #
24 # Controller (using Pagination module):
24 # Controller (using Pagination module):
25 #
25 #
26 # helper :sort
26 # helper :sort
27 # include SortHelper
27 # include SortHelper
28 #
28 #
29 # def list
29 # def list
30 # sort_init 'last_name'
30 # sort_init 'last_name'
31 # sort_update
31 # sort_update
32 # @contact_pages, @items = paginate :contacts,
32 # @contact_pages, @items = paginate :contacts,
33 # :order_by => sort_clause,
33 # :order_by => sort_clause,
34 # :per_page => 10
34 # :per_page => 10
35 # end
35 # end
36 #
36 #
37 # View (table header in list.rhtml):
37 # View (table header in list.rhtml):
38 #
38 #
39 # <thead>
39 # <thead>
40 # <tr>
40 # <tr>
41 # <%= sort_header_tag('id', :title => 'Sort by contact ID') %>
41 # <%= sort_header_tag('id', :title => 'Sort by contact ID') %>
42 # <%= sort_header_tag('last_name', :caption => 'Name') %>
42 # <%= sort_header_tag('last_name', :caption => 'Name') %>
43 # <%= sort_header_tag('phone') %>
43 # <%= sort_header_tag('phone') %>
44 # <%= sort_header_tag('address', :width => 200) %>
44 # <%= sort_header_tag('address', :width => 200) %>
45 # </tr>
45 # </tr>
46 # </thead>
46 # </thead>
47 #
47 #
48 # - The ascending and descending sort icon images are sort_asc.png and
48 # - The ascending and descending sort icon images are sort_asc.png and
49 # sort_desc.png and reside in the application's images directory.
49 # sort_desc.png and reside in the application's images directory.
50 # - Introduces instance variables: @sort_name, @sort_default.
50 # - Introduces instance variables: @sort_name, @sort_default.
51 # - Introduces params :sort_key and :sort_order.
51 # - Introduces params :sort_key and :sort_order.
52 #
52 #
53 module SortHelper
53 module SortHelper
54
54
55 # Initializes the default sort column (default_key) and sort order
55 # Initializes the default sort column (default_key) and sort order
56 # (default_order).
56 # (default_order).
57 #
57 #
58 # - default_key is a column attribute name.
58 # - default_key is a column attribute name.
59 # - default_order is 'asc' or 'desc'.
59 # - default_order is 'asc' or 'desc'.
60 # - name is the name of the session hash entry that stores the sort state,
60 # - name is the name of the session hash entry that stores the sort state,
61 # defaults to '<controller_name>_sort'.
61 # defaults to '<controller_name>_sort'.
62 #
62 #
63 def sort_init(default_key, default_order='asc', name=nil)
63 def sort_init(default_key, default_order='asc', name=nil)
64 @sort_name = name || @params[:controller] + @params[:action] + '_sort'
64 @sort_name = name || @params[:controller] + @params[:action] + '_sort'
65 @sort_default = {:key => default_key, :order => default_order}
65 @sort_default = {:key => default_key, :order => default_order}
66 end
66 end
67
67
68 # Updates the sort state. Call this in the controller prior to calling
68 # Updates the sort state. Call this in the controller prior to calling
69 # sort_clause.
69 # sort_clause.
70 #
70 #
71 def sort_update()
71 def sort_update()
72 if @params[:sort_key]
72 if @params[:sort_key]
73 sort = {:key => @params[:sort_key], :order => @params[:sort_order]}
73 sort = {:key => @params[:sort_key], :order => @params[:sort_order]}
74 elsif @session[@sort_name]
74 elsif @session[@sort_name]
75 sort = @session[@sort_name] # Previous sort.
75 sort = @session[@sort_name] # Previous sort.
76 else
76 else
77 sort = @sort_default
77 sort = @sort_default
78 end
78 end
79 @session[@sort_name] = sort
79 @session[@sort_name] = sort
80 end
80 end
81
81
82 # Returns an SQL sort clause corresponding to the current sort state.
82 # Returns an SQL sort clause corresponding to the current sort state.
83 # Use this to sort the controller's table items collection.
83 # Use this to sort the controller's table items collection.
84 #
84 #
85 def sort_clause()
85 def sort_clause()
86 @session[@sort_name][:key] + ' ' + @session[@sort_name][:order]
86 @session[@sort_name][:key] + ' ' + @session[@sort_name][:order]
87 end
87 end
88
88
89 # Returns a link which sorts by the named column.
89 # Returns a link which sorts by the named column.
90 #
90 #
91 # - column is the name of an attribute in the sorted record collection.
91 # - column is the name of an attribute in the sorted record collection.
92 # - The optional caption explicitly specifies the displayed link text.
92 # - The optional caption explicitly specifies the displayed link text.
93 # - A sort icon image is positioned to the right of the sort link.
93 # - A sort icon image is positioned to the right of the sort link.
94 #
94 #
95 def sort_link(column, caption=nil)
95 def sort_link(column, caption=nil)
96 key, order = @session[@sort_name][:key], @session[@sort_name][:order]
96 key, order = @session[@sort_name][:key], @session[@sort_name][:order]
97 if key == column
97 if key == column
98 if order.downcase == 'asc'
98 if order.downcase == 'asc'
99 icon = 'sort_asc'
99 icon = 'sort_asc'
100 order = 'desc'
100 order = 'desc'
101 else
101 else
102 icon = 'sort_desc'
102 icon = 'sort_desc'
103 order = 'asc'
103 order = 'asc'
104 end
104 end
105 else
105 else
106 icon = nil
106 icon = nil
107 order = 'desc' # changed for desc order by default
107 order = 'desc' # changed for desc order by default
108 end
108 end
109 caption = titleize(Inflector::humanize(column)) unless caption
109 caption = titleize(Inflector::humanize(column)) unless caption
110 params = {:params => {:sort_key => column, :sort_order => order}}
110 params = {:params => {:sort_key => column, :sort_order => order}}
111 link_to(caption, params) + (icon ? nbsp(2) + image_tag(icon) : '')
111 link_to_remote(caption,
112 {:update => "content", :url => { :sort_key => column, :sort_order => order}},
113 {:href => url_for(:params => { :sort_key => column, :sort_order => order})}) +
114 (icon ? nbsp(2) + image_tag(icon) : '')
112 end
115 end
113
116
114 # Returns a table header <th> tag with a sort link for the named column
117 # Returns a table header <th> tag with a sort link for the named column
115 # attribute.
118 # attribute.
116 #
119 #
117 # Options:
120 # Options:
118 # :caption The displayed link name (defaults to titleized column name).
121 # :caption The displayed link name (defaults to titleized column name).
119 # :title The tag's 'title' attribute (defaults to 'Sort by :caption').
122 # :title The tag's 'title' attribute (defaults to 'Sort by :caption').
120 #
123 #
121 # Other options hash entries generate additional table header tag attributes.
124 # Other options hash entries generate additional table header tag attributes.
122 #
125 #
123 # Example:
126 # Example:
124 #
127 #
125 # <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %>
128 # <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %>
126 #
129 #
127 # Renders:
130 # Renders:
128 #
131 #
129 # <th title="Sort by contact ID" width="40">
132 # <th title="Sort by contact ID" width="40">
130 # <a href="/contact/list?sort_order=desc&amp;sort_key=id">Id</a>
133 # <a href="/contact/list?sort_order=desc&amp;sort_key=id">Id</a>
131 # &nbsp;&nbsp;<img alt="Sort_asc" src="/images/sort_asc.png" />
134 # &nbsp;&nbsp;<img alt="Sort_asc" src="/images/sort_asc.png" />
132 # </th>
135 # </th>
133 #
136 #
134 def sort_header_tag(column, options = {})
137 def sort_header_tag(column, options = {})
135 if options[:caption]
138 if options[:caption]
136 caption = options[:caption]
139 caption = options[:caption]
137 options.delete(:caption)
140 options.delete(:caption)
138 else
141 else
139 caption = titleize(Inflector::humanize(column))
142 caption = titleize(Inflector::humanize(column))
140 end
143 end
141 options[:title]= "Sort by #{caption}" unless options[:title]
144 options[:title]= "Sort by #{caption}" unless options[:title]
142 content_tag('th', sort_link(column, caption), options)
145 content_tag('th', sort_link(column, caption), options)
143 end
146 end
144
147
145 private
148 private
146
149
147 # Return n non-breaking spaces.
150 # Return n non-breaking spaces.
148 def nbsp(n)
151 def nbsp(n)
149 '&nbsp;' * n
152 '&nbsp;' * n
150 end
153 end
151
154
152 # Return capitalized title.
155 # Return capitalized title.
153 def titleize(title)
156 def titleize(title)
154 title.split.map {|w| w.capitalize }.join(' ')
157 title.split.map {|w| w.capitalize }.join(' ')
155 end
158 end
156
159
157 end
160 end
@@ -1,30 +1,30
1 <h2><%=l(:label_auth_source_plural)%></h2>
1 <h2><%=l(:label_auth_source_plural)%></h2>
2
2
3 <table class="listTableContent">
3 <table class="listTableContent">
4 <tr class="ListHead">
4 <tr class="ListHead">
5 <td><%=l(:field_name)%></td>
5 <th><%=l(:field_name)%></th>
6 <td><%=l(:field_type)%></td>
6 <th><%=l(:field_type)%></th>
7 <td><%=l(:field_host)%></td>
7 <th><%=l(:field_host)%></th>
8 <td></td>
8 <th></th>
9 <td></td>
9 <th></th>
10 </tr>
10 </tr>
11
11
12 <% for source in @auth_sources %>
12 <% for source in @auth_sources %>
13 <tr class="<%= cycle("odd", "even") %>">
13 <tr class="<%= cycle("odd", "even") %>">
14 <td><%= link_to source.name, :action => 'edit', :id => source%></td>
14 <td><%= link_to source.name, :action => 'edit', :id => source%></td>
15 <td align="center"><%= source.auth_method_name %></td>
15 <td align="center"><%= source.auth_method_name %></td>
16 <td align="center"><%= source.host %></td>
16 <td align="center"><%= source.host %></td>
17 <td align="center">
17 <td align="center">
18 <%= link_to l(:button_test), :action => 'test_connection', :id => source %>
18 <%= link_to l(:button_test), :action => 'test_connection', :id => source %>
19 </td>
19 </td>
20 <td align="center">
20 <td align="center">
21 <%= button_to l(:button_delete), { :action => 'destroy', :id => source }, :confirm => l(:text_are_you_sure), :class => "button-small" %>
21 <%= button_to l(:button_delete), { :action => 'destroy', :id => source }, :confirm => l(:text_are_you_sure), :class => "button-small" %>
22 </td>
22 </td>
23 </tr>
23 </tr>
24 <% end %>
24 <% end %>
25 </table>
25 </table>
26
26
27 <%= pagination_links_full @auth_source_pages %>
27 <%= pagination_links_full @auth_source_pages %>
28 <br />
28 <br />
29 <%= link_to '&#187; ' + l(:label_auth_source_new), :action => 'new' %>
29 <%= link_to '&#187; ' + l(:label_auth_source_new), :action => 'new' %>
30
30
@@ -1,60 +1,60
1 <h2><%=l(:label_issue_plural)%></h2>
1 <h2><%=l(:label_issue_plural)%></h2>
2
2
3 <form method="post" class="noborder">
3 <form method="post" class="noborder">
4 <table cellpadding=2>
4 <table cellpadding=2>
5 <tr>
5 <tr>
6 <td><small><%=l(:field_status)%>:</small><br /><%= search_filter_tag 'status_id', :class => 'select-small' %></td>
6 <td><small><%=l(:field_status)%>:</small><br /><%= search_filter_tag 'status_id', :class => 'select-small' %></td>
7 <td><small><%=l(:field_tracker)%>:</small><br /><%= search_filter_tag 'tracker_id', :class => 'select-small' %></td>
7 <td><small><%=l(:field_tracker)%>:</small><br /><%= search_filter_tag 'tracker_id', :class => 'select-small' %></td>
8 <td><small><%=l(:field_priority)%>:</small><br /><%= search_filter_tag 'priority_id', :class => 'select-small' %></td>
8 <td><small><%=l(:field_priority)%>:</small><br /><%= search_filter_tag 'priority_id', :class => 'select-small' %></td>
9 <td><small><%=l(:field_category)%>:</small><br /><%= search_filter_tag 'category_id', :class => 'select-small' %></td>
9 <td><small><%=l(:field_category)%>:</small><br /><%= search_filter_tag 'category_id', :class => 'select-small' %></td>
10 <td><small><%=l(:field_fixed_version)%>:</small><br /><%= search_filter_tag 'fixed_version_id', :class => 'select-small' %></td>
10 <td><small><%=l(:field_fixed_version)%>:</small><br /><%= search_filter_tag 'fixed_version_id', :class => 'select-small' %></td>
11 <td><small><%=l(:field_assigned_to)%>:</small><br /><%= search_filter_tag 'assigned_to_id', :class => 'select-small' %></td>
11 <td><small><%=l(:field_assigned_to)%>:</small><br /><%= search_filter_tag 'assigned_to_id', :class => 'select-small' %></td>
12 <td><small><%=l(:label_subproject_plural)%>:</small><br /><%= search_filter_tag 'subproject_id', :class => 'select-small' %></td>
12 <td><small><%=l(:label_subproject_plural)%>:</small><br /><%= search_filter_tag 'subproject_id', :class => 'select-small' %></td>
13
14 <td valign="bottom">
13 <td valign="bottom">
14 <%= hidden_field_tag 'set_filter', 1 %>
15 <%= submit_tag l(:button_apply), :class => 'button-small' %>
15 <%= submit_tag l(:button_apply), :class => 'button-small' %>
16 <%= end_form_tag %>
16 </td>
17
17 <td valign="bottom">
18 <%= start_form_tag %>
18 <%= link_to l(:button_clear), :action => 'list_issues', :id => @project, :set_filter => 1 %>
19 <%= submit_tag l(:button_clear), :class => 'button-small' %>
20 <%= end_form_tag %>
21 </td>
19 </td>
22 </tr>
20 </tr>
23 </table>
21 </table>
22 <%= end_form_tag %>
23
24 &nbsp;
24 &nbsp;
25
25
26 <%= start_form_tag ({:controller => 'projects', :action => 'move_issues', :id => @project}, :id => 'issues_form' ) %>
26 <%= start_form_tag ({:controller => 'projects', :action => 'move_issues', :id => @project}, :id => 'issues_form' ) %>
27 <table class="listTableContent">
27 <table class="listTableContent">
28 <tr>
28 <tr>
29 <td colspan="6" align="left"><small><%= check_all_links 'issues_form' %></small></td>
29 <td colspan="6" align="left"><small><%= check_all_links 'issues_form' %></small></td>
30 <td colspan="2" align="right"><small><%= link_to l(:label_export_csv), :action => 'export_issues_csv', :id => @project.id %></small></td>
30 <td colspan="2" align="right"><small><%= link_to l(:label_export_csv), :action => 'export_issues_csv', :id => @project.id %></small></td>
31 </tr>
31 </tr>
32 <tr class="ListHead">
32 <tr class="ListHead">
33 <td></td>
33 <td></td>
34 <%= sort_header_tag('issues.id', :caption => '#') %>
34 <%= sort_header_tag('issues.id', :caption => '#') %>
35 <%= sort_header_tag('issue_statuses.name', :caption => l(:field_status)) %>
35 <%= sort_header_tag('issue_statuses.name', :caption => l(:field_status)) %>
36 <%= sort_header_tag('issues.tracker_id', :caption => l(:field_tracker)) %>
36 <%= sort_header_tag('issues.tracker_id', :caption => l(:field_tracker)) %>
37 <th><%=l(:field_subject)%></th>
37 <th><%=l(:field_subject)%></th>
38 <%= sort_header_tag('users.lastname', :caption => l(:field_author)) %>
38 <%= sort_header_tag('users.lastname', :caption => l(:field_author)) %>
39 <%= sort_header_tag('issues.created_on', :caption => l(:field_created_on)) %>
39 <%= sort_header_tag('issues.created_on', :caption => l(:field_created_on)) %>
40 <%= sort_header_tag('issues.updated_on', :caption => l(:field_updated_on)) %>
40 <%= sort_header_tag('issues.updated_on', :caption => l(:field_updated_on)) %>
41 </tr>
41 </tr>
42 <% for issue in @issues %>
42 <% for issue in @issues %>
43 <tr bgcolor="#<%= issue.status.html_color %>">
43 <tr bgcolor="#<%= issue.status.html_color %>">
44 <td width="15"><%= check_box_tag "issue_ids[]", issue.id %></td>
44 <td width="15"><%= check_box_tag "issue_ids[]", issue.id %></td>
45 <td align="center"><%= link_to issue.long_id, :controller => 'issues', :action => 'show', :id => issue %></td>
45 <td align="center"><%= link_to issue.long_id, :controller => 'issues', :action => 'show', :id => issue %></td>
46 <td align="center"><%= issue.status.name %></td>
46 <td align="center"><%= issue.status.name %></td>
47 <td align="center"><%= issue.tracker.name %></td>
47 <td align="center"><%= issue.tracker.name %></td>
48 <td><%= link_to issue.subject, :controller => 'issues', :action => 'show', :id => issue %></td>
48 <td><%= link_to issue.subject, :controller => 'issues', :action => 'show', :id => issue %></td>
49 <td align="center"><%= issue.author.display_name %></td>
49 <td align="center"><%= issue.author.display_name %></td>
50 <td align="center"><%= format_time(issue.created_on) %></td>
50 <td align="center"><%= format_time(issue.created_on) %></td>
51 <td align="center"><%= format_time(issue.updated_on) %></td>
51 <td align="center"><%= format_time(issue.updated_on) %></td>
52 </tr>
52 </tr>
53 <% end %>
53 <% end %>
54 </table>
54 </table>
55 <p>
55 <p>
56 <%= pagination_links_full @issue_pages %>
56 <%= pagination_links_full @issue_pages %>
57 [ <%= @issue_pages.current.first_item %> - <%= @issue_pages.current.last_item %> / <%= @issue_count %> ]
57 [ <%= @issue_pages.current.first_item %> - <%= @issue_pages.current.last_item %> / <%= @issue_count %> ]
58 </p>
58 </p>
59 <%= submit_tag l(:button_move) %>
59 <%= submit_tag l(:button_move) %>
60 <%= end_form_tag %> No newline at end of file
60 <%= end_form_tag %>
General Comments 0
You need to be logged in to leave comments. Login now