bulk_time_entry_plugin 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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