1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
# == Issuable concern
#
# Contains common functionality shared between Issues and MergeRequests
#
# Used by Issue, MergeRequest
#
module Issuable
extend ActiveSupport::Concern
include Mentionable
included do
belongs_to :author, class_name: "User"
belongs_to :assignee, class_name: "User"
belongs_to :milestone
has_many :notes, as: :noteable, dependent: :destroy
has_many :label_links, as: :target, dependent: :destroy
has_many :labels, through: :label_links
validates :author, presence: true
validates :title, presence: true, length: { within: 0..255 }
scope :authored, ->(user) { where(author_id: user) }
scope :assigned_to, ->(u) { where(assignee_id: u.id)}
scope :recent, -> { order("created_at DESC") }
scope :assigned, -> { where("assignee_id IS NOT NULL") }
scope :unassigned, -> { where("assignee_id IS NULL") }
scope :of_projects, ->(ids) { where(project_id: ids) }
scope :opened, -> { with_state(:opened, :reopened) }
scope :only_opened, -> { with_state(:opened) }
scope :only_reopened, -> { with_state(:reopened) }
scope :closed, -> { with_state(:closed) }
delegate :name,
:email,
to: :author,
prefix: true
delegate :name,
:email,
to: :assignee,
allow_nil: true,
prefix: true
attr_mentionable :title, :description
end
module ClassMethods
def search(query)
where("LOWER(title) like :query", query: "%#{query.downcase}%")
end
def full_search(query)
where("LOWER(title) like :query OR LOWER(description) like :query", query: "%#{query.downcase}%")
end
def sort(method)
case method.to_s
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")
when 'milestone_due_soon' then joins(:milestone).reorder("milestones.due_date ASC")
when 'milestone_due_later' then joins(:milestone).reorder("milestones.due_date DESC")
else reorder("#{table_name}.created_at DESC")
end
end
end
def today?
Date.today == created_at.to_date
end
def new?
today? && created_at == updated_at
end
def is_assigned?
!!assignee_id
end
def is_being_reassigned?
assignee_id_changed?
end
#
# Votes
#
# Return the number of -1 comments (downvotes)
def downvotes
notes.select(&:downvote?).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
notes.select(&:upvote?).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
# 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
def to_hook_data(user)
{
object_kind: self.class.name.underscore,
user: user.hook_attrs,
object_attributes: hook_attrs
}
end
def label_names
labels.order('title ASC').pluck(:title)
end
def remove_labels
labels.delete_all
end
def add_labels_by_names(label_names)
label_names.each do |label_name|
label = project.labels.create_with(
color: Label::DEFAULT_COLOR).find_or_create_by(title: label_name.strip)
self.labels << label
end
end
end
|