Merge remote-tracking branch 'opf/feature/rails3' into feature/ie_10_svg_text_rendering

Conflicts:
	doc/CHANGELOG.md
pull/639/head
Martin Czuchra 11 years ago
commit 7443dc83ac
  1. 24
      .travis.yml
  2. 4
      Gemfile
  3. 5
      Gemfile.lock
  4. 18
      app/controllers/application_controller.rb
  5. 31
      app/controllers/wiki_controller.rb
  6. 6
      app/controllers/wiki_menu_items_controller.rb
  7. 22
      app/helpers/application_helper.rb
  8. 1
      app/models/journal_manager.rb
  9. 2
      app/models/wiki_content.rb
  10. 2
      app/models/wiki_page.rb
  11. 8
      app/views/wiki/annotate.html.erb
  12. 2
      app/views/wiki/destroy.html.erb
  13. 6
      app/views/wiki/diff.html.erb
  14. 4
      app/views/wiki/edit.html.erb
  15. 2
      app/views/wiki/edit_parent_page.html.erb
  16. 4
      app/views/wiki/export_multiple.html.erb
  17. 4
      app/views/wiki/history.html.erb
  18. 2
      app/views/wiki/rename.html.erb
  19. 38
      app/views/wiki/show.html.erb
  20. 4
      app/views/wiki_menu_items/edit.html.erb
  21. 4
      config/configuration.yml.example
  22. 6
      config/routes.rb
  23. 45
      db/migrate/20130612120042_migrate_serialized_yaml_from_syck_to_psych.rb
  24. 25
      db/migrate/20130917131710_planning_element_data_to_work_packages.rb
  25. 76
      db/migrate/20130920095747_legacy_planning_element_journal_data.rb
  26. 11
      db/migrate/20131101125921_migrate_default_values_in_work_package_journals.rb
  27. 32
      db/migrate/migration_utils/attachable_utils.rb
  28. 36
      db/migrate/migration_utils/customizable_utils.rb
  29. 4
      db/migrate/migration_utils/db_worker.rb
  30. 3
      db/migrate/migration_utils/legacy_journal_migrator.rb
  31. 8
      db/migrate/migration_utils/utils.rb
  32. 48
      db/migrate/migration_utils/yaml_migrator.rb
  33. 11
      doc/CHANGELOG.md
  34. 56
      features/wiki/wiki_create_child.feature
  35. 1
      lib/open_project/configuration.rb
  36. 2
      lib/open_project/version.rb
  37. 8
      lib/redmine/menu_manager/menu_helper.rb
  38. 24
      lib/tasks/fix_attachments_collation.rake
  39. 61
      lib/tasks/quote_strings_with_invalid_characters_in_legacy_journals.rake
  40. 3
      lib/tasks/remove_timelines_historical_comparison_from_options.rake
  41. 3
      spec/controllers/wiki_controller_spec.rb
  42. 18
      spec/models/work_package/work_package_acts_as_journalized_spec.rb
  43. 5
      spec/spec_helper.rb
  44. 24
      test/functional/wiki_controller_test.rb
  45. 6
      test/test_helper.rb
  46. 20
      test/unit/lib/redmine/wiki_formatting/macros_test.rb

@ -34,17 +34,17 @@ branches:
- feature/rails3 - feature/rails3
env: env:
# mysql2 # mysql2
- "TEST_SUITE=cucumber RAILS_ENV=test DB=mysql2 BUNDLE_WITHOUT=rmagick:mysql:postgres:sqlite:development" - "TEST_SUITE=cucumber CI=true RAILS_ENV=test DB=mysql2 BUNDLE_WITHOUT=rmagick:mysql:postgres:sqlite:development"
- "TEST_SUITE=test:units RAILS_ENV=test DB=mysql2 BUNDLE_WITHOUT=rmagick:mysql:postgres:sqlite:development" - "TEST_SUITE=test:units CI=true RAILS_ENV=test DB=mysql2 BUNDLE_WITHOUT=rmagick:mysql:postgres:sqlite:development"
- "TEST_SUITE=test:functionals RAILS_ENV=test DB=mysql2 BUNDLE_WITHOUT=rmagick:mysql:postgres:sqlite:development" - "TEST_SUITE=test:functionals CI=true RAILS_ENV=test DB=mysql2 BUNDLE_WITHOUT=rmagick:mysql:postgres:sqlite:development"
- "TEST_SUITE=test:integration RAILS_ENV=test DB=mysql2 BUNDLE_WITHOUT=rmagick:mysql:postgres:sqlite:development" - "TEST_SUITE=test:integration CI=true RAILS_ENV=test DB=mysql2 BUNDLE_WITHOUT=rmagick:mysql:postgres:sqlite:development"
- "TEST_SUITE=spec RAILS_ENV=test DB=mysql2 BUNDLE_WITHOUT=rmagick:mysql:postgres:sqlite:development" - "TEST_SUITE=spec CI=true RAILS_ENV=test DB=mysql2 BUNDLE_WITHOUT=rmagick:mysql:postgres:sqlite:development"
# postgres # postgres
- "TEST_SUITE=cucumber RAILS_ENV=test DB=postgres BUNDLE_WITHOUT=rmagick:mysql:mysql2:sqlite:development" - "TEST_SUITE=cucumber CI=true RAILS_ENV=test DB=postgres BUNDLE_WITHOUT=rmagick:mysql:mysql2:sqlite:development"
- "TEST_SUITE=test:units RAILS_ENV=test DB=postgres BUNDLE_WITHOUT=rmagick:mysql:mysql2:sqlite:development" - "TEST_SUITE=test:units CI=true RAILS_ENV=test DB=postgres BUNDLE_WITHOUT=rmagick:mysql:mysql2:sqlite:development"
- "TEST_SUITE=test:functionals RAILS_ENV=test DB=postgres BUNDLE_WITHOUT=rmagick:mysql:mysql2:sqlite:development" - "TEST_SUITE=test:functionals CI=true RAILS_ENV=test DB=postgres BUNDLE_WITHOUT=rmagick:mysql:mysql2:sqlite:development"
- "TEST_SUITE=test:integration RAILS_ENV=test DB=postgres BUNDLE_WITHOUT=rmagick:mysql:mysql2:sqlite:development" - "TEST_SUITE=test:integration CI=true RAILS_ENV=test DB=postgres BUNDLE_WITHOUT=rmagick:mysql:mysql2:sqlite:development"
- "TEST_SUITE=spec RAILS_ENV=test DB=postgres BUNDLE_WITHOUT=rmagick:mysql:mysql2:sqlite:development" - "TEST_SUITE=spec CI=true RAILS_ENV=test DB=postgres BUNDLE_WITHOUT=rmagick:mysql:mysql2:sqlite:development"
script: "bundle exec rake $TEST_SUITE" script: "bundle exec rake $TEST_SUITE"
before_install: before_install:
- "export DISPLAY=:99.0" - "export DISPLAY=:99.0"
@ -53,3 +53,7 @@ before_script:
- "RAILS_ENV=production bundle exec rake ci:travis:prepare" - "RAILS_ENV=production bundle exec rake ci:travis:prepare"
notifications: notifications:
email: false email: false
addons:
code_climate:
repo_token:
secure: "BIooLUZt/ZPBh0KSOMrSdsm0uwyax9veNULE20hJLXxuj8dStxAHcrZW8gZvNaU0/vgz3RWKQeNJ6xV9BXYVjnAtYIkQmI+kiryRT9PE6OsLbqeU/OirahFi8Dwm4xfh/e9DVgTOyYHHhZ69aVFQxvKbXARGmfoHcy8gFduJ7ss="

@ -78,6 +78,8 @@ gem 'daemons'
gem 'rack-protection' gem 'rack-protection'
gem 'syck', :platforms => [:ruby_20, :mingw_20], :require => false
group :production do group :production do
# we use dalli as standard memcache client remove this if you don't # we use dalli as standard memcache client remove this if you don't
# requires memcached 1.4+ # requires memcached 1.4+
@ -129,8 +131,8 @@ group :test do
gem 'simplecov', ">= 0.8.pre" gem 'simplecov', ">= 0.8.pre"
gem "shoulda-matchers" gem "shoulda-matchers"
gem "json_spec" gem "json_spec"
gem "activerecord-tableless", "~> 1.0" gem "activerecord-tableless", "~> 1.0"
gem "codeclimate-test-reporter", :require => nil
end end
group :ldap do group :ldap do

