Class: Ticket

Inherits:
ActiveRecord::Base
  • Object
show all
Extended by:
Nosync
Defined in:
app/models/ticket.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Nosync

nosync, nosync=, nosync?

Class Method Details

.bugsObject



76
77
78
# File 'app/models/ticket.rb', line 76

def bugs
  where(type: %w{Bug Chore})
end

.closedObject



97
98
99
# File 'app/models/ticket.rb', line 97

def closed
  where(arel_table[:closed_at].not_eq(nil))
end

.closed_before(time) ⇒ Object



105
106
107
# File 'app/models/ticket.rb', line 105

def closed_before(time)
  where(arel_table[:closed_at].lt(time)).reorder(arel_table[:closed_at].desc)
end

.closed_on(date) ⇒ Object



109
110
111
# File 'app/models/ticket.rb', line 109

def closed_on(date)
  where(closed_at: date.to_time.beginning_of_day..date.to_time.end_of_day)
end

.created_before(time) ⇒ Object



101
102
103
# File 'app/models/ticket.rb', line 101

def created_before(time)
  where(arel_table[:created_at].lt(time)).reorder(arel_table[:created_at].desc)
end

.deployedObject



113
114
115
# File 'app/models/ticket.rb', line 113

def deployed
  where(arel_table[:deployment].not_eq(nil))
end

.deployed_to(environment) ⇒ Object



117
118
119
# File 'app/models/ticket.rb', line 117

def deployed_to(environment)
  where(deployment: environment)
end

.estimatedObject



125
126
127
128
# File 'app/models/ticket.rb', line 125

def estimated
  # !todo: will change: must be defined in terms of tasks
  where("NULLIF(tickets.extended_attributes->'estimated_effort', '')::numeric > 0")
end

.fixedObject



88
89
90
# File 'app/models/ticket.rb', line 88

def fixed
  where(resolution: "fixed")
end

.for_projects(*projects) ⇒ Object Also known as: for_project



46
47
48
49
# File 'app/models/ticket.rb', line 46

def for_projects(*projects)
  ids = projects.flatten.map { |project| project.is_a?(Project) ? project.id : project }
  where(project_id: ids)
end

.ideasObject



72
73
74
# File 'app/models/ticket.rb', line 72

def ideas
  where(type: %w{Feature Enhancement})
end

.mentioned_by_commits(*commits) ⇒ Object



52
53
54
55
56
57
58
# File 'app/models/ticket.rb', line 52

def mentioned_by_commits(*commits)
  ids = commits.flatten.map { |commit| commit.is_a?(Commit) ? commit.id : commit }
  commits_tickets = Arel::Table.new("commits_tickets")
  where arel_table[:id].in(commits_tickets
    .where(commits_tickets[:commit_id].in(ids))
    .project(commits_tickets[:ticket_id]))
end

.not_numbered(*numbers) ⇒ Object



68
69
70
# File 'app/models/ticket.rb', line 68

def not_numbered(*numbers)
  where(arel_table[:number].not_in(numbers.flatten.map(&:to_i)))
end

.numbered(*numbers) ⇒ Object



60
61
62
# File 'app/models/ticket.rb', line 60

def numbered(*numbers)
  where(number: numbers.flatten.map(&:to_i))
end

.resolve_all!Object



135
136
137
138
139
140
141
142
# File 'app/models/ticket.rb', line 135

def resolve_all!
  return unless Rails.env.production?
  all.parallel.each do |ticket|
    Houston.try 3, exceptions_matching(/connection reset by peer/i) do
      ticket.resolve!
    end
  end
end

.resolvedObject



84
85
86
# File 'app/models/ticket.rb', line 84

def resolved
  where(arel_table[:resolution].not_eq(""))
end

.unclosedObject Also known as: open



92
93
94
# File 'app/models/ticket.rb', line 92

def unclosed
  where(closed_at: nil)
end

.unestimatedObject



130
131
132
133
# File 'app/models/ticket.rb', line 130

def unestimated
  # !todo: will change: must be defined in terms of tasks
  where("NOT defined(tickets.extended_attributes, 'estimated_effort') OR NULLIF(tickets.extended_attributes->'estimated_effort', '')::numeric <= 0")
end

.unreleasedObject



121
122
123
# File 'app/models/ticket.rb', line 121

def unreleased
  where(arel_table[:deployment].not_eq("Production"))
end

.unresolvedObject



80
81
82
# File 'app/models/ticket.rb', line 80

def unresolved
  unclosed.where(resolution: "")
end

.without(tickets) ⇒ Object



64
65
66
# File 'app/models/ticket.rb', line 64

def without(tickets)
  not_numbered(tickets.map(&:number))
end

Instance Method Details

#antecedentsObject



204
205
206
# File 'app/models/ticket.rb', line 204

def antecedents
  (super || []).map { |s| TicketAntecedent.from_s(self, s) }
end

#antecedents=(antecedents) ⇒ Object



208
209
210
# File 'app/models/ticket.rb', line 208

def antecedents=(antecedents)
  super Array(antecedents).map(&:to_s)
end

#close!Object



264
265
266
267
# File 'app/models/ticket.rb', line 264

def close!
  remote_ticket.close! if remote_ticket
  update_attribute :closed_at, Time.now
end

#closed?Boolean

Returns:

  • (Boolean)


190
191
192
# File 'app/models/ticket.rb', line 190

def closed?
  closed_at.present?
end

#commit_timeObject



230
231
232
# File 'app/models/ticket.rb', line 230

def commit_time
  @commit_time ||= commits.map(&:committer_hours).compact.sum
end

#committersObject



166
167
168
# File 'app/models/ticket.rb', line 166

def committers
  commits.map { |commit| TicketCommitter.new(commit.committer, commit.committer_email) }.uniq
end

#create_comment!(comment) ⇒ Object



240
241
242
# File 'app/models/ticket.rb', line 240

def create_comment!(comment)
  remote.create_comment!(comment) if remote.respond_to?(:create_comment!)
end

#destroy_comment!(comment) ⇒ Object



248
249
250
# File 'app/models/ticket.rb', line 248

def destroy_comment!(comment)
  remote.destroy_comment!(comment) if remote.respond_to?(:destroy_comment!)
end

#due_dateObject



148
149
150
# File 'app/models/ticket.rb', line 148

def due_date
  extended_attributes["due_date"]
end

#due_date=(value) ⇒ Object



152
153
154
155
# File 'app/models/ticket.rb', line 152

def due_date=(value)
  extended_attributes["due_date"] = value
  extended_attributes_will_change!
end

#effortObject



234
235
236
# File 'app/models/ticket.rb', line 234

def effort
  @effort ||= tasks.map(&:effort).sum
end

#extended_attributesObject



224
225
226
# File 'app/models/ticket.rb', line 224

def extended_attributes
  super || (self.extended_attributes = {})
end

#in_development?Boolean

Returns:

  • (Boolean)


194
195
196
# File 'app/models/ticket.rb', line 194

def in_development?
  deployment.blank?
end

#open?Boolean

Returns:

  • (Boolean)


186
187
188
# File 'app/models/ticket.rb', line 186

def open?
  closed_at.nil?
end

#participantsObject



296
297
298
299
300
301
302
303
304
# File 'app/models/ticket.rb', line 296

def participants
  @participants ||= begin              # Participants in a Ticket include:
    User.unretired.where(id:           #
      Array(reporter_id) +             #   - its reporter
      testing_notes.pluck(:user_id) +  #   - anyone who has commented on it
      releases.pluck(:user_id)) +      #   - anyone who has released it
      committers                       #   - anyone who has comitted to it
  end                                  #
end

#released!(release) ⇒ Object



254
255
256
257
# File 'app/models/ticket.rb', line 254

def released!(release)
  cache_release_attributes(release)
  Houston.observer.fire "ticket:release", self, release
end

#reopen!Object



274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'app/models/ticket.rb', line 274

def reopen!
  return unless resolved?
  remote_ticket.reopen! if remote_ticket

  update_attributes(
    resolution: "",
    closed_at: nil,
    reopened_at: Time.now, # <-- !todo: get rid of this after introducing tasks

    deployment: nil, # <-- !todo: is this necessary?
    first_release_at: nil,
    last_release_at: nil)
end

#reporter_email=(value) ⇒ Object



159
160
161
162
# File 'app/models/ticket.rb', line 159

def reporter_email=(value)
  value = value.downcase if value
  super(value)
end

#resolve!Object



259
260
261
262
# File 'app/models/ticket.rb', line 259

def resolve!
  remote_ticket.resolve! if remote_ticket.respond_to?(:resolve!)
  update_attribute :resolution, "fixed"
end

#resolved?Boolean

Returns:

  • (Boolean)


182
183
184
# File 'app/models/ticket.rb', line 182

def resolved?
  !resolution.blank?
end

#tagsObject



214
215
216
# File 'app/models/ticket.rb', line 214

def tags
  (super || []).map(&TicketTag.method(:from_s))
end

#tags=(tags) ⇒ Object



218
219
220
# File 'app/models/ticket.rb', line 218

def tags=(tags)
  super (tags || []).map(&:to_s)
end

#testing_notes_since_last_releaseObject



290
291
292
# File 'app/models/ticket.rb', line 290

def testing_notes_since_last_release
  last_release_at ? testing_notes.where(["created_at > ?", last_release_at]) : testing_notes
end

#ticket_tracker_ticket_urlObject



172
173
174
# File 'app/models/ticket.rb', line 172

def ticket_tracker_ticket_url
  project.ticket_tracker_ticket_url(number)
end

#unclose!Object



269
270
271
272
# File 'app/models/ticket.rb', line 269

def unclose!
  remote_ticket.reopen! if remote_ticket
  update_attribute :closed_at, nil
end

#unreleased?Boolean

Returns:

  • (Boolean)


198
199
200
# File 'app/models/ticket.rb', line 198

def unreleased?
  releases.before(reopened_at).empty?
end

#unresolved?Boolean

Returns:

  • (Boolean)


178
179
180
# File 'app/models/ticket.rb', line 178

def unresolved?
  resolution.blank?
end

#update_comment!(comment) ⇒ Object



244
245
246
# File 'app/models/ticket.rb', line 244

def update_comment!(comment)
  remote.update_comment!(comment) if remote.respond_to?(:update_comment!)
end