Merge branch 'feature/rails3' into feature/changesets_on_work_packages

Conflicts:
	app/assets/stylesheets/default/application.css.erb
	app/controllers/work_packages_controller.rb
	app/models/work_package.rb
	app/views/work_packages/show.html.erb
	features/users/random_password_assignment.feature
	features/users/status.feature
	spec/helpers/work_packages_helper_spec.rb
pull/261/head
Jens Ulferts 11 years ago
commit c13a402108
  1. 1
      .gitignore
  2. 11
      app/assets/javascripts/admin_users.js
  3. 11
      app/assets/javascripts/members_form.js
  4. 11
      app/assets/javascripts/members_select_boxes.js
  5. 2160
      app/assets/stylesheets/default/application.css.erb
  6. 2
      app/controllers/activities_controller.rb
  7. 7
      app/controllers/attachments_controller.rb
  8. 92
      app/controllers/work_packages_controller.rb
  9. 82
      app/helpers/work_packages_helper.rb
  10. 3
      app/models/attachment.rb
  11. 9
      app/models/issue.rb
  12. 31
      app/models/permitted_params.rb
  13. 4
      app/models/planning_element.rb
  14. 7
      app/models/project.rb
  15. 6
      app/models/query.rb
  16. 11
      app/models/system_user.rb
  17. 49
      app/models/work_package.rb
  18. 11
      app/public/javascripts/translations.js
  19. 35
      app/views/attachments/_nested_form.html.erb
  20. 12
      app/views/members/_member_form.html.erb
  21. 12
      app/views/members/_member_form_impaired.html.erb
  22. 12
      app/views/members/_member_form_non_impaired.html.erb
  23. 12
      app/views/users/_random_password.html.erb
  24. 34
      app/views/work_packages/_attributes.html.erb
  25. 98
      app/views/work_packages/_edit.html.erb
  26. 8
      app/views/work_packages/_form.html.erb
  27. 24
      app/views/work_packages/_form_custom_fields.html.erb
  28. 21
      app/views/work_packages/_form_update.html.erb
  29. 40
      app/views/work_packages/_time_entry.html.erb
  30. 32
      app/views/work_packages/_two_column_attributes.html.erb
  31. 23
      app/views/work_packages/edit.html.erb
  32. 7
      app/views/work_packages/new.html.erb
  33. 19
      app/views/work_packages/new_type.html.erb
  34. 62
      app/views/work_packages/show.html.erb
  35. 4
      config/cucumber.yml
  36. 11
      config/locales/de.yml
  37. 11
      config/locales/en.yml
  38. 7
      config/routes.rb
  39. 11
      db/migrate/20130611154020_remove_timelines_namespace.rb
  40. 11
      db/migrate/20130620082322_create_work_packages.rb
  41. 11
      db/migrate/20130709084751_rename_end_date_on_alternate_dates.rb
  42. 11
      db/migrate/20130710145350_remove_end_date_from_work_packages.rb
  43. 11
      db/migrate/20130719133922_rename_trackers_to_types.rb
  44. 11
      db/migrate/20130722154555_rename_work_package_sti_column.rb
  45. 11
      db/migrate/20130723092240_add_activity_module.rb
  46. 11
      db/migrate/20130723134527_increase_journals_changed_data_limit.rb
  47. 5
      doc/CHANGELOG.md
  48. 11
      features/enumerations/administration.feature
  49. 2
      features/issues/issue_new.feature
  50. 1
      features/issues/issue_show.feature
  51. 15
      features/logout_ajax.feature
  52. 11
      features/members/error_messages.feature
  53. 11
      features/members/membership.feature
  54. 4
      features/planning_elements/planning_element_management.feature
  55. 4
      features/planning_elements/planning_element_textile_link.feature
  56. 11
      features/projects/settings.feature
  57. 11
      features/projects/show.feature
  58. 11
      features/roles/role_crud.feature
  59. 25
      features/step_definitions/common_steps.rb
  60. 12
      features/step_definitions/custom_field_steps.rb
  61. 11
      features/step_definitions/email_steps.rb
  62. 11
      features/step_definitions/enumeration_steps.rb
  63. 29
      features/step_definitions/general_steps.rb
  64. 18
      features/step_definitions/journal_steps.rb
  65. 12
      features/step_definitions/planning_element_status_steps.rb
  66. 37
      features/step_definitions/planning_element_steps.rb
  67. 2
      features/step_definitions/planning_element_type_steps.rb
  68. 36
      features/step_definitions/priority_steps.rb
  69. 14
      features/step_definitions/project_type_steps.rb
  70. 25
      features/step_definitions/status_steps.rb
  71. 9
      features/step_definitions/timelines_given_steps.rb
  72. 4
      features/step_definitions/user_steps.rb
  73. 29
      features/step_definitions/version_steps.rb
  74. 10
      features/step_definitions/web_steps.rb
  75. 44
      features/step_definitions/work_package_steps.rb
  76. 11
      features/support/selenium_with_firebug.rb
  77. 12
      features/timelines/timeline_view.feature
  78. 28
      features/timelines/timeline_view_with_reporters.feature
  79. 10
      features/timelines/timeline_wiki_macro.feature
  80. 1
      features/work_packages/diff_on_show.feature
  81. 95
      features/work_packages/editable_fields.feature
  82. 43
      features/work_packages/error_on_update.feature
  83. 47
      features/work_packages/log_time_on_update.feature
  84. 24
      features/work_packages/navigate_to_edit.feature
  85. 95
      features/work_packages/update.feature
  86. 6
      lib/instance_finder.rb
  87. 2
      lib/open_project/version.rb
  88. 7
      lib/redmine.rb
  89. 21
      lib/redmine/access_control.rb
  90. 64
      lib/tasks/copyright.rake
  91. 215
      spec/controllers/work_packages_controller_spec.rb
  92. 5
      spec/factories/custom_field_factory.rb
  93. 5
      spec/factories/custom_value_factory.rb
  94. 115
      spec/helpers/work_packages_helper_spec.rb
  95. 11
      spec/lib/open_project/footer_spec.rb
  96. 168
      spec/models/permitted_params_spec.rb
  97. 5
      spec/models/project_spec.rb
  98. 11
      spec/models/system_user_spec.rb
  99. 124
      spec/models/work_package_spec.rb
  100. 18
      spec/routing/work_packages_spec.rb
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitignore vendored

@ -44,4 +44,5 @@
/Gemfile.plugins
/.rvmrc*
/.ruby-version
/.ruby-gemset

@ -1,3 +1,14 @@
//-- copyright
// OpenProject is a project management system.
//
// Copyright (C) 2012-2013 the OpenProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
(function() {
// When 'assign random password' field is enabled,

@ -1,3 +1,14 @@
//-- copyright
// OpenProject is a project management system.
//
// Copyright (C) 2012-2013 the OpenProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
jQuery(document).ready(function($) {
$("#tab-content-members").submit('#members_add_form', function () {
var error = $('.errorExplanation, .flash');

@ -1,3 +1,14 @@
//-- copyright
// OpenProject is a project management system.
//
// Copyright (C) 2012-2013 the OpenProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
jQuery(document).ready(function($) {
var load_cb, memberstab, update_cb;
init_members_cb = function () {

File diff suppressed because it is too large Load Diff

@ -83,7 +83,7 @@ class ActivitiesController < ApplicationController
project_ids = []
if event.respond_to?(:changed_data) and event.changed_data['project_id']
project_ids = event.changed_data['project_id']
elsif event.respond_to?(:project_id)
elsif event.respond_to?(:project_id) or event.journaled.respond_to?(:project_id)
project_ids = [ event.project_id ]
end
if project_ids.empty?

@ -44,7 +44,12 @@ class AttachmentsController < ApplicationController
@attachment.container.attachments.delete(@attachment)
redirect_to :back
rescue ::ActionController::RedirectBackError
redirect_to :controller => '/projects', :action => 'show', :id => @project
# we cannot be sure the container actually has a project (example: LandingPage)
if @project
redirect_to :controller => '/projects', :action => 'show', :id => @project
else
redirect_to home_url
end
end
private

@ -35,8 +35,9 @@ class WorkPackagesController < ApplicationController
model_object WorkPackage
before_filter :disable_api
before_filter :find_model_object_and_project, :only => [:show]
before_filter :find_project_by_project_id, :only => [:new, :new_type, :create]
before_filter :find_model_object_and_project, :only => [:show, :edit, :update]
before_filter :find_project_by_project_id, :only => [:new, :create]
before_filter :project, :only => [:new_type]
before_filter :authorize,
:assign_planning_elements
before_filter :apply_at_timestamp, :only => [:show]
@ -47,8 +48,30 @@ class WorkPackagesController < ApplicationController
def show
respond_to do |format|
format.html
format.js { render :partial => 'show'}
format.html do
render :show, :locals => { :work_package => work_package,
:project => project,
:priorities => priorities,
:user => current_user,
:ancestors => ancestors,
:descendants => descendants,
:changesets => changesets,
:relations => relations,
:journals => journals }
end
format.js do
render :show, :partial => 'show', :locals => { :work_package => work_package,
:project => project,
:priorities => priorities,
:user => current_user,
:ancestors => ancestors,
:descendants => descendants,
:changesets => changesets,
:relations => relations,
:journals => journals }
end
format.pdf do
pdf = issue_to_pdf(work_package)
@ -61,22 +84,26 @@ class WorkPackagesController < ApplicationController
def new
respond_to do |format|
format.html
format.html { render :locals => { :work_package => new_work_package,
:project => project,
:priorities => priorities,
:user => current_user } }
end
end
def new_type
respond_to do |format|
format.js { render :partial => 'attributes', :locals => { :work_package => new_work_package,
:project => project,
:priorities => priorities } }
format.js { render :locals => { :work_package => work_package || new_work_package,
:project => project,
:priorities => priorities,
:user => current_user } }
end
end
def create
call_hook(:controller_work_package_new_before_save, { :params => params, :work_package => new_work_package })
WorkPackageObserver.instance.send_notification = params[:send_notification] == '0' ? false : true
WorkPackageObserver.instance.send_notification = send_notifications?
if new_work_package.save
flash[:notice] = I18n.t(:notice_successful_create)
@ -94,6 +121,37 @@ class WorkPackagesController < ApplicationController
end
end
def edit
respond_to do |format|
format.html do
render :edit, :locals => { :work_package => work_package,
:allowed_statuses => allowed_statuses,
:project => project,
:priorities => priorities,
:time_entry => time_entry,
:user => current_user }
end
end
end
def update
configure_update_notification(send_notifications?)
safe_params = permitted_params.update_work_package(:project => project)
updated = work_package.update_by(current_user, safe_params)
render_attachment_warning_if_needed(work_package)
if updated
flash[:notice] = l(:notice_successful_update)
show
else
edit
end
end
def work_package
@work_package ||= begin
@ -218,8 +276,24 @@ class WorkPackagesController < ApplicationController
IssuePriority.all
end
def allowed_statuses
work_package.new_statuses_allowed_to(current_user)
end
def time_entry
work_package.add_time_entry
end
protected
def configure_update_notification(state = true)
JournalObserver.instance.send_notification = state
end
def send_notifications?
params[:send_notification] == '0' ? false : true
end
def assign_planning_elements
@planning_elements = @project.planning_elements.without_deleted
end

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
module WorkPackagesHelper
def work_package_breadcrumb
full_path = ancestors_links.unshift(work_package_index_link)
@ -78,7 +89,7 @@ module WorkPackagesHelper
WorkPackageAttribute = Struct.new(:attribute, :field)
def work_package_form_two_column_attributes(form, work_package, locals = {})
def work_package_form_all_middle_attributes(form, work_package, locals = {})
[
work_package_form_status_attribute(form, work_package, locals),
work_package_form_priority_attribute(form, work_package, locals),
@ -90,13 +101,23 @@ module WorkPackagesHelper
work_package_form_due_date_attribute(form, work_package, locals),
work_package_form_estimated_hours_attribute(form, work_package, locals),
work_package_form_done_ratio_attribute(form, work_package, locals),
].compact
work_package_form_custom_values_attribute(form, work_package, locals)
].flatten.compact
end
def work_package_form_minimal_middle_attributes(form, work_package, locals = {})
[
work_package_form_status_attribute(form, work_package, locals),
work_package_form_assignee_attribute(form, work_package, locals),
work_package_form_assignable_versions_attribute(form, work_package, locals),
work_package_form_done_ratio_attribute(form, work_package, locals),
].flatten.compact
end
def work_package_form_top_attributes(form, work_package, locals = {})
[
work_package_form_type_attribute(form, work_package, locals),
work_package_form_type_attribute(form, work_package, locals),
work_package_form_planning_element_type_attribute(form, work_package, locals),
work_package_form_subject_attribute(form, work_package, locals),
work_package_form_parent_attribute(form, work_package, locals),
work_package_form_description_attribute(form, work_package, locals)
@ -192,8 +213,7 @@ module WorkPackagesHelper
def work_package_show_spent_time_attribute(work_package)
work_package_show_table_row(:spent_time) do
#This check can be removed as soon as spent_hours is part of work_package and not Issue
work_package.respond_to?(:spent_hours) && work_package.spent_hours > 0 ?
work_package.spent_hours > 0 ?
link_to(l_hours(work_package.spent_hours), issue_time_entries_path(work_package)) :
"-"
end
@ -219,16 +239,20 @@ module WorkPackagesHelper
if work_package.is_a?(Issue)
field = form.select :type_id, locals[:project].types.collect {|t| [t.name, t.id]}, :required => true
field += observe_field :work_package_type_id, :url => new_type_project_work_packages_path(locals[:project]),
:update => :attributes,
:method => :get,
:with => "Form.serialize('work_package-form')"
url = work_package.new_record? ?
new_type_project_work_packages_path(locals[:project]) :
new_type_work_package_path(work_package)
field += observe_field :work_package_type_id, :url => url,
:update => :attributes,
:method => :get,
:with => "Form.serialize('work_package-form')"
WorkPackageAttribute.new(:type, field)
end
end
def work_package_form_type_attribute(form, work_package, locals = {})
def work_package_form_planning_element_type_attribute(form, work_package, locals = {})
if work_package.is_a?(PlanningElement)
field = form.select :planning_element_type_id,
(locals[:project].planning_element_types.collect { |m| [m.name, m.id] }),
@ -268,17 +292,17 @@ module WorkPackagesHelper
end
def work_package_form_status_attribute(form, work_package, locals = {})
if work_package.is_a?(Issue)
allowed = work_package.new_statuses_allowed_to(User.current, true)
new_statuses = work_package.new_statuses_allowed_to(locals[:user], true)
field = if allowed.any?
form.select(:status_id, (allowed.map {|p| [p.name, p.id]}), :required => true)
else
form.label(:status) + work_package.status.name
end
field = if new_statuses.any?
form.select(:status_id, (new_statuses.map {|p| [p.name, p.id]}), :required => true)
elsif work_package.status
form.label(:status) + work_package.status.name
else
form.label(:status) + "-"
end
WorkPackageAttribute.new(:status, field)
end
WorkPackageAttribute.new(:status, field)
end
def work_package_form_priority_attribute(form, work_package, locals = {})
@ -342,12 +366,14 @@ module WorkPackagesHelper
end
def work_package_form_estimated_hours_attribute(form, work_package, locals = {})
estimated_hours_field = form.text_field :estimated_hours,
:size => 3,
:disabled => attrib_disabled?(work_package, 'estimated_hours')
estimated_hours_field += TimeEntry.human_attribute_name(:hours)
field = form.text_field :estimated_hours,
:size => 3,
:disabled => attrib_disabled?(work_package, 'estimated_hours'),
:value => number_with_precision(work_package.estimated_hours, :precision => 2)
WorkPackageAttribute.new(:estimated_hours, estimated_hours_field)
field += TimeEntry.human_attribute_name(:hours)
WorkPackageAttribute.new(:estimated_hours, field)
end
def work_package_form_done_ratio_attribute(form, work_package, locals = {})
@ -358,4 +384,12 @@ module WorkPackagesHelper
WorkPackageAttribute.new(:done_ratio, field)
end
end
def work_package_form_custom_values_attribute(form, work_package, locals = {})
work_package.custom_field_values.map do |value|
field = custom_field_tag_with_label :work_package, value
WorkPackageAttribute.new(:"work_package_#{value.id}", field)
end
end
end

@ -144,7 +144,8 @@ class Attachment < ActiveRecord::Base
end
def project
container.project
#not every container has a project (example: LandingPage)
container.respond_to?(:project)? container.project : nil
end
def visible?(user=User.current)

@ -414,15 +414,6 @@ class Issue < WorkPackage
notified.collect(&:mail)
end
# Returns the total number of hours spent on this issue and its descendants
#
# Example:
# spent_hours => 0.0
# spent_hours => 50.2
def spent_hours
@spent_hours ||= self_and_descendants.joins(:time_entries).sum("#{TimeEntry.table_name}.hours").to_f || 0.0
end
# Returns the time scheduled for this issue.
#
# Example:

@ -82,7 +82,13 @@ class PermittedParams < Struct.new(:params, :user)
end
def new_work_package(args = {})
permitted = permitted_attributes(args)
permitted = permitted_attributes(:new_work_package, args)
params[:work_package].permit(*permitted)
end
def update_work_package(args = {})
permitted = permitted_attributes(:new_work_package, args)
params[:work_package].permit(*permitted)
end
@ -120,8 +126,8 @@ class PermittedParams < Struct.new(:params, :user)
protected
def permitted_attributes(args)
merged_args = { :user => user }.merge(args)
def permitted_attributes(key, additions = {})
merged_args = { :params => params, :user => user }.merge(additions)
self.class.permitted_attributes[:new_work_package].map do |permission|
if permission.respond_to?(:call)
@ -151,10 +157,23 @@ class PermittedParams < Struct.new(:params, :user)
:priority_id,
:category_id,
:status_id,
:notes,
{ attachments: [:file, :description] },
Proc.new do |args|
args[:user].allowed_to?(:add_work_package_watchers, args[:project]) ?
{ :watcher_user_ids => [] } :
nil
# avoid costly allowed_to? if the param is not there at all
if args[:params]["work_package"].has_key?("watcher_user_ids") &&
args[:user].allowed_to?(:add_work_package_watchers, args[:project])
{ :watcher_user_ids => [] }
end
end,
Proc.new do |args|
# avoid costly allowed_to? if the param is not there at all
if args[:params]["work_package"].has_key?("time_entry") &&
args[:user].allowed_to?(:log_time, args[:project])
{ time_entry: [:hours, :activity_id, :comments] }
end
end
],
:color_move => [:move_to],

@ -149,7 +149,9 @@ class PlanningElement < WorkPackage
end
end
if self.parent
# TODO: reconsider self.parent.is_a?(PlanningElement)
# once any of the errors can also apply when using issues
if self.parent && self.parent.is_a?(PlanningElement)
errors.add :parent, :cannot_be_milestone if parent.is_milestone?
errors.add :parent, :cannot_be_in_another_project if parent.project != project
errors.add :parent, :cannot_be_in_recycle_bin if parent.deleted?

@ -877,7 +877,7 @@ class Project < ActiveRecord::Base
list
end
# TODO: merge with add_issue once type or similar is defined there and safe_attributes is removed
# TODO: merge with add_issue once type or similar is defined there
def add_planning_element(attributes = {})
attributes ||= {}
@ -886,7 +886,7 @@ class Project < ActiveRecord::Base
end
end
# TODO: merge with add_planning_elemement once type or similar is defined there and safe_attributes is removed
# TODO: merge with add_planning_elemement once type or similar is defined there
def add_issue(attributes = {})
attributes ||= {}
@ -901,8 +901,7 @@ class Project < ActiveRecord::Base
project.types.first
end
# TODO: this should not be necessary once StrongParameters are in place
i.assign_attributes(attributes, :without_protection => true)
i.attributes = attributes
end
end

@ -496,9 +496,9 @@ class Query < ActiveRecord::Base
order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',')
order_option = nil if order_option.blank?
WorkPackage.where(::Query.merge_conditions(statement, options[:conditions]))
.includes([:status, :project] + (options[:include] || []).uniq)
.order(order_option)
Issue.where(::Query.merge_conditions(statement, options[:conditions]))
.includes([:status, :project] + (options[:include] || []).uniq)
.order(order_option)
end
# Returns the journals

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
#
# User for tasks like migrations
#

@ -205,6 +205,11 @@ class WorkPackage < ActiveRecord::Base
self.relations_from.build
end
def add_time_entry
time_entries.build(:project => project,
:work_package => self)
end
def all_dependent_issues(except=[])
except << self
dependencies = []
@ -268,6 +273,23 @@ class WorkPackage < ActiveRecord::Base
!due_date.nil? && (due_date < Date.today) && !closed?
end
# TODO: move into Business Object and rename to update
# update for now is a private method defined by AR
def update_by(user, attributes)
init_journal(user, attributes.delete(:notes)) if attributes[:notes]
raw_attachments = attributes.delete(:attachments)
add_time_entry_for(user, attributes.delete(:time_entry))
if update_attributes(attributes)
# as attach_files always saves an attachment right away
# it is not possible to stage attaching and check for
# valid. If this would be possible, we could check
# for this along with update_attributes
attachments = Attachment.attach_files(self, raw_attachments)
end
end
def recalculate_attributes_for(work_package_id)
if work_package_id.is_a? WorkPackage
p = work_package_id
@ -311,8 +333,35 @@ class WorkPackage < ActiveRecord::Base
end
end
# This is a dummy implementation that is currently overwritten
# by issue
# Adapt once tracker/type is migrated
def new_statuses_allowed_to(user, include_default = false)
IssueStatus.all
end
def self.use_status_for_done_ratio?
Setting.issue_done_ratio == 'issue_status'
end
# Returns the total number of hours spent on this issue and its descendants
#
# Example:
# spent_hours => 0.0
# spent_hours => 50.2
def spent_hours
@spent_hours ||= self_and_descendants.joins(:time_entries)
.sum("#{TimeEntry.table_name}.hours").to_f || 0.0
end
private
def add_time_entry_for(user, attributes)
return if attributes.nil? || attributes.values.all?(&:blank?)
attributes.reverse_merge!({ :user => user,
:spent_on => Date.today })
time_entries.build(attributes)
end
end

@ -1 +1,12 @@
//-- copyright
// OpenProject is a project management system.
//
// Copyright (C) 2012-2013 the OpenProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
I18n.translations = {"en":{"date":{"formats":{"default":"%Y-%m-%d","short":"%b %d","long":"%B %d, %Y"},"day_names":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"abbr_day_names":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"month_names":[null,"January","February","March","April","May","June","July","August","September","October","November","December"],"abbr_month_names":[null,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"order":["year","month","day"]},"time":{"formats":{"default":"%a, %d %b %Y %H:%M:%S %z","short":"%d %b %H:%M","long":"%B %d, %Y %H:%M"},"am":"am","pm":"pm"},"support":{"array":{"words_connector":", ","two_words_connector":" and ","last_word_connector":", and "}},"errors":{"format":"%{attribute} %{message}","messages":{"inclusion":"is not included in the list","exclusion":"is reserved","invalid":"is invalid","confirmation":"doesn't match confirmation","accepted":"must be accepted","empty":"can't be empty","blank":"can't be blank","too_long":"is too long (maximum is %{count} characters)","too_short":"is too short (minimum is %{count} characters)","wrong_length":"is the wrong length (should be %{count} characters)","not_a_number":"is not a number","not_an_integer":"must be an integer","greater_than":"must be greater than %{count}","greater_than_or_equal_to":"must be greater than or equal to %{count}","equal_to":"must be equal to %{count}","less_than":"must be less than %{count}","less_than_or_equal_to":"must be less than or equal to %{count}","odd":"must be odd","even":"must be even"},"template":{"header":{"one":"1 error prohibited this %{model} from being saved","other":"%{count} errors prohibited this %{model} from being saved"},"body":"There were problems with the following fields:"}},"activerecord":{"errors":{"messages":{"taken":"has already been taken","record_invalid":"Validation failed: %{errors}"}}},"number":{"format":{"separator":".","delimiter":",","precision":3,"significant":false,"strip_insignificant_zeros":false},"currency":{"format":{"format":"%u%n","unit":"$","separator":".","delimiter":",","precision":2,"significant":false,"strip_insignificant_zeros":false}},"percentage":{"format":{"delimiter":""}},"precision":{"format":{"delimiter":""}},"human":{"format":{"delimiter":"","precision":3,"significant":true,"strip_insignificant_zeros":true},"storage_units":{"format":"%n %u","units":{"byte":{"one":"Byte","other":"Bytes"},"kb":"KB","mb":"MB","gb":"GB","tb":"TB"}},"decimal_units":{"format":"%n %u","units":{"unit":"","thousand":"Thousand","million":"Million","billion":"Billion","trillion":"Trillion","quadrillion":"Quadrillion"}}}},"datetime":{"distance_in_words":{"half_a_minute":"half a minute","less_than_x_seconds":{"one":"less than 1 second","other":"less than %{count} seconds"},"x_seconds":{"one":"1 second","other":"%{count} seconds"},"less_than_x_minutes":{"one":"less than a minute","other":"less than %{count} minutes"},"x_minutes":{"one":"1 minute","other":"%{count} minutes"},"about_x_hours":{"one":"about 1 hour","other":"about %{count} hours"},"x_days":{"one":"1 day","other":"%{count} days"},"about_x_months":{"one":"about 1 month","other":"about %{count} months"},"x_months":{"one":"1 month","other":"%{count} months"},"about_x_years":{"one":"about 1 year","other":"about %{count} years"},"over_x_years":{"one":"over 1 year","other":"over %{count} years"},"almost_x_years":{"one":"almost 1 year","other":"almost %{count} years"}},"prompts":{"year":"Year","month":"Month","day":"Day","hour":"Hour","minute":"Minute","second":"Seconds"}},"helpers":{"select":{"prompt":"Please select"},"submit":{"create":"Create %{model}","update":"Update %{model}","submit":"Save %{model}"},"button":{"create":"Create %{model}","update":"Update %{model}","submit":"Save %{model}"}}}};

@ -0,0 +1,35 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<%# as field_for requries the usage of nested_attributes or at least
an attachments_attributes= writer we and not every model supports this we build a nested form on our own %>
<% prefix = f.object_name + "[attachments]" %>
<div id="attachments_fields">
<div id="attachment_template" class="attachment_field">
<%= file_field_tag "#{prefix}[1][file]", :size => 15, :id => nil, :class => "attachment_choose_file" -%>
<label class="label-with-input" >
<%= l(:label_optional_description) %>
<%= text_field_tag "#{prefix}[1][description]", '', :size => 38, :id => nil %>
</label>
</div>
</div>
<br />
<span class="add_another_file">
<%= link_to l(:label_add_another_file),
'#',
:onclick => 'addFileField(); return false;' %>
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
</span>

@ -1,3 +1,15 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<% if User.current.impaired? %>
<% partial = "members/member_form_impaired" %>
<% locals = { :members => @project.member_principals.find(:all, :include => [:roles, :principal, :member_roles]) }%>

@ -1,3 +1,15 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<%= form_for(:member,
:url => {:controller => '/members', :action => 'create', :project_id => project},
:method => :post,

@ -1,3 +1,15 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<%= javascript_include_tag "members_select_boxes.js" %>
<%= form_for(:member, :url => {:controller => 'members', :action => 'create', :project_id => project},

@ -1,3 +1,15 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<p>
<label for="set_random_password">
<%=l(:field_random_password)%>

@ -10,33 +10,9 @@ See doc/COPYRIGHT.rdoc for more details.
++#%>
<%= fields_for :work_package, work_package, :builder => TabularFormBuilder do |f| %>
<% attributes = work_package_form_two_column_attributes(f, work_package,
:priorities => priorities,
:project => project) %>
<% attributes = work_package_form_all_middle_attributes(f, work_package,
:priorities => priorities,
:project => project,
:user => user) %>
<% left_attributes, right_attributes = attributes.in_groups(2, false) %>
<div class="splitcontentleft">
<% left_attributes.each do |attribute| %>
<p>
<%= attribute.field %>
</p>
<% end %>
</div>
<div class="splitcontentright">
<% right_attributes.each do |attribute| %>
<p>
<%= attribute.field %>
</p>
<% end %>
</div>
<div style="clear:both;"> </div>
<%= render :partial => 'form_custom_fields', :locals => { :work_package => work_package } %>
<% end %>
<%= render :partial => "two_column_attributes", :locals => { :attributes => attributes } %>

@ -0,0 +1,98 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<% edit_allowed = current_user.allowed_to?(:edit_work_packages, project) %>
<%= labelled_tabular_form_for work_package,
:url => work_package_path(work_package),
# TODO: remove once Issue == PlanningElement
:as => 'work_package',
:html => {
:id => 'work_package-form',
:multipart => true
} do |f| %>
<%= error_messages_for 'work_package' %>
<div class="box">
<% if edit_allowed || !allowed_statuses.empty? %>
<fieldset class="tabular">
<legend>
<%= l(:label_change_properties) %>
<% if !work_package.new_record? && !work_package.errors.any? && edit_allowed %>
<small>
(<%= link_to l(:label_more), {}, :onclick => 'Effect.toggle("work_package_descr_fields", "appear", {duration:0.3}); return false;' %>)
</small>
<% end %>
</legend>
<% edit_form = (edit_allowed ? 'form' : 'form_update') %>
<%= render :partial => edit_form,
:locals => { :f => f,
:work_package => work_package,
:priorities => priorities,
:project => project,
:user => user,
:time_entry => time_entry } %>
</fieldset>
<% end %>
<% if authorize_for('timelog', 'edit') %>
<fieldset class="tabular">
<legend>
<%= l(:button_log_time) %>
</legend>
<%= render :partial => 'time_entry',
:locals => { :time_entry => time_entry,
:f => f } %>
</fieldset>
<% end %>
<fieldset>
<legend>
<%= Journal.human_attribute_name(:notes) %>
</legend>
<%= label_tag "work_package[notes]", Journal.human_attribute_name(:notes),
:class => 'hidden-for-sighted' %>
<%= text_area_tag "work_package[notes]", work_package.journal_notes, :cols => 60,
:rows => 10,
:class => 'wiki-edit' %>
<%= wikitoolbar_for 'work_package_notes' %>
<%= call_hook(:view_issues_edit_notes_bottom, { :issue => work_package,
:notes => work_package.journal_notes,
:form => f }) %>
</fieldset>
<fieldset id="attachments" class="header_collapsible collapsible collapsed">
<legend title="<%=l(:description_attachment_toggle)%>", onclick="toggleFieldset(this);">
<a href="javascript:"><%=l(:label_attachment_plural)%></a>
</legend>
<div style="display: none;">
<%= render :partial => 'attachments/nested_form',
:locals => { :f => f } %>
</div>
</fieldset>
<%= send_notification_option %>
</div>
<%= f.hidden_field :lock_version %>
<%= submit_tag l(:button_submit) %>
<%= link_to_issue_preview(work_package) %>
<% end %>
<div id="preview" class="wiki">
</div>

@ -12,7 +12,7 @@ See doc/COPYRIGHT.rdoc for more details.
<%= call_hook(:view_issues_form_details_top, { :issue => work_package, :form => f }) %>
<div id="issue_descr_fields"<% unless work_package.new_record? || work_package.errors.any? %> style="display:none;"<% end %>>
<div id="work_package_descr_fields"<% unless work_package.new_record? || work_package.errors.any? %> style="display:none;"<% end %>>
<% work_package_form_top_attributes(f, work_package,
:priorities => priorities,
@ -26,9 +26,11 @@ See doc/COPYRIGHT.rdoc for more details.
</div>
<div id="attributes" class="attributes">
<%= render :partial => 'attributes', :locals => { :work_package => work_package,
<%= render :partial => 'attributes', :locals => { :f => f,
:work_package => work_package,
:project => project,
:priorities => priorities
:priorities => priorities,
:user => user
} %>
</div>

@ -1,24 +0,0 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<div class="splitcontentleft">
<% i = 0 %>
<% split_on = (work_package.custom_field_values.size / 2.0).ceil - 1 %>
<% work_package.custom_field_values.each do |value| %>
<p><%= custom_field_tag_with_label :issue, value %></p>
<% if i == split_on -%>
</div><div class="splitcontentright">
<% end -%>
<% i += 1 -%>
<% end -%>
</div>
<div style="clear:both;"> </div>

@ -0,0 +1,21 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<div class="attributes">
<% attributes = work_package_form_minimal_middle_attributes(f, work_package,
:priorities => priorities,
:project => project,
:user => user) %>
<%= render :partial => "two_column_attributes", :locals => { :attributes => attributes } %>
</div>

@ -0,0 +1,40 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<%= f.fields_for :time_entry,
time_entry,
{ :builder => TabularFormBuilder,
:lang => current_language} do |fields| %>
<div class="splitcontentleft">
<p>
<%= fields.text_field :hours,
:label => :label_spent_time %>
<%= TimeEntry.human_attribute_name(:hours) %>
</p>
</div>
<div class="splitcontentright">
<p>
<%= fields.select :activity_id, activity_collection_for_select_options %>
</p>
</div>
<p>
<%= fields.text_field :comments %>
</p>
<% time_entry.custom_field_values.each do |value| %>
<p>
<%= custom_field_tag_with_label :time_entry, value %>
</p>
<% end %>
<% end %>

@ -0,0 +1,32 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<% left_attributes, right_attributes = attributes.in_groups(2, false) %>
<div class="splitcontentleft">
<% left_attributes.each do |attribute| %>
<p>
<%= attribute.field %>
</p>
<% end %>
</div>
<div class="splitcontentright">
<% right_attributes.each do |attribute| %>
<p>
<%= attribute.field %>
</p>
<% end %>
</div>

@ -0,0 +1,23 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<h2><%=h work_package.to_s %></h2>
<%= render :partial => 'edit', :locals => { :work_package => work_package,
:allowed_statuses => allowed_statuses,
:project => project,
:priorities => priorities,
:time_entry => time_entry,
:user => user } %>
<% content_for :header_tags do %>
<%= robot_exclusion_tag %>
<% end %>

@ -27,9 +27,10 @@ See doc/COPYRIGHT.rdoc for more details.
<div class="box">
<%= render :partial => 'form', :locals => { :f => f,
:work_package => controller.new_work_package,
:project => controller.project,
:priorities => controller.priorities } %>
:work_package => work_package,
:project => project,
:priorities => priorities,
:user => user } %>
<%= send_notification_option %>
</div>

@ -0,0 +1,19 @@
<%#-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2013 the OpenProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
See doc/COPYRIGHT.rdoc for more details.
++#%>
<%= fields_for :work_package, work_package, :builder => TabularFormBuilder do |f| %>
<%= render :partial => 'attributes', :locals => { :f => f,
:work_package => work_package,
:priorities => priorities,
:project => project,
:user => user } %>
<% end %>

@ -11,21 +11,21 @@ See doc/COPYRIGHT.rdoc for more details.
++#%>
<%= header_tags %>
<%= render :partial => 'work_packages/action_menu', :locals => { work_package: controller.work_package } %>
<%= render :partial => 'work_packages/action_menu', :locals => { work_package: work_package } %>
<% work_package_breadcrumb %>
<%= content_tag('h2', controller.work_package.to_s) %>
<%= content_tag('h2', work_package.to_s) %>
<div class = "details">
<div class="profile-wrap">
<%= avatar(controller.work_package.author, :size => "40") %>
<%= avatar(work_package.author, :size => "40") %>
</div>
<p class="author">
<%= authoring controller.work_package.created_at, controller.work_package.author %>.
<% if controller.work_package.created_at != controller.work_package.updated_at %>
<%= l(:label_updated_time, time_tag(controller.work_package.updated_at)).html_safe %>.
<%= authoring work_package.created_at, work_package.author %>.
<% if work_package.created_at != work_package.updated_at %>
<%= l(:label_updated_time, time_tag(work_package.updated_at)).html_safe %>.
<% end %>
</p>
@ -34,7 +34,7 @@ See doc/COPYRIGHT.rdoc for more details.
<div class="issue details">
<div class="meta">
<table class="attributes">
<% work_package_show_attributes(controller.work_package).each_slice(2) do |attributes| %>
<% work_package_show_attributes(work_package).each_slice(2) do |attributes| %>
<tr>
<% attributes.each do |attribute| %>
@ -44,67 +44,67 @@ See doc/COPYRIGHT.rdoc for more details.
</tr>
<% end %>
<%= render_custom_fields_rows(controller.work_package) %>
<%= call_hook(:view_issues_show_details_bottom, :issue => controller.work_package) %>
<%= render_custom_fields_rows(work_package) %>
<%= call_hook(:view_issues_show_details_bottom, :issue => work_package) %>
</table>
</div>
</div>
<% if controller.work_package.description? %>
<% if work_package.description? %>
<div class="description">
<hr />
<div class="contextual">
<%= link_to_if_authorized(l(:button_quote), { :controller => '/issues', :action => 'quoted', :id => controller.work_package }, :class => 'quote-link icon icon-comment') %>
<%= link_to_if_authorized(l(:button_quote), { :controller => '/issues', :action => 'quoted', :id => work_package }, :class => 'quote-link icon icon-comment') %>
</div>
<p><strong><%= Issue.human_attribute_name(:description)%></strong></p>
<div class="wiki wikicontent" data-user="<%= controller.work_package.author %>">
<%= textilizable controller.work_package, :description, :attachments => controller.work_package.attachments %>
<div class="wiki wikicontent" data-user="<%= work_package.author %>">
<%= textilizable work_package, :description, :attachments => work_package.attachments %>
</div>
<hr />
</div>
<% end %>
<% if controller.work_package.attachments.any? -%>
<%= link_to_attachments controller.work_package %>
<% if work_package.attachments.any? -%>
<%= link_to_attachments work_package %>
<% end -%>
<%= call_hook(:view_issues_show_description_bottom, :issue => controller.work_package) %>
<%= call_hook(:view_issues_show_description_bottom, :issue => work_package) %>
<hr />
<%= render :partial => 'subwork_packages_paragraph', :locals => { :work_package => controller.work_package,
:ancestors => controller.ancestors,
:descendants => controller.descendants } %>
<%= render :partial => 'subwork_packages_paragraph', :locals => { :work_package => work_package,
:ancestors => ancestors,
:descendants => descendants } %>
<% if authorize_for('work_package_relations', 'create') || controller.relations.present? %>
<% if authorize_for('work_package_relations', 'create') || relations.present? %>
<div id="relations">
<hr />
<%= render :partial => 'relations', :locals => { :work_package => controller.work_package,
:relations => controller.relations } %>
<%= render :partial => 'relations', :locals => { :work_package => work_package,
:relations => relations } %>
</div>
<% end %>
<% if User.current.allowed_to?(:add_work_package_watchers, controller.project) ||
(controller.work_package.watchers.present? && User.current.allowed_to?(:view_work_package_watchers, controller.project)) %>
<% if User.current.allowed_to?(:add_work_package_watchers, project) ||
(work_package.watchers.present? && User.current.allowed_to?(:view_work_package_watchers, project)) %>
<div id="watchers">
<hr />
<%= render :partial => 'watchers/watchers', :locals => {:watched => controller.work_package} %>
<%= render :partial => 'watchers/watchers', :locals => {:watched => work_package} %>
</div>
<% end %>
</div>
<div style="clear: both;"></div>
<% if controller.changesets.present? %>
<% if changesets.present? %>
<div id="work_package-changesets">
<h3><%=l(:label_associated_revisions)%></h3>
<%= render :partial => 'changesets', :locals => { :changesets => controller.changesets} %>
<%= render :partial => 'changesets', :locals => { :changesets => changesets} %>
</div>
<% end %>
<% if controller.journals.present? %>
<% if journals.present? %>
<div id="history">
<h3><%=l(:label_history)%></h3>
<%= render :partial => 'history', :locals => { :work_package => controller.work_package, :journals => controller.journals } %>
<%= render :partial => 'history', :locals => { :work_package => work_package, :journals => journals } %>
</div>
<% end %>
@ -126,14 +126,14 @@ See doc/COPYRIGHT.rdoc for more details.
<%= f.link_to 'PDF' %>
<% end %>
<% html_title h(controller.work_package.to_s) %>
<% html_title h(work_package.to_s) %>
<% content_for :sidebar do %>
<%= render :partial => 'issues/sidebar' %>
<% end %>
<% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{controller.work_package.project} - #{controller.work_package.type} ##{controller.work_package.id}: #{controller.work_package.subject}") %>
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{work_package.project} - #{work_package.to_s}") %>
<%= stylesheet_link_tag 'context_menu_rtl' if l(:direction) == 'rtl' %>
<% end %>
<div id="context-menu" style="display: none;"></div>

@ -1,8 +1,8 @@
<%
rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --tags ~@wip"
%>
default: <%= std_opts %> features
wip: --tags @wip:3 --wip features
rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip
rerun: <%= rerun_opts %> --format rerun --out rerun.txt --tags ~@wip

@ -53,11 +53,7 @@ de:
enumeration:
active: "Aktiv"
issue:
done_ratio: "% erledigt"
fixed_version: "Zielversion"
parent: "Übergeordnete Aufgabe"
parent_issue: "Übergeordnete Aufgabe"
priority: "Priorität"
subproject: "Unterprojekt von"
time_entries: "Logzeit"
type: "Typ"
@ -98,10 +94,8 @@ de:
alternate_dates:
due_date: "Abschlussdatum des alternativen Datums"
description: "Beschreibung"
due_date: "Abschlussdatum"
id: "ID"
name: "Name"
parent: "Eltern-Element"
planning_element_type: "Typ"
start_date: "Startdatum"
planning_element_type:
@ -157,6 +151,10 @@ de:
parent_title: "Übergeordnete Seite"
redirect_existing_links: "Existierende Links umleiten"
work_package:
done_ratio: "% erledigt"
fixed_version: "Zielversion"
parent: "Übergeordnete Aufgabe"
priority: "Priorität"
progress: "% erledigt"
responsible: "Planungsverantwortlicher"
spent_time: "Aufgewendete Zeit"
@ -1131,6 +1129,7 @@ de:
permission_view_wiki_edits: "Wiki-Versionsgeschichte ansehen"
permission_view_wiki_pages: "Wiki ansehen"
project_module_activity: "Aktivität"
project_module_boards: "Foren"
project_module_calendar: "Kalender"
project_module_documents: "Dokumente"

@ -52,11 +52,7 @@ en:
enumeration:
active: "Active"
issue:
done_ratio: "% Done"
fixed_version: "Target version"
parent: "Parent"
parent_issue: "Parent"
priority: "Priority"
subproject: "Subproject"
time_entries: "Log time"
type: "Type"
@ -127,10 +123,8 @@ en:
alternate_dates:
due_date: End date of alternate date
description: Description
due_date: "End date"
id: ID
name: Name
parent: Parent element
planning_element_type: "Type"
start_date: Start date
deleted_at: Deleted at
@ -162,6 +156,10 @@ en:
reported_project_status: Project status
created_at: Created
work_package:
done_ratio: "% done"
fixed_version: "Target version"
parent: Parent
priority: "Priority"
progress: "% done"
responsible: "Responsible"
spent_time: "Spent time"
@ -1106,6 +1104,7 @@ en:
permission_view_wiki_edits: "View wiki history"
permission_view_wiki_pages: "View wiki"
project_module_activity: "Activity"
project_module_boards: "Forums"
project_module_calendar: "Calendar"
project_module_documents: "Documents"

@ -298,7 +298,9 @@ OpenProject::Application.routes.draw do
end
end
resources :work_packages, :only => [:show] do
resources :work_packages, :only => [:show, :edit, :update] do
get :new_type, :on => :member
resources :relations, :controller => 'work_package_relations', :only => [:create, :destroy]
end
@ -462,9 +464,6 @@ OpenProject::Application.routes.draw do
end
end
resources :work_packages, :controller => 'work_packages' do
end
resources :planning_elements, :controller => 'planning_elements' do
collection do
get :all

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
class RemoveTimelinesNamespace < ActiveRecord::Migration
def self.up

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
class CreateWorkPackages < ActiveRecord::Migration
def up
create_table "work_packages" do |t|

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
class RenameEndDateOnAlternateDates < ActiveRecord::Migration
def change
rename_column :alternate_dates, :end_date, :due_date

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
class RemoveEndDateFromWorkPackages < ActiveRecord::Migration
def up
# This operation is destructive. The end dates of work packages will

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
class RenameTrackersToTypes < ActiveRecord::Migration
# This migration leaves legacy issues as they are. After this

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
class RenameWorkPackageStiColumn < ActiveRecord::Migration
def up
rename_column :work_packages, :type, :sti_type

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
class AddActivityModule < ActiveRecord::Migration
def up
# activate activity module for all projects

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
class IncreaseJournalsChangedDataLimit < ActiveRecord::Migration
def up

@ -1,5 +1,10 @@
# Changelog
* `#1246` Implement uniform "edit" action/view for pe & issues
* `#1247` Implement uniform "update" action for pe & issues
## 3.0.0pre9
* `#1517` Journal changed_data cannot contain the changes of a wiki_content content
* `#779` Integrate password expiration
* `#1461` Integration Activity Plugin

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Feature: Administring the enumerations
Scenario: Creating an enumeration

@ -45,7 +45,7 @@ Feature: Issue edit
And I fill in "2013-06-18" for "Start date"
And I fill in "2013-07-18" for "Due date"
And I fill in "7" for "Estimated time"
And I select "50 %" from "% Done"
And I select "50 %" from "% done"
And I submit the form by the "Create" button
Then I should see "Successful creation."

@ -1,5 +1,4 @@
#-- copyright
#
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Feature: Doing Ajax when logged out
Background:
And there is 1 user with:
@ -24,8 +35,8 @@ Feature: Doing Ajax when logged out
And I am logged in as "manager"
And there are the following planning elements:
| Subject | Start date | Due date | description | status_name | responsible |
| January | 2012-01-01 | 2012-01-31 | Aioli Grande | closed | manager |
| Subject |
| January |
@javascript
Scenario: If we do ajax while being logged out a confirm dialog should open

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Feature: Error Messages
Background:

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Feature: Membership
Background:

@ -65,7 +65,7 @@ Feature: Planning Element Management
And I follow "New planning element"
And I fill in "February" for "Subject"
And I fill in "2012-02-01" for "Start date"
And I fill in "2012-02-29" for "End date"
And I fill in "2012-02-29" for "Due date"
And I submit the form by the "Create" button
Then I should see a notice flash stating "Successful creation."
And I should see "February"
@ -108,7 +108,7 @@ Feature: Planning Element Management
When I go to the page of the planning element "January" of the project called "ecookbook"
When I click on "Update" within "#content > .action_menu_main"
When I fill in "2012-02-01" for "worst case Start date"
And I fill in "2012-02-29" for "worst case End date"
And I fill in "2012-02-29" for "worst case Due date"
And I press "Save"
Then I should see "Scenario worst case: Start date changed from 01/01/2013 to 02/01/2012"
And I should see "Scenario worst case: Due date changed from 01/31/2013 to 02/29/2012"

@ -46,8 +46,8 @@ Feature: Planning elements textile quickinfo links
| Name |
| closed |
Given there are the following planning elements:
| Subject | Start date | Due date | description | status_name | responsible |
| January | 2012-01-01 | 2012-01-31 | Avocado Sali Grande Grande | closed | manager |
| Subject | Start date | Due date | description | planning_element_status | responsible |
| January | 2012-01-01 | 2012-01-31 | Avocado Sali Grande Grande | closed | manager |
Scenario: Adding a planning element link
Given I am admin

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Feature: Project Settings
Background:
Given there is 1 project with the following:

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Feature: Creating Projects
Background:
Given there is 1 project with the following:

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Feature: As an admin
I want to administrate roles with permissions
So that I can modify permissions of roles

@ -44,3 +44,28 @@ Given /^the [pP]roject(?: "([^\"]+?)")? uses the following types:$/ do |project,
project.update_attributes :type_ids => types.map(&:id).map(&:to_s)
end
Then(/^I should see the following fields:$/) do |table|
table.rows.each do |field, value|
# enforce matches including the value only if it is provided
# i.e. the column in the table is created
if value
begin
found = find_field(field)
rescue Capybara::ElementNotFound
raise Capybara::ExpectationNotMet, "expected to find field \"#{field}\" but there were no matches."
end
if found.tag_name == "select" && value.present?
should have_select(field, :selected => value)
else
found.value.should == value
end
else
should have_field(field)
end
end
end

@ -14,8 +14,8 @@
RouteMap.register(const, "/custom_fields")
end
Given /^the following (user|issue) custom fields are defined:$/ do |type, table|
type = (type + "_custom_field").to_sym
Given /^the following (user|issue|work package) custom fields are defined:$/ do |type, table|
type = (type.gsub(" ", "_") + "_custom_field").to_sym
as_admin do
table.hashes.each_with_index do |r, i|
@ -43,6 +43,14 @@ Given /^the user "(.+?)" has the user custom field "(.+?)" set to "(.+?)"$/ do |
user.save!
end
Given /^the work package "(.+?)" has the custom field "(.+?)" set to "(.+?)"$/ do |wp_name, field_name, value|
wp = InstanceFinder.find(WorkPackage, wp_name)
custom_field = InstanceFinder.find(WorkPackageCustomField, field_name)
wp.custom_values.build(:custom_field => custom_field, :value => value)
wp.save!
end
Given /^the custom field "(.+)" is( not)? summable$/ do |field_name, negative|
custom_field = WorkPackageCustomField.find_by_name(field_name)

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
def last_email
ActionMailer::Base.deliveries.last

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
When(/^I create a new enumeration with the following:$/) do |table|
attributes = table.rows_hash

@ -138,23 +138,6 @@ Given /^the [Uu]ser "([^\"]*)" has the following preferences$/ do |user, table|
send_table_to_object(u.pref, table)
end
Given /^there is a(?:n)? (default )?(?:issue)?status with:$/ do |default, table|
name = table.raw.select { |ary| ary.include? "name" }.first[table.raw.first.index("name") + 1].to_s
IssueStatus.find_by_name(name) || IssueStatus.create(:name => name.to_s, :is_default => !!default)
end
Given /^there is a(?:n)? (default )?issuepriority with:$/ do |default, table|
name = table.raw.select { |ary| ary.include? "name" }.first[table.raw.first.index("name") + 1].to_s
project = get_project
IssuePriority.new.tap do |prio|
prio.name = name
prio.is_default = !!default
prio.project = project
prio.save!
end
end
Given /^there is a [rR]ole "([^\"]*)"$/ do |name|
Role.spawn.tap { |r| r.name = name }.save! unless Role.find_by_name(name)
end
@ -261,18 +244,6 @@ Given /^the [Pp]roject "([^\"]*)" has (\d+) [Dd]ocument with(?: the following)?:
end
end
Given /^the [Pp]roject (.+) has 1 version with(?: the following)?:$/ do |project, table|
project.gsub!("\"", "")
p = Project.find_by_name(project) || Project.find_by_identifier(project)
table.rows_hash["effective_date"] = eval(table.rows_hash["effective_date"]).to_date if table.rows_hash["effective_date"]
as_admin do
v = Version.generate
send_table_to_object(v, table)
p.versions << v
end
end
Given /^the [pP]roject "([^\"]*)" has 1 [sS]ubproject$/ do |project|
parent = Project.find_by_name(project)
p = Project.generate

@ -0,0 +1,18 @@
# encoding: utf-8
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Then /I should see a journal with the following:$/ do |table|
if table.rows_hash["Notes"]
should have_css(".journal", :text => table.rows_hash["Notes"])
end
end

@ -0,0 +1,12 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
InstanceFinder.register(PlanningElementStatus, Proc.new { |name| PlanningElementStatus.find_by_name(name) })

@ -1,19 +1,36 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Given (/^there are the following planning elements(?: in project "([^"]*)")?:$/) do |project_name, table|
project = get_project(project_name)
table.map_headers! { |header| header.underscore.gsub(' ', '_') }
table.hashes.each do |type_attributes|
status = PlanningElementStatus.find_by_name(type_attributes.delete("status_name"))
responsible = User.find_by_login(type_attributes.delete("responsible"))
planning_element_type = PlanningElementType.find_by_name(type_attributes.delete("planning_element_type"));
factory = FactoryGirl.create(:planning_element, type_attributes.merge(:project_id => project.id))
factory.reload
[
["planning_element_status", PlanningElementStatus],
["responsible", User],
["assigned_to", User],
["planning_element_type", PlanningElementType],
["fixed_version", Version],
["priority", IssuePriority],
["parent", WorkPackage]
].each do |key, const|
if type_attributes[key].present?
type_attributes[key] = InstanceFinder.find(const, type_attributes[key])
else
type_attributes.delete(key)
end
end
factory.planning_element_status = status unless status.nil?
factory.responsible = responsible unless responsible.nil?
factory.planning_element_type = planning_element_type unless planning_element_type.nil?
factory.save! if factory.changed?
factory = FactoryGirl.create(:planning_element, type_attributes.merge(:project_id => project.id))
end
end

@ -11,6 +11,6 @@
# change from symbol to constant once namespace is removed
InstanceFinder.register(:planning_element_type, Proc.new { |name| PlanningElementType.find_by_name(name) })
InstanceFinder.register(PlanningElementType, Proc.new { |name| PlanningElementType.find_by_name(name) })
RouteMap.register(PlanningElementType, "/planning_element_types")

@ -0,0 +1,36 @@
# encoding: utf-8
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
InstanceFinder.register(IssuePriority, Proc.new{ |name| IssuePriority.find_by_name(name) })
Given /^there is a(?:n)? (default )?issuepriority with:$/ do |default, table|
name = table.raw.select { |ary| ary.include? "name" }.first[table.raw.first.index("name") + 1].to_s
project = get_project
FactoryGirl.build(:priority).tap do |prio|
prio.name = name
prio.is_default = !!default
prio.project = project
end.save!
end
Given /^there are the following priorities:$/ do |table|
table.hashes.each do |row|
project = get_project
FactoryGirl.build(:priority).tap do |prio|
prio.name = row[:name]
prio.is_default = row[:default] == "true"
prio.project = project
end.save!
end
end

@ -9,6 +9,19 @@
# See doc/COPYRIGHT.rdoc for more details.
#++
InstanceFinder.register(ProjectType, Proc.new { |name| ProjectType.find_by_name(name) })
Given /^the project(?: named "([^"]*)")? has no project type$/ do |name|
project = get_project(name)
project.update_attribute(:project_type_id, nil)
end
Given /^the project(?: named "([^"]*)")? is of the type "([^"]*)"$/ do |name, type_name|
type_id = ProjectType.select(:id).find_by_name(type_name).id
project = get_project(name)
project.update_attribute(:project_type_id, type_id)
end
When /^I follow the edit link of the project type "([^"]*)"$/ do |project_type_name|
type = ProjectType.find_by_name(project_type_name)
@ -16,3 +29,4 @@ When /^I follow the edit link of the project type "([^"]*)"$/ do |project_type_n
click_link(type.name, :href => href)
end

@ -0,0 +1,25 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Given /^there is a(?:n)? (default )?(?:issue)?status with:$/ do |default, table|
name = table.raw.select { |ary| ary.include? "name" }.first[table.raw.first.index("name") + 1].to_s
IssueStatus.find_by_name(name) || IssueStatus.create(:name => name.to_s, :is_default => !!default)
end
Given /^there are the following status:$/ do |table|
table.hashes.each do |row|
attributes = row.inject({}) { |mem, (k, v)| mem[k.to_sym] = v if v.present?; mem }
attributes[:is_default] = attributes.delete(:default) == "true"
FactoryGirl.create(:issue_status, attributes)
end
end

@ -81,10 +81,6 @@ Given /^there is a scenario "([^"]*)" in project "([^"]*)"$/ do |scenario_name,
FactoryGirl.create(:scenario, :name => scenario_name, :project_id => Project.find_by_name!(project_name).id)
end
#Factory.create(:timelines_reporting, :project => add_project, :reporting_to_project => Project.find(identifier))
Given /^there are the following alternate dates for "([^"]*)":$/ do |scenario_name, table|
scenario = Scenario.find_by_name!(scenario_name)
@ -108,11 +104,6 @@ Given /^there are the following projects of type "([^"]*)":$/ do |project_type_n
end
end
Given /^the project(?: named "([^"]*)")? has no project type$/ do |name|
project = get_project(name)
project.update_attribute(:project_type_id, nil)
end
Given /^there are the following project associations:$/ do |table|
table.map_headers! { |h| h.delete(' ').underscore }

@ -9,9 +9,13 @@
# See doc/COPYRIGHT.rdoc for more details.
#++
InstanceFinder.register(User, Proc.new { |name| User.find_by_login(name) })
##
# Editing/creating users (admin UI)
#
#
When /^I create a new user$/ do
visit '/users/new'
fill_in('user_login', :with => 'newbobby')

@ -0,0 +1,29 @@
# encoding: utf-8
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
#
InstanceFinder.register(Version, Proc.new { |name| Version.find_by_name(name) })
Given /^the [Pp]roject (.+) has 1 version with(?: the following)?:$/ do |project, table|
project.gsub!("\"", "")
p = Project.find_by_name(project) || Project.find_by_identifier(project)
table.rows_hash["effective_date"] = eval(table.rows_hash["effective_date"]).to_date if table.rows_hash["effective_date"]
as_admin do
v = FactoryGirl.build(:version) do |v|
v.project = p
end
send_table_to_object(v, table)
end
end

@ -88,12 +88,18 @@ end
# | Note | Nice guy |
# | Wants Email? | |
#
# TODO: Add support for checkbox, select or option
# TODO: Add support for checkbox and option
# based on naming conventions.
#
When /^(?:|I )fill in the following:$/ do |fields|
fields.rows_hash.each do |name, value|
step(%{I fill in "#{name}" with "#{value}"})
field = find_field(name)
if field.tag_name == "select"
step(%{I select "#{value}" from "#{name}"})
else
step(%{I fill in "#{name}" with "#{value}"})
end
end
end

@ -13,6 +13,11 @@
require "rack_session_access/capybara"
InstanceFinder.register(WorkPackage, Proc.new { |name| WorkPackage.find_by_subject(name) })
RouteMap.register(WorkPackage, "/work_packages")
RouteMap.register(PlanningElement, "/work_packages")
RouteMap.register(Issue, "/work_packages")
Given /^the work package "(.*?)" has the following children:$/ do |work_package_subject, table|
parent = WorkPackage.find_by_subject(work_package_subject)
@ -48,3 +53,42 @@ Given(/^the work_package "(.+?)" is updated with the following:$/) do |subject,
send_table_to_object(work_package, table)
end
When /^I fill in the id of work package "(.+?)" into "(.+?)"$/ do |wp_name, field_name|
work_package = InstanceFinder.find(WorkPackage, wp_name)
fill_in(field_name, :with => wp_name)
end
Then /^the "(.+?)" field should contain the id of work package "(.+?)"$/ do |field_name, wp_name|
work_package = InstanceFinder.find(WorkPackage, wp_name)
should have_field(field_name, :with => work_package.id.to_s)
end
Then /^the work package "(.+?)" should be shown as the parent$/ do |wp_name|
work_package = InstanceFinder.find(WorkPackage, wp_name)
should have_css("tr.work-package", :text => work_package.to_s)
end
Then /^the work package should be shown with the following values:$/ do |table|
table_attributes = table.raw.select do |k, v|
!["Subject", "Type", "Description"].include?(k)
end
table_attributes.each do |key, value|
label = find('th', :text => key)
should have_css("td.#{label[:class]}", :text => value)
end
if table.rows_hash["Type"] || table.rows_hash["Subject"]
expected_header = Regexp.new("#{table.rows_hash["Type"]}\\s?#\\d+: #{table.rows_hash["Subject"]}")
should have_css("h2", :text => expected_header)
end
if table.rows_hash["Description"]
should have_css(".description", :text => table.rows_hash["Description"])
end
end

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Capybara.register_driver :selenium_with_firebug do |app|
Capybara::Selenium::Driver
profile = Selenium::WebDriver::Firefox::Profile.new

@ -51,14 +51,14 @@ Feature: Timeline View Tests
And the user "manager" is a "manager"
And I am logged in as "manager"
And I am already logged in as "manager"
And there are the following planning elements:
| Subject | Start date | Due date | description | status_name | responsible |
| January | 2012-01-01 | 2012-01-31 | Aioli Grande | closed | manager |
| February | 2012-02-01 | 2012-02-24 | Aioli Sali | closed | manager |
| March | 2012-03-01 | 2012-03-30 | Sali Grande | closed | manager |
| April | 2012-04-01 | 2012-04-30 | Aioli Sali Grande | closed | manager |
| Subject | Start date | Due date | description | planning_element_status | responsible |
| January | 2012-01-01 | 2012-01-31 | Aioli Grande | closed | manager |
| February | 2012-02-01 | 2012-02-24 | Aioli Sali | closed | manager |
| March | 2012-03-01 | 2012-03-30 | Sali Grande | closed | manager |
| April | 2012-04-01 | 2012-04-30 | Aioli Sali Grande | closed | manager |
| IchBinEinSoLangesPlannungselementIchMacheAllehierkRanKundDaNnaUcHnOcHdieseGroßUNDKleinSchReiBungWieklEiNeKinDer | 2012-04-01 | 2012-04-30 | Devilish | closed | manager |
Scenario: The project manager gets 'No data to display' when there are no planning elements defined

@ -74,11 +74,11 @@ Feature: Timeline View Tests with reporters
| timelines |
And there are the following planning elements:
| Subject | Start date | Due date | description | status_name | responsible | planning element type |
| January | 2012-01-01 | 2012-01-31 | Aioli Grande | closed | manager | Phase1 |
| February | 2012-02-01 | 2012-02-24 | Aioli Sali | closed | manager | Phase2 |
| March | 2012-03-01 | 2012-03-30 | Sali Grande | closed | manager | Phase3 |
| April | 2012-04-01 | 2012-04-30 | Aioli Sali Grande | closed | manager | Phase4 |
| Subject | Start date | Due date | description | planning_element_status | responsible | planning element type |
| January | 2012-01-01 | 2012-01-31 | Aioli Grande | closed | manager | Phase1 |
| February | 2012-02-01 | 2012-02-24 | Aioli Sali | closed | manager | Phase2 |
| March | 2012-03-01 | 2012-03-30 | Sali Grande | closed | manager | Phase3 |
| April | 2012-04-01 | 2012-04-30 | Aioli Sali Grande | closed | manager | Phase4 |
And there is a project named "ecookbook13" of type "Standard Project"
@ -89,11 +89,11 @@ Feature: Timeline View Tests with reporters
| timelines |
And there are the following planning elements:
| Subject | Start date | Due date | description | status_name | responsible |
| January13 | 2013-01-01 | 2013-01-31 | Aioli Grande | closed | manager |
| February13 | 2013-02-01 | 2013-02-24 | Aioli Sali | closed | manager |
| March13 | 2013-03-01 | 2013-03-30 | Sali Grande | closed | manager |
| April13 | 2013-04-01 | 2013-04-30 | Aioli Sali Grande | closed | manager |
| Subject | Start date | Due date | description | planning_element_status | responsible |
| January13 | 2013-01-01 | 2013-01-31 | Aioli Grande | closed | manager |
| February13 | 2013-02-01 | 2013-02-24 | Aioli Sali | closed | manager |
| March13 | 2013-03-01 | 2013-03-30 | Sali Grande | closed | manager |
| April13 | 2013-04-01 | 2013-04-30 | Aioli Sali Grande | closed | manager |
And there is a project named "ecookbook_q3" of type "Extraordinary Project"
And the project "ecookbook_q3" has the parent "ecookbook13"
@ -104,10 +104,10 @@ Feature: Timeline View Tests with reporters
| timelines |
And there are the following planning elements:
| Subject | Start date | Due date | description | status_name | responsible |
| July | 2012-07-01 | 2013-07-31 | Aioli Grande | closed | manager |
| August | 2012-08-01 | 2013-08-31 | Aioli Sali | closed | manager |
| Septembre | 2012-09-01 | 2013-09-30 | Sali Grande | closed | manager |
| Subject | Start date | Due date | description | planning_element_status | responsible |
| July | 2012-07-01 | 2013-07-31 | Aioli Grande | closed | manager |
| August | 2012-08-01 | 2013-08-31 | Aioli Sali | closed | manager |
| Septembre | 2012-09-01 | 2013-09-30 | Sali Grande | closed | manager |

@ -63,11 +63,11 @@ Feature: Timeline Wiki Macro
| Name |
| closed |
And there are the following planning elements:
| Subject | Start date | Due date | description | status_name | responsible |
| January | 2012-01-01 | 2012-01-31 | Avocado Grande | closed | manager |
| February | 2012-02-01 | 2012-02-24 | Avocado Sali | closed | manager |
| March | 2012-03-01 | 2012-03-30 | Sali Grande | closed | manager |
| April | 2012-04-01 | 2012-04-30 | Avocado Sali Grande | closed | manager |
| Subject | Start date | Due date | description | planning_element_status | responsible |
| January | 2012-01-01 | 2012-01-31 | Avocado Grande | closed | manager |
| February | 2012-02-01 | 2012-02-24 | Avocado Sali | closed | manager |
| March | 2012-03-01 | 2012-03-30 | Sali Grande | closed | manager |
| April | 2012-04-01 | 2012-04-30 | Avocado Sali Grande | closed | manager |
And there is a timeline "Testline" for project "ecookbook"
@javascript

@ -1,5 +1,4 @@
#-- copyright
#
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team

@ -0,0 +1,95 @@
Feature: Fields editable on work package edit
Background:
Given there is 1 user with:
| login | manager |
| firstname | the |
| lastname | manager |
And there is a role "manager"
And there is 1 project with the following:
| identifier | ecookbook |
| name | ecookbook |
And I am working in project "ecookbook"
And the user "manager" is a "manager"
And I am already logged in as "manager"
@javascript
Scenario: Going to the page and viewing all the fields
Given there are the following planning element types:
| Name | Is Milestone | In aggregation |
| Phase | false | true |
And there are the following project types:
| Name |
| Standard Project |
And the following planning element types are default for projects of type "Standard Project"
| Phase |
And the project named "ecookbook" is of the type "Standard Project"
And there is an issuepriority with:
| name | prio1 |
And the role "manager" may have the following rights:
| edit_work_packages |
| manage_subtasks |
And the project "ecookbook" has 1 version with:
| name | version1 |
And there are the following planning elements in project "ecookbook":
| subject | description | start_date | due_date | done_ratio | planning_element_type | responsible | assigned_to | priority | parent | estimated_hours | fixed_version |
| parentpe | | | | 0 | Phase | | | prio1 | | | |
| pe1 | pe1 description | 2013-01-01 | 2013-12-31 | 30 | Phase | manager | manager | prio1 | parentpe | 5 | version1 |
When I go to the edit page of the work package called "pe1"
And I follow "More"
Then I should see the following fields:
| Type | Phase1 |
| Subject | pe1 |
| Description | pe1 description |
| Priority | prio1 |
| Assignee | the manager |
| Responsible | the manager |
| Target version | version1 |
| Start date | 2013-01-01 |
| Due date | 2013-12-31 |
| Estimated time | 5.00 |
| % done | 30 % |
| Notes | |
And the "Parent" field should contain the id of work package "parentpe"
Scenario: Going to the page and viewing timelog fields if this module is enabled
Given the role "manager" may have the following rights:
| edit_work_packages |
| log_time |
And there are the following planning elements in project "ecookbook":
| subject |
| pe1 |
And the project "ecookbook" uses the following modules:
| time_tracking |
And there is an activity "design"
When I go to the edit page of the work package called "pe1"
Then I should see the following fields:
| Spent time |
| Activity |
| Comment |
Scenario: Going to the page and viewing custom field fields
Given the role "manager" may have the following rights:
| edit_work_packages |
Given the following work package custom fields are defined:
| name | type |
| cf1 | int |
And there are the following planning elements in project "ecookbook":
| subject |
| pe1 |
And the work package "pe1" has the custom field "cf1" set to "4"
When I go to the edit page of the work package called "pe1"
Then I should see the following fields:
| cf1 | 4 |

@ -0,0 +1,43 @@
#-- copyright
#
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Feature: Logging time on work package update
Background:
Given there is 1 user with:
| login | manager |
| firstname | the |
| lastname | manager |
And there is 1 project with the following:
| identifier | ecookbook |
| name | ecookbook |
And there is a role "manager"
And the role "manager" may have the following rights:
| edit_work_packages |
| view_work_packages |
| log_time |
And I am working in project "ecookbook"
And the user "manager" is a "manager"
And there are the following planning elements in project "ecookbook":
| subject |
| pe1 |
And there is an activity "design"
And I am already logged in as "manager"
@javascript
Scenario: Logging time
When I go to the edit page of the work package called "pe1"
And I follow "More"
And I fill in the following:
| Subject | |
And I submit the form by the "Submit" button
Then I should see an error explanation stating "Subject can't be blank"

@ -0,0 +1,47 @@
#-- copyright
#
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
#
Feature: Logging time on work package update
Background:
Given there is 1 user with:
| login | manager |
| firstname | the |
| lastname | manager |
And there is 1 project with the following:
| identifier | ecookbook |
| name | ecookbook |
And there is a role "manager"
And the role "manager" may have the following rights:
| edit_work_packages |
| view_work_packages |
| log_time |
And I am working in project "ecookbook"
And the user "manager" is a "manager"
And there are the following status:
| name | default |
| status1 | true |
And there are the following planning elements in project "ecookbook":
| subject |
| pe1 |
And there is an activity "design"
And I am already logged in as "manager"
Scenario: Logging time
When I go to the edit page of the work package called "pe1"
And I fill in the following:
| Spent time | 5 |
| Activity | design |
| Comment | Needed it |
And I submit the form by the "Submit" button
Then the work package should be shown with the following values:
| Spent time | 5.00 |

@ -0,0 +1,24 @@
Feature: Navigating to the work package edit page
Scenario: Directly opening the page
Given there is 1 user with:
| login | manager |
And there is a role "manager"
And the role "manager" may have the following rights:
| edit_work_packages |
And there is 1 project with the following:
| identifier | ecookbook |
| name | ecookbook |
And I am working in project "ecookbook"
And the user "manager" is a "manager"
And there are the following planning elements in project "ecookbook":
| subject | start_date | due_date |
| pe1 | 2013-01-01 | 2013-12-31 |
And I am already logged in as "manager"
When I go to the edit page of the work package called "pe1"
Then I should be on the edit page of the work package called "pe1"

@ -0,0 +1,95 @@
#-- copyright
#
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Feature: Updating work packages
Background:
Given there is 1 user with:
| login | manager |
| firstname | the |
| lastname | manager |
And there are the following planning element types:
| Name |
| Phase1 |
| Phase2 |
And there are the following project types:
| Name |
| Standard Project |
And the following planning element types are default for projects of type "Standard Project"
| Phase1 |
| Phase2 |
And there is 1 project with the following:
| identifier | ecookbook |
| name | ecookbook |
And the project named "ecookbook" is of the type "Standard Project"
And there is a role "manager"
And the role "manager" may have the following rights:
| edit_work_packages |
| view_work_packages |
| manage_subtasks |
And I am working in project "ecookbook"
And the user "manager" is a "manager"
And there are the following priorities:
| name | default |
| prio1 | true |
| prio2 | |
And there are the following status:
| name | default |
| status1 | true |
| status2 | |
And there are the following planning elements in project "ecookbook":
| subject |
| pe1 |
| pe2 |
And I am already logged in as "manager"
@javascript
Scenario: Updating the work package and seeing the results on the show page
When I go to the edit page of the work package called "pe1"
And I follow "More"
And I fill in the following:
| Responsible | the manager |
| Assignee | the manager |
| Start date | 2013-03-04 |
| Due date | 2013-03-06 |
| Estimated time | 5.00 |
| % done | 30 % |
| Priority | prio2 |
| Status | status2 |
| Subject | New subject |
| Type | Phase2 |
| Description | Desc2 |
# Nested set is broken right now for planning elements
#And I fill in the id of work package "pe2" into "Parent"
And I submit the form by the "Submit" button
Then I should be on the page of the work package "New subject"
And the work package should be shown with the following values:
| Responsible | the manager |
| Assignee | the manager |
| Start date | 03/04/2013 |
| Due date | 03/06/2013 |
| Estimated time | 5.00 |
| % done | 30 |
| Priority | prio2 |
| Status | status2 |
| Subject | New subject |
| Type | Phase2 |
| Description | Desc2 |
#And the work package "pe2" should be shown as the parent
Scenario: Adding a note
When I go to the edit page of the work package called "pe1"
And I fill in "Notes" with "Note message"
And I submit the form by the "Submit" button
Then I should be on the page of the work package "pe1"
And I should see a journal with the following:
| Notes | Note message |

@ -17,6 +17,10 @@ class InstanceFinder
end
def self.find(model, identifier)
instance = @model_method_map[model].call(identifier)
if @model_method_map[model].nil?
raise "#{model} is not registerd with InstanceFinder"
end
@model_method_map[model].call(identifier)
end
end

@ -32,7 +32,7 @@ module OpenProject
#
# 2.0.0debian-2
def self.special
'pre8'
'pre9'
end
def self.revision

@ -90,6 +90,7 @@ Redmine::AccessControl.map do |map|
:'issues/previews' => :create}
map.permission :add_work_packages, { :work_packages => [:new, :new_type, :create] }
map.permission :edit_work_packages, { :issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form, :quoted],
:work_packages => [:edit, :update, :new_type],
:'issues/previews' => :create}
map.permission :manage_issue_relations, {:issue_relations => [:create, :destroy]}
map.permission :manage_work_package_relations, {:work_package_relations => [:create, :destroy]}
@ -168,6 +169,8 @@ Redmine::AccessControl.map do |map|
map.permission :view_calendar, :'issues/calendars' => [:index]
end
map.project_module :activity
map.project_module :timelines do |map|
map.permission :manage_project_configuration,
:require => :member
@ -284,7 +287,7 @@ Redmine::MenuManager.map :project_menu do |menu|
:if => Proc.new { |p| p.shared_versions.any? }
menu.push :issues, { :controller => '/issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
menu.push :new_issue, { :controller => '/work_packages', :action => 'new', :type => 'Issue' }, :param => :project_id, :caption => :label_issue_new, :parent => :issues,
menu.push :new_issue, { :controller => '/work_packages', :action => 'new', :sti_type => 'Issue' }, :param => :project_id, :caption => :label_issue_new, :parent => :issues,
:html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
menu.push :view_all_issues, { :controller => '/issues', :action => 'all' }, :param => :project_id, :caption => :label_issue_view_all, :parent => :issues
menu.push :summary_field, {:controller => '/issues/reports', :action => 'report'}, :param => :project_id, :caption => :label_workflow_summary, :parent => :issues
@ -369,5 +372,3 @@ Redmine::WikiFormatting.map do |format|
end
ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler
Redmine::AccessControl.available_project_modules << :activity

@ -19,6 +19,8 @@ module Redmine
yield mapper
@permissions ||= []
@permissions += mapper.mapped_permissions
@project_modules_without_permissions ||= []
@project_modules_without_permissions += mapper.project_modules_without_permissions
end
def permissions
@ -50,7 +52,9 @@ module Redmine
end
def available_project_modules
@available_project_modules ||= @permissions.collect(&:project_module).uniq.compact
@available_project_modules ||= (
@permissions.collect(&:project_module) + @project_modules_without_permissions
).uniq.compact
end
def modules_permissions(modules)
@ -61,6 +65,7 @@ module Redmine
class Mapper
def initialize
@project_module = nil
@project_modules_without_permissions = []
end
def permission(name, hash, options={})
@ -70,14 +75,22 @@ module Redmine
end
def project_module(name, options={})
@project_module = name
yield self
@project_module = nil
if block_given?
@project_module = name
yield self
@project_module = nil
else
@project_modules_without_permissions << name
end
end
def mapped_permissions
@permissions
end
def project_modules_without_permissions
@project_modules_without_permissions
end
end
class Permission

@ -51,11 +51,13 @@ namespace :copyright do
end
end
def rewrite_copyright(ending, exclude, format)
def rewrite_copyright(ending, exclude, format, path)
regexp = copyright_regexp(format)
copyright = short_copyright(format)
Dir["**/**{.#{ending}}"].each do |file_name|
path = '.' if path.nil?
raise "Path not found" unless Dir.exists?(path)
Dir[File.absolute_path(path) + "/**/*.#{ending}"].each do |file_name|
# Skip 3rd party code
next if exclude.any? {|e| file_name.include?(e) }
@ -73,7 +75,7 @@ namespace :copyright do
end
desc "Update the copyright on .rb source files"
task :update_rb do
task :update_rb, :arg1 do |task, args|
excluded = (["diff",
"ruby-net-ldap-0.0.4",
"acts_as_tree",
@ -85,37 +87,37 @@ namespace :copyright do
(["SVG",
"redcloth"].map{ |dir| "lib/#{dir}" })
rewrite_copyright("rb", excluded, :rb)
rewrite_copyright("rb", excluded, :rb, args[:arg1])
end
desc "Update the copyright on .rake source files"
task :update_rake do
rewrite_copyright("rake", [], :rb)
task :update_rake, :arg1 do |task, args|
rewrite_copyright("rake", [], :rb, args[:arg1])
end
desc "Update the copyright on .feature source files"
task :update_feature do
rewrite_copyright("feature", [], :rb)
task :update_feature, :arg1 do |task, args|
rewrite_copyright("feature", [], :rb, args[:arg1])
end
desc "Update the copyright on .css source files"
task :update_css do
task :update_css, :arg1 do |task, args|
excluded = ["app/assets/stylesheets/reset.css",
"lib/assets",
"app/assets/javascripts/tinymce"]
rewrite_copyright("css", excluded, :css)
rewrite_copyright("css", excluded, :css, args[:arg1])
end
desc "Update the copyright on .css.erb source files"
task :update_css_erb do
task :update_css_erb, :arg1 do |task, args|
excluded = ["lib/assets/stylesheets/select2.css.erb"]
rewrite_copyright("css.erb", excluded, :css)
rewrite_copyright("css.erb", excluded, :css, args[:arg1])
end
desc "Update the copyright on .js source files"
task :update_js do
task :update_js, :arg1 do |task, args|
excluded = ["lib/assets",
"app/assets/javascripts/Bitstream_Vera_Sans_400.font.js",
"app/assets/javascripts/date-de-DE.js",
@ -126,37 +128,41 @@ namespace :copyright do
"app/assets/javascripts/calendar",
"app/assets/javascripts/jstoolbar"]
rewrite_copyright("js", excluded, :js)
rewrite_copyright("js", excluded, :js, args[:arg1])
end
desc "Update the copyright on .js.erb source files"
task :update_js_erb do
task :update_js_erb, :arg1 do |task, args|
excluded = ["lib/assets",
"app/assets/javascripts/tinymce",
"app/assets/javascripts/calendar",
"app/assets/javascripts/jstoolbar"]
rewrite_copyright("js.erb", excluded, :erb)
rewrite_copyright("js.erb", excluded, :erb, args[:arg1])
end
desc "Update the copyright on .html.erb source files"
task :update_html_erb do
rewrite_copyright("html.erb", [], :erb)
task :update_html_erb, :arg1 do |task, args|
rewrite_copyright("html.erb", [], :erb, args[:arg1])
end
desc "Update the copyright on .api.rsb source files"
task :update_api_rsb do
rewrite_copyright("api.rsb", [], :rb)
task :update_api_rsb, :arg1 do |task, args|
rewrite_copyright("api.rsb", [], :rb, args[:arg1])
end
desc "Update the copyright on all source files"
task :update => [:update_css,
:update_rb,
:update_js,
:update_js_erb,
:update_css_erb,
:update_html_erb,
:update_api_rsb,
:update_rake,
:update_feature]
task :update, :arg1 do |task, args|
[:update_css,
:update_rb,
:update_js,
:update_js_erb,
:update_css_erb,
:update_html_erb,
:update_api_rsb,
:update_rake,
:update_feature].each do |t|
Rake::Task['copyright:' + t.to_s].invoke(args[:arg1])
end
end
end

@ -233,13 +233,13 @@ describe WorkPackagesController do
end
describe 'new_type.js' do
describe 'w/o specifying a project_id' do
describe 'w/o specifying a project_id or an id' do
before do
xhr :get, :new_type
end
it 'should return 404 Not found' do
response.response_code.should == 404
it 'should return 403 Not found' do
response.response_code.should == 403
end
end
@ -254,16 +254,35 @@ describe WorkPackagesController do
end
describe 'w/ beeing a member
w/ having the necessary permissions' do
w/ having the necessary permissions
w/ specifying a project_id' do
become_member_with_permissions [:add_work_packages]
before do
xhr :get, :new_type, :project_id => project.id,
:type => 'Issue' #TODO: remove type once Issue == PlanningElement
xhr :get, :new_type, :project_id => project.id
end
it 'renders the new builder template' do
response.should render_template('work_packages/_attributes', :formats => ["html"])
response.should render_template('work_packages/new_type', :formats => ["html"])
end
it 'should respond with 200 OK' do
response.response_code.should == 200
end
end
describe 'w/ beeing a member
w/ having the necessary permissions
w/ specifying an id' do
become_member_with_permissions [:view_work_packages,
:edit_work_packages]
before do
xhr :get, :new_type, :id => planning_element.id
end
it 'renders the new builder template' do
response.should render_template('work_packages/new_type', :formats => ["html"])
end
it 'should respond with 200 OK' do
@ -373,6 +392,162 @@ describe WorkPackagesController do
end
end
describe 'edit.html' do
become_admin
describe 'w/o a valid work_package id' do
describe 'w/o being a member or administrator' do
become_non_member
it 'renders a 404 page' do
get 'edit', :id => '1337'
response.response_code.should === 404
end
end
describe 'w/ the current user being a member' do
become_member_with_view_planning_element_permissions
it 'raises ActiveRecord::RecordNotFound errors' do
get 'edit', :id => '1337'
response.response_code.should === 404
end
end
end
describe 'w/ a valid work package id' do
become_admin
describe 'w/o being a member or administrator' do
become_non_member
it 'renders a 403 Forbidden page' do
get 'edit', :id => planning_element.id
response.response_code.should == 403
end
end
describe 'w/ the current user being a member' do
become_member_with_permissions [:edit_work_packages]
before do
get 'edit', :id => planning_element.id
end
it 'renders the show builder template' do
response.should render_template('work_packages/edit', :formats => ["html"], :layout => :base)
end
end
end
end
describe 'update.html' do
describe 'w/o being a member' do
before do
put 'update'
end
it 'should return 404 Not Found' do
response.response_code.should == 404
end
end
describe 'w/ beeing a member
w/ having the necessary permissions
w/ a valid wp id
w/ having a successful save' do
let(:wp_params) { { :wp_attribute => double('wp_attribute') } }
let(:params) { { :id => planning_element.id, :work_package => wp_params } }
become_member_with_permissions [:edit_work_packages]
before do
controller.stub!(:work_package).and_return(planning_element)
controller.send(:permitted_params).should_receive(:update_work_package)
.with(:project => planning_element.project)
.and_return(wp_params)
planning_element.should_receive(:update_by).with(current_user, wp_params).and_return(true)
end
it 'should respond with 200 OK' do
put 'update', params
response.response_code.should == 200
end
it 'should show a flash message' do
disable_flash_sweep
put 'update', params
flash[:notice].should == I18n.t(:notice_successful_update)
end
end
describe 'w/ beeing a member
w/ having the necessary permissions
w/ a valid wp id
w/ having an unsuccessful save' do
let(:wp_params) { { :wp_attribute => double('wp_attribute') } }
let(:params) { { :id => planning_element.id, :work_package => wp_params } }
become_member_with_permissions [:edit_work_packages]
before do
controller.stub!(:work_package).and_return(planning_element)
controller.send(:permitted_params).should_receive(:update_work_package)
.with(:project => planning_element.project)
.and_return(wp_params)
planning_element.should_receive(:update_by).with(current_user, wp_params).and_return(false)
end
it 'render the edit action' do
put 'update', params
response.should render_template('work_packages/edit', :formats => ["html"], :layout => :base)
end
end
describe 'w/ beeing a member
w/ having the necessary permissions
w/ a valid wp id
w/ having a successful save
w/ having a faulty attachment' do
let(:wp_params) { { :wp_attribute => double('wp_attribute') } }
let(:params) { { :id => planning_element.id, :work_package => wp_params } }
become_member_with_permissions [:edit_work_packages]
before do
controller.stub!(:work_package).and_return(planning_element)
controller.send(:permitted_params).should_receive(:update_work_package)
.with(:project => planning_element.project)
.and_return(wp_params)
planning_element.should_receive(:update_by).with(current_user, wp_params).and_return(true)
planning_element.stub(:unsaved_attachments).and_return([double('unsaved_attachment')])
end
it 'should respond with 200 OK' do
put 'update', params
response.response_code.should == 200
end
it 'should show a flash message' do
disable_flash_sweep
put 'update', params
flash[:warning].should == I18n.t(:warning_attachments_not_saved, :count => 1)
end
end
end
describe :work_package do
describe 'when beeing allowed to see the work_package' do
become_member_with_view_planning_element_permissions
@ -586,4 +761,30 @@ describe WorkPackagesController do
controller.priorities.should == expected
end
end
describe :allowed_statuses do
it "should return all statuses allowed by the issue" do
expected = double('statuses')
controller.stub!(:work_package).and_return(stub_issue)
stub_issue.stub!(:new_statuses_allowed_to).with(current_user).and_return(expected)
controller.allowed_statuses.should == expected
end
end
describe :time_entry do
before do
controller.stub!(:work_package).and_return(stub_planning_element)
end
it "should return a time entry" do
expected = double('time_entry')
stub_planning_element.stub!(:add_time_entry).and_return(expected)
controller.time_entry.should == expected
end
end
end

@ -63,6 +63,11 @@ FactoryGirl.define do
end
end
factory :work_package_custom_field do
sequence(:name) { |n| "Work Package Custom Field #{n}" }
type "WorkPackageCustomField"
end
factory :issue_custom_field do
sequence(:name) { |n| "Issue Custom Field #{n}" }
type "WorkPackageCustomField"

@ -23,5 +23,10 @@ FactoryGirl.define do
custom_field :factory => :issue_custom_field
customized :factory => :issue
end
factory :work_package_custom_value do
custom_field :factory => :issue_custom_field
customized :factory => :issue
end
end
end

@ -13,6 +13,18 @@ require 'spec_helper'
describe WorkPackagesHelper do
let(:stub_work_package) { FactoryGirl.build_stubbed(:planning_element) }
let(:form) { double('form', :select => "").as_null_object }
let(:stub_user) { FactoryGirl.build_stubbed(:user) }
def inside_form &block
ret = ''
form_for(stub_work_package, :as => 'work_package', :url => work_package_path(stub_work_package)) do |f|
ret = yield f
end
ret
end
describe :work_package_breadcrumb do
it 'should provide a link to index as the first element and all ancestors as links' do
@ -50,10 +62,29 @@ describe WorkPackagesHelper do
end
end
describe :work_package_show_spent_time_attribute do
it "should show a spent time link pointing to the time entries of the work package" do
stub_work_package.stub(:spent_hours).and_return(5.0)
field = helper.work_package_show_spent_time_attribute(stub_work_package).field
expected_href = issue_time_entries_path(stub_work_package)
field.should have_css(".spent-time a[@href='#{ expected_href }']", :text => '5.0')
end
it "should show a '-' if spent time is 0" do
stub_work_package.stub(:spent_hours).and_return(0.0)
field = helper.work_package_show_spent_time_attribute(stub_work_package).field
field.should have_css(".spent-time", :text => '-')
end
end
describe :work_package_form_issue_category_attribute do
let(:stub_project) { FactoryGirl.build_stubbed(:project) }
let(:stub_category) { FactoryGirl.build_stubbed(:issue_category) }
let(:form) { double('form', :select => "").as_null_object }
before do
# set sensible defaults
@ -211,4 +242,86 @@ describe WorkPackagesHelper do
helper.work_package_css_classes(stub_work_package).should_not include("assigned-to-me")
end
end
describe :work_package_form_estimated_hours_attribute do
it "should output the estimated hours value with a precision of 2" do
stub_work_package.estimated_hours = 3
attribute = inside_form do |f|
helper.work_package_form_estimated_hours_attribute(f, stub_work_package, {})
end
attribute.field.should have_selector('input#work_package_estimated_hours[@value="3.00"]')
end
end
describe :work_package_form_custom_values_attribute do
let(:stub_custom_value) { FactoryGirl.build_stubbed(:work_package_custom_value) }
let(:expected) { "field contents" }
before do
stub_work_package.stub!(:custom_field_values).and_return([stub_custom_value])
helper.should_receive(:custom_field_tag_with_label).with(:work_package, stub_custom_value).and_return(expected)
end
it "should return an array for an element for every value" do
helper.work_package_form_custom_values_attribute(form, stub_work_package, {}).size.should == 1
end
it "should return the result inside the field" do
helper.work_package_form_custom_values_attribute(form, stub_work_package, {}).first.field.should == expected
end
end
describe :work_package_form_status_attribute do
let(:status1) { FactoryGirl.build_stubbed(:issue_status) }
let(:status2) { FactoryGirl.build_stubbed(:issue_status) }
it "should return a select with every available status as an option" do
stub_work_package.stub!(:new_statuses_allowed_to)
.with(stub_user, true)
.and_return([status1, status2])
stub_work_package.status = status1
attribute = inside_form do |f|
helper.work_package_form_status_attribute(f, stub_work_package, :user => stub_user)
end
status1_selector = "select#work_package_status_id option[@value='#{status1.id}'][@selected='selected']"
status2_selector = "select#work_package_status_id option[@value='#{status1.id}']"
attribute.field.should have_selector(status1_selector)
attribute.field.should have_selector(status2_selector)
end
it "should return a label and the name of the current status if no new status is available" do
stub_work_package.stub!(:new_statuses_allowed_to)
.with(stub_user, true)
.and_return([])
stub_work_package.status = status1
attribute = inside_form do |f|
helper.work_package_form_status_attribute(f, stub_work_package, :user => stub_user)
end
attribute.field.should have_text(WorkPackage.human_attribute_name(:status))
attribute.field.should have_text(status1.name)
end
it "should return a label and a '-' if the work_package has no status" do
stub_work_package.stub!(:new_statuses_allowed_to)
.with(stub_user, true)
.and_return([])
attribute = inside_form do |f|
helper.work_package_form_status_attribute(f, stub_work_package, :user => stub_user)
end
attribute.field.should have_text(WorkPackage.human_attribute_name(:status))
attribute.field.should have_text("-")
end
end
end

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
require 'open_project/footer'

@ -411,6 +411,174 @@ describe PermittedParams do
end
end
describe :update_work_package do
it "should permit subject" do
hash = { "subject" => "blubs" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit description" do
hash = { "description" => "blubs" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit start_date" do
hash = { "start_date" => "2013-07-08" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit due_date" do
hash = { "due_date" => "2013-07-08" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit assigned_to_id" do
hash = { "assigned_to_id" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit responsible_id" do
hash = { "responsible_id" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit type_id" do
hash = { "type_id" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit planning_element_type_id" do
hash = { "planning_element_type_id" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit prioritiy_id" do
hash = { "priority_id" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit parent_issue_id" do
hash = { "parent_id" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit parent_issue_id" do
hash = { "parent_issue_id" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit fixed_version_id" do
hash = { "fixed_version_id" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit estimated_hours" do
hash = { "estimated_hours" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit done_ratio" do
hash = { "done_ratio" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit status_id" do
hash = { "status_id" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit category_id" do
hash = { "category_id" => "1" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit notes" do
hash = { "notes" => "blubs" }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit attachments" do
hash = { "attachments" => [{ "file" => "djskfj", "description" => "desc" }] }
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package.should == hash
end
it "should permit time_entry if the user has the log_time permission" do
hash = { "time_entry" => { "hours" => "5", "activity_id" => "1", "comments" => "lorem" } }
project = double('project')
user.stub(:allowed_to?).with(:log_time, project).and_return(true)
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package(:project => project).should == hash
end
it "should not permit time_entry if the user lacks the log_time permission" do
hash = { "time_entry" => { "hours" => "5", "activity_id" => "1", "comments" => "lorem" } }
project = double('project')
user.stub(:allowed_to?).with(:log_time, project).and_return(false)
params = ActionController::Parameters.new(:work_package => hash)
PermittedParams.new(params, user).update_work_package(:project => project).should == {}
end
end
describe :user do
admin_permissions = ['firstname',
'lastname',

@ -119,12 +119,11 @@ describe Project do
project.add_issue(:type_id => specific_type.id).type.should == specific_type
end
it "should call safe_attributes to override all the other attributes" do
# TODO: replace once StrongParameters is in place
it "should set all the other attributes" do
attributes = { :blubs => double('blubs') }
new_issue = FactoryGirl.build_stubbed(:issue)
new_issue.should_receive(:assign_attributes).with(attributes, :without_protection => true)
new_issue.should_receive(:attributes=).with(attributes)
Issue.stub!(:new).and_yield(new_issue)

@ -1,3 +1,14 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe SystemUser do

@ -15,6 +15,10 @@ describe WorkPackage do
let(:stub_work_package) { FactoryGirl.build_stubbed(:work_package) }
let(:stub_user) { FactoryGirl.build_stubbed(:user) }
let(:stub_version) { FactoryGirl.build_stubbed(:version) }
let(:stub_project) { FactoryGirl.build_stubbed(:project) }
let(:issue) { FactoryGirl.create(:issue) }
let(:planning_element) { FactoryGirl.create(:planning_element).reload }
let(:user) { FactoryGirl.create(:user) }
describe :assignable_users do
it 'should return all users the project deems to be assignable' do
@ -75,4 +79,124 @@ describe WorkPackage do
sink.project_id.should == orig_project_id
end
end
describe :new_statuses_allowed_to do
it "should return all status" do
# Dummy implementation as long as trackers/types are not merged
expected = double('expect')
IssueStatus.stub(:all).and_return(expected)
stub_work_package.new_statuses_allowed_to(stub_user).should == expected
end
end
describe :add_time_entry do
it "should return a new time entry" do
stub_work_package.add_time_entry.should be_a TimeEntry
end
it "should already have the project assigned" do
stub_work_package.project = stub_project
stub_work_package.add_time_entry.project.should == stub_project
end
it "should already have the work_package assigned" do
stub_work_package.add_time_entry.work_package.should == stub_work_package
end
it "should return an usaved entry" do
stub_work_package.add_time_entry.should be_new_record
end
end
describe :update_with do
#TODO remove once only WP exists
[:issue, :planning_element].each do |subclass|
describe "for #{subclass}" do
let(:instance) { send(subclass) }
it "should return true" do
instance.update_by(user, {}).should be_true
end
it "should set the values" do
instance.update_by(user, { :subject => "New subject" })
instance.subject.should == "New subject"
end
it "should create a journal with the journal's 'notes' attribute set to the supplied" do
instance.update_by(user, { :notes => "blubs" })
instance.journals.last.notes.should == "blubs"
end
it "should attach an attachment" do
raw_attachments = [double('attachment')]
attachment = FactoryGirl.build(:attachment)
Attachment.should_receive(:attach_files)
.with(instance, raw_attachments)
.and_return(attachment)
instance.update_by(user, { :attachments => raw_attachments })
end
it "should only attach the attachment when saving was successful" do
raw_attachments = [double('attachment')]
attachment = FactoryGirl.build(:attachment)
Attachment.should_not_receive(:attach_files)
instance.update_by(user, { :subject => "", :attachments => raw_attachments })
end
it "should add a time entry" do
activity = FactoryGirl.create(:time_entry_activity)
instance.update_by(user, { :time_entry => { "hours" => "5",
"activity_id" => activity.id.to_s,
"comments" => "blubs" } } )
instance.should have(1).time_entries
entry = instance.time_entries.first
entry.should be_persisted
entry.work_package.should == instance
entry.user.should == user
entry.project.should == instance.project
entry.spent_on.should == Date.today
end
it "should not persist the time entry if the #{subclass}'s update fails" do
activity = FactoryGirl.create(:time_entry_activity)
instance.update_by(user, { :subject => '',
:time_entry => { "hours" => "5",
"activity_id" => activity.id.to_s,
"comments" => "blubs" } } )
instance.should have(1).time_entries
entry = instance.time_entries.first
entry.should_not be_persisted
end
it "should not add a time entry if the time entry attributes are empty" do
time_attributes = { "hours" => "",
"activity_id" => "",
"comments" => "" }
instance.update_by(user, :time_entry => time_attributes)
instance.should have(0).time_entries
end
end
end
end
end

@ -31,10 +31,28 @@ describe WorkPackagesController do
:project_id => '1' )
end
it "should connect GET /work_packages/1/new_type to work_packages#new_type" do
get("/work_packages/1/new_type").should route_to( :controller => 'work_packages',
:action => 'new_type',
:id => '1' )
end
it "should connect GET /work_packages/:id/edit to work_packages#edit" do
get("/work_packages/1/edit").should route_to( :controller => 'work_packages',
:action => 'edit',
:id => '1' )
end
it "should connect POST /projects/:project_id/work_packages to work_packages#new" do
post("/projects/1/work_packages").should route_to( :controller => 'work_packages',
:action => 'create',
:project_id => '1' )
end
it "should connect PUT /work_packages/1 to work_packages#update" do
put("/work_packages/1").should route_to( :controller => 'work_packages',
:action => 'update',
:id => '1' )
end
end

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

Loading…
Cancel
Save