Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
a54fdc38
Commit
a54fdc38
authored
Aug 09, 2016
by
Rémy Coutable
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enforce permissions in `{Issues,MergeRequests}::{Close,Reopen}Service`
Signed-off-by:
Rémy Coutable
<
remy@rymai.me
>
parent
0eea8c88
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
178 additions
and
21 deletions
+178
-21
app/services/issues/close_service.rb
app/services/issues/close_service.rb
+2
-0
app/services/issues/reopen_service.rb
app/services/issues/reopen_service.rb
+2
-0
app/services/merge_requests/close_service.rb
app/services/merge_requests/close_service.rb
+2
-0
app/services/merge_requests/reopen_service.rb
app/services/merge_requests/reopen_service.rb
+2
-0
spec/services/issues/close_service_spec.rb
spec/services/issues/close_service_spec.rb
+16
-2
spec/services/issues/reopen_service_spec.rb
spec/services/issues/reopen_service_spec.rb
+25
-0
spec/services/merge_requests/close_service_spec.rb
spec/services/merge_requests/close_service_spec.rb
+15
-1
spec/services/merge_requests/reopen_service_spec.rb
spec/services/merge_requests/reopen_service_spec.rb
+16
-3
spec/support/issuable_slash_commands_shared_examples.rb
spec/support/issuable_slash_commands_shared_examples.rb
+98
-15
No files found.
app/services/issues/close_service.rb
View file @
a54fdc38
module
Issues
module
Issues
class
CloseService
<
Issues
::
BaseService
class
CloseService
<
Issues
::
BaseService
def
execute
(
issue
,
commit:
nil
,
notifications:
true
,
system_note:
true
)
def
execute
(
issue
,
commit:
nil
,
notifications:
true
,
system_note:
true
)
return
issue
unless
can?
(
current_user
,
:update_issue
,
issue
)
if
project
.
jira_tracker?
&&
project
.
jira_service
.
active
if
project
.
jira_tracker?
&&
project
.
jira_service
.
active
project
.
jira_service
.
execute
(
commit
,
issue
)
project
.
jira_service
.
execute
(
commit
,
issue
)
todo_service
.
close_issue
(
issue
,
current_user
)
todo_service
.
close_issue
(
issue
,
current_user
)
...
...
app/services/issues/reopen_service.rb
View file @
a54fdc38
module
Issues
module
Issues
class
ReopenService
<
Issues
::
BaseService
class
ReopenService
<
Issues
::
BaseService
def
execute
(
issue
)
def
execute
(
issue
)
return
issue
unless
can?
(
current_user
,
:update_issue
,
issue
)
if
issue
.
reopen
if
issue
.
reopen
event_service
.
reopen_issue
(
issue
,
current_user
)
event_service
.
reopen_issue
(
issue
,
current_user
)
create_note
(
issue
)
create_note
(
issue
)
...
...
app/services/merge_requests/close_service.rb
View file @
a54fdc38
module
MergeRequests
module
MergeRequests
class
CloseService
<
MergeRequests
::
BaseService
class
CloseService
<
MergeRequests
::
BaseService
def
execute
(
merge_request
,
commit
=
nil
)
def
execute
(
merge_request
,
commit
=
nil
)
return
merge_request
unless
can?
(
current_user
,
:update_merge_request
,
merge_request
)
# If we close MergeRequest we want to ignore validation
# If we close MergeRequest we want to ignore validation
# so we can close broken one (Ex. fork project removed)
# so we can close broken one (Ex. fork project removed)
merge_request
.
allow_broken
=
true
merge_request
.
allow_broken
=
true
...
...
app/services/merge_requests/reopen_service.rb
View file @
a54fdc38
module
MergeRequests
module
MergeRequests
class
ReopenService
<
MergeRequests
::
BaseService
class
ReopenService
<
MergeRequests
::
BaseService
def
execute
(
merge_request
)
def
execute
(
merge_request
)
return
merge_request
unless
can?
(
current_user
,
:update_merge_request
,
merge_request
)
if
merge_request
.
reopen
if
merge_request
.
reopen
event_service
.
reopen_mr
(
merge_request
,
current_user
)
event_service
.
reopen_mr
(
merge_request
,
current_user
)
create_note
(
merge_request
)
create_note
(
merge_request
)
...
...
spec/services/issues/close_service_spec.rb
View file @
a54fdc38
...
@@ -3,6 +3,7 @@ require 'spec_helper'
...
@@ -3,6 +3,7 @@ require 'spec_helper'
describe
Issues
::
CloseService
,
services:
true
do
describe
Issues
::
CloseService
,
services:
true
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:user2
)
{
create
(
:user
)
}
let
(
:user2
)
{
create
(
:user
)
}
let
(
:guest
)
{
create
(
:user
)
}
let
(
:issue
)
{
create
(
:issue
,
assignee:
user2
)
}
let
(
:issue
)
{
create
(
:issue
,
assignee:
user2
)
}
let
(
:project
)
{
issue
.
project
}
let
(
:project
)
{
issue
.
project
}
let!
(
:todo
)
{
create
(
:todo
,
:assigned
,
user:
user
,
project:
project
,
target:
issue
,
author:
user2
)
}
let!
(
:todo
)
{
create
(
:todo
,
:assigned
,
user:
user
,
project:
project
,
target:
issue
,
author:
user2
)
}
...
@@ -10,13 +11,14 @@ describe Issues::CloseService, services: true do
...
@@ -10,13 +11,14 @@ describe Issues::CloseService, services: true do
before
do
before
do
project
.
team
<<
[
user
,
:master
]
project
.
team
<<
[
user
,
:master
]
project
.
team
<<
[
user2
,
:developer
]
project
.
team
<<
[
user2
,
:developer
]
project
.
team
<<
[
guest
,
:guest
]
end
end
describe
'#execute'
do
describe
'#execute'
do
context
"valid params"
do
context
"valid params"
do
before
do
before
do
perform_enqueued_jobs
do
perform_enqueued_jobs
do
@issue
=
Issues
::
CloseService
.
new
(
project
,
user
,
{}).
execute
(
issue
)
@issue
=
described_class
.
new
(
project
,
user
,
{}).
execute
(
issue
)
end
end
end
end
...
@@ -39,10 +41,22 @@ describe Issues::CloseService, services: true do
...
@@ -39,10 +41,22 @@ describe Issues::CloseService, services: true do
end
end
end
end
context
'current user is not authorized to close issue'
do
before
do
perform_enqueued_jobs
do
@issue
=
described_class
.
new
(
project
,
guest
).
execute
(
issue
)
end
end
it
'does not close the issue'
do
expect
(
@issue
).
to
be_open
end
end
context
"external issue tracker"
do
context
"external issue tracker"
do
before
do
before
do
allow
(
project
).
to
receive
(
:default_issues_tracker?
).
and_return
(
false
)
allow
(
project
).
to
receive
(
:default_issues_tracker?
).
and_return
(
false
)
@issue
=
Issues
::
CloseService
.
new
(
project
,
user
,
{}).
execute
(
issue
)
@issue
=
described_class
.
new
(
project
,
user
,
{}).
execute
(
issue
)
end
end
it
{
expect
(
@issue
).
to
be_valid
}
it
{
expect
(
@issue
).
to
be_valid
}
...
...
spec/services/issues/reopen_service_spec.rb
0 → 100644
View file @
a54fdc38
require
'spec_helper'
describe
Issues
::
ReopenService
,
services:
true
do
let
(
:guest
)
{
create
(
:user
)
}
let
(
:issue
)
{
create
(
:issue
,
:closed
)
}
let
(
:project
)
{
issue
.
project
}
before
do
project
.
team
<<
[
guest
,
:guest
]
end
describe
'#execute'
do
context
'current user is not authorized to reopen issue'
do
before
do
perform_enqueued_jobs
do
@issue
=
described_class
.
new
(
project
,
guest
).
execute
(
issue
)
end
end
it
'does not reopen the issue'
do
expect
(
@issue
).
to
be_closed
end
end
end
end
spec/services/merge_requests/close_service_spec.rb
View file @
a54fdc38
...
@@ -3,6 +3,7 @@ require 'spec_helper'
...
@@ -3,6 +3,7 @@ require 'spec_helper'
describe
MergeRequests
::
CloseService
,
services:
true
do
describe
MergeRequests
::
CloseService
,
services:
true
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:user2
)
{
create
(
:user
)
}
let
(
:user2
)
{
create
(
:user
)
}
let
(
:guest
)
{
create
(
:user
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
assignee:
user2
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
assignee:
user2
)
}
let
(
:project
)
{
merge_request
.
project
}
let
(
:project
)
{
merge_request
.
project
}
let!
(
:todo
)
{
create
(
:todo
,
:assigned
,
user:
user
,
project:
project
,
target:
merge_request
,
author:
user2
)
}
let!
(
:todo
)
{
create
(
:todo
,
:assigned
,
user:
user
,
project:
project
,
target:
merge_request
,
author:
user2
)
}
...
@@ -10,11 +11,12 @@ describe MergeRequests::CloseService, services: true do
...
@@ -10,11 +11,12 @@ describe MergeRequests::CloseService, services: true do
before
do
before
do
project
.
team
<<
[
user
,
:master
]
project
.
team
<<
[
user
,
:master
]
project
.
team
<<
[
user2
,
:developer
]
project
.
team
<<
[
user2
,
:developer
]
project
.
team
<<
[
guest
,
:guest
]
end
end
describe
'#execute'
do
describe
'#execute'
do
context
'valid params'
do
context
'valid params'
do
let
(
:service
)
{
MergeRequests
::
CloseService
.
new
(
project
,
user
,
{})
}
let
(
:service
)
{
described_class
.
new
(
project
,
user
,
{})
}
before
do
before
do
allow
(
service
).
to
receive
(
:execute_hooks
)
allow
(
service
).
to
receive
(
:execute_hooks
)
...
@@ -47,5 +49,17 @@ describe MergeRequests::CloseService, services: true do
...
@@ -47,5 +49,17 @@ describe MergeRequests::CloseService, services: true do
expect
(
todo
.
reload
).
to
be_done
expect
(
todo
.
reload
).
to
be_done
end
end
end
end
context
'current user is not authorized to close merge request'
do
before
do
perform_enqueued_jobs
do
@merge_request
=
described_class
.
new
(
project
,
guest
).
execute
(
merge_request
)
end
end
it
'does not close the merge request'
do
expect
(
@merge_request
).
to
be_open
end
end
end
end
end
end
spec/services/merge_requests/reopen_service_spec.rb
View file @
a54fdc38
...
@@ -3,22 +3,23 @@ require 'spec_helper'
...
@@ -3,22 +3,23 @@ require 'spec_helper'
describe
MergeRequests
::
ReopenService
,
services:
true
do
describe
MergeRequests
::
ReopenService
,
services:
true
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:user2
)
{
create
(
:user
)
}
let
(
:user2
)
{
create
(
:user
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
assignee:
user2
)
}
let
(
:guest
)
{
create
(
:user
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
:closed
,
assignee:
user2
)
}
let
(
:project
)
{
merge_request
.
project
}
let
(
:project
)
{
merge_request
.
project
}
before
do
before
do
project
.
team
<<
[
user
,
:master
]
project
.
team
<<
[
user
,
:master
]
project
.
team
<<
[
user2
,
:developer
]
project
.
team
<<
[
user2
,
:developer
]
project
.
team
<<
[
guest
,
:guest
]
end
end
describe
'#execute'
do
describe
'#execute'
do
context
'valid params'
do
context
'valid params'
do
let
(
:service
)
{
MergeRequests
::
ReopenService
.
new
(
project
,
user
,
{})
}
let
(
:service
)
{
described_class
.
new
(
project
,
user
,
{})
}
before
do
before
do
allow
(
service
).
to
receive
(
:execute_hooks
)
allow
(
service
).
to
receive
(
:execute_hooks
)
merge_request
.
state
=
:closed
perform_enqueued_jobs
do
perform_enqueued_jobs
do
service
.
execute
(
merge_request
)
service
.
execute
(
merge_request
)
end
end
...
@@ -43,5 +44,17 @@ describe MergeRequests::ReopenService, services: true do
...
@@ -43,5 +44,17 @@ describe MergeRequests::ReopenService, services: true do
expect
(
note
.
note
).
to
include
'Status changed to reopened'
expect
(
note
.
note
).
to
include
'Status changed to reopened'
end
end
end
end
context
'current user is not authorized to reopen merge request'
do
before
do
perform_enqueued_jobs
do
@merge_request
=
described_class
.
new
(
project
,
guest
).
execute
(
merge_request
)
end
end
it
'does not reopen the merge request'
do
expect
(
@merge_request
).
to
be_closed
end
end
end
end
end
end
spec/support/issuable_slash_commands_shared_examples.rb
View file @
a54fdc38
...
@@ -2,8 +2,9 @@
...
@@ -2,8 +2,9 @@
# It takes a `issuable_type`, and expect an `issuable`.
# It takes a `issuable_type`, and expect an `issuable`.
shared_examples
'issuable record that supports slash commands in its description and notes'
do
|
issuable_type
|
shared_examples
'issuable record that supports slash commands in its description and notes'
do
|
issuable_type
|
let
(
:
us
er
)
{
create
(
:user
)
}
let
(
:
mast
er
)
{
create
(
:user
)
}
let
(
:assignee
)
{
create
(
:user
,
username:
'bob'
)
}
let
(
:assignee
)
{
create
(
:user
,
username:
'bob'
)
}
let
(
:guest
)
{
create
(
:user
)
}
let
(
:project
)
{
create
(
:project
,
:public
)
}
let
(
:project
)
{
create
(
:project
,
:public
)
}
let!
(
:milestone
)
{
create
(
:milestone
,
project:
project
,
title:
'ASAP'
)
}
let!
(
:milestone
)
{
create
(
:milestone
,
project:
project
,
title:
'ASAP'
)
}
let!
(
:label_bug
)
{
create
(
:label
,
project:
project
,
title:
'bug'
)
}
let!
(
:label_bug
)
{
create
(
:label
,
project:
project
,
title:
'bug'
)
}
...
@@ -11,9 +12,10 @@ shared_examples 'issuable record that supports slash commands in its description
...
@@ -11,9 +12,10 @@ shared_examples 'issuable record that supports slash commands in its description
let
(
:new_url_opts
)
{
{}
}
let
(
:new_url_opts
)
{
{}
}
before
do
before
do
project
.
team
<<
[
us
er
,
:master
]
project
.
team
<<
[
mast
er
,
:master
]
project
.
team
<<
[
assignee
,
:developer
]
project
.
team
<<
[
assignee
,
:developer
]
login_with
(
user
)
project
.
team
<<
[
guest
,
:guest
]
login_with
(
master
)
end
end
describe
"new
#{
issuable_type
}
"
do
describe
"new
#{
issuable_type
}
"
do
...
@@ -83,6 +85,87 @@ shared_examples 'issuable record that supports slash commands in its description
...
@@ -83,6 +85,87 @@ shared_examples 'issuable record that supports slash commands in its description
end
end
end
end
context
"with a note closing the
#{
issuable_type
}
"
do
before
do
expect
(
issuable
).
to
be_open
end
context
"when current user can close
#{
issuable_type
}
"
do
it
"closes the
#{
issuable_type
}
"
do
page
.
within
(
'.js-main-target-form'
)
do
fill_in
'note[note]'
,
with:
"/close"
click_button
'Comment'
end
expect
(
page
).
not_to
have_content
'/close'
expect
(
page
).
to
have_content
'Your commands are being executed.'
expect
(
issuable
.
reload
).
to
be_closed
end
end
context
"when current user cannot close
#{
issuable_type
}
"
do
before
do
logout
login_with
(
guest
)
visit
public_send
(
"namespace_project_
#{
issuable_type
}
_path"
,
project
.
namespace
,
project
,
issuable
)
end
it
"does not close the
#{
issuable_type
}
"
do
page
.
within
(
'.js-main-target-form'
)
do
fill_in
'note[note]'
,
with:
"/close"
click_button
'Comment'
end
expect
(
page
).
not_to
have_content
'/close'
expect
(
page
).
to
have_content
'Your commands are being executed.'
expect
(
issuable
).
to
be_open
end
end
end
context
"with a note reopening the
#{
issuable_type
}
"
do
before
do
issuable
.
close
expect
(
issuable
).
to
be_closed
end
context
"when current user can reopen
#{
issuable_type
}
"
do
it
"reopens the
#{
issuable_type
}
"
do
page
.
within
(
'.js-main-target-form'
)
do
fill_in
'note[note]'
,
with:
"/reopen"
click_button
'Comment'
end
expect
(
page
).
not_to
have_content
'/reopen'
expect
(
page
).
to
have_content
'Your commands are being executed.'
expect
(
issuable
.
reload
).
to
be_open
end
end
context
"when current user cannot reopen
#{
issuable_type
}
"
do
before
do
logout
login_with
(
guest
)
visit
public_send
(
"namespace_project_
#{
issuable_type
}
_path"
,
project
.
namespace
,
project
,
issuable
)
end
it
"does not reopen the
#{
issuable_type
}
"
do
page
.
within
(
'.js-main-target-form'
)
do
fill_in
'note[note]'
,
with:
"/reopen"
click_button
'Comment'
end
expect
(
page
).
not_to
have_content
'/reopen'
expect
(
page
).
to
have_content
'Your commands are being executed.'
expect
(
issuable
).
to
be_closed
end
end
end
context
"with a note marking the
#{
issuable_type
}
as todo"
do
context
"with a note marking the
#{
issuable_type
}
as todo"
do
it
"creates a new todo for the
#{
issuable_type
}
"
do
it
"creates a new todo for the
#{
issuable_type
}
"
do
page
.
within
(
'.js-main-target-form'
)
do
page
.
within
(
'.js-main-target-form'
)
do
...
@@ -93,31 +176,31 @@ shared_examples 'issuable record that supports slash commands in its description
...
@@ -93,31 +176,31 @@ shared_examples 'issuable record that supports slash commands in its description
expect
(
page
).
not_to
have_content
'/todo'
expect
(
page
).
not_to
have_content
'/todo'
expect
(
page
).
to
have_content
'Your commands are being executed.'
expect
(
page
).
to
have_content
'Your commands are being executed.'
todos
=
TodosFinder
.
new
(
us
er
).
execute
todos
=
TodosFinder
.
new
(
mast
er
).
execute
todo
=
todos
.
first
todo
=
todos
.
first
expect
(
todos
.
size
).
to
eq
1
expect
(
todos
.
size
).
to
eq
1
expect
(
todo
).
to
be_pending
expect
(
todo
).
to
be_pending
expect
(
todo
.
target
).
to
eq
issuable
expect
(
todo
.
target
).
to
eq
issuable
expect
(
todo
.
author
).
to
eq
us
er
expect
(
todo
.
author
).
to
eq
mast
er
expect
(
todo
.
user
).
to
eq
us
er
expect
(
todo
.
user
).
to
eq
mast
er
end
end
end
end
context
"with a note marking the
#{
issuable_type
}
as done"
do
context
"with a note marking the
#{
issuable_type
}
as done"
do
before
do
before
do
TodoService
.
new
.
mark_todo
(
issuable
,
us
er
)
TodoService
.
new
.
mark_todo
(
issuable
,
mast
er
)
end
end
it
"creates a new todo for the
#{
issuable_type
}
"
do
it
"creates a new todo for the
#{
issuable_type
}
"
do
todos
=
TodosFinder
.
new
(
us
er
).
execute
todos
=
TodosFinder
.
new
(
mast
er
).
execute
todo
=
todos
.
first
todo
=
todos
.
first
expect
(
todos
.
size
).
to
eq
1
expect
(
todos
.
size
).
to
eq
1
expect
(
todos
.
first
).
to
be_pending
expect
(
todos
.
first
).
to
be_pending
expect
(
todo
.
target
).
to
eq
issuable
expect
(
todo
.
target
).
to
eq
issuable
expect
(
todo
.
author
).
to
eq
us
er
expect
(
todo
.
author
).
to
eq
mast
er
expect
(
todo
.
user
).
to
eq
us
er
expect
(
todo
.
user
).
to
eq
mast
er
page
.
within
(
'.js-main-target-form'
)
do
page
.
within
(
'.js-main-target-form'
)
do
fill_in
'note[note]'
,
with:
"/done"
fill_in
'note[note]'
,
with:
"/done"
...
@@ -133,7 +216,7 @@ shared_examples 'issuable record that supports slash commands in its description
...
@@ -133,7 +216,7 @@ shared_examples 'issuable record that supports slash commands in its description
context
"with a note subscribing to the
#{
issuable_type
}
"
do
context
"with a note subscribing to the
#{
issuable_type
}
"
do
it
"creates a new todo for the
#{
issuable_type
}
"
do
it
"creates a new todo for the
#{
issuable_type
}
"
do
expect
(
issuable
.
subscribed?
(
us
er
)).
to
be_falsy
expect
(
issuable
.
subscribed?
(
mast
er
)).
to
be_falsy
page
.
within
(
'.js-main-target-form'
)
do
page
.
within
(
'.js-main-target-form'
)
do
fill_in
'note[note]'
,
with:
"/subscribe"
fill_in
'note[note]'
,
with:
"/subscribe"
...
@@ -143,17 +226,17 @@ shared_examples 'issuable record that supports slash commands in its description
...
@@ -143,17 +226,17 @@ shared_examples 'issuable record that supports slash commands in its description
expect
(
page
).
not_to
have_content
'/subscribe'
expect
(
page
).
not_to
have_content
'/subscribe'
expect
(
page
).
to
have_content
'Your commands are being executed.'
expect
(
page
).
to
have_content
'Your commands are being executed.'
expect
(
issuable
.
subscribed?
(
us
er
)).
to
be_truthy
expect
(
issuable
.
subscribed?
(
mast
er
)).
to
be_truthy
end
end
end
end
context
"with a note unsubscribing to the
#{
issuable_type
}
as done"
do
context
"with a note unsubscribing to the
#{
issuable_type
}
as done"
do
before
do
before
do
issuable
.
subscribe
(
us
er
)
issuable
.
subscribe
(
mast
er
)
end
end
it
"creates a new todo for the
#{
issuable_type
}
"
do
it
"creates a new todo for the
#{
issuable_type
}
"
do
expect
(
issuable
.
subscribed?
(
us
er
)).
to
be_truthy
expect
(
issuable
.
subscribed?
(
mast
er
)).
to
be_truthy
page
.
within
(
'.js-main-target-form'
)
do
page
.
within
(
'.js-main-target-form'
)
do
fill_in
'note[note]'
,
with:
"/unsubscribe"
fill_in
'note[note]'
,
with:
"/unsubscribe"
...
@@ -163,7 +246,7 @@ shared_examples 'issuable record that supports slash commands in its description
...
@@ -163,7 +246,7 @@ shared_examples 'issuable record that supports slash commands in its description
expect
(
page
).
not_to
have_content
'/unsubscribe'
expect
(
page
).
not_to
have_content
'/unsubscribe'
expect
(
page
).
to
have_content
'Your commands are being executed.'
expect
(
page
).
to
have_content
'Your commands are being executed.'
expect
(
issuable
.
subscribed?
(
us
er
)).
to
be_falsy
expect
(
issuable
.
subscribed?
(
mast
er
)).
to
be_falsy
end
end
end
end
end
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment