timesheet_plugin 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/README.rdoc +1 -0
  2. data/Rakefile +2 -2
  3. data/VERSION +1 -1
  4. data/app/controllers/timesheet_controller.rb +16 -3
  5. data/app/helpers/timesheet_helper.rb +13 -8
  6. data/app/models/timesheet.rb +120 -12
  7. data/app/views/timesheet/_form.rhtml +5 -31
  8. data/app/views/timesheet/_issue_time_entries.rhtml +9 -2
  9. data/app/views/timesheet/index.rhtml +2 -5
  10. data/app/views/timesheet/report.rhtml +2 -5
  11. data/assets/images/csv.png +0 -0
  12. data/assets/javascripts/timesheet.js +17 -0
  13. data/assets/stylesheets/timesheet.css +6 -0
  14. data/config/locales/hu.yml +1 -1
  15. data/config/locales/hy.yml +9 -0
  16. data/config/locales/ja.yml +10 -0
  17. data/config/locales/pt-br.yml +10 -0
  18. data/config/locales/ru.yml +1 -0
  19. data/config/locales/sr.yml +10 -0
  20. data/config/locales/sv.yml +10 -0
  21. data/config/locales/uk.yml +10 -0
  22. data/config/routes.rb +4 -0
  23. data/init.rb +47 -1
  24. data/lang/hu.yml +1 -1
  25. data/lang/hy.yml +8 -0
  26. data/lang/ja.yml +9 -0
  27. data/lang/pt-br.yml +9 -0
  28. data/lang/ru.yml +1 -0
  29. data/lang/sr.yml +9 -0
  30. data/lang/sv.yml +9 -0
  31. data/lang/uk.yml +9 -0
  32. data/lib/timesheet_compatibility.rb +12 -1
  33. data/rails/init.rb +1 -29
  34. data/test/functional/timesheet_controller_test.rb +256 -0
  35. data/test/integration/timesheet_menu_test.rb +53 -0
  36. data/test/test_helper.rb +24 -0
  37. data/test/unit/sanity_test.rb +20 -0
  38. data/test/unit/timesheet_test.rb +653 -0
  39. metadata +28 -7
  40. data/lib/tasks/plugin_stat.rake +0 -38
  41. data/spec/controllers/timesheet_controller_spec.rb +0 -263
  42. data/spec/models/timesheet_spec.rb +0 -537
  43. data/spec/sanity_spec.rb +0 -7
  44. data/spec/spec_helper.rb +0 -40
@@ -0,0 +1,10 @@
1
+ pt-BR:
2
+ timesheet_title: Relatório de Apontamentos
3
+ timesheet_date_from_label: De
4
+ timesheet_date_to_label: Até
5
+ timesheet_project_label: Projeto
6
+ timesheet_activities_label: Atividades
7
+ timesheet_users_label: Usuários
8
+ timesheet_showing_users: 'Exibindo usuários: '
9
+ timesheet_permalink: 'Link permanente'
10
+ timesheet_group_by: 'Agrupar por'
@@ -5,5 +5,6 @@ ru:
5
5
  timesheet_project_label: Проект
6
6
  timesheet_activities_label: Активность
7
7
  timesheet_users_label: Пользователи
8
+ timesheet_showing_users: 'сводка для пользователя: '
8
9
  timesheet_permalink: '(Постоянная ссылка на эту таблицу)'
9
10
  timesheet_group_by: Группировать по
@@ -0,0 +1,10 @@
1
+ "sr":
2
+ timesheet_title: Satnica
3
+ timesheet_date_from_label: Od
4
+ timesheet_date_to_label: Do
5
+ timesheet_project_label: Projekat
6
+ timesheet_activities_label: Aktivnost
7
+ timesheet_users_label: Korisnici
8
+ timesheet_showing_users: 'pokazujem vreme za: '
9
+ timesheet_permalink: '(Stalni link za ovu satnicu)'
10
+ timesheet_group_by: Grupiši po
@@ -0,0 +1,10 @@
1
+ "sv":
2
+ timesheet_title: Tidkort
3
+ timesheet_date_from_label: Fr�n
4
+ timesheet_date_to_label: Till
5
+ timesheet_project_label: Projekt
6
+ timesheet_activities_label: Aktivitet
7
+ timesheet_users_label: Anv�ndare
8
+ timesheet_showing_users: 'visar tid f�r: '
9
+ timesheet_permalink: '(Permal�nk till detta tidkort)'
10
+ timesheet_group_by: Gruppera efter
@@ -0,0 +1,10 @@
1
+ uk:
2
+ timesheet_title: Таблиця витрат часу
3
+ timesheet_date_from_label: Починаючи з
4
+ timesheet_date_to_label: до
5
+ timesheet_project_label: Проект
6
+ timesheet_activities_label: Активність
7
+ timesheet_users_label: Користувачі
8
+ timesheet_showing_users: 'час витрачений користувачем: '
9
+ timesheet_permalink: '(Постійний лінк на цю таблицю)'
10
+ timesheet_group_by: Групувати за
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.connect 'timesheet/report.:format', :controller => 'timesheet', :action => 'report'
3
+ map.connect 'timesheet/reset', :controller => 'timesheet', :action => 'reset', :conditions => { :method => :delete }
4
+ end
data/init.rb CHANGED
@@ -1,2 +1,48 @@
1
- require File.dirname(__FILE__) + "/rails/init"
1
+ require 'redmine'
2
2
 
3
+ # Taken from lib/redmine.rb
4
+ if RUBY_VERSION < '1.9'
5
+ require 'faster_csv'
6
+ else
7
+ require 'csv'
8
+ FCSV = CSV
9
+ end
10
+
11
+ require 'dispatcher'
12
+ Dispatcher.to_prepare :timesheet_plugin do
13
+ # Needed for the compatibility check
14
+ begin
15
+ require_dependency 'time_entry_activity'
16
+ rescue LoadError
17
+ # TimeEntryActivity is not available
18
+ end
19
+ end
20
+
21
+
22
+ unless Redmine::Plugin.registered_plugins.keys.include?(:timesheet_plugin)
23
+ Redmine::Plugin.register :timesheet_plugin do
24
+ name 'Timesheet Plugin'
25
+ author 'Eric Davis of Little Stream Software'
26
+ description 'This is a Timesheet plugin for Redmine to show timelogs for all projects'
27
+ url 'https://projects.littlestreamsoftware.com/projects/redmine-timesheet'
28
+ author_url 'http://www.littlestreamsoftware.com'
29
+
30
+ version '0.6.0'
31
+ requires_redmine :version_or_higher => '0.8.7'
32
+
33
+ settings :default => {'list_size' => '5', 'precision' => '2'}, :partial => 'settings/timesheet_settings'
34
+
35
+ permission :see_project_timesheets, { }, :require => :member
36
+
37
+ menu(:top_menu,
38
+ :timesheet,
39
+ {:controller => 'timesheet', :action => 'index'},
40
+ :caption => :timesheet_title,
41
+ :if => Proc.new {
42
+ User.current.allowed_to?(:see_project_timesheets, nil, :global => true) ||
43
+ User.current.allowed_to?(:view_time_entries, nil, :global => true) ||
44
+ User.current.admin?
45
+ })
46
+
47
+ end
48
+ end
data/lang/hu.yml CHANGED
@@ -1,4 +1,4 @@
1
- timesheet_title: Időlap
1
+ timesheet_title: Időlap
2
2
  timesheet_date_from_label: Kezdő dátum
3
3
  timesheet_date_to_label: Vég dátum
4
4
  timesheet_project_label: Projekt
data/lang/hy.yml ADDED
@@ -0,0 +1,8 @@
1
+ timesheet_title: Ծախսված ժամանակի աղյուսակ
2
+ timesheet_date_from_label: Սկսած
3
+ timesheet_date_to_label: մինչև
4
+ timesheet_project_label: Նախագիծ
5
+ timesheet_activities_label: Ակտիվությունը
6
+ timesheet_users_label: Օգտագործողներ
7
+ timesheet_permalink: '(Մշտական հղում դեպի այս աղյուսակը)'
8
+ timesheet_group_by: Դասավորել ըստ
data/lang/ja.yml ADDED
@@ -0,0 +1,9 @@
1
+ timesheet_title: 記録時間表
2
+ timesheet_date_from_label: 期間
3
+ timesheet_date_to_label: から
4
+ timesheet_project_label: プロジェクト
5
+ timesheet_activities_label: 活動
6
+ timesheet_users_label: ユーザ
7
+ timesheet_showing_users: 'ユーザ: '
8
+ timesheet_permalink: '(この記録時間表へ直接リンク)'
9
+ timesheet_group_by: グループ化
data/lang/pt-br.yml ADDED
@@ -0,0 +1,9 @@
1
+ timesheet_title: Relatório de Apontamentos
2
+ timesheet_date_from_label: De
3
+ timesheet_date_to_label: Até
4
+ timesheet_project_label: Projeto
5
+ timesheet_activities_label: Atividades
6
+ timesheet_users_label: Usuários
7
+ timesheet_showing_users: 'Exibindo usuários: '
8
+ timesheet_permalink: 'Link permanente'
9
+ timesheet_group_by: 'Agrupar por'
data/lang/ru.yml CHANGED
@@ -4,5 +4,6 @@ timesheet_date_to_label: по
4
4
  timesheet_project_label: Проект
5
5
  timesheet_activities_label: Активность
6
6
  timesheet_users_label: Пользователи
7
+ timesheet_showing_users: 'сводка для пользователя: '
7
8
  timesheet_permalink: '(Постоянная ссылка на эту таблицу)'
8
9
  timesheet_group_by: Группировать по
data/lang/sr.yml ADDED
@@ -0,0 +1,9 @@
1
+ timesheet_title: Satnica
2
+ timesheet_date_from_label: Od
3
+ timesheet_date_to_label: Do
4
+ timesheet_project_label: Projekat
5
+ timesheet_activities_label: Aktivnost
6
+ timesheet_users_label: Korisnici
7
+ timesheet_showing_users: 'pokazujem vreme za: '
8
+ timesheet_permalink: '(Stalni link za ovu satnicu)'
9
+ timesheet_group_by: Grupiši po
data/lang/sv.yml ADDED
@@ -0,0 +1,9 @@
1
+ timesheet_title: "Tidkort"
2
+ timesheet_date_from_label: "Från"
3
+ timesheet_date_to_label: "Till"
4
+ timesheet_project_label: "Projekt"
5
+ timesheet_activities_label: "Aktivitet"
6
+ timesheet_users_label: "Användare"
7
+ timesheet_showing_users: 'visar tid för: '
8
+ timesheet_permalink: '(Permalänk till detta tidkort)'
9
+ timesheet_group_by: "Gruppera efter"
data/lang/uk.yml ADDED
@@ -0,0 +1,9 @@
1
+ timesheet_title: Таблиця витрат часу
2
+ timesheet_date_from_label: Починаючи з
3
+ timesheet_date_to_label: до
4
+ timesheet_project_label: Проект
5
+ timesheet_activities_label: Активність
6
+ timesheet_users_label: Користувачі
7
+ timesheet_showing_users: 'час витрачений користувачем: '
8
+ timesheet_permalink: '(Постійний лінк на цю таблицю)'
9
+ timesheet_group_by: Групувати за
@@ -4,11 +4,22 @@ module TimesheetCompatibility
4
4
  # Wrapper around Redmine's API since Enumerations changed in r2472
5
5
  # This can be removed once 0.9.0 is stable
6
6
  def self.activities
7
- if ::Enumeration.respond_to?(:activities)
7
+ if Object.const_defined?('TimeEntryActivity')
8
+ return ::TimeEntryActivity.all
9
+ elsif ::Enumeration.respond_to?(:activities)
8
10
  return ::Enumeration.activities
9
11
  else
10
12
  return ::Enumeration::get_values('ACTI')
11
13
  end
12
14
  end
15
+
16
+ # Wrapper for Project Specific Enumerations in Redmine 0.9+
17
+ def self.project_specific_sql
18
+ if ::Enumeration.column_names.include?('parent_id') && ::Enumeration.column_names.include?('project_id')
19
+ "OR (#{::Enumeration.table_name}.parent_id IN (:activities) AND #{::Enumeration.table_name}.project_id IN (:projects))"
20
+ else
21
+ ''
22
+ end
23
+ end
13
24
  end
14
25
  end
