Skip to content
Snippets Groups Projects
Commit a5521bad authored by Hiroyuki Sato's avatar Hiroyuki Sato Committed by Hiroyuki Sato
Browse files

Prevent concurrent editing wiki

parent e78a3669
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -56,6 +56,9 @@ class Projects::WikisController < Projects::ApplicationController
else
render 'edit'
end
rescue WikiPage::PageChangedError
@conflict = true
render 'edit'
end
 
def create
Loading
Loading
@@ -125,6 +128,6 @@ class Projects::WikisController < Projects::ApplicationController
end
 
def wiki_params
params[:wiki].slice(:title, :content, :format, :message)
params[:wiki].slice(:title, :content, :format, :message, :last_commit_sha)
end
end
class WikiPage
PageChangedError = Class.new(StandardError)
include ActiveModel::Validations
include ActiveModel::Conversion
include StaticModel
Loading
Loading
@@ -176,17 +178,22 @@ class WikiPage
 
# Updates an existing Wiki Page, creating a new version.
#
# new_content - The raw markup content to replace the existing.
# format - Optional symbol representing the content format.
# See ProjectWiki::MARKUPS Hash for available formats.
# message - Optional commit message to set on the new version.
# new_content - The raw markup content to replace the existing.
# format - Optional symbol representing the content format.
# See ProjectWiki::MARKUPS Hash for available formats.
# message - Optional commit message to set on the new version.
# last_commit_sha - Optional last commit sha to validate the page unchanged.
#
# Returns the String SHA1 of the newly created page
# or False if the save was unsuccessful.
def update(new_content = "", format = :markdown, message = nil)
def update(new_content = "", format = :markdown, message = nil, last_commit_sha = nil)
@attributes[:content] = new_content
@attributes[:format] = format
 
if last_commit_sha && last_commit_sha != commit.sha
raise PageChangedError.new("You are attempting to update a page that has changed since you started editing it.")
end
save :update_page, @page, content, format, message
end
 
Loading
Loading
module WikiPages
class UpdateService < WikiPages::BaseService
def execute(page)
if page.update(@params[:content], @params[:format], @params[:message])
if page.update(@params[:content], @params[:format], @params[:message], @params[:last_commit_sha])
execute_hooks(page, 'update')
end
 
Loading
Loading
Loading
Loading
@@ -2,6 +2,8 @@
= form_errors(@page)
 
= f.hidden_field :title, value: @page.title
- if @page.persisted?
= f.hidden_field :last_commit_sha, value: @page.commit.sha
.form-group
= f.label :format, class: 'control-label'
.col-sm-10
Loading
Loading
Loading
Loading
@@ -2,6 +2,12 @@
- page_title "Edit", @page.title.capitalize, "Wiki"
 
%div{ class: container_class }
- if @conflict
.alert.alert-danger
Someone edited the page the same time you did. Please check out
= link_to "the page", namespace_project_wiki_path(@project.namespace, @project, @page), target: "_blank"
and make sure your changes will not unintentionally remove theirs.
.wiki-page-header.has-sidebar-toggle
%button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
= icon('angle-double-left')
Loading
Loading
---
title: Prevent concurrent editing wiki
merge_request: 9707
author: Hiroyuki Sato
Loading
Loading
@@ -8,7 +8,7 @@ feature 'Projects > Wiki > User updates wiki page', feature: true do
login_as(user)
 
visit namespace_project_path(project.namespace, project)
WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
@wiki_page = WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
click_link 'Wiki'
end
 
Loading
Loading
@@ -25,6 +25,16 @@ feature 'Projects > Wiki > User updates wiki page', feature: true do
expect(page).to have_content("Last edited by #{user.name}")
expect(page).to have_content('My awesome wiki!')
end
scenario 'page has been updated since the user opened the edit page' do
click_link 'Edit'
@wiki_page.update("Update")
click_button 'Save changes'
expect(page).to have_content 'Someone edited the page the same time you did.'
end
end
 
context 'in a group namespace' do
Loading
Loading
Loading
Loading
@@ -208,6 +208,20 @@ describe WikiPage, models: true do
expect(@page.update("more content")).to be_truthy
end
end
context "with same last commit sha" do
it "returns true" do
last_commit_sha = @page.commit.sha
expect(@page.update("more content", :markdown, nil, last_commit_sha)).to be_truthy
end
end
context "with different last commit sha" do
it "raises exception" do
last_commit_sha = "xxx"
expect { @page.update("more content", :markdown, nil, last_commit_sha) }.to raise_error(WikiPage::PageChangedError)
end
end
end
 
describe "#destroy" do
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment