Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
heptapod
heptapod
Commits
547888e1c445
Commit
3bdc57f0
authored
Apr 16, 2016
by
Zeger-Jan van de Weg
Browse files
Create table for award emoji
parent
963fef07e305
Changes
41
Hide whitespace changes
Inline
Side-by-side
app/controllers/concerns/toggle_award_emoji.rb
0 → 100644
View file @
547888e1
module
ToggleAwardEmoji
extend
ActiveSupport
::
Concern
included
do
before_action
:authenticate_user!
,
only:
[
:toggle_award_emoji
]
end
def
toggle_award_emoji
name
=
params
.
require
(
:name
)
awardable
.
toggle_award_emoji
(
name
,
current_user
)
render
json:
{
ok:
true
}
end
private
def
awardable
raise
NotImplementedError
end
end
app/controllers/projects/issues_controller.rb
View file @
547888e1
class
Projects::IssuesController
<
Projects
::
ApplicationController
include
ToggleSubscriptionAction
include
IssuableActions
include
ToggleAwardEmoji
before_action
:module_enabled
before_action
:issue
,
...
...
@@ -61,7 +62,7 @@ def edit
def
show
@note
=
@project
.
notes
.
new
(
noteable:
@issue
)
@notes
=
@issue
.
notes
.
nonawards
.
with_associations
.
fresh
@notes
=
@issue
.
notes
.
with_associations
.
fresh
@noteable
=
@issue
respond_to
do
|
format
|
...
...
@@ -158,6 +159,7 @@ def issue
end
alias_method
:subscribable_resource
,
:issue
alias_method
:issuable
,
:issue
alias_method
:awardable
,
:issue
def
authorize_read_issue!
return
render_404
unless
can?
(
current_user
,
:read_issue
,
@issue
)
...
...
app/controllers/projects/merge_requests_controller.rb
View file @
547888e1
...
...
@@ -2,6 +2,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
include
ToggleSubscriptionAction
include
DiffHelper
include
IssuableActions
include
ToggleAwardEmoji
before_action
:module_enabled
before_action
:merge_request
,
only:
[
...
...
@@ -195,7 +196,7 @@ def merge
if
params
[
:merge_when_build_succeeds
].
present?
&&
@merge_request
.
ci_commit
&&
@merge_request
.
ci_commit
.
active?
MergeRequests
::
MergeWhenBuildSucceedsService
.
new
(
@project
,
current_user
,
merge_params
)
.
execute
(
@merge_request
)
.
execute
(
@merge_request
)
@status
=
:merge_when_build_succeeds
else
MergeWorker
.
perform_async
(
@merge_request
.
id
,
current_user
.
id
,
params
)
...
...
@@ -264,6 +265,7 @@ def merge_request
end
alias_method
:subscribable_resource
,
:merge_request
alias_method
:issuable
,
:merge_request
alias_method
:awardable
,
:merge_request
def
closes_issues
@closes_issues
||=
@merge_request
.
closes_issues
...
...
@@ -299,7 +301,7 @@ def validates_merge_request
def
define_show_vars
# Build a note object for comment form
@note
=
@project
.
notes
.
new
(
noteable:
@merge_request
)
@notes
=
@merge_request
.
mr_and_commit_notes
.
nonawards
.
inc_author
.
fresh
@notes
=
@merge_request
.
mr_and_commit_notes
.
inc_author
.
fresh
@discussions
=
Note
.
discussions_from_notes
(
@notes
)
@noteable
=
@merge_request
...
...
app/controllers/projects/notes_controller.rb
View file @
547888e1
...
...
@@ -3,7 +3,7 @@ class Projects::NotesController < Projects::ApplicationController
before_action
:authorize_read_note!
before_action
:authorize_create_note!
,
only:
[
:create
]
before_action
:authorize_admin_note!
,
only:
[
:update
,
:destroy
]
before_action
:find_current_user_notes
,
except:
[
:destroy
,
:delete_attachment
,
:award_toggle
]
before_action
:find_current_user_notes
,
only:
[
:index
]
def
index
current_fetched_at
=
Time
.
now
.
to_i
...
...
@@ -22,8 +22,10 @@ def index
def
create
@note
=
Notes
::
CreateService
.
new
(
project
,
current_user
,
note_params
).
execute
@note
=
note
.
is_a?
(
AwardEmoji
)
?
@note
.
to_note_json
:
note_json
(
@note
)
respond_to
do
|
format
|
format
.
json
{
render
json:
note_json
(
@note
)
}
format
.
json
{
render
json:
@note
}
format
.
html
{
redirect_back_or_default
}
end
end
...
...
@@ -56,35 +58,12 @@ def delete_attachment
end
end
def
award_toggle
noteable
=
if
note_params
[
:noteable_type
]
==
"issue"
project
.
issues
.
find
(
note_params
[
:noteable_id
])
else
project
.
merge_requests
.
find
(
note_params
[
:noteable_id
])
end
data
=
{
author:
current_user
,
is_award:
true
,
note:
note_params
[
:note
].
delete
(
":"
)
}
note
=
noteable
.
notes
.
find_by
(
data
)
if
note
note
.
destroy
else
Notes
::
CreateService
.
new
(
project
,
current_user
,
note_params
).
execute
end
render
json:
{
ok:
true
}
end
private
def
note
@note
||=
@project
.
notes
.
find
(
params
[
:id
])
end
alias_method
:awardable
,
:note
def
note_to_html
(
note
)
render_to_string
(
...
...
@@ -137,7 +116,7 @@ def note_json(note)
id:
note
.
id
,
discussion_id:
note
.
discussion_id
,
html:
note_to_html
(
note
),
award:
note
.
is_award
,
award:
false
,
note:
note
.
note
,
discussion_html:
note_to_discussion_html
(
note
),
discussion_with_diff_html:
note_to_discussion_with_diff_html
(
note
)
...
...
@@ -145,7 +124,7 @@ def note_json(note)
else
{
valid:
false
,
award:
note
.
is_award
,
award:
false
,
errors:
note
.
errors
}
end
...
...
app/controllers/projects_controller.rb
View file @
547888e1
...
...
@@ -145,7 +145,7 @@ def autocomplete_sources
participants
=
::
Projects
::
ParticipantsService
.
new
(
@project
,
current_user
).
execute
(
note_type
,
note_id
)
@suggestions
=
{
emojis:
AwardEmoji
.
urls
,
emojis:
Gitlab
::
AwardEmoji
.
urls
,
issues:
autocomplete
.
issues
,
mergerequests:
autocomplete
.
merge_requests
,
members:
participants
...
...
app/helpers/issues_helper.rb
View file @
547888e1
...
...
@@ -144,16 +144,17 @@ def emoji_icon(name, unicode = nil, aliases = [], sprite: true)
end
end
def
emoji_author_list
(
notes
,
current_user
)
list
=
notes
.
map
do
|
note
|
note
.
author
==
current_user
?
"me"
:
note
.
author
.
name
end
def
award_user_list
(
awards
,
current_user
)
list
=
awards
.
map
do
|
award
|
award
.
user
==
current_user
?
"me"
:
award
.
user
.
name
end
list
.
join
(
", "
)
end
def
note
_active_class
(
note
s
,
current_user
)
if
current_user
&&
notes
.
pluck
(
:author_id
).
include?
(
current_user
.
id
)
def
award
_active_class
(
award
s
,
current_user
)
if
current_user
&&
awards
.
find
{
|
a
|
a
.
user_id
==
current_user
.
id
}
"active"
else
""
...
...
app/models/award_emoji.rb
0 → 100644
View file @
547888e1
class
AwardEmoji
<
ActiveRecord
::
Base
DOWNVOTE_NAME
=
"thumbsdown"
.
freeze
UPVOTE_NAME
=
"thumbsup"
.
freeze
include
Participable
belongs_to
:awardable
,
polymorphic:
true
belongs_to
:user
validates
:awardable
,
:user
,
presence:
true
validates
:name
,
presence:
true
,
inclusion:
{
in:
Emoji
.
emojis_names
}
validates
:name
,
uniqueness:
{
scope:
[
:user
,
:awardable_type
,
:awardable_id
]
}
participant
:user
scope
:downvotes
,
->
{
where
(
name:
DOWNVOTE_NAME
)
}
scope
:upvotes
,
->
{
where
(
name:
UPVOTE_NAME
)
}
def
downvote?
self
.
name
==
DOWNVOTE_NAME
end
def
upvote?
self
.
name
==
UPVOTE_NAME
end
def
to_note_json
{
valid:
valid?
,
award:
true
,
id:
id
,
name:
name
}
end
end
app/models/concerns/awardable.rb
0 → 100644
View file @
547888e1
module
Awardable
extend
ActiveSupport
::
Concern
included
do
has_many
:award_emoji
,
as: :awardable
,
dependent: :destroy
if
self
<
Participable
participant
:award_emoji
end
end
module
ClassMethods
def
order_upvotes_desc
order_votes_desc
(
AwardEmoji
::
UPVOTE_NAME
)
end
def
order_downvotes_desc
order_votes_desc
(
AwardEmoji
::
DOWNVOTE_NAME
)
end
def
order_votes_desc
(
emoji_name
)
awardable_table
=
self
.
arel_table
awards_table
=
AwardEmoji
.
arel_table
join_clause
=
awardable_table
.
join
(
awards_table
,
Arel
::
Nodes
::
OuterJoin
).
on
(
awards_table
[
:awardable_id
].
eq
(
awardable_table
[
:id
]).
and
(
awards_table
[
:awardable_type
].
eq
(
self
.
name
).
and
(
awards_table
[
:name
].
eq
(
emoji_name
)
)
)
).
join_sources
joins
(
join_clause
).
group
(
awardable_table
[
:id
]).
reorder
(
"COUNT(award_emoji.id) DESC"
)
end
end
def
grouped_awards
(
with_thumbs
=
true
)
awards
=
award_emoji
.
group_by
(
&
:name
)
if
with_thumbs
awards
[
AwardEmoji
::
UPVOTE_NAME
]
||=
AwardEmoji
.
none
awards
[
AwardEmoji
::
DOWNVOTE_NAME
]
||=
AwardEmoji
.
none
end
awards
end
def
downvotes
award_emoji
.
where
(
name:
AwardEmoji
::
DOWNVOTE_NAME
).
count
end
def
upvotes
award_emoji
.
where
(
name:
AwardEmoji
::
UPVOTE_NAME
).
count
end
def
emoji_awardable?
true
end
def
awarded_emoji?
(
emoji_name
,
current_user
)
award_emoji
.
where
(
name:
emoji_name
,
user:
current_user
).
exists?
end
def
create_award_emoji
(
name
,
current_user
)
return
unless
emoji_awardable?
award_emoji
.
create
(
name:
name
,
user:
current_user
)
end
def
remove_award_emoji
(
name
,
current_user
)
award_emoji
.
where
(
name:
name
,
user:
current_user
).
destroy_all
end
def
toggle_award_emoji
(
emoji_name
,
current_user
)
if
awarded_emoji?
(
emoji_name
,
current_user
)
remove_award_emoji
(
emoji_name
,
current_user
)
else
create_award_emoji
(
emoji_name
,
current_user
)
end
end
end
app/models/concerns/issuable.rb
View file @
547888e1
...
...
@@ -10,6 +10,7 @@ module Issuable
include
Mentionable
include
Subscribable
include
StripAttribute
include
Awardable
included
do
belongs_to
:author
,
class_name:
"User"
...
...
@@ -99,29 +100,6 @@ def sort(method)
order_by
(
method
)
end
end
def
order_downvotes_desc
order_votes_desc
(
'thumbsdown'
)
end
def
order_upvotes_desc
order_votes_desc
(
'thumbsup'
)
end
def
order_votes_desc
(
award_emoji_name
)
issuable_table
=
self
.
arel_table
note_table
=
Note
.
arel_table
join_clause
=
issuable_table
.
join
(
note_table
,
Arel
::
Nodes
::
OuterJoin
).
on
(
note_table
[
:noteable_id
].
eq
(
issuable_table
[
:id
]).
and
(
note_table
[
:noteable_type
].
eq
(
self
.
name
).
and
(
note_table
[
:is_award
].
eq
(
true
).
and
(
note_table
[
:note
].
eq
(
award_emoji_name
))
)
)
).
join_sources
joins
(
join_clause
).
group
(
issuable_table
[
:id
]).
reorder
(
"COUNT(notes.id) DESC"
)
end
end
def
today?
...
...
@@ -144,14 +122,6 @@ def open?
opened?
||
reopened?
end
def
downvotes
notes
.
awards
.
where
(
note:
"thumbsdown"
).
count
end
def
upvotes
notes
.
awards
.
where
(
note:
"thumbsup"
).
count
end
def
subscribed_without_subscriptions?
(
user
)
participants
(
user
).
include?
(
user
)
end
...
...
app/models/merge_request.rb
View file @
547888e1
...
...
@@ -36,6 +36,7 @@ class MergeRequest < ActiveRecord::Base
include
Referable
include
Sortable
include
Taskable
include
Awardable
belongs_to
:target_project
,
foreign_key: :target_project_id
,
class_name:
"Project"
belongs_to
:source_project
,
foreign_key: :source_project_id
,
class_name:
"Project"
...
...
app/models/note.rb
View file @
547888e1
...
...
@@ -16,7 +16,6 @@
# system :boolean default(FALSE), not null
# st_diff :text
# updated_by_id :integer
# is_award :boolean default(FALSE), not null
#
require
'carrierwave/orm/activerecord'
...
...
@@ -43,12 +42,9 @@ class Note < ActiveRecord::Base
delegate
:name
,
to: :project
,
prefix:
true
delegate
:name
,
:email
,
to: :author
,
prefix:
true
before_validation
:set_award!
before_validation
:clear_blank_line_code!
validates
:note
,
:project
,
presence:
true
validates
:note
,
uniqueness:
{
scope:
[
:author
,
:noteable_type
,
:noteable_id
]
},
if:
->
(
n
)
{
n
.
is_award
}
validates
:note
,
inclusion:
{
in:
Emoji
.
emojis_names
},
if:
->
(
n
)
{
n
.
is_award
}
validates
:line_code
,
line_code:
true
,
allow_blank:
true
# Attachments are deprecated and are handled by Markdown uploader
validates
:attachment
,
file_size:
{
maximum: :max_attachment_size
}
...
...
@@ -60,8 +56,6 @@ class Note < ActiveRecord::Base
mount_uploader
:attachment
,
AttachmentUploader
# Scopes
scope
:awards
,
->
{
where
(
is_award:
true
)
}
scope
:nonawards
,
->
{
where
(
is_award:
false
)
}
scope
:for_commit_id
,
->
(
commit_id
)
{
where
(
noteable_type:
"Commit"
,
commit_id:
commit_id
)
}
scope
:inline
,
->
{
where
(
"line_code IS NOT NULL"
)
}
scope
:not_inline
,
->
{
where
(
line_code:
nil
)
}
...
...
@@ -119,19 +113,6 @@ def search(query)
where
(
table
[
:note
].
matches
(
pattern
))
end
def
grouped_awards
notes
=
{}
awards
.
select
(
:note
).
distinct
.
map
do
|
note
|
notes
[
note
.
note
]
=
where
(
note:
note
.
note
)
end
notes
[
"thumbsup"
]
||=
Note
.
none
notes
[
"thumbsdown"
]
||=
Note
.
none
notes
end
end
def
cross_reference?
...
...
@@ -347,37 +328,25 @@ def reset_events_cache
Event
.
reset_event_cache_for
(
self
)
end
def
downvote?
is_award
&&
note
==
"thumbsdown"
end
def
upvote?
is_award
&&
note
==
"thumbsup"
def
system?
read_attribute
(
:system
)
end
def
editable?
!
system
?
&&
!
is_award
!
system
?
end
def
cross_reference_not_visible_for?
(
user
)
cross_reference?
&&
referenced_mentionables
(
user
).
empty?
end
# Checks if note is an award added as a comment
#
# If note is an award, this method sets is_award to true
# and changes content of the note to award name.
#
# Method is executed as a before_validation callback.
#
def
set_award!
return
unless
awards_supported?
&&
contains_emoji_only?
self
.
is_award
=
true
self
.
note
=
award_emoji_name
def
award_emoji?
award_emoji_supported?
&&
contains_emoji_only?
end
private
def
create_award_emoji
self
.
noteable
.
award_emoji
(
award_emoji_name
,
author
)
end
def
clear_blank_line_code!
self
.
line_code
=
nil
if
self
.
line_code
.
blank?
...
...
@@ -389,8 +358,8 @@ def find_noteable_diff
diffs
.
find
{
|
d
|
d
.
new_path
==
self
.
diff
.
new_path
}
end
def
award
s
_supported?
(
for_issue?
||
for_merge_request?
)
&&
!
for_diff_line?
def
award
_emoji
_supported?
noteable
.
is_a?
(
Awardable
)
&&
!
for_diff_line?
end
def
contains_emoji_only?
...
...
@@ -399,6 +368,6 @@ def contains_emoji_only?
def
award_emoji_name
original_name
=
note
.
match
(
Banzai
::
Filter
::
EmojiFilter
.
emoji_pattern
)[
1
]
AwardEmoji
.
normilize_emoji_name
(
original_name
)
Gitlab
::
AwardEmoji
.
normilize_emoji_name
(
original_name
)
end
end
app/models/user.rb
View file @
547888e1
...
...
@@ -144,6 +144,7 @@ class User < ActiveRecord::Base
has_many
:builds
,
dependent: :nullify
,
class_name:
'Ci::Build'
has_many
:todos
,
dependent: :destroy
has_many
:notification_settings
,
dependent: :destroy
has_many
:award_emoji
,
as: :awardable
,
dependent: :destroy
#
# Validations
...
...
app/services/notes/create_service.rb
View file @
547888e1
...
...
@@ -5,6 +5,11 @@ def execute
note
.
author
=
current_user
note
.
system
=
false
if
note
.
award_emoji?
return
ToggleAwardEmojiService
.
new
(
project
,
current_user
,
params
).
execute
(
note
.
noteable
,
note
.
note
)
end
if
note
.
save
# Finish the harder work in the background
NewNoteWorker
.
perform_in
(
2
.
seconds
,
note
.
id
,
params
)
...
...
app/services/notes/post_process_service.rb
View file @
547888e1
...
...
@@ -8,7 +8,7 @@ def initialize(note)
def
execute
# Skip system notes, like status changes and cross-references and awards
unless
@note
.
system
||
@note
.
is_award
unless
@note
.
system
EventCreateService
.
new
.
leave_note
(
@note
,
@note
.
author
)
@note
.
create_cross_references!
execute_note_hooks
...
...
app/services/notification_service.rb
View file @
547888e1
...
...
@@ -131,7 +131,6 @@ def new_note(note)
# ignore gitlab service messages
return
true
if
note
.
note
.
start_with?
(
'Status changed to closed'
)
return
true
if
note
.
cross_reference?
&&
note
.
system
==
true
return
true
if
note
.
is_award
target
=
note
.
noteable
...
...
app/services/todo_service.rb
View file @
547888e1
...
...
@@ -98,6 +98,14 @@ def update_note(note, current_user)
handle_note
(
note
,
current_user
)
end
# When an emoji is awarded we should:
#
# * mark all pending todos related to the awardable for the current user as done
#
def
new_award_emoji
(
awardable
,
current_user
)
mark_pending_todos_as_done
(
awardable
,
current_user
)
end
# When marking pending todos as done we should:
#
# * mark all pending todos related to the target for the current user as done
...
...
app/services/toggle_award_emoji_service.rb
0 → 100644
View file @
547888e1
require_relative
'base_service'
class
ToggleAwardEmojiService
<
BaseService
# For an award emoji being posted we should:
# - Mark the TODO as done for this issuable (skip on snippets)
# - Save the award emoji
def
execute
(
awardable
,
emoji
)
todo_service
.
new_award_emoji
(
awardable
,
current_user
)
# Needed if its posted as a note containing only :+1:
emoji
=
award_emoji_name
(
emoji
)
if
emoji
.
start_with?
':'
awardable
.
toggle_award_emoji
(
emoji
,
current_user
)
end
private
def
award_emoji_name
(
emoji
)
original_name
=
emoji
.
match
(
Banzai
::
Filter
::
EmojiFilter
.
emoji_pattern
)[
1
]
Gitlab
::
AwardEmoji
.
normalize_emoji_name
(
original_name
)
end
end
app/views/award_emoji/_awards_block.html.haml
0 → 100644
View file @
547888e1
-
grouped_awards
=
awardable
.
grouped_awards
(
inline
)
.awards.js-awards-block
{
class:
(
"hidden"
if
!
inline
&&
grouped_emojis
.
size
==
0
),
data:
{
award_url:
url_for
([
:toggle_award_emoji
,
@project
.
namespace
.
becomes
(
Namespace
),
@project
,
awardable
])
}
}
-
awards_sort
(
grouped_awards
).
each
do
|
emoji
,
awards
|
%button
.btn.award-control.js-emoji-btn.has-tooltip
{
type:
"button"
,
class:
(
award_active_class
(
awards
,
current_user
)),
title:
award_user_list
(
awards
,
current_user
),
data:
{
placement:
"bottom"
}
}
=
emoji_icon
(
emoji
)
%span
.award-control-text.js-counter
=
awards
.
count
-
if
current_user
.award-menu-holder.js-award-holder
%button
.btn.award-control.js-add-award
{
type:
"button"
,
data:
{
award_menu_url:
emojis_path
}
}
=
icon
(
'smile-o'
,
{
class:
"award-control-icon award-control-icon-normal"
})
=
icon
(
'spinner spin'
,
{
class:
"award-control-icon award-control-icon-loading"
})
%span
.award-control-text
Add
app/views/emojis/index.html.haml
View file @
547888e1
.emoji-menu
.emoji-menu-content
=
text_field_tag
:emoji_search
,
""
,
class:
"emoji-search search-input form-control"
-
AwardEmoji
.
emoji_by_category
.
each
do
|
category
,
emojis
|
-
Gitlab
::
AwardEmoji
.
emoji_by_category
.
each
do
|
category
,
emojis
|
%h5
.emoji-menu-title
=
AwardEmoji
::
CATEGORIES
[
category
]
=
Gitlab
::
AwardEmoji
::
CATEGORIES
[
category
]
%ul
.clearfix.emoji-menu-list
-
emojis
.
each
do
|
emoji
|
%li
.pull-left.text-center.emoji-menu-list-item
...
...
app/views/projects/issues/_issue.html.haml
View file @
547888e1
...
...
@@ -27,7 +27,7 @@
=
icon
(
'thumbs-down'
)
=
downvotes
-
note_count
=
issue
.
notes
.
user
.
nonawards
.
count
-
note_count
=
issue
.
notes
.
user
.
count
-
if
note_count
>
0
%li
=
link_to
issue_path
(
issue
)
+
"#notes"
do
...
...
Prev
1
2
3
Next
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