issuable.rb 3.07 KB
Newer Older
1
# == Issuable concern
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
2
#
3
# Contains common functionality shared between Issues and MergeRequests
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
4 5 6
#
# Used by Issue, MergeRequest
#
7
module Issuable
8
  extend ActiveSupport::Concern
9
  include Mentionable
10 11

  included do
12 13
    belongs_to :author, class_name: "User"
    belongs_to :assignee, class_name: "User"
14
    belongs_to :milestone
15
    has_many :notes, as: :noteable, dependent: :destroy
16

Andrey Kumanyaev's avatar
Andrey Kumanyaev committed
17 18
    validates :author, presence: true
    validates :title, presence: true, length: { within: 0..255 }
19

20
    scope :authored, ->(user) { where(author_id: user) }
21
    scope :assigned_to, ->(u) { where(assignee_id: u.id)}
Andrew8xx8's avatar
Andrew8xx8 committed
22
    scope :recent, -> { order("created_at DESC") }
23 24
    scope :assigned, -> { where("assignee_id IS NOT NULL") }
    scope :unassigned, -> { where("assignee_id IS NULL") }
25
    scope :of_projects, ->(ids) { where(project_id: ids) }
26 27
    scope :opened, -> { with_state(:opened, :reopened) }
    scope :closed, -> { with_state(:closed) }
28

29 30
    delegate :name,
             :email,
31 32
             to: :author,
             prefix: true
33 34 35

    delegate :name,
             :email,
36 37 38
             to: :assignee,
             allow_nil: true,
             prefix: true
39

40
    attr_mentionable :title, :description
41 42
  end

43 44
  module ClassMethods
    def search(query)
45
      where("title like :query", query: "%#{query}%")
46
    end
47 48 49

    def sort(method)
      case method.to_s
50 51 52 53
      when 'newest' then reorder("#{table_name}.created_at DESC")
      when 'oldest' then reorder("#{table_name}.created_at ASC")
      when 'recently_updated' then reorder("#{table_name}.updated_at DESC")
      when 'last_updated' then reorder("#{table_name}.updated_at ASC")
54 55
      when 'milestone_due_soon' then joins(:milestone).reorder("milestones.due_date ASC")
      when 'milestone_due_later' then joins(:milestone).reorder("milestones.due_date DESC")
56
      else reorder("#{table_name}.created_at DESC")
57 58
      end
    end
59 60 61 62 63 64 65 66 67
  end

  def today?
    Date.today == created_at.to_date
  end

  def new?
    today? && created_at == updated_at
  end
68 69 70 71 72 73 74 75 76

  def is_assigned?
    !!assignee_id
  end

  def is_being_reassigned?
    assignee_id_changed?
  end

77 78 79 80 81 82 83
  #
  # Votes
  #

  # Return the number of -1 comments (downvotes)
  def downvotes
    notes.select(&:downvote?).size
84 85
  end

86
  def downvotes_in_percent
87 88 89
    if votes_count.zero?
      0
    else
90
      100.0 - upvotes_in_percent
91 92 93
    end
  end

94 95 96
  # Return the number of +1 comments (upvotes)
  def upvotes
    notes.select(&:upvote?).size
97 98
  end

99
  def upvotes_in_percent
100 101 102
    if votes_count.zero?
      0
    else
103
      100.0 / votes_count * upvotes
104 105 106 107 108 109 110
    end
  end

  # Return the total number of votes
  def votes_count
    upvotes + downvotes
  end
111 112 113 114 115 116 117 118 119 120 121 122 123 124

  # Return all users participating on the discussion
  def participants
    users = []
    users << author
    users << assignee if is_assigned?
    mentions = []
    mentions << self.mentioned_users
    notes.each do |note|
      users << note.author
      mentions << note.mentioned_users
    end
    users.concat(mentions.reduce([], :|)).uniq
  end
125 126 127 128 129 130 131

  def to_hook_data
    {
      object_kind: self.class.name.underscore,
      object_attributes: self.attributes
    }
  end
132
end