award emoji
This commit is contained in:
parent
61867abeec
commit
fd2c0fe446
|
|
@ -0,0 +1,55 @@
|
|||
class @AwardsHandler
|
||||
constructor: (@post_emoji_url, @noteable_type, @noteable_id) ->
|
||||
|
||||
addAward: (emoji) ->
|
||||
@postEmoji emoji, =>
|
||||
if @exist(emoji)
|
||||
if @isActive(emoji)
|
||||
@decrementCounter(emoji)
|
||||
else
|
||||
counter = $(".icon." + emoji).siblings(".counter")
|
||||
counter.text(parseInt(counter.text()) + 1)
|
||||
counter.parent().addClass("active")
|
||||
else
|
||||
@createEmoji(emoji)
|
||||
|
||||
|
||||
exist: (emoji) ->
|
||||
$(".icon").hasClass(emoji)
|
||||
|
||||
isActive: (emoji) ->
|
||||
$(".icon." + emoji).parent().hasClass("active")
|
||||
|
||||
decrementCounter: (emoji) ->
|
||||
counter = $(".icon." + emoji).siblings(".counter")
|
||||
|
||||
if parseInt(counter.text()) > 1
|
||||
counter.text(parseInt(counter.text()) - 1)
|
||||
counter.parent().removeClass("active")
|
||||
else
|
||||
counter.parent().remove()
|
||||
|
||||
|
||||
createEmoji: (emoji) ->
|
||||
nodes = []
|
||||
nodes.push("<div class='award active'>")
|
||||
nodes.push("<div class='icon " + emoji + "'>")
|
||||
nodes.push(@getImage(emoji))
|
||||
nodes.push("</div>")
|
||||
nodes.push("<div class='counter'>1")
|
||||
nodes.push("</div></div>")
|
||||
|
||||
$(".awards").append(nodes.join("\n"))
|
||||
|
||||
getImage: (emoji) ->
|
||||
$("li." + emoji).html()
|
||||
|
||||
postEmoji: (emoji, callback) ->
|
||||
emoji = emoji.replace("emoji-", "")
|
||||
$.post @post_emoji_url, {
|
||||
emoji: emoji
|
||||
noteable_type: @noteable_type
|
||||
noteable_id: @noteable_id
|
||||
},(data) ->
|
||||
if data.ok
|
||||
callback.call()
|
||||
|
|
@ -113,13 +113,16 @@ class @Notes
|
|||
renderNote: (note) ->
|
||||
# render note if it not present in loaded list
|
||||
# or skip if rendered
|
||||
if @isNewNote(note)
|
||||
if @isNewNote(note) && !note.award
|
||||
@note_ids.push(note.id)
|
||||
$('ul.main-notes-list').
|
||||
append(note.html).
|
||||
syntaxHighlight()
|
||||
@initTaskList()
|
||||
|
||||
if note.award
|
||||
awards_handler.addAward("emoji-" + note.note)
|
||||
|
||||
###
|
||||
Check if note does not exists on page
|
||||
###
|
||||
|
|
@ -255,7 +258,6 @@ class @Notes
|
|||
###
|
||||
addNote: (xhr, note, status) =>
|
||||
@renderNote(note)
|
||||
@updateVotes()
|
||||
|
||||
###
|
||||
Called in response to the new note form being submitted
|
||||
|
|
@ -473,9 +475,6 @@ class @Notes
|
|||
form = $(e.target).closest(".js-discussion-note-form")
|
||||
@removeDiscussionNoteForm(form)
|
||||
|
||||
updateVotes: ->
|
||||
true
|
||||
|
||||
###
|
||||
Called after an attachment file has been selected.
|
||||
|
||||
|
|
|
|||
|
|
@ -101,3 +101,45 @@
|
|||
background-color: $background-color;
|
||||
}
|
||||
}
|
||||
|
||||
.awards {
|
||||
.award {
|
||||
border: 1px solid;
|
||||
padding: 1px 3px;
|
||||
width: 50px;
|
||||
border-radius: 5px;
|
||||
float:left;
|
||||
margin: 0 3px;
|
||||
border-color: #ccc;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
border-color: rgba(79,176,252,.4);
|
||||
background-color: rgba(79,176,252,.08);
|
||||
|
||||
.counter {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
#add-award {
|
||||
font-size: 20px;
|
||||
border-radius: 5px;
|
||||
float: left;
|
||||
width: 50px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.awards-menu{
|
||||
li {
|
||||
float: left;
|
||||
margin: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
def show
|
||||
@participants = @issue.participants(current_user)
|
||||
@note = @project.notes.new(noteable: @issue)
|
||||
@notes = @issue.notes.with_associations.fresh
|
||||
@notes = @issue.notes.nonawards.with_associations.fresh
|
||||
@noteable = @issue
|
||||
|
||||
respond_with(@issue)
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
|
||||
# Build a note object for comment form
|
||||
@note = @project.notes.new(noteable: @merge_request)
|
||||
@notes = @merge_request.mr_and_commit_notes.inc_author.fresh
|
||||
@notes = @merge_request.nonawards.mr_and_commit_notes.inc_author.fresh
|
||||
@discussions = Note.discussions_from_notes(@notes)
|
||||
@noteable = @merge_request
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
before_action :find_current_user_notes, except: [:destroy, :delete_attachment, :award_toggle]]
|
||||
|
||||
def index
|
||||
current_fetched_at = Time.now.to_i
|
||||
|
|
@ -58,6 +58,27 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def award_toggle
|
||||
noteable = params[:noteable_type] == "Issue" ? Issue : MergeRequest
|
||||
noteable = noteable.find(params[:noteable_id])
|
||||
data = {
|
||||
noteable: noteable,
|
||||
author: current_user,
|
||||
is_award: true,
|
||||
note: params[:emoji]
|
||||
}
|
||||
|
||||
note = project.notes.find_by(data)
|
||||
|
||||
if note
|
||||
note.destroy
|
||||
else
|
||||
project.notes.create(data)
|
||||
end
|
||||
|
||||
render json: {ok: true}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def note
|
||||
|
|
@ -111,6 +132,8 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
id: note.id,
|
||||
discussion_id: note.discussion_id,
|
||||
html: note_to_html(note),
|
||||
award: note.is_award,
|
||||
note: note.note,
|
||||
discussion_html: note_to_discussion_html(note),
|
||||
discussion_with_diff_html: note_to_discussion_with_diff_html(note)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,11 @@ module IssuesHelper
|
|||
merge_requests.map(&:to_reference).to_sentence(last_word_connector: ', or ')
|
||||
end
|
||||
|
||||
def url_to_emoji(name)
|
||||
emoji_path = "emoji/#{Emoji.emoji_filename(name)}.png"
|
||||
url_to_image(emoji_path)
|
||||
end
|
||||
|
||||
# Required for Gitlab::Markdown::IssueReferenceFilter
|
||||
module_function :url_for_issue
|
||||
end
|
||||
|
|
|
|||
|
|
@ -89,41 +89,6 @@ module Issuable
|
|||
opened? || reopened?
|
||||
end
|
||||
|
||||
#
|
||||
# Votes
|
||||
#
|
||||
|
||||
# Return the number of -1 comments (downvotes)
|
||||
def downvotes
|
||||
filter_superceded_votes(notes.select(&:downvote?), notes).size
|
||||
end
|
||||
|
||||
def downvotes_in_percent
|
||||
if votes_count.zero?
|
||||
0
|
||||
else
|
||||
100.0 - upvotes_in_percent
|
||||
end
|
||||
end
|
||||
|
||||
# Return the number of +1 comments (upvotes)
|
||||
def upvotes
|
||||
filter_superceded_votes(notes.select(&:upvote?), notes).size
|
||||
end
|
||||
|
||||
def upvotes_in_percent
|
||||
if votes_count.zero?
|
||||
0
|
||||
else
|
||||
100.0 / votes_count * upvotes
|
||||
end
|
||||
end
|
||||
|
||||
# Return the total number of votes
|
||||
def votes_count
|
||||
upvotes + downvotes
|
||||
end
|
||||
|
||||
def subscribed?(user)
|
||||
subscription = subscriptions.find_by_user_id(user.id)
|
||||
|
||||
|
|
@ -183,18 +148,4 @@ module Issuable
|
|||
def notes_with_associations
|
||||
notes.includes(:author, :project)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def filter_superceded_votes(votes, notes)
|
||||
filteredvotes = [] + votes
|
||||
|
||||
votes.each do |vote|
|
||||
if vote.superceded?(notes)
|
||||
filteredvotes.delete(vote)
|
||||
end
|
||||
end
|
||||
|
||||
filteredvotes
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ class Note < ActiveRecord::Base
|
|||
mount_uploader :attachment, AttachmentUploader
|
||||
|
||||
# Scopes
|
||||
scope :awards, ->{ where("is_award IS TRUE") }
|
||||
scope :nonawards, ->{ where("is_award IS 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, '']) }
|
||||
|
|
@ -97,6 +99,12 @@ class Note < ActiveRecord::Base
|
|||
def search(query)
|
||||
where("LOWER(note) like :query", query: "%#{query.downcase}%")
|
||||
end
|
||||
|
||||
def grouped_awards
|
||||
select(:note).distinct.map do |note|
|
||||
[ note.note, where(note: note.note) ]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def cross_reference?
|
||||
|
|
@ -288,44 +296,6 @@ class Note < ActiveRecord::Base
|
|||
nil
|
||||
end
|
||||
|
||||
DOWNVOTES = %w(-1 :-1: :thumbsdown: :thumbs_down_sign:)
|
||||
|
||||
# Check if the note is a downvote
|
||||
def downvote?
|
||||
votable? && note.start_with?(*DOWNVOTES)
|
||||
end
|
||||
|
||||
UPVOTES = %w(+1 :+1: :thumbsup: :thumbs_up_sign:)
|
||||
|
||||
# Check if the note is an upvote
|
||||
def upvote?
|
||||
votable? && note.start_with?(*UPVOTES)
|
||||
end
|
||||
|
||||
def superceded?(notes)
|
||||
return false unless vote?
|
||||
|
||||
notes.each do |note|
|
||||
next if note == self
|
||||
|
||||
if note.vote? &&
|
||||
self[:author_id] == note[:author_id] &&
|
||||
self[:created_at] <= note[:created_at]
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def vote?
|
||||
upvote? || downvote?
|
||||
end
|
||||
|
||||
def votable?
|
||||
for_issue? || (for_merge_request? && !for_diff_line?)
|
||||
end
|
||||
|
||||
# Mentionable override.
|
||||
def gfm_reference(from_project = nil)
|
||||
noteable.gfm_reference(from_project)
|
||||
|
|
|
|||
|
|
@ -5,11 +5,16 @@ module Notes
|
|||
note.author = current_user
|
||||
note.system = false
|
||||
|
||||
if contains_emoji_only?(params[:note])
|
||||
note.is_award = true
|
||||
note.note = emoji_name(params[:note])
|
||||
end
|
||||
|
||||
if note.save
|
||||
notification_service.new_note(note)
|
||||
|
||||
# Skip system notes, like status changes and cross-references.
|
||||
unless note.system
|
||||
# Skip system notes, like status changes and cross-references and awards
|
||||
unless note.system || note.is_award
|
||||
event_service.leave_note(note, note.author)
|
||||
note.create_cross_references!
|
||||
execute_hooks(note)
|
||||
|
|
@ -28,5 +33,13 @@ module Notes
|
|||
note.project.execute_hooks(note_data, :note_hooks)
|
||||
note.project.execute_services(note_data, :note_hooks)
|
||||
end
|
||||
|
||||
def contains_emoji_only?(note)
|
||||
note =~ /^:[-_+[:alnum:]]*:\s?/
|
||||
end
|
||||
|
||||
def emoji_name(note)
|
||||
note.match(/\A:([-_+[:alnum:]]*):\s?/)[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ class NotificationService
|
|||
# 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
|
||||
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@
|
|||
|
||||
.issue-info
|
||||
= "#{issue.to_reference} opened #{time_ago_with_tooltip(issue.created_at, placement: 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe
|
||||
- if issue.votes_count > 0
|
||||
= render 'votes/votes_inline', votable: issue
|
||||
- if issue.milestone
|
||||
|
||||
%span
|
||||
|
|
|
|||
|
|
@ -34,8 +34,6 @@
|
|||
|
||||
.merge-request-info
|
||||
= "##{merge_request.iid} opened #{time_ago_with_tooltip(merge_request.created_at, placement: 'bottom')} by #{link_to_member(@project, merge_request.author, avatar: false)}".html_safe
|
||||
- if merge_request.votes_count > 0
|
||||
= render 'votes/votes_inline', votable: merge_request
|
||||
- if merge_request.milestone_id?
|
||||
|
||||
%span
|
||||
|
|
|
|||
|
|
@ -35,26 +35,6 @@
|
|||
- if note.updated_by && note.updated_by != note.author
|
||||
by #{link_to_member(note.project, note.updated_by, avatar: false, author_class: nil)}
|
||||
|
||||
- if note.superceded?(@notes)
|
||||
- if note.upvote?
|
||||
%span.vote.upvote.label.label-gray.strikethrough
|
||||
= icon('thumbs-up')
|
||||
\+1
|
||||
- if note.downvote?
|
||||
%span.vote.downvote.label.label-gray.strikethrough
|
||||
= icon('thumbs-down')
|
||||
\-1
|
||||
- else
|
||||
- if note.upvote?
|
||||
%span.vote.upvote.label.label-success
|
||||
= icon('thumbs-up')
|
||||
\+1
|
||||
- if note.downvote?
|
||||
%span.vote.downvote.label.label-danger
|
||||
= icon('thumbs-down')
|
||||
\-1
|
||||
|
||||
|
||||
.note-body{class: note_editable?(note) ? 'js-task-list-container' : ''}
|
||||
.note-text
|
||||
= preserve do
|
||||
|
|
|
|||
|
|
@ -1,10 +1,33 @@
|
|||
.votes.votes-block
|
||||
.btn-group
|
||||
- unless votable.upvotes.zero?
|
||||
.btn.btn-sm.disabled.cgreen
|
||||
%i.fa.fa-thumbs-up
|
||||
= votable.upvotes
|
||||
- unless votable.downvotes.zero?
|
||||
.btn.btn-sm.disabled.cred
|
||||
%i.fa.fa-thumbs-down
|
||||
= votable.downvotes
|
||||
.awards.votes-block
|
||||
- votable.notes.awards.grouped_awards.each do | vote |
|
||||
.award{class: ("active" if vote.last.pluck(:author_id).include?(current_user.id))}
|
||||
.icon{class: "emoji-#{vote.first}"}
|
||||
= image_tag url_to_emoji(vote.first), height: "20px", width: "20px"
|
||||
.counter
|
||||
= vote.last.count
|
||||
|
||||
%button.dropdown
|
||||
%a#add-award{"data-toggle" => "dropdown", "data-target" => "#", "href" => "#"} +
|
||||
%ul.dropdown-menu.awards-menu
|
||||
- ["100", "blush", "heart", "smile", "rage", "beers", "thumbsup", "disappointed", "ok_hand", "helicopter"].each do |emoji|
|
||||
%li{class: "emoji-#{emoji}"}= image_tag url_to_emoji(emoji), height: "20px", width: "20px"
|
||||
|
||||
|
||||
:coffeescript
|
||||
post_emoji_url = "#{award_toggle_namespace_project_notes_path(@project.namespace, @project)}"
|
||||
noteable_type = "Issue"
|
||||
noteable_id = #{@issue.id}
|
||||
awards_handler = new AwardsHandler(post_emoji_url, noteable_type, noteable_id)
|
||||
|
||||
$ ->
|
||||
$(".awards-menu li").click (e)->
|
||||
emoji = $(this).attr("class")
|
||||
awards_handler.addAward(emoji)
|
||||
|
||||
$(".awards").on "click", ".award", (e)->
|
||||
emoji = /(emoji-\S*)/.exec($(this).find(".icon").attr("class"))[0]
|
||||
awards_handler.addAward(emoji)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
.votes.votes-inline
|
||||
- unless votable.upvotes.zero?
|
||||
%span.upvotes.cgreen
|
||||
+ #{votable.upvotes}
|
||||
- unless votable.downvotes.zero?
|
||||
\/
|
||||
- unless votable.downvotes.zero?
|
||||
%span.downvotes.cred
|
||||
\- #{votable.downvotes}
|
||||
|
|
@ -664,6 +664,10 @@ Gitlab::Application.routes.draw do
|
|||
member do
|
||||
delete :delete_attachment
|
||||
end
|
||||
|
||||
collection do
|
||||
post :award_toggle
|
||||
end
|
||||
end
|
||||
|
||||
resources :uploads, only: [:create] do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
class AddIsAwardToNotes < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :notes, :is_award, :boolean, default: false
|
||||
end
|
||||
end
|
||||
|
|
@ -531,7 +531,7 @@ ActiveRecord::Schema.define(version: 20151116144118) do
|
|||
t.string "type"
|
||||
t.string "description", default: "", null: false
|
||||
t.string "avatar"
|
||||
t.boolean "public", default: false
|
||||
t.boolean "visible", default: false
|
||||
end
|
||||
|
||||
add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree
|
||||
|
|
@ -554,6 +554,7 @@ ActiveRecord::Schema.define(version: 20151116144118) do
|
|||
t.boolean "system", default: false, null: false
|
||||
t.text "st_diff"
|
||||
t.integer "updated_by_id"
|
||||
t.boolean "is_award", default: false
|
||||
end
|
||||
|
||||
add_index "notes", ["author_id"], name: "index_notes_on_author_id", using: :btree
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ Parameters:
|
|||
"project_id": 3,
|
||||
"title": "test1",
|
||||
"state": "opened",
|
||||
"upvotes": 0,
|
||||
"downvotes": 0,
|
||||
"author": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
|
|
@ -77,8 +75,6 @@ Parameters:
|
|||
"project_id": 3,
|
||||
"title": "test1",
|
||||
"state": "merged",
|
||||
"upvotes": 0,
|
||||
"downvotes": 0,
|
||||
"author": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
|
|
@ -126,8 +122,6 @@ Parameters:
|
|||
"updated_at": "2015-02-02T20:08:49.959Z",
|
||||
"target_branch": "secret_token",
|
||||
"source_branch": "version-1-9",
|
||||
"upvotes": 0,
|
||||
"downvotes": 0,
|
||||
"author": {
|
||||
"name": "Chad Hamill",
|
||||
"username": "jarrett",
|
||||
|
|
@ -198,8 +192,6 @@ Parameters:
|
|||
"project_id": 3,
|
||||
"title": "test1",
|
||||
"state": "opened",
|
||||
"upvotes": 0,
|
||||
"downvotes": 0,
|
||||
"author": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
|
|
@ -250,8 +242,6 @@ Parameters:
|
|||
"title": "test1",
|
||||
"description": "description1",
|
||||
"state": "opened",
|
||||
"upvotes": 0,
|
||||
"downvotes": 0,
|
||||
"author": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
|
|
@ -304,8 +294,6 @@ Parameters:
|
|||
"project_id": 3,
|
||||
"title": "test1",
|
||||
"state": "merged",
|
||||
"upvotes": 0,
|
||||
"downvotes": 0,
|
||||
"author": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
|
|
|
|||
|
|
@ -32,9 +32,7 @@ Parameters:
|
|||
"created_at": "2013-09-30T13:46:01Z"
|
||||
},
|
||||
"created_at": "2013-10-02T09:22:45Z",
|
||||
"system": true,
|
||||
"upvote": false,
|
||||
"downvote": false
|
||||
"system": true
|
||||
},
|
||||
{
|
||||
"id": 305,
|
||||
|
|
@ -49,9 +47,7 @@ Parameters:
|
|||
"created_at": "2013-09-30T13:46:01Z"
|
||||
},
|
||||
"created_at": "2013-10-02T09:56:03Z",
|
||||
"system": false,
|
||||
"upvote": false,
|
||||
"downvote": false
|
||||
"system": false
|
||||
}
|
||||
]
|
||||
```
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ module API
|
|||
end
|
||||
|
||||
class MergeRequest < ProjectEntity
|
||||
expose :target_branch, :source_branch, :upvotes, :downvotes
|
||||
expose :target_branch, :source_branch
|
||||
expose :author, :assignee, using: Entities::UserBasic
|
||||
expose :source_project_id, :target_project_id
|
||||
expose :label_names, as: :labels
|
||||
|
|
@ -192,8 +192,6 @@ module API
|
|||
expose :author, using: Entities::UserBasic
|
||||
expose :created_at
|
||||
expose :system?, as: :system
|
||||
expose :upvote?, as: :upvote
|
||||
expose :downvote?, as: :downvote
|
||||
end
|
||||
|
||||
class MRNote < Grape::Entity
|
||||
|
|
|
|||
|
|
@ -1,188 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Issue, 'Votes' do
|
||||
let(:issue) { create(:issue) }
|
||||
|
||||
describe "#upvotes" do
|
||||
it "with no notes has a 0/0 score" do
|
||||
expect(issue.upvotes).to eq(0)
|
||||
end
|
||||
|
||||
it "should recognize non-+1 notes" do
|
||||
add_note "No +1 here"
|
||||
expect(issue.notes.size).to eq(1)
|
||||
expect(issue.notes.first.upvote?).to be_falsey
|
||||
expect(issue.upvotes).to eq(0)
|
||||
end
|
||||
|
||||
it "should recognize a single +1 note" do
|
||||
add_note "+1 This is awesome"
|
||||
expect(issue.upvotes).to eq(1)
|
||||
end
|
||||
|
||||
it 'should recognize multiple +1 notes' do
|
||||
add_note '+1 This is awesome', create(:user)
|
||||
add_note '+1 I want this', create(:user)
|
||||
expect(issue.upvotes).to eq(2)
|
||||
end
|
||||
|
||||
it 'should not count 2 +1 votes from the same user' do
|
||||
add_note '+1 This is awesome'
|
||||
add_note '+1 I want this'
|
||||
expect(issue.upvotes).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#downvotes" do
|
||||
it "with no notes has a 0/0 score" do
|
||||
expect(issue.downvotes).to eq(0)
|
||||
end
|
||||
|
||||
it "should recognize non--1 notes" do
|
||||
add_note "Almost got a -1"
|
||||
expect(issue.notes.size).to eq(1)
|
||||
expect(issue.notes.first.downvote?).to be_falsey
|
||||
expect(issue.downvotes).to eq(0)
|
||||
end
|
||||
|
||||
it "should recognize a single -1 note" do
|
||||
add_note "-1 This is bad"
|
||||
expect(issue.downvotes).to eq(1)
|
||||
end
|
||||
|
||||
it "should recognize multiple -1 notes" do
|
||||
add_note('-1 This is bad', create(:user))
|
||||
add_note('-1 Away with this', create(:user))
|
||||
expect(issue.downvotes).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#votes_count" do
|
||||
it "with no notes has a 0/0 score" do
|
||||
expect(issue.votes_count).to eq(0)
|
||||
end
|
||||
|
||||
it "should recognize non notes" do
|
||||
add_note "No +1 here"
|
||||
expect(issue.notes.size).to eq(1)
|
||||
expect(issue.votes_count).to eq(0)
|
||||
end
|
||||
|
||||
it "should recognize a single +1 note" do
|
||||
add_note "+1 This is awesome"
|
||||
expect(issue.votes_count).to eq(1)
|
||||
end
|
||||
|
||||
it "should recognize a single -1 note" do
|
||||
add_note "-1 This is bad"
|
||||
expect(issue.votes_count).to eq(1)
|
||||
end
|
||||
|
||||
it "should recognize multiple notes" do
|
||||
add_note('+1 This is awesome', create(:user))
|
||||
add_note('-1 This is bad', create(:user))
|
||||
add_note('+1 I want this', create(:user))
|
||||
expect(issue.votes_count).to eq(3)
|
||||
end
|
||||
|
||||
it 'should not count 2 -1 votes from the same user' do
|
||||
add_note '-1 This is suspicious'
|
||||
add_note '-1 This is bad'
|
||||
expect(issue.votes_count).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#upvotes_in_percent" do
|
||||
it "with no notes has a 0% score" do
|
||||
expect(issue.upvotes_in_percent).to eq(0)
|
||||
end
|
||||
|
||||
it "should count a single 1 note as 100%" do
|
||||
add_note "+1 This is awesome"
|
||||
expect(issue.upvotes_in_percent).to eq(100)
|
||||
end
|
||||
|
||||
it 'should count multiple +1 notes as 100%' do
|
||||
add_note('+1 This is awesome', create(:user))
|
||||
add_note('+1 I want this', create(:user))
|
||||
expect(issue.upvotes_in_percent).to eq(100)
|
||||
end
|
||||
|
||||
it 'should count fractions for multiple +1 and -1 notes correctly' do
|
||||
add_note('+1 This is awesome', create(:user))
|
||||
add_note('+1 I want this', create(:user))
|
||||
add_note('-1 This is bad', create(:user))
|
||||
add_note('+1 me too', create(:user))
|
||||
expect(issue.upvotes_in_percent).to eq(75)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#downvotes_in_percent" do
|
||||
it "with no notes has a 0% score" do
|
||||
expect(issue.downvotes_in_percent).to eq(0)
|
||||
end
|
||||
|
||||
it "should count a single -1 note as 100%" do
|
||||
add_note "-1 This is bad"
|
||||
expect(issue.downvotes_in_percent).to eq(100)
|
||||
end
|
||||
|
||||
it 'should count multiple -1 notes as 100%' do
|
||||
add_note('-1 This is bad', create(:user))
|
||||
add_note('-1 Away with this', create(:user))
|
||||
expect(issue.downvotes_in_percent).to eq(100)
|
||||
end
|
||||
|
||||
it 'should count fractions for multiple +1 and -1 notes correctly' do
|
||||
add_note('+1 This is awesome', create(:user))
|
||||
add_note('+1 I want this', create(:user))
|
||||
add_note('-1 This is bad', create(:user))
|
||||
add_note('+1 me too', create(:user))
|
||||
expect(issue.downvotes_in_percent).to eq(25)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#filter_superceded_votes' do
|
||||
|
||||
it 'should count a users vote only once amongst multiple votes' do
|
||||
add_note('-1 This needs work before I will accept it')
|
||||
add_note('+1 I want this', create(:user))
|
||||
add_note('+1 This is is awesome', create(:user))
|
||||
add_note('+1 this looks good now')
|
||||
add_note('+1 This is awesome', create(:user))
|
||||
add_note('+1 me too', create(:user))
|
||||
expect(issue.downvotes).to eq(0)
|
||||
expect(issue.upvotes).to eq(5)
|
||||
end
|
||||
|
||||
it 'should count each users vote only once' do
|
||||
add_note '-1 This needs work before it will be accepted'
|
||||
add_note '+1 I like this'
|
||||
add_note '+1 I still like this'
|
||||
add_note '+1 I really like this'
|
||||
add_note '+1 Give me this now!!!!'
|
||||
expect(issue.downvotes).to eq(0)
|
||||
expect(issue.upvotes).to eq(1)
|
||||
end
|
||||
|
||||
it 'should count a users vote only once without caring about comments' do
|
||||
add_note '-1 This needs work before it will be accepted'
|
||||
add_note 'Comment 1'
|
||||
add_note 'Another comment'
|
||||
add_note '+1 vote'
|
||||
add_note 'final comment'
|
||||
expect(issue.downvotes).to eq(0)
|
||||
expect(issue.upvotes).to eq(1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def add_note(text, author = issue.author)
|
||||
created_at = Time.now - 1.hour + Note.count.seconds
|
||||
issue.notes << create(:note,
|
||||
note: text,
|
||||
project: issue.project,
|
||||
author_id: author.id,
|
||||
created_at: created_at)
|
||||
end
|
||||
end
|
||||
|
|
@ -345,17 +345,6 @@ describe Project do
|
|||
expect(project1.star_count).to eq(0)
|
||||
expect(project2.star_count).to eq(0)
|
||||
end
|
||||
|
||||
it 'is decremented when an upvoter account is deleted' do
|
||||
user = create :user
|
||||
project = create :project, :public
|
||||
user.toggle_star(project)
|
||||
project.reload
|
||||
expect(project.star_count).to eq(1)
|
||||
user.destroy
|
||||
project.reload
|
||||
expect(project.star_count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
describe :avatar_type do
|
||||
|
|
|
|||
Loading…
Reference in New Issue