Module: Issuable
- Extended by:
- ActiveSupport::Concern
- Includes:
- AfterCommitQueue, Awardable, CacheMarkdownField, ClosedAtFilterable, CreatedAtFilterable, Editable, Gitlab::SQL::Pattern, Importable, Mentionable, Milestoneable, Participable, Redactable, Sortable, SortableTitle, StripAttribute, Subscribable, Taskable, UpdatedAtFilterable, VersionedDescription
- Included in:
- Issue, MergeRequest
- Defined in:
- app/models/concerns/issuable.rb,
app/services/issuable/destroy_service.rb,
app/services/issuable/process_assignees.rb,
app/services/issuable/clone/base_service.rb,
app/services/issuable/bulk_update_service.rb,
app/services/issuable/export_csv/base_service.rb,
app/services/issuable/import_csv/base_service.rb,
app/services/issuable/clone/attributes_rewriter.rb,
app/workers/issuable/label_links_destroy_worker.rb,
app/services/issuable/common_system_notes_service.rb,
app/services/issuable/destroy_label_links_service.rb
Overview
This follows the rules specified in the specs. See spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb
Defined Under Namespace
Modules: Clone, ExportCsv, ImportCsv
Classes: BulkUpdateService, CommonSystemNotesService, DestroyLabelLinksService, DestroyService, LabelLinksDestroyWorker, ProcessAssignees
Constant Summary
collapse
- TITLE_LENGTH_MAX =
255
- TITLE_HTML_LENGTH_MAX =
800
- DESCRIPTION_LENGTH_MAX =
1.megabyte
- DESCRIPTION_HTML_LENGTH_MAX =
5.megabytes
- SEARCHABLE_FIELDS =
%w(title description).freeze
- STATE_ID_MAP =
{
opened: 1,
closed: 2,
merged: 3,
locked: 4
}.with_indifferent_access.freeze
Constants included
from Taskable
Taskable::COMPLETED, Taskable::COMPLETE_PATTERN, Taskable::INCOMPLETE, Taskable::INCOMPLETE_PATTERN, Taskable::ITEM_PATTERN
CacheMarkdownField::INVALIDATED_BY
Constants included
from Redactable
Redactable::UNSUBSCRIBE_PATTERN
Gitlab::SQL::Pattern::MIN_CHARS_FOR_PARTIAL_MATCHING, Gitlab::SQL::Pattern::REGEX_QUOTED_WORD
Instance Attribute Summary
Attributes included from Importable
#imported, #importing
Instance Method Summary
collapse
#run_after_commit, #run_after_commit_or_now
Methods included from Editable
#edited?, #last_edited_by
Methods included from Taskable
get_tasks, get_updated_tasks, #task_completion_status, #task_list_items, #task_status, #task_status_short, #tasks, #tasks?
Methods included from Awardable
#awarded_emoji?, #downvotes, #emoji_awardable?, #grouped_awards, #upvotes, #user_authored?, #user_can_award?
#strip_attributes!
#lazy_subscription, #set_subscription, #subscribe, #subscribed?, #subscribers, #toggle_subscription, #unsubscribe
#milestone_available?, #supports_milestone?
#all_references, #create_cross_references!, #create_new_cross_references!, #directly_addressed_users, #extractors, #gfm_reference, #local_reference, #matches_cross_reference_regex?, #mentioned_users, #referenced_group_users, #referenced_groups, #referenced_mentionables, #referenced_project_users, #referenced_projects, #referenced_users, #user_mention_class, #user_mention_identifier
#participant?, #participants, #visible_participants
#attribute_invalidated?, #banzai_render_context, #cached_html_for, #cached_html_up_to_date?, #can_cache_field?, #invalidated_markdown_cache?, #latest_cached_markdown_version, #local_version, #mentionable_attributes_changed?, #parent_user, #refresh_markdown_cache, #refresh_markdown_cache!, #rendered_field_content, #skip_project_check?, #store_mentions!, #updated_cached_html_for
Instance Method Details
#assignee_list ⇒ Object
556
557
558
|
# File 'app/models/concerns/issuable.rb', line 556
def assignee_list
assignees.map(&:name).to_sentence
end
|
#assignee_or_author?(user) ⇒ Boolean
431
432
433
|
# File 'app/models/concerns/issuable.rb', line 431
def assignee_or_author?(user)
author_id == user.id || assignees.exists?(user.id)
end
|
#assignee_username_list ⇒ Object
560
561
562
|
# File 'app/models/concerns/issuable.rb', line 560
def assignee_username_list
assignees.map(&:username).to_sentence
end
|
#can_assign_epic?(user) ⇒ Boolean
471
472
473
|
# File 'app/models/concerns/issuable.rb', line 471
def can_assign_epic?(user)
false
end
|
#can_move? ⇒ Boolean
Method that checks if issuable can be moved to another project.
Should be overridden if issuable can be moved.
594
595
596
|
# File 'app/models/concerns/issuable.rb', line 594
def can_move?(*)
false
end
|
#card_attributes ⇒ Object
Returns a Hash of attributes to be used for Twitter card metadata
549
550
551
552
553
554
|
# File 'app/models/concerns/issuable.rb', line 549
def card_attributes
{
'Author' => author.try(:name),
'Assignee' => assignee_list
}
end
|
#created_hours_ago ⇒ Object
439
440
441
|
# File 'app/models/concerns/issuable.rb', line 439
def created_hours_ago
(Time.now.utc.to_i - created_at.utc.to_i) / 3600
end
|
#draftless_title_changed(old_title) ⇒ Object
Overridden in MergeRequest
612
613
614
|
# File 'app/models/concerns/issuable.rb', line 612
def draftless_title_changed(old_title)
old_title != title
end
|
#ensure_metrics ⇒ Object
605
606
607
|
# File 'app/models/concerns/issuable.rb', line 605
def ensure_metrics
self.metrics || create_metrics
end
|
#first_contribution? ⇒ Boolean
Override in issuable specialization
601
602
603
|
# File 'app/models/concerns/issuable.rb', line 601
def first_contribution?
false
end
|
#hook_association_changes(old_associations) ⇒ Object
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
|
# File 'app/models/concerns/issuable.rb', line 475
def hook_association_changes(old_associations)
changes = {}
old_labels = old_associations.fetch(:labels, labels)
old_assignees = old_associations.fetch(:assignees, assignees)
old_severity = old_associations.fetch(:severity, severity)
if old_labels != labels
changes[:labels] = [old_labels.map(&:hook_attrs), labels.map(&:hook_attrs)]
end
if old_assignees != assignees
changes[:assignees] = [old_assignees.map(&:hook_attrs), assignees.map(&:hook_attrs)]
end
if supports_severity? && old_severity != severity
changes[:severity] = [old_severity, severity]
end
if supports_escalation? && escalation_status
current_escalation_status = escalation_status.status_name
old_escalation_status = old_associations.fetch(:escalation_status, current_escalation_status)
if old_escalation_status != current_escalation_status
changes[:escalation_status] = [old_escalation_status, current_escalation_status]
end
end
if self.respond_to?(:total_time_spent)
old_total_time_spent = old_associations.fetch(:total_time_spent, total_time_spent)
old_time_change = old_associations.fetch(:time_change, time_change)
if old_total_time_spent != total_time_spent
changes[:total_time_spent] = [old_total_time_spent, total_time_spent]
changes[:time_change] = [old_time_change, time_change]
end
end
changes
end
|
#label_names ⇒ Object
530
531
532
|
# File 'app/models/concerns/issuable.rb', line 530
def label_names
labels.order('title ASC').pluck(:title)
end
|
#labels_array ⇒ Object
526
527
528
|
# File 'app/models/concerns/issuable.rb', line 526
def labels_array
labels.to_a
end
|
#labels_hook_attrs ⇒ Object
534
535
536
|
# File 'app/models/concerns/issuable.rb', line 534
def labels_hook_attrs
labels.map(&:hook_attrs)
end
|
#new? ⇒ Boolean
443
444
445
|
# File 'app/models/concerns/issuable.rb', line 443
def new?
created_hours_ago < 24
end
|
#notes_with_associations ⇒ Object
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
|
# File 'app/models/concerns/issuable.rb', line 564
def notes_with_associations
includes = []
includes << :author unless notes.authors_loaded?
includes << :award_emoji unless notes.award_emojis_loaded?
includes << :project unless notes.projects_loaded?
includes << :system_note_metadata unless notes.system_note_metadata_loaded?
if includes.any?
notes.includes(includes)
else
notes
end
end
|
#open? ⇒ Boolean
447
448
449
|
# File 'app/models/concerns/issuable.rb', line 447
def open?
opened?
end
|
#overdue? ⇒ Boolean
451
452
453
454
455
|
# File 'app/models/concerns/issuable.rb', line 451
def overdue?
return false unless respond_to?(:due_date)
due_date.try(:past?) || false
end
|
#resource_parent ⇒ Object
427
428
429
|
# File 'app/models/concerns/issuable.rb', line 427
def resource_parent
project
end
|
#state ⇒ Object
419
420
421
|
# File 'app/models/concerns/issuable.rb', line 419
def state
self.class.available_states.key(state_id)
end
|
#state=(value) ⇒ Object
423
424
425
|
# File 'app/models/concerns/issuable.rb', line 423
def state=(value)
self.state_id = self.class.available_states[value]
end
|
#subscribed_without_subscriptions?(user, project) ⇒ Boolean
467
468
469
|
# File 'app/models/concerns/issuable.rb', line 467
def subscribed_without_subscriptions?(user, project)
participant?(user)
end
|
#to_ability_name ⇒ Object
Convert this Issuable class name to a format usable by Ability definitions
Examples:
issuable.class issuable.to_ability_name
544
545
546
|
# File 'app/models/concerns/issuable.rb', line 544
def to_ability_name
self.class.to_ability_name
end
|
#to_hook_data(user, old_associations: {}) ⇒ Object
516
517
518
519
520
521
522
523
524
|
# File 'app/models/concerns/issuable.rb', line 516
def to_hook_data(user, old_associations: {})
changes = previous_changes
if old_associations.present?
changes.merge!(hook_association_changes(old_associations))
end
Gitlab::DataBuilder::Issuable.new(self).build(user: user, changes: changes)
end
|
#today? ⇒ Boolean
435
436
437
|
# File 'app/models/concerns/issuable.rb', line 435
def today?
Date.today == created_at.to_date
end
|
#updated_tasks ⇒ Object
584
585
586
587
|
# File 'app/models/concerns/issuable.rb', line 584
def updated_tasks
Taskable.get_updated_tasks(old_content: previous_changes['description'].first,
new_content: description)
end
|
#user_notes_count ⇒ Object
457
458
459
460
461
462
463
464
465
|
# File 'app/models/concerns/issuable.rb', line 457
def user_notes_count
if notes.loaded?
notes.to_a.count { |note| !note.system? }
else
notes.user.count
end
end
|