bulk_time_entry_plugin 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ Dir[File.expand_path(File.dirname(__FILE__)) + "/lib/tasks/**/*.rake"].sort.each
6
6
  RedminePluginSupport::Base.setup do |plugin|
7
7
  plugin.project_name = 'bulk_time_entry_plugin'
8
8
  plugin.default_task = [:test]
9
- plugin.tasks = [:doc, :release, :clean, :test, :db]
9
+ plugin.tasks = [:doc, :release, :clean, :test, :db, :metrics]
10
10
  # TODO: gem not getting this automaticly
11
11
  plugin.redmine_root = File.expand_path(File.dirname(__FILE__) + '/../../../')
12
12
  end
@@ -35,3 +35,4 @@ begin
35
35
  rescue LoadError
36
36
  puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
37
37
  end
38
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.5.0
@@ -4,55 +4,45 @@ class BulkTimeEntriesController < ApplicationController
4
4
  layout 'base'
5
5
  before_filter :load_activities
6
6
  before_filter :load_allowed_projects
7
+ before_filter :load_first_project
8
+ before_filter :check_for_no_projects
7
9
 
8
10
  helper :custom_fields
11
+ include BulkTimeEntriesHelper
9
12
 
10
13
  protect_from_forgery :only => [:index, :save]
11
14
 
12
15
  def index
13
16
  @time_entries = [TimeEntry.new(:spent_on => Date.today.to_s)]
14
-
15
- if @projects.empty?
16
- render :action => 'no_projects'
17
- end
18
17
  end
19
18
 
20
- def get_issues(project_id)
21
- @issues = Issue.find(:all, :conditions => { :project_id => project_id })
22
- end
23
-
24
19
  def load_assigned_issues
25
- get_issues params[:project_id]
26
- render(:update) do |page|
27
- page.replace_html params[:entry_id]+'_issues', :partial => 'issues_selector', :locals => { :issues => @issues, :rnd => params[:entry_id].split('_')[1] }
20
+ @issues = get_issues(params[:project_id])
21
+ @selected_project = BulkTimeEntriesController.allowed_project?(params[:project_id])
22
+ respond_to do |format|
23
+ format.js {}
28
24
  end
29
25
  end
30
26
 
31
27
 
32
28
  def save
33
29
  if request.post?
34
- @time_entries = params[:time_entries]
30
+ @unsaved_entries = {}
31
+ @saved_entries = {}
35
32
 
36
- render :update do |page|
37
- @time_entries.each_pair do |html_id, entry|
38
- next unless BulkTimeEntriesController.allowed_project?(entry[:project_id])
39
- @time_entry = TimeEntry.new(entry)
40
- @time_entry.hours = nil if @time_entry.hours.blank? or @time_entry.hours <= 0
41
- @time_entry.project_id = entry[:project_id] # project_id is protected from mass assignment
42
- @time_entry.user = User.current
43
- unless @time_entry.save
44
- page.replace "entry_#{html_id}", :partial => 'time_entry', :object => @time_entry
45
- else
46
- time_entry_target = if @time_entry.issue
47
- "#{h(@time_entry.project.name)} - #{h(@time_entry.issue.subject)}"
48
- else
49
- "#{h(@time_entry.project.name)}"
50
- end
51
- page.replace_html "entry_#{html_id}", "<div class='flash notice'>#{l(:text_time_added_to_project, :count => @time_entry.hours, :target => time_entry_target)}#{" (#{@time_entry.comments})" unless @time_entry.comments.blank?}.</div>"
52
- end
33
+ params[:time_entries].each_pair do |html_id, entry|
34
+ time_entry = TimeEntry.create_bulk_time_entry(entry)
35
+ if time_entry.new_record?
36
+ @unsaved_entries[html_id] = time_entry
37
+ else
38
+ @saved_entries[html_id] = time_entry
53
39
  end
54
40
  end
55
- end
41
+
42
+ respond_to do |format|
43
+ format.js {}
44
+ end
45
+ end
56
46
  end
57
47
 
58
48
  def add_entry
@@ -65,18 +55,14 @@ class BulkTimeEntriesController < ApplicationController
65
55
 
66
56
  @time_entry = TimeEntry.new(:spent_on => spent_on.to_s)
67
57
  respond_to do |format|
68
- format.js do
69
- render :update do |page|
70
- page.insert_html :bottom, 'entries', :partial => 'time_entry', :object => @time_entry
71
- end
72
- end
58
+ format.js {}
73
59
  end
74
60
  end
75
61
 
76
62
  private
77
63
 
78
64
  def load_activities
79
- @activities = BulkTimeEntryCompatibility::Enumeration::activities
65
+ @activities = TimeEntryActivity.all
80
66
  end
81
67
 
82
68
  def load_allowed_projects
@@ -84,28 +70,18 @@ class BulkTimeEntriesController < ApplicationController
84
70
  Project.allowed_to_condition(User.current, :log_time))
