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
0
Merge Requests
0
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
Tatuya Kamada
gitlab-ce
Commits
9bb1d8fc
Commit
9bb1d8fc
authored
Sep 04, 2014
by
Dmitriy Zaporozhets
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #7382 from Razer6/git_ref_validation
Validate branch/tag-names and references WebUI, API
parents
640a3c5c
39211391
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
333 additions
and
42 deletions
+333
-42
app/controllers/projects/branches_controller.rb
app/controllers/projects/branches_controller.rb
+11
-3
app/controllers/projects/tags_controller.rb
app/controllers/projects/tags_controller.rb
+9
-4
app/services/create_branch_service.rb
app/services/create_branch_service.rb
+26
-1
app/services/create_tag_service.rb
app/services/create_tag_service.rb
+26
-1
app/services/delete_branch_service.rb
app/services/delete_branch_service.rb
+6
-5
app/views/projects/branches/new.html.haml
app/views/projects/branches/new.html.haml
+6
-2
app/views/projects/tags/new.html.haml
app/views/projects/tags/new.html.haml
+6
-2
doc/api/branches.md
doc/api/branches.md
+4
-1
doc/api/repositories.md
doc/api/repositories.md
+3
-0
features/project/commits/branches.feature
features/project/commits/branches.feature
+19
-1
features/project/commits/tags.feature
features/project/commits/tags.feature
+20
-0
features/steps/project/browse_branches.rb
features/steps/project/browse_branches.rb
+31
-3
features/steps/project/browse_tags.rb
features/steps/project/browse_tags.rb
+45
-1
lib/api/branches.rb
lib/api/branches.rb
+12
-4
lib/api/repositories.rb
lib/api/repositories.rb
+9
-4
lib/gitlab/git_ref_validator.rb
lib/gitlab/git_ref_validator.rb
+11
-0
spec/lib/git_ref_validator_spec.rb
spec/lib/git_ref_validator_spec.rb
+20
-0
spec/requests/api/branches_spec.rb
spec/requests/api/branches_spec.rb
+39
-6
spec/requests/api/repositories_spec.rb
spec/requests/api/repositories_spec.rb
+30
-4
No files found.
app/controllers/projects/branches_controller.rb
View file @
9bb1d8fc
...
...
@@ -17,9 +17,17 @@ class Projects::BranchesController < Projects::ApplicationController
end
def
create
@branch
=
CreateBranchService
.
new
.
execute
(
project
,
params
[
:branch_name
],
params
[
:ref
],
current_user
)
redirect_to
project_tree_path
(
@project
,
@branch
.
name
)
result
=
CreateBranchService
.
new
.
execute
(
project
,
params
[
:branch_name
],
params
[
:ref
],
current_user
)
if
result
[
:status
]
==
:success
@branch
=
result
[
:branch
]
redirect_to
project_tree_path
(
@project
,
@branch
.
name
)
else
@error
=
result
[
:message
]
render
action:
'new'
end
end
def
destroy
...
...
app/controllers/projects/tags_controller.rb
View file @
9bb1d8fc
...
...
@@ -13,10 +13,15 @@ class Projects::TagsController < Projects::ApplicationController
end
def
create
@tag
=
CreateTagService
.
new
.
execute
(
@project
,
params
[
:tag_name
],
params
[
:ref
],
current_user
)
redirect_to
project_tags_path
(
@project
)
result
=
CreateTagService
.
new
.
execute
(
@project
,
params
[
:tag_name
],
params
[
:ref
],
current_user
)
if
result
[
:status
]
==
:success
@tag
=
result
[
:tag
]
redirect_to
project_tags_path
(
@project
)
else
@error
=
result
[
:message
]
render
action:
'new'
end
end
def
destroy
...
...
app/services/create_branch_service.rb
View file @
9bb1d8fc
class
CreateBranchService
def
execute
(
project
,
branch_name
,
ref
,
current_user
)
valid_branch
=
Gitlab
::
GitRefValidator
.
validate
(
branch_name
)
if
valid_branch
==
false
return
error
(
'Branch name invalid'
)
end
repository
=
project
.
repository
existing_branch
=
repository
.
find_branch
(
branch_name
)
if
existing_branch
return
error
(
'Branch already exists'
)
end
repository
.
add_branch
(
branch_name
,
ref
)
new_branch
=
repository
.
find_branch
(
branch_name
)
if
new_branch
Event
.
create_ref_event
(
project
,
current_user
,
new_branch
,
'add'
)
return
success
(
new_branch
)
else
return
error
(
'Invalid reference name'
)
end
end
def
error
(
message
)
{
message:
message
,
status: :error
}
end
new_branch
def
success
(
branch
)
{
branch:
branch
,
status: :success
}
end
end
app/services/create_tag_service.rb
View file @
9bb1d8fc
class
CreateTagService
def
execute
(
project
,
tag_name
,
ref
,
current_user
)
valid_tag
=
Gitlab
::
GitRefValidator
.
validate
(
tag_name
)
if
valid_tag
==
false
return
error
(
'Tag name invalid'
)
end
repository
=
project
.
repository
existing_tag
=
repository
.
find_tag
(
tag_name
)
if
existing_tag
return
error
(
'Tag already exists'
)
end
repository
.
add_tag
(
tag_name
,
ref
)
new_tag
=
repository
.
find_tag
(
tag_name
)
if
new_tag
Event
.
create_ref_event
(
project
,
current_user
,
new_tag
,
'add'
,
'refs/tags'
)
return
success
(
new_tag
)
else
return
error
(
'Invalid reference name'
)
end
end
def
error
(
message
)
{
message:
message
,
status: :error
}
end
new_tag
def
success
(
branch
)
{
tag:
branch
,
status: :success
}
end
end
app/services/delete_branch_service.rb
View file @
9bb1d8fc
...
...
@@ -5,21 +5,21 @@ class DeleteBranchService
# No such branch
unless
branch
return
error
(
'No such branch'
)
return
error
(
'No such branch'
,
404
)
end
if
branch_name
==
repository
.
root_ref
return
error
(
'Cannot remove HEAD branch'
)
return
error
(
'Cannot remove HEAD branch'
,
405
)
end
# Dont allow remove of protected branch
if
project
.
protected_branch?
(
branch_name
)
return
error
(
'Protected branch cant be removed'
)
return
error
(
'Protected branch cant be removed'
,
405
)
end
# Dont allow user to remove branch if he is not allowed to push
unless
current_user
.
can?
(
:push_code
,
project
)
return
error
(
'You dont have push access to repo'
)
return
error
(
'You dont have push access to repo'
,
405
)
end
if
repository
.
rm_branch
(
branch_name
)
...
...
@@ -30,9 +30,10 @@ class DeleteBranchService
end
end
def
error
(
message
)
def
error
(
message
,
return_code
=
400
)
{
message:
message
,
return_code:
return_code
,
state: :error
}
end
...
...
app/views/projects/branches/new.html.haml
View file @
9bb1d8fc
-
if
@error
.alert.alert-danger
%button
{
type:
"button"
,
class:
"close"
,
"data-dismiss"
=>
"alert"
}
×
=
@error
%h3
.page-title
%i
.icon-code-fork
New branch
...
...
@@ -5,11 +9,11 @@
.form-group
=
label_tag
:branch_name
,
'Name for new branch'
,
class:
'control-label'
.col-sm-10
=
text_field_tag
:branch_name
,
nil
,
placeholder:
'enter new branch name'
,
required:
true
,
tabindex:
1
,
class:
'form-control'
=
text_field_tag
:branch_name
,
params
[
:branch_name
]
,
placeholder:
'enter new branch name'
,
required:
true
,
tabindex:
1
,
class:
'form-control'
.form-group
=
label_tag
:ref
,
'Create from'
,
class:
'control-label'
.col-sm-10
=
text_field_tag
:ref
,
nil
,
placeholder:
'existing branch name, tag or commit SHA'
,
required:
true
,
tabindex:
2
,
class:
'form-control'
=
text_field_tag
:ref
,
params
[
:ref
]
,
placeholder:
'existing branch name, tag or commit SHA'
,
required:
true
,
tabindex:
2
,
class:
'form-control'
.form-actions
=
submit_tag
'Create branch'
,
class:
'btn btn-create'
,
tabindex:
3
=
link_to
'Cancel'
,
project_branches_path
(
@project
),
class:
'btn btn-cancel'
...
...
app/views/projects/tags/new.html.haml
View file @
9bb1d8fc
-
if
@error
.alert.alert-danger
%button
{
type:
"button"
,
class:
"close"
,
"data-dismiss"
=>
"alert"
}
×
=
@error
%h3
.page-title
%i
.icon-code-fork
New tag
...
...
@@ -5,11 +9,11 @@
.form-group
=
label_tag
:tag_name
,
'Name for new tag'
,
class:
'control-label'
.col-sm-10
=
text_field_tag
:tag_name
,
nil
,
placeholder:
'v3.0.1'
,
required:
true
,
tabindex:
1
,
class:
'form-control'
=
text_field_tag
:tag_name
,
params
[
:tag_name
]
,
placeholder:
'v3.0.1'
,
required:
true
,
tabindex:
1
,
class:
'form-control'
.form-group
=
label_tag
:ref
,
'Create from'
,
class:
'control-label'
.col-sm-10
=
text_field_tag
:ref
,
nil
,
placeholder:
'master'
,
required:
true
,
tabindex:
2
,
class:
'form-control'
=
text_field_tag
:ref
,
params
[
:ref
]
,
placeholder:
'master'
,
required:
true
,
tabindex:
2
,
class:
'form-control'
.light
Branch name or commit SHA
.form-actions
=
submit_tag
'Create tag'
,
class:
'btn btn-create'
,
tabindex:
3
...
...
doc/api/branches.md
View file @
9bb1d8fc
...
...
@@ -196,6 +196,8 @@ Parameters:
}
```
It return 200 if succeed or 400 if failed with error message explaining reason.
## Delete repository branch
```
...
...
@@ -207,4 +209,5 @@ Parameters:
-
`id`
(required) - The ID of a project
-
`branch`
(required) - The name of the branch
It return 200 if succeed or 405 if failed with error message explaining reason.
It return 200 if succeed, 404 if the branch to be deleted does not exist
or 400 for other reasons. In case of an error, an explaining message is provided.
doc/api/repositories.md
View file @
9bb1d8fc
...
...
@@ -71,6 +71,9 @@ Parameters:
]
```
It returns 200 if the operation succeed. In case of an error,
405 with an explaining error message is returned.
## List repository tree
Get a list of repository files and directories in a project.
...
...
features/project/commits/branches.feature
View file @
9bb1d8fc
...
...
@@ -15,7 +15,7 @@ Feature: Project Browse branches
Scenario
:
I
create a branch
Given
I visit project branches page
And
I click new branch link
When
I submit new branch form
And
I submit new branch form
Then
I should see new branch created
@javascript
...
...
@@ -23,3 +23,21 @@ Feature: Project Browse branches
Given
I visit project branches page
And
I click branch 'improve/awesome' delete link
Then
I should not see branch 'improve/awesome'
Scenario
:
I
create a branch with invalid name
Given
I visit project branches page
And
I click new branch link
And
I submit new branch form with invalid name
Then
I should see new an error that branch is invalid
Scenario
:
I
create a branch with invalid reference
Given
I visit project branches page
And
I click new branch link
And
I submit new branch form with invalid reference
Then
I should see new an error that ref is invalid
Scenario
:
I
create a branch that already exists
Given
I visit project branches page
And
I click new branch link
And
I submit new branch form with branch that already exists
Then
I should see new an error that branch already exists
features/project/commits/tags.feature
View file @
9bb1d8fc
...
...
@@ -7,5 +7,25 @@ Feature: Project Browse tags
Scenario
:
I
can see all git tags
Then
I should see
"Shop"
all tags list
Scenario
:
I
create a tag
And
I click new tag link
And
I submit new tag form
Then
I should see new tag created
Scenario
:
I
create a tag with invalid name
And
I click new tag link
And
I submit new tag form with invalid name
Then
I should see new an error that tag is invalid
Scenario
:
I
create a tag with invalid reference
And
I click new tag link
And
I submit new tag form with invalid reference
Then
I should see new an error that tag ref is invalid
Scenario
:
I
create a tag that already exists
And
I click new tag link
And
I submit new tag form with tag that already exists
Then
I should see new an error that tag already exists
# @wip
# Scenario: I can download project by tag
features/steps/project/browse_branches.rb
View file @
9bb1d8fc
...
...
@@ -38,10 +38,38 @@ class ProjectBrowseBranches < Spinach::FeatureSteps
click_button
'Create branch'
end
step
'I submit new branch form with invalid name'
do
fill_in
'branch_name'
,
with:
'1.0 stable'
fill_in
'ref'
,
with:
'master'
click_button
'Create branch'
end
step
'I submit new branch form with invalid reference'
do
fill_in
'branch_name'
,
with:
'foo'
fill_in
'ref'
,
with:
'foo'
click_button
'Create branch'
end
step
'I submit new branch form with branch that already exists'
do
fill_in
'branch_name'
,
with:
'master'
fill_in
'ref'
,
with:
'master'
click_button
'Create branch'
end
step
'I should see new branch created'
do
within
'.tree-ref-holder'
do
page
.
should
have_content
'deploy_keys'
end
page
.
should
have_content
'deploy_keys'
end
step
'I should see new an error that branch is invalid'
do
page
.
should
have_content
'Branch name invalid'
end
step
'I should see new an error that ref is invalid'
do
page
.
should
have_content
'Invalid reference name'
end
step
'I should see new an error that branch already exists'
do
page
.
should
have_content
'Branch already exists'
end
step
"I click branch 'improve/awesome' delete link"
do
...
...
features/steps/project/browse_tags.rb
View file @
9bb1d8fc
...
...
@@ -3,8 +3,52 @@ class ProjectBrowseTags < Spinach::FeatureSteps
include
SharedProject
include
SharedPaths
Then
'I should see "Shop" all tags list'
do
step
'I should see "Shop" all tags list'
do
page
.
should
have_content
"Tags"
page
.
should
have_content
"v1.0.0"
end
step
'I click new tag link'
do
click_link
'New tag'
end
step
'I submit new tag form'
do
fill_in
'tag_name'
,
with:
'v7.0'
fill_in
'ref'
,
with:
'master'
click_button
'Create tag'
end
step
'I submit new tag form with invalid name'
do
fill_in
'tag_name'
,
with:
'v 1.0'
fill_in
'ref'
,
with:
'master'
click_button
'Create tag'
end
step
'I submit new tag form with invalid reference'
do
fill_in
'tag_name'
,
with:
'foo'
fill_in
'ref'
,
with:
'foo'
click_button
'Create tag'
end
step
'I submit new tag form with tag that already exists'
do
fill_in
'tag_name'
,
with:
'v1.0.0'
fill_in
'ref'
,
with:
'master'
click_button
'Create tag'
end
step
'I should see new tag created'
do
page
.
should
have_content
'v7.0'
end
step
'I should see new an error that tag is invalid'
do
page
.
should
have_content
'Tag name invalid'
end
step
'I should see new an error that tag ref is invalid'
do
page
.
should
have_content
'Invalid reference name'
end
step
'I should see new an error that tag already exists'
do
page
.
should
have_content
'Tag already exists'
end
end
lib/api/branches.rb
View file @
9bb1d8fc
...
...
@@ -80,9 +80,17 @@ module API
# POST /projects/:id/repository/branches
post
":id/repository/branches"
do
authorize_push_project
@branch
=
CreateBranchService
.
new
.
execute
(
user_project
,
params
[
:branch_name
],
params
[
:ref
],
current_user
)
present
@branch
,
with:
Entities
::
RepoObject
,
project:
user_project
result
=
CreateBranchService
.
new
.
execute
(
user_project
,
params
[
:branch_name
],
params
[
:ref
],
current_user
)
if
result
[
:status
]
==
:success
present
result
[
:branch
],
with:
Entities
::
RepoObject
,
project:
user_project
else
render_api_error!
(
result
[
:message
],
400
)
end
end
# Delete branch
...
...
@@ -99,7 +107,7 @@ module API
if
result
[
:state
]
==
:success
true
else
render_api_error!
(
result
[
:message
],
405
)
render_api_error!
(
result
[
:message
],
result
[
:return_code
]
)
end
end
end
...
...
lib/api/repositories.rb
View file @
9bb1d8fc
...
...
@@ -36,10 +36,15 @@ module API
# POST /projects/:id/repository/tags
post
':id/repository/tags'
do
authorize_push_project
@tag
=
CreateTagService
.
new
.
execute
(
user_project
,
params
[
:tag_name
],
params
[
:ref
],
current_user
)
present
@tag
,
with:
Entities
::
RepoObject
,
project:
user_project
result
=
CreateTagService
.
new
.
execute
(
user_project
,
params
[
:tag_name
],
params
[
:ref
],
current_user
)
if
result
[
:status
]
==
:success
present
result
[
:tag
],
with:
Entities
::
RepoObject
,
project:
user_project
else
render_api_error!
(
result
[
:message
],
400
)
end
end
# Get a project repository tree
...
...
lib/gitlab/git_ref_validator.rb
0 → 100644
View file @
9bb1d8fc
module
Gitlab
module
GitRefValidator
extend
self
# Validates a given name against the git reference specification
#
# Returns true for a valid reference name, false otherwise
def
validate
(
ref_name
)
system
*
%W(git check-ref-format refs/
#{
ref_name
}
)
end
end
end
spec/lib/git_ref_validator_spec.rb
0 → 100644
View file @
9bb1d8fc
require
'spec_helper'
describe
Gitlab
::
GitRefValidator
do
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature/new'
).
should
be_true
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'implement_@all'
).
should
be_true
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'my_new_feature'
).
should
be_true
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'#1'
).
should
be_true
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature/~new/'
).
should
be_false
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature/^new/'
).
should
be_false
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature/:new/'
).
should
be_false
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature/?new/'
).
should
be_false
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature/*new/'
).
should
be_false
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature/[new/'
).
should
be_false
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature/new/'
).
should
be_false
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature/new.'
).
should
be_false
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature\@{'
).
should
be_false
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature\new'
).
should
be_false
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature//new'
).
should
be_false
}
it
{
Gitlab
::
GitRefValidator
.
validate
(
'feature new'
).
should
be_false
}
end
spec/requests/api/branches_spec.rb
View file @
9bb1d8fc
...
...
@@ -94,22 +94,50 @@ describe API::API, api: true do
describe
"POST /projects/:id/repository/branches"
do
it
"should create a new branch"
do
post
api
(
"/projects/
#{
project
.
id
}
/repository/branches"
,
user
),
branch_name:
branch_name
,
ref:
branch_sha
branch_name:
'feature1'
,
ref:
branch_sha
response
.
status
.
should
==
201
json_response
[
'name'
].
should
==
branch_name
json_response
[
'name'
].
should
==
'feature1'
json_response
[
'commit'
][
'id'
].
should
==
branch_sha
end
it
"should deny for user without push access"
do
post
api
(
"/projects/
#{
project
.
id
}
/repository/branches"
,
user2
),
branch_name:
branch_name
,
ref:
branch_sha
branch_name:
branch_name
,
ref:
branch_sha
response
.
status
.
should
==
403
end
it
'should return 400 if branch name is invalid'
do
post
api
(
"/projects/
#{
project
.
id
}
/repository/branches"
,
user
),
branch_name:
'new design'
,
ref:
branch_sha
response
.
status
.
should
==
400
json_response
[
'message'
].
should
==
'Branch name invalid'
end
it
'should return 400 if branch already exists'
do
post
api
(
"/projects/
#{
project
.
id
}
/repository/branches"
,
user
),
branch_name:
'new_design1'
,
ref:
branch_sha
response
.
status
.
should
==
201
post
api
(
"/projects/
#{
project
.
id
}
/repository/branches"
,
user
),
branch_name:
'new_design1'
,
ref:
branch_sha
response
.
status
.
should
==
400
json_response
[
'message'
].
should
==
'Branch already exists'
end
it
'should return 400 if ref name is invalid'
do
post
api
(
"/projects/
#{
project
.
id
}
/repository/branches"
,
user
),
branch_name:
'new_design3'
,
ref:
'foo'
response
.
status
.
should
==
400
json_response
[
'message'
].
should
==
'Invalid reference name'
end
end
describe
"DELETE /projects/:id/repository/branches/:branch"
do
...
...
@@ -120,6 +148,11 @@ describe API::API, api: true do
response
.
status
.
should
==
200
end
it
'should return 404 if branch not exists'
do
delete
api
(
"/projects/
#{
project
.
id
}
/repository/branches/foobar"
,
user
)
response
.
status
.
should
==
404
end
it
"should remove protected branch"
do
project
.
protected_branches
.
create
(
name:
branch_name
)
delete
api
(
"/projects/
#{
project
.
id
}
/repository/branches/
#{
branch_name
}
"
,
user
)
...
...
spec/requests/api/repositories_spec.rb
View file @
9bb1d8fc
...
...
@@ -25,20 +25,46 @@ describe API::API, api: true do
describe
'POST /projects/:id/repository/tags'
do
it
'should create a new tag'
do
post
api
(
"/projects/
#{
project
.
id
}
/repository/tags"
,
user
),
tag_name:
'v
1
.0.0'
,
tag_name:
'v
2
.0.0'
,
ref:
'master'
response
.
status
.
should
==
201
json_response
[
'name'
].
should
==
'v
1
.0.0'
json_response
[
'name'
].
should
==
'v
2
.0.0'
end
it
'should deny for user without push access'
do
post
api
(
"/projects/
#{
project
.
id
}
/repository/tags"
,
user2
),
tag_name:
'v1.0.0'
,
ref:
'621491c677087aa243f165eab467bfdfbee00be1'
response
.
status
.
should
==
403
end
it
'should return 400 if tag name is invalid'
do
post
api
(
"/projects/
#{
project
.
id
}
/repository/tags"
,
user
),
tag_name:
'v 1.0.0'
,
ref:
'master'
response
.
status
.
should
==
400
json_response
[
'message'
].
should
==
'Tag name invalid'
end
it
'should return 400 if tag already exists'
do
post
api
(
"/projects/
#{
project
.
id
}
/repository/tags"
,
user
),
tag_name:
'v8.0.0'
,
ref:
'master'
response
.
status
.
should
==
201
post
api
(
"/projects/
#{
project
.
id
}
/repository/tags"
,
user
),
tag_name:
'v8.0.0'
,
ref:
'master'
response
.
status
.
should
==
400
json_response
[
'message'
].
should
==
'Tag already exists'
end
it
'should return 400 if ref name is invalid'
do
post
api
(
"/projects/
#{
project
.
id
}
/repository/tags"
,
user
),
tag_name:
'mytag'
,
ref:
'foo'
response
.
status
.
should
==
400
json_response
[
'message'
].
should
==
'Invalid reference name'
end
end
describe
"GET /projects/:id/repository/tree"
do
...
...
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