Merge branch 'dev' into feature/21231-apply-table-styling

pull/6827/head
Henriette Dinger 9 years ago
commit 714666743f
  1. 12
      .rubocop.yml
  2. 6
      app/controllers/rb_application_controller.rb
  3. 5
      app/controllers/rb_burndown_charts_controller.rb
  4. 14
      app/controllers/rb_export_card_configurations_controller.rb
  5. 7
      app/controllers/rb_impediments_controller.rb
  6. 2
      app/controllers/rb_master_backlogs_controller.rb
  7. 13
      app/controllers/rb_queries_controller.rb
  8. 4
      app/controllers/rb_server_variables_controller.rb
  9. 4
      app/controllers/rb_sprints_controller.rb
  10. 10
      app/controllers/rb_stories_controller.rb
  11. 8
      app/controllers/rb_taskboards_controller.rb
  12. 7
      app/controllers/rb_tasks_controller.rb
  13. 6
      app/controllers/rb_wikis_controller.rb
  14. 4
      app/controllers/version_settings_controller.rb
  15. 14
      app/controllers/work_package_boxes_controller.rb
  16. 12
      app/helpers/burndown_charts_helper.rb
  17. 52
      app/helpers/rb_common_helper.rb
  18. 66
      app/helpers/rb_master_backlogs_helper.rb
  19. 6
      app/helpers/taskboards_helper.rb
  20. 14
      app/helpers/version_settings_helper.rb
  21. 10
      app/models/backlog.rb
  22. 36
      app/models/burndown.rb
  23. 36
      app/models/impediment.rb
  24. 97
      app/models/sprint.rb
  25. 53
      app/models/story.rb
  26. 18
      app/models/task.rb
  27. 6
      app/models/version_setting.rb
  28. 2
      app/views/version_settings/_form.html.erb
  29. 6
      app/views/versions/_form.html.erb
  30. 2
      config/locales/de.yml
  31. 16
      config/locales/fr.yml
  32. 145
      config/locales/it.yml
  33. 6
      config/locales/js-it.yml
  34. 6
      config/locales/js-sv-SE.yml
  35. 2
      config/locales/pt-BR.yml
  36. 145
      config/locales/sv-SE.yml
  37. 37
      config/routes.rb
  38. 67
      db/migrate/20111014073606_aggregated_backlogs_migrations.rb
  39. 3
      db/migrate/20130916094370_legacy_issues_backlogs_data_to_work_packages.rb
  40. 2
      db/migrate/20130919092624_add_backlog_columns_to_work_package_journal.rb
  41. 6
      features/fixed_version_by_issue_hierarchy.feature
  42. 80
      features/step_definitions/_given_steps.rb
  43. 58
      features/step_definitions/_then_steps.rb
  44. 118
      features/step_definitions/_when_steps.rb
  45. 15
      features/step_definitions/helpers.rb
  46. 8
      features/step_definitions/modal_steps.rb
  47. 13
      features/step_definitions/sprint_steps.rb
  48. 19
      features/step_definitions/story_steps.rb
  49. 10
      features/step_definitions/version_steps.rb
  50. 4
      features/support/paths.rb
  51. 2
      lib/open_project/backlogs.rb
  52. 2
      lib/open_project/backlogs/burndown/series.rb
  53. 14
      lib/open_project/backlogs/burndown/series_raw_data.rb
  54. 105
      lib/open_project/backlogs/engine.rb
  55. 30
      lib/open_project/backlogs/hooks.rb
  56. 17
      lib/open_project/backlogs/list.rb
  57. 4
      lib/open_project/backlogs/mixins/prevent_issue_sti.rb
  58. 8
      lib/open_project/backlogs/patches/my_controller_patch.rb
  59. 3
      lib/open_project/backlogs/patches/permitted_params_patch.rb
  60. 8
      lib/open_project/backlogs/patches/project_patch.rb
  61. 10
      lib/open_project/backlogs/patches/projects_controller_patch.rb
  62. 8
      lib/open_project/backlogs/patches/projects_helper_patch.rb
  63. 46
      lib/open_project/backlogs/patches/query_patch.rb
  64. 2
      lib/open_project/backlogs/patches/status_patch.rb
  65. 2
      lib/open_project/backlogs/patches/type_patch.rb
  66. 13
      lib/open_project/backlogs/patches/user_patch.rb
  67. 12
      lib/open_project/backlogs/patches/version_patch.rb
  68. 21
      lib/open_project/backlogs/patches/versions_controller_patch.rb
  69. 79
      lib/open_project/backlogs/patches/work_package_patch.rb
  70. 2
      lib/open_project/backlogs/patches/work_package_schema_patch.rb
  71. 11
      lib/open_project/backlogs/patches/work_packages_helper_patch.rb
  72. 2
      lib/openproject-backlogs.rb
  73. 30
      openproject-backlogs.gemspec
  74. 8
      spec/api/work_packages/create_contract_spec.rb
  75. 14
      spec/controllers/versions_controller_spec.rb
  76. 60
      spec/controllers/work_packages_controller_spec.rb
  77. 10
      spec/factories/impediment_factory.rb
  78. 6
      spec/factories/sprint_factory.rb
  79. 10
      spec/factories/story_factory.rb
  80. 10
      spec/factories/task_factory.rb
  81. 8
      spec/helpers/version_settings_helper_spec.rb
  82. 17
      spec/models/backlog_spec.rb
  83. 96
      spec/models/burndown_spec.rb
  84. 271
      spec/models/impediment_spec.rb
  85. 345
      spec/models/issue_fixed_version_propagated_down_spec.rb
  86. 204
      spec/models/issue_fixed_version_restricted_spec.rb
  87. 503
      spec/models/issue_hierarchy_restriction_project_boundaries_spec.rb
  88. 124
      spec/models/issue_position_spec.rb
  89. 33
      spec/models/issue_spec.rb
  90. 49
      spec/models/sprint_spec.rb
  91. 97
      spec/models/story_spec.rb
  92. 2
      spec/models/user_spec.rb
  93. 12
      spec/models/version_setting_spec.rb
  94. 54
      spec/models/version_spec.rb
  95. 18
      spec/models/work_package_spec.rb
  96. 14
      spec/routing/rb_burndown_charts_routing_spec.rb
  97. 26
      spec/routing/rb_impediments_routing_spec.rb
  98. 12
      spec/routing/rb_master_backlogs_routing_spec.rb
  99. 14
      spec/routing/rb_queries_routing_spec.rb
  100. 14
      spec/routing/rb_server_variables_routing_spec.rb
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,7 +1,6 @@
AllCops:
Exclude:
- db/schema.rb
- lib/plugins/rfpdf/**/*
"*.gemspec"
AccessorMethodName:
Enabled: false
@ -30,6 +29,15 @@ Attr:
BlockNesting:
Enabled: false
BlockDelimiters:
Enabled: true
EnforcedStyle: semantic
IgnoredMethods:
- default_scope
- lambda
- proc
- it
Blocks:
Enabled: false

@ -35,8 +35,6 @@
# Base class of all controllers in Backlogs
class RbApplicationController < ApplicationController
unloadable
helper :rb_common
before_filter :load_sprint_and_project, :check_if_plugin_is_configured, :authorize
@ -56,9 +54,9 @@ class RbApplicationController < ApplicationController
def check_if_plugin_is_configured
settings = Setting.plugin_openproject_backlogs
if settings["story_types"].blank? || settings["task_type"].blank?
if settings['story_types'].blank? || settings['task_type'].blank?
respond_to do |format|
format.html { render :file => "shared/not_configured" }
format.html { render file: 'shared/not_configured' }
end
end
end

@ -34,16 +34,13 @@
#++
class RbBurndownChartsController < RbApplicationController
unloadable
helper :burndown_charts
def show
@burndown = @sprint.burndown(@project)
respond_to do |format|
format.html { render :layout => false }
format.html { render layout: false }
end
end
end

@ -33,9 +33,7 @@
# See doc/COPYRIGHT.rdoc for more details.
#++
class RbExportCardConfigurationsController < RbApplicationController
unloadable
include OpenProject::PdfExport::ExportCard
before_filter :load_project_and_sprint
@ -49,12 +47,14 @@ class RbExportCardConfigurationsController < RbApplicationController
cards_document = OpenProject::PdfExport::ExportCard::DocumentGenerator.new(config, @sprint.stories(@project))
filename = "#{@project.to_s}-#{@sprint.to_s}-#{Time.now.strftime("%B-%d-%Y")}.pdf"
filename = "#{@project}-#{@sprint}-#{Time.now.strftime('%B-%d-%Y')}.pdf"
respond_to do |format|
format.pdf { send_data(cards_document.render,
:disposition => 'attachment',
:type => 'application/pdf',
:filename => filename) }
format.pdf {
send_data(cards_document.render,
disposition: 'attachment',
type: 'application/pdf',
filename: filename)
}
end
end

@ -34,15 +34,13 @@
#++
class RbImpedimentsController < RbApplicationController
unloadable
def create
@impediment = Impediment.create_with_relationships(params, @project.id)
status = (@impediment.errors.empty? ? 200 : 400)
@include_meta = true
respond_to do |format|
format.html { render :partial => "impediment", :object => @impediment, :status => status }
format.html { render partial: 'impediment', object: @impediment, status: status }
end
end
@ -53,8 +51,7 @@ class RbImpedimentsController < RbApplicationController
@include_meta = true
respond_to do |format|
format.html { render :partial => "impediment", :object => @impediment, :status => status }
format.html { render partial: 'impediment', object: @impediment, status: status }
end
end
end

@ -34,8 +34,6 @@
#++
class RbMasterBacklogsController < RbApplicationController
unloadable
menu_item :backlogs
before_filter :set_export_card_config_meta

@ -34,19 +34,18 @@
#++
class RbQueriesController < RbApplicationController
unloadable
include WorkPackagesFilterHelper
def show
filters = []
if params[:sprint_id]
filters.push(filter_object("status_id", "*"))
filters.push(filter_object("fixed_version_id", "=", [params[:sprint_id]]))
# Note: We need a filter for backlogs_work_package_type but currently it's not possible for plugins to introduce new filter types
filters.push(filter_object('status_id', '*'))
filters.push(filter_object('fixed_version_id', '=', [params[:sprint_id]]))
# Note: We need a filter for backlogs_work_package_type but currently it's not possible for plugins to introduce new filter types
else
filters.push(filter_object("status_id", "o"))
filters.push(filter_object("fixed_version_id", "!*", [params[:sprint_id]]))
# Same as above
filters.push(filter_object('status_id', 'o'))
filters.push(filter_object('fixed_version_id', '!*', [params[:sprint_id]]))
# Same as above
end
query = {

@ -34,11 +34,9 @@
#++
class RbServerVariablesController < RbApplicationController
unloadable
def show
respond_to do |format|
format.js { render :layout => false }
format.js { render layout: false }
end
end
end

@ -38,8 +38,6 @@
# objects within a sprint. For info about the taskboard, see
# RbTaskboardsController
class RbSprintsController < RbApplicationController
unloadable
def update
result = @sprint.update_attributes(params.slice(:name,
:start_date,
@ -47,7 +45,7 @@ class RbSprintsController < RbApplicationController
status = (result ? 200 : 400)
respond_to do |format|
format.html { render :partial => "sprint", :status => status, :object => @sprint }
format.html { render partial: 'sprint', status: status, object: @sprint }
end
end

@ -34,17 +34,16 @@
#++
class RbStoriesController < RbApplicationController
unloadable
include OpenProject::PdfExport::ExportCard
def create
params['author_id'] = User.current.id
story = Story.create_and_position(params, :project => @project,
:author => User.current)
story = Story.create_and_position(params, project: @project,
author: User.current)
status = (story.id ? 200 : 400)
respond_to do |format|
format.html { render :partial => "story", :object => story, :status => status }
format.html { render partial: 'story', object: story, status: status }
end
end
@ -55,8 +54,7 @@ class RbStoriesController < RbApplicationController
status = (result ? 200 : 400)
respond_to do |format|
format.html { render :partial => "story", :object => story, :status => status }
format.html { render partial: 'story', object: story, status: status }
end
end
end

@ -34,18 +34,16 @@
#++
class RbTaskboardsController < RbApplicationController
unloadable
menu_item :backlogs
helper :taskboards
def show
@statuses = Type.find_by_id(Task.type).statuses
@story_ids = @sprint.stories(@project).map{|s| s.id}
@story_ids = @sprint.stories(@project).map(&:id)
@last_updated = Task.find(:first,
:conditions => ["parent_id in (?)", @story_ids],
:order => "updated_at DESC")
conditions: ['parent_id in (?)', @story_ids],
order: 'updated_at DESC')
end
def default_breadcrumb

@ -34,8 +34,6 @@
#++
class RbTasksController < RbApplicationController
unloadable
def create
@task = Task.create_with_relationships(params, @project.id)
@ -43,7 +41,7 @@ class RbTasksController < RbApplicationController
@include_meta = true
respond_to do |format|
format.html { render :partial => "task", :object => @task, :status => status }
format.html { render partial: 'task', object: @task, status: status }
end
end
@ -54,8 +52,7 @@ class RbTasksController < RbApplicationController
@include_meta = true
respond_to do |format|
format.html { render :partial => "task", :object => @task, :status => status }
format.html { render partial: 'task', object: @task, status: status }
end
end
end

@ -34,17 +34,15 @@
#++
class RbWikisController < RbApplicationController
unloadable
# NOTE: The methods #show and #edit are public (see init.rb). We will let
# OpenProject's WikiController#index take care of autorization
#
# NOTE: The methods #show and #edit create a template page when called.
def show
redirect_to :controller => '/wiki', :action => 'index', :project_id => @project.id, :id => @sprint.wiki_page
redirect_to controller: '/wiki', action: 'index', project_id: @project.id, id: @sprint.wiki_page
end
def edit
redirect_to :controller => '/wiki', :action => 'edit', :project_id => @project.id, :id => @sprint.wiki_page
redirect_to controller: '/wiki', action: 'edit', project_id: @project.id, id: @sprint.wiki_page
end
end

@ -34,8 +34,6 @@
#++
class VersionSettingsController < RbApplicationController
unloadable
def edit
@version = Version.find(params[:id])
end
@ -45,6 +43,6 @@ class VersionSettingsController < RbApplicationController
def authorize
# Everyone with the right to edit versions has the right to edit version
# settings
super "versions", "edit"
super 'versions', 'edit'
end
end

@ -34,8 +34,6 @@
#++
class WorkPackageBoxesController < WorkPackagesController
unloadable
helper :rb_common
def show
@ -44,14 +42,14 @@ class WorkPackageBoxesController < WorkPackagesController
load_journals
@changesets = @work_package.changesets.visible.all
@changesets.reverse! if User.current.wants_comments_in_reverse_order?
@relations = @work_package.relations.select {|r| r.other_work_package(@work_package) && r.other_work_package(@work_package).visible? }
@relations = @work_package.relations.select { |r| r.other_work_package(@work_package) && r.other_work_package(@work_package).visible? }
@allowed_statuses = @work_package.new_statuses_allowed_to(User.current)
@edit_allowed = User.current.allowed_to?(:edit_work_packages, @project)
@priorities = IssuePriority.all
@time_entry = TimeEntry.new
respond_to do |format|
format.js { render :partial => 'show' }
format.js { render partial: 'show' }
end
end
@ -63,7 +61,7 @@ class WorkPackageBoxesController < WorkPackagesController
@journal = @work_package.current_journal
respond_to do |format|
format.js { render :partial => 'edit' }
format.js { render partial: 'edit' }
end
end
@ -74,12 +72,12 @@ class WorkPackageBoxesController < WorkPackagesController
@work_package.reload
load_journals
respond_to do |format|
format.js { render :partial => 'show' }
format.js { render partial: 'show' }
end
else
@journal = @work_package.current_journal
respond_to do |format|
format.js { render :partial => 'edit' }
format.js { render partial: 'edit' }
end
end
end
@ -87,7 +85,7 @@ class WorkPackageBoxesController < WorkPackagesController
private
def load_journals
@journals = @work_package.journals.find(:all, :include => [:user], :order => "#{Journal.table_name}.created_at ASC")
@journals = @work_package.journals.find(:all, include: [:user], order: "#{Journal.table_name}.created_at ASC")
@journals.reverse! if User.current.wants_comments_in_reverse_order?
end
end

@ -39,7 +39,7 @@ module BurndownChartsHelper
mvalue = (max / 25) + 1
labels = (0..mvalue).collect{ |i| "[#{i*25}, #{i*25}]"}
labels = (0..mvalue).map { |i| "[#{i * 25}, #{i * 25}]" }
mvalue = mvalue + 1 if mvalue == 1 || ((max % 25) == 0)
@ -51,17 +51,17 @@ module BurndownChartsHelper
end
def xaxis_labels(burndown)
burndown.days.enum_for(:each_with_index).collect{|d,i| "[#{i+1}, '#{escape_javascript(::I18n.t('date.abbr_day_names')[d.wday % 7])}']"}.join(',').html_safe +
", [#{burndown.days.length + 1}, '<span class=\"axislabel\">#{I18n.t('backlogs.date')}</span>']".html_safe
burndown.days.enum_for(:each_with_index).map { |d, i| "[#{i + 1}, '#{escape_javascript(::I18n.t('date.abbr_day_names')[d.wday % 7])}']" }.join(',').html_safe +
", [#{burndown.days.length + 1}, '<span class=\"axislabel\">#{I18n.t('backlogs.date')}</span>']".html_safe
end
def dataseries(burndown)
burndown.series.collect{|s| "#{s.first.to_s}: {label: '#{l('backlogs.' + s.first.to_s)}', data: [#{s.last.enum_for(:each_with_index).collect{|s, i| "[#{i+1}, #{s}] "}.join(', ')}]} "}.join(', ').html_safe
burndown.series.map { |s| "#{s.first}: {label: '#{l('backlogs.' + s.first.to_s)}', data: [#{s.last.enum_for(:each_with_index).map { |s, i| "[#{i + 1}, #{s}] " }.join(', ')}]} " }.join(', ').html_safe
end
def burndown_series_checkboxes(burndown)
boxes = ""
burndown.series(:all).collect{|s| s.first.to_s }.sort.each do |series|
boxes = ''
burndown.series(:all).map { |s| s.first.to_s }.sort.each do |series|
boxes += "<input class=\"series_enabled\" type=\"checkbox\" id=\"#{series}\" name=\"#{series}\" value=\"#{series}\" checked>#{l('backlogs.' + series.to_s)}<br/>"
end
boxes.html_safe

@ -34,14 +34,12 @@
#++
module RbCommonHelper
unloadable
def assignee_id_or_empty(story)
story.assigned_to_id.to_s
end
def assignee_name_or_empty(story)
story.blank? || story.assigned_to.blank? ? "" : "#{story.assigned_to.firstname} #{story.assigned_to.lastname}"
story.blank? || story.assigned_to.blank? ? '' : "#{story.assigned_to.firstname} #{story.assigned_to.lastname}"
end
def blocks_ids(ids)
@ -59,11 +57,11 @@ module RbCommonHelper
end
def color_contrast_class(task)
if is_assigned_task?(task)
color_contrast(background_color_hex(task)) ? 'light' : 'dark'
else
''
end
if is_assigned_task?(task)
color_contrast(background_color_hex(task)) ? 'light' : 'dark'
else
''
end
end
def is_assigned_task?(task)
@ -85,7 +83,7 @@ module RbCommonHelper
end
def work_package_link_or_empty(work_package)
modal_link_to_work_package(work_package.id, work_package, :class => 'prevent_edit') unless work_package.new_record?
modal_link_to_work_package(work_package.id, work_package, class: 'prevent_edit') unless work_package.new_record?
end
def modal_link_to_work_package(title, work_package, options = {})
@ -94,17 +92,17 @@ module RbCommonHelper
def modal_link_to(title, path, options = {})
html_id = "modal_work_package_#{SecureRandom.hex(10)}"
link_to(title, path, options.merge(:id => html_id, :'data-modal' => ''))
link_to(title, path, options.merge(id: html_id, :'data-modal' => ''))
end
def sprint_link_or_empty(item)
item_id = item.id.to_s
text = (item_id.length > 8 ? "#{item_id[0..1]}...#{item_id[-4..-1]}" : item_id)
item.new_record? ? "" : link_to(text, {:controller => '/sprint', :action => "show", :id => item}, {:class => "prevent_edit"})
item.new_record? ? '' : link_to(text, { controller: '/sprint', action: 'show', id: item }, class: 'prevent_edit')
end
def mark_if_closed(story)
!story.new_record? && work_package_status_for_id(story.status_id).is_closed? ? "closed" : ""
!story.new_record? && work_package_status_for_id(story.status_id).is_closed? ? 'closed' : ''
end
def story_points_or_empty(story)
@ -139,14 +137,13 @@ module RbCommonHelper
date_string_with_milliseconds(story.updated_on, 0.001) unless story.blank?
end
def date_string_with_milliseconds(d, add=0)
def date_string_with_milliseconds(d, add = 0)
return '' if d.blank?
d.strftime("%B %d, %Y %H:%M:%S") + '.' + (d.to_f % 1 + add).to_s.split('.')[1]
d.strftime('%B %d, %Y %H:%M:%S') + '.' + (d.to_f % 1 + add).to_s.split('.')[1]
end
def remaining_hours(item)
item.remaining_hours.blank? || item.remaining_hours==0 ? "" : item.remaining_hours
item.remaining_hours.blank? || item.remaining_hours == 0 ? '' : item.remaining_hours
end
def available_story_types
@ -178,13 +175,12 @@ module RbCommonHelper
end
def show_burndown_link(sprint)
ret = ""
ret = ''
ret += link_to(l('backlogs.show_burndown_chart'),
{},
class: 'show_burndown_chart button')
ret += javascript_tag "
jQuery(document).ready(function(){
var burndown = RB.Factory.initialize(RB.Burndown, jQuery('.show_burndown_chart'));
@ -215,23 +211,23 @@ module RbCommonHelper
end
def all_workflows
@all_workflows ||= Workflow.all(:include => [:new_status, :old_status],
:conditions => { :role_id => User.current.roles_for_project(@project).collect(&:id),
:type_id => story_types.collect(&:id) })
@all_workflows ||= Workflow.all(include: [:new_status, :old_status],
conditions: { role_id: User.current.roles_for_project(@project).map(&:id),
type_id: story_types.map(&:id) })
end
def all_work_package_status
@all_work_package_status ||= Status.all(:order => 'position ASC')
@all_work_package_status ||= Status.all(order: 'position ASC')
end
def backlogs_types
@backlogs_types ||= begin
backlogs_ids = Setting.plugin_openproject_backlogs["story_types"]
backlogs_ids << Setting.plugin_openproject_backlogs["task_type"]
backlogs_ids = Setting.plugin_openproject_backlogs['story_types']
backlogs_ids << Setting.plugin_openproject_backlogs['task_type']
Type.find(:all,
:conditions => { :id => backlogs_ids },
:order => 'position ASC')
conditions: { id: backlogs_ids },
order: 'position ASC')
end
end
@ -246,9 +242,9 @@ module RbCommonHelper
def story_types
@story_types ||= begin
backlogs_type_ids = Setting.plugin_openproject_backlogs["story_types"].map(&:to_i)
backlogs_type_ids = Setting.plugin_openproject_backlogs['story_types'].map(&:to_i)
backlogs_types.select{ |t| backlogs_type_ids.include?(t.id) }
backlogs_types.select { |t| backlogs_type_ids.include?(t.id) }
end
end

@ -34,20 +34,16 @@
#++
module RbMasterBacklogsHelper
unloadable
include Redmine::I18n
def render_backlog_menu(backlog)
content_tag(:div, :class => 'menu') do
content_tag(:div, class: 'menu') do
[
content_tag(:div, '', :class => "ui-icon ui-icon-carat-1-s"),
content_tag(:ul, :class => 'items') do
backlog_menu_items_for(backlog).map do |item|
content_tag(:li, item, :class => 'item')
end.join.html_safe
content_tag(:div, '', class: 'ui-icon ui-icon-carat-1-s'),
content_tag(:ul, class: 'items') do
backlog_menu_items_for(backlog).map { |item|
content_tag(:li, item, class: 'item')
}.join.html_safe
end
].join.html_safe
end
@ -73,14 +69,14 @@ module RbMasterBacklogsHelper
items[:new_story] = content_tag(:a,
l('backlogs.add_new_story'),
:href => '#',
:class => 'add_new_story')
href: '#',
class: 'add_new_story')
items[:stories_tasks] = link_to(l(:label_stories_tasks),
:controller => '/rb_queries',
:action => 'show',
:project_id => @project,
:sprint_id => backlog.sprint)
controller: '/rb_queries',
action: 'show',
project_id: @project,
sprint_id: backlog.sprint)
if @export_card_config_meta[:count] > 0
items[:configs] = export_export_cards_link(backlog)
@ -96,12 +92,12 @@ module RbMasterBacklogsHelper
def export_export_cards_link(backlog)
if @export_card_config_meta[:count] == 1
link_to(l(:label_backlogs_export_card_export),
:controller => '/rb_export_card_configurations',
:action => 'show',
:project_id => @project,
:sprint_id => backlog.sprint,
:id => @export_card_config_meta[:default],
:format => :pdf)
controller: '/rb_export_card_configurations',
action: 'show',
project_id: @project,
sprint_id: backlog.sprint,
id: @export_card_config_meta[:default],
format: :pdf)
else
export_modal_link(backlog)
end
@ -110,7 +106,7 @@ module RbMasterBacklogsHelper
def properties_link(backlog)
back_path = backlogs_project_backlogs_path(@project)
version_path = edit_version_path(backlog.sprint, :back_url => back_path)
version_path = edit_version_path(backlog.sprint, back_url: back_path)
link_to(l(:'backlogs.properties'), version_path)
end
@ -118,31 +114,31 @@ module RbMasterBacklogsHelper
def export_modal_link(backlog, options = {})
path = backlogs_project_sprint_export_card_configurations_path(@project.id, backlog.sprint.id)
html_id = "modal_work_package_#{SecureRandom.hex(10)}"
link_to(l(:label_backlogs_export_card_export), path, options.merge(:id => html_id, :'data-modal' => ''))
link_to(l(:label_backlogs_export_card_export), path, options.merge(id: html_id, :'data-modal' => ''))
end
def sprint_backlog_menu_items_for(backlog)
items = {}
items[:task_board] = link_to(l(:label_task_board),
:controller => '/rb_taskboards',
:action => 'show',
:project_id => @project,
:sprint_id => backlog.sprint)
controller: '/rb_taskboards',
action: 'show',
project_id: @project,
sprint_id: backlog.sprint)
if backlog.sprint.has_burndown?
items[:burndown] = content_tag(:a,
l('backlogs.show_burndown_chart'),
:href => '#',
:class => 'show_burndown_chart')
href: '#',
class: 'show_burndown_chart')
end
if @project.module_enabled? "wiki"
if @project.module_enabled? 'wiki'
items[:wiki] = link_to(l(:label_wiki),
:controller => '/rb_wikis',
:action => 'edit',
:project_id => @project,
:sprint_id => backlog.sprint)
controller: '/rb_wikis',
action: 'edit',
project_id: @project,
sprint_id: backlog.sprint)
end
items

@ -34,9 +34,7 @@
#++
module TaskboardsHelper
unloadable
def impediments_by_position_for_status sprint, project, status
sprint.impediments(project).select{ |i| i.status_id == status.id }.sort_by {|i| i.position.present? ? i.position : 0 }
def impediments_by_position_for_status(sprint, project, status)
sprint.impediments(project).select { |i| i.status_id == status.id }.sort_by { |i| i.position.present? ? i.position : 0 }
end
end

@ -34,8 +34,6 @@
#++
module VersionSettingsHelper
unloadable
def version_settings_fields(version, project)
setting = version_setting_for_project(version, project)
@ -53,14 +51,14 @@ module VersionSettingsHelper
def version_hidden_id_field(setting)
return '' unless setting.id
hidden_field_tag(name_for_setting_attributes("id"), setting.id)
hidden_field_tag(name_for_setting_attributes('id'), setting.id)
end
def version_setting_for_project(version, project)
setting = version.version_settings.detect { |vs| vs.project_id == project.id || vs.project_id.nil? }
# nil? because some settings in the active codebase do have that right now
setting ||= version.version_settings.new(:display => VersionSetting::DISPLAY_LEFT, :project => project)
setting ||= version.version_settings.new(display: VersionSetting::DISPLAY_LEFT, project: project)
setting
end
@ -73,17 +71,17 @@ module VersionSettingsHelper
options = [::VersionSetting::DISPLAY_NONE,
::VersionSetting::DISPLAY_LEFT,
::VersionSetting::DISPLAY_RIGHT]
options.collect {|s| [humanize_display_option(s), s]}
options.map { |s| [humanize_display_option(s), s] }
end
def humanize_display_option(option)
case option
when ::VersionSetting::DISPLAY_NONE
t("version_settings_display_option_none")
t('version_settings_display_option_none')
when ::VersionSetting::DISPLAY_LEFT
t("version_settings_display_option_left")
t('version_settings_display_option_left')
when ::VersionSetting::DISPLAY_RIGHT
t("version_settings_display_option_right")
t('version_settings_display_option_right')
end
end
end

@ -34,19 +34,17 @@
#++
class Backlog
unloadable
attr_accessor :sprint
attr_accessor :stories
def self.owner_backlogs(project, options = {} )
options.reverse_merge!({ :limit => nil })
def self.owner_backlogs(project, options = {})
options.reverse_merge!(limit: nil)
backlogs = Sprint.apply_to(project).open.displayed_right(project).order_by_name
stories_by_sprints = Story.backlogs(project.id, backlogs.map(&:id))
backlogs.map{ |sprint| new(:stories => stories_by_sprints[sprint.id], :owner_backlog => true, :sprint => sprint)}
backlogs.map { |sprint| new(stories: stories_by_sprints[sprint.id], owner_backlog: true, sprint: sprint) }
end
def self.sprint_backlogs(project)
@ -54,7 +52,7 @@ class Backlog
stories_by_sprints = Story.backlogs(project.id, sprints.map(&:id))
sprints.map{ |sprint| new(:stories => stories_by_sprints[sprint.id], :sprint => sprint)}
sprints.map { |sprint| new(stories: stories_by_sprints[sprint.id], sprint: sprint) }
end
def initialize(options = {})

@ -34,10 +34,8 @@
#++
class Burndown
unloadable
def initialize(sprint, project, burn_direction = nil)
burn_direction ||= Setting.plugin_openproject_backlogs["points_burn_direction"]
burn_direction ||= Setting.plugin_openproject_backlogs['points_burn_direction']
@sprint_id = sprint.id
@ -45,9 +43,9 @@ class Burndown
series_data = OpenProject::Backlogs::Burndown::SeriesRawData.new(project,
sprint,
:points => ["story_points"])
points: ['story_points'])
series_data.collect
series_data.map
calculate_series series_data
@ -61,41 +59,41 @@ class Burndown
attr_reader :story_points
attr_reader :story_points_ideal
def series(select = :active)
def series(_select = :active)
@available_series
end
private
def make_date_series sprint
def make_date_series(sprint)
@days = sprint.days
end
def calculate_series series_data
def calculate_series(series_data)
series_data.collect_names.each do |c|
# need to differentiate between hours and sp
make_series c.to_sym, series_data.unit_for(c), series_data[c].to_a.sort_by{ |a| a.first }.collect(&:last)
make_series c.to_sym, series_data.unit_for(c), series_data[c].to_a.sort_by(&:first).map(&:last)
end
calculate_ideals(series_data)
end
def calculate_ideals(data)
(["story_points"] & data.collect_names).each do |ideal|
(['story_points'] & data.collect_names).each do |ideal|
calculate_ideal(ideal, data.unit_for(ideal))
end
end
def calculate_ideal(name, unit)
max = self.send(name).first || 0.0
delta = max / (self.days.size - 1)
max = send(name).first || 0.0
delta = max / (days.size - 1)
ideal = []
days.each_with_index do |d, i|
days.each_with_index do |_d, i|
ideal[i] = max - delta * i
end
make_series name.to_s + "_ideal", unit, ideal
make_series name.to_s + '_ideal', unit, ideal
end
def make_series(name, units, data)
@ -107,19 +105,19 @@ class Burndown
def determine_max
@max = {
:points => @available_series.values.select{|s| s.unit == :points}.flatten.compact.reject(&:nan?).max || 0.0,
:hours => @available_series.values.select{|s| s.unit == :hours}.flatten.compact.reject(&:nan?).max || 0.0
points: @available_series.values.select { |s| s.unit == :points }.flatten.compact.reject(&:nan?).max || 0.0,
hours: @available_series.values.select { |s| s.unit == :hours }.flatten.compact.reject(&:nan?).max || 0.0
}
end
def to_h(keys, values)
return Hash[*keys.zip(values).flatten]
Hash[*keys.zip(values).flatten]
end
def workday_before(date = Date.today)
d = date - 1
#TODO: make weekday configurable
d = workday_before(d) unless (d.wday > 0 and d.wday < 6)
# TODO: make weekday configurable
d = workday_before(d) unless d.wday > 0 and d.wday < 6
d
end
end

@ -34,30 +34,28 @@
#++
class Impediment < Task
unloadable
extend OpenProject::Backlogs::Mixins::PreventIssueSti
after_save :update_blocks_list
validate :validate_blocks_list
safe_attributes "blocks_ids",
:if => lambda {|impediment, user|
(impediment.new_record? && user.allowed_to?(:create_impediments, impediment.project)) ||
user.allowed_to?(:update_impediments, impediment.project)
}
safe_attributes 'blocks_ids',
if: lambda {|impediment, user|
(impediment.new_record? && user.allowed_to?(:create_impediments, impediment.project)) ||
user.allowed_to?(:update_impediments, impediment.project)
}
def self.find(*args)
if args[1] && args[1][:conditions]
if args[1][:conditions].is_a?(Hash)
args[1][:conditions][:parent_id] = nil
args[1][:conditions][:type_id] = self.type
args[1][:conditions][:type_id] = type
elsif args[1][:conditions].is_a?(Array)
args[1][:conditions][0] += " AND parent_id is NULL AND type_id = #{self.type}"
args[1][:conditions][0] += " AND parent_id is NULL AND type_id = #{type}"
end
else
args << {:conditions => {:parent_id => nil, :type_id => self.type}}
args << { conditions: { parent_id: nil, type_id: type } }
end
super
@ -65,12 +63,12 @@ class Impediment < Task
def blocks_ids=(ids)
@blocks_ids_list = [ids] if ids.is_a?(Integer)
@blocks_ids_list = ids.split(/\D+/).map{|id| id.to_i} if ids.is_a?(String)
@blocks_ids_list = ids.map {|id| id.to_i} if ids.is_a?(Array)
@blocks_ids_list = ids.split(/\D+/).map(&:to_i) if ids.is_a?(String)
@blocks_ids_list = ids.map(&:to_i) if ids.is_a?(Array)
end
def blocks_ids
@blocks_ids_list ||= relations_from.select{ |rel| rel.relation_type == Relation::TYPE_BLOCKS }.collect(&:to_id)
@blocks_ids_list ||= relations_from.select { |rel| rel.relation_type == Relation::TYPE_BLOCKS }.map(&:to_id)
end
private
@ -82,16 +80,16 @@ class Impediment < Task
end
def remove_from_blocks_list
self.relations_from.delete(self.relations_from.select{|rel| rel.relation_type == Relation::TYPE_BLOCKS && !blocks_ids.include?(rel.to_id) })
relations_from.delete(relations_from.select { |rel| rel.relation_type == Relation::TYPE_BLOCKS && !blocks_ids.include?(rel.to_id) })
end
def add_to_blocks_list
currently_blocking = relations_from.select{|rel| rel.relation_type == Relation::TYPE_BLOCKS}.collect(&:to_id)
currently_blocking = relations_from.select { |rel| rel.relation_type == Relation::TYPE_BLOCKS }.map(&:to_id)
(self.blocks_ids - currently_blocking).each{ |id|
rel = Relation.new(:relation_type => Relation::TYPE_BLOCKS, :from => self)
(blocks_ids - currently_blocking).each{ |id|
rel = Relation.new(relation_type: Relation::TYPE_BLOCKS, from: self)
rel.to_id = id
self.relations_from << rel
relations_from << rel
}
end
@ -100,7 +98,7 @@ class Impediment < Task
errors.add :blocks_ids, :must_block_at_least_one_work_package
else
work_packages = WorkPackage.find_all_by_id(blocks_ids)
errors.add :blocks_ids, :can_only_contain_work_packages_of_current_sprint if work_packages.size == 0 || work_packages.any?{|i| i.fixed_version != self.fixed_version }
errors.add :blocks_ids, :can_only_contain_work_packages_of_current_sprint if work_packages.size == 0 || work_packages.any? { |i| i.fixed_version != fixed_version }
end
end
end

@ -36,41 +36,45 @@
require 'date'
class Sprint < Version
unloadable
scope :open_sprints, lambda { |project|
{
:order => "COALESCE(start_date, CAST('4000-12-30' as date)) ASC, COALESCE(effective_date, CAST('4000-12-30' as date)) ASC",
:conditions => [ "versions.status = 'open' and versions.project_id = ?", project.id ]
order: "COALESCE(start_date, CAST('4000-12-30' as date)) ASC, COALESCE(effective_date, CAST('4000-12-30' as date)) ASC",
conditions: ["versions.status = 'open' and versions.project_id = ?", project.id]
}
}
# null last ordering
scope :order_by_date, :order => "COALESCE(start_date, CAST('4000-12-30' as date)) ASC, COALESCE(effective_date, CAST('4000-12-30' as date)) ASC"
scope :order_by_name, :order => "#{Version.table_name}.name ASC"
scope :apply_to, lambda { |project| {:include => :project,
:conditions => ["#{Version.table_name}.project_id = #{project.id}" +
" OR (#{Project.table_name}.status = #{Project::STATUS_ACTIVE} AND (" +
" #{Version.table_name}.sharing = 'system'" +
" OR (#{Project.table_name}.lft >= #{project.root.lft} AND #{Project.table_name}.rgt <= #{project.root.rgt} AND #{Version.table_name}.sharing = 'tree')" +
" OR (#{Project.table_name}.lft < #{project.lft} AND #{Project.table_name}.rgt > #{project.rgt} AND #{Version.table_name}.sharing IN ('hierarchy', 'descendants'))" +
" OR (#{Project.table_name}.lft > #{project.lft} AND #{Project.table_name}.rgt < #{project.rgt} AND #{Version.table_name}.sharing = 'hierarchy')" +
"))"]}}
scope :displayed_left, lambda { |project| { :joins => sanitize_sql_array(["LEFT OUTER JOIN (SELECT * from #{VersionSetting.table_name}" +
" WHERE project_id = ? ) version_settings" +
" ON version_settings.version_id = versions.id",
project.id]),
:conditions => ["(version_settings.project_id = ? AND version_settings.display = ?)" +
" OR (version_settings.project_id is NULL)",
project.id, VersionSetting::DISPLAY_LEFT] } }
scope :displayed_right, lambda { |project| {:include => :version_settings,
:conditions => ["version_settings.project_id = ? AND version_settings.display = ?",
project.id, VersionSetting::DISPLAY_RIGHT]} }
def stories(project, options = {} )
scope :order_by_date, order: "COALESCE(start_date, CAST('4000-12-30' as date)) ASC, COALESCE(effective_date, CAST('4000-12-30' as date)) ASC"
scope :order_by_name, order: "#{Version.table_name}.name ASC"
scope :apply_to, lambda { |project|
{ include: :project,
conditions: ["#{Version.table_name}.project_id = #{project.id}" +
" OR (#{Project.table_name}.status = #{Project::STATUS_ACTIVE} AND (" +
" #{Version.table_name}.sharing = 'system'" +
" OR (#{Project.table_name}.lft >= #{project.root.lft} AND #{Project.table_name}.rgt <= #{project.root.rgt} AND #{Version.table_name}.sharing = 'tree')" +
" OR (#{Project.table_name}.lft < #{project.lft} AND #{Project.table_name}.rgt > #{project.rgt} AND #{Version.table_name}.sharing IN ('hierarchy', 'descendants'))" +
" OR (#{Project.table_name}.lft > #{project.lft} AND #{Project.table_name}.rgt < #{project.rgt} AND #{Version.table_name}.sharing = 'hierarchy')" +
'))'] }
}
scope :displayed_left, lambda { |project|
{ joins: sanitize_sql_array(["LEFT OUTER JOIN (SELECT * from #{VersionSetting.table_name}" +
' WHERE project_id = ? ) version_settings' +
' ON version_settings.version_id = versions.id',
project.id]),
conditions: ['(version_settings.project_id = ? AND version_settings.display = ?)' +
' OR (version_settings.project_id is NULL)',
project.id, VersionSetting::DISPLAY_LEFT] }
}
scope :displayed_right, lambda { |project|
{ include: :version_settings,
conditions: ['version_settings.project_id = ? AND version_settings.display = ?',
project.id, VersionSetting::DISPLAY_RIGHT] }
}
def stories(project, options = {})
Story.sprint_backlog(project, self, options)
end
@ -81,10 +85,10 @@ class Sprint < Version
def has_wiki_page
return false if wiki_page_title.blank?
page = project.wiki.find_page(self.wiki_page_title)
page = project.wiki.find_page(wiki_page_title)
return false if !page
template = project.wiki.find_page(Setting.plugin_openproject_backlogs["wiki_template"])
template = project.wiki.find_page(Setting.plugin_openproject_backlogs['wiki_template'])
return false if template && page.text == template.text
true
@ -93,14 +97,14 @@ class Sprint < Version
def wiki_page
return '' unless project.wiki
self.update_attribute(:wiki_page_title, Wiki.titleize(self.name)) if wiki_page_title.blank?
update_attribute(:wiki_page_title, Wiki.titleize(name)) if wiki_page_title.blank?
page = project.wiki.find_page(self.wiki_page_title)
template = project.wiki.find_page(Setting.plugin_openproject_backlogs["wiki_template"])
page = project.wiki.find_page(wiki_page_title)
template = project.wiki.find_page(Setting.plugin_openproject_backlogs['wiki_template'])
if template and not page
page = project.wiki.pages.build(:title => self.wiki_page_title)
page.build_content(:text => "h1. #{self.name}\n\n#{template.text}")
page = project.wiki.pages.build(title: wiki_page_title)
page.build_content(text: "h1. #{name}\n\n#{template.text}")
page.save!
end
@ -110,24 +114,24 @@ class Sprint < Version
def days(cutoff = nil, alldays = false)
# TODO: Assumes mon-fri are working days, sat-sun are not. This assumption
# is not globally right, we need to make this configurable.
cutoff = self.effective_date if cutoff.nil?
cutoff = effective_date if cutoff.nil?
(self.start_date .. cutoff).select {|d| alldays || (d.wday > 0 and d.wday < 6) }
(start_date..cutoff).select { |d| alldays || (d.wday > 0 and d.wday < 6) }
end
def has_burndown?
!!(self.effective_date and self.start_date)
!!(effective_date and start_date)
end
def activity
bd = self.burndown('up')
bd = burndown('up')
return false if bd.blank?
# Assume a sprint is active if it's only 2 days old
return true if bd.remaining_hours.size <= 2
WorkPackage.exists?(['fixed_version_id = ? and ((updated_on between ? and ?) or (created_on between ? and ?))',
self.id, -2.days.from_now, Time.now, -2.days.from_now, Time.now])
id, -2.days.from_now, Time.now, -2.days.from_now, Time.now])
end
def burndown(project, burn_direction = nil)
@ -138,18 +142,15 @@ class Sprint < Version
def self.generate_burndown(only_current = true)
if only_current
conditions = ["? BETWEEN start_date AND effective_date", Date.today]
conditions = ['? BETWEEN start_date AND effective_date', Date.today]
else
conditions = "1 = 1"
conditions = '1 = 1'
end
Version.find(:all, :conditions => conditions).each { |sprint|
sprint.burndown
}
Version.find(:all, conditions: conditions).each(&:burndown)
end
def impediments(project)
Impediment.find(:all, :conditions => {:fixed_version_id => self, :project_id => project})
Impediment.find(:all, conditions: { fixed_version_id: self, project_id: project })
end
end

@ -34,14 +34,11 @@
#++
class Story < WorkPackage
unloadable
extend OpenProject::Backlogs::Mixins::PreventIssueSti
def self.backlogs(project_id, sprint_ids, options = {})
options.reverse_merge!({ :order => Story::ORDER,
:conditions => Story.condition(project_id, sprint_ids) })
options.reverse_merge!(order: Story::ORDER,
conditions: Story.condition(project_id, sprint_ids))
candidates = Story.all(options)
@ -61,7 +58,7 @@ class Story < WorkPackage
stories_by_version
end
def self.sprint_backlog(project, sprint, options={})
def self.sprint_backlog(project, sprint, options = {})
Story.backlogs(project.id, [sprint.id], options)[sprint.id]
end
@ -78,51 +75,51 @@ class Story < WorkPackage
end
def self.at_rank(project_id, sprint_id, rank)
return Story.find(:first,
:order => Story::ORDER,
:conditions => Story.condition(project_id, sprint_id),
:joins => :status,
:limit => 1,
:offset => rank - 1)
Story.find(:first,
order: Story::ORDER,
conditions: Story.condition(project_id, sprint_id),
joins: :status,
limit: 1,
offset: rank - 1)
end
def self.types
types = Setting.plugin_openproject_backlogs["story_types"]
types = Setting.plugin_openproject_backlogs['story_types']
return [] if types.blank?
types.map { |type| Integer(type) }
end
def tasks
Task.tasks_for(self.id)
Task.tasks_for(id)
end
def tasks_and_subtasks
return [] unless Task.type
self.descendants.find_all_by_type_id(Task.type)
descendants.find_all_by_type_id(Task.type)
end
def direct_tasks_and_subtasks
return [] unless Task.type
self.children.find_all_by_type_id(Task.type).collect { |t| [t] + t.descendants }.flatten
children.find_all_by_type_id(Task.type).map { |t| [t] + t.descendants }.flatten
end
def set_points(p)
self.init_journal(User.current)
init_journal(User.current)
if p.blank? || p == '-'
self.update_attribute(:story_points, nil)
update_attribute(:story_points, nil)
return
end
if p.downcase == 's'
self.update_attribute(:story_points, 0)
update_attribute(:story_points, 0)
return
end
p = Integer(p)
if p >= 0
self.update_attribute(:story_points, p)
update_attribute(:story_points, p)
return
end
end
@ -136,7 +133,7 @@ class Story < WorkPackage
closed = 0
open = 0
self.tasks.each do |task|
tasks.each do |task|
if task.closed?
closed += 1
else
@ -144,7 +141,7 @@ class Story < WorkPackage
end
end
{:open => open, :closed => closed}
{ open: open, closed: closed }
end
def update_and_position!(params)
@ -164,21 +161,21 @@ class Story < WorkPackage
end
def rank
if self.position.blank?
extras = ["and ((#{WorkPackage.table_name}.position is NULL and #{WorkPackage.table_name}.id <= ?) or not #{WorkPackage.table_name}.position is NULL)", self.id]
if position.blank?
extras = ["and ((#{WorkPackage.table_name}.position is NULL and #{WorkPackage.table_name}.id <= ?) or not #{WorkPackage.table_name}.position is NULL)", id]
else
extras = ["and not #{WorkPackage.table_name}.position is NULL and #{WorkPackage.table_name}.position <= ?", self.position]
extras = ["and not #{WorkPackage.table_name}.position is NULL and #{WorkPackage.table_name}.position <= ?", position]
end
@rank ||= WorkPackage.count(:conditions => Story.condition(self.project.id, self.fixed_version_id, extras), :joins => :status)
@rank ||= WorkPackage.count(conditions: Story.condition(project.id, fixed_version_id, extras), joins: :status)
return @rank
@rank
end
private
def self.condition(project_id, sprint_ids, extras = [])
c = ["project_id = ? AND type_id in (?) AND fixed_version_id in (?)",
c = ['project_id = ? AND type_id in (?) AND fixed_version_id in (?)',
project_id, Story.types, sprint_ids]
if extras.size > 0

@ -36,19 +36,17 @@
require 'date'
class Task < WorkPackage
unloadable
extend OpenProject::Backlogs::Mixins::PreventIssueSti
def self.type
task_type = Setting.plugin_openproject_backlogs["task_type"]
task_type = Setting.plugin_openproject_backlogs['task_type']
task_type.blank? ? nil : task_type.to_i
end
# This method is used by Backlogs::List. It ensures, that tasks and stories
# follow a similar interface
def self.types
[self.type]
[type]
end
def self.create_with_relationships(params, project_id)
@ -64,11 +62,11 @@ class Task < WorkPackage
task.move_after params[:prev]
end
return task
task
end
def self.tasks_for(story_id)
Task.find_all_by_parent_id(story_id, :order => :lft).each_with_index do |task, i|
Task.find_all_by_parent_id(story_id, order: :lft).each_with_index do |task, i|
task.rank = i + 1
end
end
@ -78,7 +76,7 @@ class Task < WorkPackage
self.remaining_hours = 0 if Status.find(id).is_closed?
end
def update_with_relationships(params, is_impediment = false)
def update_with_relationships(params, _is_impediment = false)
self.safe_attributes = params
save.tap do |result|
@ -89,7 +87,7 @@ class Task < WorkPackage
# Assumes the task is already under the same story as 'prev_id'
def move_after(prev_id)
if prev_id.blank?
sib = self.siblings
sib = siblings
move_to_left_of(sib[0].id) if sib.any?
else
move_to_right_of(prev_id)
@ -101,7 +99,7 @@ class Task < WorkPackage
end
def rank
@rank ||= WorkPackage.count(:conditions => ['type_id = ? and not parent_id is NULL and root_id = ? and lft <= ?', Task.type, story_id, self.lft])
return @rank
@rank ||= WorkPackage.count(conditions: ['type_id = ? and not parent_id is NULL and root_id = ? and lft <= ?', Task.type, story_id, lft])
@rank
end
end

@ -46,7 +46,7 @@ class VersionSetting < ActiveRecord::Base
DISPLAY_RIGHT = 3
def display_right?
self.display == DISPLAY_RIGHT
display == DISPLAY_RIGHT
end
def display_right!
@ -54,7 +54,7 @@ class VersionSetting < ActiveRecord::Base
end
def display_left?
self.display == DISPLAY_LEFT
display == DISPLAY_LEFT
end
def display_left!
@ -62,7 +62,7 @@ class VersionSetting < ActiveRecord::Base
end
def display_none?
self.display == DISPLAY_NONE
display == DISPLAY_NONE
end
def display_none!

@ -36,6 +36,6 @@ See doc/COPYRIGHT.rdoc for more details.
<%= error_messages_for 'version' %>
<% if @project.enabled_modules.collect(&:name).include?("backlogs") %>
<% if @project.enabled_modules.map(&:name).include?("backlogs") %>
<%= version_settings_fields @version, @project %>
<% end %>

@ -45,7 +45,7 @@ See doc/COPYRIGHT.rdoc for more details.
<%= f.text_field :description %>
</div>
<div class="form--field">
<%= f.select :status, Version::VERSION_STATUSES.collect {|s| [l("version_status_#{s}"), s]} %>
<%= f.select :status, Version::VERSION_STATUSES.map {|s| [l("version_status_#{s}"), s]} %>
</div>
<div class="form--field">
<%= f.text_field :wiki_page_title, label: :label_wiki_page, disabled: @project.wiki.nil? %>
@ -57,11 +57,11 @@ See doc/COPYRIGHT.rdoc for more details.
<%= f.text_field :effective_date %><%= calendar_for('version_effective_date') %>
</div>
<div class="form--field">
<%= f.select :sharing, @version.allowed_sharings.collect {|v| [format_version_sharing(v), v]} %>
<%= f.select :sharing, @version.allowed_sharings.map {|v| [format_version_sharing(v), v]} %>
</div>
<% end %>
<% if @project.enabled_modules.collect(&:name).include?("backlogs") %>
<% if @project.enabled_modules.map(&:name).include?("backlogs") %>
<%= version_settings_fields(@version, @project).html_safe %>

@ -5,7 +5,7 @@ de:
position: Position
remaining_hours: Verbleibende Stunden
story_points: Story Punkte
backlogs_work_package_type: Backlog type
backlogs_work_package_type: Backlog Typ
errors:
models:
work_package:

@ -2,7 +2,7 @@ fr:
activerecord:
attributes:
work_package:
position: Position
position: position
remaining_hours: Heures restantes
story_points: "Points d'histoire"
backlogs_work_package_type: Type de backlog
@ -11,15 +11,15 @@ fr:
work_package:
attributes:
blocks_ids:
can_only_contain_work_packages_of_current_sprint: can only contain IDs of work packages in the current sprint.
must_block_at_least_one_work_package: must contain the ID of at least one ticket.
can_only_contain_work_packages_of_current_sprint: ne peut contenir que des ID de lots de travaux du sprint actuel.
must_block_at_least_one_work_package: "doit contenir l'ID d'au moins un ticket."
fixed_version_id:
task_version_must_be_the_same_as_story_version: "must be the same as the story's version."
task_version_must_be_the_same_as_story_version: "doit être identique à la version de l'histoire."
parent_id:
parent_child_relationship_across_projects: "is invalid because the work package '%{work_package_name}' is a backlog task and therefore cannot have a parent outside of the current project."
type_must_be_one_of_the_following: 'Type must be one of the following: %{type_names}.'
parent_child_relationship_across_projects: "n'est pas valide parce que le lot de travaux «%{work_package_name}» est une tâche de backlog et par conséquent ne peut avoir un parent en dehors du projet actuel."
type_must_be_one_of_the_following: 'Type doit être parmi : %{type_names}.'
sprint:
cannot_end_before_it_starts: Sprint cannot end before it starts.
cannot_end_before_it_starts: "Un sprint ne peut pas se terminer avant d'avoir débuté."
backlogs:
add_new_story: Nouvelle histoire
any: tout
@ -88,7 +88,7 @@ fr:
label_backlog: Backlog
label_backlogs: Backlogs
label_backlogs_unconfigured: "Vous n'avez pas encore configuré Backlogs. Veuillez vous rendre dans %{administration} > %{plugins}, puis cliquer sur le lien %{configure} pour ce plugin. Une fois que vous avez défini les champs, revenez sur cette page pour commencer à utiliser l'outil."
label_blocks_ids: IDs of blocked work packages
label_blocks_ids: ID des lots de travaux bloqués
label_burndown: Avancement
label_chart_options: Options du graphique
label_column_in_backlog: Colonne dans le backlog

@ -0,0 +1,145 @@
it:
activerecord:
attributes:
work_package:
position: Posizione
remaining_hours: Ore rimanenti
story_points: Punti della storia
backlogs_work_package_type: Tipo di backlog
errors:
models:
work_package:
attributes:
blocks_ids:
can_only_contain_work_packages_of_current_sprint: può contenere solo ID dei pacchetti di lavoro presenti nello sprint corrente.
must_block_at_least_one_work_package: "deve contenere l'ID di almeno un ticket."
fixed_version_id:
task_version_must_be_the_same_as_story_version: deve essere uguale alla versione della storia.
parent_id:
parent_child_relationship_across_projects: "non è valido perché il pacchetto di lavoro '%{work_package_name}' è un task di backlog e pertanto non può avere una dipendenza esterna al progetto corrente."
type_must_be_one_of_the_following: 'Il tipo deve essere uno dei seguenti: %{type_names}.'
sprint:
cannot_end_before_it_starts: Uno sprint non può terminare prima che venga avviato.
backlogs:
add_new_story: Nuova storia
any: qualsiasi
backlog_settings: Impostazioni di backlog
burndown_graph: Grafico Burndown
card_paper_size: Formato della carta per la stampa delle schede
chart_options: Serie attive
close: Chiuso
column_width: 'Larghezza della colonna:'
date: Giorno
definition_of_done: Definizione di fatto
generating_chart: Grafico in generazione...
hours: Ore
impediment: Impedimento
label_versions_default_fold_state: Espandi le versioni
work_package_is_closed: Il pacchetto di lavoro è fatto, quando
label_is_done_status: 'Lo stato %{status_name} vuol dire completato'
no_burndown_data: Non sono disponibili i dati del burndown. È necessario avere impostato le date di inizio e fine dello sprint.
points: Punti
positions_could_not_be_rebuilt: Le posizioni non potrebbero essere ricostruite.
positions_rebuilt_successfully: Posizioni ricostruite correttamente.
properties: Proprietà
rebuild: Ricostruisci
rebuild_positions: Ricostruisce le posizioni
remaining_hours: Ore rimanenti
remaining_hours_ideal: Ore rimanenti (ideale)
show_burndown_chart: Grafico Burndown
story: Storia
story_points: Punti della storia
story_points_ideal: Punti della storia (ideale)
task: Attività
task_color: Colore attività
unassigned: Non assegnato
x_more: '%{count} più...'
backlogs_active: attivo
backlogs_any: qualsiasi
backlogs_card_specification: Tipi di etichette per la stampa delle schede
backlogs_inactive: Progetto non mostra alcuna attività
backlogs_points_burn_direction: Punteggi per burn positivo/negativo
backlogs_product_backlog: Backlog prodotto
backlogs_product_backlog_is_empty: Il backlog prodotto è vuoto
backlogs_product_backlog_unsized: In cima al prodotto backlog vi sono storie non quantificate
backlogs_sizing_inconsistent: Le dimensioni della storia variano rispetto le loro stime
backlogs_sprint_notes_missing: Sprint chiusi senza note retrospettive/recensioni
backlogs_sprint_unestimated: Sprint chiusi o attivi con storie non quantificate
backlogs_sprint_unsized: Il progetto ha storie su sprint attivi o chiusi di recente che non sono stati quantificati
backlogs_sprints: Sprint
backlogs_story: Storia
backlogs_story_type: Tipi di storia
backlogs_task: Attività
backlogs_task_type: Tipo di attività
backlogs_velocity_missing: Per questo progetto non può essere calcolata la velocità
backlogs_velocity_varies: La velocità del progetto varia in modo significativo tra gli sprint
backlogs_wiki_template: Modello per pagina wiki dello sprint
button_edit_wiki: Modifica la pagina wiki
error_intro_plural: 'Si sono verificati i seguenti errori:'
error_intro_singular: 'È stato rilevato il seguente errore:'
error_outro: Si prega di correggere gli errori riportati prima di inviare nuovamente.
event_sprint_description: |
%{summary}: %{url}
%{description}
event_sprint_summary: '%{project}: %{summary}'
ideal: ideale
inclusion: "non è incluso nell'elenco"
label_back_to_project: Torna alla pagina del progetto
label_backlog: Backlog
label_backlogs: Backlog
label_backlogs_unconfigured: 'Non hai ancora configurato i Backlog. Vai su %{administration} > %{plugins}, quindi fai clic sul link %{configure} per il plugin. Dopo aver impostato i campi, torna su questa pagina per iniziare a utilizzare lo strumento.'
label_blocks_ids: ID dei pacchetti di lavoro bloccati
label_burndown: Burndown
label_chart_options: Opzioni grafico
label_column_in_backlog: Colonna nel backlog
label_hours: ore
label_work_package_hierarchy: Gerarchia dei pacchetto di lavoro
label_master_backlog: Master Backlog
label_not_prioritized: priorità non definita
label_points: punti
label_points_burn_down: Verso il basso
label_points_burn_up: "Verso l'alto"
label_product_backlog: backlog prodotto
label_select_all: Seleziona tutto
label_sprint_backlog: backlog di sprint
label_sprint_cards: Esporta schede
label_sprint_impediments: Impedimenti allo sprint
label_sprint_name: 'Sprint "%{name}"'
label_sprint_velocity: 'La velocity %{velocity}, basato su %{sprints} Sprint di %{days} giorni in media'
label_stories: Storie
label_stories_tasks: Storie/Attività
label_task_board: Pannello delle attività
label_version_setting: Versioni
label_webcal: Webcal Feed
label_wiki: Wiki
permission_view_master_backlog: Visualizza il master backlog
permission_view_taskboards: Visualizza i pannelli delle attività
permission_update_sprints: Aggiorna gli sprint
permission_create_stories: Crea le storie
permission_update_stories: Aggiorna le storie
permission_create_tasks: Crea attività
permission_update_tasks: Aggiorna attività
permission_create_impediments: Crea impedimenti
permission_update_impediments: Aggiorna impedimenti
points_accepted: punti accettati
points_committed: punti prenotati
points_resolved: punti risolti
points_to_accept: punti non accettati
points_to_resolve: punti non risolti
project_module_backlogs: Backlog
rb_label_copy_tasks: Copia i pacchetti di lavoro
rb_label_copy_tasks_all: Tutti
rb_label_copy_tasks_none: Nessuno
rb_label_copy_tasks_open: Aperti
rb_label_link_to_original: Include il link alla storia originale
remaining_hours: ore rimanenti
required_burn_rate_hours: burn rate richiesto (ore)
required_burn_rate_points: burn rate richiesto (punti)
todo_work_package_description: |
%{summary}: %{url}
%{description}
todo_work_package_summary: '%{type}: %{summary}'
version_settings_display_label: Colonna nel backlog
version_settings_display_option_left: sinistra
version_settings_display_option_none: nessuno
version_settings_display_option_right: destra

@ -0,0 +1,6 @@
it:
js:
work_packages:
properties:
storyPoints: Punti della storia
remainingTime: Ore rimanenti

@ -0,0 +1,6 @@
sv:
js:
work_packages:
properties:
storyPoints: Berättelsepoäng
remainingTime: Återstående timmar

@ -12,7 +12,7 @@ pt-BR:
attributes:
blocks_ids:
can_only_contain_work_packages_of_current_sprint: pode conter somente os IDs dos pacotes de trabalho no sprint atual.
must_block_at_least_one_work_package: deve conter o ID de pelo menos um bilhete.
must_block_at_least_one_work_package: deve conter o ID de pelo menos um tíquete.
fixed_version_id:
task_version_must_be_the_same_as_story_version: deve ser da mesma versão da história.
parent_id:

@ -0,0 +1,145 @@
sv:
activerecord:
attributes:
work_package:
position: Position
remaining_hours: Återstående timmar
story_points: Berättelsepoäng
backlogs_work_package_type: Typ av backlogg
errors:
models:
work_package:
attributes:
blocks_ids:
can_only_contain_work_packages_of_current_sprint: kan endast innehålla ID:n för arbetspaket i den aktuella sprinten.
must_block_at_least_one_work_package: måste innehålla ID för minst ett arbetspaket.
fixed_version_id:
task_version_must_be_the_same_as_story_version: måste vara samma som berättelsens version.
parent_id:
parent_child_relationship_across_projects: "är ogiltig eftersom arbetspaketet '%{work_package_name}' är en backlog aktivitet och kan därför inte ha en förälder utanför det aktuella projektet."
type_must_be_one_of_the_following: 'Typen måste vara en av följande: %{type_names}.'
sprint:
cannot_end_before_it_starts: En sprint kan inte avslutas innan den startar.
backlogs:
add_new_story: Ny berättelse
any: någon
backlog_settings: Inställningar för backlog
burndown_graph: Burndown Graph
card_paper_size: Pappersstorlek för kortutskrift
chart_options: Aktiva serier
close: Stäng
column_width: 'Kolumnens bredd:'
date: Dag
definition_of_done: Definition av klart
generating_chart: Genererar diagram...
hours: Timmar
impediment: Hinder
label_versions_default_fold_state: Visa ihopfällda versioner
work_package_is_closed: Arbetspaket är klart, när
label_is_done_status: 'Status %{status_name} innebär klart'
no_burndown_data: 'Ingen Burndown data tillgänglig. Start- och slutdatum för sprint måste definieras.'
points: Poäng
positions_could_not_be_rebuilt: Positioner kunde inte beräknas om.
positions_rebuilt_successfully: Positioner beräknades om.
properties: Egenskaper
rebuild: Rekonstruera
rebuild_positions: Rekonstruera positioner
remaining_hours: Återstående timmar
remaining_hours_ideal: Återstående timmar (ideal)
show_burndown_chart: Burndown-diagram
story: Berättelse
story_points: Berättelsepoäng
story_points_ideal: Berättelsepoäng (ideala)
task: Aktivitet
task_color: Aktivitetsfärg
unassigned: Ej tilldelad
x_more: '%{count} mer...'
backlogs_active: aktiv
backlogs_any: någon
backlogs_card_specification: Typ av etikett för kortutskrift
backlogs_inactive: Projektet visar ingen aktivitet
backlogs_points_burn_direction: Burn up/-down poäng
backlogs_product_backlog: Produktbacklog
backlogs_product_backlog_is_empty: Produktbacklogen är tom
backlogs_product_backlog_unsized: Toppen av produktbackloggen har berättelser utan storlek
backlogs_sizing_inconsistent: Berättelsernas storlekar avviker ifrån sina uppskattningar
backlogs_sprint_notes_missing: Stängda sprinter utan retrospektiv/granskningsanteckningar
backlogs_sprint_unestimated: Stängda eller aktiva sprintar med berättelser utan storlek
backlogs_sprint_unsized: Projektet har aktiva eller nyligen stängda sprintar med berättelser som saknar storlek
backlogs_sprints: Sprinter
backlogs_story: Berättelse
backlogs_story_type: Berättelsetyp
backlogs_task: Aktivitet
backlogs_task_type: Aktivitetstyp
backlogs_velocity_missing: Ingen hastighet kunde beräknas för detta projekt
backlogs_velocity_varies: Hastigheten varierar betydligt över sprinter
backlogs_wiki_template: Mall för sprint wiki-sida
button_edit_wiki: Redigera wiki-sidor
error_intro_plural: 'Följande fel uppstod:'
error_intro_singular: 'Följande fel uppstod:'
error_outro: Vänligen korrigera ovanstående fel innan du skickar in igen.
event_sprint_description: |
%{summary}: %{url}
%{description}
event_sprint_summary: '%{project}: %{summary}'
ideal: ideala
inclusion: ingår inte i listan
label_back_to_project: Tillbaka till projektsidan
label_backlog: Backlog
label_backlogs: Backloggar
label_backlogs_unconfigured: 'Du har inte konfigurerat backloggar ännu. Gå till %{administration} > %{plugins}, klicka på %{configure} länken för denna plugin. När du har ställt in fälten, kan du komma tillbaka till denna sida för att börja använda verktyget.'
label_blocks_ids: ID:n för blockerade arbetspaket
label_burndown: Burndown
label_chart_options: Diagramalternativ
label_column_in_backlog: Kolumn i backlog
label_hours: timmar
label_work_package_hierarchy: Arbetspaketshierarki
label_master_backlog: Master Backlog
label_not_prioritized: inte prioriterad
label_points: poäng
label_points_burn_down: Ner
label_points_burn_up: Upp
label_product_backlog: produkt backlog
label_select_all: Markera alla
label_sprint_backlog: sprint backlogg
label_sprint_cards: Exportera kort
label_sprint_impediments: Sprint hinder
label_sprint_name: 'Sprint "%{name}"'
label_sprint_velocity: 'Hastighet %{velocity}, baserat på %{sprints} sprinter med genomsnitt av %{days} dagar'
label_stories: Berättelser
label_stories_tasks: Berättelser/uppgifter
label_task_board: Aktivitetstavla
label_version_setting: Versioner
label_webcal: Webcal Feed
label_wiki: Wiki
permission_view_master_backlog: Visa master backlog
permission_view_taskboards: Visa aktivitetstavlor
permission_update_sprints: Uppdatera sprinter
permission_create_stories: Skapa berättelser
permission_update_stories: Uppdatera berättelser
permission_create_tasks: Skapa aktiviteter
permission_update_tasks: Uppdatera aktiviteter
permission_create_impediments: Skapa hinder
permission_update_impediments: Uppdatera hinder
points_accepted: accepterade poäng
points_committed: incheckade poäng
points_resolved: lösta poäng
points_to_accept: ej accepterade poäng
points_to_resolve: ej lösta poäng
project_module_backlogs: Backloggar
rb_label_copy_tasks: Kopiera arbetspaket
rb_label_copy_tasks_all: Alla
rb_label_copy_tasks_none: Inga
rb_label_copy_tasks_open: Öppna
rb_label_link_to_original: Inkludera länk till originalberättelsen
remaining_hours: återstående timmar
required_burn_rate_hours: tempo som krävs (timmar)
required_burn_rate_points: tempo som krävs (poäng)
todo_work_package_description: |
%{summary}: %{url}
%{description}
todo_work_package_summary: '%{type}: %{summary}'
version_settings_display_label: Kolumn i backlog
version_settings_display_option_left: vänster
version_settings_display_option_none: inga
version_settings_display_option_right: höger

@ -34,40 +34,35 @@
#++
OpenProject::Application.routes.draw do
scope '', as: 'backlogs' do
scope 'projects/:project_id', as: 'project' do
resources :backlogs, controller: :rb_master_backlogs, only: :index
scope "", as: "backlogs" do
resource :server_variables, controller: :rb_server_variables, only: :show, format: :js
scope "projects/:project_id", as: 'project' do
resources :sprints, controller: :rb_sprints, only: :update do
resource :query, controller: :rb_queries, only: :show
resources :backlogs, :controller => :rb_master_backlogs, :only => :index
resource :taskboard, controller: :rb_taskboards, only: :show
resource :server_variables, :controller => :rb_server_variables, :only => :show, :format => :js
resource :wiki, controller: :rb_wikis, only: [:show, :edit]
resources :sprints, :controller => :rb_sprints, :only => :update do
resource :burndown_chart, controller: :rb_burndown_charts, only: :show
resource :query, :controller => :rb_queries, :only => :show
resources :impediments, controller: :rb_impediments, only: [:create, :update]
resource :taskboard, :controller => :rb_taskboards, :only => :show
resources :tasks, controller: :rb_tasks, only: [:create, :update]
resource :wiki, :controller => :rb_wikis, :only => [:show, :edit]
resource :burndown_chart, :controller => :rb_burndown_charts, :only => :show
resources :impediments, :controller => :rb_impediments, :only => [:create, :update]
resources :tasks, :controller => :rb_tasks, :only => [:create, :update]
resources :export_card_configurations, :controller => :rb_export_card_configurations, :only => [:index, :show] do
resources :stories, :controller => :rb_stories, :only => [:index]
resources :export_card_configurations, controller: :rb_export_card_configurations, only: [:index, :show] do
resources :stories, controller: :rb_stories, only: [:index]
end
resources :stories, :controller => :rb_stories, :only => [:create, :update]
resources :stories, controller: :rb_stories, only: [:create, :update]
end
end
end
get 'projects/:project_id/versions/:id/edit' => 'version_settings#edit'
post 'projects/:id/project_done_statuses' => 'projects#project_done_statuses'
get 'projects/:project_id/versions/:id/edit' => 'version_settings#edit'
post 'projects/:id/project_done_statuses' => 'projects#project_done_statuses'
post 'projects/:id/rebuild_positions' => 'projects#rebuild_positions'
end

@ -33,20 +33,19 @@
# See doc/COPYRIGHT.rdoc for more details.
#++
require Rails.root.join("db","migrate","migration_utils","migration_squasher").to_s
require Rails.root.join("db","migrate","migration_utils","setting_renamer").to_s
require Rails.root.join('db', 'migrate', 'migration_utils', 'migration_squasher').to_s
require Rails.root.join('db', 'migrate', 'migration_utils', 'setting_renamer').to_s
require 'open_project/plugins/migration_mapping'
# This migration aggregates the migrations detailed in MIGRATION_FILES
class AggregatedBacklogsMigrations < ActiveRecord::Migration
def initialize
def initialize(*)
super
@issues_table_exists = ActiveRecord::Base.connection.tables.include? 'issues'
end
REPLACED = {
"story_trackers" => "story_types",
"task_tracker" => "task_type"
'story_trackers' => 'story_types',
'task_tracker' => 'task_type'
}
MIGRATION_FILES = <<-MIGRATIONS
@ -58,47 +57,47 @@ class AggregatedBacklogsMigrations < ActiveRecord::Migration
20111014073605_drop_burndown_days.rb
MIGRATIONS
OLD_PLUGIN_NAME = "chiliproject_backlogs"
OLD_PLUGIN_NAME = 'chiliproject_backlogs'
def up
migration_names = OpenProject::Plugins::MigrationMapping.migration_files_to_migration_names(MIGRATION_FILES, OLD_PLUGIN_NAME)
Migration::MigrationSquasher.squash(migration_names) do
create_table "version_settings" do |t|
t.integer "project_id"
t.integer "version_id"
t.integer "display"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
create_table 'version_settings' do |t|
t.integer 'project_id'
t.integer 'version_id'
t.integer 'display'
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
end
add_index "version_settings", ["project_id", "version_id"], :name => "index_version_settings_on_project_id_and_version_id"
add_index 'version_settings', ['project_id', 'version_id'], name: 'index_version_settings_on_project_id_and_version_id'
create_table "issue_done_statuses_for_project", :id => false do |t|
t.integer "project_id"
t.integer "issue_status_id"
create_table 'issue_done_statuses_for_project', id: false do |t|
t.integer 'project_id'
t.integer 'issue_status_id'
end
if(@issues_table_exists)
change_table "issues" do |t|
t.integer "position"
t.integer "story_points"
t.float "remaining_hours"
if @issues_table_exists
change_table 'issues' do |t|
t.integer 'position'
t.integer 'story_points'
t.float 'remaining_hours'
end
end
end
Migration::SettingRenamer.rename("plugin_backlogs","plugin_openproject_backlogs")
Migration::SettingRenamer.rename("plugin_redmine_backlogs","plugin_openproject_backlogs")
Migration::SettingRenamer.rename('plugin_backlogs', 'plugin_openproject_backlogs')
Migration::SettingRenamer.rename('plugin_redmine_backlogs', 'plugin_openproject_backlogs')
# Rename Tracker to Type
Setting['plugin_openproject_backlogs'] = replace(Setting['plugin_openproject_backlogs'], REPLACED)
end
def down
drop_table "version_settings"
drop_table "issue_done_statuses_for_project"
if(@issues_table_exists)
change_table "issues" do |t|
remove_column "position"
remove_column "story_points"
remove_column "remaining_hours"
drop_table 'version_settings'
drop_table 'issue_done_statuses_for_project'
if @issues_table_exists
change_table 'issues' do |_t|
remove_column 'position'
remove_column 'story_points'
remove_column 'remaining_hours'
end
end
Setting['plugin_openproject_backlogs'] = replace(Setting['plugin_openproject_backlogs'], REPLACED.invert)
@ -106,15 +105,15 @@ class AggregatedBacklogsMigrations < ActiveRecord::Migration
private
def replace(hash,mapping)
Hash[hash.map { |k,v| [mapping[k] || k, v] }]
def replace(hash, mapping)
Hash[hash.map { |k, v| [mapping[k] || k, v] }]
end
def settings_table
@settings_table ||= ActiveRecord::Base.connection.quote_table_name('settings')
end
def quote_value s
def quote_value(s)
ActiveRecord::Base.connection.quote(s)
end
end

@ -33,10 +33,9 @@
# See doc/COPYRIGHT.rdoc for more details.
#++
require Rails.root.join("db","migrate","migration_utils","utils").to_s
require Rails.root.join('db', 'migrate', 'migration_utils', 'utils').to_s
class LegacyIssuesBacklogsDataToWorkPackages < ActiveRecord::Migration
def up
if legacy_backlog_data_exists?
execute <<-SQL

@ -42,7 +42,7 @@ class AddBacklogColumnsToWorkPackageJournal < ActiveRecord::Migration
:status_id,
:project_id,
:type_id],
:name => 'work_package_journal_on_burndown_attributes'
name: 'work_package_journal_on_burndown_attributes'
Journal::WorkPackageJournal.reset_column_information
end
end

@ -114,14 +114,14 @@ Feature: The work_package hierarchy defines the allowed versions for each work_p
Given I am on the taskboard for "Sprint 001"
When I click to add a new task for story "Story A"
And I fill in "Task1" for "subject"
And I fill in "3" for "remaining_hours"
And I fill in "3" for "remaining hours"
And I press "OK"
And I click to add a new task for story "Story A"
And I fill in "Task2" for "subject"
And I press "OK"
And I click to add a new task for story "Story A"
And I fill in "Task3" for "subject"
And I fill in "3" for "remaining_hours"
And I fill in "7" for "remaining hours"
And I press "OK"
And the request on task "Task1" is finished
And the request on task "Task2" is finished
@ -131,7 +131,7 @@ Feature: The work_package hierarchy defines the allowed versions for each work_p
And the task "Task2" should have "Sprint 001" as its target version
And the task "Task3" should have "Sprint 001" as its target version
And task Task1 should have remaining_hours set to 3
And task Task3 should have remaining_hours set to 3
And task Task3 should have remaining_hours set to 7
#Scenario: Moving a task between stories on the taskboard
# not testable for now

@ -38,12 +38,12 @@ Given /^I am logged out$/ do
end
Given /^I set the (.+) of the story to (.+)$/ do |attribute, value|
if attribute == "type"
attribute = "type_id"
value = Type.find(:first, :conditions => ["name=?", value]).id
elsif attribute == "status"
attribute = "status_id"
value = Status.find(:first, :conditions => ["name=?", value]).id
if attribute == 'type'
attribute = 'type_id'
value = Type.find(:first, conditions: ['name=?', value]).id
elsif attribute == 'status'
attribute = 'status_id'
value = Status.find(:first, conditions: ['name=?', value]).id
elsif %w[backlog sprint].include? attribute
attribute = 'fixed_version_id'
value = Version.find_by_name(value).id
@ -64,51 +64,51 @@ end
Given /^I want to create a task for (.+)(?: in [pP]roject "(.+?)")?$/ do |story_subject, project_name|
project = get_project(project_name)
story = Story.find(:first, :conditions => ["subject=?", story_subject])
story = Story.find(:first, conditions: ['subject=?', story_subject])
@task_params = initialize_task_params(project, story)
end
Given /^I want to create an impediment for (.+?)(?: in [pP]roject "(.+?)")?$/ do |sprint_subject, project_name|
project = get_project(project_name)
sprint = Sprint.find(:first, :conditions => { :name => sprint_subject })
sprint = Sprint.find(:first, conditions: { name: sprint_subject })
@impediment_params = initialize_impediment_params(project, sprint.id)
end
Given /^I want to edit the task named (.+)$/ do |task_subject|
task = Task.find(:first, :conditions => { :subject => task_subject })
task = Task.find(:first, conditions: { subject: task_subject })
task.should_not be_nil
@task_params = HashWithIndifferentAccess.new(task.attributes)
end
Given /^I want to edit the impediment named (.+)$/ do |impediment_subject|
impediment = Task.find(:first, :conditions => { :subject => impediment_subject })
impediment = Task.find(:first, conditions: { subject: impediment_subject })
impediment.should_not be_nil
@impediment_params = HashWithIndifferentAccess.new(impediment.attributes)
end
Given /^I want to edit the sprint named (.+)$/ do |name|
sprint = Sprint.find(:first, :conditions => ["name=?", name])
sprint = Sprint.find(:first, conditions: ['name=?', name])
sprint.should_not be_nil
@sprint_params = HashWithIndifferentAccess.new(sprint.attributes)
end
Given /^I want to indicate that the impediment blocks (.+)$/ do |blocks_csv|
blocks_csv = Story.find(:all, :conditions => { :subject => blocks_csv.split(', ') }).map{ |s| s.id }.join(',')
blocks_csv = Story.find(:all, conditions: { subject: blocks_csv.split(', ') }).map(&:id).join(',')
@impediment_params[:blocks] = blocks_csv
end
Given /^I want to set the (.+) of the sprint to (.+)$/ do |attribute, value|
value = '' if value == "an empty string"
value = '' if value == 'an empty string'
@sprint_params[attribute] = value
end
Given /^I want to set the (.+) of the impediment to (.+)$/ do |attribute, value|
value = '' if value == "an empty string"
value = '' if value == 'an empty string'
@impediment_params[attribute] = value
end
Given /^I want to edit the story with subject (.+)$/ do |subject|
@story = Story.find(:first, :conditions => ["subject=?", subject])
@story = Story.find(:first, conditions: ['subject=?', subject])
@story.should_not be_nil
@story_params = HashWithIndifferentAccess.new(@story.attributes)
end
@ -126,7 +126,7 @@ Given /^the [pP]roject(?: "([^\"]*)")? has the following sprints:$/ do |project_
table.hashes.each do |version|
['effective_date', 'start_date'].each do |date_attr|
version[date_attr] = eval(version[date_attr]).strftime("%Y-%m-%d") if version[date_attr].match(/^(\d+)\.(year|month|week|day|hour|minute|second)(s?)\.(ago|from_now)$/)
version[date_attr] = eval(version[date_attr]).strftime('%Y-%m-%d') if version[date_attr].match(/^(\d+)\.(year|month|week|day|hour|minute|second)(s?)\.(ago|from_now)$/)
end
sprint = Sprint.new version
sprint.project = project
@ -143,7 +143,7 @@ Given /^the [pP]roject(?: "([^\"]*)")? has the following (?:product )?(?:owner )
project = get_project(project_name)
table.raw.each do |row|
version = Version.create!(:project => project, :name => row.first)
version = Version.create!(project: project, name: row.first)
vs = version.version_settings.build
vs.project = project
@ -154,9 +154,9 @@ end
Given /^the [pP]roject(?: "(.+?)")? has the following stories in the following (?:product )?(?:owner )?backlogs:$/ do |project_name, table|
if project_name
step %Q{the project "#{project_name}" has the following stories in the following sprints:}, table
step %{the project "#{project_name}" has the following stories in the following sprints:}, table
else
step "the project has the following stories in the following sprints:", table
step 'the project has the following stories in the following sprints:', table
end
end
@ -176,11 +176,11 @@ Given /^the [pP]roject(?: "([^\"]*)")? has the following stories in the followin
params['status_id'] = Status.find_by_name(story['status']).id if story['status']
params['type_id'] = Type.find_by_name(story['type']).id if story['type']
params.delete "position"
params.delete 'position'
# NOTE: We're bypassing the controller here because we're just
# setting up the database for the actual tests. The actual tests,
# however, should NOT bypass the controller
s = Story.create_and_position(params, :project => params[:project], :author => params['author'])
s = Story.create_and_position(params, project: params[:project], author: params['author'])
prev_id = s.id
end
end
@ -192,7 +192,7 @@ Given /^the [pP]roject(?: "([^\"]*)")? has the following tasks:$/ do |project_na
as_admin do
table.hashes.each do |task|
story = Story.find(:first, :conditions => { :subject => task['parent'] })
story = Story.find(:first, conditions: { subject: task['parent'] })
params = initialize_task_params(project, story)
params['subject'] = task['subject']
@ -213,7 +213,7 @@ Given /^the [pP]roject(?: "([^\"]*)")? has the following work_packages:$/ do |pr
as_admin do
table.hashes.each do |task|
parent = WorkPackage.find(:first, :conditions => { :subject => task['parent'] })
parent = WorkPackage.find(:first, conditions: { subject: task['parent'] })
type = Type.find_by_name(task['type'])
params = initialize_work_package_params(project, type, parent)
params['subject'] = task['subject']
@ -237,8 +237,8 @@ Given /^the [pP]roject(?: "([^\"]*)")? has the following impediments:$/ do |proj
as_admin do
table.hashes.each do |impediment|
sprint = Sprint.find(:first, :conditions => { :name => impediment['sprint'] })
blocks = Story.find(:all, :conditions => { :subject => impediment['blocks'].split(', ') }).map{ |s| s.id }
sprint = Sprint.find(:first, conditions: { name: impediment['sprint'] })
blocks = Story.find(:all, conditions: { subject: impediment['blocks'].split(', ') }).map(&:id)
params = initialize_impediment_params(project, sprint)
params['subject'] = impediment['subject']
params['blocks_ids'] = blocks.join(',')
@ -256,7 +256,7 @@ end
Given /^I have selected card label stock (.+)$/ do |stock|
settings = Setting.plugin_openproject_backlogs
settings["card_spec"] = stock
settings['card_spec'] = stock
Setting.plugin_openproject_backlogs = settings
# If this goes wrong, you are probably missing
@ -283,8 +283,8 @@ end
Given /^I have set the content for wiki page (.+) to (.+)$/ do |title, content|
title = Wiki.titleize(title)
page = @project.wiki.find_page(title)
if ! page
page = WikiPage.new(:wiki => @project.wiki, :title => title)
if !page
page = WikiPage.new(wiki: @project.wiki, title: title)
page.content = WikiContent.new
page.save
end
@ -294,7 +294,7 @@ Given /^I have set the content for wiki page (.+) to (.+)$/ do |title, content|
end
Given /^I have made (.+) the template page for sprint notes/ do |title|
Setting.plugin_openproject_backlogs = Setting.plugin_openproject_backlogs.merge("wiki_template" => Wiki.titleize(title))
Setting.plugin_openproject_backlogs = Setting.plugin_openproject_backlogs.merge('wiki_template' => Wiki.titleize(title))
end
Given /^there are no stories in the [pP]roject$/ do
@ -303,9 +303,9 @@ end
Given /^the type "(.+?)" is configured to track tasks$/ do |type_name|
type = Type.find_by_name(type_name)
type = FactoryGirl.create(:type, :name => type_name) if type.blank?
type = FactoryGirl.create(:type, name: type_name) if type.blank?
Setting.plugin_openproject_backlogs = Setting.plugin_openproject_backlogs.merge("task_type" => type.id)
Setting.plugin_openproject_backlogs = Setting.plugin_openproject_backlogs.merge('task_type' => type.id)
end
Given /^the following types are configured to track stories:$/ do |table|
@ -314,14 +314,14 @@ Given /^the following types are configured to track stories:$/ do |table|
name = line.first
type = Type.find_by_name(name)
type = FactoryGirl.create(:type, :name => name) if type.blank?
type = FactoryGirl.create(:type, name: name) if type.blank?
story_types << type
end
# otherwise the type id's from the previous test are still active
WorkPackage.instance_variable_set(:@backlogs_types, nil)
Setting.plugin_openproject_backlogs = Setting.plugin_openproject_backlogs.merge("story_types" => story_types.map(&:id))
Setting.plugin_openproject_backlogs = Setting.plugin_openproject_backlogs.merge('story_types' => story_types.map(&:id))
end
Given /^the [tT]ype(?: "([^\"]*)")? has for the Role "(.+?)" the following workflows:$/ do |type_name, role_name, table|
@ -332,7 +332,7 @@ Given /^the [tT]ype(?: "([^\"]*)")? has for the Role "(.+?)" the following workf
table.hashes.each do |workflow|
old_status = Status.find_by_name(workflow['old_status']).id
new_status = Status.find_by_name(workflow['new_status']).id
type.workflows.build(:old_status_id => old_status , :new_status_id => new_status , :role => role)
type.workflows.build(old_status_id: old_status, new_status_id: new_status, role: role)
end
type.save!
end
@ -344,11 +344,9 @@ Given /^the status of "([^"]*)" is "([^"]*)"$/ do |work_package_subject, status_
end
Given /^there is the single default export card configuration$/ do
config = ExportCardConfiguration.create!({
name: "Default",
per_page: 1,
page_size: "A4",
orientation: "landscape",
rows: "group1:\n has_border: false\n rows:\n row1:\n height: 50\n priority: 1\n columns:\n id:\n has_label: false"
})
config = ExportCardConfiguration.create!(name: 'Default',
per_page: 1,
page_size: 'A4',
orientation: 'landscape',
rows: "group1:\n has_border: false\n rows:\n row1:\n height: 50\n priority: 1\n columns:\n id:\n has_label: false")
end

@ -35,28 +35,28 @@
Then /^(.+) should be in the (\d+)(?:st|nd|rd|th) position of the sprint named (.+)$/ do |story_subject, position, sprint_name|
position = position.to_i
story = Story.find(:first, :conditions => ["subject=? and name=?", story_subject, sprint_name], :joins => :fixed_version)
story = Story.find(:first, conditions: ['subject=? and name=?', story_subject, sprint_name], joins: :fixed_version)
story_position(story).should == position.to_i
end
Then /^I should see (\d+) (?:product )?owner backlogs$/ do |count|
sprint_backlogs = page.all(:css, "#owner_backlogs_container .sprint")
sprint_backlogs = page.all(:css, '#owner_backlogs_container .sprint')
sprint_backlogs.length.should == count.to_i
end
Then /^I should see (\d+) sprint backlogs$/ do |count|
sprint_backlogs = page.all(:css, "#sprint_backlogs_container .sprint")
sprint_backlogs = page.all(:css, '#sprint_backlogs_container .sprint')
sprint_backlogs.length.should == count.to_i
end
Then /^I should see the burndown chart for sprint "(.+?)"$/ do |sprint|
sprint = Sprint.find_by_name(sprint)
page.should have_css("#burndown_#{sprint.id.to_s}")
page.should have_css("#burndown_#{sprint.id}")
end
Then /^I should see the WorkPackages page$/ do
page.should have_css(".workpackages-table")
page.should have_css('.workpackages-table')
end
Then /^I should see the taskboard$/ do
@ -78,7 +78,7 @@ Then /^the velocity of "(.+?)" should be "(.+?)"$/ do |backlog_name, velocity|
end
Then /^show me the list of sprints$/ do
sprints = Sprint.find(:all, :conditions => ["project_id=?", @project.id])
sprints = Sprint.find(:all, conditions: ['project_id=?', @project.id])
puts "\n"
puts "\t| #{'id'.ljust(3)} | #{'name'.ljust(18)} | #{'start_date'.ljust(18)} | #{'effective_date'.ljust(18)} | #{'updated_on'.ljust(20)}"
@ -89,15 +89,15 @@ Then /^show me the list of sprints$/ do
end
Then /^show me the list of stories$/ do
stories = Story.find(:all, :conditions => "project_id=#{@project.id}", :order => "position ASC")
subject_max = (stories.map{|s| s.subject} << "subject").sort{|a,b| a.length <=> b.length}.last.length
stories = Story.find(:all, conditions: "project_id=#{@project.id}", order: 'position ASC')
subject_max = (stories.map(&:subject) << 'subject').sort { |a, b| a.length <=> b.length }.last.length
sprints = @project.versions.find(:all)
sprint_max = (sprints.map{|s| s.name} << "sprint").sort{|a,b| a.length <=> b.length}.last.length
sprint_max = (sprints.map(&:name) << 'sprint').sort { |a, b| a.length <=> b.length }.last.length
puts "\n"
puts "\t| #{'id'.ljust(5)} | #{'position'.ljust(8)} | #{'status'.ljust(12)} | #{'rank'.ljust(4)} | #{'subject'.ljust(subject_max)} | #{'sprint'.ljust(sprint_max)} |"
stories.each do |story|
puts "\t| #{story.id.to_s.ljust(5)} | #{story.position.to_s.ljust(8)} | #{story.status.name[0,12].ljust(12)} | #{story.rank.to_s.ljust(4)} | #{story.subject.ljust(subject_max)} | #{(story.fixed_version_id.nil? ? Sprint.new : Sprint.find(story.fixed_version_id)).name.ljust(sprint_max)} |"
puts "\t| #{story.id.to_s.ljust(5)} | #{story.position.to_s.ljust(8)} | #{story.status.name[0, 12].ljust(12)} | #{story.rank.to_s.ljust(4)} | #{story.subject.ljust(subject_max)} | #{(story.fixed_version_id.nil? ? Sprint.new : Sprint.find(story.fixed_version_id)).name.ljust(sprint_max)} |"
end
puts "\n\n"
end
@ -105,13 +105,13 @@ end
Then /^(.+) should be the higher (story|item|task) of (.+)$/ do |higher_subject, type, lower_subject|
work_package_class = (type == 'task') ? Task : Story
higher = work_package_class.find(:all, :conditions => { :subject => higher_subject })
higher = work_package_class.find(:all, conditions: { subject: higher_subject })
higher.length.should == 1
lower = work_package_class.find(:all, :conditions => { :subject => lower_subject })
lower = work_package_class.find(:all, conditions: { subject: lower_subject })
lower.length.should == 1
if type == "task"
if type == 'task'
lower.first.id.should == higher.first.right_sibling.id
else
lower.first.higher_item.id.should == higher.first.id
@ -152,7 +152,7 @@ Then /^all positions should be unique for each version$/ do
end
Then /^the (\d+)(?:st|nd|rd|th) task for (.+) should be (.+)$/ do |position, story_subject, task_subject|
story = Story.find(:first, :conditions => ["subject=?", story_subject])
story = Story.find(:first, conditions: ['subject=?', story_subject])
story.children[position.to_i - 1].subject.should == task_subject
end
@ -165,16 +165,16 @@ Then /^the server should return (\d+) updated (.+)$/ do |count, object_type|
end
Then /^the sprint named (.+) should have (\d+) impediments? named (.+)$/ do |sprint_name, count, impediment_subject|
sprints = Sprint.find(:all, :conditions => { :name => sprint_name })
sprints = Sprint.find(:all, conditions: { name: sprint_name })
sprints.length.should == 1
sprints.first.impediments.map{ |i| i.subject==impediment_subject}.length.should == count.to_i
sprints.first.impediments.map { |i| i.subject == impediment_subject }.length.should == count.to_i
end
Then /^the impediment "(.+)" should signal( | un)successful saving$/ do |impediment_subject, negative|
pos_or_neg_should = !negative.blank? ? :should : :should_not
page.send(pos_or_neg_should, have_selector("div.impediment.error", :text => impediment_subject))
page.send(pos_or_neg_should, have_selector('div.impediment.error', text: impediment_subject))
end
Then /^the sprint should be updated accordingly$/ do
@ -182,7 +182,7 @@ Then /^the sprint should be updated accordingly$/ do
sprint.attributes.each_key do |key|
unless ['updated_on', 'created_on'].include?(key)
(key.include?('_date') ? sprint[key].strftime("%Y-%m-%d") : sprint[key]).should == @sprint_params[key]
(key.include?('_date') ? sprint[key].strftime('%Y-%m-%d') : sprint[key]).should == @sprint_params[key]
end
end
end
@ -193,10 +193,10 @@ Then /^the status of the story should be set as (.+)$/ do |status|
end
Then /^the story named (.+) should have 1 task named (.+)$/ do |story_subject, task_subject|
stories = Story.find(:all, :conditions => { :subject => story_subject })
stories = Story.find(:all, conditions: { subject: story_subject })
stories.length.should == 1
tasks = Task.find(:all, :conditions => { :parent_id => stories.first.id, :subject => task_subject })
tasks = Task.find(:all, conditions: { parent_id: stories.first.id, subject: task_subject })
tasks.length.should == 1
end
@ -214,9 +214,9 @@ end
Then /^the story should have a (.+) of (.+)$/ do |attribute, value|
@story.reload
if attribute=="type"
attribute="type_id"
value = Type.find(:first, :conditions => ["name=?", value]).id
if attribute == 'type'
attribute = 'type_id'
value = Type.find(:first, conditions: ['name=?', value]).id
end
@story[attribute].should == value
end
@ -229,19 +229,19 @@ Then /^the wiki page (.+) should contain (.+)$/ do |title, content|
raise "\"#{content}\" not found on page \"#{title}\"" unless page.content.text.match(/#{content}/)
end
Then /^(work_package|task|story) (.+) should have (.+) set to (.+)$/ do |type, subject, attribute, value|
Then /^(work_package|task|story) (.+) should have (.+) set to (.+)$/ do |_type, subject, attribute, value|
work_package = WorkPackage.find_by_subject(subject)
work_package[attribute].should == value.to_i
end
Then /^the error alert should show "(.+?)"$/ do |msg|
step %Q{I should see "#{msg}" within "#msgBox"}
step %{I should see "#{msg}" within "#msgBox"}
end
Then /^the start date of "(.+?)" should be "(.+?)"$/ do |sprint_name, date|
version = Version.find_by_name(sprint_name)
step %Q{I should see "#{date}" within "div#sprint_#{version.id} div.start_date"}
step %{I should see "#{date}" within "div#sprint_#{version.id} div.start_date"}
end
Then /^I should see "(.+?)" as a task to story "(.+?)"$/ do |task_name, story_name|
@ -259,12 +259,12 @@ end
Then /^there should not be a saving error on task "(.+?)"$/ do |task_name|
elements = all(:xpath, "//*[contains(., \"#{task_name}\")]")
task_div = elements.find{|e| e.tag_name == "div" && e[:class].include?("task")}
task_div[:class].should_not include("error")
task_div = elements.find { |e| e.tag_name == 'div' && e[:class].include?('task') }
task_div[:class].should_not include('error')
end
Then /^I should be notified that the work_package "(.+?)" is an invalid parent to the work_package "(.+?)" because of cross project limitations$/ do |parent_name, child_name|
step %Q{I should see "Parent is invalid because the work package '#{child_name}' is a backlog task and therefore cannot have a parent outside of the current project." within "#errorExplanation"}
step %{I should see "Parent is invalid because the work package '#{child_name}' is a backlog task and therefore cannot have a parent outside of the current project." within "#errorExplanation"}
end
Then /^the PDF download dialog should be displayed$/ do

@ -34,106 +34,120 @@
#++
When /^I create the impediment$/ do
page.driver.post url_for(:controller => '/rb_impediments', :action => :create),
@impediment_params
page.driver.post backlogs_project_sprint_impediments_url(
*@impediment_params.values_at('project_id', 'fixed_version_id')
), @impediment_params
end
When /^I create the story$/ do
page.driver.post url_for(:controller => '/rb_stories', :action => :create),
@story_params
page.driver.post backlogs_project_sprint_stories_url(
*@story_params.values_at('project_id', 'fixed_version_id')
), @story_params
end
When /^I create the task$/ do
page.driver.post url_for(:controller => '/rb_tasks', :action => :create),
@task_params
page.driver.post backlogs_project_sprint_tasks_url(
*@task_params.values_at('project_id', 'fixed_version_id')
), @task_params
end
When /^I move the (story|item|task) named (.+) below (.+)$/ do |type, story_subject, prev_subject|
work_package_class, controller_name =
if type.strip == "task" then [Task, "rb_tasks"] else [Story, "rb_stories"] end
story = work_package_class.find(:first, :conditions => ["subject=?", story_subject.strip])
prev = work_package_class.find(:first, :conditions => ["subject=?", prev_subject.strip])
work_package_class = if type.strip == 'task' then Task else Story end
story = work_package_class.find(:first, conditions: ['subject=?', story_subject.strip])
prev = work_package_class.find(:first, conditions: ['subject=?', prev_subject.strip])
attributes = story.attributes
attributes[:prev] = prev.id
attributes[:fixed_version_id] = prev.fixed_version_id unless type == "task"
attributes[:fixed_version_id] = prev.fixed_version_id unless type == 'task'
page.driver.post url_for(:controller => '/'+controller_name, :action => "update", :id => story),
attributes.merge({ "_method" => "put" })
project = Project.find(attributes['project_id'])
sprint = prev.fixed_version
page.driver.post polymorphic_url(
[:backlogs, project, sprint.becomes(Sprint), story]
), attributes.merge('_method' => 'put')
end
When /^I move the story named (.+) (up|down) to the (\d+)(?:st|nd|rd|th) position of the sprint named (.+)$/ do |story_subject, direction, position, sprint_name|
position = position.to_i
story = Story.find(:first, :conditions => ["subject=?", story_subject])
sprint = Sprint.find(:first, :conditions => ["name=?", sprint_name])
story = Story.find(:first, conditions: ['subject=?', story_subject])
sprint = Sprint.find(:first, conditions: ['name=?', sprint_name])
story.fixed_version = sprint
attributes = story.attributes
attributes[:prev] = if position == 1
''
else
stories = Story.find(:all, :conditions => ["fixed_version_id=? AND type_id IN (?)", sprint.id, Story.types], :order => "position ASC")
stories = Story.find(:all, conditions: ['fixed_version_id=? AND type_id IN (?)', sprint.id, Story.types], order: 'position ASC')
raise "You indicated an invalid position (#{position}) in a sprint with #{stories.length} stories" if 0 > position or position > stories.length
stories[position - (direction=="up" ? 2 : 1)].id
stories[position - (direction == 'up' ? 2 : 1)].id
end
page.driver.post url_for(:controller => '/rb_stories', :action => "update", :id => story.id),
attributes.merge({ "_method" => "put" })
page.driver.post backlogs_project_sprint_story_url(
*attributes.values_at('project_id', 'fixed_version_id', 'id')
), attributes.merge('_method' => 'put')
end
When /^I move the (\d+)(?:st|nd|rd|th) story to the (\d+|last)(?:st|nd|rd|th)? position$/ do |old_pos, new_pos|
@story_ids = page.all(:css, "#owner_backlogs_container .stories .story .id")
@story_ids = page.all(:css, '#owner_backlogs_container .stories .story .id')
story = @story_ids[old_pos.to_i-1]
story = @story_ids[old_pos.to_i - 1]
story.should_not == nil
prev = if new_pos.to_i == 1
nil
elsif new_pos=='last'
elsif new_pos == 'last'
@story_ids.last
elsif old_pos.to_i > new_pos.to_i
@story_ids[new_pos.to_i-2]
@story_ids[new_pos.to_i - 2]
else
@story_ids[new_pos.to_i-1]
@story_ids[new_pos.to_i - 1]
end
page.driver.post url_for(:controller => '/rb_stories', :action => :update, :id => story.text),
{:prev => (prev.nil? ? '' : prev.text), :project_id => @project.id, "_method" => "put"}
@story = Story.find(story.text.to_i)
page.driver.post backlogs_project_sprint_story_url(
@project.id,
@story.fixed_version_id,
@story.id
), prev: (prev.nil? ? '' : prev.text), '_method' => 'put'
end
When /^I request the server_variables resource$/ do
visit url_for(:controller => '/rb_server_variables', :action => :show, :project_id => @project)
visit backlogs_project_server_variables_url(@project.id, format: 'js')
end
When /^I update the impediment$/ do
page.driver.post url_for(:controller => '/rb_impediments', :action => :update),
@impediment_params.merge({ "_method" => "put" })
page.driver.post backlogs_project_sprint_impediment_url(
*@impediment_params.values_at('project_id', 'fixed_version_id', 'id')
), @impediment_params.merge('_method' => 'put')
end
When /^I update the sprint$/ do
page.driver.post url_for(:controller => '/rb_sprints', :action => "update", :sprint_id => @sprint_params['id']),
@sprint_params.merge({ "_method" => "put" })
page.driver.post backlogs_project_sprint_url(
*@sprint_params.values_at('project_id', 'id')
), @sprint_params.merge('_method' => 'put')
end
When /^I update the story$/ do
page.driver.post url_for(:controller => '/rb_stories', :action => :update, :id => @story_params[:id]),
@story_params.merge({ "_method" => "put" })
page.driver.post backlogs_project_sprint_story_url(
*@story_params.values_at('project_id', 'fixed_version_id', 'id')
), @story_params.merge('_method' => 'put')
end
When /^I update the task$/ do
page.driver.post url_for(:controller => '/rb_tasks', :action => :update, :id => @task_params[:id]),
@task_params.merge({ "_method" => "put" })
page.driver.post backlogs_project_sprint_task_url(
*@task_params.values_at('project_id', 'fixed_version_id', 'id')
), @task_params.merge('_method' => 'put')
end
When /^I view the master backlog$/ do
visit url_for(:controller => '/projects', :action => :show, :id => @project)
click_link("Backlogs")
visit url_for(controller: '/projects', action: :show, id: @project)
click_link('Backlogs')
end
When /^I view the stories of (.+) in the work_packages tab/ do |sprint_name|
sprint = Sprint.find(:first, conditions: ["name=?", sprint_name])
sprint = Sprint.find(:first, conditions: ['name=?', sprint_name])
visit url_for(controller: '/rb_queries', action: :show, project_id: sprint.project, sprint_id: sprint, only_path: true)
end
@ -144,37 +158,37 @@ end
# WARN: Depends on deprecated behavior of path_for('the task board for
# "sprint name"')
When /^I view the sprint notes$/ do
visit url_for(:controller => '/rb_wikis', :action => 'show', :sprint_id => @sprint)
visit url_for(controller: '/rb_wikis', action: 'show', sprint_id: @sprint)
end
# WARN: Depends on deprecated behavior of path_for('the task board for
# "sprint name"')
When /^I edit the sprint notes$/ do
visit url_for(:controller => '/rb_wikis', :action => 'edit', :sprint_id => @sprint)
visit url_for(controller: '/rb_wikis', action: 'edit', sprint_id: @sprint)
end
When /^I follow "(.+?)" of the "(.+?)" (?:backlogs )?menu$/ do |link, backlog_name|
sprint = Sprint.find_by_name(backlog_name)
step %Q{I follow "#{link}" within "#backlog_#{sprint.id} .menu"}
step %{I follow "#{link}" within "#backlog_#{sprint.id} .menu"}
end
When /^I open the "(.+?)" backlogs(?: )?menu/ do |backlog_name|
sprint = Sprint.find_by_name(backlog_name)
step %Q{I hover over "#backlog_#{sprint.id} .menu"}
step %{I hover over "#backlog_#{sprint.id} .menu"}
end
When /^I close the "(.+?)" backlogs(?: )?menu/ do |backlog_name|
sprint = Sprint.find_by_name(backlog_name)
step %Q{I stop hovering over "#backlog_#{sprint.id} .menu"}
step %{I stop hovering over "#backlog_#{sprint.id} .menu"}
end
When /^I click on the text "(.+?)"$/ do |locator|
find(:xpath, %Q{//*[contains(text(), "#{locator}")]}).click
find(:xpath, %{//*[contains(text(), "#{locator}")]}).click
end
When /^I click on the link on the modal window with text "(.+?)"$/ do |locator|
browser = page.driver.browser
browser.switch_to.frame("modalIframe")
browser.switch_to.frame('modalIframe')
click_link(locator)
end
@ -183,20 +197,20 @@ When /^I click on the element with class "([^"]+?)"$/ do |locator|
end
When /^I confirm the story form$/ do
find(:xpath, XPath::HTML.fillable_field("subject")).native.send_key :return
find(:xpath, XPath::HTML.fillable_field('subject')).native.send_key :return
step 'I wait for AJAX requests to finish'
step 'I should not see ".saving"'
end
When /^I fill in the ids of the (tasks|work_packages|stories) "(.+?)" for "(.+?)"$/ do |model_name, subjects, field|
model = Kernel.const_get(model_name.classify)
ids = subjects.split(/,/).collect { |subject| model.find_by_subject(subject).id }
ids = subjects.split(/,/).map { |subject| model.find_by_subject(subject).id }
step %{I fill in "#{ids.join(", ")}" for "#{field}"}
step %{I fill in "#{ids.join(', ')}" for "#{field}"}
end
When /^I click on the impediment called "(.+?)"$/ do |impediment_name|
step %Q{I click on the text "#{impediment_name}"}
step %{I click on the text "#{impediment_name}"}
end
When /^I click to add a new task for story "(.+?)"$/ do |story_name|
@ -230,9 +244,9 @@ When /^I follow the link to add a subtask$/ do
end
When /^I change the fold state of a version$/ do
find(".backlog .toggler").click
find('.backlog .toggler').click
end
When /^I click on the Export link$/ do
click_link("Export")
click_link('Export')
end

@ -49,7 +49,10 @@ end
def initialize_task_params(project, story, user = User.find(:first))
params = HashWithIndifferentAccess.new
params['type_id'] = Task.type
params['parent_id'] = story.id if story
if story
params['fixed_version_id'] = story.fixed_version_id
params['parent_id'] = story.id
end
params['status_id'] = Status.find(:first).id
# unsafe attributes that will not be used directly but added for your
@ -92,22 +95,22 @@ def initialize_impediment_params(project, sprint, user = User.find(:first))
end
def task_position(task)
p1 = task.story.tasks.select{|t| t.id == task.id}[0].rank
p1 = task.story.tasks.select { |t| t.id == task.id }[0].rank
p2 = task.rank
p1.should == p2
return p1
p1
end
def story_position(story)
p1 = Story.sprint_backlog(story.project, story.fixed_version).detect{ |s| s.id == story.id }.rank
p1 = Story.sprint_backlog(story.project, story.fixed_version).detect { |s| s.id == story.id }.rank
p2 = story.rank
p1.should == p2
Story.at_rank(story.project_id, story.fixed_version_id, p1).id.should == story.id
return p1
p1
end
def logout
visit url_for(:controller => '/account', :action=>'logout')
visit url_for(controller: '/account', action: 'logout')
@user = nil
end

@ -60,9 +60,9 @@ end
When(/^I switch the modal window into edit mode$/) do
browser = page.driver.browser
browser.switch_to.frame("modalIframe")
within("#content > .action_menu_specific") do
click_link("Update")
browser.switch_to.frame('modalIframe')
within('#content > .action_menu_specific') do
click_link('Update')
end
safeguard_backlogs_modal_in_edit_mode
end
@ -73,5 +73,5 @@ And(/^I switch out of the modal$/) do
end
def safeguard_backlogs_modal_in_edit_mode
find_field("work_package[description]")
find_field('work_package[description]')
end

@ -33,15 +33,14 @@
# See doc/COPYRIGHT.rdoc for more details.
#++
Then /^the sprint "(.+?)" should be displayed to the (right|left)$/ do |sprint_name, orientation|
selector = case orientation
when "right"
"#owner_backlogs_container"
when "left"
"#sprint_backlogs_container"
when 'right'
'#owner_backlogs_container'
when 'left'
'#sprint_backlogs_container'
else
raise "Only right and left are supported"
raise 'Only right and left are supported'
end
step %{I should see "#{sprint_name}" within "#{selector} .name"}
step %{I should see "#{sprint_name}" within "#{selector} .name"}
end

@ -37,26 +37,25 @@ Then(/^the available status of the story called "(.+?)" should be the following:
# the order of the available status is important
story = Story.find_by_subject(story_name)
expected = table.raw.flatten.join(" ")
expected = table.raw.flatten.join(' ')
within("#story_#{story.id} .editors") do
should have_field("status_id", :text => expected)
should have_field('status_id', text: expected)
end
end
Then(/^the displayed attributes of the story called "(.+?)" should be the following:$/) do |story_name, table|
story = Story.find_by_subject(story_name)
within("#story_#{story.id}") do
table.rows_hash.each do |key, value|
case key
when "Status"
within(".status_id") do
should have_selector("div.t", :text => value)
when 'Status'
within('.status_id') do
should have_selector('div.t', text: value)
end
else
raise "Not an implemented attribute"
raise 'Not an implemented attribute'
end
end
end
@ -68,10 +67,10 @@ Then(/^the editable attributes of the story called "(.+?)" should be the followi
within("#story_#{story.id} .editors") do
table.rows_hash.each do |key, value|
case key
when "Status"
should have_select("status_id", :text => value)
when 'Status'
should have_select('status_id', text: value)
else
raise "Not an implemented attribute"
raise 'Not an implemented attribute'
end
end
end

@ -36,12 +36,12 @@
Then(/^the editable attributes of the version should be the following:$/) do |table|
table.rows_hash.each do |key, value|
case key
when "Column in backlog"
page.should have_select(key, :selected => value)
when "Start date"
page.should have_field(key, :with => value)
when 'Column in backlog'
page.should have_select(key, selected: value)
when 'Start date'
page.should have_field(key, with: value)
else
raise "Not an implemented attribute"
raise 'Not an implemented attribute'
end
end
end

@ -48,11 +48,11 @@ module BacklogsNavigationHelpers
when /^the (:?overview ?)?page (?:for|of) the [pP]roject$/
project = get_project
path_to %Q{the overview page of the project called "#{project.name}"}
path_to %{the overview page of the project called "#{project.name}"}
when /^the work_packages index page$/
project = get_project
path_to %Q{the work packages index page of the project called "#{project.name}"}
path_to %{the work packages index page of the project called "#{project.name}"}
when /^the burndown for "(.+?)"(?: (?:in|of) the [pP]roject "(.+?)")?$/
project = get_project($2)

@ -35,6 +35,6 @@
module OpenProject
module Backlogs
require "open_project/backlogs/engine"
require 'open_project/backlogs/engine'
end
end

@ -34,8 +34,6 @@
#++
module OpenProject::Backlogs::Burndown
unloadable
class Series < Array
def initialize(*args)
@unit = args.pop

@ -35,8 +35,6 @@
module OpenProject::Backlogs::Burndown
class SeriesRawData < Hash
unloadable
def initialize(*args)
@collect = args.pop
@sprint = args.pop
@ -49,7 +47,7 @@ module OpenProject::Backlogs::Burndown
attr_reader :project
def collect_names
@names ||= @collect.to_a.collect(&:last).flatten
@names ||= @collect.to_a.map(&:last).flatten
end
def unit_for(name)
@ -88,7 +86,7 @@ module OpenProject::Backlogs::Burndown
def collected_days
@collected_days ||= begin
days = sprint.days(nil)
days.sort.select{ |d| d <= Date.today }
days.sort.select { |d| d <= Date.today }
end
end
@ -157,14 +155,14 @@ module OpenProject::Backlogs::Burndown
def dates_of_interest_join_table(dates)
raise 'dates must not be empty!' if dates.empty?
@date_join ||= dates.map do |date|
@date_join ||= dates.map { |date|
"SELECT CAST('#{date}' AS DATE) AS date"
end.join(" UNION ")
}.join(' UNION ')
end
def status_query
@status_query ||= begin
non_closed_statuses = Status.where(:is_closed => false).select(:id).map(&:id)
non_closed_statuses = Status.where(is_closed: false).select(:id).map(&:id)
done_statuses_for_project = project.done_statuses.select(:id).map(&:id)
@ -191,7 +189,7 @@ module OpenProject::Backlogs::Burndown
end
def collected_from_children?(key, story)
key == "remaining_hours" && story_has_children?(story)
key == 'remaining_hours' && story_has_children?(story)
end
def collected_types

@ -42,81 +42,74 @@ module OpenProject::Backlogs
engine_name :openproject_backlogs
def self.settings
{ :default => { "story_types" => nil,
"task_type" => nil,
"card_spec" => nil
{ default: { 'story_types' => nil,
'task_type' => nil,
'card_spec' => nil
},
:partial => 'shared/settings' }
partial: 'shared/settings' }
end
include OpenProject::Plugins::ActsAsOpEngine
register 'openproject-backlogs',
:author_url => 'http://finn.de',
:requires_openproject => '>= 4.0.0',
:settings => settings do
Redmine::AccessControl.permission(:edit_project).actions << "projects/project_done_statuses"
Redmine::AccessControl.permission(:edit_project).actions << "projects/rebuild_positions"
author_url: 'http://finn.de',
requires_openproject: '>= 4.0.0',
settings: settings do
Redmine::AccessControl.permission(:edit_project).actions << 'projects/project_done_statuses'
Redmine::AccessControl.permission(:edit_project).actions << 'projects/rebuild_positions'
project_module :backlogs do
# SYNTAX: permission :name_of_permission, { :controller_name => [:action1, :action2] }
# Master backlog permissions
permission :view_master_backlog, {
:rb_master_backlogs => :index,
:rb_sprints => [:index, :show],
:rb_wikis => :show,
:rb_stories => [:index, :show],
:rb_queries => :show,
:rb_server_variables => :show,
:rb_burndown_charts => :show,
:rb_export_card_configurations => [:index, :show]
}
permission :view_taskboards, {
:rb_taskboards => :show,
:rb_sprints => :show,
:rb_stories => :show,
:rb_tasks => [:index, :show],
:rb_impediments => [:index, :show],
:rb_wikis => :show,
:rb_server_variables => :show,
:rb_burndown_charts => :show,
:rb_export_card_configurations => [:index, :show]
}
permission :view_master_backlog, rb_master_backlogs: :index,
rb_sprints: [:index, :show],
rb_wikis: :show,
rb_stories: [:index, :show],
rb_queries: :show,
rb_server_variables: :show,
rb_burndown_charts: :show,
rb_export_card_configurations: [:index, :show]
permission :view_taskboards, rb_taskboards: :show,
rb_sprints: :show,
rb_stories: :show,
rb_tasks: [:index, :show],
rb_impediments: [:index, :show],
rb_wikis: :show,
rb_server_variables: :show,
rb_burndown_charts: :show,
rb_export_card_configurations: [:index, :show]
# Sprint permissions
# :show_sprints and :list_sprints are implicit in :view_master_backlog permission
permission :update_sprints, {
:rb_sprints => [:edit, :update],
:rb_wikis => [:edit, :update]
}
permission :update_sprints, rb_sprints: [:edit, :update],
rb_wikis: [:edit, :update]
# Story permissions
# :show_stories and :list_stories are implicit in :view_master_backlog permission
permission :create_stories, { :rb_stories => :create }
permission :update_stories, { :rb_stories => :update }
permission :create_stories, rb_stories: :create
permission :update_stories, rb_stories: :update
# Task permissions
# :show_tasks and :list_tasks are implicit in :view_sprints
permission :create_tasks, { :rb_tasks => [:new, :create] }
permission :update_tasks, { :rb_tasks => [:edit, :update] }
permission :create_tasks, rb_tasks: [:new, :create]
permission :update_tasks, rb_tasks: [:edit, :update]
# Impediment permissions
# :show_impediments and :list_impediments are implicit in :view_sprints
permission :create_impediments, { :rb_impediments => [:new, :create] }
permission :update_impediments, { :rb_impediments => [:edit, :update] }
permission :create_impediments, rb_impediments: [:new, :create]
permission :update_impediments, rb_impediments: [:edit, :update]
end
menu :project_menu,
:backlogs,
{:controller => '/rb_master_backlogs', :action => :index},
:caption => :project_module_backlogs,
:before => :calendar,
:param => :project_id,
:if => proc { not(User.current.respond_to?(:impaired?) and User.current.impaired?) },
:html => {:class => 'icon2 icon-backlogs-icon'}
:backlogs,
{ controller: '/rb_master_backlogs', action: :index },
caption: :project_module_backlogs,
before: :calendar,
param: :project_id,
if: proc { not(User.current.respond_to?(:impaired?) and User.current.impaired?) },
html: { class: 'icon2 icon-backlogs-icon' }
end
assets %w(
@ -206,17 +199,17 @@ module OpenProject::Backlogs
end
config.to_prepare do
if WorkPackage.const_defined? "SAFE_ATTRIBUTES"
WorkPackage::SAFE_ATTRIBUTES << "story_points"
WorkPackage::SAFE_ATTRIBUTES << "remaining_hours"
WorkPackage::SAFE_ATTRIBUTES << "position"
if WorkPackage.const_defined? 'SAFE_ATTRIBUTES'
WorkPackage::SAFE_ATTRIBUTES << 'story_points'
WorkPackage::SAFE_ATTRIBUTES << 'remaining_hours'
WorkPackage::SAFE_ATTRIBUTES << 'position'
else
WorkPackage.safe_attributes "story_points", "remaining_hours", "position"
WorkPackage.safe_attributes 'story_points', 'remaining_hours', 'position'
end
end
initializer "backlogs.register_hooks" do
require "open_project/backlogs/hooks"
initializer 'backlogs.register_hooks' do
require 'open_project/backlogs/hooks'
end
end
end

@ -63,7 +63,7 @@ module OpenProject::Backlogs::Hooks
end
def work_package_show_remaining_hours_attribute(work_package)
work_package_show_table_row(:"remaining_hours") do
work_package_show_table_row(:remaining_hours) do
work_package.remaining_hours ? l_hours(work_package.remaining_hours) : empty_element_tag
end
end
@ -78,7 +78,7 @@ module OpenProject::Backlogs::Hooks
render_on :view_work_packages_form_details_bottom,
partial: 'hooks/backlogs/view_work_packages_form_details_bottom'
def view_versions_show_bottom(context={ })
def view_versions_show_bottom(context = {})
version = context[:version]
project = version.project
@ -88,7 +88,7 @@ module OpenProject::Backlogs::Hooks
if User.current.allowed_to?(:edit_wiki_pages, project)
snippet += '<span id="edit_wiki_page_action">'
snippet += link_to l(:button_edit_wiki), {:controller => '/rb_wikis', :action => 'edit', :project_id => project.id, :sprint_id => version.id }, :class => 'icon icon-edit'
snippet += link_to l(:button_edit_wiki), { controller: '/rb_wikis', action: 'edit', project_id: project.id, sprint_id: version.id }, class: 'icon icon-edit'
snippet += '</span>'
# This wouldn't be necesary if the schedules plugin didn't disable the
@ -103,14 +103,12 @@ module OpenProject::Backlogs::Hooks
end
end
def view_my_account(context={ })
return context[:controller].send(:render_to_string, {
:partial => 'shared/view_my_account',
:locals => {:user => context[:user], :color => context[:user].backlogs_preference(:task_color), :versions_default_fold_state => context[:user].backlogs_preference(:versions_default_fold_state) }
})
def view_my_account(context = {})
context[:controller].send(:render_to_string, partial: 'shared/view_my_account',
locals: { user: context[:user], color: context[:user].backlogs_preference(:task_color), versions_default_fold_state: context[:user].backlogs_preference(:versions_default_fold_state) })
end
def controller_work_package_new_after_save(context={ })
def controller_work_package_new_after_save(context = {})
params = context[:params]
work_package = context[:work_package]
@ -132,15 +130,15 @@ module OpenProject::Backlogs::Hooks
story = (id.nil? ? nil : Story.find(Integer(id)))
if ! story.nil? && action != 'none'
if !story.nil? && action != 'none'
tasks = story.tasks
case action
when 'open'
tasks = tasks.select{|t| !t.closed?}
when 'all', 'none'
#
else
raise "Unexpected value #{params[:copy_tasks]}"
when 'open'
tasks = tasks.select { |t| !t.closed? }
when 'all', 'none'
#
else
raise "Unexpected value #{params[:copy_tasks]}"
end
tasks.each {|t|

@ -34,19 +34,14 @@
#++
module OpenProject::Backlogs::List
unloadable
def self.included(base)
base.class_eval do
unloadable
acts_as_silent_list
# Reorder list, if work_package is removed from sprint
before_update :fix_other_work_package_positions
before_update :fix_own_work_package_position
# Used by acts_as_silent_list to limit the list to a certain subset within
# the table.
#
@ -54,7 +49,7 @@ module OpenProject::Backlogs::List
# we're using send to circumvent visibility work_packages.
def scope_condition
self.class.send(:sanitize_sql, ['project_id = ? AND fixed_version_id = ? AND type_id IN (?)',
self.project_id, self.fixed_version_id, self.types])
project_id, fixed_version_id, types])
end
include InstanceMethods
@ -62,8 +57,6 @@ module OpenProject::Backlogs::List
end
module InstanceMethods
def move_after(prev_id)
# Remove so the potential 'prev' has a correct position
remove_from_list
@ -95,8 +88,8 @@ module OpenProject::Backlogs::List
def fix_other_work_package_positions
if changes.slice('project_id', 'type_id', 'fixed_version_id').present?
if changes.slice('project_id', 'fixed_version_id').blank? and
Story.types.include?(type_id.to_i) and
Story.types.include?(type_id_was.to_i)
Story.types.include?(type_id.to_i) and
Story.types.include?(type_id_was.to_i)
return
end
@ -139,8 +132,8 @@ module OpenProject::Backlogs::List
def fix_own_work_package_position
if changes.slice('project_id', 'type_id', 'fixed_version_id').present?
if changes.slice('project_id', 'fixed_version_id').blank? and
Story.types.include?(type_id.to_i) and
Story.types.include?(type_id_was.to_i)
Story.types.include?(type_id.to_i) and
Story.types.include?(type_id_was.to_i)
return
end

@ -38,13 +38,13 @@ module OpenProject::Backlogs::Mixins
# Overrides ActiveRecord::Inheritance::ClassMethods#sti_name
# so that stories are stored and found with type-attribute = "WorkPackage"
def sti_name
"WorkPackage"
'WorkPackage'
end
# Overrides ActiveRecord::Inheritance::ClassMethods#find_sti_classes
# so that stories are instantiated correctly despite sti_name beeing "WorkPackage"
def find_sti_class(type_name)
type_name = self.to_s if type_name == "WorkPackage"
type_name = to_s if type_name == 'WorkPackage'
super(type_name)
end

@ -38,18 +38,16 @@ require_dependency 'my_controller'
module OpenProject::Backlogs::Patches::MyControllerPatch
def self.included(base)
base.class_eval do
unloadable
include InstanceMethods
after_filter :save_backlogs_preferences, :only => [:account]
after_filter :save_backlogs_preferences, only: [:account]
end
end
module InstanceMethods
def save_backlogs_preferences
if request.put? && flash[:notice] == l(:notice_account_updated)
versions_default_fold_state = (params[:backlogs] && params[:backlogs][:versions_default_fold_state]) ? params[:backlogs][:versions_default_fold_state] : "open"
if request.patch? && flash[:notice] == l(:notice_account_updated)
versions_default_fold_state = (params[:backlogs] && params[:backlogs][:versions_default_fold_state]) ? params[:backlogs][:versions_default_fold_state] : 'open'
User.current.backlogs_preference(:versions_default_fold_state, versions_default_fold_state)
color = (params[:backlogs] ? params[:backlogs][:task_color] : '').to_s

@ -37,7 +37,6 @@ require_dependency 'permitted_params'
module OpenProject::Backlogs::Patches::PermittedParamsPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
@ -55,8 +54,8 @@ module OpenProject::Backlogs::Patches::PermittedParamsPatch
permitted_params
end
def update_work_package_with_backlogs(args = {})
def update_work_package_with_backlogs(args = {})
permitted_params = update_work_package_without_backlogs(args)
backlogs_params = params.require(:work_package).permit(:story_points, :remaining_hours)

@ -38,9 +38,7 @@ require_dependency 'project'
module OpenProject::Backlogs::Patches::ProjectPatch
def self.included(base)
base.class_eval do
unloadable
has_and_belongs_to_many :done_statuses, :join_table => :done_statuses_for_project, :class_name => "Status"
has_and_belongs_to_many :done_statuses, join_table: :done_statuses_for_project, class_name: 'Status'
include InstanceMethods
end
@ -50,12 +48,12 @@ module OpenProject::Backlogs::Patches::ProjectPatch
def rebuild_positions
return unless backlogs_enabled?
shared_versions.each { |v| v.rebuild_positions(self) }
shared_versions.each do |v| v.rebuild_positions(self) end
nil
end
def backlogs_enabled?
module_enabled? "backlogs"
module_enabled? 'backlogs'
end
end
end

@ -51,23 +51,23 @@ module OpenProject::Backlogs::Patches::ProjectsControllerPatch
end
def project_done_statuses
selected_statuses = (params[:statuses] || []).map do |work_package_status|
selected_statuses = (params[:statuses] || []).map { |work_package_status|
Status.find(work_package_status[:status_id].to_i)
end.compact
}.compact
@project.done_statuses = selected_statuses
@project.save!
flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'settings', :id => @project, :tab => 'backlogs_settings'
redirect_to action: 'settings', id: @project, tab: 'backlogs_settings'
end
def rebuild_positions
@project.rebuild_positions
flash[:notice] = l('backlogs.positions_rebuilt_successfully')
redirect_to :action => 'settings', :id => @project, :tab => 'backlogs_settings'
redirect_to action: 'settings', id: @project, tab: 'backlogs_settings'
rescue ActiveRecord::ActiveRecordError
flash[:error] = l('backlogs.positions_could_not_be_rebuilt')
@ -75,7 +75,7 @@ module OpenProject::Backlogs::Patches::ProjectsControllerPatch
logger.error($!)
logger.error($@)
redirect_to :action => 'settings', :id => @project, :tab => 'backlogs_settings'
redirect_to action: 'settings', id: @project, tab: 'backlogs_settings'
end
end
end

@ -42,10 +42,10 @@ module OpenProject::Backlogs::Patches::ProjectsHelperPatch
project_settings_tabs_without_backlogs_settings.tap do |settings|
if @project.module_enabled? 'backlogs'
settings << {
:name => 'backlogs_settings',
:action => :manage_project_activities,
:partial => 'projects/settings/backlogs_settings',
:label => 'backlogs.backlog_settings'
name: 'backlogs_settings',
action: :manage_project_activities,
partial: 'projects/settings/backlogs_settings',
label: 'backlogs.backlog_settings'
}
end
end

@ -38,17 +38,15 @@ require_dependency 'query'
module OpenProject::Backlogs::Patches::QueryPatch
def self.included(base)
base.class_eval do
unloadable
include InstanceMethods
add_available_column(QueryColumn.new(:story_points, :sortable => "#{WorkPackage.table_name}.story_points"))
add_available_column(QueryColumn.new(:remaining_hours, :sortable => "#{WorkPackage.table_name}.remaining_hours"))
add_available_column(QueryColumn.new(:story_points, sortable: "#{WorkPackage.table_name}.story_points"))
add_available_column(QueryColumn.new(:remaining_hours, sortable: "#{WorkPackage.table_name}.remaining_hours"))
add_available_column(QueryColumn.new(:position,
:default_order => 'asc',
default_order: 'asc',
# Sort by position only, always show work_packages without a position at the end
:sortable => "CASE WHEN #{WorkPackage.table_name}.position IS NULL THEN 1 ELSE 0 END ASC, #{WorkPackage.table_name}.position"
sortable: "CASE WHEN #{WorkPackage.table_name}.position IS NULL THEN 1 ELSE 0 END ASC, #{WorkPackage.table_name}.position"
))
Queries::WorkPackages::Filter.add_filter_type_by_field('backlogs_work_package_type', 'list')
@ -61,20 +59,20 @@ module OpenProject::Backlogs::Patches::QueryPatch
def available_work_package_filters_with_backlogs_work_package_type
available_work_package_filters_without_backlogs_work_package_type.tap do |filters|
if backlogs_configured? and backlogs_enabled?
filters["backlogs_work_package_type"] = {
:type => :list,
:values => [[l(:story, :scope => [:backlogs]), "story"],
[l(:task, :scope => [:backlogs]), "task"],
[l(:impediment, :scope => [:backlogs]), "impediment"],
[l(:any, :scope => [:backlogs]), "any"]],
:order => 20
filters['backlogs_work_package_type'] = {
type: :list,
values: [[l(:story, scope: [:backlogs]), 'story'],
[l(:task, scope: [:backlogs]), 'task'],
[l(:impediment, scope: [:backlogs]), 'impediment'],
[l(:any, scope: [:backlogs]), 'any']],
order: 20
}
end
end
end
def sql_for_field_with_backlogs_work_package_type(field, operator, v, db_table, db_field, is_custom_filter=false)
if field == "backlogs_work_package_type"
def sql_for_field_with_backlogs_work_package_type(field, operator, v, db_table, db_field, is_custom_filter = false)
if field == 'backlogs_work_package_type'
db_table = WorkPackage.table_name
sql = []
@ -82,16 +80,16 @@ module OpenProject::Backlogs::Patches::QueryPatch
selected_values = values_for(field)
selected_values = ['story', 'task'] if selected_values.include?('any')
story_types = Story.types.collect { |val| "#{val}" }.join(",")
all_types = (Story.types + [Task.type]).collect { |val| "#{val}" }.join(",")
story_types = Story.types.map { |val| "#{val}" }.join(',')
all_types = (Story.types + [Task.type]).map { |val| "#{val}" }.join(',')
selected_values.each do |val|
case val
when "story"
when 'story'
sql << "(#{db_table}.type_id IN (#{story_types}))"
when "task"
when 'task'
sql << "(#{db_table}.type_id = #{Task.type} AND NOT #{db_table}.parent_id IS NULL)"
when "impediment"
when 'impediment'
sql << "(#{db_table}.id IN (
select from_id
FROM relations ir
@ -105,10 +103,10 @@ module OpenProject::Backlogs::Patches::QueryPatch
end
case operator
when "="
sql = sql.join(" OR ")
when "!"
sql = "NOT (" + sql.join(" OR ") + ")"
when '='
sql = sql.join(' OR ')
when '!'
sql = 'NOT (' + sql.join(' OR ') + ')'
end
sql

@ -38,8 +38,6 @@ require_dependency 'status'
module OpenProject::Backlogs::Patches::StatusPatch
def self.included(base)
base.class_eval do
unloadable
include InstanceMethods
end
end

@ -38,8 +38,6 @@ require_dependency 'type'
module OpenProject::Backlogs::Patches::TypePatch
def self.included(base)
base.class_eval do
unloadable
include InstanceMethods
extend ClassMethods
end

@ -38,15 +38,12 @@ require_dependency 'user'
module OpenProject::Backlogs::Patches::UserPatch
def self.included(base)
base.class_eval do
unloadable
include InstanceMethods
end
end
module InstanceMethods
def backlogs_preference(attr, new_value = nil)
setting = read_backlogs_preference(attr)
if setting.nil? and new_value.nil?
@ -63,14 +60,14 @@ module OpenProject::Backlogs::Patches::UserPatch
protected
def read_backlogs_preference(attr)
setting = self.pref[:"backlogs_#{attr}"]
setting = pref[:"backlogs_#{attr}"]
setting.blank? ? nil : setting
end
def write_backlogs_preference(attr, new_value)
self.pref[:"backlogs_#{attr}"] = new_value
self.pref.save! unless self.new_record?
pref[:"backlogs_#{attr}"] = new_value
pref.save! unless self.new_record?
new_value
end
@ -78,9 +75,9 @@ module OpenProject::Backlogs::Patches::UserPatch
def compute_backlogs_preference(attr)
case attr
when :task_color
("#%0.6x" % rand(0xFFFFFF)).upcase
('#%0.6x' % rand(0xFFFFFF)).upcase
when :versions_default_fold_state
"open"
'open'
else
raise "Unsupported attribute '#{attr}'"
end

@ -38,9 +38,7 @@ require_dependency 'version'
module OpenProject::Backlogs::Patches::VersionPatch
def self.included(base)
base.class_eval do
unloadable
has_many :version_settings, :dependent => :destroy
has_many :version_settings, dependent: :destroy
accepts_nested_attributes_for :version_settings
include Redmine::SafeAttributes
@ -56,13 +54,13 @@ module OpenProject::Backlogs::Patches::VersionPatch
WorkPackage.transaction do
# Remove position from all non-stories
WorkPackage.update_all({:position => nil}, ['project_id = ? AND type_id NOT IN (?) AND position IS NOT NULL', project, Story.types])
WorkPackage.update_all({ position: nil }, ['project_id = ? AND type_id NOT IN (?) AND position IS NOT NULL', project, Story.types])
# Add work_packages w/o position to the top of the list and add
# work_packages, that have a position, at the end
stories_wo_position = self.fixed_issues.find(:all, :conditions => {:project_id => project, :type_id => Story.types, :position => nil}, :order => 'id')
stories_wo_position = fixed_issues.find(:all, conditions: { project_id: project, type_id: Story.types, position: nil }, order: 'id')
stories_w_position = self.fixed_issues.find(:all, :conditions => ['project_id = ? AND type_id IN (?) AND position IS NOT NULL', project, Story.types], :order => 'COALESCE(position, 0), id')
stories_w_position = fixed_issues.find(:all, conditions: ['project_id = ? AND type_id IN (?) AND position IS NOT NULL', project, Story.types], order: 'COALESCE(position, 0), id')
(stories_w_position + stories_wo_position).each_with_index do |story, index|
story.send(:update_attribute_silently, 'position', index + 1)
@ -74,7 +72,7 @@ module OpenProject::Backlogs::Patches::VersionPatch
def ==(other)
super ||
other.is_a?(self.class) &&
other.is_a?(self.class) &&
id.present? &&
other.id == id
end

@ -38,19 +38,17 @@ require_dependency 'versions_controller'
module OpenProject::Backlogs::Patches::VersionsControllerPatch
def self.included(base)
base.class_eval do
unloadable
include VersionSettingsHelper
helper :version_settings
# Find project explicitly on update and edit
skip_before_filter :find_project_from_association, :only => [:edit, :update]
skip_before_filter :find_model_object, :only => [:edit, :update]
prepend_before_filter :find_project_and_version, :only => [:edit, :update]
skip_before_filter :find_project_from_association, only: [:edit, :update]
skip_before_filter :find_model_object, only: [:edit, :update]
prepend_before_filter :find_project_and_version, only: [:edit, :update]
before_filter :add_project_to_version_settings_attributes, :only => [:update, :create]
before_filter :add_project_to_version_settings_attributes, only: [:update, :create]
before_filter :whitelist_update_params, :only => :update
before_filter :whitelist_update_params, only: :update
def whitelist_update_params
if @project != @version.project
@ -58,14 +56,13 @@ module OpenProject::Backlogs::Patches::VersionsControllerPatch
# (column=left|right|none) can be stored when current project does not
# equal the version project (which is valid in inherited versions)
if params[:version] and params[:version][:version_settings_attributes]
params[:version] = { :version_settings_attributes => params[:version][:version_settings_attributes] }
params[:version] = { version_settings_attributes: params[:version][:version_settings_attributes] }
else
params[:version] = {}
end
end
end
def find_project_and_version
find_model_object
if params[:project_id]
@ -78,9 +75,9 @@ module OpenProject::Backlogs::Patches::VersionsControllerPatch
# This forces the current project for the nested version settings in order
# to prevent it from being set through firebug etc. #mass_assignment
def add_project_to_version_settings_attributes
if params["version"]["version_settings_attributes"]
params["version"]["version_settings_attributes"].each do |attr_hash|
attr_hash["project"] = @project
if params['version']['version_settings_attributes']
params['version']['version_settings_attributes'].each do |attr_hash|
attr_hash['project'] = @project
end
end
end

@ -38,33 +38,30 @@ require_dependency 'work_package'
module OpenProject::Backlogs::Patches::WorkPackagePatch
def self.included(base)
base.class_eval do
unloadable
include InstanceMethods
extend ClassMethods
alias_method_chain :recalculate_attributes_for, :remaining_hours
before_validation :backlogs_before_validation, :if => lambda {|i| i.backlogs_enabled?}
before_validation :backlogs_before_validation, if: lambda { |i| i.backlogs_enabled? }
before_save :inherit_version_from_closest_story_or_impediment, :if => lambda { |i| i.is_task? }
after_save :inherit_version_to_descendants, :if => lambda {|i| (i.fixed_version_id_changed? && i.backlogs_enabled? && i.closest_story_or_impediment == i) }
after_move :inherit_version_to_descendants, :if => lambda {|i| i.is_task? }
before_save :inherit_version_from_closest_story_or_impediment, if: lambda { |i| i.is_task? }
after_save :inherit_version_to_descendants, if: lambda { |i| (i.fixed_version_id_changed? && i.backlogs_enabled? && i.closest_story_or_impediment == i) }
after_move :inherit_version_to_descendants, if: lambda { |i| i.is_task? }
register_on_journal_formatter(:fraction, 'remaining_hours')
register_on_journal_formatter(:decimal, 'story_points')
register_on_journal_formatter(:decimal, 'position')
validates_numericality_of :story_points, :only_integer => true,
:allow_nil => true,
:greater_than_or_equal_to => 0,
:less_than => 10_000,
:if => lambda { |i| i.backlogs_enabled? }
validates_numericality_of :remaining_hours, :only_integer => false,
:allow_nil => true,
:greater_than_or_equal_to => 0,
:if => lambda { |i| i.project && i.project.module_enabled?('backlogs') }
validates_numericality_of :story_points, only_integer: true,
allow_nil: true,
greater_than_or_equal_to: 0,
less_than: 10_000,
if: lambda { |i| i.backlogs_enabled? }
validates_numericality_of :remaining_hours, only_integer: false,
allow_nil: true,
greater_than_or_equal_to: 0,
if: lambda { |i| i.project && i.project.module_enabled?('backlogs') }
validates_each :parent_id do |record, attr, value|
validate_parent_work_package_relation(record, attr, value)
@ -101,9 +98,9 @@ module OpenProject::Backlogs::Patches::WorkPackagePatch
parent = WorkPackage.find_by_id(value)
if parent && parent_work_package_relationship_spanning_projects?(parent, work_package)
work_package.errors.add(parent_attr,
:parent_child_relationship_across_projects,
:work_package_name => work_package.subject,
:parent_name => parent.subject)
:parent_child_relationship_across_projects,
work_package_name: work_package.subject,
parent_name: parent.subject)
end
end
@ -114,7 +111,7 @@ module OpenProject::Backlogs::Patches::WorkPackagePatch
module InstanceMethods
def done?
self.project.done_statuses.include?(self.status)
project.done_statuses.include?(status)
end
def to_story
@ -122,7 +119,7 @@ module OpenProject::Backlogs::Patches::WorkPackagePatch
end
def is_story?
backlogs_enabled? && Story.types.include?(self.type_id)
backlogs_enabled? && Story.types.include?(type_id)
end
def to_task
@ -130,11 +127,11 @@ module OpenProject::Backlogs::Patches::WorkPackagePatch
end
def is_task?
backlogs_enabled? && (self.parent_id && self.type_id == Task.type && Task.type.present?)
backlogs_enabled? && (parent_id && type_id == Task.type && Task.type.present?)
end
def is_impediment?
backlogs_enabled? && (self.parent_id.nil? && self.type_id == Task.type && Task.type.present?)
backlogs_enabled? && (parent_id.nil? && type_id == Task.type && Task.type.present?)
end
def types
@ -150,11 +147,11 @@ module OpenProject::Backlogs::Patches::WorkPackagePatch
def story
if self.is_story?
return Story.find(self.id)
return Story.find(id)
elsif self.is_task?
# Make sure to get the closest ancestor that is a Story, i.e. the one with the highest lft
# otherwise, the highest parent that is a Story is returned
story_work_package = self.ancestors.find_by_type_id(Story.types, :order => 'lft DESC')
story_work_package = ancestors.find_by_type_id(Story.types, order: 'lft DESC')
return Story.find(story_work_package.id) if story_work_package
end
nil
@ -163,13 +160,13 @@ module OpenProject::Backlogs::Patches::WorkPackagePatch
def blocks
# return work_packages that I block that aren't closed
return [] if closed?
relations_from.collect {|ir| ir.relation_type == 'blocks' && !ir.to.closed? ? ir.to : nil}.compact
relations_from.map { |ir| ir.relation_type == 'blocks' && !ir.to.closed? ? ir.to : nil }.compact
end
def blockers
# return work_packages that block me
return [] if closed?
relations_to.collect {|ir| ir.relation_type == 'blocks' && !ir.from.closed? ? ir.from : nil}.compact
relations_to.map { |ir| ir.relation_type == 'blocks' && !ir.from.closed? ? ir.from : nil }.compact
end
def recalculate_attributes_for_with_remaining_hours(work_package_id)
@ -184,7 +181,7 @@ module OpenProject::Backlogs::Patches::WorkPackagePatch
p.left != (p.right + 1) # this node has children
p.remaining_hours = p.leaves.sum(:remaining_hours).to_f
p.remaining_hours = nil if p.remaining_hours == 0.0
p.remaining_hours = nil if p.remaining_hours == 0.0
end
recalculate_attributes_for_without_remaining_hours(p)
@ -192,42 +189,42 @@ module OpenProject::Backlogs::Patches::WorkPackagePatch
end
def inherit_version_from(source)
self.fixed_version_id = source.fixed_version_id if source && self.project_id == source.project_id
self.fixed_version_id = source.fixed_version_id if source && project_id == source.project_id
end
def backlogs_enabled?
!!self.project.try(:module_enabled?, "backlogs")
!!project.try(:module_enabled?, 'backlogs')
end
def in_backlogs_type?
backlogs_enabled? && WorkPackage.backlogs_types.include?(self.type.try(:id))
backlogs_enabled? && WorkPackage.backlogs_types.include?(type.try(:id))
end
# ancestors array similar to Module#ancestors
# i.e. returns immediate ancestors first
def ancestor_chain
ancestors = []
unless self.parent_id.nil?
unless parent_id.nil?
# Unfortunately the nested set is only build on save hence, the #parent
# method is not always correct. Therefore we go to the parent the hard
# way and use nested set from there
real_parent = WorkPackage.find_by_id(self.parent_id)
real_parent = WorkPackage.find_by_id(parent_id)
# Sort immediate ancestors first
ancestors = ([real_parent] + real_parent.ancestors.all(:include => { :project => :enabled_modules })).sort_by(&:right)
ancestors = ([real_parent] + real_parent.ancestors.all(include: { project: :enabled_modules })).sort_by(&:right)
end
ancestors
end
def closest_story_or_impediment
return nil unless in_backlogs_type?
return self if (self.is_story? || self.is_impediment?)
return self if self.is_story? || self.is_impediment?
closest = nil
ancestor_chain.each do |i|
# break if we found an element in our chain that is not relevant in backlogs
break unless i.in_backlogs_type?
if (i.is_story? || i.is_impediment?)
if i.is_story? || i.is_impediment?
closest = i
break
end
@ -238,9 +235,9 @@ module OpenProject::Backlogs::Patches::WorkPackagePatch
private
def backlogs_before_validation
if self.type_id == Task.type
self.estimated_hours = self.remaining_hours if self.estimated_hours.blank? && ! self.remaining_hours.blank?
self.remaining_hours = self.estimated_hours if self.remaining_hours.blank? && ! self.estimated_hours.blank?
if type_id == Task.type
self.estimated_hours = remaining_hours if estimated_hours.blank? && !remaining_hours.blank?
self.remaining_hours = estimated_hours if remaining_hours.blank? && !estimated_hours.blank?
end
end
@ -254,8 +251,8 @@ module OpenProject::Backlogs::Patches::WorkPackagePatch
begin
WorkPackage.take_child_update_semaphore
descendant_tasks, stop_descendants = self.descendants.all(:include => { :project => :enabled_modules }).partition { |d| d.is_task? }
descendant_tasks.reject!{ |t| stop_descendants.any? { |s| s.left < t.left && s.right > t.right } }
descendant_tasks, stop_descendants = descendants.all(include: { project: :enabled_modules }).partition(&:is_task?)
descendant_tasks.reject! do |t| stop_descendants.any? { |s| s.left < t.left && s.right > t.right } end
descendant_tasks.each do |task|
task.inherit_version_from(self)

@ -38,8 +38,6 @@ require_dependency 'api/v3/work_packages/schema/work_package_schema'
module OpenProject::Backlogs::Patches::WorkPackageSchemaPatch
def self.included(base)
base.class_eval do
unloadable
include InstanceMethods
extend ClassMethods
end

@ -36,8 +36,6 @@
module OpenProject::Backlogs::Patches::WorkPackagesHelperPatch
def self.included(base)
base.class_eval do
unloadable
def work_package_form_all_middle_attributes_with_backlogs(form, work_package, locals = {})
attributes = work_package_form_all_middle_attributes_without_backlogs(form, work_package, locals)
@ -50,12 +48,12 @@ module OpenProject::Backlogs::Patches::WorkPackagesHelperPatch
end
def work_package_form_remaining_hours_attribute(form, work_package, _)
field = work_package_form_field do
field = work_package_form_field {
options = { placeholder: l(:label_hours) }
options[:disabled] = 'disabled' unless work_package.leaf?
form.text_field(:remaining_hours, options)
end
}
WorkPackagesHelper::WorkPackageAttribute.new(:remaining_hours, field)
end
@ -63,9 +61,9 @@ module OpenProject::Backlogs::Patches::WorkPackagesHelperPatch
def work_package_form_story_points_attribute(form, work_package, _)
return unless work_package.is_story?
field = work_package_form_field do
field = work_package_form_field {
form.text_field(:story_points)
end
}
WorkPackagesHelper::WorkPackageAttribute.new(:story_points, field)
end
@ -73,7 +71,6 @@ module OpenProject::Backlogs::Patches::WorkPackagesHelperPatch
alias_method_chain :work_package_form_all_middle_attributes, :backlogs
end
end
end
WorkPackagesHelper.send(:include, OpenProject::Backlogs::Patches::WorkPackagesHelperPatch)

@ -33,4 +33,4 @@
# See doc/COPYRIGHT.rdoc for more details.
#++
require "open_project/backlogs"
require 'open_project/backlogs'

@ -1,24 +1,24 @@
$:.push File.expand_path("../lib", __FILE__)
$:.push File.expand_path('../lib', __FILE__)
# Maintain your gem's version:
require "open_project/backlogs/version"
require 'open_project/backlogs/version'
# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
s.name = "openproject-backlogs"
s.name = 'openproject-backlogs'
s.version = OpenProject::Backlogs::VERSION
s.authors = "Finn GmbH"
s.email = "info@finn.de"
s.homepage = "https://www.openproject.org/projects/plugin-backlogs"
s.summary = "OpenProject Backlogs"
s.description = "This plugin adds features enabling agile teams to work with OpenProject in Scrum projects."
s.files = Dir["{app,config,db,lib,doc}/**/*", "README.md"]
s.test_files = Dir["spec/**/*"]
s.authors = 'Finn GmbH'
s.email = 'info@finn.de'
s.homepage = 'https://www.openproject.org/projects/plugin-backlogs'
s.summary = 'OpenProject Backlogs'
s.description = 'This plugin adds features enabling agile teams to work with OpenProject in Scrum projects.'
s.files = Dir['{app,config,db,lib,doc}/**/*', 'README.md']
s.test_files = Dir['spec/**/*']
s.add_dependency "rails", "~> 3.2.9"
s.add_dependency "acts_as_silent_list"
s.add_dependency "openproject-pdf_export"
s.add_dependency 'rails', '~> 4.0.13'
s.add_dependency 'acts_as_silent_list'
s.add_development_dependency "factory_girl_rails", "~> 4.0"
s.add_dependency 'openproject-pdf_export'
s.add_development_dependency 'factory_girl_rails', '~> 4.0'
end

@ -40,9 +40,11 @@ describe ::API::V3::WorkPackages::CreateContract do
FactoryGirl.build(:work_package,
project: project)
end
let(:member) { FactoryGirl.create(:user,
member_in_project: project,
member_through_role: role) }
let(:member) {
FactoryGirl.create(:user,
member_in_project: project,
member_through_role: role)
}
let (:project) { FactoryGirl.create(:project) }
let(:current_user) { member }
let(:permissions) {

@ -35,38 +35,38 @@
require 'spec_helper'
describe VersionsController, :type => :controller do
describe VersionsController, type: :controller do
before do
allow(@controller).to receive(:authorize)
# Create a version assigned to a project
@version = FactoryGirl.create(:version)
@oldVersionName = @version.name
@newVersionName = "NewVersionName"
@newVersionName = 'NewVersionName'
# Create another project
@project = FactoryGirl.create(:project)
# Create params to update version
@params = {}
@params[:id] = @version.id
@params[:version] = { :name => @newVersionName }
@params[:version] = { name: @newVersionName }
end
describe 'update' do
it 'does not allow to update versions from different projects' do
@params[:project_id] = @project.id
put 'update', @params
patch 'update', @params
@version.reload
expect(response).to redirect_to :controller => '/projects', :action => 'settings', :tab => 'versions', :id => @project
expect(response).to redirect_to controller: '/projects', action: 'settings', tab: 'versions', id: @project
expect(@version.name).to eq(@oldVersionName)
end
it 'allows to update versions from the version project' do
@params[:project_id] = @version.project.id
put 'update', @params
patch 'update', @params
@version.reload
expect(response).to redirect_to :controller => '/projects', :action => 'settings', :tab => 'versions', :id => @version.project
expect(response).to redirect_to controller: '/projects', action: 'settings', tab: 'versions', id: @version.project
expect(@version.name).to eq(@newVersionName)
end
end

@ -35,21 +35,21 @@
require 'spec_helper'
describe WorkPackagesController, :type => :controller do
describe WorkPackagesController, type: :controller do
before do
allow(User).to receive(:current).and_return current_user
# disables sending mails
allow(UserMailer).to receive(:new).and_return(double('mailer').as_null_object)
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"points_burn_direction" => "down",
"wiki_template" => "",
"card_spec" => "Sattleford VM-5040",
"story_types" => [story_type.id.to_s],
"task_type" => task_type.id.to_s })
[task, story, closed_task].collect(&:reload)
allow(Setting).to receive(:plugin_openproject_backlogs).and_return('points_burn_direction' => 'down',
'wiki_template' => '',
'card_spec' => 'Sattleford VM-5040',
'story_types' => [story_type.id.to_s],
'task_type' => task_type.id.to_s)
[task, story, closed_task].map(&:reload)
end
let(:current_user) { FactoryGirl.create(:admin) }
let(:project) { FactoryGirl.create(:project, :identifier => 'test_project', :is_public => true) }
let(:project) { FactoryGirl.create(:project, identifier: 'test_project', is_public: true) }
let(:status) { FactoryGirl.create :default_status }
let(:closed) { FactoryGirl.create :closed_status }
let(:story_type) { FactoryGirl.create(:type_feature) }
@ -61,20 +61,22 @@ describe WorkPackagesController, :type => :controller do
describe 'show' do
let(:story_points) { 42 }
let(:story_with_sp) { FactoryGirl.create(:story,
type: story_type,
author: current_user,
project: project,
status: status,
story_points: story_points) }
let(:story_with_sp) {
FactoryGirl.create(:story,
type: story_type,
author: current_user,
project: project,
status: status,
story_points: story_points)
}
before { get 'show', id: story_with_sp.id }
before do get 'show', id: story_with_sp.id end
subject { response }
it { is_expected.to be_success }
it { is_expected.to render_template('work_packages/show', formats: ['html']) }
it { is_expected.to render_template('work_packages/show') }
context 'view' do
render_views
@ -86,41 +88,43 @@ describe WorkPackagesController, :type => :controller do
end
describe 'create with copy_from' do
describe do 'copying no tasks'
describe do
'copying no tasks'
before do
post('create', params.merge({copy_tasks: "none"}))
post('create', params.merge(copy_tasks: 'none'))
end
subject { response }
it { expect(assigns["new_work_package"].children(true)).to be_empty }
it { expect(assigns['new_work_package'].children(true)).to be_empty }
end
describe do 'copying no tasks'
describe do
'copying no tasks'
before do
post('create', params.merge({copy_tasks: "open:#{story.id}"}))
post('create', params.merge(copy_tasks: "open:#{story.id}"))
end
subject { response }
it do
expect(assigns["new_work_package"].children(true)).not_to be_empty
expect(assigns["new_work_package"].children(true).count).to eq(1)
expect(assigns['new_work_package'].children(true)).not_to be_empty
expect(assigns['new_work_package'].children(true).count).to eq(1)
end
end
describe do 'copying no tasks'
describe do
'copying no tasks'
before do
post('create', params.merge({copy_tasks: "all:#{story.id}"}))
post('create', params.merge(copy_tasks: "all:#{story.id}"))
end
subject { response }
it do
expect(assigns["new_work_package"].children(true)).not_to be_empty
expect(assigns["new_work_package"].children(true).count).to eq(2)
expect(assigns['new_work_package'].children(true)).not_to be_empty
expect(assigns['new_work_package'].children(true).count).to eq(2)
end
end
end
end

@ -35,10 +35,10 @@
FactoryGirl.define do
factory :impediment do
association :type, :factory => :type_task
subject "Impeding progress"
description "Unable to print recipes"
association :priority, :factory => :priority
association :author, :factory => :user
association :type, factory: :type_task
subject 'Impeding progress'
description 'Unable to print recipes'
association :priority, factory: :priority
association :author, factory: :user
end
end

@ -35,9 +35,9 @@
FactoryGirl.define do
factory :sprint do
name "version"
name 'version'
effective_date Date.today + 14.days
sharing "none"
status "open"
sharing 'none'
status 'open'
end
end

@ -35,10 +35,10 @@
FactoryGirl.define do
factory :story do
association :priority, :factory => :priority
sequence(:subject) { |n| "story#{n}" }
description "story story story"
association :type, :factory => :type_feature
association :author, :factory => :user
association :priority, factory: :priority
sequence(:subject) do |n| "story#{n}" end
description 'story story story'
association :type, factory: :type_feature
association :author, factory: :user
end
end

@ -35,10 +35,10 @@
FactoryGirl.define do
factory :task do
association :type, :factory => :type_task
subject "Printing Recipes"
description "Just printing recipes"
association :priority, :factory => :priority
association :author, :factory => :user
association :type, factory: :type_task
subject 'Printing Recipes'
description 'Just printing recipes'
association :priority, factory: :priority
association :author, factory: :user
end
end

@ -35,12 +35,12 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe VersionSettingsHelper, :type => :helper do
describe VersionSettingsHelper, type: :helper do
describe '#position_display_options' do
before(:each) do
@expected_options = [[I18n.t("version_settings_display_option_none"), 1],
[I18n.t("version_settings_display_option_left"), 2],
[I18n.t("version_settings_display_option_right"), 3]]
@expected_options = [[I18n.t('version_settings_display_option_none'), 1],
[I18n.t('version_settings_display_option_left'), 2],
[I18n.t('version_settings_display_option_right'), 3]]
end
it { expect(helper.send(:position_display_options)).to eql @expected_options }

@ -35,29 +35,28 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe Backlog, :type => :model do
describe Backlog, type: :model do
let(:project) { FactoryGirl.build(:project) }
before(:each) do
@feature = FactoryGirl.create(:type_feature)
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ "story_types" => [@feature.id.to_s],
"task_type" => "0" })
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'story_types' => [@feature.id.to_s],
'task_type' => '0' })
@status = FactoryGirl.create(:status)
end
describe "Class Methods" do
describe 'Class Methods' do
describe '#owner_backlogs' do
describe "WITH one open version defined in the project" do
describe 'WITH one open version defined in the project' do
before(:each) do
@project = project
@work_packages = [FactoryGirl.create(:work_package, :subject => "work_package1", :project => @project, :type => @feature, :status => @status)]
@version = FactoryGirl.create(:version, :project => project, :fixed_issues => @work_packages)
@version_settings = @version.version_settings.create(:display => VersionSetting::DISPLAY_RIGHT, :project => project)
@work_packages = [FactoryGirl.create(:work_package, subject: 'work_package1', project: @project, type: @feature, status: @status)]
@version = FactoryGirl.create(:version, project: project, fixed_issues: @work_packages)
@version_settings = @version.version_settings.create(display: VersionSetting::DISPLAY_RIGHT, project: project)
end
it { expect(Backlog.owner_backlogs(@project)[0]).to be_owner_backlog }
end
end
end
end

@ -35,7 +35,7 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe Burndown, :type => :model do
describe Burndown, type: :model do
def set_attribute_journalized(story, attribute, value, day)
story.reload
story.send(attribute, value)
@ -47,36 +47,35 @@ describe Burndown, :type => :model do
let(:role) { @role ||= FactoryGirl.create(:role) }
let(:type_feature) { @type_feature ||= FactoryGirl.create(:type_feature) }
let(:type_task) { @type_task ||= FactoryGirl.create(:type_task) }
let(:issue_priority) { @issue_priority ||= FactoryGirl.create(:priority, :is_default => true) }
let(:version) { @version ||= FactoryGirl.create(:version, :project => project) }
let(:issue_priority) { @issue_priority ||= FactoryGirl.create(:priority, is_default: true) }
let(:version) { @version ||= FactoryGirl.create(:version, project: project) }
let(:sprint) { @sprint ||= Sprint.find(version.id) }
let(:project) do
unless @project
@project = FactoryGirl.build(:project)
@project.members = [FactoryGirl.build(:member, :principal => user,
:project => @project,
:roles => [role])]
@project.members = [FactoryGirl.build(:member, principal: user,
project: @project,
roles: [role])]
@project.versions << version
end
@project
end
let(:issue_open) { @status1 ||= FactoryGirl.create(:status, :name => "status 1", :is_default => true) }
let(:issue_closed) { @status2 ||= FactoryGirl.create(:status, :name => "status 2", :is_closed => true) }
let(:issue_resolved) { @status3 ||= FactoryGirl.create(:status, :name => "status 3", :is_closed => false) }
let(:issue_open) { @status1 ||= FactoryGirl.create(:status, name: 'status 1', is_default: true) }
let(:issue_closed) { @status2 ||= FactoryGirl.create(:status, name: 'status 2', is_closed: true) }
let(:issue_resolved) { @status3 ||= FactoryGirl.create(:status, name: 'status 3', is_closed: false) }
before(:each) do
Rails.cache.clear
allow(User).to receive(:current).and_return(user)
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"points_burn_direction" => "down",
"wiki_template" => "",
"card_spec" => "Sattleford VM-5040",
"story_types" => [type_feature.id.to_s],
"task_type" => type_task.id.to_s })
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'points_burn_direction' => 'down',
'wiki_template' => '',
'card_spec' => 'Sattleford VM-5040',
'story_types' => [type_feature.id.to_s],
'task_type' => type_task.id.to_s })
project.save!
@ -89,52 +88,52 @@ describe Burndown, :type => :model do
end
end
describe "Sprint Burndown" do
describe "WITH the today date fixed to April 4th, 2011 and having a 10 (working days) sprint" do
describe 'Sprint Burndown' do
describe 'WITH the today date fixed to April 4th, 2011 and having a 10 (working days) sprint' do
before(:each) do
allow(Time).to receive(:now).and_return(Time.utc(2011,"apr",4,20,15,1))
allow(Date).to receive(:today).and_return(Date.civil(2011,04,04))
allow(Time).to receive(:now).and_return(Time.utc(2011, 'apr', 4, 20, 15, 1))
allow(Date).to receive(:today).and_return(Date.civil(2011, 04, 04))
end
describe "WITH having a version in the future" do
describe 'WITH having a version in the future' do
before(:each) do
version.start_date = Date.today + 1.days
version.effective_date = Date.today + 6.days
version.save!
end
it "should generate a burndown" do
it 'should generate a burndown' do
expect(sprint.burndown(project).series[:story_points]).to be_empty
end
end
describe "WITH having a 10 (working days) sprint and being 5 (working) days into it" do
describe 'WITH having a 10 (working days) sprint and being 5 (working) days into it' do
before(:each) do
version.start_date = Date.today - 7.days
version.effective_date = Date.today + 6.days
version.save!
end
describe "WITH 1 story assigned to the sprint" do
describe 'WITH 1 story assigned to the sprint' do
before(:each) do
@story = FactoryGirl.build(:story, :subject => "Story 1",
:project => project,
:fixed_version => version,
:type => type_feature,
:status => issue_open,
:priority => issue_priority,
:created_at => Date.today - 20.days,
:updated_at => Date.today - 20.days)
@story = FactoryGirl.build(:story, subject: 'Story 1',
project: project,
fixed_version: version,
type: type_feature,
status: issue_open,
priority: issue_priority,
created_at: Date.today - 20.days,
updated_at: Date.today - 20.days)
end
describe "WITH the story having story_point defined on creation" do
describe 'WITH the story having story_point defined on creation' do
before(:each) do
@story.story_points = 9
@story.save!
@story.current_journal.update_attribute(:created_at, @story.created_at)
end
describe "WITH the story being closed and opened again within the sprint duration" do
describe 'WITH the story being closed and opened again within the sprint duration' do
before(:each) do
set_attribute_journalized @story, :status_id=, issue_closed.id, Time.now - 6.days
set_attribute_journalized @story, :status_id=, issue_open.id, Time.now - 3.days
@ -144,7 +143,7 @@ describe Burndown, :type => :model do
it { expect(@burndown.story_points).to eql [9.0, 0.0, 0.0, 0.0, 9.0, 9.0] }
it { expect(@burndown.story_points.unit).to eql :points }
it { expect(@burndown.days).to eql(sprint.days()) }
it { expect(@burndown.days).to eql(sprint.days) }
it { expect(@burndown.max[:hours]).to eql 0.0 }
it { expect(@burndown.max[:points]).to eql 9.0 }
it { expect(@burndown.story_points_ideal).to eql [9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0] }
@ -164,31 +163,31 @@ describe Burndown, :type => :model do
end
end
describe "WITH 10 stories assigned to the sprint" do
describe 'WITH 10 stories assigned to the sprint' do
before(:each) do
@stories = []
(0..9).each do |i|
@stories[i] = FactoryGirl.create(:story, :subject => "Story #{i}",
:project => project,
:fixed_version => version,
:type => type_feature,
:status => issue_open,
:priority => issue_priority,
:created_at => Date.today - (20 - i).days,
:updated_at => Date.today - (20 - i).days)
@stories[i] = FactoryGirl.create(:story, subject: "Story #{i}",
project: project,
fixed_version: version,
type: type_feature,
status: issue_open,
priority: issue_priority,
created_at: Date.today - (20 - i).days,
updated_at: Date.today - (20 - i).days)
@stories[i].current_journal.update_attribute(:created_at, @stories[i].created_at)
end
end
describe "WITH each story having story points defined at start" do
describe 'WITH each story having story points defined at start' do
before(:each) do
@stories.each_with_index do |s, i|
@stories.each_with_index do |s, _i|
set_attribute_journalized s, :story_points=, 10, version.start_date - 3.days
end
end
describe "WITH 5 stories having been reduced to 0 story points, one story per day" do
describe 'WITH 5 stories having been reduced to 0 story points, one story per day' do
before(:each) do
@finished_hours
(0..4).each do |i|
@ -196,21 +195,20 @@ describe Burndown, :type => :model do
end
end
describe "THEN" do
describe 'THEN' do
before(:each) do
@burndown = Burndown.new(sprint, project)
end
it { expect(@burndown.story_points).to eql [90.0, 80.0, 70.0, 60.0, 50.0, 50.0] }
it { expect(@burndown.story_points.unit).to eql :points }
it { expect(@burndown.days).to eql(sprint.days()) }
it { expect(@burndown.days).to eql(sprint.days) }
it { expect(@burndown.max[:hours]).to eql 0.0 }
it { expect(@burndown.max[:points]).to eql 90.0 }
it { expect(@burndown.story_points_ideal).to eql [90.0, 80.0, 70.0, 60.0, 50.0, 40.0, 30.0, 20.0, 10.0, 0.0] }
end
end
end
end
end
end