data/rails/init.rb CHANGED
@@ -1,29 +1 @@
1
- require 'redmine'
2
-
3
- unless Redmine::Plugin.registered_plugins.keys.include?(:timesheet_plugin)
4
- Redmine::Plugin.register :timesheet_plugin do
5
- name 'Timesheet Plugin'
6
- author 'Eric Davis of Little Stream Software'
7
- description 'This is a Timesheet plugin for Redmine to show timelogs for all projects'
8
- url 'https://projects.littlestreamsoftware.com/projects/redmine-timesheet'
9
- author_url 'http://www.littlestreamsoftware.com'
10
-
11
- version '0.5.0'
12
- requires_redmine :version_or_higher => '0.8.0'
13
-
14
- settings :default => {'list_size' => '5', 'precision' => '2'}, :partial => 'settings/timesheet_settings'
15
-
16
- permission :see_project_timesheets, { }, :require => :member
17
-
18
- menu(:top_menu,
19
- :timesheet,
20
- {:controller => 'timesheet', :action => 'index'},
21
- :caption => :timesheet_title,
22
- :if => Proc.new {
23
- User.current.allowed_to?(:see_project_timesheets, nil, :global => true) ||
24
- User.current.allowed_to?(:view_time_entries, nil, :global => true) ||
25
- User.current.admin?
26
- })
27
-
28
- end
29
- end
1
+ require File.dirname(__FILE__) + "/../init"
@@ -0,0 +1,256 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ class ActiveSupport::TestCase
3
+ def self.use_timesheet_controller_shared(&block)
4
+ should 'should set @timesheet.allowed_projects to the list of current projects the user is a member of' do
5
+ Member.destroy_all # clear any setup memberships
6
+
7
+ project1 = Project.generate!
8
+ project2 = Project.generate!
9
+ projects = [project1, project2]
10
+
11
+ projects.each do |project|
12
+ Member.generate!(:principal => @current_user, :project => project, :roles => [@normal_role])
13
+ end
14
+
15
+ instance_eval &block
16
+
17
+ assert_equal projects, assigns['timesheet'].allowed_projects
18
+ end
19
+
20
+ should 'include public projects in @timesheet.allowed_projects' do
21
+ project1 = Project.generate!(:is_public => true)
22
+ project2 = Project.generate!(:is_public => true)
23
+ projects = [project1, project2]
24
+
25
+ instance_eval &block
26
+
27
+ assert_contains assigns['timesheet'].allowed_projects, project1
28
+ assert_contains assigns['timesheet'].allowed_projects, project2
29
+ end
30
+
31
+ should 'should set @timesheet.allowed_projects to all the projects if the user is an admin' do
32
+ Member.destroy_all # clear any setup memberships
33
+
34
+ @current_user.admin = true
35
+ project1, _ = *generate_project_membership(@current_user)
36
+ project2, _ = *generate_project_membership(@current_user)
37
+ projects = [project1, project2]
38
+
39
+ instance_eval &block
40
+
41
+ assert_equal projects, assigns['timesheet'].allowed_projects
42
+ end
43
+
44
+ should 'should get the list size from the settings' do
45
+ settings = { 'list_size' => 10, 'precision' => '2' }
46
+ Setting.plugin_timesheet_plugin = settings
47
+
48
+ instance_eval &block
49
+ assert_equal 10, assigns['list_size']
50
+ end
51
+
52
+ should 'should get the precision from the settings' do
53
+ settings = { 'list_size' => 10, 'precision' => '2' }
54
+ Setting.plugin_timesheet_plugin = settings
55
+
56
+ instance_eval &block
57
+ assert_equal 2, assigns['precision']
58
+ end
59
+
60
+ should 'should create a new @timesheet' do
61
+ instance_eval &block
62
+ assert assigns['timesheet']
63
+ end
64
+ end
65
+ end
66
+
67
+
68
+ class TimesheetControllerTest < ActionController::TestCase
69
+ def generate_and_login_user(options = {})
70
+ @current_user = User.generate_with_protected!(:admin => false)
71
+ @request.session[:user_id] = @current_user.id
72
+ end
73
+
74
+ def generate_project_membership(user)
75
+ @project = Project.generate!(:is_public => false)
76
+ @member = Member.generate!(:principal => user, :project => @project, :roles => [@normal_role])
77
+ [@project, @member]
78
+ end
79
+
80
+ def setup
81
+ @normal_role = Role.generate!(:name => 'Normal User', :permissions => [:view_time_entries])
82
+ end
83
+
84
+ context "#index with GET request" do
85
+ setup do
86
+ generate_and_login_user
87
+ generate_project_membership(@current_user)
88
+ get 'index'
89
+ end
90
+
91
+ use_timesheet_controller_shared do
92
+ get 'index'
93
+ end
94
+
95
+ should_render_template :index
96
+
97
+ should 'have no timelog entries' do
98
+ assert assigns['timesheet'].time_entries.empty?
99
+ end
100
+ end
101
+
102
+ context "#index with GET request and a session" do
103
+
104
+ should 'should read the session data' do
105
+ generate_and_login_user
106
+ @current_user.admin = true
107
+ @current_user.save!
108
+
109
+ projects = []
110
+ 4.times do |i|
111
+ projects << Project.generate!
112
+ end
113
+
114
+ session[TimesheetController::SessionKey] = HashWithIndifferentAccess.new(
115
+ :projects => projects.collect(&:id).collect(&:to_s),
116
+ :date_to => '2009-01-01',
117
+ :date_from => '2009-01-01'
118
+ )
119
+
120
+ get :index
121
+ assert_equal '2009-01-01', assigns['timesheet'].date_from
122
+ assert_equal '2009-01-01', assigns['timesheet'].date_to
123
+ assert_equal projects, assigns['timesheet'].projects
124
+ end
125
+ end
126
+
127
+ context "#index with GET request from an Anonymous user" do
128
+ setup do
129
+ get 'index'
130
+ end
131
+
132
+ should_render_template :no_projects
133
+
134
+ end
135
+
136
+ context "#report with GET request from an Anonymous user" do
137
+ setup do
138
+ get :report
139
+ end
140
+
141
+ should_respond_with :redirect
142
+ should_redirect_to('index') {{:action => 'index'}}
143
+ end
144
+
145
+ context "#report with POST request from an Anonymous user" do
146
+ setup do
147
+ post :report
148
+ end
149
+
150
+ should_respond_with :redirect
151
+ should_redirect_to('index') {{:action => 'index'}}
152
+
153
+ end
154
+
155
+ context "#report with POST request" do
156
+ setup do
157
+ generate_and_login_user
158
+ end
159
+
160
+ use_timesheet_controller_shared do
161
+ post :report, :timesheet => {}
162
+ end
163
+
164
+ should 'should only allow the allowed projects into @timesheet.projects' do
165
+ project1 = Project.generate!(:is_public => false)
166
+ project2 = Project.generate!(:is_public => false)
167
+ projects = [project1, project2]
168
+
169
+ Member.generate!(:principal => @current_user, :project => project1, :roles => [@normal_role])
170
+
171
+ post :report, :timesheet => { :projects => [project1.id.to_s, project2.id.to_s] }
172
+
173
+ assert_equal [project1], assigns['timesheet'].projects
174
+ end
175
+
176
+ should 'include public projects' do
177
+ project1 = Project.generate!(:is_public => true)
178
+ project2 = Project.generate!(:is_public => true)
179
+ projects = [project1, project2]
180
+
181
+ post :report, :timesheet => { :projects => [project1.id.to_s, project2.id.to_s] }
182
+
183
+ assert_contains assigns['timesheet'].allowed_projects, project1
184
+ assert_contains assigns['timesheet'].allowed_projects, project2
185
+ end
186
+
187
+ should 'should save the session data' do
188
+ generate_project_membership(@current_user)
189
+ post :report, :timesheet => { :projects => ['1'] }
190
+
191
+ assert @request.session[TimesheetController::SessionKey]
192
+ assert @request.session[TimesheetController::SessionKey].keys.include?('projects')
193
+ assert_equal ['1'], @request.session[TimesheetController::SessionKey]['projects']
194
+ end
195
+
196
+ context ":csv format" do
197
+ setup do
198
+ generate_project_membership(@current_user)
199
+ post :report, :timesheet => {:projects => ['1']}, :format => 'csv'
200
+ end
201
+
202
+ should_respond_with_content_type 'text/csv'
203
+ should_respond_with :success
204
+ end
205
+ end
206
+
207
+ context "#report with request with no data" do
208
+ setup do
209
+ generate_and_login_user
210
+ end
211
+
212
+ context 'should redirect to the index' do
213
+ context "from a GET request" do
214
+ setup do
215
+ get 'report', { }
216
+ end
217
+
218
+ should_respond_with :redirect
219
+ should_redirect_to('index') {{:action => 'index' }}
220
+ end
221
+
222
+ context "from a POST request" do
223
+ setup do
224
+ post 'report', { }
225
+ end
226
+
227
+ should_respond_with :redirect
228
+ should_redirect_to('index') {{:action => 'index' }}
229
+ end
230
+ end
231
+ end
232
+
233
+ context "DELETE to :reset" do
234
+ setup do
235
+ generate_and_login_user
236
+ @current_user.admin = true
237
+ @current_user.save!
238
+
239
+ @project = Project.generate!
240
+ session[TimesheetController::SessionKey] = HashWithIndifferentAccess.new(
241
+ :projects => [@project.id.to_s],
242
+ :date_to => '2009-01-01',
243
+ :date_from => '2009-01-01'
244
+ )
245
+
246
+ delete :reset
247
+ end
248
+
249
+ should_respond_with :redirect
250
+ should_redirect_to('index') {{:action => 'index'}}
251
+ should 'clear the session' do
252
+ assert session[TimesheetController::SessionKey].blank?
253
+ end
254
+
255
+ end
256
+ end