# frozen_string_literal: true module Decidim module Comments # A command with all the business logic to upvote a comment class VoteComment < Decidim::Command # Public: Initializes the command. # # comment - A comment # author - A user # options - An optional hash of options (default: { weight: 1 }) # * weight: The vote's weight. Valid values 1 and -1. def initialize(comment, author, options = { weight: 1 }) @comment = comment @author = author @weight = options[:weight] end # Executes the command. Broadcasts these events: # # - :ok when everything is valid. # - :invalid if the vote was not create # # Returns nothing. def call case @weight when 1 previous_vote = @comment.up_votes.find_by(author: @author) if previous_vote previous_vote.destroy! else @vote = @comment.up_votes.create!(author: @author) end when -1 previous_vote = @comment.down_votes.find_by(author: @author) if previous_vote previous_vote.destroy! else @vote = @comment.down_votes.create!(author: @author) end else return broadcast(:invalid) end notify_comment_author if @vote broadcast(:ok, @comment) rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique broadcast(:invalid) end def notify_comment_author Decidim::EventsManager.publish( event: "decidim.events.comments.comment_#{upvote? ? "upvoted" : "downvoted"}", event_class: upvote? ? Decidim::Comments::CommentUpvotedEvent : Decidim::Comments::CommentDownvotedEvent, resource: @comment.commentable, affected_users: [@comment.author], extra: { comment_id: @comment.id, weight: @weight, downvotes: @comment.down_votes.count, upvotes: @comment.up_votes.count } ) end private def upvote? @weight.positive? end end end end