@ -35,56 +35,64 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe Impediment, :type => :model do
describe Impediment, type: :model do
let(:user) { @user ||= FactoryGirl.create(:user) }
let(:role) { @role ||= FactoryGirl.create(:role) }
let(:type_feature) { @type_feature ||= FactoryGirl.create(:type_feature) }
let(:type_task) { @type_task ||= FactoryGirl.create(:type_task) }
let(:issue_priority) { @issue_priority ||= FactoryGirl.create(:priority, :is_default => true) }
let(:task) { FactoryGirl.build(:task, :type => type_task,
:project => project,
:author => user,
:priority => issue_priority,
:status => status1) }
let(:feature) { FactoryGirl.build(:work_package, :type => type_feature,
:project => project,
:author => user,
:priority => issue_priority,
:status => status1) }
let(:version) { FactoryGirl.create(:version, :project => project) }
let(:issue_priority) { @issue_priority ||= FactoryGirl.create(:priority, is_default: true) }
let(:task) {
FactoryGirl.build(:task, type: type_task,
project: project,
author: user,
priority: issue_priority,
status: status1)
}
let(:feature) {
FactoryGirl.build(:work_package, type: type_feature,
project: project,
author: user,
priority: issue_priority,
status: status1)
}
let(:version) { FactoryGirl.create(:version, project: project) }
let(:project) do
unless @project
@project = FactoryGirl.build(:project, :types => [type_feature, type_task])
@project.members = [FactoryGirl.build(:member, :principal => user,
:project => @project,
:roles => [role])]
@project = FactoryGirl.build(:project, types: [type_feature, type_task])
@project.members = [FactoryGirl.build(:member, principal: user,
project: @project,
roles: [role])]
end
@project
end
let(:status1) { @status1 ||= FactoryGirl.create(:status, :name => "status 1", :is_default => true) }
let(:status2) { @status2 ||= FactoryGirl.create(:status, :name => "status 2") }
let(:type_workflow) { @workflow ||= Workflow.create(:type_id => type_task.id,
:old_status => status1,
:new_status => status2,
:role => role) }
let(:impediment) { FactoryGirl.build(:impediment, :author => user,
:fixed_version => version,
:assigned_to => user,
:priority => issue_priority,
:project => project,
:type => type_task,
:status => status1)}
let(:status1) { @status1 ||= FactoryGirl.create(:status, name: 'status 1', is_default: true) }
let(:status2) { @status2 ||= FactoryGirl.create(:status, name: 'status 2') }
let(:type_workflow) {
@workflow ||= Workflow.create(type_id: type_task.id,
old_status: status1,
new_status: status2,
role: role)
}
let(:impediment) {
FactoryGirl.build(:impediment, author: user,
fixed_version: version,
assigned_to: user,
priority: issue_priority,
project: project,
type: type_task,
status: status1)
}
before(:each) do
ActionController::Base.perform_caching = false
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"points_burn_direction" => "down",
"wiki_template" => "",
"card_spec" => "Sattleford VM-5040",
"story_types" => [type_feature.id.to_s],
"task_type" => type_task.id.to_s })
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'points_burn_direction' => 'down',
'wiki_template' => '',
'card_spec' => 'Sattleford VM-5040',
'story_types' => [type_feature.id.to_s],
'task_type' => type_task.id.to_s })
allow(User).to receive(:current).and_return(user)
issue_priority.save
@ -93,107 +101,106 @@ describe Impediment, :type => :model do
type_workflow.save
end
describe "class methods" do
describe 'class methods' do
describe '#create_with_relationships' do
before(:each) do
@impediment_subject = "Impediment A"
@impediment_subject = 'Impediment A'
role.permissions = [:create_impediments]
role.save
end
shared_examples_for "impediment creation" do
shared_examples_for 'impediment creation' do
it { expect(@impediment.subject).to eql @impediment_subject }
it { expect(@impediment.author).to eql User.current }
it { expect(@impediment.project).to eql project }
it { expect(@impediment.fixed_version).to eql version }
it { expect(@impediment.priority).to eql issue_priority}
it { expect(@impediment.priority).to eql issue_priority }
it { expect(@impediment.status).to eql status1 }
it { expect(@impediment.type).to eql type_task }
it { expect(@impediment.assigned_to).to eql user }
end
shared_examples_for "impediment creation with 1 blocking relationship" do
it_should_behave_like "impediment creation"
shared_examples_for 'impediment creation with 1 blocking relationship' do
it_should_behave_like 'impediment creation'
it { expect(@impediment.relations_from.size).to eq(1) }
it { expect(@impediment.relations_from[0].to).to eql feature }
it { expect(@impediment.relations_from[0].relation_type).to eql Relation::TYPE_BLOCKS }
end
shared_examples_for "impediment creation with no blocking relationship" do
it_should_behave_like "impediment creation"
shared_examples_for 'impediment creation with no blocking relationship' do
it_should_behave_like 'impediment creation'
it { expect(@impediment.relations_from.size).to eq(0) }
end
describe "WITH a blocking relationship to a story" do
describe "WITH the story having the same version" do
describe 'WITH a blocking relationship to a story' do
describe 'WITH the story having the same version' do
before(:each) do
feature.fixed_version = version
feature.save
@impediment = Impediment.create_with_relationships({:subject => @impediment_subject,
:assigned_to_id => user.id,
:blocks_ids => feature.id.to_s,
:status_id => status1.id,
:fixed_version_id => version.id},
project.id)
@impediment = Impediment.create_with_relationships({ subject: @impediment_subject,
assigned_to_id: user.id,
blocks_ids: feature.id.to_s,
status_id: status1.id,
fixed_version_id: version.id },
project.id)
end
it_should_behave_like "impediment creation with 1 blocking relationship"
it_should_behave_like 'impediment creation with 1 blocking relationship'
it { expect(@impediment).not_to be_new_record }
it { expect(@impediment.relations_from[0]).not_to be_new_record }
end
describe "WITH the story having another version" do
describe 'WITH the story having another version' do
before(:each) do
feature.fixed_version = FactoryGirl.create(:version, :project => project, :name => "another version")
feature.fixed_version = FactoryGirl.create(:version, project: project, name: 'another version')
feature.save
@impediment = Impediment.create_with_relationships({:subject => @impediment_subject,
:assigned_to_id => user.id,
:blocks_ids => feature.id.to_s,
:status_id => status1.id,
:fixed_version_id => version.id},
project.id)
@impediment = Impediment.create_with_relationships({ subject: @impediment_subject,
assigned_to_id: user.id,
blocks_ids: feature.id.to_s,
status_id: status1.id,
fixed_version_id: version.id },
project.id)
end
it_should_behave_like "impediment creation with no blocking relationship"
it_should_behave_like 'impediment creation with no blocking relationship'
it { expect(@impediment).to be_new_record }
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:can_only_contain_work_packages_of_current_sprint, :scope => [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:can_only_contain_work_packages_of_current_sprint, scope: [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
end
describe "WITH the story being non existent" do
describe 'WITH the story being non existent' do
before(:each) do
@impediment = Impediment.create_with_relationships({:subject => @impediment_subject,
:assigned_to_id => user.id,
:blocks_ids => "0",
:status_id => status1.id,
:fixed_version_id => version.id},
project.id)
@impediment = Impediment.create_with_relationships({ subject: @impediment_subject,
assigned_to_id: user.id,
blocks_ids: '0',
status_id: status1.id,
fixed_version_id: version.id },
project.id)
end
it_should_behave_like "impediment creation with no blocking relationship"
it_should_behave_like 'impediment creation with no blocking relationship'
it { expect(@impediment).to be_new_record }
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:can_only_contain_work_packages_of_current_sprint, :scope => [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:can_only_contain_work_packages_of_current_sprint, scope: [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
end
end
describe "WITHOUT a blocking relationship defined" do
describe 'WITHOUT a blocking relationship defined' do
before(:each) do
@impediment = Impediment.create_with_relationships({:subject => @impediment_subject,
:assigned_to_id => user.id,
:blocks_ids => "",
:status_id => status1.id,
:fixed_version_id => version.id},
project.id)
@impediment = Impediment.create_with_relationships({ subject: @impediment_subject,
assigned_to_id: user.id,
blocks_ids: '',
status_id: status1.id,
fixed_version_id: version.id },
project.id)
end
it_should_behave_like "impediment creation with no blocking relationship"
it_should_behave_like 'impediment creation with no blocking relationship'
it { expect(@impediment).to be_new_record }
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:must_block_at_least_one_work_package, :scope => [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:must_block_at_least_one_work_package, scope: [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
end
end
end
describe "instance methods" do
describe 'instance methods' do
describe '#update_with_relationships' do
before(:each) do
role.permissions = [:update_impediments]
@ -207,133 +214,133 @@ describe Impediment, :type => :model do
@impediment.save
end
shared_examples_for "impediment update" do
shared_examples_for 'impediment update' do
it { expect(@impediment.author).to eql user }
it { expect(@impediment.project).to eql project }
it { expect(@impediment.fixed_version).to eql version }
it { expect(@impediment.priority).to eql issue_priority}
it { expect(@impediment.priority).to eql issue_priority }
it { expect(@impediment.status).to eql status1 }
it { expect(@impediment.type).to eql type_task }
it { expect(@impediment.blocks_ids).to eql @blocks.split(/\D+/).map{|id| id.to_i} }
it { expect(@impediment.blocks_ids).to eql @blocks.split(/\D+/).map(&:to_i) }
end
shared_examples_for "impediment update with changed blocking relationship" do
it_should_behave_like "impediment update"
shared_examples_for 'impediment update with changed blocking relationship' do
it_should_behave_like 'impediment update'
it { expect(@impediment.relations_from.size).to eq(1) }
it { expect(@impediment.relations_from[0]).not_to be_new_record }
it { expect(@impediment.relations_from[0].to).to eql @story }
it { expect(@impediment.relations_from[0].relation_type).to eql Relation::TYPE_BLOCKS }
end
shared_examples_for "impediment update with unchanged blocking relationship" do
it_should_behave_like "impediment update"
shared_examples_for 'impediment update with unchanged blocking relationship' do
it_should_behave_like 'impediment update'
it { expect(@impediment.relations_from.size).to eq(1) }
it { expect(@impediment.relations_from[0]).not_to be_changed }
it { expect(@impediment.relations_from[0].to).to eql feature }
it { expect(@impediment.relations_from[0].relation_type).to eql Relation::TYPE_BLOCKS }
end
describe "WHEN changing the blocking relationship to another story" do
describe 'WHEN changing the blocking relationship to another story' do
before(:each) do
@story = FactoryGirl.build(:work_package, :subject => "another story",
:type => type_feature,
:project => project,
:author => user,
:priority => issue_priority,
:status => status1)
@story = FactoryGirl.build(:work_package, subject: 'another story',
type: type_feature,
project: project,
author: user,
priority: issue_priority,
status: status1)
end
describe "WITH the story having the same version" do
describe 'WITH the story having the same version' do
before(:each) do
@story.fixed_version = version
@story.save
@blocks = @story.id.to_s
@impediment.update_with_relationships({:blocks_ids => @blocks,
:status_id => status1.id.to_s})
@impediment.update_with_relationships({ blocks_ids: @blocks,
status_id: status1.id.to_s })
end
it_should_behave_like "impediment update with changed blocking relationship"
it_should_behave_like 'impediment update with changed blocking relationship'
it { expect(@impediment).not_to be_changed }
end
describe "WITH the story having another version" do
describe 'WITH the story having another version' do
before(:each) do
@story.fixed_version = FactoryGirl.create(:version, :project => project, :name => "another version")
@story.fixed_version = FactoryGirl.create(:version, project: project, name: 'another version')
@story.save
@blocks = @story.id.to_s
@saved = @impediment.update_with_relationships({:blocks_ids => @blocks,
:status_id => status1.id.to_s})
@saved = @impediment.update_with_relationships({ blocks_ids: @blocks,
status_id: status1.id.to_s })
end
it_should_behave_like "impediment update with unchanged blocking relationship"
it "should not be saved successfully" do
it_should_behave_like 'impediment update with unchanged blocking relationship'
it 'should not be saved successfully' do
expect(@saved).to be_falsey
end
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:can_only_contain_work_packages_of_current_sprint, :scope => [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:can_only_contain_work_packages_of_current_sprint, scope: [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
end
describe "WITH the story beeing non existent" do
describe 'WITH the story beeing non existent' do
before(:each) do
@blocks = "0"
@saved = @impediment.update_with_relationships({:blocks_ids => @blocks,
:status_id => status1.id.to_s})
@blocks = '0'
@saved = @impediment.update_with_relationships({ blocks_ids: @blocks,
status_id: status1.id.to_s })
end
it_should_behave_like "impediment update with unchanged blocking relationship"
it "should not be saved successfully" do
it_should_behave_like 'impediment update with unchanged blocking relationship'
it 'should not be saved successfully' do
expect(@saved).to be_falsey
end
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:can_only_contain_work_packages_of_current_sprint, :scope => [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:can_only_contain_work_packages_of_current_sprint, scope: [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
end
end
describe "WITHOUT a blocking relationship defined" do
describe 'WITHOUT a blocking relationship defined' do
before(:each) do
@blocks = ""
@saved = @impediment.update_with_relationships({:blocks_ids => @blocks,
:status_id => status1.id.to_s})
@blocks = ''
@saved = @impediment.update_with_relationships({ blocks_ids: @blocks,
status_id: status1.id.to_s })
end
it_should_behave_like "impediment update with unchanged blocking relationship"
it "should not be saved successfully" do
it_should_behave_like 'impediment update with unchanged blocking relationship'
it 'should not be saved successfully' do
expect(@saved).to be_falsey
end
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:must_block_at_least_one_work_package, :scope => [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
it { expect(@impediment.errors[:blocks_ids]).to include I18n.t(:must_block_at_least_one_work_package, scope: [:activerecord, :errors, :models, :work_package, :attributes, :blocks_ids]) }
end
end
describe "blocks_ids=/blocks_ids" do
describe "WITH an integer" do
describe 'blocks_ids=/blocks_ids' do
describe 'WITH an integer' do
it do
impediment.blocks_ids = 2
expect(impediment.blocks_ids).to eql [2]
end
end
describe "WITH a string" do
describe 'WITH a string' do
it do
impediment.blocks_ids = "1, 2, 3"
expect(impediment.blocks_ids).to eql [1,2,3]
impediment.blocks_ids = '1, 2, 3'
expect(impediment.blocks_ids).to eql [1, 2, 3]
end
end
describe "WITH an array" do
describe 'WITH an array' do
it do
impediment.blocks_ids = [1,2,3]
expect(impediment.blocks_ids).to eql [1,2,3]
impediment.blocks_ids = [1, 2, 3]
expect(impediment.blocks_ids).to eql [1, 2, 3]
end
end
describe "WITH only prior blockers defined" do
describe 'WITH only prior blockers defined' do
before(:each) do
feature.fixed_version = version
feature.save
task.fixed_version = version
task.save
impediment.relations_from = [Relation.new(:from => impediment, :to => feature, :relation_type => Relation::TYPE_BLOCKS),
Relation.new(:from => impediment, :to => task, :relation_type => Relation::TYPE_BLOCKS)]
impediment.relations_from = [Relation.new(from: impediment, to: feature, relation_type: Relation::TYPE_BLOCKS),
Relation.new(from: impediment, to: task, relation_type: Relation::TYPE_BLOCKS)]
true
end

@ -44,146 +44,163 @@ describe WorkPackage, "changing a story's fixed_version changes the fixed_versio
let(:role) { FactoryGirl.build(:role) }
let(:user) { FactoryGirl.build(:user) }
let(:issue_priority) { FactoryGirl.build(:priority) }
let(:status) { FactoryGirl.build(:status, :name => "status 1", :is_default => true) }
let(:status) { FactoryGirl.build(:status, name: 'status 1', is_default: true) }
let(:project) do
p = FactoryGirl.build(:project, :members => [FactoryGirl.build(:member,
:principal => user,
:roles => [role])],
:types => [type_feature, type_task, type_bug])
p = FactoryGirl.build(:project, members: [FactoryGirl.build(:member,
principal: user,
roles: [role])],
types: [type_feature, type_task, type_bug])
p.versions << FactoryGirl.build(:version, :name => "Version1", :project => p)
p.versions << FactoryGirl.build(:version, :name => "Version2", :project => p)
p.versions << FactoryGirl.build(:version, name: 'Version1', project: p)
p.versions << FactoryGirl.build(:version, name: 'Version2', project: p)
p
end
let(:story) do
story = FactoryGirl.build(:work_package,
:subject => "Story",
:project => project,
:type => type_feature,
:fixed_version => version1,
:status => status,
:author => user,
:priority => issue_priority)
subject: 'Story',
project: project,
type: type_feature,
fixed_version: version1,
status: status,
author: user,
priority: issue_priority)
story
end
let(:story2) do
story = FactoryGirl.build(:work_package,
:subject => "Story2",
:project => project,
:type => type_feature,
:fixed_version => version1,
:status => status,
:author => user,
:priority => issue_priority)
subject: 'Story2',
project: project,
type: type_feature,
fixed_version: version1,
status: status,
author: user,
priority: issue_priority)
story
end
let(:story3) do
story = FactoryGirl.build(:work_package,
:subject => "Story3",
:project => project,
:type => type_feature,
:fixed_version => version1,
:status => status,
:author => user,
:priority => issue_priority)
subject: 'Story3',
project: project,
type: type_feature,
fixed_version: version1,
status: status,
author: user,
priority: issue_priority)
story
end
let(:task) { FactoryGirl.build(:work_package,
:subject => "Task",
:type => type_task,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:task2) { FactoryGirl.build(:work_package,
:subject => "Task2",
:type => type_task,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:task3) { FactoryGirl.build(:work_package,
:subject => "Task3",
:type => type_task,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:task4) { FactoryGirl.build(:work_package,
:subject => "Task4",
:type => type_task,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:task5) { FactoryGirl.build(:work_package,
:subject => "Task5",
:type => type_task,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:task6) { FactoryGirl.build(:work_package,
:subject => "Task6",
:type => type_task,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:bug) { FactoryGirl.build(:work_package,
:subject => "Bug",
:type => type_bug,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:bug2) { FactoryGirl.build(:work_package,
:subject => "Bug2",
:type => type_bug,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:bug3) { FactoryGirl.build(:work_package,
:subject => "Bug3",
:type => type_bug,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:task) {
FactoryGirl.build(:work_package,
subject: 'Task',
type: type_task,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
let(:task2) {
FactoryGirl.build(:work_package,
subject: 'Task2',
type: type_task,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
let(:task3) {
FactoryGirl.build(:work_package,
subject: 'Task3',
type: type_task,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
let(:task4) {
FactoryGirl.build(:work_package,
subject: 'Task4',
type: type_task,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
let(:task5) {
FactoryGirl.build(:work_package,
subject: 'Task5',
type: type_task,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
let(:task6) {
FactoryGirl.build(:work_package,
subject: 'Task6',
type: type_task,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
let(:bug) {
FactoryGirl.build(:work_package,
subject: 'Bug',
type: type_bug,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
let(:bug2) {
FactoryGirl.build(:work_package,
subject: 'Bug2',
type: type_bug,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
let(:bug3) {
FactoryGirl.build(:work_package,
subject: 'Bug3',
type: type_bug,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
before(:each) do
project.save!
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"points_burn_direction" => "down",
"wiki_template" => "",
"card_spec" => "Sattleford VM-5040",
"story_types" => [type_feature.id],
"task_type" => type_task.id.to_s})
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'points_burn_direction' => 'down',
'wiki_template' => '',
'card_spec' => 'Sattleford VM-5040',
'story_types' => [type_feature.id],
'task_type' => type_task.id.to_s })
end
def standard_child_layout
@ -212,11 +229,8 @@ describe WorkPackage, "changing a story's fixed_version changes the fixed_versio
child.reload
end
describe "WHEN changing fixed_version" do
describe 'WHEN changing fixed_version' do
shared_examples_for "changing parent's fixed_version changes child's fixed version" do
it "SHOULD change the child's fixed version to the parent's fixed version" do
subject.save!
child.parent_id = subject.id
@ -241,7 +255,6 @@ describe WorkPackage, "changing a story's fixed_version changes the fixed_versio
end
shared_examples_for "changing parent's fixed_version does not change child's fixed_version" do
it "SHOULD keep the child's version" do
subject.save!
child.parent_id = subject.id
@ -265,65 +278,65 @@ describe WorkPackage, "changing a story's fixed_version changes the fixed_versio
end
end
describe "WITH backlogs enabled" do
describe 'WITH backlogs enabled' do
before(:each) do
project.enabled_module_names += ["backlogs"]
project.enabled_module_names += ['backlogs']
end
describe "WITH a story" do
describe 'WITH a story' do
subject { story }
describe "WITH a task as child" do
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "changing parent's fixed_version changes child's fixed version"
end
describe "WITH a non backlogs work_package as child" do
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
describe "WITH a story as a child" do
describe 'WITH a story as a child' do
let(:child) { story2 }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
end
describe "WITH a task (impediment) without a parent" do
describe 'WITH a task (impediment) without a parent' do
subject { task }
describe "WITH a task as child" do
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "changing parent's fixed_version changes child's fixed version"
end
describe "WITH a non backlogs work_package as child" do
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
end
describe "WITH a non backlogs work_package" do
describe 'WITH a non backlogs work_package' do
subject { bug }
describe "WITH a task as child" do
describe 'WITH a task as child' do
let(:child) { task }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
describe "WITH a non backlogs work_package as child" do
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
describe "WITH a story as a child" do
describe 'WITH a story as a child' do
let(:child) { story }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
@ -331,34 +344,34 @@ describe WorkPackage, "changing a story's fixed_version changes the fixed_versio
end
end
describe "WITH backlogs disabled" do
describe 'WITH backlogs disabled' do
before(:each) do
project.enabled_module_names = project.enabled_module_names.find_all{|n| n != "backlogs" }
project.enabled_module_names = project.enabled_module_names.find_all { |n| n != 'backlogs' }
end
describe "WITH a story" do
describe 'WITH a story' do
subject { story }
describe "WITH a task as child" do
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
describe "WITH a non backlogs work_package as child" do
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
describe "WITH a story as a child" do
describe 'WITH a story as a child' do
let(:child) { story2 }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
end
describe "WITH a task" do
describe 'WITH a task' do
before(:each) do
bug2.save!
task.parent_id = bug2.id # so that it is considered a task
@ -367,51 +380,51 @@ describe WorkPackage, "changing a story's fixed_version changes the fixed_versio
subject { task }
describe "WITH a task as child" do
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
describe "WITH a non backlogs work_package as child" do
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
end
describe "WITH a task (impediment) without a parent" do
describe 'WITH a task (impediment) without a parent' do
subject { task }
describe "WITH a task as child" do
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
describe "WITH a non backlogs work_package as child" do
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
end
describe "WITH a non backlogs work_package" do
describe 'WITH a non backlogs work_package' do
subject { bug }
describe "WITH a task as child" do
describe 'WITH a task as child' do
let(:child) { task }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
describe "WITH a non backlogs work_package as child" do
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
end
describe "WITH a story as a child" do
describe 'WITH a story as a child' do
let(:child) { story }
it_should_behave_like "changing parent's fixed_version does not change child's fixed_version"
@ -420,9 +433,8 @@ describe WorkPackage, "changing a story's fixed_version changes the fixed_versio
end
end
describe "WHEN changing the parent_id" do
describe 'WHEN changing the parent_id' do
shared_examples_for "changing the child's parent_issue to the parent changes child's fixed version" do
it "SHOULD change the child's fixed version to the parent's fixed version" do
child.save!
standard_child_layout
@ -444,7 +456,6 @@ describe WorkPackage, "changing a story's fixed_version changes the fixed_versio
end
shared_examples_for "changing the child's parent to the parent leaves child's fixed version" do
it "SHOULD keep the child's version" do
child.save!
standard_child_layout
@ -465,27 +476,27 @@ describe WorkPackage, "changing a story's fixed_version changes the fixed_versio
end
end
describe "WITH backogs enabled" do
describe 'WITH backogs enabled' do
before(:each) do
story.project.enabled_module_names += ["backlogs"]
story.project.enabled_module_names += ['backlogs']
end
describe "WITH a story as parent" do
describe 'WITH a story as parent' do
let(:parent) { story }
describe "WITH a story as child" do
describe 'WITH a story as child' do
let(:child) { story2 }
it_should_behave_like "changing the child's parent to the parent leaves child's fixed version"
end
describe "WITH a task as child" do
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "changing the child's parent_issue to the parent changes child's fixed version"
end
describe "WITH a non-backlogs work_package as child" do
describe 'WITH a non-backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "changing the child's parent to the parent leaves child's fixed version"
@ -507,7 +518,7 @@ describe WorkPackage, "changing a story's fixed_version changes the fixed_versio
it_should_behave_like "changing the child's parent_issue to the parent changes child's fixed version"
end
describe "WITH a task as parent" do
describe 'WITH a task as parent' do
before(:each) do
story.save!
task.parent_id = story.id
@ -520,51 +531,51 @@ describe WorkPackage, "changing a story's fixed_version changes the fixed_versio
# 'fixed_version_id'
let(:parent) { story }
describe "WITH a task as child" do
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "changing the child's parent_issue to the parent changes child's fixed version"
end
describe "WITH a non-backlogs work_package as child" do
describe 'WITH a non-backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "changing the child's parent to the parent leaves child's fixed version"
end
end
describe "WITH an impediment (task) as parent" do
describe 'WITH an impediment (task) as parent' do
let(:parent) { task }
describe "WITH a task as child" do
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "changing the child's parent_issue to the parent changes child's fixed version"
end
describe "WITH a non-backlogs work_package as child" do
describe 'WITH a non-backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "changing the child's parent to the parent leaves child's fixed version"
end
end
describe "WITH a non-backlogs work_package as parent" do
describe 'WITH a non-backlogs work_package as parent' do
let(:parent) { bug }
describe "WITH a story as child" do
describe 'WITH a story as child' do
let(:child) { story2 }
it_should_behave_like "changing the child's parent to the parent leaves child's fixed version"
end
describe "WITH a task as child" do
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "changing the child's parent to the parent leaves child's fixed version"
end
describe "WITH a non-backlogs work_package as child" do
describe 'WITH a non-backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "changing the child's parent to the parent leaves child's fixed version"

@ -44,86 +44,91 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
let(:role) { FactoryGirl.build(:role) }
let(:user) { FactoryGirl.build(:user) }
let(:issue_priority) { FactoryGirl.build(:priority) }
let(:status) { FactoryGirl.build(:status, :name => "status 1", :is_default => true) }
let(:status) { FactoryGirl.build(:status, name: 'status 1', is_default: true) }
let(:project) do
p = FactoryGirl.build(:project, :members => [FactoryGirl.build(:member,
:principal => user,
:roles => [role])],
:types => [type_feature, type_task, type_bug])
p = FactoryGirl.build(:project, members: [FactoryGirl.build(:member,
principal: user,
roles: [role])],
types: [type_feature, type_task, type_bug])
p.versions << FactoryGirl.build(:version, :name => "Version1", :project => p)
p.versions << FactoryGirl.build(:version, :name => "Version2", :project => p)
p.versions << FactoryGirl.build(:version, name: 'Version1', project: p)
p.versions << FactoryGirl.build(:version, name: 'Version2', project: p)
p
end
let(:story) do
story = FactoryGirl.build(:work_package,
:subject => "Story",
:project => project,
:type => type_feature,
:fixed_version => version1,
:status => status,
:author => user,
:priority => issue_priority)
story.project.enabled_module_names += ["backlogs"]
subject: 'Story',
project: project,
type: type_feature,
fixed_version: version1,
status: status,
author: user,
priority: issue_priority)
story.project.enabled_module_names += ['backlogs']
story
end
let(:story2) do
story = FactoryGirl.build(:work_package,
:subject => "Story2",
:project => project,
:type => type_feature,
:fixed_version => version1,
:status => status,
:author => user,
:priority => issue_priority)
story.project.enabled_module_names += ["backlogs"]
subject: 'Story2',
project: project,
type: type_feature,
fixed_version: version1,
status: status,
author: user,
priority: issue_priority)
story.project.enabled_module_names += ['backlogs']
story
end
let(:task) { FactoryGirl.build(:work_package,
:subject => "Task",
:type => type_task,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:task2) { FactoryGirl.build(:work_package,
:subject => "Task2",
:type => type_task,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:bug) { FactoryGirl.build(:work_package,
:subject => "Bug",
:type => type_bug,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
let(:bug2) { FactoryGirl.build(:work_package,
:subject => "Bug2",
:type => type_bug,
:fixed_version => version1,
:project => project,
:status => status,
:author => user,
:priority => issue_priority) }
shared_examples_for "fixed version beeing inherited from the parent" do
let(:task) {
FactoryGirl.build(:work_package,
subject: 'Task',
type: type_task,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
let(:task2) {
FactoryGirl.build(:work_package,
subject: 'Task2',
type: type_task,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
let(:bug) {
FactoryGirl.build(:work_package,
subject: 'Bug',
type: type_bug,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
let(:bug2) {
FactoryGirl.build(:work_package,
subject: 'Bug2',
type: type_bug,
fixed_version: version1,
project: project,
status: status,
author: user,
priority: issue_priority)
}
shared_examples_for 'fixed version beeing inherited from the parent' do
before(:each) do
parent.save!
subject.parent_id = parent.id unless subject.parent_id.present?
@ -131,7 +136,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
parent.reload
end
describe "WITHOUT a fixed version and the parent also having no fixed version" do
describe 'WITHOUT a fixed version and the parent also having no fixed version' do
before(:each) do
parent.fixed_version = nil
parent.save!
@ -143,7 +148,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
it { expect(subject.reload.fixed_version).to be_nil }
end
describe "WITHOUT a fixed version and the parent having a fixed version" do
describe 'WITHOUT a fixed version and the parent having a fixed version' do
before(:each) do
parent.fixed_version = version1
parent.save!
@ -154,7 +159,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
it { expect(subject.reload.fixed_version).to eql version1 }
end
describe "WITH a fixed version and the parent having a different fixed version" do
describe 'WITH a fixed version and the parent having a different fixed version' do
before(:each) do
parent.fixed_version = version1
parent.save!
@ -165,7 +170,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
it { expect(subject.reload.fixed_version).to eql version1 }
end
describe "WITH a fixed version and the parent having the same fixed version" do
describe 'WITH a fixed version and the parent having the same fixed version' do
before(:each) do
parent.fixed_version = version1
parent.save!
@ -176,7 +181,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
it { expect(subject.reload.fixed_version).to eql version1 }
end
describe "WITH a fixed version and the parent having no fixed version" do
describe 'WITH a fixed version and the parent having no fixed version' do
before(:each) do
parent.fixed_version = nil
parent.save!
@ -189,8 +194,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
end
end
shared_examples_for "fixed version not beeing inherited from the parent" do
shared_examples_for 'fixed version not beeing inherited from the parent' do
before(:each) do
parent.save!
subject.parent_id = parent.id unless subject.parent_id.present?
@ -198,7 +202,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
parent.reload
end
describe "WITHOUT a fixed version and the parent also having no fixed version" do
describe 'WITHOUT a fixed version and the parent also having no fixed version' do
before(:each) do
parent.fixed_version = nil
parent.save!
@ -210,7 +214,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
it { expect(subject.reload.fixed_version).to be_nil }
end
describe "WITHOUT a fixed version and the parent having a fixed version" do
describe 'WITHOUT a fixed version and the parent having a fixed version' do
before(:each) do
parent.fixed_version = version1
parent.save!
@ -221,7 +225,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
it { expect(subject.reload.fixed_version).to be_nil }
end
describe "WITH a fixed version and the parent having a different fixed version" do
describe 'WITH a fixed version and the parent having a different fixed version' do
before(:each) do
parent.fixed_version = version1
parent.save!
@ -232,7 +236,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
it { expect(subject.reload.fixed_version).to eql version2 }
end
describe "WITH a fixed version and the parent having the same fixed version" do
describe 'WITH a fixed version and the parent having the same fixed version' do
before(:each) do
parent.fixed_version = version1
parent.save!
@ -243,7 +247,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
it { expect(subject.reload.fixed_version).to eql version1 }
end
describe "WITH a fixed version and the parent having no fixed version" do
describe 'WITH a fixed version and the parent having no fixed version' do
before(:each) do
parent.fixed_version = nil
parent.save!
@ -256,8 +260,8 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
end
end
shared_examples_for "fixed version without restriction" do
describe "WITHOUT a fixed version" do
shared_examples_for 'fixed version without restriction' do
describe 'WITHOUT a fixed version' do
before(:each) do
subject.fixed_version = nil
subject.save!
@ -266,7 +270,7 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
it { expect(subject.reload.fixed_version).to be_nil }
end
describe "WITH a fixed version" do
describe 'WITH a fixed version' do
before(:each) do
subject.fixed_version = version1
subject.save!
@ -279,38 +283,38 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
before(:each) do
project.save!
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"points_burn_direction" => "down",
"wiki_template" => "",
"card_spec" => "Sattleford VM-5040",
"story_types" => [type_feature.id],
"task_type" => type_task.id.to_s})
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'points_burn_direction' => 'down',
'wiki_template' => '',
'card_spec' => 'Sattleford VM-5040',
'story_types' => [type_feature.id],
'task_type' => type_task.id.to_s })
end
describe "WITH a story" do
describe 'WITH a story' do
subject { story }
describe "WITHOUT a parent work_package" do
it_should_behave_like "fixed version without restriction"
describe 'WITHOUT a parent work_package' do
it_should_behave_like 'fixed version without restriction'
end
describe "WITH a story as it's parent" do
let(:parent) { story2 }
it_should_behave_like "fixed version not beeing inherited from the parent"
it_should_behave_like 'fixed version not beeing inherited from the parent'
end
describe "WITH a non backlogs tracked work_package as it's parent" do
let(:parent) { bug }
it_should_behave_like "fixed version not beeing inherited from the parent"
it_should_behave_like 'fixed version not beeing inherited from the parent'
end
end
describe "WITH a task" do
describe 'WITH a task' do
subject { task }
describe "WITHOUT a parent work_package (would then be an impediment)" do
it_should_behave_like "fixed version without restriction"
describe 'WITHOUT a parent work_package (would then be an impediment)' do
it_should_behave_like 'fixed version without restriction'
end
describe "WITH a task as it's parent" do
@ -328,45 +332,45 @@ describe WorkPackage, "fixed version restricted by an work_package parents (if i
# It's actually the grandparent but it makes no difference for the test
let(:parent) { story }
it_should_behave_like "fixed version beeing inherited from the parent"
it_should_behave_like 'fixed version beeing inherited from the parent'
end
describe "WITH a story as it's parent" do
let(:parent) { story }
it_should_behave_like "fixed version beeing inherited from the parent"
it_should_behave_like 'fixed version beeing inherited from the parent'
end
describe "WITH a non backlogs tracked work_package as it's parent" do
let(:parent) { bug }
it_should_behave_like "fixed version not beeing inherited from the parent"
it_should_behave_like 'fixed version not beeing inherited from the parent'
end
end
describe "WITH a non backlogs work_package" do
describe 'WITH a non backlogs work_package' do
subject { bug }
describe "WITHOUT a parent work_package" do
it_should_behave_like "fixed version without restriction"
describe 'WITHOUT a parent work_package' do
it_should_behave_like 'fixed version without restriction'
end
describe "WITH a task as it's parent" do
let(:parent) { task2 }
it_should_behave_like "fixed version not beeing inherited from the parent"
it_should_behave_like 'fixed version not beeing inherited from the parent'
end
describe "WITH a story as it's parent" do
let(:parent) { story }
it_should_behave_like "fixed version not beeing inherited from the parent"
it_should_behave_like 'fixed version not beeing inherited from the parent'
end
describe "WITH a non backlogs tracked work_package as it's parent" do
let(:parent) { bug2 }
it_should_behave_like "fixed version not beeing inherited from the parent"
it_should_behave_like 'fixed version not beeing inherited from the parent'
end
end
end

@ -54,357 +54,368 @@ describe WorkPackage, 'parent-child relationships between backlogs stories and b
let(:role) { FactoryGirl.build(:role) }
let(:user) { FactoryGirl.build(:user) }
let(:issue_priority) { FactoryGirl.build(:priority) }
let(:status) { FactoryGirl.build(:status, :name => "status 1", :is_default => true) }
let(:status) { FactoryGirl.build(:status, name: 'status 1', is_default: true) }
let(:parent_project) do
p = FactoryGirl.build(:project, :name => "parent_project",
:members => [FactoryGirl.build(:member,
:principal => user,
:roles => [role])],
:types => [type_feature, type_task, type_bug])
p = FactoryGirl.build(:project, name: 'parent_project',
members: [FactoryGirl.build(:member,
principal: user,
roles: [role])],
types: [type_feature, type_task, type_bug])
p.versions << FactoryGirl.build(:version, :name => "Version1", :project => p)
p.versions << FactoryGirl.build(:version, :name => "Version2", :project => p)
p.versions << FactoryGirl.build(:version, name: 'Version1', project: p)
p.versions << FactoryGirl.build(:version, name: 'Version2', project: p)
p
end
let(:child_project) do
p = FactoryGirl.build(:project, :name => "child_project",
:members => [FactoryGirl.build(:member,
:principal => user,
:roles => [role])],
:types => [type_feature, type_task, type_bug])
p = FactoryGirl.build(:project, name: 'child_project',
members: [FactoryGirl.build(:member,
principal: user,
roles: [role])],
types: [type_feature, type_task, type_bug])
p.versions << FactoryGirl.build(:version, :name => "Version1", :project => p)
p.versions << FactoryGirl.build(:version, :name => "Version2", :project => p)
p.versions << FactoryGirl.build(:version, name: 'Version1', project: p)
p.versions << FactoryGirl.build(:version, name: 'Version2', project: p)
p
end
let(:story) { FactoryGirl.build(:work_package,
:subject => "Story",
:type => type_feature,
:status => status,
:author => user,
:priority => issue_priority) }
let(:story2) { FactoryGirl.build(:work_package,
:subject => "Story2",
:type => type_feature,
:status => status,
:author => user,
:priority => issue_priority) }
let(:task) { FactoryGirl.build(:work_package,
:subject => "Task",
:type => type_task,
:status => status,
:author => user,
:priority => issue_priority) }
let(:task2) { FactoryGirl.build(:work_package,
:subject => "Task2",
:type => type_task,
:status => status,
:author => user,
:priority => issue_priority) }
let(:bug) { FactoryGirl.build(:work_package,
:subject => "Bug",
:type => type_bug,
:status => status,
:author => user,
:priority => issue_priority) }
let(:bug2) { FactoryGirl.build(:work_package,
:subject => "Bug2",
:type => type_bug,
:status => status,
:author => user,
:priority => issue_priority) }
let(:story) {
FactoryGirl.build(:work_package,
subject: 'Story',
type: type_feature,
status: status,
author: user,
priority: issue_priority)
}
let(:story2) {
FactoryGirl.build(:work_package,
subject: 'Story2',
type: type_feature,
status: status,
author: user,
priority: issue_priority)
}
let(:task) {
FactoryGirl.build(:work_package,
subject: 'Task',
type: type_task,
status: status,
author: user,
priority: issue_priority)
}
let(:task2) {
FactoryGirl.build(:work_package,
subject: 'Task2',
type: type_task,
status: status,
author: user,
priority: issue_priority)
}
let(:bug) {
FactoryGirl.build(:work_package,
subject: 'Bug',
type: type_bug,
status: status,
author: user,
priority: issue_priority)
}
let(:bug2) {
FactoryGirl.build(:work_package,
subject: 'Bug2',
type: type_bug,
status: status,
author: user,
priority: issue_priority)
}
before do
allow(Setting).to receive(:cross_project_work_package_relations).and_return("1")
allow(Setting).to receive(:cross_project_work_package_relations).and_return('1')
end
before(:each) do
parent_project.save!
child_project.save!
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"points_burn_direction" => "down",
"wiki_template" => "",
"card_spec" => "Sattleford VM-5040",
"story_types" => [type_feature.id],
"task_type" => type_task.id.to_s})
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'points_burn_direction' => 'down',
'wiki_template' => '',
'card_spec' => 'Sattleford VM-5040',
'story_types' => [type_feature.id],
'task_type' => type_task.id.to_s })
end
if project_boundaries_spanning_work_package_hierarchy_allowed?
describe "WHEN creating the child" do
shared_examples_for "restricted hierarchy on creation" do
before(:each) do
parent.project = parent_project
parent.save
child.parent_id = parent.id
end
describe "WITH the child in a different project" do
describe 'WHEN creating the child' do
shared_examples_for 'restricted hierarchy on creation' do
before(:each) do
child.project = child_project
parent.project = parent_project
parent.save
child.parent_id = parent.id
end
it { expect(child).not_to be_valid }
end
describe 'WITH the child in a different project' do
before(:each) do
child.project = child_project
end
describe "WITH the child in the same project" do
before(:each) do
child.project = parent_project
it { expect(child).not_to be_valid }
end
it { expect(child).to be_valid }
end
end
describe 'WITH the child in the same project' do
before(:each) do
child.project = parent_project
end
shared_examples_for "unrestricted hierarchy on creation" do
before(:each) do
parent.project = parent_project
parent.save
child.parent_id = parent.id
it { expect(child).to be_valid }
end
end
describe "WITH the child in a different project" do
shared_examples_for 'unrestricted hierarchy on creation' do
before(:each) do
child.project = child_project
parent.project = parent_project
parent.save
child.parent_id = parent.id
end
it { expect(child).to be_valid }
end
describe 'WITH the child in a different project' do
before(:each) do
child.project = child_project
end
describe "WITH the child in the same project" do
before(:each) do
child.project = parent_project
it { expect(child).to be_valid }
end
it { expect(child).to be_valid }
describe 'WITH the child in the same project' do
before(:each) do
child.project = parent_project
end
it { expect(child).to be_valid }
end
end
end
describe "WITH backlogs enabled in both projects" do
describe "WITH a story as parent" do
let(:parent) { story }
describe 'WITH backlogs enabled in both projects' do
describe 'WITH a story as parent' do
let(:parent) { story }
describe "WITH a task as child" do
let(:child) { task2 }
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "restricted hierarchy on creation"
end
it_should_behave_like 'restricted hierarchy on creation'
end
describe "WITH a non backlogs work_package as child" do
let(:child) { bug2 }
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "unrestricted hierarchy on creation"
end
it_should_behave_like 'unrestricted hierarchy on creation'
end
describe "WITH a story as child" do
let(:child) { story2 }
describe 'WITH a story as child' do
let(:child) { story2 }
it_should_behave_like "unrestricted hierarchy on creation"
it_should_behave_like 'unrestricted hierarchy on creation'
end
end
end
describe "WITH a task as parent (with or without parent does not matter)" do
let(:parent) { task }
describe 'WITH a task as parent (with or without parent does not matter)' do
let(:parent) { task }
describe "WITH a task as child" do
let(:child) { task2 }
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "restricted hierarchy on creation"
end
it_should_behave_like 'restricted hierarchy on creation'
end
describe "WITH a non backlogs work_package as child" do
let(:child) { bug2 }
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "unrestricted hierarchy on creation"
end
it_should_behave_like 'unrestricted hierarchy on creation'
end
describe "WITH a story as child" do
let(:child) { story2 }
describe 'WITH a story as child' do
let(:child) { story2 }
it_should_behave_like "unrestricted hierarchy on creation"
it_should_behave_like 'unrestricted hierarchy on creation'
end
end
end
describe "WITH a non backlogs work_package as parent" do
let(:parent) { bug }
describe 'WITH a non backlogs work_package as parent' do
let(:parent) { bug }
describe "WITH a task as child" do
let(:child) { task2 }
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "unrestricted hierarchy on creation"
end
it_should_behave_like 'unrestricted hierarchy on creation'
end
describe "WITH a non backlogs work_package as child" do
let(:child) { bug2 }
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "unrestricted hierarchy on creation"
end
it_should_behave_like 'unrestricted hierarchy on creation'
end
describe "WITH a story as child" do
let(:child) { story2 }
describe 'WITH a story as child' do
let(:child) { story2 }
it_should_behave_like "unrestricted hierarchy on creation"
it_should_behave_like 'unrestricted hierarchy on creation'
end
end
end
end
end
# This could happen when the project enables backlogs afterwards
describe "WITH an existing child" do
shared_examples_for "restricted hierarchy by enabling backlogs" do
before(:each) do
parent.project = parent_project
parent.save
child.parent_id = parent.id
end
describe "WITH the child in a different project" do
# This could happen when the project enables backlogs afterwards
describe 'WITH an existing child' do
shared_examples_for 'restricted hierarchy by enabling backlogs' do
before(:each) do
child_project.enabled_module_names = child_project.enabled_module_names.find_all{|n| n != "backlogs" }
child_project.save!
child.project = child_project
child_project.reload
child.save!
child_project.enabled_module_names = child_project.enabled_module_names + ["backlogs"]
child_project.save!
end
it { expect(child.reload).not_to be_valid }
it { expect(parent.reload).not_to be_valid }
end
parent.project = parent_project
parent.save
describe "WITH the child in the same project" do
before(:each) do
parent_project.enabled_module_names = parent_project.enabled_module_names.find_all{|n| n != "backlogs" }
parent_project.save!
parent_project.reload
child.project = parent_project
child.save!
parent_project.enabled_module_names = parent_project.enabled_module_names + ["backlogs"]
parent_project.save!
child.parent_id = parent.id
end
it { expect(child.reload).to be_valid }
it { expect(parent.reload).to be_valid }
end
end
shared_examples_for "unrestricted hierarchy even when enabling backlogs" do
before(:each) do
parent.project = parent_project
parent.save
describe 'WITH the child in a different project' do
before(:each) do
child_project.enabled_module_names = child_project.enabled_module_names.find_all { |n| n != 'backlogs' }
child_project.save!
child.project = child_project
child_project.reload
child.save!
child_project.enabled_module_names = child_project.enabled_module_names + ['backlogs']
child_project.save!
end
it { expect(child.reload).not_to be_valid }
it { expect(parent.reload).not_to be_valid }
end
child.parent_id = parent.id
describe 'WITH the child in the same project' do
before(:each) do
parent_project.enabled_module_names = parent_project.enabled_module_names.find_all { |n| n != 'backlogs' }
parent_project.save!
parent_project.reload
child.project = parent_project
child.save!
parent_project.enabled_module_names = parent_project.enabled_module_names + ['backlogs']
parent_project.save!
end
it { expect(child.reload).to be_valid }
it { expect(parent.reload).to be_valid }
end
end
describe "WITH the child in a different project" do
shared_examples_for 'unrestricted hierarchy even when enabling backlogs' do
before(:each) do
child_project.enabled_module_names = child_project.enabled_module_names.find_all{|n| n != "backlogs" }
child_project.save!
child.project = child_project
child.save!
child_project.enabled_module_names = child_project.enabled_module_names + ["backlogs"]
child_project.save!
end
parent.project = parent_project
parent.save
it { expect(child.reload).to be_valid }
it { expect(parent.reload).to be_valid }
end
child.parent_id = parent.id
end
describe "WITH the child in the same project" do
before(:each) do
parent_project.enabled_module_names = parent_project.enabled_module_names.find_all{|n| n != "backlogs" }
parent_project.save!
child.project = parent_project
child.save!
parent_project.enabled_module_names = parent_project.enabled_module_names + ["backlogs"]
parent_project.save!
describe 'WITH the child in a different project' do
before(:each) do
child_project.enabled_module_names = child_project.enabled_module_names.find_all { |n| n != 'backlogs' }
child_project.save!
child.project = child_project
child.save!
child_project.enabled_module_names = child_project.enabled_module_names + ['backlogs']
child_project.save!
end
it { expect(child.reload).to be_valid }
it { expect(parent.reload).to be_valid }
end
it { expect(child.reload).to be_valid }
it { expect(parent.reload).to be_valid }
describe 'WITH the child in the same project' do
before(:each) do
parent_project.enabled_module_names = parent_project.enabled_module_names.find_all { |n| n != 'backlogs' }
parent_project.save!
child.project = parent_project
child.save!
parent_project.enabled_module_names = parent_project.enabled_module_names + ['backlogs']
parent_project.save!
end
it { expect(child.reload).to be_valid }
it { expect(parent.reload).to be_valid }
end
end
end
describe "WITH a story as parent" do
let(:parent) { story }
describe 'WITH a story as parent' do
let(:parent) { story }
describe "WITH a task as child" do
let(:child) { task2 }
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "restricted hierarchy by enabling backlogs"
end
it_should_behave_like 'restricted hierarchy by enabling backlogs'
end
describe "WITH a non backlogs work_package as child" do
let(:child) { bug2 }
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "unrestricted hierarchy even when enabling backlogs"
end
it_should_behave_like 'unrestricted hierarchy even when enabling backlogs'
end
describe "WITH a story as child" do
let(:child) { story2 }
describe 'WITH a story as child' do
let(:child) { story2 }
it_should_behave_like "unrestricted hierarchy even when enabling backlogs"
it_should_behave_like 'unrestricted hierarchy even when enabling backlogs'
end
end
end
describe "WITH a task as parent" do
let(:parent) { task }
describe 'WITH a task as parent' do
let(:parent) { task }
describe "WITH a task as child" do
let(:child) { task2 }
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "restricted hierarchy by enabling backlogs"
end
it_should_behave_like 'restricted hierarchy by enabling backlogs'
end
describe "WITH a non backlogs work_package as child" do
let(:child) { bug2 }
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "unrestricted hierarchy even when enabling backlogs"
end
it_should_behave_like 'unrestricted hierarchy even when enabling backlogs'
end
describe "WITH a story as child" do
let(:child) { story2 }
describe 'WITH a story as child' do
let(:child) { story2 }
it_should_behave_like "unrestricted hierarchy even when enabling backlogs"
it_should_behave_like 'unrestricted hierarchy even when enabling backlogs'
end
end
end
describe "WITH a non-backlogs-work_package as parent" do
let(:parent) { bug }
describe 'WITH a non-backlogs-work_package as parent' do
let(:parent) { bug }
describe "WITH a task as child" do
let(:child) { task2 }
describe 'WITH a task as child' do
let(:child) { task2 }
it_should_behave_like "unrestricted hierarchy even when enabling backlogs"
end
it_should_behave_like 'unrestricted hierarchy even when enabling backlogs'
end
describe "WITH a non backlogs work_package as child" do
let(:child) { bug2 }
describe 'WITH a non backlogs work_package as child' do
let(:child) { bug2 }
it_should_behave_like "unrestricted hierarchy even when enabling backlogs"
end
it_should_behave_like 'unrestricted hierarchy even when enabling backlogs'
end
describe "WITH a story as child" do
let(:child) { story2 }
describe 'WITH a story as child' do
let(:child) { story2 }
it_should_behave_like "unrestricted hierarchy even when enabling backlogs"
it_should_behave_like 'unrestricted hierarchy even when enabling backlogs'
end
end
end
end
end
end

@ -35,47 +35,51 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe WorkPackage, :type => :model do
describe WorkPackage, type: :model do
describe 'Story positions' do
def build_work_package(options)
FactoryGirl.build(:work_package, options.reverse_merge(:fixed_version_id => sprint_1.id,
:priority_id => priority.id,
:project_id => project.id,
:status_id => status.id,
:type_id => story_type.id))
FactoryGirl.build(:work_package, options.reverse_merge(fixed_version_id: sprint_1.id,
priority_id: priority.id,
project_id: project.id,
status_id: status.id,
type_id: story_type.id))
end
def create_work_package(options)
build_work_package(options).tap { |i| i.save! }
build_work_package(options).tap(&:save!)
end
let(:status) { FactoryGirl.create(:status) }
let(:priority) { FactoryGirl.create(:priority_normal) }
let(:project) { FactoryGirl.create(:project) }
let(:story_type) { FactoryGirl.create(:type, :name => 'Story') }
let(:epic_type) { FactoryGirl.create(:type, :name => 'Epic') }
let(:task_type) { FactoryGirl.create(:type, :name => 'Task') }
let(:other_type) { FactoryGirl.create(:type, :name => 'Feedback') }
let(:story_type) { FactoryGirl.create(:type, name: 'Story') }
let(:epic_type) { FactoryGirl.create(:type, name: 'Epic') }
let(:task_type) { FactoryGirl.create(:type, name: 'Task') }
let(:other_type) { FactoryGirl.create(:type, name: 'Feedback') }
let(:sprint_1) { FactoryGirl.create(:version, :project_id => project.id, :name => 'Sprint 1') }
let(:sprint_2) { FactoryGirl.create(:version, :project_id => project.id, :name => 'Sprint 2') }
let(:sprint_1) { FactoryGirl.create(:version, project_id: project.id, name: 'Sprint 1') }
let(:sprint_2) { FactoryGirl.create(:version, project_id: project.id, name: 'Sprint 2') }
let(:work_package_1) { create_work_package(:subject => 'WorkPackage 1', :fixed_version_id => sprint_1.id) }
let(:work_package_2) { create_work_package(:subject => 'WorkPackage 2', :fixed_version_id => sprint_1.id) }
let(:work_package_3) { create_work_package(:subject => 'WorkPackage 3', :fixed_version_id => sprint_1.id) }
let(:work_package_4) { create_work_package(:subject => 'WorkPackage 4', :fixed_version_id => sprint_1.id) }
let(:work_package_5) { create_work_package(:subject => 'WorkPackage 5', :fixed_version_id => sprint_1.id) }
let(:work_package_1) { create_work_package(subject: 'WorkPackage 1', fixed_version_id: sprint_1.id) }
let(:work_package_2) { create_work_package(subject: 'WorkPackage 2', fixed_version_id: sprint_1.id) }
let(:work_package_3) { create_work_package(subject: 'WorkPackage 3', fixed_version_id: sprint_1.id) }
let(:work_package_4) { create_work_package(subject: 'WorkPackage 4', fixed_version_id: sprint_1.id) }
let(:work_package_5) { create_work_package(subject: 'WorkPackage 5', fixed_version_id: sprint_1.id) }
let(:work_package_a) { create_work_package(:subject => 'WorkPackage a', :fixed_version_id => sprint_2.id) }
let(:work_package_b) { create_work_package(:subject => 'WorkPackage b', :fixed_version_id => sprint_2.id) }
let(:work_package_c) { create_work_package(:subject => 'WorkPackage c', :fixed_version_id => sprint_2.id) }
let(:work_package_a) { create_work_package(subject: 'WorkPackage a', fixed_version_id: sprint_2.id) }
let(:work_package_b) { create_work_package(subject: 'WorkPackage b', fixed_version_id: sprint_2.id) }
let(:work_package_c) { create_work_package(subject: 'WorkPackage c', fixed_version_id: sprint_2.id) }
let(:feedback_1) { create_work_package(:subject => 'Feedback 1', :fixed_version_id => sprint_1.id,
:type_id => other_type.id) }
let(:feedback_1) {
create_work_package(subject: 'Feedback 1', fixed_version_id: sprint_1.id,
type_id: other_type.id)
}
let(:task_1) { create_work_package(:subject => 'Task 1', :fixed_version_id => sprint_1.id,
:type_id => task_type.id) }
let(:task_1) {
create_work_package(subject: 'Task 1', fixed_version_id: sprint_1.id,
type_id: task_type.id)
}
before do
# We had problems while writing these specs, that some elements kept
@ -90,8 +94,8 @@ describe WorkPackage, :type => :model do
Version.delete_all
# Enable and configure backlogs
project.enabled_module_names = project.enabled_module_names + ["backlogs"]
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"story_types" => [story_type.id, epic_type.id], "task_type" => task_type.id})
project.enabled_module_names = project.enabled_module_names + ['backlogs']
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'story_types' => [story_type.id, epic_type.id], 'task_type' => task_type.id })
# Otherwise the type id's from the previous test are still active
WorkPackage.instance_variable_set(:@backlogs_types, nil)
@ -114,14 +118,14 @@ describe WorkPackage, :type => :model do
describe '- Creating a work_package in a sprint' do
it 'adds it to the bottom of the list' do
new_work_package = create_work_package(:subject => 'Newest WorkPackage', :fixed_version_id => sprint_1.id)
new_work_package = create_work_package(subject: 'Newest WorkPackage', fixed_version_id: sprint_1.id)
expect(new_work_package).not_to be_new_record
expect(new_work_package).to be_last
end
it 'does not reorder the existing work_packages' do
new_work_package = create_work_package(:subject => 'Newest WorkPackage', :fixed_version_id => sprint_1.id)
new_work_package = create_work_package(subject: 'Newest WorkPackage', fixed_version_id: sprint_1.id)
expect([work_package_1, work_package_2, work_package_3, work_package_4, work_package_5].each(&:reload).map(&:position)).to eq([1, 2, 3, 4, 5])
end
@ -132,8 +136,8 @@ describe WorkPackage, :type => :model do
work_package_2.fixed_version = sprint_2
work_package_2.save!
expect(sprint_1.fixed_issues.all(:order => 'id')).to eq([work_package_1, work_package_3, work_package_4, work_package_5])
expect(sprint_1.fixed_issues.all(:order => 'id').each(&:reload).map(&:position)).to eq([1, 2, 3, 4])
expect(sprint_1.fixed_issues.all(order: 'id')).to eq([work_package_1, work_package_3, work_package_4, work_package_5])
expect(sprint_1.fixed_issues.all(order: 'id').each(&:reload).map(&:position)).to eq([1, 2, 3, 4])
end
end
@ -245,14 +249,18 @@ describe WorkPackage, :type => :model do
let(:project_wo_backlogs) { FactoryGirl.create(:project) }
let(:sub_project_wo_backlogs) { FactoryGirl.create(:project) }
let(:shared_sprint) { FactoryGirl.create(:version,
:project_id => project.id,
:name => 'Shared Sprint',
:sharing => 'descendants') }
let(:version_go_live) { FactoryGirl.create(:version,
:project_id => project_wo_backlogs.id,
:name => 'Go-Live') }
let(:shared_sprint) {
FactoryGirl.create(:version,
project_id: project.id,
name: 'Shared Sprint',
sharing: 'descendants')
}
let(:version_go_live) {
FactoryGirl.create(:version,
project_id: project_wo_backlogs.id,
name: 'Go-Live')
}
let(:admin) { FactoryGirl.create(:admin) }
def move_to_project(work_package, project)
@ -262,8 +270,8 @@ describe WorkPackage, :type => :model do
end
before do
project_wo_backlogs.enabled_module_names = project_wo_backlogs.enabled_module_names - ["backlogs"]
sub_project_wo_backlogs.enabled_module_names = sub_project_wo_backlogs.enabled_module_names - ["backlogs"]
project_wo_backlogs.enabled_module_names = project_wo_backlogs.enabled_module_names - ['backlogs']
sub_project_wo_backlogs.enabled_module_names = sub_project_wo_backlogs.enabled_module_names - ['backlogs']
project_wo_backlogs.types = [story_type, task_type, other_type]
sub_project_wo_backlogs.types = [story_type, task_type, other_type]
@ -276,9 +284,11 @@ describe WorkPackage, :type => :model do
describe '- Moving an work_package from a project without backlogs to a backlogs_enabled project' do
describe 'if the fixed_version may not be kept' do
let(:work_package_i) { create_work_package(:subject => 'WorkPackage I',
:fixed_version_id => version_go_live.id,
:project_id => project_wo_backlogs.id) }
let(:work_package_i) {
create_work_package(subject: 'WorkPackage I',
fixed_version_id: version_go_live.id,
project_id: project_wo_backlogs.id)
}
before do
work_package_i
end
@ -301,9 +311,11 @@ describe WorkPackage, :type => :model do
end
describe 'if the fixed_version may be kept' do
let(:work_package_i) { create_work_package(:subject => 'WorkPackage I',
:fixed_version_id => shared_sprint.id,
:project_id => sub_project_wo_backlogs.id) }
let(:work_package_i) {
create_work_package(subject: 'WorkPackage I',
fixed_version_id: shared_sprint.id,
project_id: sub_project_wo_backlogs.id)
}
before do
work_package_i
@ -355,12 +367,18 @@ describe WorkPackage, :type => :model do
end
describe 'if the fixed_version may be kept' do
let(:work_package_i) { create_work_package(:subject => 'WorkPackage I',
:fixed_version_id => shared_sprint.id) }
let(:work_package_ii) { create_work_package(:subject => 'WorkPackage II',
:fixed_version_id => shared_sprint.id) }
let(:work_package_iii) { create_work_package(:subject => 'WorkPackage III',
:fixed_version_id => shared_sprint.id) }
let(:work_package_i) {
create_work_package(subject: 'WorkPackage I',
fixed_version_id: shared_sprint.id)
}
let(:work_package_ii) {
create_work_package(subject: 'WorkPackage II',
fixed_version_id: shared_sprint.id)
}
let(:work_package_iii) {
create_work_package(subject: 'WorkPackage III',
fixed_version_id: shared_sprint.id)
}
before do
work_package_i.move_to_bottom

@ -35,7 +35,7 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe WorkPackage, :type => :model do
describe WorkPackage, type: :model do
describe 'behavior for #3200' do
let(:empty_work_package) { WorkPackage.new }
let(:admin) { FactoryGirl.create(:admin) }
@ -58,7 +58,7 @@ describe WorkPackage, :type => :model do
describe 'story points' do
before(:each) do
work_package.project.enabled_module_names += ["backlogs"]
work_package.project.enabled_module_names += ['backlogs']
end
it 'allows empty values' do
@ -103,7 +103,6 @@ describe WorkPackage, :type => :model do
end
end
describe 'remaining hours' do
it 'allows empty values' do
expect(work_package.remaining_hours).to be_nil
@ -137,14 +136,14 @@ describe WorkPackage, :type => :model do
describe 'definition of done' do
before(:each) do
@status_resolved = FactoryGirl.build(:status, :name => "Resolved", :is_default => false)
@status_open = FactoryGirl.build(:status, :name => "Open", :is_default => true)
@status_resolved = FactoryGirl.build(:status, name: 'Resolved', is_default: false)
@status_open = FactoryGirl.build(:status, name: 'Open', is_default: true)
@project = FactoryGirl.build(:project)
@project.done_statuses = [@status_resolved]
@work_package = FactoryGirl.build(:work_package, :project => @project,
:status => @status_open,
:type => FactoryGirl.build(:type_feature))
@work_package = FactoryGirl.build(:work_package, project: @project,
status: @status_open,
type: FactoryGirl.build(:type_feature))
end
it 'should not be done when having the initial status "open"' do
@ -156,30 +155,30 @@ describe WorkPackage, :type => :model do
expect(@work_package.done?).to be_truthy
end
it 'should not be done when removing done status from "resolved"' do
@work_package.status = @status_resolved
@project.done_statuses = Array.new
expect(@work_package.done?).to be_falsey
it 'should not be done when removing done status from "resolved"' do
@work_package.status = @status_resolved
@project.done_statuses = Array.new
expect(@work_package.done?).to be_falsey
end
end
describe "backlogs_enabled?" do
describe 'backlogs_enabled?' do
let(:project) { FactoryGirl.build(:project) }
let(:work_package) { FactoryGirl.build(:work_package) }
it "should be false without a project" do
it 'should be false without a project' do
work_package.project = nil
expect(work_package).not_to be_backlogs_enabled
end
it "should be true with a project having the backlogs module" do
project.enabled_module_names = project.enabled_module_names + ["backlogs"]
it 'should be true with a project having the backlogs module' do
project.enabled_module_names = project.enabled_module_names + ['backlogs']
work_package.project = project
expect(work_package).to be_backlogs_enabled
end
it "should be false with a project not having the backlogs module" do
it 'should be false with a project not having the backlogs module' do
work_package.project = project
work_package.project.enabled_module_names = nil

@ -35,31 +35,32 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe Sprint, :type => :model do
describe Sprint, type: :model do
let(:sprint) { FactoryGirl.build(:sprint) }
let(:project) { FactoryGirl.build(:project) }
describe "Class Methods" do
describe 'Class Methods' do
describe '#displayed_left' do
describe "WITH display set to left" do
describe 'WITH display set to left' do
before(:each) do
sprint.version_settings = [FactoryGirl.build(:version_setting, :project => project,
:display => VersionSetting::DISPLAY_LEFT)]
sprint.version_settings = [FactoryGirl.build(:version_setting, project: project,
display: VersionSetting::DISPLAY_LEFT)]
sprint.project = project
sprint.save!
end
it {
expect(Sprint.displayed_left(project)).to match_array [sprint] }
expect(Sprint.displayed_left(project)).to match_array [sprint]
}
end
describe "WITH a version setting defined for another project" do
describe 'WITH a version setting defined for another project' do
before(:each) do
another_project = FactoryGirl.build(:project, :name => 'another project',
:identifier => 'another project')
another_project = FactoryGirl.build(:project, name: 'another project',
identifier: 'another project')
sprint.version_settings = [FactoryGirl.build(:version_setting, :project => another_project,
:display => VersionSetting::DISPLAY_RIGHT)]
sprint.version_settings = [FactoryGirl.build(:version_setting, project: another_project,
display: VersionSetting::DISPLAY_RIGHT)]
sprint.project = project
sprint.save
end
@ -67,7 +68,7 @@ describe Sprint, :type => :model do
it { expect(Sprint.displayed_left(project)).to match_array [sprint] }
end
describe "WITH no version setting defined" do
describe 'WITH no version setting defined' do
before(:each) do
sprint.project = project
sprint.save!
@ -79,7 +80,7 @@ describe Sprint, :type => :model do
describe '#displayed_right' do
before(:each) do
sprint.version_settings = [FactoryGirl.build(:version_setting, :project => project, :display => VersionSetting::DISPLAY_RIGHT)]
sprint.version_settings = [FactoryGirl.build(:version_setting, project: project, display: VersionSetting::DISPLAY_RIGHT)]
sprint.project = project
sprint.save!
end
@ -89,9 +90,9 @@ describe Sprint, :type => :model do
describe '#order_by_date' do
before(:each) do
@sprint1 = FactoryGirl.create(:sprint, :name => "sprint1", :project => project, :start_date => Date.today + 2.days)
@sprint2 = FactoryGirl.create(:sprint, :name => "sprint2", :project => project, :start_date => Date.today + 1.day, :effective_date => Date.today + 3.days)
@sprint3 = FactoryGirl.create(:sprint, :name => "sprint3", :project => project, :start_date => Date.today + 1.day, :effective_date => Date.today + 2.days)
@sprint1 = FactoryGirl.create(:sprint, name: 'sprint1', project: project, start_date: Date.today + 2.days)
@sprint2 = FactoryGirl.create(:sprint, name: 'sprint2', project: project, start_date: Date.today + 1.day, effective_date: Date.today + 3.days)
@sprint3 = FactoryGirl.create(:sprint, name: 'sprint3', project: project, start_date: Date.today + 1.day, effective_date: Date.today + 2.days)
end
it { expect(Sprint.order_by_date[0]).to eql @sprint3 }
@ -105,43 +106,43 @@ describe Sprint, :type => :model do
@other_project = FactoryGirl.create(:project)
end
describe "WITH the version beeing shared system wide" do
describe 'WITH the version beeing shared system wide' do
before(:each) do
@version = FactoryGirl.create(:sprint, :name => "systemwide", :project => @other_project, :sharing => 'system')
@version = FactoryGirl.create(:sprint, name: 'systemwide', project: @other_project, sharing: 'system')
end
it { expect(Sprint.apply_to(project).size).to eq(1) }
it { expect(Sprint.apply_to(project)[0]).to eql(@version) }
end
describe "WITH the version beeing shared from a parent project" do
describe 'WITH the version beeing shared from a parent project' do
before(:each) do
project.set_parent!(@other_project)
@version = FactoryGirl.create(:sprint, :name => "descended", :project => @other_project, :sharing => 'descendants')
@version = FactoryGirl.create(:sprint, name: 'descended', project: @other_project, sharing: 'descendants')
end
it { expect(Sprint.apply_to(project).size).to eq(1) }
it { expect(Sprint.apply_to(project)[0]).to eql(@version) }
end
describe "WITH the version beeing shared within the tree" do
describe 'WITH the version beeing shared within the tree' do
before(:each) do
@parent_project = FactoryGirl.create(:project)
# Setting the parent has to be in this order, don't know why yet
@other_project.set_parent!(@parent_project)
project.set_parent!(@parent_project)
@version = FactoryGirl.create(:sprint, :name => "treed", :project => @other_project, :sharing => 'tree')
@version = FactoryGirl.create(:sprint, name: 'treed', project: @other_project, sharing: 'tree')
end
it { expect(Sprint.apply_to(project).size).to eq(1) }
it { expect(Sprint.apply_to(project)[0]).to eql(@version) }
end
describe "WITH the version beeing shared within the tree" do
describe 'WITH the version beeing shared within the tree' do
before(:each) do
@descendant_project = FactoryGirl.create(:project)
@descendant_project.set_parent!(project)
@version = FactoryGirl.create(:sprint, :name => "hierar", :project => @descendant_project, :sharing => 'hierarchy')
@version = FactoryGirl.create(:sprint, name: 'hierar', project: @descendant_project, sharing: 'hierarchy')
end
it { expect(Sprint.apply_to(project).size).to eq(1) }

@ -35,39 +35,45 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe Story, :type => :model do
describe Story, type: :model do
let(:user) { @user ||= FactoryGirl.create(:user) }
let(:role) { @role ||= FactoryGirl.create(:role) }
let(:status1) { @status1 ||= FactoryGirl.create(:status, :name => "status 1", :is_default => true) }
let(:status1) { @status1 ||= FactoryGirl.create(:status, name: 'status 1', is_default: true) }
let(:type_feature) { @type_feature ||= FactoryGirl.create(:type_feature) }
let(:version) { @version ||= FactoryGirl.create(:version, :project => project) }
let(:version2) { FactoryGirl.create(:version, :project => project) }
let(:sprint) { @sprint ||= FactoryGirl.create(:sprint, :project => project) }
let(:version) { @version ||= FactoryGirl.create(:version, project: project) }
let(:version2) { FactoryGirl.create(:version, project: project) }
let(:sprint) { @sprint ||= FactoryGirl.create(:sprint, project: project) }
let(:issue_priority) { @issue_priority ||= FactoryGirl.create(:priority) }
let(:task_type) { FactoryGirl.create(:type_task) }
let(:task) { FactoryGirl.create(:story, :fixed_version => version,
:project => project,
:status => status1,
:type => task_type,
:priority => issue_priority) }
let(:story1) { FactoryGirl.create(:story, :fixed_version => version,
:project => project,
:status => status1,
:type => type_feature,
:priority => issue_priority) }
let(:story2) { FactoryGirl.create(:story, :fixed_version => version,
:project => project,
:status => status1,
:type => type_feature,
:priority => issue_priority) }
let(:task) {
FactoryGirl.create(:story, fixed_version: version,
project: project,
status: status1,
type: task_type,
priority: issue_priority)
}
let(:story1) {
FactoryGirl.create(:story, fixed_version: version,
project: project,
status: status1,
type: type_feature,
priority: issue_priority)
}
let(:story2) {
FactoryGirl.create(:story, fixed_version: version,
project: project,
status: status1,
type: type_feature,
priority: issue_priority)
}
let(:project) do
unless @project
@project = FactoryGirl.build(:project)
@project.members = [FactoryGirl.build(:member, :principal => user,
:project => @project,
:roles => [role])]
@project.members = [FactoryGirl.build(:member, principal: user,
project: @project,
roles: [role])]
end
@project
end
@ -75,17 +81,16 @@ describe Story, :type => :model do
before(:each) do
ActionController::Base.perform_caching = false
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"points_burn_direction" => "down",
"wiki_template" => "",
"card_spec" => "Sattleford VM-5040",
"story_types" => [type_feature.id.to_s],
"task_type" => task_type.id.to_s })
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'points_burn_direction' => 'down',
'wiki_template' => '',
'card_spec' => 'Sattleford VM-5040',
'story_types' => [type_feature.id.to_s],
'task_type' => task_type.id.to_s })
project.types << task_type
end
describe "Class methods" do
describe 'Class methods' do
describe '#backlogs' do
describe "WITH one sprint
WITH the sprint having 1 story" do
before(:each) do
@ -99,7 +104,6 @@ describe Story, :type => :model do
WITH two stories
WITH one story per sprint
WITH querying for the two sprints" do
before do
version2
story1
@ -115,7 +119,6 @@ describe Story, :type => :model do
WITH two stories
WITH one story per sprint
WITH querying one sprints" do
before do
version2
story1
@ -133,7 +136,6 @@ describe Story, :type => :model do
WITH one story per sprint
WITH querying for the two sprints
WITH one sprint beeing in another project" do
before do
story1
@ -151,7 +153,7 @@ describe Story, :type => :model do
describe "WITH one sprint
WITH the sprint having one story in this project and one story in another project" do
before(:each) do
version.sharing = "system"
version.sharing = 'system'
version.save!
another_project = FactoryGirl.create(:project)
@ -167,7 +169,6 @@ describe Story, :type => :model do
describe "WITH one sprint
WITH the sprint having two storys
WITH one beeing the child of the other" do
before(:each) do
story1.parent_id = story2.id
@ -180,7 +181,6 @@ describe Story, :type => :model do
describe "WITH one sprint
WITH the sprint having one story
WITH the story having a child task" do
before(:each) do
task.parent_id = story1.id
@ -193,7 +193,6 @@ describe Story, :type => :model do
describe "WITH one sprint
WITH the sprint having one story and one task
WITH the two having no connection" do
before(:each) do
task
story1
@ -204,22 +203,22 @@ describe Story, :type => :model do
end
end
describe "journals created after adding a subtask to a story" do
describe 'journals created after adding a subtask to a story' do
before(:each) do
@current = FactoryGirl.create(:user, :login => "user1", :mail => "user1@users.com")
@current = FactoryGirl.create(:user, login: 'user1', mail: 'user1@users.com')
allow(User).to receive(:current).and_return(@current)
@story = FactoryGirl.create(:story, :fixed_version => version,
:project => project,
:status => status1,
:type => type_feature,
:priority => issue_priority)
@story.project.enabled_module_names += ["backlogs"]
@story = FactoryGirl.create(:story, fixed_version: version,
project: project,
status: status1,
type: type_feature,
priority: issue_priority)
@story.project.enabled_module_names += ['backlogs']
@work_package ||= FactoryGirl.create(:work_package, :project => project, :status => status1, :type => type_feature, :author => @current)
@work_package ||= FactoryGirl.create(:work_package, project: project, status: status1, type: type_feature, author: @current)
end
it "should create a journal when adding a subtask which has remaining hours set" do
it 'should create a journal when adding a subtask which has remaining hours set' do
@work_package.remaining_hours = 15.0
@work_package.parent_id = @story.id
@work_package.save!
@ -227,7 +226,7 @@ describe Story, :type => :model do
expect(@story.journals.last.changed_data[:remaining_hours]).to eq([nil, 15])
end
it "should not create an empty journal when adding a subtask without remaining hours set" do
it 'should not create an empty journal when adding a subtask without remaining hours set' do
@work_package.parent_id = @story.id
@work_package.save!

@ -35,7 +35,7 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe User, :type => :model do
describe User, type: :model do
describe 'backlogs_preference' do
describe 'task_color' do
it 'reads from and writes to a user preference' do

@ -35,15 +35,15 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe VersionSetting, :type => :model do
describe VersionSetting, type: :model do
let(:version_setting) { FactoryGirl.build(:version_setting) }
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:version) }
it { expect(VersionSetting.column_names).to include("display") }
it { expect(VersionSetting.column_names).to include('display') }
describe "Instance Methods" do
describe "WITH display set to left" do
describe 'Instance Methods' do
describe 'WITH display set to left' do
before(:each) do
version_setting.display_left!
end
@ -51,7 +51,7 @@ describe VersionSetting, :type => :model do
it { expect(version_setting.display_left?).to be_truthy }
end
describe "WITH display set to right" do
describe 'WITH display set to right' do
before(:each) do
version_setting.display_right!
end
@ -59,7 +59,7 @@ describe VersionSetting, :type => :model do
it { expect(version_setting.display_right?).to be_truthy }
end
describe "WITH display set to none" do
describe 'WITH display set to none' do
before(:each) do
version_setting.display_none!
end

@ -35,31 +35,31 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe Version, :type => :model do
describe Version, type: :model do
it { is_expected.to have_many :version_settings }
describe 'rebuild positions' do
def build_work_package(options = {})
FactoryGirl.build(:work_package, options.reverse_merge(:fixed_version_id => version.id,
:priority_id => priority.id,
:project_id => project.id,
:status_id => status.id))
FactoryGirl.build(:work_package, options.reverse_merge(fixed_version_id: version.id,
priority_id: priority.id,
project_id: project.id,
status_id: status.id))
end
def create_work_package(options = {})
build_work_package(options).tap { |i| i.save! }
build_work_package(options).tap(&:save!)
end
let(:status) { FactoryGirl.create(:status) }
let(:priority) { FactoryGirl.create(:priority_normal) }
let(:project) { FactoryGirl.create(:project, :name => "Project 1", :types => [epic_type, story_type, task_type, other_type])}
let(:project) { FactoryGirl.create(:project, name: 'Project 1', types: [epic_type, story_type, task_type, other_type]) }
let(:epic_type) { FactoryGirl.create(:type, :name => 'Epic') }
let(:story_type) { FactoryGirl.create(:type, :name => 'Story') }
let(:task_type) { FactoryGirl.create(:type, :name => 'Task') }
let(:other_type) { FactoryGirl.create(:type, :name => 'Other') }
let(:epic_type) { FactoryGirl.create(:type, name: 'Epic') }
let(:story_type) { FactoryGirl.create(:type, name: 'Story') }
let(:task_type) { FactoryGirl.create(:type, name: 'Task') }
let(:other_type) { FactoryGirl.create(:type, name: 'Other') }
let(:version) { FactoryGirl.create(:version, :project_id => project.id, :name => 'Version') }
let(:version) { FactoryGirl.create(:version, project_id: project.id, name: 'Version') }
let(:admin) { FactoryGirl.create(:admin) }
@ -82,8 +82,8 @@ describe Version, :type => :model do
Version.delete_all
# Enable and configure backlogs
project.enabled_module_names = project.enabled_module_names + ["backlogs"]
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"story_types" => [epic_type.id, story_type.id], "task_type" => task_type.id})
project.enabled_module_names = project.enabled_module_names + ['backlogs']
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'story_types' => [epic_type.id, story_type.id], 'task_type' => task_type.id })
# Otherwise the type id's from the previous test are still active
WorkPackage.instance_variable_set(:@backlogs_types, nil)
@ -93,14 +93,14 @@ describe Version, :type => :model do
end
it 'moves an work_package to a project where backlogs is disabled while using versions' do
project2 = FactoryGirl.create(:project, :name => "Project 2", :types => [epic_type, story_type, task_type, other_type])
project2.enabled_module_names = project2.enabled_module_names - ["backlogs"]
project2 = FactoryGirl.create(:project, name: 'Project 2', types: [epic_type, story_type, task_type, other_type])
project2.enabled_module_names = project2.enabled_module_names - ['backlogs']
project2.save!
project2.reload
work_package1 = FactoryGirl.create(:work_package, :type_id => task_type.id, :status_id => status.id, :project_id => project.id)
work_package2 = FactoryGirl.create(:work_package, :parent_id => work_package1.id, :type_id => task_type.id, :status_id => status.id, :project_id => project.id)
work_package3 = FactoryGirl.create(:work_package, :parent_id => work_package2.id, :type_id => task_type.id, :status_id => status.id, :project_id => project.id)
work_package1 = FactoryGirl.create(:work_package, type_id: task_type.id, status_id: status.id, project_id: project.id)
work_package2 = FactoryGirl.create(:work_package, parent_id: work_package1.id, type_id: task_type.id, status_id: status.id, project_id: project.id)
work_package3 = FactoryGirl.create(:work_package, parent_id: work_package2.id, type_id: task_type.id, status_id: status.id, project_id: project.id)
work_package1.reload
work_package1.fixed_version_id = version.id
@ -132,13 +132,13 @@ describe Version, :type => :model do
end
it 'rebuilds postions' do
e1 = create_work_package(:type_id => epic_type.id)
s2 = create_work_package(:type_id => story_type.id)
s3 = create_work_package(:type_id => story_type.id)
s4 = create_work_package(:type_id => story_type.id)
s5 = create_work_package(:type_id => story_type.id)
t3 = create_work_package(:type_id => task_type.id)
o9 = create_work_package(:type_id => other_type.id)
e1 = create_work_package(type_id: epic_type.id)
s2 = create_work_package(type_id: story_type.id)
s3 = create_work_package(type_id: story_type.id)
s4 = create_work_package(type_id: story_type.id)
s5 = create_work_package(type_id: story_type.id)
t3 = create_work_package(type_id: task_type.id)
o9 = create_work_package(type_id: other_type.id)
[e1, s2, s3, s4, s5].each(&:move_to_bottom)
@ -151,7 +151,7 @@ describe Version, :type => :model do
version.rebuild_positions(project)
work_packages = version.fixed_issues.find(:all, :conditions => {:project_id => project}, :order => 'COALESCE(position, 0) ASC, id ASC')
work_packages = version.fixed_issues.find(:all, conditions: { project_id: project }, order: 'COALESCE(position, 0) ASC, id ASC')
expect(work_packages.map(&:position)).to eq([nil, nil, 1, 2, 3, 4, 5])
expect(work_packages.map(&:subject)).to eq([t3, o9, e1, s2, s5, s3, s4].map(&:subject))

@ -35,26 +35,26 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe WorkPackage, :type => :model do
describe WorkPackage, type: :model do
describe '#backlogs_types' do
it "should return all the ids of types that are configures to be considered backlogs types" do
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"story_types" => [1], "task_type" => 2})
it 'should return all the ids of types that are configures to be considered backlogs types' do
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'story_types' => [1], 'task_type' => 2 })
expect(WorkPackage.backlogs_types).to match_array([1,2])
expect(WorkPackage.backlogs_types).to match_array([1, 2])
end
it "should return an empty array if nothing is defined" do
it 'should return an empty array if nothing is defined' do
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({})
expect(WorkPackage.backlogs_types).to eq([])
end
it 'should reflect changes to the configuration' do
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"story_types" => [1], "task_type" => 2})
expect(WorkPackage.backlogs_types).to match_array([1,2])
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'story_types' => [1], 'task_type' => 2 })
expect(WorkPackage.backlogs_types).to match_array([1, 2])
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({"story_types" => [3], "task_type" => 4})
expect(WorkPackage.backlogs_types).to match_array([3,4])
allow(Setting).to receive(:plugin_openproject_backlogs).and_return({ 'story_types' => [3], 'task_type' => 4 })
expect(WorkPackage.backlogs_types).to match_array([3, 4])
end
end
end

@ -35,11 +35,13 @@
require 'spec_helper'
describe RbBurndownChartsController, :type => :routing do
describe "routing" do
it { expect(get('/projects/project_42/sprints/21/burndown_chart')).to route_to(:controller => 'rb_burndown_charts',
:action => 'show',
:project_id => 'project_42',
:sprint_id => '21') }
describe RbBurndownChartsController, type: :routing do
describe 'routing' do
it {
expect(get('/projects/project_42/sprints/21/burndown_chart')).to route_to(controller: 'rb_burndown_charts',
action: 'show',
project_id: 'project_42',
sprint_id: '21')
}
end
end

@ -35,16 +35,20 @@
require 'spec_helper'
describe RbImpedimentsController, :type => :routing do
describe "routing" do
it { expect(post('/projects/project_42/sprints/21/impediments')).to route_to(:controller => 'rb_impediments',
:action => 'create',
:project_id => 'project_42',
:sprint_id => '21') }
it { expect(put('/projects/project_42/sprints/21/impediments/85')).to route_to(:controller => 'rb_impediments',
:action => 'update',
:project_id => 'project_42',
:sprint_id => '21',
:id => '85') }
describe RbImpedimentsController, type: :routing do
describe 'routing' do
it {
expect(post('/projects/project_42/sprints/21/impediments')).to route_to(controller: 'rb_impediments',
action: 'create',
project_id: 'project_42',
sprint_id: '21')
}
it {
expect(put('/projects/project_42/sprints/21/impediments/85')).to route_to(controller: 'rb_impediments',
action: 'update',
project_id: 'project_42',
sprint_id: '21',
id: '85')
}
end
end

@ -35,10 +35,12 @@
require 'spec_helper'
describe RbMasterBacklogsController, :type => :routing do
describe "routing" do
it { expect(get('/projects/project_42/backlogs')).to route_to(:controller => 'rb_master_backlogs',
:action => 'index',
:project_id => 'project_42') }
describe RbMasterBacklogsController, type: :routing do
describe 'routing' do
it {
expect(get('/projects/project_42/backlogs')).to route_to(controller: 'rb_master_backlogs',
action: 'index',
project_id: 'project_42')
}
end
end

@ -35,11 +35,13 @@
require 'spec_helper'
describe RbQueriesController, :type => :routing do
describe "routing" do
it { expect(get('/projects/project_42/sprints/21/query')).to route_to(:controller => 'rb_queries',
:action => 'show',
:project_id => 'project_42',
:sprint_id => '21') }
describe RbQueriesController, type: :routing do
describe 'routing' do
it {
expect(get('/projects/project_42/sprints/21/query')).to route_to(controller: 'rb_queries',
action: 'show',
project_id: 'project_42',
sprint_id: '21')
}
end
end

@ -35,11 +35,13 @@
require 'spec_helper'
describe RbServerVariablesController, :type => :routing do
describe "routing" do
it { expect(get('/projects/project_42/server_variables.js')).to route_to(:controller => 'rb_server_variables',
:action => 'show',
:format => 'js',
:project_id => 'project_42') }
describe RbServerVariablesController, type: :routing do
describe 'routing' do
it {
expect(get('/projects/project_42/server_variables.js')).to route_to(controller: 'rb_server_variables',
action: 'show',
format: 'js',
project_id: 'project_42')
}
end
end

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save