@ -69,6 +69,8 @@ GEM
timers (~> 1.1.0) timers (~> 1.1.0)
childprocess (0.3.9) childprocess (0.3.9)
ffi (~> 1.0, >= 1.0.11) ffi (~> 1.0, >= 1.0.11)
codeclimate-test-reporter (0.1.1)
simplecov (>= 0.7.1, < 1.0.0)
coderay (1.0.9) coderay (1.0.9)
coffee-rails (3.2.2) coffee-rails (3.2.2)
coffee-script (>= 2.2.0) coffee-script (>= 2.2.0)
@ -318,6 +320,7 @@ GEM
railties (~> 3.0) railties (~> 3.0)
structured_warnings (0.1.4) structured_warnings (0.1.4)
svg-graph (1.0.5) svg-graph (1.0.5)
syck (1.0.1)
test-unit (2.5.5) test-unit (2.5.5)
therubyracer (0.11.4) therubyracer (0.11.4)
libv8 (~> 3.11.8.12) libv8 (~> 3.11.8.12)
@ -355,6 +358,7 @@ DEPENDENCIES
awesome_nested_set awesome_nested_set
capybara capybara
capybara-screenshot capybara-screenshot
codeclimate-test-reporter
coderay (~> 1.0.5) coderay (~> 1.0.5)
coffee-rails (~> 3.2.1) coffee-rails (~> 3.2.1)
color-tools (~> 1.3.0) color-tools (~> 1.3.0)
@ -424,6 +428,7 @@ DEPENDENCIES
sqlite3 sqlite3
strong_parameters strong_parameters
svg-graph svg-graph
syck
therubyracer therubyracer
thin thin
timecop (~> 0.6.1) timecop (~> 0.6.1)

@ -45,8 +45,6 @@ require_dependency 'principal'
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
# ensure the OpenProject models are required in the right order (as they have circular dependencies)
class_attribute :_model_object class_attribute :_model_object
class_attribute :_model_scope class_attribute :_model_scope
class_attribute :accept_key_auth_actions class_attribute :accept_key_auth_actions
@ -87,7 +85,9 @@ class ApplicationController < ActionController::Base
:reset_i18n_fallbacks, :reset_i18n_fallbacks,
:set_localization, :set_localization,
:check_session_lifetime, :check_session_lifetime,
:stop_if_feeds_disabled :stop_if_feeds_disabled,
:set_cache_buster
rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
@ -104,6 +104,18 @@ class ApplicationController < ActionController::Base
{ :layout => params["layout"] } { :layout => params["layout"] }
end end
# set http headers so that the browser does not store any
# data (caches) of this site
# see: https://websecuritytool.codeplex.com/wikipage?title=Checks#http-cache-control-header-no-store
# see: http://stackoverflow.com/questions/711418/how-to-prevent-browser-page-caching-in-rails
def set_cache_buster
if OpenProject::Configuration['disable_browser_cache']
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
end
end
# the current user is a per-session kind of thing and session stuff is controller responsibility. # the current user is a per-session kind of thing and session stuff is controller responsibility.
# a globally accessible User.current is a big code smell. when used incorrectly it allows getting # a globally accessible User.current is a big code smell. when used incorrectly it allows getting
# the current user outside of a session scope, i.e. in the model layer, from mailers or in the console # the current user outside of a session scope, i.e. in the model layer, from mailers or in the console

@ -57,6 +57,7 @@ class WikiController < ApplicationController
:add_attachment, :add_attachment,
:list_attachments, :list_attachments,
:destroy] :destroy]
before_filter :build_wiki_page_and_content, only: [:new, :create]
verify :method => :post, :only => [:protect], :redirect_to => { :action => :show } verify :method => :post, :only => [:protect], :redirect_to => { :action => :show }
verify :method => :get, :only => [:new, :new_child], :render => {:nothing => true, :status => :method_not_allowed} verify :method => :get, :only => [:new, :new_child], :render => {:nothing => true, :status => :method_not_allowed}
@ -94,11 +95,6 @@ class WikiController < ApplicationController
end end
def new def new
@page = WikiPage.new(:wiki => @wiki)
@page.content = WikiContent.new(:page => @page)
@content = @page.content_for_version(nil)
@content.text = initial_page_content(@page)
end end
def new_child def new_child
@ -107,15 +103,13 @@ class WikiController < ApplicationController
old_page = @page old_page = @page
new build_wiki_page_and_content
@page.parent = old_page @page.parent = old_page
render :action => 'new' render :action => 'new'
end end
def create def create
new
@page.title = params[:page][:title] @page.title = params[:page][:title]
@page.parent_id = params[:page][:parent_id] @page.parent_id = params[:page][:parent_id]
@ -126,6 +120,7 @@ class WikiController < ApplicationController
attachments = Attachment.attach_files(@page, params[:attachments]) attachments = Attachment.attach_files(@page, params[:attachments])
render_attachment_warning_if_needed(@page) render_attachment_warning_if_needed(@page)
call_hook(:controller_wiki_edit_after_save, :params => params, :page => @page) call_hook(:controller_wiki_edit_after_save, :params => params, :page => @page)
flash[:notice] = l(:notice_successful_create)
redirect_to_show redirect_to_show
else else
render :action => 'new' render :action => 'new'
@ -304,7 +299,11 @@ class WikiController < ApplicationController
end end
@page.destroy @page.destroy
redirect_to @wiki.pages.any? ? {:action => 'index', :project_id => @project} : project_path(@project) if page = @wiki.find_page(@wiki.start_page) || @wiki.pages.first
redirect_to :action => 'index', :project_id => @project, id: page
else
redirect_to project_path(@project)
end
end end
# Export wiki to a single html file # Export wiki to a single html file
@ -334,7 +333,7 @@ class WikiController < ApplicationController
return render_403 unless editable? return render_403 unless editable?
attachments = Attachment.attach_files(@page, params[:attachments]) attachments = Attachment.attach_files(@page, params[:attachments])
render_attachment_warning_if_needed(@page) render_attachment_warning_if_needed(@page)
redirect_to :action => 'show', :id => @page.title, :project_id => @project redirect_to :action => 'show', :id => @page, :project_id => @project
end end
def list_attachments def list_attachments
@ -352,7 +351,7 @@ class WikiController < ApplicationController
nil nil
end end
private private
def find_wiki def find_wiki
@project = Project.find(params[:project_id]) @project = Project.find(params[:project_id])
@ -368,6 +367,14 @@ private
render_404 if @page.nil? render_404 if @page.nil?
end end
def build_wiki_page_and_content
@page = WikiPage.new wiki: @wiki
@page.content = WikiContent.new page: @page
@content = @page.content_for_version nil
@content.text = initial_page_content @page
end
# Returns true if the current user is allowed to edit the page, otherwise false # Returns true if the current user is allowed to edit the page, otherwise false
def editable?(page = @page) def editable?(page = @page)
page.editable_by?(User.current) page.editable_by?(User.current)
@ -389,6 +396,6 @@ private
end end
def redirect_to_show def redirect_to_show
redirect_to :action => 'show', :project_id => @project, :id => @page.title redirect_to action: :show, project_id: @project, id: @page
end end
end end

@ -75,10 +75,10 @@ class WikiMenuItemsController < ApplicationController
if not @wiki_menu_item.errors.size >= 1 and (@wiki_menu_item.destroyed? or @wiki_menu_item.save) if not @wiki_menu_item.errors.size >= 1 and (@wiki_menu_item.destroyed? or @wiki_menu_item.save)
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_back_or_default({ :action => 'edit', :id => @page_title }) redirect_back_or_default({ :action => 'edit', :id => @page })
else else
respond_to do |format| respond_to do |format|
format.html { render :action => 'edit', :id => @page_title } format.html { render :action => 'edit', :id => @page }
end end
end end
end end
@ -96,7 +96,7 @@ class WikiMenuItemsController < ApplicationController
current_menu_item.destroy current_menu_item.destroy
end end
redirect_to action: :edit, id: current_page.title redirect_to action: :edit, id: current_page
end end
private private

@ -240,19 +240,17 @@ module ApplicationHelper
end end
def render_page_hierarchy(pages, node=nil, options={}) def render_page_hierarchy(pages, node=nil, options={})
content = '' return '' unless pages[node]
if pages[node]
content << "<ul class=\"pages-hierarchy\">\n" content_tag :ul, class: 'pages-hierarchy' do
pages[node].each do |page| pages[node].collect do |page|
content << "<li>" content_tag :li do
content << link_to(page.pretty_title, project_wiki_path(page.project, page), concat link_to(page.pretty_title, project_wiki_path(page.project, page),
:title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil)) title: (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id] concat render_page_hierarchy(pages, page.id, options) if pages[page.id]
content << "</li>\n" end
end end.join.html_safe
content << "</ul>\n"
end end
content.html_safe
end end
# Renders flash messages # Renders flash messages

@ -51,6 +51,7 @@ class JournalManager
predecessor = journable.journals.last.data.journaled_attributes predecessor = journable.journals.last.data.journaled_attributes
current = normalize_newlines(current) current = normalize_newlines(current)
predecessor = normalize_newlines(predecessor)
return predecessor.map{|k,v| current[k.to_s] != v} return predecessor.map{|k,v| current[k.to_s] != v}
.inject(false) { |r, c| r || c } .inject(false) { |r, c| r || c }