85
71
  end
86
72
 
87
- def self.allowed_project?(project_id)
88
- return User.current.projects.find_by_id(project_id, Project.allowed_to_condition(User.current, :log_time))
73
+ def load_first_project
74
+ @first_project = @projects.sort_by(&:lft).first unless @projects.empty?
89
75
  end
90
76
 
91
- # Redmine 0.8 compatibility fix
92
- if Redmine::VERSION::MAJOR <= 0 && Redmine::VERSION::MINOR < 9
93
- include ERB::Util
94
-
95
- def project_tree_options_for_select(projects)
96
- result = []
97
- user_projects_by_root = projects.group_by(&:root)
98
- user_projects_by_root.keys.sort.each do |root|
99
- result << [h(root.name), root.id]
100
- user_projects_by_root[root].sort.each do |project|
101
- next if project == root
102
- result << ["» #{h(project.name)}", project.id]
103
- end
104
- end
105
- return result
77
+ def check_for_no_projects
78
+ if @projects.empty?
79
+ render :action => 'no_projects'
80
+ return false
106
81
  end
107
- helper_method :project_tree_options_for_select
108
-
109
82
  end
110
83
 
84
+ def self.allowed_project?(project_id)
85
+ return User.current.projects.find_by_id(project_id, :conditions => Project.allowed_to_condition(User.current, :log_time))
86
+ end
111
87
  end
@@ -11,28 +11,32 @@ module BulkTimeEntriesHelper
11
11
  end
12
12
 
13
13
  def grouped_options_for_issues(issues)
14
- open_issues = []
15
- closed_issues = []
16
- issues.each do |issue|
17
- if issue.closed?
18
- closed_issues << issue
19
- else
20
- open_issues << issue
21
- end
22
- end
14
+ closed_issues, open_issues = *issues.partition {|issue| issue.closed?}
23
15
 
24
16
  html = '<option></option>'
25
17
  unless open_issues.empty?
26
- html << "<optgroup label='#{l(:label_open_issues)}'>"
27
- html << options_from_collection_for_select(open_issues, :id, :to_s)
28
- html << "</optgroup>"
18
+ html << labeled_option_group_from_collection_for_select(:label_open_issues, open_issues)
29
19
  end
30
20
 
31
21
  unless closed_issues.empty?
32
- html << "<optgroup label='#{l(:label_closed_issues)}'>"
33
- html << options_from_collection_for_select(closed_issues, :id, :to_s)
34
- html << "</optgroup>"
22
+ html << labeled_option_group_from_collection_for_select(:label_closed_issues, closed_issues)
35
23
  end
36
24
  html
37
25
  end
26
+
27
+ def labeled_option_group_from_collection_for_select(label, collection)
28
+ html = "<optgroup label='#{l(label)}'>"
29
+ html << options_from_collection_for_select(collection, :id, :to_s)
30
+ html << "</optgroup>"
31
+ html
32
+ end
33
+
34
+ def get_issues(project_id)
35
+ project = BulkTimeEntriesController.allowed_project?(project_id)
36
+ if project
37
+ project.issues.all(:order => 'id ASC')
38
+ else
39
+ []
40
+ end
41
+ end
38
42
  end
