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
Boxiang Sun
gitlab-ce
Commits
adab5dba
Commit
adab5dba
authored
Sep 27, 2016
by
Rémy Coutable
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix permission for setting an issue's due date
Signed-off-by:
Rémy Coutable
<
remy@rymai.me
>
parent
7d79a943
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
216 additions
and
66 deletions
+216
-66
CHANGELOG
CHANGELOG
+1
-0
app/services/issuable_base_service.rb
app/services/issuable_base_service.rb
+1
-0
app/services/slash_commands/interpret_service.rb
app/services/slash_commands/interpret_service.rb
+2
-2
spec/features/issues/user_uses_slash_commands_spec.rb
spec/features/issues/user_uses_slash_commands_spec.rb
+59
-13
spec/services/issues/create_service_spec.rb
spec/services/issues/create_service_spec.rb
+29
-7
spec/services/issues/update_service_spec.rb
spec/services/issues/update_service_spec.rb
+63
-34
spec/services/slash_commands/interpret_service_spec.rb
spec/services/slash_commands/interpret_service_spec.rb
+61
-10
spec/support/features/issuable_slash_commands_shared_examples.rb
...pport/features/issuable_slash_commands_shared_examples.rb
+0
-0
spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
...issuable_create_service_slash_commands_shared_examples.rb
+0
-0
No files found.
CHANGELOG
View file @
adab5dba
...
@@ -7,6 +7,7 @@ v 8.13.0 (unreleased)
...
@@ -7,6 +7,7 @@ v 8.13.0 (unreleased)
- Log LDAP lookup errors and don't swallow unrelated exceptions. !6103 (Markus Koller)
- Log LDAP lookup errors and don't swallow unrelated exceptions. !6103 (Markus Koller)
- Add more tests for calendar contribution (ClemMakesApps)
- Add more tests for calendar contribution (ClemMakesApps)
- Avoid database queries on Banzai::ReferenceParser::BaseParser for nodes without references
- Avoid database queries on Banzai::ReferenceParser::BaseParser for nodes without references
- Fix permission for setting an issue's due date
- Fix robots.txt disallowing access to groups starting with "s" (Matt Harrison)
- Fix robots.txt disallowing access to groups starting with "s" (Matt Harrison)
- Only update issuable labels if they have been changed
- Only update issuable labels if they have been changed
- Revoke button in Applications Settings underlines on hover.
- Revoke button in Applications Settings underlines on hover.
...
...
app/services/issuable_base_service.rb
View file @
adab5dba
...
@@ -50,6 +50,7 @@ class IssuableBaseService < BaseService
...
@@ -50,6 +50,7 @@ class IssuableBaseService < BaseService
params
.
delete
(
:remove_label_ids
)
params
.
delete
(
:remove_label_ids
)
params
.
delete
(
:label_ids
)
params
.
delete
(
:label_ids
)
params
.
delete
(
:assignee_id
)
params
.
delete
(
:assignee_id
)
params
.
delete
(
:due_date
)
end
end
end
end
...
...
app/services/slash_commands/interpret_service.rb
View file @
adab5dba
...
@@ -195,7 +195,7 @@ module SlashCommands
...
@@ -195,7 +195,7 @@ module SlashCommands
params
'<in 2 days | this Friday | December 31st>'
params
'<in 2 days | this Friday | December 31st>'
condition
do
condition
do
issuable
.
respond_to?
(
:due_date
)
&&
issuable
.
respond_to?
(
:due_date
)
&&
current_user
.
can?
(
:"
update_
#{
issuable
.
to_ability_name
}
"
,
issuable
)
current_user
.
can?
(
:"
admin_
#{
issuable
.
to_ability_name
}
"
,
project
)
end
end
command
:due
do
|
due_date_param
|
command
:due
do
|
due_date_param
|
due_date
=
Chronic
.
parse
(
due_date_param
).
try
(
:to_date
)
due_date
=
Chronic
.
parse
(
due_date_param
).
try
(
:to_date
)
...
@@ -208,7 +208,7 @@ module SlashCommands
...
@@ -208,7 +208,7 @@ module SlashCommands
issuable
.
persisted?
&&
issuable
.
persisted?
&&
issuable
.
respond_to?
(
:due_date
)
&&
issuable
.
respond_to?
(
:due_date
)
&&
issuable
.
due_date?
&&
issuable
.
due_date?
&&
current_user
.
can?
(
:"
update_
#{
issuable
.
to_ability_name
}
"
,
issuable
)
current_user
.
can?
(
:"
admin_
#{
issuable
.
to_ability_name
}
"
,
project
)
end
end
command
:remove_due_date
do
command
:remove_due_date
do
@updates
[
:due_date
]
=
nil
@updates
[
:due_date
]
=
nil
...
...
spec/features/issues/user_uses_slash_commands_spec.rb
View file @
adab5dba
...
@@ -25,32 +25,78 @@ feature 'Issues > User uses slash commands', feature: true, js: true do
...
@@ -25,32 +25,78 @@ feature 'Issues > User uses slash commands', feature: true, js: true do
describe
'adding a due date from note'
do
describe
'adding a due date from note'
do
let
(
:issue
)
{
create
(
:issue
,
project:
project
)
}
let
(
:issue
)
{
create
(
:issue
,
project:
project
)
}
it
'does not create a note, and sets the due date accordingly'
do
context
'when the current user can update the due date'
do
write_note
(
"/due 2016-08-28"
)
it
'does not create a note, and sets the due date accordingly'
do
write_note
(
"/due 2016-08-28"
)
expect
(
page
).
not_to
have_content
'/due 2016-08-28'
expect
(
page
).
not_to
have_content
'/due 2016-08-28'
expect
(
page
).
to
have_content
'Your commands have been executed!'
expect
(
page
).
to
have_content
'Your commands have been executed!'
issue
.
reload
issue
.
reload
expect
(
issue
.
due_date
).
to
eq
Date
.
new
(
2016
,
8
,
28
)
expect
(
issue
.
due_date
).
to
eq
Date
.
new
(
2016
,
8
,
28
)
end
end
context
'when the current user cannot update the due date'
do
let
(
:guest
)
{
create
(
:user
)
}
before
do
project
.
team
<<
[
guest
,
:guest
]
logout
login_with
(
guest
)
visit
namespace_project_issue_path
(
project
.
namespace
,
project
,
issue
)
end
it
'does not create a note, and sets the due date accordingly'
do
write_note
(
"/due 2016-08-28"
)
expect
(
page
).
to
have_content
'/due 2016-08-28'
expect
(
page
).
not_to
have_content
'Your commands have been executed!'
issue
.
reload
expect
(
issue
.
due_date
).
to
be_nil
end
end
end
end
end
describe
'removing a due date from note'
do
describe
'removing a due date from note'
do
let
(
:issue
)
{
create
(
:issue
,
project:
project
,
due_date:
Date
.
new
(
2016
,
8
,
28
))
}
let
(
:issue
)
{
create
(
:issue
,
project:
project
,
due_date:
Date
.
new
(
2016
,
8
,
28
))
}
it
'does not create a note, and removes the due date accordingly'
do
context
'when the current user can update the due date'
do
expect
(
issue
.
due_date
).
to
eq
Date
.
new
(
2016
,
8
,
28
)
it
'does not create a note, and removes the due date accordingly'
do
expect
(
issue
.
due_date
).
to
eq
Date
.
new
(
2016
,
8
,
28
)
write_note
(
"/remove_due_date"
)
expect
(
page
).
not_to
have_content
'/remove_due_date'
expect
(
page
).
to
have_content
'Your commands have been executed!'
issue
.
reload
expect
(
issue
.
due_date
).
to
be_nil
end
end
context
'when the current user cannot update the due date'
do
let
(
:guest
)
{
create
(
:user
)
}
before
do
project
.
team
<<
[
guest
,
:guest
]
logout
login_with
(
guest
)
visit
namespace_project_issue_path
(
project
.
namespace
,
project
,
issue
)
end
write_note
(
"/remove_due_date"
)
it
'does not create a note, and sets the due date accordingly'
do
write_note
(
"/remove_due_date"
)
expect
(
page
).
not_
to
have_content
'/remove_due_date'
expect
(
page
).
to
have_content
'/remove_due_date'
expect
(
page
).
to
have_content
'Your commands have been executed!'
expect
(
page
).
not_
to
have_content
'Your commands have been executed!'
issue
.
reload
issue
.
reload
expect
(
issue
.
due_date
).
to
be_nil
expect
(
issue
.
due_date
).
to
eq
Date
.
new
(
2016
,
8
,
28
)
end
end
end
end
end
end
end
...
...
spec/services/issues/create_service_spec.rb
View file @
adab5dba
...
@@ -20,16 +20,38 @@ describe Issues::CreateService, services: true do
...
@@ -20,16 +20,38 @@ describe Issues::CreateService, services: true do
let
(
:opts
)
do
let
(
:opts
)
do
{
title:
'Awesome issue'
,
{
title:
'Awesome issue'
,
description:
'please fix'
,
description:
'please fix'
,
assignee
:
assignee
,
assignee
_id:
assignee
.
id
,
label_ids:
labels
.
map
(
&
:id
),
label_ids:
labels
.
map
(
&
:id
),
milestone_id:
milestone
.
id
}
milestone_id:
milestone
.
id
,
due_date:
Date
.
tomorrow
}
end
end
it
{
expect
(
issue
).
to
be_valid
}
it
'creates the issue with the given params'
do
it
{
expect
(
issue
.
title
).
to
eq
(
'Awesome issue'
)
}
expect
(
issue
).
to
be_persisted
it
{
expect
(
issue
.
assignee
).
to
eq
assignee
}
expect
(
issue
.
title
).
to
eq
(
'Awesome issue'
)
it
{
expect
(
issue
.
labels
).
to
match_array
labels
}
expect
(
issue
.
assignee
).
to
eq
assignee
it
{
expect
(
issue
.
milestone
).
to
eq
milestone
}
expect
(
issue
.
labels
).
to
match_array
labels
expect
(
issue
.
milestone
).
to
eq
milestone
expect
(
issue
.
due_date
).
to
eq
Date
.
tomorrow
end
context
'when current user cannot admin issues in the project'
do
let
(
:guest
)
{
create
(
:user
)
}
before
do
project
.
team
<<
[
guest
,
:guest
]
end
it
'filters out params that cannot be set without the :admin_issue permission'
do
issue
=
described_class
.
new
(
project
,
guest
,
opts
).
execute
expect
(
issue
).
to
be_persisted
expect
(
issue
.
title
).
to
eq
(
'Awesome issue'
)
expect
(
issue
.
assignee
).
to
be_nil
expect
(
issue
.
labels
).
to
be_empty
expect
(
issue
.
milestone
).
to
be_nil
expect
(
issue
.
due_date
).
to
be_nil
end
end
it
'creates a pending todo for new assignee'
do
it
'creates a pending todo for new assignee'
do
attributes
=
{
attributes
=
{
...
...
spec/services/issues/update_service_spec.rb
View file @
adab5dba
...
@@ -32,55 +32,84 @@ describe Issues::UpdateService, services: true do
...
@@ -32,55 +32,84 @@ describe Issues::UpdateService, services: true do
described_class
.
new
(
project
,
user
,
opts
).
execute
(
issue
)
described_class
.
new
(
project
,
user
,
opts
).
execute
(
issue
)
end
end
context
"valid params"
do
context
'valid params'
do
before
do
let
(
:opts
)
do
opts
=
{
{
title:
'New title'
,
title:
'New title'
,
description:
'Also please fix'
,
description:
'Also please fix'
,
assignee_id:
user2
.
id
,
assignee_id:
user2
.
id
,
state_event:
'close'
,
state_event:
'close'
,
label_ids:
[
label
.
id
]
label_ids:
[
label
.
id
],
due_date:
Date
.
tomorrow
}
}
perform_enqueued_jobs
do
update_issue
(
opts
)
end
end
end
it
{
expect
(
issue
).
to
be_valid
}
it
'updates the issue with the given params'
do
it
{
expect
(
issue
.
title
).
to
eq
(
'New title'
)
}
update_issue
(
opts
)
it
{
expect
(
issue
.
assignee
).
to
eq
(
user2
)
}
it
{
expect
(
issue
).
to
be_closed
}
expect
(
issue
).
to
be_valid
it
{
expect
(
issue
.
labels
.
count
).
to
eq
(
1
)
}
expect
(
issue
.
title
).
to
eq
'New title'
it
{
expect
(
issue
.
labels
.
first
.
title
).
to
eq
(
label
.
name
)
}
expect
(
issue
.
description
).
to
eq
'Also please fix'
expect
(
issue
.
assignee
).
to
eq
user2
it
'sends email to user2 about assign of new issue and email to user3 about issue unassignment'
do
expect
(
issue
).
to
be_closed
deliveries
=
ActionMailer
::
Base
.
deliveries
expect
(
issue
.
labels
).
to
match_array
[
label
]
email
=
deliveries
.
last
expect
(
issue
.
due_date
).
to
eq
Date
.
tomorrow
recipients
=
deliveries
.
last
(
2
).
map
(
&
:to
).
flatten
expect
(
recipients
).
to
include
(
user2
.
email
,
user3
.
email
)
expect
(
email
.
subject
).
to
include
(
issue
.
title
)
end
end
it
'creates system note about issue reassign'
do
context
'when current user cannot admin issues in the project'
do
note
=
find_note
(
'Reassigned to'
)
let
(
:guest
)
{
create
(
:user
)
}
before
do
project
.
team
<<
[
guest
,
:guest
]
end
expect
(
note
).
not_to
be_nil
it
'filters out params that cannot be set without the :admin_issue permission'
do
expect
(
note
.
note
).
to
include
"Reassigned to
\@
#{
user2
.
username
}
"
described_class
.
new
(
project
,
guest
,
opts
).
execute
(
issue
)
expect
(
issue
).
to
be_valid
expect
(
issue
.
title
).
to
eq
'New title'
expect
(
issue
.
description
).
to
eq
'Also please fix'
expect
(
issue
.
assignee
).
to
eq
user3
expect
(
issue
.
labels
).
to
be_empty
expect
(
issue
.
milestone
).
to
be_nil
expect
(
issue
.
due_date
).
to
be_nil
end
end
end
it
'creates system note about issue label edit'
do
context
'with background jobs processed'
do
note
=
find_note
(
'Added ~'
)
before
do
perform_enqueued_jobs
do
update_issue
(
opts
)
end
end
it
'sends email to user2 about assign of new issue and email to user3 about issue unassignment'
do
deliveries
=
ActionMailer
::
Base
.
deliveries
email
=
deliveries
.
last
recipients
=
deliveries
.
last
(
2
).
map
(
&
:to
).
flatten
expect
(
recipients
).
to
include
(
user2
.
email
,
user3
.
email
)
expect
(
email
.
subject
).
to
include
(
issue
.
title
)
end
expect
(
note
).
not_to
be_nil
it
'creates system note about issue reassign'
do
expect
(
note
.
note
).
to
include
"Added ~
#{
label
.
id
}
label"
note
=
find_note
(
'Reassigned to'
)
end
it
'creates system note about title change'
do
expect
(
note
).
not_to
be_nil
note
=
find_note
(
'Changed title:'
)
expect
(
note
.
note
).
to
include
"Reassigned to
\@
#{
user2
.
username
}
"
end
expect
(
note
).
not_to
be_nil
it
'creates system note about issue label edit'
do
expect
(
note
.
note
).
to
eq
'Changed title: **{-Old-} title** → **{+New+} title**'
note
=
find_note
(
'Added ~'
)
expect
(
note
).
not_to
be_nil
expect
(
note
.
note
).
to
include
"Added ~
#{
label
.
id
}
label"
end
it
'creates system note about title change'
do
note
=
find_note
(
'Changed title:'
)
expect
(
note
).
not_to
be_nil
expect
(
note
.
note
).
to
eq
'Changed title: **{-Old-} title** → **{+New+} title**'
end
end
end
end
end
...
...
spec/services/slash_commands/interpret_service_spec.rb
View file @
adab5dba
require
'spec_helper'
require
'spec_helper'
describe
SlashCommands
::
InterpretService
,
services:
true
do
describe
SlashCommands
::
InterpretService
,
services:
true
do
let
(
:project
)
{
create
(
:
project
)
}
let
(
:project
)
{
create
(
:
empty_project
,
:public
)
}
let
(
:
us
er
)
{
create
(
:user
)
}
let
(
:
develop
er
)
{
create
(
:user
)
}
let
(
:issue
)
{
create
(
:issue
,
project:
project
)
}
let
(
:issue
)
{
create
(
:issue
,
project:
project
)
}
let
(
:milestone
)
{
create
(
:milestone
,
project:
project
,
title:
'9.10'
)
}
let
(
:milestone
)
{
create
(
:milestone
,
project:
project
,
title:
'9.10'
)
}
let
(
:inprogress
)
{
create
(
:label
,
project:
project
,
title:
'In Progress'
)
}
let
(
:inprogress
)
{
create
(
:label
,
project:
project
,
title:
'In Progress'
)
}
let
(
:bug
)
{
create
(
:label
,
project:
project
,
title:
'Bug'
)
}
let
(
:bug
)
{
create
(
:label
,
project:
project
,
title:
'Bug'
)
}
before
do
before
do
project
.
team
<<
[
us
er
,
:developer
]
project
.
team
<<
[
develop
er
,
:developer
]
end
end
describe
'#execute'
do
describe
'#execute'
do
let
(
:service
)
{
described_class
.
new
(
project
,
us
er
)
}
let
(
:service
)
{
described_class
.
new
(
project
,
develop
er
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
source_project:
project
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
source_project:
project
)
}
shared_examples
'reopen command'
do
shared_examples
'reopen command'
do
...
@@ -45,13 +45,13 @@ describe SlashCommands::InterpretService, services: true do
...
@@ -45,13 +45,13 @@ describe SlashCommands::InterpretService, services: true do
it
'fetches assignee and populates assignee_id if content contains /assign'
do
it
'fetches assignee and populates assignee_id if content contains /assign'
do
_
,
updates
=
service
.
execute
(
content
,
issuable
)
_
,
updates
=
service
.
execute
(
content
,
issuable
)
expect
(
updates
).
to
eq
(
assignee_id:
us
er
.
id
)
expect
(
updates
).
to
eq
(
assignee_id:
develop
er
.
id
)
end
end
end
end
shared_examples
'unassign command'
do
shared_examples
'unassign command'
do
it
'populates assignee_id: nil if content contains /unassign'
do
it
'populates assignee_id: nil if content contains /unassign'
do
issuable
.
update
(
assignee_id:
us
er
.
id
)
issuable
.
update
(
assignee_id:
develop
er
.
id
)
_
,
updates
=
service
.
execute
(
content
,
issuable
)
_
,
updates
=
service
.
execute
(
content
,
issuable
)
expect
(
updates
).
to
eq
(
assignee_id:
nil
)
expect
(
updates
).
to
eq
(
assignee_id:
nil
)
...
@@ -124,7 +124,7 @@ describe SlashCommands::InterpretService, services: true do
...
@@ -124,7 +124,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples
'done command'
do
shared_examples
'done command'
do
it
'populates todo_event: "done" if content contains /done'
do
it
'populates todo_event: "done" if content contains /done'
do
TodoService
.
new
.
mark_todo
(
issuable
,
us
er
)
TodoService
.
new
.
mark_todo
(
issuable
,
develop
er
)
_
,
updates
=
service
.
execute
(
content
,
issuable
)
_
,
updates
=
service
.
execute
(
content
,
issuable
)
expect
(
updates
).
to
eq
(
todo_event:
'done'
)
expect
(
updates
).
to
eq
(
todo_event:
'done'
)
...
@@ -141,7 +141,7 @@ describe SlashCommands::InterpretService, services: true do
...
@@ -141,7 +141,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples
'unsubscribe command'
do
shared_examples
'unsubscribe command'
do
it
'populates subscription_event: "unsubscribe" if content contains /unsubscribe'
do
it
'populates subscription_event: "unsubscribe" if content contains /unsubscribe'
do
issuable
.
subscribe
(
us
er
)
issuable
.
subscribe
(
develop
er
)
_
,
updates
=
service
.
execute
(
content
,
issuable
)
_
,
updates
=
service
.
execute
(
content
,
issuable
)
expect
(
updates
).
to
eq
(
subscription_event:
'unsubscribe'
)
expect
(
updates
).
to
eq
(
subscription_event:
'unsubscribe'
)
...
@@ -209,12 +209,12 @@ describe SlashCommands::InterpretService, services: true do
...
@@ -209,12 +209,12 @@ describe SlashCommands::InterpretService, services: true do
end
end
it_behaves_like
'assign command'
do
it_behaves_like
'assign command'
do
let
(
:content
)
{
"/assign @
#{
us
er
.
username
}
"
}
let
(
:content
)
{
"/assign @
#{
develop
er
.
username
}
"
}
let
(
:issuable
)
{
issue
}
let
(
:issuable
)
{
issue
}
end
end
it_behaves_like
'assign command'
do
it_behaves_like
'assign command'
do
let
(
:content
)
{
"/assign @
#{
us
er
.
username
}
"
}
let
(
:content
)
{
"/assign @
#{
develop
er
.
username
}
"
}
let
(
:issuable
)
{
merge_request
}
let
(
:issuable
)
{
merge_request
}
end
end
...
@@ -380,5 +380,56 @@ describe SlashCommands::InterpretService, services: true do
...
@@ -380,5 +380,56 @@ describe SlashCommands::InterpretService, services: true do
let
(
:content
)
{
'/remove_due_date'
}
let
(
:content
)
{
'/remove_due_date'
}
let
(
:issuable
)
{
merge_request
}
let
(
:issuable
)
{
merge_request
}
end
end
context
'when current_user cannot :admin_issue'
do
let
(
:visitor
)
{
create
(
:user
)
}
let
(
:issue
)
{
create
(
:issue
,
project:
project
,
author:
visitor
)
}
let
(
:service
)
{
described_class
.
new
(
project
,
visitor
)
}
it_behaves_like
'empty command'
do
let
(
:content
)
{
"/assign @
#{
developer
.
username
}
"
}
let
(
:issuable
)
{
issue
}
end
it_behaves_like
'empty command'
do
let
(
:content
)
{
'/unassign'
}
let
(
:issuable
)
{
issue
}
end
it_behaves_like
'empty command'
do
let
(
:content
)
{
"/milestone %
#{
milestone
.
title
}
"
}
let
(
:issuable
)
{
issue
}
end
it_behaves_like
'empty command'
do
let
(
:content
)
{
'/remove_milestone'
}
let
(
:issuable
)
{
issue
}
end
it_behaves_like
'empty command'
do
let
(
:content
)
{
%(/label ~"#{inprogress.title}" ~#{bug.title} ~unknown)
}
let
(
:issuable
)
{
issue
}
end
it_behaves_like
'empty command'
do
let
(
:content
)
{
%(/unlabel ~"#{inprogress.title}")
}
let
(
:issuable
)
{
issue
}
end
it_behaves_like
'empty command'
do
let
(
:content
)
{
%(/relabel ~"#{inprogress.title}")
}
let
(
:issuable
)
{
issue
}
end
it_behaves_like
'empty command'
do
let
(
:content
)
{
'/due tomorrow'
}
let
(
:issuable
)
{
issue
}
end
it_behaves_like
'empty command'
do
let
(
:content
)
{
'/remove_due_date'
}
let
(
:issuable
)
{
issue
}
end
end
end
end
end
end
spec/support/issuable_slash_commands_shared_examples.rb
→
spec/support/
features/
issuable_slash_commands_shared_examples.rb
View file @
adab5dba
File moved
spec/support/issuable_create_service_slash_commands_shared_examples.rb
→
spec/support/
services/
issuable_create_service_slash_commands_shared_examples.rb
View file @
adab5dba
File moved
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