@ -43,7 +43,7 @@ class WikiContent < ActiveRecord::Base
acts_as_journalized :event_type => 'wiki-page', acts_as_journalized :event_type => 'wiki-page',
:event_title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.journal.journable.page.title} (##{o.journal.journable.version})"}, :event_title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.journal.journable.page.title} (##{o.journal.journable.version})"},
:event_url => Proc.new {|o| {:controller => '/wiki', :action => 'show', :id => o.journal.journable.page.title, :project_id => o.journal.journable.page.wiki.project, :version => o.journal.journable.version}}, :event_url => Proc.new {|o| {:controller => '/wiki', :action => 'show', :id => o.journal.journable.page, :project_id => o.journal.journable.page.wiki.project, :version => o.journal.journable.version}},
:activity_type => 'wiki_edits', :activity_type => 'wiki_edits',
:activity_permission => :view_wiki_edits, :activity_permission => :view_wiki_edits,
:activity_find_options => { :include => { :page => { :wiki => :project } } } :activity_find_options => { :include => { :page => { :wiki => :project } } }

@ -239,7 +239,7 @@ class WikiPage < ActiveRecord::Base
end end
def to_param def to_param
title CGI.escape title
end end
def is_only_wiki_page? def is_only_wiki_page?

@ -28,14 +28,14 @@ See doc/COPYRIGHT.rdoc for more details.
++#%> ++#%>
<div class="contextual"> <div class="contextual">
<%= link_to(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit') %> <%= link_to(l(:button_edit), {:action => 'edit', :id => @page}, :class => 'icon icon-edit') %>
<%= link_to(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> <%= link_to(l(:label_history), {:action => 'history', :id => @page}, :class => 'icon icon-history') %>
</div> </div>
<h2><%= h(@page.pretty_title) %></h2> <h2><%= h(@page.pretty_title) %></h2>
<p> <p>
<%= Version.model_name.human %> <%= link_to h(@annotate.content.version), :action => 'show', :id => @page.title, :version => @annotate.content.version %> <%= Version.model_name.human %> <%= link_to h(@annotate.content.version), :action => 'show', :id => @page, :version => @annotate.content.version %>
<em>(<%= h(@annotate.content.journable.author ? @annotate.content.journable.author.name : l(:label_user_anonymous)) %>, <%= format_time(@annotate.content.journable.updated_on) %>)</em> <em>(<%= h(@annotate.content.journable.author ? @annotate.content.journable.author.name : l(:label_user_anonymous)) %>, <%= format_time(@annotate.content.journable.updated_on) %>)</em>
</p> </p>
@ -47,7 +47,7 @@ See doc/COPYRIGHT.rdoc for more details.
<% @annotate.lines.each do |line| -%> <% @annotate.lines.each do |line| -%>
<tr class="bloc-<%= colors[line[0]] %>"> <tr class="bloc-<%= colors[line[0]] %>">
<th class="line-num"><%= line_num %></th> <th class="line-num"><%= line_num %></th>
<td class="revision"><%= link_to line[0], :controller => '/wiki', :action => 'show', :project_id => @project, :id => @page.title, :version => line[0] %></td> <td class="revision"><%= link_to line[0], :controller => '/wiki', :action => 'show', :project_id => @project, :id => @page, :version => line[0] %></td>
<td class="author"><%= h(line[1]) %></td> <td class="author"><%= h(line[1]) %></td>
<td class="line-code"><pre><%=h line[2] %></pre></td> <td class="line-code"><pre><%=h line[2] %></pre></td>
</tr> </tr>

@ -45,5 +45,5 @@ See doc/COPYRIGHT.rdoc for more details.
</div> </div>
<%= submit_tag l(:button_apply) %> <%= submit_tag l(:button_apply) %>
<%= link_to l(:button_cancel), :controller => '/wiki', :action => 'show', :project_id => @project, :id => @page.title %> <%= link_to l(:button_cancel), controller: '/wiki', action: 'show', project_id: @project, id: @page %>
<% end %> <% end %>

@ -28,16 +28,16 @@ See doc/COPYRIGHT.rdoc for more details.
++#%> ++#%>
<div class="contextual"> <div class="contextual">
<%= link_to(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> <%= link_to(l(:label_history), {:action => 'history', :id => @page}, :class => 'icon icon-history') %>
</div> </div>
<h2><%= h(@page.pretty_title) %></h2> <h2><%= h(@page.pretty_title) %></h2>
<p> <p>
<%= Version.model_name.human %> <%= link_to @diff.content_from.version, :action => 'show', :id => @page.title, :project_id => @page.project, :version => @diff.content_from.version %>/<%= @page.content.version %> <%= Version.model_name.human %> <%= link_to @diff.content_from.version, :action => 'show', :id => @page, :project_id => @page.project, :version => @diff.content_from.version %>/<%= @page.content.version %>
<em>(<%= @diff.content_from.user ? link_to_user(@diff.content_from.user) : l(:label_user_anonymous) %>, <%= format_time(@diff.content_from.created_at) %>)</em> <em>(<%= @diff.content_from.user ? link_to_user(@diff.content_from.user) : l(:label_user_anonymous) %>, <%= format_time(@diff.content_from.created_at) %>)</em>
&#8594; &#8594;
<%= Version.model_name.human %> <%= link_to @diff.content_to.version, :action => 'show', :id => @page.title, :project_id => @page.project, :version => @diff.content_to.version %>/<%= @page.content.version %> <%= Version.model_name.human %> <%= link_to @diff.content_to.version, :action => 'show', :id => @page, :project_id => @page.project, :version => @diff.content_to.version %>/<%= @page.content.version %>
<em>(<%= @diff.content_to.user ? link_to_user(@diff.content_to.user) : l(:label_user_anonymous) %>, <%= format_time(@diff.content_to.created_at) %>)</em> <em>(<%= @diff.content_to.user ? link_to_user(@diff.content_to.user) : l(:label_user_anonymous) %>, <%= format_time(@diff.content_to.created_at) %>)</em>
</p> </p>

@ -29,7 +29,7 @@ See doc/COPYRIGHT.rdoc for more details.
<h2><%=h @page.pretty_title %></h2> <h2><%=h @page.pretty_title %></h2>
<%= form_for @content, :as => :content, :url => {:action => 'update', :id => @page.title}, :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %> <%= form_for @content, :as => :content, :url => {:action => 'update', :id => @page}, :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %>
<%= f.hidden_field :lock_version %> <%= f.hidden_field :lock_version %>
<%= error_messages_for 'content' %> <%= error_messages_for 'content' %>
@ -40,7 +40,7 @@ See doc/COPYRIGHT.rdoc for more details.
<p><%= submit_tag l(:button_save) %> <p><%= submit_tag l(:button_save) %>
<%= link_to_remote l(:label_preview), <%= link_to_remote l(:label_preview),
{ :url => { :controller => '/wiki', :action => 'preview', :project_id => @project, :id => @page.title }, { :url => { :controller => '/wiki', :action => 'preview', :project_id => @project, :id => @page },
:method => :post, :method => :post,
:update => 'preview', :update => 'preview',
:before => 'var form_data = Form.serialize("wiki_form", true); form_data._method="post";', :before => 'var form_data = Form.serialize("wiki_form", true); form_data._method="post";',

@ -31,7 +31,7 @@ See doc/COPYRIGHT.rdoc for more details.
<%= error_messages_for 'page' %> <%= error_messages_for 'page' %>
<%= labelled_tabular_form_for @page, :url => { :action => 'update_parent_page' } do |f| %> <%= labelled_tabular_form_for @page, :url => { id: @page, action: 'update_parent_page' } do |f| %>
<div class="box"> <div class="box">
<p> <p>
<%= f.select :parent_id, <%= f.select :parent_id,

@ -49,13 +49,13 @@ h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display
<strong><%= l(:label_index_by_title) %></strong> <strong><%= l(:label_index_by_title) %></strong>
<ul> <ul>
<% @pages.each do |page| %> <% @pages.each do |page| %>
<li><a href="#<%= h(page.title) %>"><%= h(page.pretty_title) %></a></li> <li><a href="#<%= h(page.to_param) %>"><%= h(page.pretty_title) %></a></li>
<% end %> <% end %>
</ul> </ul>
<% @pages.each do |page| %> <% @pages.each do |page| %>
<hr /> <hr />
<a name="<%= h(page.title) %>" /> <a name="<%= h(page.to_param) %>" />
<%= textilizable page.content ,:text, :wiki_links => :anchor %> <%= textilizable page.content ,:text, :wiki_links => :anchor %>
<% end %> <% end %>

@ -47,7 +47,7 @@ See doc/COPYRIGHT.rdoc for more details.
<% line_num = 1 %> <% line_num = 1 %>
<% @versions.each do |ver| %> <% @versions.each do |ver| %>
<tr class="wiki-page-version <%= cycle("odd", "even") %>"> <tr class="wiki-page-version <%= cycle("odd", "even") %>">
<td class="id"><%= link_to h(ver.version), :action => 'show', :id => @page.title, :project_id => @page.project, :version => ver.version %></td> <td class="id"><%= link_to h(ver.version), :action => 'show', :id => @page, :project_id => @page.project, :version => ver.version %></td>
<td class="checkbox"> <td class="checkbox">
<% if show_diff && (line_num < @versions.size) %> <% if show_diff && (line_num < @versions.size) %>
<label for="<%="cb-#{line_num}"%>" class="hidden-for-sighted"><%=l(:description_compare_from) + " " + h(ver.version.to_s) %></label> <label for="<%="cb-#{line_num}"%>" class="hidden-for-sighted"><%=l(:description_compare_from) + " " + h(ver.version.to_s) %></label>
@ -63,7 +63,7 @@ See doc/COPYRIGHT.rdoc for more details.
<td class="updated_on"><%= format_time(ver.created_at) %></td> <td class="updated_on"><%= format_time(ver.created_at) %></td>
<td class="author"><%= link_to_user ver.user %></td> <td class="author"><%= link_to_user ver.user %></td>
<td class="comments"><%=h ver.notes %></td> <td class="comments"><%=h ver.notes %></td>
<td class="buttons"><%= link_to l(:button_annotate), :action => 'annotate', :id => @page.title, :version => ver.version %></td> <td class="buttons"><%= link_to l(:button_annotate), :action => 'annotate', :id => @page, :version => ver.version %></td>
</tr> </tr>
<% line_num += 1 %> <% line_num += 1 %>
<% end %> <% end %>

@ -31,7 +31,7 @@ See doc/COPYRIGHT.rdoc for more details.
<%= error_messages_for 'page' %> <%= error_messages_for 'page' %>
<%= labelled_tabular_form_for @page, :url => { :action => 'rename' }, :as => :wiki_page do |f| %> <%= labelled_tabular_form_for @page, :url => { id: @page, action: 'rename' }, :as => :wiki_page do |f| %>
<div class="box"> <div class="box">
<p><%= f.text_field :title, :required => true, :size => 100 %></p> <p><%= f.text_field :title, :required => true, :size => 100 %></p>
<p><%= f.check_box :redirect_existing_links %></p> <p><%= f.check_box :redirect_existing_links %></p>

@ -30,44 +30,44 @@ See doc/COPYRIGHT.rdoc for more details.
<%= call_hook :wiki_navigation %> <%= call_hook :wiki_navigation %>
<% content_for :action_menu_main do %> <% content_for :action_menu_main do %>
<% if @editable %> <% if @editable %>
<%= li_unless_nil(link_to_if_authorized(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit))) if @content.version == @page.content.version %> <%= li_unless_nil(link_to_if_authorized(l(:button_edit), {:action => 'edit', :id => @page}, :class => 'icon icon-edit', :accesskey => accesskey(:edit))) if @content.version == @page.content.version %>
<%= li_unless_nil(watcher_link(@page, User.current)) if Setting.notified_events.include?("wiki_content_added") or Setting.notified_events.include?("wiki_content_updated") %> <%= li_unless_nil(watcher_link(@page, User.current)) if Setting.notified_events.include?("wiki_content_added") or Setting.notified_events.include?("wiki_content_updated") %>
<% end %> <% end %>
<% end %> <% end %>
<% content_for :action_menu_more do %> <% content_for :action_menu_more do %>
<% if @editable %> <% if @editable %>
<%= li_unless_nil(link_to_if_authorized(l(:button_lock), {:action => 'protect', :id => @page.title, :protected => 1}, :method => :post, :class => 'icon icon-lock')) if !@page.protected? %> <%= li_unless_nil(link_to_if_authorized(l(:button_lock), {:action => 'protect', :id => @page, :protected => 1}, :method => :post, :class => 'icon icon-lock')) if !@page.protected? %>
<%= li_unless_nil(link_to_if_authorized(l(:button_unlock), {:action => 'protect', :id => @page.title, :protected => 0}, :method => :post, :class => 'icon icon-unlock')) if @page.protected? %> <%= li_unless_nil(link_to_if_authorized(l(:button_unlock), {:action => 'protect', :id => @page, :protected => 0}, :method => :post, :class => 'icon icon-unlock')) if @page.protected? %>
<% if User.current.allowed_to? :edit_wiki_pages, @project %> <% if User.current.allowed_to? :edit_wiki_pages, @project %>
<% if @page %> <% if @page %>
<%= content_tag(:li, link_to(l(:create_child_page), wiki_new_child_path(:id => @page.title, :project_id => @project), :class => 'icon icon-duplicate')) %> <%= content_tag(:li, link_to(l(:create_child_page), wiki_new_child_path(:id => @page, :project_id => @project), :class => 'icon icon-duplicate')) %>
<% end %> <% end %>
<% end %> <% end %>
<% if @content.version == @page.content.version %> <% if @content.version == @page.content.version %>
<%= li_unless_nil(link_to_if_authorized(t(:button_rename), <%= li_unless_nil(link_to_if_authorized(t(:button_rename),
{:action => 'rename', :id => @page.title}, {:action => 'rename', :id => @page},
:class => 'icon icon-rename')) %> :class => 'icon icon-rename')) %>
<%= li_unless_nil(link_to_if_authorized(t(:button_change_parent_page), <%= li_unless_nil(link_to_if_authorized(t(:button_change_parent_page),
{:action => 'edit_parent_page', :id => @page.title}, {:action => 'edit_parent_page', :id => @page},
:class => 'icon icon-parent')) %> :class => 'icon icon-parent')) %>
<% end %> <% end %>
<%= li_unless_nil(link_to_if_authorized(l(:button_delete), {:action => 'destroy', :id => @page.title}, :method => :delete, :confirm => l(:text_are_you_sure), :class => 'icon icon-del')) %> <%= li_unless_nil(link_to_if_authorized(l(:button_delete), {:action => 'destroy', :id => @page}, :method => :delete, :confirm => l(:text_are_you_sure), :class => 'icon icon-del')) %>
<%= li_unless_nil(link_to_if_authorized(l(:button_rollback), {:action => 'edit', :id => @page.title, :version => @content.version }, :class => 'icon icon-cancel')) if @content.version < @page.content.version %> <%= li_unless_nil(link_to_if_authorized(l(:button_rollback), {:action => 'edit', :id => @page, :version => @content.version }, :class => 'icon icon-cancel')) if @content.version < @page.content.version %>
<% end %> <% end %>
<%= li_unless_nil(link_to_if_authorized(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history')) %> <%= li_unless_nil(link_to_if_authorized(l(:label_history), {:action => 'history', :id => @page}, :class => 'icon icon-history')) %>
<%= li_unless_nil(link_to_if_authorized(l(:button_wiki_menu_entry), {:controller => '/wiki_menu_items', :action => 'edit', :project_id => @project.identifier, :id => @page.title}, :class => 'icon icon-configure')) %> <%= li_unless_nil(link_to_if_authorized(l(:button_wiki_menu_entry), {:controller => '/wiki_menu_items', :action => 'edit', :project_id => @project.identifier, :id => @page}, :class => 'icon icon-configure')) %>
<% end %> <% end %>
<% breadcrumb_paths(*(@page.ancestors.reverse.collect {|parent| link_to h(parent.breadcrumb_title), {:id => parent.title, :project_id => parent.project}} + [h(@page.breadcrumb_title)])) %> <% breadcrumb_paths(*(@page.ancestors.reverse.collect {|parent| link_to h(parent.breadcrumb_title), {:id => parent, :project_id => parent.project}} + [h(@page.breadcrumb_title)])) %>
<% if @content.version != @page.content.version %> <% if @content.version != @page.content.version %>
<p> <p>
<%= link_to(l(:label_previous), { :action => 'show', :id => @page.title, :project_id => @page.project, :version => (@content.version - 1) }, :class => 'navigate-left') + " - " if @content.version > 1 %> <%= link_to(l(:label_previous), { :action => 'show', :id => @page, :project_id => @page.project, :version => (@content.version - 1) }, :class => 'navigate-left') + " - " if @content.version > 1 %>
<%= "#{Version.model_name.human} #{@content.version}/#{@page.content.version}" %> <%= "#{Version.model_name.human} #{@content.version}/#{@page.content.version}" %>
<%= '(' + link_to(l(:label_diff), :controller => '/wiki', :action => 'diff', :id => @page.title, :project_id => @page.project, :version => @content.version) + ')' if @content.version > 1 %> - <%= '(' + link_to(l(:label_diff), :controller => '/wiki', :action => 'diff', :id => @page, :project_id => @page.project, :version => @content.version) + ')' if @content.version > 1 %> -
<%= link_to(l(:label_next), :action => 'show', :id => @page.title, :project_id => @page.project, :version => (@content.version + 1), :class => 'navigate-right') + " - " if @content.version < @page.content.version %> <%= link_to(l(:label_next), :action => 'show', :id => @page, :project_id => @page.project, :version => (@content.version + 1), :class => 'navigate-right') + " - " if @content.version < @page.content.version %>
<%= link_to(l(:label_current_version), :action => 'show', :id => @page.title, :project_id => @page.project) %> <%= link_to(l(:label_current_version), :action => 'show', :id => @page, :project_id => @page.project) %>
<br /> <br />
<em><%= @content.author ? link_to_user(@content.author) : l(:label_user_anonymous) %>, <%= format_time(@content.updated_on) %> </em><br /> <em><%= @content.author ? link_to_user(@content.author) : l(:label_user_anonymous) %>, <%= format_time(@content.updated_on) %> </em><br />
<%=h @content.comments %> <%=h @content.comments %>
@ -83,7 +83,7 @@ See doc/COPYRIGHT.rdoc for more details.
<div id="wiki_add_attachment"> <div id="wiki_add_attachment">
<p><%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;", <p><%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;",
:id => 'attach_files_link' %></p> :id => 'attach_files_link' %></p>
<%= form_tag({ :controller => '/wiki', :action => 'add_attachment', :project_id => @project, :id => @page.title }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %> <%= form_tag({ :controller => '/wiki', :action => 'add_attachment', :project_id => @project, :id => @page }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %>
<div class="box"> <div class="box">
<p><%= render :partial => 'attachments/form' %></p> <p><%= render :partial => 'attachments/form' %></p>
</div> </div>
@ -98,9 +98,9 @@ See doc/COPYRIGHT.rdoc for more details.
:action => 'index', :action => 'index',
:show_wiki_edits => 1, :show_wiki_edits => 1,
:key => User.current.rss_key } %> :key => User.current.rss_key } %>
<%= f.link_to 'HTML', :url => { :version => @content.version } %> <%= f.link_to 'HTML', :url => { version: @content.version, id: @page } %>
<%= f.link_to 'TXT', :url => { :version => @content.version } %> <%= f.link_to 'TXT', :url => { version: @content.version, id: @page } %>
<%= call_hook(:view_wiki_show_other_formats, {:link_builder => f, :url_params => {:id => @page.title, :version => @content.version}}) %> <%= call_hook(:view_wiki_show_other_formats, {:link_builder => f, :url_params => {:id => @page, :version => @content.version}}) %>
<% end if User.current.allowed_to?(:export_wiki_pages, @project) %> <% end if User.current.allowed_to?(:export_wiki_pages, @project) %>
<% content_for :header_tags do %> <% content_for :header_tags do %>

@ -29,10 +29,10 @@ See doc/COPYRIGHT.rdoc for more details.
<%= error_messages_for "wiki_menu_item", :object => @wiki_menu_item %> <%= error_messages_for "wiki_menu_item", :object => @wiki_menu_item %>
<% breadcrumb_paths(*@page.ancestors.reverse.collect {|parent| link_to h(parent.pretty_title), {:id => parent.title, :project_id => parent.project}}.push(@page.title)) %> <% breadcrumb_paths(*@page.ancestors.reverse.collect {|parent| link_to h(parent.pretty_title), {:id => parent.title, :project_id => parent.project}}.push(@page)) %>
<h2><%= l(:wiki_menu_item_for, :title => @page_title) %></h2> <h2><%= l(:wiki_menu_item_for, :title => @page_title) %></h2>
<%= form_for @wiki_menu_item, :html => {:id => 'wiki_menu_item_form', :class => 'wiki_menu_item_form', :method => :put}, :url => wiki_menu_item_path(@project, @page_title) do |form| %> <%= form_for @wiki_menu_item, :html => {:id => 'wiki_menu_item_form', :class => 'wiki_menu_item_form', :method => :put}, :url => wiki_menu_item_path(@project, @page) do |form| %>
<p class="name_of_item"> <p class="name_of_item">
<%= form.label :name, l(:label_menu_item_name), {:id => 'name_of_item'} %> <%= form.label :name, l(:label_menu_item_name), {:id => 'name_of_item'} %>
<% if @wiki_menu_item.name.nil? %> <% if @wiki_menu_item.name.nil? %>

@ -127,6 +127,10 @@ default:
# autologin_cookie_path: # autologin_cookie_path:
# autologin_cookie_secure: # autologin_cookie_secure:
# disable browser cache for security reasons
# see: https://websecuritytool.codeplex.com/wikipage?title=Checks#http-cache-control-header-no-store
# disable_browser_cache: true
# Configuration of SCM executable command. # Configuration of SCM executable command.
# Absolute path (e.g. /usr/local/bin/hg) or command name (e.g. hg.exe, bzr.exe) # Absolute path (e.g. /usr/local/bin/hg) or command name (e.g. hg.exe, bzr.exe)
# On Windows, *.cmd, *.bat (e.g. hg.cmd, bzr.bat) does not work. # On Windows, *.cmd, *.bat (e.g. hg.cmd, bzr.bat) does not work.

@ -30,6 +30,12 @@
OpenProject::Application.routes.draw do OpenProject::Application.routes.draw do
root :to => 'welcome#index', :as => 'home' root :to => 'welcome#index', :as => 'home'
# Redirect deprecated issue links to new work packages uris
match '/issues(/)' => redirect('/work_packages/')
# The URI.escape doesn't escape / unless you ask it to.
# see https://github.com/rails/rails/issues/5688
match '/issues/*rest' => redirect { |params, req| "/work_packages/#{URI.escape(params[:rest])}" }
scope :controller => 'account' do scope :controller => 'account' do
get '/account/force_password_change', :action => 'force_password_change' get '/account/force_password_change', :action => 'force_password_change'
post '/account/change_password', :action => 'change_password' post '/account/change_password', :action => 'change_password'

@ -0,0 +1,45 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2011-2013 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.md for more details.
#++
require_relative 'migration_utils/yaml_migrator'
class MigrateSerializedYamlFromSyckToPsych < ActiveRecord::Migration
include Migration::YamlMigrator
def up
migrate_yaml_columns('syck', 'psych')
end
def down
migrate_yaml_columns('psych', 'syck')
end
def migrate_yaml_columns(source_yamler, target_yamler)
['filters', 'column_names', 'sort_criteria'].each do |column|
migrate_yaml('queries', column, source_yamler, target_yamler)
end
migrate_yaml('custom_field_translations', 'possible_values', source_yamler, target_yamler)
migrate_yaml('roles', 'permissions', source_yamler, target_yamler)
migrate_yaml('settings', 'value', source_yamler, target_yamler)
migrate_yaml('timelines', 'options', source_yamler, target_yamler)
migrate_yaml('user_preferences', 'others', source_yamler, target_yamler)
migrate_yaml('wiki_menu_items', 'options', source_yamler, target_yamler)
end
end

@ -9,7 +9,12 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
# #
require_relative 'migration_utils/utils'
class PlanningElementDataToWorkPackages < ActiveRecord::Migration class PlanningElementDataToWorkPackages < ActiveRecord::Migration
include Migration::Utils
def up def up
add_new_id_column add_new_id_column
@ -251,13 +256,31 @@ class PlanningElementDataToWorkPackages < ActiveRecord::Migration
num_updated = 1 num_updated = 1
while num_updated != 0 while num_updated != 0
num_updated = update <<-SQL num_updated = update set_root_id_for_children_db_statement
end
end
def set_root_id_for_children_db_statement
if mysql?
<<-SQL
UPDATE #{db_work_packages_table} AS child
JOIN #{db_work_packages_table} AS parent
ON (child.#{db_column('parent_id')} = parent.#{db_column('id')})
SET child.#{db_column('root_id')} = parent.#{db_column('id')}
WHERE child.#{db_column('root_id')} IS NULL
SQL
else
<<-SQL
UPDATE #{db_work_packages_table} UPDATE #{db_work_packages_table}
SET #{db_column('root_id')} = (SELECT parent.#{db_column('root_id')} SET #{db_column('root_id')} = (SELECT parent.#{db_column('root_id')}
FROM #{db_work_packages_table} AS parent FROM #{db_work_packages_table} AS parent
WHERE parent.#{db_column('id')} = #{db_work_packages_table}.#{db_column('parent_id')}) WHERE parent.#{db_column('id')} = #{db_work_packages_table}.#{db_column('parent_id')})
WHERE #{db_work_packages_table}.#{db_column('root_id')} IS NULL WHERE #{db_work_packages_table}.#{db_column('root_id')} IS NULL
SQL SQL
end end
end end

@ -44,6 +44,37 @@ class LegacyPlanningElementJournalData < ActiveRecord::Migration
migrator.run migrator.run
reset_public_key_sequence_in_postgres 'journals' reset_public_key_sequence_in_postgres 'journals'
unless migrator.missing_type_ids.empty?
puts "Cannot resolve new type ids for all journals!"\
"\n\n"\
"The following list contains all legacy planning element "\
"type ids for which no new type id exists. Furthermore, "\
"the list contains all journal ids for which no new type "\
"id exists."\
"\n\n"\
"#{migrator.missing_type_ids}"\
"\n\n"\
"The type id is set to '0' for all journals containing a "\
"planning element type id for which no type id exists."\
"\n\n\n"
end
unless migrator.missing_journaled_ids.empty?
puts "Cannot resolve work package ids for all journals!"\
"\n\n"\
"The following list contains all legacy planning element "\
"ids for which no new work package id exists. Furthermore,"\
" the list contains all journal ids for which no new"\
"work package id exists."\
"\n\n"\
"#{migrator.missing_journaled_ids}"\
"\n\n"\
"The work package id is set to '0' for all journals "\
"containing a planning element type id for which no type "\
"id exists."
"\n\n\n"
end
end end
def down def down
@ -66,7 +97,7 @@ class LegacyPlanningElementJournalData < ActiveRecord::Migration
def migrate_key_value_pairs!(to_insert, legacy_journal, journal_id) def migrate_key_value_pairs!(to_insert, legacy_journal, journal_id)
update_type_id(to_insert) update_type_id(to_insert, journal_id)
set_empty_description(to_insert) set_empty_description(to_insert)
@ -77,30 +108,31 @@ class LegacyPlanningElementJournalData < ActiveRecord::Migration
end end
def update_journaled_id(legacy_journal) def update_journaled_id(legacy_journal)
new_journaled_id = new_journaled_id_for_old(legacy_journal["journaled_id"]) legecy_journal_id = legacy_journal["id"]
old_journaled_id = legacy_journal["journaled_id"]
new_journaled_id = new_journaled_id_for_old(old_journaled_id)
if new_journaled_id.nil? if new_journaled_id.nil?
raise UnknownJournaledError, <<-MESSAGE.split("\n").map(&:strip!).join(" ") + "\n" add_missing_journaled_id_for_legacy_journal_id(old_journaled_id, legecy_journal_id)
No new journaled_id could be found to replace the journaled_id value of
#{legacy_journal["journaled_id"]} for the legacy journal with the id new_journaled_id = 0
#{legacy_journal["id"]}
MESSAGE
end end
legacy_journal["journaled_id"] = new_journaled_id legacy_journal["journaled_id"] = new_journaled_id
end end
def update_type_id(to_insert) def update_type_id(to_insert, journal_id)
return if to_insert["planning_element_type_id"].nil? || return if to_insert["planning_element_type_id"].nil? ||
to_insert["planning_element_type_id"].last.nil? to_insert["planning_element_type_id"].last.nil?
new_type_id = new_type_id_for_old(to_insert["planning_element_type_id"].last) old_type_id = to_insert["planning_element_type_id"].last
new_type_id = new_type_id_for_old(old_type_id)
if new_type_id.nil? if new_type_id.nil?
raise UnknownTypeError, <<-MESSAGE.split("\n").map(&:strip!).join(" ") + "\n" add_missing_type_id_for_journal_id(old_type_id, journal_id)
No new type_id could be found to replace the type_id value of
#{to_insert["planning_element_type_id"].last} new_type_id = 0
MESSAGE
end end
to_insert["type_id"] = [nil, new_type_id] to_insert["type_id"] = [nil, new_type_id]
@ -146,6 +178,24 @@ class LegacyPlanningElementJournalData < ActiveRecord::Migration
def set_empty_description(to_insert) def set_empty_description(to_insert)
to_insert['description'] = [nil, ''] unless to_insert.has_key?('description') to_insert['description'] = [nil, ''] unless to_insert.has_key?('description')
end end
def missing_journaled_ids
@missing_journaled_ids ||= {}
end
def add_missing_journaled_id_for_legacy_journal_id(old_journaled_id, legacy_journal_id)
missing_journaled_ids[old_journaled_id] = [] unless missing_journaled_ids.has_key? old_journaled_id
missing_journaled_ids[old_journaled_id] << legacy_journal_id
end
def missing_type_ids
@missing_type_ids ||= {}
end
def add_missing_type_id_for_journal_id(old_type_id, journal_id)
missing_type_ids[old_type_id] = [] unless missing_type_ids.has_key? old_type_id
missing_type_ids[old_type_id] << journal_id
end
end end
end end
end end

@ -27,7 +27,10 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require_relative 'migration_utils/utils'
class MigrateDefaultValuesInWorkPackageJournals < ActiveRecord::Migration class MigrateDefaultValuesInWorkPackageJournals < ActiveRecord::Migration
include Migration::Utils
def up def up
@ -47,14 +50,6 @@ class MigrateDefaultValuesInWorkPackageJournals < ActiveRecord::Migration
%w(author_id status_id priority_id) %w(author_id status_id priority_id)
end end
def postgres?
ActiveRecord::Base.connection.instance_values["config"][:adapter] == "postgresql"
end
def mysql?
ActiveRecord::Base.connection.instance_values["config"][:adapter] == "mysql2"
end
def migrate_field(field) def migrate_field(field)
if postgres? if postgres?
execute <<-SQL execute <<-SQL

@ -67,16 +67,28 @@ module Migration::Utils
private private
def missing_attachments def missing_attachments
result = select_all <<-SQL begin
SELECT * FROM ( result = select_all <<-SQL
SELECT a.container_id AS journaled_id, a.container_type AS journaled_type, a.id AS attachment_id, a.filename, MAX(aj.id) AS aj_id, MAX(j.version) AS last_version SELECT * FROM (
FROM attachments AS a JOIN journals AS j SELECT a.container_id AS journaled_id, a.container_type AS journaled_type, a.id AS attachment_id, a.filename, MAX(aj.id) AS aj_id, MAX(j.version) AS last_version
ON (a.container_id = j.journable_id AND a.container_type = j.journable_type) LEFT JOIN attachable_journals AS aj FROM attachments AS a JOIN journals AS j
ON (a.id = aj.attachment_id) ON (a.container_id = j.journable_id AND a.container_type = j.journable_type) LEFT JOIN attachable_journals AS aj
GROUP BY a.container_id, a.container_type, a.id, a.filename ON (a.id = aj.attachment_id)
) AS tmp GROUP BY a.container_id, a.container_type, a.id, a.filename
WHERE aj_id IS NULL ) AS tmp
SQL WHERE aj_id IS NULL
SQL
rescue ActiveRecord::StatementInvalid => ex
raise ex unless mysql?
raise "An MySQL error occured (see details below)!"\
"\n\n"\
"If you're facing an 'Illegal mix of collations error, consider "\
"running rake task "\
"'migrations:journals:fix_attachments_collation'."\
"\n\n"\
"#{ex.message}"
end
result.collect { |row| MissingAttachment.new(row['journaled_id'], result.collect { |row| MissingAttachment.new(row['journaled_id'],
row['journaled_type'], row['journaled_type'],

@ -19,6 +19,8 @@ module Migration::Utils
:last_version) :last_version)
def add_missing_customizable_journals def add_missing_customizable_journals
delete_invalid_work_package_custom_values
result = missing_custom_values result = missing_custom_values
repair_journals(result) repair_journals(result)
@ -66,6 +68,40 @@ module Migration::Utils
private private
# Removes all work package custom values that are not referenced by the
# work package's project AND type.
def delete_invalid_work_package_custom_values
if mysql?
delete <<-SQL
DELETE cv.* FROM custom_values AS cv
JOIN work_packages AS w ON (w.id = cv.customized_id AND cv.customized_type = 'WorkPackage')
JOIN custom_fields AS cf ON (cv.custom_field_id = cf.id)
JOIN projects AS p ON (w.project_id = p.id)
LEFT JOIN custom_fields_projects AS cfp ON (cv.custom_field_id = cfp.custom_field_id AND w.project_id = cfp.project_id)
LEFT JOIN custom_fields_types AS cft ON (cv.custom_field_id = cft.custom_field_id AND w.type_id = cft.type_id)
WHERE cfp.project_id IS NULL
OR cft.type_id IS NULL
SQL
else
delete <<-SQL
DELETE FROM custom_values AS cvd
WHERE EXISTS
(
SELECT w.id, cf.id, cfp.project_id, p.name, cft.type_id
FROM work_packages AS w
JOIN custom_values AS cv ON (w.id = cv.customized_id AND cv.customized_type = 'WorkPackage')
JOIN custom_fields AS cf ON (cv.custom_field_id = cf.id)
JOIN projects AS p ON (w.project_id = p.id)
LEFT JOIN custom_fields_projects AS cfp ON (cv.custom_field_id = cfp.custom_field_id AND w.project_id = cfp.project_id)
LEFT JOIN custom_fields_types AS cft ON (cv.custom_field_id = cft.custom_field_id AND w.type_id = cft.type_id)
WHERE (cfp.project_id IS NULL
OR cft.type_id IS NULL)
AND cv.id = cvd.id
);
SQL
end
end
def missing_custom_values def missing_custom_values
result = select_all <<-SQL result = select_all <<-SQL
SELECT tmp.customized_id, SELECT tmp.customized_id,

@ -41,6 +41,10 @@ module Migration
ActiveRecord::Base.connection.table_exists? name ActiveRecord::Base.connection.table_exists? name
end end
def db_column(name)
ActiveRecord::Base.connection.quote_column_name(name)
end
def db_columns(table_name) def db_columns(table_name)
ActiveRecord::Base.connection.columns table_name ActiveRecord::Base.connection.columns table_name
end end

@ -29,6 +29,7 @@
require_relative 'db_worker' require_relative 'db_worker'
require_relative 'legacy_table_checker' require_relative 'legacy_table_checker'
require 'syck'
module Migration module Migration
class IncompleteJournalsError < ::StandardError class IncompleteJournalsError < ::StandardError
@ -279,7 +280,7 @@ module Migration
changed_data = journal["changed_data"] changed_data = journal["changed_data"]
return Hash.new if changed_data.nil? return Hash.new if changed_data.nil?
current_yamler = YAML::ENGINE.yamler current_yamler = YAML::ENGINE.yamler || 'psych'
begin begin
# The change to 'syck' ensures that legacy data is correctly read from # The change to 'syck' ensures that legacy data is correctly read from
# the 'legacy_journals' table. Otherwise, we would end up with false # the 'legacy_journals' table. Otherwise, we would end up with false

@ -56,6 +56,14 @@ module Migration
ActiveRecord::Base.connection.reset_pk_sequence!(table) ActiveRecord::Base.connection.reset_pk_sequence!(table)
end end
def postgres?
ActiveRecord::Base.connection.instance_values["config"][:adapter] == "postgresql"
end
def mysql?
ActiveRecord::Base.connection.instance_values["config"][:adapter] == "mysql2"
end
private private
def select_rows_from_database(table, column_list, conditions) def select_rows_from_database(table, column_list, conditions)

@ -0,0 +1,48 @@
# 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_relative 'db_worker'
require 'syck'
module Migration
module YamlMigrator
include DbWorker
def migrate_yaml(table, column, source_yamler, target_yamler)
current_yamler = YAML::ENGINE.yamler
fetch_data(table,column).each do | data |
db_execute <<-SQL
UPDATE #{quoted_table_name(table)}
SET #{db_column(column)} = #{quote_value(yaml_to_yaml(data[column],source_yamler, target_yamler))}
WHERE id = #{data['id']};
SQL
end
ensure
# psych is the default starting at ruby 1.9.3, so we explicitely set it here
# in case no yamler was set to return to a sensible default
YAML::ENGINE.yamler = current_yamler.present? ? current_yamler : 'psych'
end
def fetch_data(table, column)
ActiveRecord::Base.connection.select_all <<-SQL
SELECT #{db_column('id')}, #{db_column(column)}
FROM #{quoted_table_name(table)}
WHERE #{db_column(column)} LIKE #{quote_value('---%')}
SQL
end
def yaml_to_yaml(data, source_yamler, target_yamler)
YAML::ENGINE.yamler = source_yamler
original = YAML.load(data)
YAML::ENGINE.yamler = target_yamler
YAML.dump original
end
end
end

@ -31,12 +31,21 @@ See doc/COPYRIGHT.rdoc for more details.
* `#2653` Remove relative vertical offset corrections and custom border fixes for IE8. * `#2653` Remove relative vertical offset corrections and custom border fixes for IE8.
* `#2654` Remove custom font rendering/kerning as well as VML from timelines. * `#2654` Remove custom font rendering/kerning as well as VML from timelines.
* `#2699` [Wiki] 400 error when entering special character in wiki title
* Fix mysql data migrations
## 3.0.0pre30
* Redirect old issue links to new work package URIs
* `#2721` Fix: Fix: Fix: Fix: Missing journal entries for customizable_journals
* `#2731` Migrated serialized yaml from syck to psych
## 3.0.0pre29 ## 3.0.0pre29
* `#2473` [Timelines] Tooltip in timeline report shows star * instead of hash # in front of ID * `#2473` [Timelines] Tooltip in timeline report shows star * instead of hash # in front of ID
* `#2721` Fix: Fix: Fix: Missing journal entries for customizable_journals * `#2721` Fix: Fix: Fix: Missing journal entries for customizable_journals
* `#2718` Newlines in workpackage descriptions aren't normalized for change tracking * `#2718` Newlines in workpackage descriptions aren't normalized for change tracking
* `#1748` Add option to diable browser cache
## 3.0.0pre28 ## 3.0.0pre28

@ -0,0 +1,56 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2013 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Feature: Creating a wiki child page
Background:
Given there are no wiki menu items
And there is 1 user with the following:
| login | bob |
And there is a role "member"
And the role "member" may have the following rights:
| view_wiki_pages |
| edit_wiki_pages |
And there is 1 project with the following:
| name | project1 |
| identifier | project1 |
And the user "bob" is a "member" in the project "project1"
And I am already logged in as "bob"
@javascript
Scenario: Creating a wiki child page the title of which contains special characters
Given the project "project1" has 1 wiki page with the following:
| title | ParentWikiPage |
And the project "project1" has 1 wiki menu item with the following:
| title | ParentWikiPage |
| new_wiki_page | true |
When I go to the wiki new child page below the "ParentWikiPage" page of the project called "project1"
And I click "Create new child page"
And I fill in "page_title" with "Child Page !@#{$%^&*()_},./<>?;':"
And I click "Save"
Then I should see "Successful creation."

@ -39,6 +39,7 @@ module OpenProject
'database_cipher_key' => nil, 'database_cipher_key' => nil,
'scm_git_command' => nil, 'scm_git_command' => nil,
'scm_subversion_command' => nil, 'scm_subversion_command' => nil,
'disable_browser_cache' => true,
# email configuration # email configuration
'email_delivery_method' => nil, 'email_delivery_method' => nil,

@ -49,7 +49,7 @@ module OpenProject
# #
# 2.0.0debian-2 # 2.0.0debian-2
def self.special def self.special
'pre29' 'pre30'
end end
def self.revision def self.revision

@ -49,27 +49,27 @@ module Redmine::MenuManager::MenuHelper
WikiMenuItem.main_items(project_wiki).each do |main_item| WikiMenuItem.main_items(project_wiki).each do |main_item|
Redmine::MenuManager.loose :project_menu do |menu| Redmine::MenuManager.loose :project_menu do |menu|
menu.push "#{main_item.item_class}".to_sym, menu.push "#{main_item.item_class}".to_sym,
{ :controller => '/wiki', :action => 'show', :id => h(main_item.title) }, { :controller => '/wiki', :action => 'show', :id => CGI.escape(main_item.title) },
:param => :project_id, :param => :project_id,
:caption => main_item.name, :caption => main_item.name,
:after => :repository :after => :repository
menu.push :"#{main_item.item_class}_new_page", menu.push :"#{main_item.item_class}_new_page",
{ :action=>"new_child", :controller=>"/wiki", :id => h(main_item.title) }, { :action=>"new_child", :controller=>"/wiki", :id => CGI.escape(main_item.title) },
:param => :project_id, :param => :project_id,
:caption => :create_child_page, :caption => :create_child_page,
:parent => "#{main_item.item_class}".to_sym if main_item.new_wiki_page and :parent => "#{main_item.item_class}".to_sym if main_item.new_wiki_page and
WikiPage.find_by_wiki_id_and_title(project_wiki.id, main_item.title) WikiPage.find_by_wiki_id_and_title(project_wiki.id, main_item.title)
menu.push :"#{main_item.item_class}_toc", menu.push :"#{main_item.item_class}_toc",
{ :action => 'index', :controller => '/wiki', :id => h(main_item.title) }, { :action => 'index', :controller => '/wiki', :id => CGI.escape(main_item.title) },
:param => :project_id, :param => :project_id,
:caption => :label_table_of_contents, :caption => :label_table_of_contents,
:parent => "#{main_item.item_class}".to_sym if main_item.index_page :parent => "#{main_item.item_class}".to_sym if main_item.index_page
main_item.children.each do |child| main_item.children.each do |child|
menu.push "#{child.item_class}".to_sym, menu.push "#{child.item_class}".to_sym,
{ :controller => '/wiki', :action => 'show', :id => h(child.title) }, { :controller => '/wiki', :action => 'show', :id => CGI.escape(child.title) },
:param => :project_id, :param => :project_id,
:caption => child.name, :caption => child.name,
:parent => "#{main_item.item_class}".to_sym :parent => "#{main_item.item_class}".to_sym

@ -0,0 +1,24 @@
#-- 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.
#++
require_relative '../../db/migrate/migration_utils/utils'
namespace :migrations do
namespace :journals do
desc "Fixes 'attachments' table collation"
task :fix_attachments_collation => :environment do |task|
ActiveRecord::Base.connection.execute <<-SQL
ALTER TABLE attachments CONVERT TO character SET utf8 COLLATE utf8_unicode_ci;
SQL
end
end
end

@ -0,0 +1,61 @@
#-- 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.
#++
require_relative '../../db/migrate/migration_utils/timelines'
namespace :migrations do
namespace :journals do
desc "Quotes all strings starting with an invalid character in column 'changed_data' of table 'legacy_journals'"
task :quote_strings_with_invalid_characters_in_legacy_journals => :environment do |task|
quoter = InvalidChangedDataStringQuoter.new
quoter.quote_strings_with_invalid_characters
end
private
class InvalidChangedDataStringQuoter < ActiveRecord::Migration
include Migration::Utils
def quote_strings_with_invalid_characters
say_with_time_silently "Quote journal strings with invalid characters" do
update_column_values('legacy_journals',
['changed_data'],
quote_invalid_strings,
invalid_changed_data_filter)
end
end
private
def invalid_changed_data_filter
"changed_data LIKE '%- ,%'"
end
INVALID_STARTING_CHARACTER_REGEX = /(?<start>\n- )(?<text>,.*)(?<end>\n.*:)/
def quote_invalid_strings
Proc.new do |row|
changed_data = row['changed_data']
quoted_changed_data = changed_data.gsub(INVALID_STARTING_CHARACTER_REGEX) do |m|
"#{$1}\"#{$2}\"#{$3}"
end
row['changed_data'] = quoted_changed_data
UpdateResult.new(row, changed_data != quoted_changed_data)
end
end
end
end
end

@ -14,9 +14,6 @@ require_relative '../../db/migrate/migration_utils/timelines'
namespace :migrations do namespace :migrations do
namespace :timelines do namespace :timelines do
desc "Sets all timelines with historical comparison from 'historical' to 'none'" desc "Sets all timelines with historical comparison from 'historical' to 'none'"
task :remove_timelines_historical_comparison_from_options => :environment do |task| task :remove_timelines_historical_comparison_from_options => :environment do |task|
setter = TimelinesHistoricalComparisonSetter.new setter = TimelinesHistoricalComparisonSetter.new

@ -192,6 +192,7 @@ describe WikiController do
describe 'successful action' do describe 'successful action' do
context 'when it is not the only wiki page' do context 'when it is not the only wiki page' do
let(:wiki) { @project.wiki } let(:wiki) { @project.wiki }
let(:redirect_page_after_destroy) { wiki.find_page(wiki.start_page) || wiki.pages.first }
before do before do
another_wiki_page = FactoryGirl.create :wiki_page, wiki: wiki another_wiki_page = FactoryGirl.create :wiki_page, wiki: wiki
@ -199,7 +200,7 @@ describe WikiController do
it 'redirects to wiki#index' do it 'redirects to wiki#index' do
delete :destroy, project_id: @project, id: @existing_page delete :destroy, project_id: @project, id: @existing_page
response.should redirect_to action: 'index', project_id: @project response.should redirect_to action: 'index', project_id: @project, id: redirect_page_after_destroy
end end
end end

@ -106,14 +106,16 @@ describe WorkPackage do
end end
context 'when there is a legacy journal containing non-escaped newlines' do context 'when there is a legacy journal containing non-escaped newlines' do
before do let!(:work_package_journal_1) { FactoryGirl.create(:work_package_journal,
work_package_1.save journable_id: work_package_1.id,
# force the latest journal to match the description with unescaped newline characters version: 2,
legacy_journal = work_package_1.journals.last data: FactoryGirl.build(:journal_work_package_journal,
legacy_journal.data.update_column :description, changed_description description: description)) }
# rollback work package description to normalized newlines let!(:work_package_journal_2) { FactoryGirl.create(:work_package_journal,
work_package_1.update_attributes description: description journable_id: work_package_1.id,
end version: 3,
data: FactoryGirl.build(:journal_work_package_journal,
description: changed_description)) }
subject { work_package_1.journals.last.details } subject { work_package_1.journals.last.details }

@ -27,6 +27,11 @@
#++ #++
require 'rubygems' require 'rubygems'
if ENV['CI'] == true
# we are running on a CI server, report coverage to code climate
require "codeclimate-test-reporter"
CodeClimate::TestReporter.start
end
# This file is copied to spec/ when you run 'rails generate rspec:install' # This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test' ENV["RAILS_ENV"] ||= 'test'

@ -43,6 +43,14 @@ class WikiControllerTest < ActionController::TestCase
User.current = nil User.current = nil
end end
def wiki
Project.first.wiki
end
def redirect_page
wiki.find_page(wiki.start_page) || wiki.pages.first
end
def test_show_start_page def test_show_start_page
get :show, :project_id => 'ecookbook' get :show, :project_id => 'ecookbook'
assert_response :success assert_response :success
@ -97,7 +105,7 @@ class WikiControllerTest < ActionController::TestCase
:content => {:comments => 'Created the page', :content => {:comments => 'Created the page',
:text => "h1. New page\n\nThis is a new page" } :text => "h1. New page\n\nThis is a new page" }
assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page' assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page'
page = Project.find(1).wiki.find_page('New page') page = wiki.find_page('New page')
assert !page.new_record? assert !page.new_record?
assert_not_nil page.content assert_not_nil page.content
assert_equal 'Created the page', page.content.last_journal.notes assert_equal 'Created the page', page.content.last_journal.notes
@ -115,7 +123,7 @@ class WikiControllerTest < ActionController::TestCase
:attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}} :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
end end
end end
page = Project.find(1).wiki.find_page('New page') page = wiki.find_page('New page')
assert_equal 1, page.attachments.count assert_equal 1, page.attachments.count
assert_equal 'testfile.txt', page.attachments.first.filename assert_equal 'testfile.txt', page.attachments.first.filename
end end
@ -326,7 +334,6 @@ class WikiControllerTest < ActionController::TestCase
:wiki_page => { :title => 'Another renamed page', :wiki_page => { :title => 'Another renamed page',
:redirect_existing_links => 1 } :redirect_existing_links => 1 }
assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page' assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
wiki = Project.find(1).wiki
# Check redirects # Check redirects
assert_not_nil wiki.find_page('Another page') assert_not_nil wiki.find_page('Another page')
assert_nil wiki.find_page('Another page', :with_redirect => false) assert_nil wiki.find_page('Another page', :with_redirect => false)
@ -338,7 +345,6 @@ class WikiControllerTest < ActionController::TestCase
:wiki_page => { :title => 'Another renamed page', :wiki_page => { :title => 'Another renamed page',
:redirect_existing_links => "0" } :redirect_existing_links => "0" }
assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page' assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
wiki = Project.find(1).wiki
# Check that there's no redirects # Check that there's no redirects
assert_nil wiki.find_page('Another page') assert_nil wiki.find_page('Another page')
end end
@ -346,7 +352,7 @@ class WikiControllerTest < ActionController::TestCase
def test_destroy_child def test_destroy_child
@request.session[:user_id] = 2 @request.session[:user_id] = 2
delete :destroy, :project_id => 1, :id => 'Child_1' delete :destroy, :project_id => 1, :id => 'Child_1'
assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert_redirected_to action: 'index', project_id: 'ecookbook', id: redirect_page
end end
def test_destroy_parent def test_destroy_parent
@ -363,7 +369,7 @@ class WikiControllerTest < ActionController::TestCase
assert_difference('WikiPage.count', -1) do assert_difference('WikiPage.count', -1) do
delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'nullify' delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'nullify'
end end
assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert_redirected_to action: 'index', project_id: 'ecookbook', id: redirect_page
assert_nil WikiPage.find_by_id(2) assert_nil WikiPage.find_by_id(2)
end end
@ -372,7 +378,7 @@ class WikiControllerTest < ActionController::TestCase
assert_difference('WikiPage.count', -3) do assert_difference('WikiPage.count', -3) do
delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'destroy' delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'destroy'
end end
assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert_redirected_to action: 'index', project_id: 'ecookbook', id: redirect_page
assert_nil WikiPage.find_by_id(2) assert_nil WikiPage.find_by_id(2)
assert_nil WikiPage.find_by_id(5) assert_nil WikiPage.find_by_id(5)
end end
@ -382,7 +388,7 @@ class WikiControllerTest < ActionController::TestCase
assert_difference('WikiPage.count', -1) do assert_difference('WikiPage.count', -1) do
delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1
end end
assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert_redirected_to action: 'index', project_id: 'ecookbook', id: redirect_page
assert_nil WikiPage.find_by_id(2) assert_nil WikiPage.find_by_id(2)
assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
end end
@ -393,7 +399,7 @@ class WikiControllerTest < ActionController::TestCase
assert_template 'index' assert_template 'index'
pages = assigns(:pages) pages = assigns(:pages)
assert_not_nil pages assert_not_nil pages
assert_equal Project.find(1).wiki.pages.size, pages.size assert_equal wiki.pages.size, pages.size
assert_equal pages.first.content.updated_on, pages.first.updated_on assert_equal pages.first.content.updated_on, pages.first.updated_on
assert_tag :ul, :attributes => { :class => 'pages-hierarchy' }, assert_tag :ul, :attributes => { :class => 'pages-hierarchy' },

@ -29,6 +29,12 @@
ENV["RAILS_ENV"] = "test" ENV["RAILS_ENV"] = "test"
if ENV['CI'] == true
# we are running on a CI server, report coverage to code climate
require "codeclimate-test-reporter"
CodeClimate::TestReporter.start
end
require File.expand_path('../../config/environment', __FILE__) require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help' require 'rails/test_help'
require 'fileutils' require 'fileutils'

@ -73,10 +73,10 @@ class Redmine::WikiFormatting::MacrosTest < HelperTestCase
end end
def test_macro_child_pages def test_macro_child_pages
expected = "<p><ul class=\"pages-hierarchy\">\n" + expected = "<p><ul class=\"pages-hierarchy\">" +
"<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a></li>\n" + "<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a></li>" +
"<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" + "<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>" +
"</ul>\n</p>" "</ul></p>"
@project = Project.find(1) @project = Project.find(1)
# child pages of the current wiki page # child pages of the current wiki page
@ -89,12 +89,12 @@ class Redmine::WikiFormatting::MacrosTest < HelperTestCase
end end
def test_macro_child_pages_with_option def test_macro_child_pages_with_option
expected = "<p><ul class=\"pages-hierarchy\">\n" + expected = "<p><ul class=\"pages-hierarchy\">" +
"<li><a href=\"/projects/ecookbook/wiki/Another_page\">Another page</a>\n" + "<li><a href=\"/projects/ecookbook/wiki/Another_page\">Another page</a>" +
"<ul class=\"pages-hierarchy\">\n" + "<ul class=\"pages-hierarchy\">" +
"<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a></li>\n" + "<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a></li>" +
"<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" + "<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>" +
"</ul>\n</li>\n</ul>\n</p>" "</ul></li></ul></p>"
@project = Project.find(1) @project = Project.find(1)
# child pages of the current wiki page # child pages of the current wiki page

Loading…
Cancel
Save