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
Léo-Paul Géneau
gitlab-ce
Commits
b4004488
Commit
b4004488
authored
Oct 04, 2016
by
Valery Sizov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make guests unable to view MRs
parent
a3169d52
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
143 additions
and
13 deletions
+143
-13
CHANGELOG
CHANGELOG
+1
-0
app/models/event.rb
app/models/event.rb
+7
-1
app/policies/project_policy.rb
app/policies/project_policy.rb
+2
-1
app/services/notification_service.rb
app/services/notification_service.rb
+4
-2
app/services/todo_service.rb
app/services/todo_service.rb
+3
-3
doc/user/permissions.md
doc/user/permissions.md
+1
-0
spec/features/projects/guest_navigation_menu_spec.rb
spec/features/projects/guest_navigation_menu_spec.rb
+28
-0
spec/features/security/project/private_access_spec.rb
spec/features/security/project/private_access_spec.rb
+1
-1
spec/models/event_spec.rb
spec/models/event_spec.rb
+11
-0
spec/policies/project_policy_spec.rb
spec/policies/project_policy_spec.rb
+3
-2
spec/services/merge_requests/update_service_spec.rb
spec/services/merge_requests/update_service_spec.rb
+6
-0
spec/services/notification_service_spec.rb
spec/services/notification_service_spec.rb
+56
-1
spec/services/todo_service_spec.rb
spec/services/todo_service_spec.rb
+20
-2
No files found.
CHANGELOG
View file @
b4004488
...
@@ -93,6 +93,7 @@ v 8.13.0 (unreleased)
...
@@ -93,6 +93,7 @@ v 8.13.0 (unreleased)
- Cleanup Ci::ApplicationController. !6757 (Takuya Noguchi)
- Cleanup Ci::ApplicationController. !6757 (Takuya Noguchi)
- Fix a typo in doc/api/labels.md
- Fix a typo in doc/api/labels.md
- API: all unknown routing will be handled with 404 Not Found
- API: all unknown routing will be handled with 404 Not Found
- Make guests unable to view MRs on private projects
v 8.12.5 (unreleased)
v 8.12.5 (unreleased)
- Update the mail_room gem to 0.8.1 to fix a race condition with the mailbox watching thread
- Update the mail_room gem to 0.8.1 to fix a race condition with the mailbox watching thread
...
...
app/models/event.rb
View file @
b4004488
...
@@ -68,8 +68,10 @@ class Event < ActiveRecord::Base
...
@@ -68,8 +68,10 @@ class Event < ActiveRecord::Base
true
true
elsif
issue?
||
issue_note?
elsif
issue?
||
issue_note?
Ability
.
allowed?
(
user
,
:read_issue
,
note?
?
note_target
:
target
)
Ability
.
allowed?
(
user
,
:read_issue
,
note?
?
note_target
:
target
)
elsif
merge_request?
||
merge_request_note?
Ability
.
allowed?
(
user
,
:read_merge_request
,
note?
?
note_target
:
target
)
else
else
((
merge_request?
||
note?
)
&&
target
.
present?
)
||
milestone?
milestone?
end
end
end
end
...
@@ -280,6 +282,10 @@ class Event < ActiveRecord::Base
...
@@ -280,6 +282,10 @@ class Event < ActiveRecord::Base
note?
&&
target
&&
target
.
for_issue?
note?
&&
target
&&
target
.
for_issue?
end
end
def
merge_request_note?
note?
&&
target
&&
target
.
for_merge_request?
end
def
project_snippet_note?
def
project_snippet_note?
target
.
for_snippet?
target
.
for_snippet?
end
end
...
...
app/policies/project_policy.rb
View file @
b4004488
...
@@ -40,7 +40,6 @@ class ProjectPolicy < BasePolicy
...
@@ -40,7 +40,6 @@ class ProjectPolicy < BasePolicy
can!
:read_milestone
can!
:read_milestone
can!
:read_project_snippet
can!
:read_project_snippet
can!
:read_project_member
can!
:read_project_member
can!
:read_merge_request
can!
:read_note
can!
:read_note
can!
:create_project
can!
:create_project
can!
:create_issue
can!
:create_issue
...
@@ -63,6 +62,7 @@ class ProjectPolicy < BasePolicy
...
@@ -63,6 +62,7 @@ class ProjectPolicy < BasePolicy
can!
:read_pipeline
can!
:read_pipeline
can!
:read_environment
can!
:read_environment
can!
:read_deployment
can!
:read_deployment
can!
:read_merge_request
end
end
# Permissions given when an user is team member of a project
# Permissions given when an user is team member of a project
...
@@ -117,6 +117,7 @@ class ProjectPolicy < BasePolicy
...
@@ -117,6 +117,7 @@ class ProjectPolicy < BasePolicy
can!
:read_container_image
can!
:read_container_image
can!
:build_download_code
can!
:build_download_code
can!
:build_read_container_image
can!
:build_read_container_image
can!
:read_merge_request
end
end
def
owner_access!
def
owner_access!
...
...
app/services/notification_service.rb
View file @
b4004488
...
@@ -475,10 +475,12 @@ class NotificationService
...
@@ -475,10 +475,12 @@ class NotificationService
end
end
def
reject_users_without_access
(
recipients
,
target
)
def
reject_users_without_access
(
recipients
,
target
)
return
recipients
unless
target
.
is_a?
(
Issue
)
return
recipients
unless
target
.
is_a?
(
Issuable
)
ability
=
:"read_
#{
target
.
to_ability_name
}
"
recipients
.
select
do
|
user
|
recipients
.
select
do
|
user
|
user
.
can?
(
:read_issue
,
target
)
user
.
can?
(
ability
,
target
)
end
end
end
end
...
...
app/services/todo_service.rb
View file @
b4004488
...
@@ -273,12 +273,12 @@ class TodoService
...
@@ -273,12 +273,12 @@ class TodoService
end
end
def
reject_users_without_access
(
users
,
project
,
target
)
def
reject_users_without_access
(
users
,
project
,
target
)
if
target
.
is_a?
(
Note
)
&&
target
.
for_issue?
if
target
.
is_a?
(
Note
)
&&
(
target
.
for_issue?
||
target
.
for_merge_request?
)
target
=
target
.
noteable
target
=
target
.
noteable
end
end
if
target
.
is_a?
(
Issue
)
if
target
.
is_a?
(
Issu
abl
e
)
select_users
(
users
,
:
read_issue
,
target
)
select_users
(
users
,
:
"read_
#{
target
.
to_ability_name
}
"
,
target
)
else
else
select_users
(
users
,
:read_project
,
project
)
select_users
(
users
,
:read_project
,
project
)
end
end
...
...
doc/user/permissions.md
View file @
b4004488
...
@@ -32,6 +32,7 @@ The following table depicts the various user permission levels in a project.
...
@@ -32,6 +32,7 @@ The following table depicts the various user permission levels in a project.
| See a commit status | | ✓ | ✓ | ✓ | ✓ |
| See a commit status | | ✓ | ✓ | ✓ | ✓ |
| See a container registry | | ✓ | ✓ | ✓ | ✓ |
| See a container registry | | ✓ | ✓ | ✓ | ✓ |
| See environments | | ✓ | ✓ | ✓ | ✓ |
| See environments | | ✓ | ✓ | ✓ | ✓ |
| See a list of merge requests | | ✓ | ✓ | ✓ | ✓ |
| Manage/Accept merge requests | | | ✓ | ✓ | ✓ |
| Manage/Accept merge requests | | | ✓ | ✓ | ✓ |
| Create new merge request | | | ✓ | ✓ | ✓ |
| Create new merge request | | | ✓ | ✓ | ✓ |
| Create new branches | | | ✓ | ✓ | ✓ |
| Create new branches | | | ✓ | ✓ | ✓ |
...
...
spec/features/projects/guest_navigation_menu_spec.rb
0 → 100644
View file @
b4004488
require
'spec_helper'
describe
"Guest navigation menu"
do
let
(
:project
)
{
create
:empty_project
,
:private
}
let
(
:guest
)
{
create
:user
}
before
do
project
.
team
<<
[
guest
,
:guest
]
login_as
(
guest
)
end
it
"shows allowed tabs only"
do
visit
namespace_project_path
(
project
.
namespace
,
project
)
within
(
".nav-links"
)
do
expect
(
page
).
to
have_content
'Project'
expect
(
page
).
to
have_content
'Activity'
expect
(
page
).
to
have_content
'Issues'
expect
(
page
).
to
have_content
'Wiki'
expect
(
page
).
not_to
have_content
'Repository'
expect
(
page
).
not_to
have_content
'Pipelines'
expect
(
page
).
not_to
have_content
'Graphs'
expect
(
page
).
not_to
have_content
'Merge Requests'
end
end
end
spec/features/security/project/private_access_spec.rb
View file @
b4004488
...
@@ -203,7 +203,7 @@ describe "Private Project Access", feature: true do
...
@@ -203,7 +203,7 @@ describe "Private Project Access", feature: true do
it
{
is_expected
.
to
be_allowed_for
master
}
it
{
is_expected
.
to
be_allowed_for
master
}
it
{
is_expected
.
to
be_allowed_for
developer
}
it
{
is_expected
.
to
be_allowed_for
developer
}
it
{
is_expected
.
to
be_allowed_for
reporter
}
it
{
is_expected
.
to
be_allowed_for
reporter
}
it
{
is_expected
.
to
be_
allowed_for
guest
}
it
{
is_expected
.
to
be_
denied_for
guest
}
it
{
is_expected
.
to
be_denied_for
:user
}
it
{
is_expected
.
to
be_denied_for
:user
}
it
{
is_expected
.
to
be_denied_for
:external
}
it
{
is_expected
.
to
be_denied_for
:external
}
it
{
is_expected
.
to
be_denied_for
:visitor
}
it
{
is_expected
.
to
be_denied_for
:visitor
}
...
...
spec/models/event_spec.rb
View file @
b4004488
...
@@ -135,6 +135,17 @@ describe Event, models: true do
...
@@ -135,6 +135,17 @@ describe Event, models: true do
it
{
expect
(
event
.
visible_to_user?
(
member
)).
to
eq
true
}
it
{
expect
(
event
.
visible_to_user?
(
member
)).
to
eq
true
}
it
{
expect
(
event
.
visible_to_user?
(
guest
)).
to
eq
true
}
it
{
expect
(
event
.
visible_to_user?
(
guest
)).
to
eq
true
}
it
{
expect
(
event
.
visible_to_user?
(
admin
)).
to
eq
true
}
it
{
expect
(
event
.
visible_to_user?
(
admin
)).
to
eq
true
}
context
'private project'
do
let
(
:project
)
{
create
(
:project
,
:private
)
}
it
{
expect
(
event
.
visible_to_user?
(
non_member
)).
to
eq
false
}
it
{
expect
(
event
.
visible_to_user?
(
author
)).
to
eq
true
}
it
{
expect
(
event
.
visible_to_user?
(
assignee
)).
to
eq
true
}
it
{
expect
(
event
.
visible_to_user?
(
member
)).
to
eq
true
}
it
{
expect
(
event
.
visible_to_user?
(
guest
)).
to
eq
false
}
it
{
expect
(
event
.
visible_to_user?
(
admin
)).
to
eq
true
}
end
end
end
end
end
...
...
spec/policies/project_policy_spec.rb
View file @
b4004488
...
@@ -12,7 +12,7 @@ describe ProjectPolicy, models: true do
...
@@ -12,7 +12,7 @@ describe ProjectPolicy, models: true do
[
[
:read_project
,
:read_board
,
:read_list
,
:read_wiki
,
:read_issue
,
:read_label
,
:read_project
,
:read_board
,
:read_list
,
:read_wiki
,
:read_issue
,
:read_label
,
:read_milestone
,
:read_project_snippet
,
:read_project_member
,
:read_milestone
,
:read_project_snippet
,
:read_project_member
,
:read_
merge_request
,
:read_
note
,
:create_project
,
:create_issue
,
:create_note
,
:read_note
,
:create_project
,
:create_issue
,
:create_note
,
:upload_file
:upload_file
]
]
end
end
...
@@ -21,7 +21,8 @@ describe ProjectPolicy, models: true do
...
@@ -21,7 +21,8 @@ describe ProjectPolicy, models: true do
[
[
:download_code
,
:fork_project
,
:create_project_snippet
,
:update_issue
,
:download_code
,
:fork_project
,
:create_project_snippet
,
:update_issue
,
:admin_issue
,
:admin_label
,
:admin_list
,
:read_commit_status
,
:read_build
,
:admin_issue
,
:admin_label
,
:admin_list
,
:read_commit_status
,
:read_build
,
:read_container_image
,
:read_pipeline
,
:read_environment
,
:read_deployment
:read_container_image
,
:read_pipeline
,
:read_environment
,
:read_deployment
,
:read_merge_request
]
]
end
end
...
...
spec/services/merge_requests/update_service_spec.rb
View file @
b4004488
...
@@ -17,6 +17,7 @@ describe MergeRequests::UpdateService, services: true do
...
@@ -17,6 +17,7 @@ describe MergeRequests::UpdateService, 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
<<
[
user3
,
:developer
]
end
end
describe
'execute'
do
describe
'execute'
do
...
@@ -188,6 +189,11 @@ describe MergeRequests::UpdateService, services: true do
...
@@ -188,6 +189,11 @@ describe MergeRequests::UpdateService, services: true do
let!
(
:non_subscriber
)
{
create
(
:user
)
}
let!
(
:non_subscriber
)
{
create
(
:user
)
}
let!
(
:subscriber
)
{
create
(
:user
).
tap
{
|
u
|
label
.
toggle_subscription
(
u
)
}
}
let!
(
:subscriber
)
{
create
(
:user
).
tap
{
|
u
|
label
.
toggle_subscription
(
u
)
}
}
before
do
project
.
team
<<
[
non_subscriber
,
:developer
]
project
.
team
<<
[
subscriber
,
:developer
]
end
it
'sends notifications for subscribers of newly added labels'
do
it
'sends notifications for subscribers of newly added labels'
do
opts
=
{
label_ids:
[
label
.
id
]
}
opts
=
{
label_ids:
[
label
.
id
]
}
...
...
spec/services/notification_service_spec.rb
View file @
b4004488
...
@@ -331,7 +331,7 @@ describe NotificationService, services: true do
...
@@ -331,7 +331,7 @@ describe NotificationService, services: true do
describe
'#new_note'
do
describe
'#new_note'
do
it
"records sent notifications"
do
it
"records sent notifications"
do
# Ensure create SentNotification by noteable = merge_request 6 times, not noteable = note
# Ensure create SentNotification by noteable = merge_request 6 times, not noteable = note
expect
(
SentNotification
).
to
receive
(
:record_note
).
with
(
note
,
any_args
).
exactly
(
4
).
times
.
and_call_original
expect
(
SentNotification
).
to
receive
(
:record_note
).
with
(
note
,
any_args
).
exactly
(
3
).
times
.
and_call_original
notification
.
new_note
(
note
)
notification
.
new_note
(
note
)
...
@@ -1169,6 +1169,61 @@ describe NotificationService, services: true do
...
@@ -1169,6 +1169,61 @@ describe NotificationService, services: true do
end
end
end
end
context
'guest user in private project'
do
let
(
:private_project
)
{
create
(
:empty_project
,
:private
)
}
let
(
:guest
)
{
create
(
:user
)
}
let
(
:developer
)
{
create
(
:user
)
}
let
(
:assignee
)
{
create
(
:user
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
source_project:
private_project
,
assignee:
assignee
)
}
let
(
:merge_request1
)
{
create
(
:merge_request
,
source_project:
private_project
,
assignee:
assignee
,
description:
"cc @
#{
guest
.
username
}
"
)
}
let
(
:note
)
{
create
(
:note
,
noteable:
merge_request
,
project:
private_project
)
}
before
do
private_project
.
team
<<
[
assignee
,
:developer
]
private_project
.
team
<<
[
developer
,
:developer
]
private_project
.
team
<<
[
guest
,
:guest
]
ActionMailer
::
Base
.
deliveries
.
clear
end
it
'filters out guests when new note is created'
do
expect
(
SentNotification
).
to
receive
(
:record
).
with
(
merge_request
,
any_args
).
exactly
(
1
).
times
notification
.
new_note
(
note
)
should_not_email
(
guest
)
should_email
(
assignee
)
end
it
'filters out guests when new merge request is created'
do
notification
.
new_merge_request
(
merge_request1
,
@u_disabled
)
should_not_email
(
guest
)
should_email
(
assignee
)
end
it
'filters out guests when merge request is closed'
do
notification
.
close_mr
(
merge_request
,
developer
)
should_not_email
(
guest
)
should_email
(
assignee
)
end
it
'filters out guests when merge request is reopened'
do
notification
.
reopen_mr
(
merge_request
,
developer
)
should_not_email
(
guest
)
should_email
(
assignee
)
end
it
'filters out guests when merge request is merged'
do
notification
.
merge_mr
(
merge_request
,
developer
)
should_not_email
(
guest
)
should_email
(
assignee
)
end
end
def
build_team
(
project
)
def
build_team
(
project
)
@u_watcher
=
create_global_setting_for
(
create
(
:user
),
:watch
)
@u_watcher
=
create_global_setting_for
(
create
(
:user
),
:watch
)
@u_participating
=
create_global_setting_for
(
create
(
:user
),
:participating
)
@u_participating
=
create_global_setting_for
(
create
(
:user
),
:participating
)
...
...
spec/services/todo_service_spec.rb
View file @
b4004488
...
@@ -345,7 +345,7 @@ describe TodoService, services: true do
...
@@ -345,7 +345,7 @@ describe TodoService, services: true do
service
.
new_merge_request
(
mr_assigned
,
author
)
service
.
new_merge_request
(
mr_assigned
,
author
)
should_create_todo
(
user:
member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_create_todo
(
user:
member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_create_todo
(
user:
guest
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_
not_
create_todo
(
user:
guest
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_create_todo
(
user:
author
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_create_todo
(
user:
author
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
john_doe
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
john_doe
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
non_member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
non_member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
...
@@ -357,7 +357,7 @@ describe TodoService, services: true do
...
@@ -357,7 +357,7 @@ describe TodoService, services: true do
service
.
update_merge_request
(
mr_assigned
,
author
)
service
.
update_merge_request
(
mr_assigned
,
author
)
should_create_todo
(
user:
member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_create_todo
(
user:
member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_create_todo
(
user:
guest
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_
not_
create_todo
(
user:
guest
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_create_todo
(
user:
john_doe
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_create_todo
(
user:
john_doe
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_create_todo
(
user:
author
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_create_todo
(
user:
author
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
non_member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
non_member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
...
@@ -381,6 +381,7 @@ describe TodoService, services: true do
...
@@ -381,6 +381,7 @@ describe TodoService, services: true do
should_not_create_todo
(
user:
john_doe
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
john_doe
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
non_member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
non_member
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
should_not_create_todo
(
user:
guest
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
end
end
it
'does not raise an error when description not change'
do
it
'does not raise an error when description not change'
do
...
@@ -430,6 +431,11 @@ describe TodoService, services: true do
...
@@ -430,6 +431,11 @@ describe TodoService, services: true do
should_create_todo
(
user:
john_doe
,
target:
mr_assigned
,
author:
john_doe
,
action:
Todo
::
ASSIGNED
)
should_create_todo
(
user:
john_doe
,
target:
mr_assigned
,
author:
john_doe
,
action:
Todo
::
ASSIGNED
)
end
end
it
'does not create a todo for guests'
do
service
.
reassigned_merge_request
(
mr_assigned
,
author
)
should_not_create_todo
(
user:
guest
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
end
end
end
describe
'#merge_merge_request'
do
describe
'#merge_merge_request'
do
...
@@ -441,6 +447,11 @@ describe TodoService, services: true do
...
@@ -441,6 +447,11 @@ describe TodoService, services: true do
expect
(
first_todo
.
reload
).
to
be_done
expect
(
first_todo
.
reload
).
to
be_done
expect
(
second_todo
.
reload
).
to
be_done
expect
(
second_todo
.
reload
).
to
be_done
end
end
it
'does not create todo for guests'
do
service
.
merge_merge_request
(
mr_assigned
,
john_doe
)
should_not_create_todo
(
user:
guest
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
end
end
end
describe
'#new_award_emoji'
do
describe
'#new_award_emoji'
do
...
@@ -495,6 +506,13 @@ describe TodoService, services: true do
...
@@ -495,6 +506,13 @@ describe TodoService, services: true do
should_create_todo
(
user:
john_doe
,
target:
mr_unassigned
,
author:
author
,
action:
Todo
::
MENTIONED
,
note:
legacy_diff_note_on_merge_request
)
should_create_todo
(
user:
john_doe
,
target:
mr_unassigned
,
author:
author
,
action:
Todo
::
MENTIONED
,
note:
legacy_diff_note_on_merge_request
)
end
end
it
'does not create todo for guests'
do
note_on_merge_request
=
create
:note_on_merge_request
,
project:
project
,
noteable:
mr_assigned
,
note:
mentions
service
.
new_note
(
note_on_merge_request
,
author
)
should_not_create_todo
(
user:
guest
,
target:
mr_assigned
,
action:
Todo
::
MENTIONED
)
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