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
9f949d4e
Commit
9f949d4e
authored
Feb 28, 2017
by
mhasbini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add /award slash command
add /award slash command; Allow posting of just an emoji in comment
parent
c5b29ed6
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
138 additions
and
86 deletions
+138
-86
app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js.es6
...cripts/issuable/time_tracking/time_tracking_bundle.js.es6
+3
-2
app/assets/javascripts/notes.js
app/assets/javascripts/notes.js
+17
-18
app/controllers/projects/notes_controller.rb
app/controllers/projects/notes_controller.rb
+2
-9
app/models/note.rb
app/models/note.rb
+0
-4
app/services/issuable_base_service.rb
app/services/issuable_base_service.rb
+9
-0
app/services/notes/create_service.rb
app/services/notes/create_service.rb
+1
-9
app/services/slash_commands/interpret_service.rb
app/services/slash_commands/interpret_service.rb
+17
-0
changelogs/unreleased/25437-just-emoji.yml
changelogs/unreleased/25437-just-emoji.yml
+4
-0
doc/user/project/slash_commands.md
doc/user/project/slash_commands.md
+1
-0
features/project/issues/award_emoji.feature
features/project/issues/award_emoji.feature
+1
-1
features/steps/project/issues/award_emoji.rb
features/steps/project/issues/award_emoji.rb
+4
-0
spec/features/issues/award_emoji_spec.rb
spec/features/issues/award_emoji_spec.rb
+25
-0
spec/requests/api/notes_spec.rb
spec/requests/api/notes_spec.rb
+2
-2
spec/requests/api/v3/notes_spec.rb
spec/requests/api/v3/notes_spec.rb
+2
-2
spec/services/notes/create_service_spec.rb
spec/services/notes/create_service_spec.rb
+11
-39
spec/services/slash_commands/interpret_service_spec.rb
spec/services/slash_commands/interpret_service_spec.rb
+39
-0
No files found.
app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js.es6
View file @
9f949d4e
...
@@ -39,8 +39,9 @@ require('../../subbable_resource');
...
@@ -39,8 +39,9 @@ require('../../subbable_resource');
listenForSlashCommands() {
listenForSlashCommands() {
$(document).on('ajax:success', '.gfm-form', (e, data) => {
$(document).on('ajax:success', '.gfm-form', (e, data) => {
const subscribedCommands = ['spend_time', 'time_estimate'];
const subscribedCommands = ['spend_time', 'time_estimate'];
const changedCommands = data.commands_changes;
const changedCommands = data.commands_changes
? Object.keys(data.commands_changes)
: [];
if (changedCommands && _.intersection(subscribedCommands, changedCommands).length) {
if (changedCommands && _.intersection(subscribedCommands, changedCommands).length) {
this.fetchIssuable();
this.fetchIssuable();
}
}
...
...
app/assets/javascripts/notes.js
View file @
9f949d4e
...
@@ -246,12 +246,21 @@ require('./task_list');
...
@@ -246,12 +246,21 @@ require('./task_list');
};
};
Notes
.
prototype
.
handleCreateChanges
=
function
(
note
)
{
Notes
.
prototype
.
handleCreateChanges
=
function
(
note
)
{
var
votesBlock
;
if
(
typeof
note
===
'
undefined
'
)
{
if
(
typeof
note
===
'
undefined
'
)
{
return
;
return
;
}
}
if
(
note
.
commands_changes
&&
note
.
commands_changes
.
indexOf
(
'
merge
'
)
!==
-
1
)
{
if
(
note
.
commands_changes
)
{
$
.
get
(
mrRefreshWidgetUrl
);
if
(
'
merge
'
in
note
.
commands_changes
)
{
$
.
get
(
mrRefreshWidgetUrl
);
}
if
(
'
emoji_award
'
in
note
.
commands_changes
)
{
votesBlock
=
$
(
'
.js-awards-block
'
).
eq
(
0
);
gl
.
awardsHandler
.
addAwardToEmojiBar
(
votesBlock
,
note
.
commands_changes
.
emoji_award
);
return
gl
.
awardsHandler
.
scrollToAwards
();
}
}
}
};
};
...
@@ -262,26 +271,16 @@ require('./task_list');
...
@@ -262,26 +271,16 @@ require('./task_list');
*/
*/
Notes
.
prototype
.
renderNote
=
function
(
note
)
{
Notes
.
prototype
.
renderNote
=
function
(
note
)
{
var
$notesList
,
votesBlock
;
var
$notesList
;
if
(
!
note
.
valid
)
{
if
(
!
note
.
valid
)
{
if
(
note
.
award
)
{
if
(
note
.
errors
.
commands_only
)
{
new
Flash
(
'
You have already awarded this emoji!
'
,
'
alert
'
,
this
.
parentTimeline
);
new
Flash
(
note
.
errors
.
commands_only
,
'
notice
'
,
this
.
parentTimeline
);
}
this
.
refresh
();
else
{
if
(
note
.
errors
.
commands_only
)
{
new
Flash
(
note
.
errors
.
commands_only
,
'
notice
'
,
this
.
parentTimeline
);
this
.
refresh
();
}
}
}
return
;
return
;
}
}
if
(
note
.
award
)
{
votesBlock
=
$
(
'
.js-awards-block
'
).
eq
(
0
);
if
(
this
.
isNewNote
(
note
))
{
gl
.
awardsHandler
.
addAwardToEmojiBar
(
votesBlock
,
note
.
name
);
return
gl
.
awardsHandler
.
scrollToAwards
();
// render note if it not present in loaded list
// or skip if rendered
}
else
if
(
this
.
isNewNote
(
note
))
{
this
.
note_ids
.
push
(
note
.
id
);
this
.
note_ids
.
push
(
note
.
id
);
$notesList
=
$
(
'
ul.main-notes-list
'
);
$notesList
=
$
(
'
ul.main-notes-list
'
);
$notesList
.
append
(
note
.
html
).
syntaxHighlight
();
$notesList
.
append
(
note
.
html
).
syntaxHighlight
();
...
...
app/controllers/projects/notes_controller.rb
View file @
9f949d4e
...
@@ -148,17 +148,10 @@ class Projects::NotesController < Projects::ApplicationController
...
@@ -148,17 +148,10 @@ class Projects::NotesController < Projects::ApplicationController
def
note_json
(
note
)
def
note_json
(
note
)
attrs
=
{
attrs
=
{
award:
false
,
id:
note
.
id
id:
note
.
id
}
}
if
note
.
is_a?
(
AwardEmoji
)
if
note
.
persisted?
attrs
.
merge!
(
valid:
note
.
valid?
,
award:
true
,
name:
note
.
name
)
elsif
note
.
persisted?
Banzai
::
NoteRenderer
.
render
([
note
],
@project
,
current_user
)
Banzai
::
NoteRenderer
.
render
([
note
],
@project
,
current_user
)
attrs
.
merge!
(
attrs
.
merge!
(
...
@@ -198,7 +191,7 @@ class Projects::NotesController < Projects::ApplicationController
...
@@ -198,7 +191,7 @@ class Projects::NotesController < Projects::ApplicationController
)
)
end
end
attrs
[
:commands_changes
]
=
note
.
commands_changes
unless
attrs
[
:award
]
attrs
[
:commands_changes
]
=
note
.
commands_changes
attrs
attrs
end
end
...
...
app/models/note.rb
View file @
9f949d4e
...
@@ -231,10 +231,6 @@ class Note < ActiveRecord::Base
...
@@ -231,10 +231,6 @@ class Note < ActiveRecord::Base
note
=~
/\A
#{
Banzai
::
Filter
::
EmojiFilter
.
emoji_pattern
}
\s?\Z/
note
=~
/\A
#{
Banzai
::
Filter
::
EmojiFilter
.
emoji_pattern
}
\s?\Z/
end
end
def
award_emoji_name
note
.
match
(
Banzai
::
Filter
::
EmojiFilter
.
emoji_pattern
)[
1
]
end
def
to_ability_name
def
to_ability_name
for_personal_snippet?
?
'personal_snippet'
:
noteable_type
.
underscore
for_personal_snippet?
?
'personal_snippet'
:
noteable_type
.
underscore
end
end
...
...
app/services/issuable_base_service.rb
View file @
9f949d4e
...
@@ -203,6 +203,7 @@ class IssuableBaseService < BaseService
...
@@ -203,6 +203,7 @@ class IssuableBaseService < BaseService
change_state
(
issuable
)
change_state
(
issuable
)
change_subscription
(
issuable
)
change_subscription
(
issuable
)
change_todo
(
issuable
)
change_todo
(
issuable
)
toggle_award
(
issuable
)
filter_params
(
issuable
)
filter_params
(
issuable
)
old_labels
=
issuable
.
labels
.
to_a
old_labels
=
issuable
.
labels
.
to_a
old_mentioned_users
=
issuable
.
mentioned_users
.
to_a
old_mentioned_users
=
issuable
.
mentioned_users
.
to_a
...
@@ -263,6 +264,14 @@ class IssuableBaseService < BaseService
...
@@ -263,6 +264,14 @@ class IssuableBaseService < BaseService
end
end
end
end
def
toggle_award
(
issuable
)
award
=
params
.
delete
(
:emoji_award
)
if
award
todo_service
.
new_award_emoji
(
issuable
,
current_user
)
issuable
.
toggle_award_emoji
(
award
,
current_user
)
end
end
def
has_changes?
(
issuable
,
old_labels:
[])
def
has_changes?
(
issuable
,
old_labels:
[])
valid_attrs
=
[
:title
,
:description
,
:assignee_id
,
:milestone_id
,
:target_branch
]
valid_attrs
=
[
:title
,
:description
,
:assignee_id
,
:milestone_id
,
:target_branch
]
...
...
app/services/notes/create_service.rb
View file @
9f949d4e
...
@@ -8,14 +8,6 @@ module Notes
...
@@ -8,14 +8,6 @@ module Notes
note
.
author
=
current_user
note
.
author
=
current_user
note
.
system
=
false
note
.
system
=
false
if
note
.
award_emoji?
noteable
=
note
.
noteable
if
noteable
.
user_can_award?
(
current_user
,
note
.
award_emoji_name
)
todo_service
.
new_award_emoji
(
noteable
,
current_user
)
return
noteable
.
create_award_emoji
(
note
.
award_emoji_name
,
current_user
)
end
end
# We execute commands (extracted from `params[:note]`) on the noteable
# We execute commands (extracted from `params[:note]`) on the noteable
# **before** we save the note because if the note consists of commands
# **before** we save the note because if the note consists of commands
# only, there is no need be create a note!
# only, there is no need be create a note!
...
@@ -48,7 +40,7 @@ module Notes
...
@@ -48,7 +40,7 @@ module Notes
note
.
errors
.
add
(
:commands_only
,
'Commands applied'
)
note
.
errors
.
add
(
:commands_only
,
'Commands applied'
)
end
end
note
.
commands_changes
=
command_params
.
keys
note
.
commands_changes
=
command_params
end
end
note
note
...
...
app/services/slash_commands/interpret_service.rb
View file @
9f949d4e
...
@@ -255,6 +255,18 @@ module SlashCommands
...
@@ -255,6 +255,18 @@ module SlashCommands
@updates
[
:wip_event
]
=
issuable
.
work_in_progress?
?
'unwip'
:
'wip'
@updates
[
:wip_event
]
=
issuable
.
work_in_progress?
?
'unwip'
:
'wip'
end
end
desc
'Toggle emoji reward'
params
':emoji:'
condition
do
issuable
.
persisted?
end
command
:award
do
|
emoji
|
name
=
award_emoji_name
(
emoji
)
if
name
&&
issuable
.
user_can_award?
(
current_user
,
name
)
@updates
[
:emoji_award
]
=
name
end
end
desc
'Set time estimate'
desc
'Set time estimate'
params
'<1w 3d 2h 14m>'
params
'<1w 3d 2h 14m>'
condition
do
condition
do
...
@@ -329,5 +341,10 @@ module SlashCommands
...
@@ -329,5 +341,10 @@ module SlashCommands
ext
.
references
(
type
)
ext
.
references
(
type
)
end
end
def
award_emoji_name
(
emoji
)
match
=
emoji
.
match
(
Banzai
::
Filter
::
EmojiFilter
.
emoji_pattern
)
match
[
1
]
if
match
end
end
end
end
end
changelogs/unreleased/25437-just-emoji.yml
0 → 100644
View file @
9f949d4e
---
title
:
Introduce /award slash command; Allow posting of just an emoji in comment
merge_request
:
9382
author
:
mhasbini
doc/user/project/slash_commands.md
View file @
9f949d4e
...
@@ -35,3 +35,4 @@ do.
...
@@ -35,3 +35,4 @@ do.
|
<code>
/spend
<
1h 30m
|
-1h 5m
>
</code>
| Add or subtract spent time |
|
<code>
/spend
<
1h 30m
|
-1h 5m
>
</code>
| Add or subtract spent time |
|
`/remove_time_spent`
| Remove time spent |
|
`/remove_time_spent`
| Remove time spent |
|
`/target_branch <Branch Name>`
| Set target branch for current merge request |
|
`/target_branch <Branch Name>`
| Set target branch for current merge request |
|
`/award :emoji:`
| Toggle award for :emoji: |
features/project/issues/award_emoji.feature
View file @
9f949d4e
...
@@ -42,4 +42,4 @@ Feature: Award Emoji
...
@@ -42,4 +42,4 @@ Feature: Award Emoji
@javascript
@javascript
Scenario
:
I
add award emoji using regular comment
Scenario
:
I
add award emoji using regular comment
Given
I leave comment with a single emoji
Given
I leave comment with a single emoji
Then
I have
award
added
Then
I have
new comment with emoji
added
features/steps/project/issues/award_emoji.rb
View file @
9f949d4e
...
@@ -44,6 +44,10 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
...
@@ -44,6 +44,10 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
end
end
end
end
step
'I have new comment with emoji added'
do
expect
(
page
).
to
have_selector
".emoji[title=':smile:']"
end
step
'I have award added'
do
step
'I have award added'
do
page
.
within
'.awards'
do
page
.
within
'.awards'
do
expect
(
page
).
to
have_selector
'.js-emoji-btn'
expect
(
page
).
to
have_selector
'.js-emoji-btn'
...
...
spec/features/issues/award_emoji_spec.rb
View file @
9f949d4e
...
@@ -67,6 +67,18 @@ describe 'Awards Emoji', feature: true do
...
@@ -67,6 +67,18 @@ describe 'Awards Emoji', feature: true do
expect
(
page
).
not_to
have_selector
(
emoji_counter
)
expect
(
page
).
not_to
have_selector
(
emoji_counter
)
end
end
end
end
context
'execute /award slash command'
do
it
'toggles the emoji award on noteable'
,
js:
true
do
execute_slash_command
(
'/award :100:'
)
expect
(
find
(
noteable_award_counter
)).
to
have_text
(
"1"
)
execute_slash_command
(
'/award :100:'
)
expect
(
page
).
not_to
have_selector
(
noteable_award_counter
)
end
end
end
end
end
end
...
@@ -80,6 +92,15 @@ describe 'Awards Emoji', feature: true do
...
@@ -80,6 +92,15 @@ describe 'Awards Emoji', feature: true do
end
end
end
end
def
execute_slash_command
(
cmd
)
within
(
'.js-main-target-form'
)
do
fill_in
'note[note]'
,
with:
cmd
click_button
'Comment'
end
wait_for_ajax
end
def
thumbsup_emoji
def
thumbsup_emoji
page
.
all
(
emoji_counter
).
first
page
.
all
(
emoji_counter
).
first
end
end
...
@@ -92,6 +113,10 @@ describe 'Awards Emoji', feature: true do
...
@@ -92,6 +113,10 @@ describe 'Awards Emoji', feature: true do
'span.js-counter'
'span.js-counter'
end
end
def
noteable_award_counter
".awards .active"
end
def
toggle_smiley_emoji
(
status
)
def
toggle_smiley_emoji
(
status
)
within
(
'.note'
)
do
within
(
'.note'
)
do
find
(
'.note-emoji-button'
).
click
find
(
'.note-emoji-button'
).
click
...
...
spec/requests/api/notes_spec.rb
View file @
9f949d4e
...
@@ -225,11 +225,11 @@ describe API::Notes, api: true do
...
@@ -225,11 +225,11 @@ describe API::Notes, api: true do
context
'when the user is posting an award emoji on an issue created by someone else'
do
context
'when the user is posting an award emoji on an issue created by someone else'
do
let
(
:issue2
)
{
create
(
:issue
,
project:
project
)
}
let
(
:issue2
)
{
create
(
:issue
,
project:
project
)
}
it
'
returns an award emoji
'
do
it
'
creates a new issue note
'
do
post
api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue2
.
id
}
/notes"
,
user
),
body:
':+1:'
post
api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue2
.
id
}
/notes"
,
user
),
body:
':+1:'
expect
(
response
).
to
have_http_status
(
201
)
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'
awardable_id'
]).
to
eq
issue2
.
id
expect
(
json_response
[
'
body'
]).
to
eq
(
':+1:'
)
end
end
end
end
...
...
spec/requests/api/v3/notes_spec.rb
View file @
9f949d4e
...
@@ -227,11 +227,11 @@ describe API::V3::Notes, api: true do
...
@@ -227,11 +227,11 @@ describe API::V3::Notes, api: true do
context
'when the user is posting an award emoji on an issue created by someone else'
do
context
'when the user is posting an award emoji on an issue created by someone else'
do
let
(
:issue2
)
{
create
(
:issue
,
project:
project
)
}
let
(
:issue2
)
{
create
(
:issue
,
project:
project
)
}
it
'
returns an award emoji
'
do
it
'
creates a new issue note
'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue2
.
id
}
/notes"
,
user
),
body:
':+1:'
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue2
.
id
}
/notes"
,
user
),
body:
':+1:'
expect
(
response
).
to
have_http_status
(
201
)
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'
awardable_id'
]).
to
eq
issue2
.
id
expect
(
json_response
[
'
body'
]).
to
eq
(
':+1:'
)
end
end
end
end
...
...
spec/services/notes/create_service_spec.rb
View file @
9f949d4e
...
@@ -102,47 +102,19 @@ describe Notes::CreateService, services: true do
...
@@ -102,47 +102,19 @@ describe Notes::CreateService, services: true do
expect
(
subject
.
note
).
to
eq
(
params
[
:note
])
expect
(
subject
.
note
).
to
eq
(
params
[
:note
])
end
end
end
end
end
describe
"award emoji"
do
before
do
project
.
team
<<
[
user
,
:master
]
end
it
"creates an award emoji"
do
opts
=
{
note:
':smile: '
,
noteable_type:
'Issue'
,
noteable_id:
issue
.
id
}
note
=
described_class
.
new
(
project
,
user
,
opts
).
execute
expect
(
note
).
to
be_valid
expect
(
note
.
name
).
to
eq
(
'smile'
)
end
it
"creates regular note if emoji name is invalid"
do
describe
'note with emoji only'
do
opts
=
{
it
'creates regular note'
do
note:
':smile: moretext:'
,
opts
=
{
noteable_type:
'Issue'
,
note:
':smile: '
,
noteable_id:
issue
.
id
noteable_type:
'Issue'
,
}
noteable_id:
issue
.
id
note
=
described_class
.
new
(
project
,
user
,
opts
).
execute
}
note
=
described_class
.
new
(
project
,
user
,
opts
).
execute
expect
(
note
).
to
be_valid
expect
(
note
.
note
).
to
eq
(
opts
[
:note
])
end
it
"normalizes the emoji name"
do
opts
=
{
note:
':+1:'
,
noteable_type:
'Issue'
,
noteable_id:
issue
.
id
}
expect_any_instance_of
(
TodoService
).
to
receive
(
:new_award_emoji
).
with
(
issue
,
user
)
described_class
.
new
(
project
,
user
,
opts
).
execute
expect
(
note
).
to
be_valid
expect
(
note
.
note
).
to
eq
(
':smile:'
)
end
end
end
end
end
end
end
spec/services/slash_commands/interpret_service_spec.rb
View file @
9f949d4e
...
@@ -267,6 +267,14 @@ describe SlashCommands::InterpretService, services: true do
...
@@ -267,6 +267,14 @@ describe SlashCommands::InterpretService, services: true do
end
end
end
end
shared_examples
'award command'
do
it
'toggle award 100 emoji if content containts /award :100:'
do
_
,
updates
=
service
.
execute
(
content
,
issuable
)
expect
(
updates
).
to
eq
(
emoji_award:
"100"
)
end
end
it_behaves_like
'reopen command'
do
it_behaves_like
'reopen command'
do
let
(
:content
)
{
'/reopen'
}
let
(
:content
)
{
'/reopen'
}
let
(
:issuable
)
{
issue
}
let
(
:issuable
)
{
issue
}
...
@@ -654,6 +662,37 @@ describe SlashCommands::InterpretService, services: true do
...
@@ -654,6 +662,37 @@ describe SlashCommands::InterpretService, services: true do
end
end
end
end
context
'/award command'
do
it_behaves_like
'award command'
do
let
(
:content
)
{
'/award :100:'
}
let
(
:issuable
)
{
issue
}
end
it_behaves_like
'award command'
do
let
(
:content
)
{
'/award :100:'
}
let
(
:issuable
)
{
merge_request
}
end
context
'ignores command with no argument'
do
it_behaves_like
'empty command'
do
let
(
:content
)
{
'/award'
}
let
(
:issuable
)
{
issue
}
end
end
context
'ignores non-existing / invalid emojis'
do
it_behaves_like
'empty command'
do
let
(
:content
)
{
'/award noop'
}
let
(
:issuable
)
{
issue
}
end
it_behaves_like
'empty command'
do
let
(
:content
)
{
'/award :lorem_ipsum:'
}
let
(
:issuable
)
{
issue
}
end
end
end
context
'/target_branch command'
do
context
'/target_branch command'
do
let
(
:non_empty_project
)
{
create
(
:project
)
}
let
(
:non_empty_project
)
{
create
(
:project
)
}
let
(
:another_merge_request
)
{
create
(
:merge_request
,
author:
developer
,
source_project:
non_empty_project
)
}
let
(
:another_merge_request
)
{
create
(
:merge_request
,
author:
developer
,
source_project:
non_empty_project
)
}
...
...
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