@@ -0,0 +1,6 @@
1
+ <%= label_for_field :activity_id, rnd, :required => true %>
2
+ <% if activities.present? %>
3
+ <%= select_tag "time_entries[#{rnd}][activity_id]", options_from_collection_for_select(activities, :id, :name) %>
4
+ <% else %>
5
+ <em><%= l(:label_no_data) %></em>
6
+ <% end %>
@@ -4,15 +4,15 @@
4
4
  @object = time_entry
5
5
  @object_name = 'time_entry' -%>
6
6
  <div class="box" id="entry_<%= rnd %>">
7
- <%= error_messages_for 'time_entry' %>
7
+ <%= error_messages_for 'time_entry', :object => time_entry %>
8
8
  <p>
9
9
  <%= label_for_field :project_id, rnd, :required => true %>
10
- <% projects = project_tree_options_for_select(Project.has_module(:time_tracking)) %>
10
+ <% projects = project_tree_options_for_select(@projects, :selected => @first_project) %>
11
11
  <%= f.select :project_id, projects, {},
12
12
  { :onchange => "new Ajax.Request('#{url_for :action => 'load_assigned_issues'}', { parameters: { project_id: $F(this), entry_id: $(this).up(1).id } } )" } %>&nbsp;
13
13
  </p>
14
14
  <p id="entry_<%= rnd %>_issues">
15
- <% @issues = controller.get_issues projects.first.id %>
15
+ <% @issues = get_issues @first_project.id %>
16
16
  <%= render :partial => 'issues_selector', :locals => { :issues => @issues, :f => f, :rnd => rnd } %>
17
17
  </p>
18
18
  <p>
@@ -27,9 +27,8 @@
27
27
  <%= label_for_field :comments, rnd %>
28
28
  <%= f.text_field :comments, :size => 100, :maxlength => 255 %>
29
29
  </p>
30
- <p>
31
- <%= label_for_field :activity_id, rnd, :required => true %>
32
- <%= f.select :activity_id, (@activities.collect {|p| [p.name, p.id]}) %>
30
+ <p id="entry_<%= rnd %>_activities">
31
+ <%= render :partial => 'activities_selector', :locals => {:rnd => rnd, :activities => @first_project.activities } %>
33
32
  </p>
34
33
  <% time_entry.custom_field_values.each do |value| %>
35
34
  <p><%= custom_field_tag_with_label "time_entries[#{rnd}]", value %></p>
@@ -37,4 +36,5 @@
37
36
  </div>
38
37
  <% end %>
39
38
 
39
+ <%= javascript_tag("Element.scrollTo('time_entries_#{time_entry.id}_project_id')") %>
40
40
  <%= javascript_tag("Form.Element.focus('time_entries_#{time_entry.id}_project_id')") %>
@@ -0,0 +1 @@
1
+ page.insert_html :bottom, 'entries', :partial => 'time_entry', :object => @time_entry
@@ -0,0 +1,3 @@
1
+ page.replace_html params[:entry_id]+'_issues', :partial => 'issues_selector', :locals => { :issues => @issues, :rnd => params[:entry_id].split('_')[1] }
2
+
3
+ page.replace_html params[:entry_id]+'_activities', :partial => 'activities_selector', :locals => { :rnd => params[:entry_id].split('_')[1], :activities => (@selected_project.present? ? @selected_project.activities : []) }
@@ -0,0 +1,12 @@
1
+ @unsaved_entries.each do |html_id, entry|
2
+ page.replace "entry_#{html_id}", :partial => 'time_entry', :object => entry
3
+ end
4
+
5
+ @saved_entries.each do |html_id, entry|
6
+ time_entry_target = if entry.issue
7
+ "#{h(entry.project.name)} - #{h(entry.issue.subject)}"
8
+ else
9
+ "#{h(entry.project.name)}"
10
+ end
11
+ page.replace_html "entry_#{html_id}", "<div class='flash notice'>#{l(:text_time_added_to_project, :count => entry.hours, :target => time_entry_target)}#{" (#{entry.comments})" unless entry.comments.blank?}.</div>"
12
+ end
@@ -0,0 +1,6 @@
1
+ de:
2
+ bulk_time_entry_title: Zeiterfassung
3
+ label_bulk_time_entries: Zeiterfassung
4
+ label_bulk_time_add_another: Weiteren Eintrag hinzufügen
5
+ text_bulk_time_entry_permission: Sie haben keine Berechtigung um Zeiten für irgendein Projekt zu erfassen
6
+ text_time_added_to_project: "{{count}} Stunde/n im Projekt {{target}} erfasst"
@@ -0,0 +1,7 @@
1
+ nl:
2
+ bulk_time_entry_title: Bulk tijd loggen
3
+ label_bulk_time_entries: Bulk tijd loggen
4
+ label_bulk_time_add_another: Voeg extra toe
5
+ text_bulk_time_entry_permission: Je hebt geen rechten om op een project tijd te loggen
6
+ text_time_added_to_project: %s uren toegevoegd aan project
7
+
data/init.rb CHANGED
@@ -1 +1,23 @@
1
- require File.dirname(__FILE__) + "/rails/init"
1
+ require 'redmine'
2
+
3
+ config.gem 'fastercsv' if respond_to? :config
4
+
5
+ Redmine::Plugin.register :bulk_time_entry_plugin do
6
+ name 'Bulk Time Entry'
7
+ author 'Eric Davis'
8
+ description 'This is a plugin to enter multiple time entries at one time.'
9
+ version '0.5.0'
10
+
11
+ requires_redmine :version_or_higher => '0.9.0'
12
+
13
+ menu :top_menu, :bulk_time_entry, {:controller => "bulk_time_entries", :action => 'index'},
14
+ :caption => :bulk_time_entry_title, :if => Proc.new{User.current.allowed_to?(:log_time, nil, :global => true)}
15
+ end
16
+
17
+ # Patches to the Redmine core.
18
+ require 'dispatcher'
19
+
20
+ Dispatcher.to_prepare :bulk_time_entry_plugin do
21
+ require_dependency 'time_entry'
22
+ TimeEntry.send(:include, BulkTimeEntryPlugin::Patches::TimeEntryPatch)
23
+ end
data/lang/de.yml ADDED
@@ -0,0 +1,5 @@
1
+ bulk_time_entry_title: Zeiterfassung
2
+ label_bulk_time_entries: Zeiterfassung
3
+ label_bulk_time_add_another: Weiteren Eintrag hinzufügen
4
+ text_bulk_time_entry_permission: Sie haben keine Berechtigung um Zeiten für irgendein Projekt zu erfassen
5
+ text_time_added_to_project: %s Stunde/n zum Projekt hinzugefügt
data/lang/nl.yml ADDED
@@ -0,0 +1,6 @@
1
+ bulk_time_entry_title: Bulk tijd loggen
2
+ label_bulk_time_entries: Bulk tijd loggen
3
+ label_bulk_time_add_another: Voeg extra toe
4
+ text_bulk_time_entry_permission: Je hebt geen rechten om op een project tijd te loggen
5
+ text_time_added_to_project: %s uren toegevoegd aan project
6
+
@@ -1,22 +1,3 @@
1
- begin
2
- require 'time_entry_activity'
3
- rescue LoadError
4
- # TimeEntryActivity is not available
5
- end
6
-
7
1
  # Wrappers around the Redmine core API changes between versions
8
2
  module BulkTimeEntryCompatibility
9
- class Enumeration
10
- # Wrapper around Redmine's API since Enumerations changed in r2472
11
- # This can be removed once 0.9.0 is stable
12
- def self.activities
13
- if Object.const_defined?('TimeEntryActivity')
14
- return ::TimeEntryActivity.all
15
- elsif ::Enumeration.respond_to?(:activities)
16
- return ::Enumeration.activities
17
- else
18
- return ::Enumeration::get_values('ACTI')
19
- end
20
- end
21
- end
22
3
  end
@@ -0,0 +1,25 @@
1
+ module BulkTimeEntryPlugin
2
+ module Patches
3
+ module TimeEntryPatch
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+
10
+ def create_bulk_time_entry(entry)
11
+ time_entry = TimeEntry.new(entry)
12
+ time_entry.hours = nil if time_entry.hours.blank? or time_entry.hours <= 0
13
+ if BulkTimeEntriesController.allowed_project?(entry[:project_id])
14
+ time_entry.project_id = entry[:project_id] # project_id is protected from mass assignment
15
+ end
16
+ time_entry.user = User.current
17
+ time_entry.save
18
+ time_entry
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+ end
25
+ end
data/rails/init.rb CHANGED
@@ -1,13 +1 @@
1
- require 'redmine'
2
-
3
- config.gem 'fastercsv' if respond_to? :config
4
-
5
- Redmine::Plugin.register :bulk_time_entry_plugin do
6
- name 'Bulk Time Entry'
7
- author 'Eric Davis'
8
- description 'This is a plugin to enter multiple time entries at one time.'
9
- version '0.4.0'
10
-
11
- menu :top_menu, :bulk_time_entry, {:controller => "bulk_time_entries", :action => 'index'},
12
- :caption => :bulk_time_entry_title, :if => Proc.new{User.current.allowed_to?(:log_time, nil, :global => true)}
13
- end
1
+ require File.dirname(__FILE__) + "/../init"
@@ -10,6 +10,8 @@ class BulkTimeEntriesControllerTest < ActionController::TestCase
10
10
 
11
11
  should_have_before_filter :load_activities
12
12
  should_have_before_filter :load_allowed_projects
13
+ should_have_before_filter :load_first_project
14
+ should_have_before_filter :check_for_no_projects
13
15
 
14
16
  context "GET to :index" do
15
17
  context "as a user without any projects" do
@@ -21,7 +23,7 @@ class BulkTimeEntriesControllerTest < ActionController::TestCase
21
23
  end
22
24
 
23
25
  should_respond_with :success
24
- should_assign_to :time_entries
26
+ should_not_assign_to :time_entries
25
27
  should_assign_to :projects
26
28
  should_render_template :no_projects
27
29
 
@@ -38,7 +40,134 @@ class BulkTimeEntriesControllerTest < ActionController::TestCase
38
40
  should_respond_with :success
39
41
  should_assign_to :time_entries
40
42
  should_assign_to :projects
43
+ should_assign_to :first_project
41
44
  should_render_template :index
42
45
  end
43
46
  end
47
+
48
+ context "POST to :save with valid params and a valid user" do
49
+ setup do
50
+ @project = Project.generate!
51
+ @activity = TimeEntryActivity.generate!
52
+
53
+ generate_user_and_login_for_project(@project)
54
+ @issue = Issue.generate!(:project => @project, :tracker => @project.trackers.first, :priority => IssuePriority.generate!(:name => 'Low'))
55
+ end
56
+
57
+ should "save a new time entry" do
58
+
59
+ assert_difference('TimeEntry.count',2) do
60
+ post :save, :time_entries => {
61
+ "1234" => {
62
+ "comments" => 'a comment',
63
+ "project_id" => @project.id,
64
+ "issue_id" => @issue.id,
65
+ "activity_id" => @activity.id,
66
+ "spent_on" => Date.today.to_s,
67
+ "hours" => '42'
68
+ },
69
+ "9658" => {
70
+ "comments" => 'a comment',
71
+ "project_id" => @project.id,
72
+ "issue_id" => @issue.id,
73
+ "activity_id" => @activity.id,
74
+ "spent_on" => Date.today.to_s,
75
+ "hours" => '42'
76
+ }
77
+ }
78
+ end
79
+
80
+ end
81
+
82
+ should "replace the time entry form with a flash message" do
83
+ post :save, :time_entries => {
84
+ "1234" => {
85
+ "comments" => 'a comment',
86
+ "project_id" => @project.id,
87
+ "issue_id" => @issue.id,
88
+ "activity_id" => @activity.id,
89
+ "spent_on" => Date.today.to_s,
90
+ "hours" => '42'
91
+ }
92
+ }
93
+
94
+ assert_select_rjs :replace_html, 'entry_1234', :text => /notice/
95
+ end
96
+ end
97
+
98
+ context "POST to :save with invalid params and a valid user" do
99
+ setup do
100
+ @project = Project.generate!
101
+ @activity = TimeEntryActivity.generate!
102
+
103
+ generate_user_and_login_for_project(@project)
104
+ @issue = Issue.generate!(:project => @project, :tracker => @project.trackers.first, :priority => IssuePriority.generate!(:name => 'Low'))
105
+ end
106
+ should "not save a time entry" do
107
+
108
+ assert_no_difference('TimeEntry.count') do
109
+ post :save, :time_entries => {
110
+ "1234" => {
111
+ "comments" => 'a comment',
112
+ "project_id" => @project.id,
113
+ "issue_id" => @issue.id,
114
+ "activity_id" => @activity.id,
115
+ "spent_on" => '',
116
+ "hours" => '42'
117
+ }
118
+ }
119
+ end
120
+
121
+ end
122
+
123
+ should "re-render the time entry from" do
124
+ post :save, :time_entries => {
125
+ "1234" => {
126
+ "comments" => 'a comment',
127
+ "project_id" => @project.id,
128
+ "issue_id" => @issue.id,
129
+ "activity_id" => @activity.id,
130
+ "spent_on" => '',
131
+ "hours" => '42'
132
+ }
133
+ }
134
+
135
+ assert_select_rjs :replace, 'entry_1234', :text => /blank/
136
+ end
137
+ end
138
+
139
+ context "POST to :load_assigned_issues with an allowed project" do
140
+ setup do
141
+ @project = Project.generate!
142
+ generate_user_and_login_for_project(@project)
143
+ end
144
+
145
+ should "replace the issues selector" do
146
+ post :load_assigned_issues, :entry_id => '1234', :project_id => @project.id.to_s
147
+ assert_select_rjs :replace_html, '1234_issues'
148
+ end
149
+
150
+ should "replace the activities selector" do
151
+ post :load_assigned_issues, :entry_id => '1234', :project_id => @project.id.to_s
152
+ assert_select_rjs :replace_html, '1234_activities'
153
+ end
154
+ end
155
+
156
+ context "POST to :load_assigned_issues with an unallowed project" do
157
+ setup do
158
+ @project = Project.generate!
159
+ generate_user_and_login_for_project(@project)
160
+ @unallowed_project = Project.generate!
161
+ end
162
+
163
+ should "replace the issues selector with an empty select field" do
164
+ post :load_assigned_issues, :entry_id => '1234', :project_id => @unallowed_project.id.to_s
165
+ assert_select_rjs :replace_html, '1234_issues', :text => /no data to display/
166
+ end
167
+
168
+ should "replace the activities selector with an empty select field" do
169
+ post :load_assigned_issues, :entry_id => '1234', :project_id => @unallowed_project.id.to_s
170
+ assert_select_rjs :replace_html, '1234_activities', :text => /no data to display/
171
+ end
172
+ end
44
173
  end
data/test/test_helper.rb CHANGED
@@ -8,9 +8,13 @@ Engines::Testing.set_fixture_path
8
8
  class ActiveSupport::TestCase
9
9
  def setup
10
10
  User.anonymous
11
- non_member = Role.generate!
12
- non_member.builtin = Role::BUILTIN_NON_MEMBER
13
- non_member.save!
11
+ begin
12
+ Role.non_member
13
+ rescue
14
+ non_member = Role.generate!
15
+ non_member.builtin = Role::BUILTIN_NON_MEMBER
16
+ non_member.save!
17
+ end
14
18
  end
15
19
  end
16
20
 
@@ -0,0 +1,88 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+
3
+ class BulkTimeEntriesHelperTest < HelperTestCase
4
+ include ApplicationHelper
5
+ include BulkTimeEntriesHelper
6
+ include ActionController::Assertions::SelectorAssertions
7
+
8
+ # Used by assert_select
9
+ def html_document
10
+ HTML::Document.new(@response.body)
11
+ end
12
+
13
+ def setup
14
+ @response = ActionController::TestResponse.new
15
+ super
16
+ end
17
+
18
+ context "#grouped_options_for_issues" do
19
+ setup do
20
+ @project = Project.generate!
21
+ end
22
+
23
+ context "with no issues" do
24
+ should "return an empty option" do
25
+ @response.body = grouped_options_for_issues([])
26
+ assert_select 'option', :text => ''
27
+ end
28
+ end
29
+
30
+ context "with issues" do
31
+ setup do
32
+ closed = IssueStatus.generate!(:is_closed => true)
33
+ @issues = [
34
+ Issue.generate_for_project!(@project, :tracker => @project.trackers.first),
35
+ Issue.generate_for_project!(@project, :tracker => @project.trackers.first, :status => closed),
36
+ Issue.generate_for_project!(@project, :tracker => @project.trackers.first),
37
+ Issue.generate_for_project!(@project, :tracker => @project.trackers.first)
38
+ ]
39
+ @response.body = grouped_options_for_issues(@issues)
40
+ end
41
+
42
+ should 'render an option tag per issue plan a blank one' do
43
+ assert_select 'option', :count => 5
44
+ end
45
+
46
+ should 'group the open issues with the Open Issues label' do
47
+ assert_select 'optgroup[label=?]', l(:label_open_issues) do
48
+ assert_select 'option', :count => 3
49
+ end
50
+ end
51
+
52
+ should 'group the closed issues with the Closed Issues label' do
53
+ assert_select 'optgroup[label=?]', l(:label_closed_issues) do
54
+ assert_select 'option', :count => 1
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ context "#get_issues" do
61
+ context "as a user without any projects" do
62
+ should "be empty" do
63
+ @user = User.generate_with_protected!
64
+ User.current = @user
65
+ @project = Project.generate!
66
+ Issue.generate_for_project!(@project)
67
+ Issue.generate_for_project!(@project)
68
+
69
+ assert get_issues(@project.id).empty?
70
+ end
71
+ end
72
+
73
+ context "as a user with a project" do
74
+ should "return the project's issues" do
75
+ @project = Project.generate!
76
+ generate_user_and_login_for_project(@project)
77
+ User.current = @user
78
+ issue1 = Issue.generate_for_project!(@project)
79
+ issue2 = Issue.generate_for_project!(@project)
80
+
81
+ result = get_issues(@project.id)
82
+ assert_equal 2, result.size
83
+ assert result.include? issue1
84
+ assert result.include? issue2
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,49 @@
1
+ require 'test_helper'
2
+
3
+ class BulkTimeEntryPlugin::Patches::TimeEntryPatchTest < ActiveSupport::TestCase
4
+ context "TimeEntry#create_bulk_time_entry" do
5
+ setup do
6
+ User.current = @user = User.generate_with_protected!
7
+ @project = Project.generate!
8
+ @role = Role.generate!(:permissions => Redmine::AccessControl.permissions.collect(&:name))
9
+ Member.generate!(:project => @project, :roles => [@role], :principal => @user)
10
+ @valid_params = {:project_id => @project.id, :hours => 5, :activity_id => TimeEntryActivity.generate!.id, :spent_on => Date.today.to_s}
11
+ end
12
+
13
+ should "return the unsaved TimeEntry if the current user is not allowed to log time to the project" do
14
+ @role.update_attributes(:permissions => [])
15
+
16
+ assert_no_difference('TimeEntry.count') do
17
+ @entry = TimeEntry.create_bulk_time_entry(@valid_params)
18
+ end
19
+ assert_equal false, @entry.valid?
20
+ end
21
+
22
+ context "saving a valid record" do
23
+ should "save a new Time Entry record" do
24
+ assert_difference('TimeEntry.count') do
25
+ @entry = TimeEntry.create_bulk_time_entry(@valid_params)
26
+ end
27
+
28
+ assert @entry.is_a? TimeEntry
29
+ end
30
+
31
+ should "set the project of the new record" do
32
+ @entry = TimeEntry.create_bulk_time_entry(@valid_params)
33
+ assert_equal @project, @entry.project
34
+ end
35
+
36
+ should "assign the current user" do
37
+ @entry = TimeEntry.create_bulk_time_entry(@valid_params)
38
+ assert_equal @user, @entry.user
39
+ end
40
+
41
+ should "set hours to nil if they are passed in as 0" do
42
+ @entry = TimeEntry.create_bulk_time_entry(@valid_params.merge(:hours => 0))
43
+ assert_equal @user, @entry.user
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bulk_time_entry_plugin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Davis
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-30 00:00:00 -08:00
12
+ date: 2010-02-25 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -32,30 +32,41 @@ files:
32
32
  - app/controllers/bulk_time_entries_controller.rb
33
33
  - app/helpers/bulk_time_entries_helper.rb
34
34
  - app/models/bulk_time_entry.rb
35
+ - app/views/bulk_time_entries/_activities_selector.html.erb
35
36
  - app/views/bulk_time_entries/_issues_selector.html.erb
36
37
  - app/views/bulk_time_entries/_time_entry.html.erb
38
+ - app/views/bulk_time_entries/add_entry.js.rjs
37
39
  - app/views/bulk_time_entries/index.html.erb
40
+ - app/views/bulk_time_entries/load_assigned_issues.js.rjs
38
41
  - app/views/bulk_time_entries/no_projects.html.erb
42
+ - app/views/bulk_time_entries/save.js.rjs
43
+ - config/locales/de.yml
39
44
  - config/locales/en.yml
40
45
  - config/locales/fr.yml
41
46
  - config/locales/hu.yml
42
47
  - config/locales/it.yml
43
48
  - config/locales/ko.yml
49
+ - config/locales/nl.yml
44
50
  - config/locales/pl.yml
45
51
  - init.rb
52
+ - lang/de.yml
46
53
  - lang/en.yml
47
54
  - lang/fr.yml
48
55
  - lang/hu.yml
49
56
  - lang/it.yml
50
57
  - lang/ko.yml
58
+ - lang/nl.yml
51
59
  - lang/pl.yml
52
60
  - lib/bulk_time_entry_compatibility.rb
61
+ - lib/bulk_time_entry_plugin/patches/time_entry_patch.rb
53
62
  - lib/tasks/import_from_csv.rake
54
63
  - rails/init.rb
55
64
  - test/functional/bulk_time_entries_controller_test.rb
56
65
  - test/test_helper.rb
57
66
  - test/unit/bulk_time_entry_test.rb
58
67
  - test/unit/bulk_time_entry_transaction_test.rb
68
+ - test/unit/helpers/bulk_time_entries_helper_test.rb
69
+ - test/unit/lib/bulk_time_entry_plugin/patches/time_entry_patch_test.rb
59
70
  - test/unit/sanity_test.rb
60
71
  has_rdoc: true
61
72
  homepage: https://projects.littlestreamsoftware.com/projects/redmine-bte
@@ -89,5 +100,7 @@ test_files:
89
100
  - test/test_helper.rb
90
101
  - test/unit/bulk_time_entry_transaction_test.rb
91
102
  - test/unit/bulk_time_entry_test.rb
103
+ - test/unit/helpers/bulk_time_entries_helper_test.rb
104
+ - test/unit/lib/bulk_time_entry_plugin/patches/time_entry_patch_test.rb
92
105
  - test/unit/sanity_test.rb
93
106
  - test/functional/bulk_time_entries_controller_test.rb