@@ -553,8 +553,13 class ApplicationController < ActionController::Base | |||||
553 |
|
553 | |||
554 | # Renders a 200 response for successfull updates or deletions via the API |
|
554 | # Renders a 200 response for successfull updates or deletions via the API | |
555 | def render_api_ok |
|
555 | def render_api_ok | |
556 | # head :ok would return a response body with one space |
|
556 | render_api_head :ok | |
557 | render :text => '', :status => :ok, :layout => nil |
|
557 | end | |
|
558 | ||||
|
559 | # Renders a head API response | |||
|
560 | def render_api_head(status) | |||
|
561 | # #head would return a response body with one space | |||
|
562 | render :text => '', :status => status, :layout => nil | |||
558 | end |
|
563 | end | |
559 |
|
564 | |||
560 | # Renders API response on validation failure |
|
565 | # Renders API response on validation failure |
@@ -36,7 +36,7 class WikiController < ApplicationController | |||||
36 | before_filter :find_wiki, :authorize |
|
36 | before_filter :find_wiki, :authorize | |
37 | before_filter :find_existing_or_new_page, :only => [:show, :edit, :update] |
|
37 | before_filter :find_existing_or_new_page, :only => [:show, :edit, :update] | |
38 | before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version] |
|
38 | before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version] | |
39 | accept_api_auth :index, :show |
|
39 | accept_api_auth :index, :show, :update | |
40 |
|
40 | |||
41 | helper :attachments |
|
41 | helper :attachments | |
42 | include AttachmentsHelper |
|
42 | include AttachmentsHelper | |
@@ -130,15 +130,18 class WikiController < ApplicationController | |||||
130 | # Creates a new page or updates an existing one |
|
130 | # Creates a new page or updates an existing one | |
131 | def update |
|
131 | def update | |
132 | return render_403 unless editable? |
|
132 | return render_403 unless editable? | |
|
133 | was_new_page = @page.new_record? | |||
133 | @page.content = WikiContent.new(:page => @page) if @page.new_record? |
|
134 | @page.content = WikiContent.new(:page => @page) if @page.new_record? | |
134 | @page.safe_attributes = params[:wiki_page] |
|
135 | @page.safe_attributes = params[:wiki_page] | |
135 |
|
136 | |||
136 |
@content = @page.content |
|
137 | @content = @page.content | |
137 | @content.text = initial_page_content(@page) if @content.text.blank? |
|
138 | content_params = params[:content] | |
138 | # don't keep previous comment |
|
139 | if content_params.nil? && params[:wiki_page].is_a?(Hash) | |
139 | @content.comments = nil |
|
140 | content_params = params[:wiki_page].slice(:text, :comments, :version) | |
|
141 | end | |||
|
142 | content_params ||= {} | |||
140 |
|
143 | |||
141 |
if !@page.new_record? && |
|
144 | if !@page.new_record? && content_params.present? && @content.text == content_params[:text] | |
142 | attachments = Attachment.attach_files(@page, params[:attachments]) |
|
145 | attachments = Attachment.attach_files(@page, params[:attachments]) | |
143 | render_attachment_warning_if_needed(@page) |
|
146 | render_attachment_warning_if_needed(@page) | |
144 | # don't save content if text wasn't changed |
|
147 | # don't save content if text wasn't changed | |
@@ -147,14 +150,14 class WikiController < ApplicationController | |||||
147 | return |
|
150 | return | |
148 | end |
|
151 | end | |
149 |
|
152 | |||
150 |
@content.comments = |
|
153 | @content.comments = content_params[:comments] | |
151 |
@text = |
|
154 | @text = content_params[:text] | |
152 | if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? |
|
155 | if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? | |
153 | @section = params[:section].to_i |
|
156 | @section = params[:section].to_i | |
154 | @section_hash = params[:section_hash] |
|
157 | @section_hash = params[:section_hash] | |
155 | @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash) |
|
158 | @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash) | |
156 | else |
|
159 | else | |
157 |
@content.version = params[: |
|
160 | @content.version = content_params[:version] if content_params[:version] | |
158 | @content.text = @text |
|
161 | @content.text = @text | |
159 | end |
|
162 | end | |
160 | @content.author = User.current |
|
163 | @content.author = User.current | |
@@ -163,17 +166,38 class WikiController < ApplicationController | |||||
163 | attachments = Attachment.attach_files(@page, params[:attachments]) |
|
166 | attachments = Attachment.attach_files(@page, params[:attachments]) | |
164 | render_attachment_warning_if_needed(@page) |
|
167 | render_attachment_warning_if_needed(@page) | |
165 | call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page}) |
|
168 | call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page}) | |
166 | redirect_to :action => 'show', :project_id => @project, :id => @page.title |
|
169 | ||
|
170 | respond_to do |format| | |||
|
171 | format.html { redirect_to :action => 'show', :project_id => @project, :id => @page.title } | |||
|
172 | format.api { | |||
|
173 | if was_new_page | |||
|
174 | render :action => 'show', :status => :created, :location => url_for(:controller => 'wiki', :action => 'show', :project_id => @project, :id => @page.title) | |||
|
175 | else | |||
|
176 | render_api_ok | |||
|
177 | end | |||
|
178 | } | |||
|
179 | end | |||
167 | else |
|
180 | else | |
168 | render :action => 'edit' |
|
181 | respond_to do |format| | |
|
182 | format.html { render :action => 'edit' } | |||
|
183 | format.api { render_validation_errors(@content) } | |||
|
184 | end | |||
169 | end |
|
185 | end | |
170 |
|
186 | |||
171 | rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError |
|
187 | rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError | |
172 | # Optimistic locking exception |
|
188 | # Optimistic locking exception | |
173 | flash.now[:error] = l(:notice_locking_conflict) |
|
189 | respond_to do |format| | |
174 | render :action => 'edit' |
|
190 | format.html { | |
|
191 | flash.now[:error] = l(:notice_locking_conflict) | |||
|
192 | render :action => 'edit' | |||
|
193 | } | |||
|
194 | format.api { render_api_head :conflict } | |||
|
195 | end | |||
175 | rescue ActiveRecord::RecordNotSaved |
|
196 | rescue ActiveRecord::RecordNotSaved | |
176 | render :action => 'edit' |
|
197 | respond_to do |format| | |
|
198 | format.html { render :action => 'edit' } | |||
|
199 | format.api { render_validation_errors(@content) } | |||
|
200 | end | |||
177 | end |
|
201 | end | |
178 |
|
202 | |||
179 | # rename a page |
|
203 | # rename a page |
@@ -57,7 +57,7 class WikiPage < ActiveRecord::Base | |||||
57 | # Wiki pages that are protected by default |
|
57 | # Wiki pages that are protected by default | |
58 | DEFAULT_PROTECTED_PAGES = %w(sidebar) |
|
58 | DEFAULT_PROTECTED_PAGES = %w(sidebar) | |
59 |
|
59 | |||
60 | safe_attributes 'parent_id', |
|
60 | safe_attributes 'parent_id', 'parent_title', | |
61 | :if => lambda {|page, user| page.new_record? || user.allowed_to?(:rename_wiki_pages, page.project)} |
|
61 | :if => lambda {|page, user| page.new_record? || user.allowed_to?(:rename_wiki_pages, page.project)} | |
62 |
|
62 | |||
63 | def initialize(attributes=nil, *args) |
|
63 | def initialize(attributes=nil, *args) |
@@ -28,7 +28,7 class ApiTest::WikiPagesTest < ActionController::IntegrationTest | |||||
28 |
|
28 | |||
29 | test "GET /projects/:project_id/wiki/index.xml should return wiki pages" do |
|
29 | test "GET /projects/:project_id/wiki/index.xml should return wiki pages" do | |
30 | get '/projects/ecookbook/wiki/index.xml' |
|
30 | get '/projects/ecookbook/wiki/index.xml' | |
31 |
assert_response |
|
31 | assert_response 200 | |
32 | assert_equal 'application/xml', response.content_type |
|
32 | assert_equal 'application/xml', response.content_type | |
33 | assert_select 'wiki_pages[type=array]' do |
|
33 | assert_select 'wiki_pages[type=array]' do | |
34 | assert_select 'wiki_page', :count => Wiki.find(1).pages.count |
|
34 | assert_select 'wiki_page', :count => Wiki.find(1).pages.count | |
@@ -38,12 +38,16 class ApiTest::WikiPagesTest < ActionController::IntegrationTest | |||||
38 | assert_select 'created_on' |
|
38 | assert_select 'created_on' | |
39 | assert_select 'updated_on' |
|
39 | assert_select 'updated_on' | |
40 | end |
|
40 | end | |
|
41 | assert_select 'wiki_page' do | |||
|
42 | assert_select 'title', :text => 'Page_with_an_inline_image' | |||
|
43 | assert_select 'parent[title=?]', 'CookBook_documentation' | |||
|
44 | end | |||
41 | end |
|
45 | end | |
42 | end |
|
46 | end | |
43 |
|
47 | |||
44 | test "GET /projects/:project_id/wiki/:title.xml should return wiki page" do |
|
48 | test "GET /projects/:project_id/wiki/:title.xml should return wiki page" do | |
45 | get '/projects/ecookbook/wiki/CookBook_documentation.xml' |
|
49 | get '/projects/ecookbook/wiki/CookBook_documentation.xml' | |
46 |
assert_response |
|
50 | assert_response 200 | |
47 | assert_equal 'application/xml', response.content_type |
|
51 | assert_equal 'application/xml', response.content_type | |
48 | assert_select 'wiki_page' do |
|
52 | assert_select 'wiki_page' do | |
49 | assert_select 'title', :text => 'CookBook_documentation' |
|
53 | assert_select 'title', :text => 'CookBook_documentation' | |
@@ -63,7 +67,7 class ApiTest::WikiPagesTest < ActionController::IntegrationTest | |||||
63 |
|
67 | |||
64 | test "GET /projects/:project_id/wiki/:title/:version.xml should return wiki page version" do |
|
68 | test "GET /projects/:project_id/wiki/:title/:version.xml should return wiki page version" do | |
65 | get '/projects/ecookbook/wiki/CookBook_documentation/2.xml' |
|
69 | get '/projects/ecookbook/wiki/CookBook_documentation/2.xml' | |
66 |
assert_response |
|
70 | assert_response 200 | |
67 | assert_equal 'application/xml', response.content_type |
|
71 | assert_equal 'application/xml', response.content_type | |
68 | assert_select 'wiki_page' do |
|
72 | assert_select 'wiki_page' do | |
69 | assert_select 'title', :text => 'CookBook_documentation' |
|
73 | assert_select 'title', :text => 'CookBook_documentation' | |
@@ -82,4 +86,83 class ApiTest::WikiPagesTest < ActionController::IntegrationTest | |||||
82 | assert_response 401 |
|
86 | assert_response 401 | |
83 | assert_equal 'application/xml', response.content_type |
|
87 | assert_equal 'application/xml', response.content_type | |
84 | end |
|
88 | end | |
|
89 | ||||
|
90 | test "PUT /projects/:project_id/wiki/:title.xml should update wiki page" do | |||
|
91 | assert_no_difference 'WikiPage.count' do | |||
|
92 | assert_difference 'WikiContent::Version.count' do | |||
|
93 | put '/projects/ecookbook/wiki/CookBook_documentation.xml', | |||
|
94 | {:wiki_page => {:text => 'New content from API', :comments => 'API update'}}, | |||
|
95 | credentials('jsmith') | |||
|
96 | assert_response 200 | |||
|
97 | end | |||
|
98 | end | |||
|
99 | ||||
|
100 | page = WikiPage.find(1) | |||
|
101 | assert_equal 'New content from API', page.content.text | |||
|
102 | assert_equal 4, page.content.version | |||
|
103 | assert_equal 'API update', page.content.comments | |||
|
104 | assert_equal 'jsmith', page.content.author.login | |||
|
105 | end | |||
|
106 | ||||
|
107 | test "PUT /projects/:project_id/wiki/:title.xml with current versino should update wiki page" do | |||
|
108 | assert_no_difference 'WikiPage.count' do | |||
|
109 | assert_difference 'WikiContent::Version.count' do | |||
|
110 | put '/projects/ecookbook/wiki/CookBook_documentation.xml', | |||
|
111 | {:wiki_page => {:text => 'New content from API', :comments => 'API update', :version => '3'}}, | |||
|
112 | credentials('jsmith') | |||
|
113 | assert_response 200 | |||
|
114 | end | |||
|
115 | end | |||
|
116 | ||||
|
117 | page = WikiPage.find(1) | |||
|
118 | assert_equal 'New content from API', page.content.text | |||
|
119 | assert_equal 4, page.content.version | |||
|
120 | assert_equal 'API update', page.content.comments | |||
|
121 | assert_equal 'jsmith', page.content.author.login | |||
|
122 | end | |||
|
123 | ||||
|
124 | test "PUT /projects/:project_id/wiki/:title.xml with stale version should respond with 409" do | |||
|
125 | assert_no_difference 'WikiPage.count' do | |||
|
126 | assert_no_difference 'WikiContent::Version.count' do | |||
|
127 | put '/projects/ecookbook/wiki/CookBook_documentation.xml', | |||
|
128 | {:wiki_page => {:text => 'New content from API', :comments => 'API update', :version => '2'}}, | |||
|
129 | credentials('jsmith') | |||
|
130 | assert_response 409 | |||
|
131 | end | |||
|
132 | end | |||
|
133 | end | |||
|
134 | ||||
|
135 | test "PUT /projects/:project_id/wiki/:title.xml should create the page if it does not exist" do | |||
|
136 | assert_difference 'WikiPage.count' do | |||
|
137 | assert_difference 'WikiContent::Version.count' do | |||
|
138 | put '/projects/ecookbook/wiki/New_page_from_API.xml', | |||
|
139 | {:wiki_page => {:text => 'New content from API', :comments => 'API create'}}, | |||
|
140 | credentials('jsmith') | |||
|
141 | assert_response 201 | |||
|
142 | end | |||
|
143 | end | |||
|
144 | ||||
|
145 | page = WikiPage.order('id DESC').first | |||
|
146 | assert_equal 'New_page_from_API', page.title | |||
|
147 | assert_equal 'New content from API', page.content.text | |||
|
148 | assert_equal 1, page.content.version | |||
|
149 | assert_equal 'API create', page.content.comments | |||
|
150 | assert_equal 'jsmith', page.content.author.login | |||
|
151 | assert_nil page.parent | |||
|
152 | end | |||
|
153 | ||||
|
154 | test "PUT /projects/:project_id/wiki/:title.xml with parent" do | |||
|
155 | assert_difference 'WikiPage.count' do | |||
|
156 | assert_difference 'WikiContent::Version.count' do | |||
|
157 | put '/projects/ecookbook/wiki/New_subpage_from_API.xml', | |||
|
158 | {:wiki_page => {:parent_title => 'CookBook_documentation', :text => 'New content from API', :comments => 'API create'}}, | |||
|
159 | credentials('jsmith') | |||
|
160 | assert_response 201 | |||
|
161 | end | |||
|
162 | end | |||
|
163 | ||||
|
164 | page = WikiPage.order('id DESC').first | |||
|
165 | assert_equal 'New_subpage_from_API', page.title | |||
|
166 | assert_equal WikiPage.find(1), page.parent | |||
|
167 | end | |||
85 | end |
|
168 | end |
@@ -34,16 +34,6 class RoutingWikiTest < ActionController::IntegrationTest | |||||
34 | :id => 'lalala', :format => 'pdf' } |
|
34 | :id => 'lalala', :format => 'pdf' } | |
35 | ) |
|
35 | ) | |
36 | assert_routing( |
|
36 | assert_routing( | |
37 | { :method => 'get', :path => "/projects/567/wiki/lalala.xml" }, |
|
|||
38 | { :controller => 'wiki', :action => 'show', :project_id => '567', |
|
|||
39 | :id => 'lalala', :format => 'xml' } |
|
|||
40 | ) |
|
|||
41 | assert_routing( |
|
|||
42 | { :method => 'get', :path => "/projects/567/wiki/lalala.json" }, |
|
|||
43 | { :controller => 'wiki', :action => 'show', :project_id => '567', |
|
|||
44 | :id => 'lalala', :format => 'json' } |
|
|||
45 | ) |
|
|||
46 | assert_routing( |
|
|||
47 | { :method => 'get', :path => "/projects/1/wiki/CookBook_documentation/diff" }, |
|
37 | { :method => 'get', :path => "/projects/1/wiki/CookBook_documentation/diff" }, | |
48 | { :controller => 'wiki', :action => 'diff', :project_id => '1', |
|
38 | { :controller => 'wiki', :action => 'diff', :project_id => '1', | |
49 | :id => 'CookBook_documentation' } |
|
39 | :id => 'CookBook_documentation' } | |
@@ -54,16 +44,6 class RoutingWikiTest < ActionController::IntegrationTest | |||||
54 | :id => 'CookBook_documentation', :version => '2' } |
|
44 | :id => 'CookBook_documentation', :version => '2' } | |
55 | ) |
|
45 | ) | |
56 | assert_routing( |
|
46 | assert_routing( | |
57 | { :method => 'get', :path => "/projects/1/wiki/CookBook_documentation/2.xml" }, |
|
|||
58 | { :controller => 'wiki', :action => 'show', :project_id => '1', |
|
|||
59 | :id => 'CookBook_documentation', :version => '2', :format => 'xml' } |
|
|||
60 | ) |
|
|||
61 | assert_routing( |
|
|||
62 | { :method => 'get', :path => "/projects/1/wiki/CookBook_documentation/2.json" }, |
|
|||
63 | { :controller => 'wiki', :action => 'show', :project_id => '1', |
|
|||
64 | :id => 'CookBook_documentation', :version => '2', :format => 'json' } |
|
|||
65 | ) |
|
|||
66 | assert_routing( |
|
|||
67 | { :method => 'get', :path => "/projects/1/wiki/CookBook_documentation/2/diff" }, |
|
47 | { :method => 'get', :path => "/projects/1/wiki/CookBook_documentation/2/diff" }, | |
68 | { :controller => 'wiki', :action => 'diff', :project_id => '1', |
|
48 | { :controller => 'wiki', :action => 'diff', :project_id => '1', | |
69 | :id => 'CookBook_documentation', :version => '2' } |
|
49 | :id => 'CookBook_documentation', :version => '2' } | |
@@ -92,14 +72,6 class RoutingWikiTest < ActionController::IntegrationTest | |||||
92 | { :method => 'get', :path => "/projects/567/wiki/index" }, |
|
72 | { :method => 'get', :path => "/projects/567/wiki/index" }, | |
93 | { :controller => 'wiki', :action => 'index', :project_id => '567' } |
|
73 | { :controller => 'wiki', :action => 'index', :project_id => '567' } | |
94 | ) |
|
74 | ) | |
95 | assert_routing( |
|
|||
96 | { :method => 'get', :path => "/projects/567/wiki/index.xml" }, |
|
|||
97 | { :controller => 'wiki', :action => 'index', :project_id => '567', :format => 'xml' } |
|
|||
98 | ) |
|
|||
99 | assert_routing( |
|
|||
100 | { :method => 'get', :path => "/projects/567/wiki/index.json" }, |
|
|||
101 | { :controller => 'wiki', :action => 'index', :project_id => '567', :format => 'json' } |
|
|||
102 | ) |
|
|||
103 | end |
|
75 | end | |
104 |
|
76 | |||
105 | def test_wiki_resources |
|
77 | def test_wiki_resources | |
@@ -156,4 +128,45 class RoutingWikiTest < ActionController::IntegrationTest | |||||
156 | :id => 'ladida', :version => '3' } |
|
128 | :id => 'ladida', :version => '3' } | |
157 | ) |
|
129 | ) | |
158 | end |
|
130 | end | |
|
131 | ||||
|
132 | def test_api | |||
|
133 | assert_routing( | |||
|
134 | { :method => 'get', :path => "/projects/567/wiki/my_page.xml" }, | |||
|
135 | { :controller => 'wiki', :action => 'show', :project_id => '567', | |||
|
136 | :id => 'my_page', :format => 'xml' } | |||
|
137 | ) | |||
|
138 | assert_routing( | |||
|
139 | { :method => 'get', :path => "/projects/567/wiki/my_page.json" }, | |||
|
140 | { :controller => 'wiki', :action => 'show', :project_id => '567', | |||
|
141 | :id => 'my_page', :format => 'json' } | |||
|
142 | ) | |||
|
143 | assert_routing( | |||
|
144 | { :method => 'get', :path => "/projects/1/wiki/CookBook_documentation/2.xml" }, | |||
|
145 | { :controller => 'wiki', :action => 'show', :project_id => '1', | |||
|
146 | :id => 'CookBook_documentation', :version => '2', :format => 'xml' } | |||
|
147 | ) | |||
|
148 | assert_routing( | |||
|
149 | { :method => 'get', :path => "/projects/1/wiki/CookBook_documentation/2.json" }, | |||
|
150 | { :controller => 'wiki', :action => 'show', :project_id => '1', | |||
|
151 | :id => 'CookBook_documentation', :version => '2', :format => 'json' } | |||
|
152 | ) | |||
|
153 | assert_routing( | |||
|
154 | { :method => 'get', :path => "/projects/567/wiki/index.xml" }, | |||
|
155 | { :controller => 'wiki', :action => 'index', :project_id => '567', :format => 'xml' } | |||
|
156 | ) | |||
|
157 | assert_routing( | |||
|
158 | { :method => 'get', :path => "/projects/567/wiki/index.json" }, | |||
|
159 | { :controller => 'wiki', :action => 'index', :project_id => '567', :format => 'json' } | |||
|
160 | ) | |||
|
161 | assert_routing( | |||
|
162 | { :method => 'put', :path => "/projects/567/wiki/my_page.xml" }, | |||
|
163 | { :controller => 'wiki', :action => 'update', :project_id => '567', | |||
|
164 | :id => 'my_page', :format => 'xml' } | |||
|
165 | ) | |||
|
166 | assert_routing( | |||
|
167 | { :method => 'put', :path => "/projects/567/wiki/my_page.json" }, | |||
|
168 | { :controller => 'wiki', :action => 'update', :project_id => '567', | |||
|
169 | :id => 'my_page', :format => 'json' } | |||
|
170 | ) | |||
|
171 | end | |||
159 | end |
|
172 | end |
General Comments 0
You need to be logged in to leave comments.
Login now