Class: Issue
- Inherits:
-
ApplicationRecord
show all
- Extended by:
- Gitlab::Utils::Override
- Includes:
- AtomicInternalId, EachBatch, FasterCacheKeys, FromUnion, IdInOrdered, IidRoutes, Issuable, IssueAvailableFeatures, LabelEventable, MilestoneEventable, Noteable, PgFullTextSearchable, Presentable, Referable, RelativePositioning, Spammable, StateEventable, ThrottledTouch, TimeTrackable, Todoable, WhereComposite
- Defined in:
- app/models/issue.rb
Defined Under Namespace
Classes: Email, Metrics
Constant Summary
collapse
- DueDateStruct =
Struct.new(:title, :name).freeze
- NoDueDate =
DueDateStruct.new('No Due Date', '0').freeze
- AnyDueDate =
DueDateStruct.new('Any Due Date', 'any').freeze
- Overdue =
DueDateStruct.new('Overdue', 'overdue').freeze
- DueToday =
DueDateStruct.new('Due Today', 'today').freeze
- DueTomorrow =
DueDateStruct.new('Due Tomorrow', 'tomorrow').freeze
- DueThisWeek =
DueDateStruct.new('Due This Week', 'week').freeze
- DueThisMonth =
DueDateStruct.new('Due This Month', 'month').freeze
- DueNextMonthAndPreviousTwoWeeks =
DueDateStruct.new('Due Next Month And Previous Two Weeks', 'next_month_and_previous_two_weeks').freeze
- IssueTypeOutOfSyncError =
Class.new(StandardError)
- SORTING_PREFERENCE_FIELD =
:issues_sort
- MAX_BRANCH_TEMPLATE =
255
- TYPES_FOR_LIST =
%w[issue incident test_case task objective key_result].freeze
- TYPES_FOR_BOARD_LIST =
Types of issues that should be displayed on issue board lists
%w[issue incident].freeze
- DEFAULT_ISSUE_TYPE =
This default came from the enum ‘issue_type` column. Defined as default in the DB
:issue
PgFullTextSearchable::LONG_WORDS_REGEX, PgFullTextSearchable::TEXT_SEARCH_DICTIONARY, PgFullTextSearchable::TSQUERY_DISALLOWED_CHARACTERS_REGEX, PgFullTextSearchable::TSVECTOR_MAX_LENGTH, PgFullTextSearchable::URL_SCHEME_REGEX
ThrottledTouch::TOUCH_INTERVAL
Gitlab::RelativePositioning::IDEAL_DISTANCE, Gitlab::RelativePositioning::IllegalRange, Gitlab::RelativePositioning::InvalidPosition, Gitlab::RelativePositioning::IssuePositioningDisabled, Gitlab::RelativePositioning::MAX_GAP, Gitlab::RelativePositioning::MAX_POSITION, Gitlab::RelativePositioning::MIN_GAP, Gitlab::RelativePositioning::MIN_POSITION, Gitlab::RelativePositioning::NoSpaceLeft, Gitlab::RelativePositioning::START_POSITION, Gitlab::RelativePositioning::STEPS
Constants included
from Noteable
Noteable::MAX_NOTES_LIMIT
Constants included
from Issuable
Issuable::DESCRIPTION_HTML_LENGTH_MAX, Issuable::DESCRIPTION_LENGTH_MAX, Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS, Issuable::SEARCHABLE_FIELDS, Issuable::STATE_ID_MAP, Issuable::TITLE_HTML_LENGTH_MAX, Issuable::TITLE_LENGTH_MAX
Constants included
from Taskable
Taskable::COMPLETED, Taskable::COMPLETE_PATTERN, Taskable::INCOMPLETE, Taskable::INCOMPLETE_PATTERN, Taskable::ITEM_PATTERN, Taskable::ITEM_PATTERN_UNTRUSTED, Taskable::REGEX
CacheMarkdownField::INVALIDATED_BY
Constants included
from Redactable
Redactable::UNSUBSCRIBE_PATTERN
Gitlab::SQL::Pattern::MIN_CHARS_FOR_PARTIAL_MATCHING, Gitlab::SQL::Pattern::REGEX_QUOTED_TERM
AtomicInternalId::MissingValueError
ApplicationRecord::MAX_PLUCK
ResetOnUnionError::MAX_RESET_PERIOD
Instance Attribute Summary
Attributes included from Noteable
#system_note_timestamp
#transitioning
Attributes included from Importable
#imported, #importing
#skip_markdown_cache_validation
Class Method Summary
collapse
Instance Method Summary
collapse
extended, extensions, included, method_added, override, prepended, queue_verification, verify!
#update_search_data!
#issue_type_supports?
#present
#touch
#human_time_change, #human_time_estimate, #human_total_time_spent, #set_time_estimate_default_value, #spend_time, #time_change, #time_estimate=, #total_time_spent
#exclude_self, #model_class, #move_after, #move_before, #move_between, #move_to_end, #move_to_start, mover, #relative_positioning_scoped_items, #reset_relative_position, #update_relative_siblings
range
#cache_key
Methods included from Spammable
#check_for_spam, #check_for_spam?, #clear_spam_flags!, #invalidate_if_spam, #needs_recaptcha!, #recaptcha_error!, #render_recaptcha?, #spam, #spam!, #spam_description, #spam_title, #spammable_attribute_changed?, #spammable_entity_type, #spammable_text, #submittable_as_spam?, #submittable_as_spam_by?, #unrecoverable_spam_error!
Methods included from Referable
#referable_inspect, #reference_link_text, #to_reference_base
Methods included from Noteable
#after_note_created, #after_note_destroyed, #base_class_name, #broadcast_notes_changed, #capped_notes_count, #commenters, #creatable_note_email_address, #discussion_ids_relation, #discussion_notes, #discussion_root_note_ids, #discussions, #discussions_can_be_resolved_by?, #discussions_resolvable?, #discussions_resolved?, #discussions_to_be_resolved, #grouped_diff_discussions, #has_any_diff_note_positions?, #human_class_name, #lockable?, #noteable_target_type_name, #preloads_discussion_diff_highlighting?, #resolvable_discussions, #supports_creating_notes_by_email?, #supports_discussions?, #supports_replying_to_individual_notes?, #supports_resolvable_notes?, #supports_suggestion?
Methods included from Issuable
#allows_scoped_labels?, #assignee?, #assignee_list, #assignee_or_author?, #assignee_username_list, #can_assign_epic?, #card_attributes, #draftless_title_changed, #first_contribution?, #hook_association_changes, #hook_reviewer_changes, #label_names, #labels_array, #labels_hook_attrs, #notes_with_associations, #open?, #overdue?, #read_ability_for, #state, #state=, #subscribed_without_subscriptions?, #supports_health_status?, #to_ability_name, #to_hook_data, #updated_tasks, #user_notes_count
Methods included from Exportable
#exportable_association?, #restricted_associations, #to_authorized_json
#run_after_commit, #run_after_commit_or_now
Methods included from Editable
#edited?, #last_edited_by
#disable_transitioning, #enable_transitioning, #transitioning?
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?, #subscribed_without_subscriptions?, #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?, #cached_html_for, #cached_html_up_to_date?, #can_cache_field?, #invalidated_markdown_cache?, #latest_cached_markdown_version, #local_version, #mentionable_attributes_changed?, #mentioned_filtered_user_ids_for, #parent_user, #refresh_markdown_cache, #refresh_markdown_cache!, #rendered_field_content, #skip_project_check?, #store_mentions!, #updated_cached_html_for
split_query_to_search_terms
Methods included from IidRoutes
#to_param
group_init, #internal_id_read_scope, #internal_id_scope_attrs, #internal_id_scope_usage, namespace_init, project_init, scope_attrs, scope_usage
cached_column_list, #create_or_load_association, declarative_enum, default_select_columns, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, #to_ability_name, underscore, where_exists, where_not_exists, with_fast_read_statement_timeout, without_order
#serializable_hash
Class Method Details
.alternative_reference_prefix ⇒ Object
Alternative prefix for situations where the standard prefix would be interpreted as a comment, most notably to begin commit messages with (e.g. “GL-123: My commit”)
370
371
372
|
# File 'app/models/issue.rb', line 370
def self.alternative_reference_prefix
'GL-'
end
|
.column_order_id_asc ⇒ Object
.column_order_relative_position ⇒ Object
433
434
435
436
437
438
439
440
441
|
# File 'app/models/issue.rb', line 433
def self.column_order_relative_position
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
attribute_name: 'relative_position',
column_expression: arel_table[:relative_position],
order_expression: Issue.arel_table[:relative_position].asc.nulls_last,
nullable: :nulls_last,
distinct: false
)
end
|
.full_search(query, matched_columns: nil, use_minimum_char_limit: true) ⇒ Object
.link_reference_pattern ⇒ Object
386
387
388
|
# File 'app/models/issue.rb', line 386
def self.link_reference_pattern
@link_reference_pattern ||= compose_link_reference_pattern(%r{issues(?:\/incident)?}, Gitlab::Regex.issue)
end
|
.order_by_relative_position ⇒ Object
429
430
431
|
# File 'app/models/issue.rb', line 429
def self.order_by_relative_position
reorder(Gitlab::Pagination::Keyset::Order.build([column_order_relative_position, column_order_id_asc]))
end
|
.order_upvotes_asc ⇒ Object
305
306
307
|
# File 'app/models/issue.rb', line 305
def order_upvotes_asc
reorder(upvotes_count: :asc)
end
|
.order_upvotes_desc ⇒ Object
300
301
302
|
# File 'app/models/issue.rb', line 300
def order_upvotes_desc
reorder(upvotes_count: :desc)
end
|
.participant_includes ⇒ Object
324
325
326
|
# File 'app/models/issue.rb', line 324
def self.participant_includes
[:assignees] + super
end
|
.project_foreign_key ⇒ Object
394
395
396
|
# File 'app/models/issue.rb', line 394
def self.project_foreign_key
'project_id'
end
|
.reference_pattern ⇒ Object
Pattern used to extract ‘#123` issue references from text
This pattern supports cross-project references.
377
378
379
380
381
382
383
384
|
# File 'app/models/issue.rb', line 377
def self.reference_pattern
@reference_pattern ||= %r{
(?:
(#{Project.reference_pattern})?#{Regexp.escape(reference_prefix)} |
#{Regexp.escape(alternative_reference_prefix)}
)#{Gitlab::Regex.issue}
}x
end
|
.reference_prefix ⇒ Object
363
364
365
|
# File 'app/models/issue.rb', line 363
def self.reference_prefix
'#'
end
|
.reference_valid?(reference) ⇒ Boolean
390
391
392
|
# File 'app/models/issue.rb', line 390
def self.reference_valid?(reference)
reference.to_i > 0 && reference.to_i <= Gitlab::Database::MAX_INT_VALUE
end
|
319
320
321
|
# File 'app/models/issue.rb', line 319
def related_link_class
IssueLink
end
|
.relative_positioning_parent_column ⇒ Object
359
360
361
|
# File 'app/models/issue.rb', line 359
def self.relative_positioning_parent_column
:project_id
end
|
.relative_positioning_query_base(issue) ⇒ Object
355
356
357
|
# File 'app/models/issue.rb', line 355
def self.relative_positioning_query_base(issue)
in_projects(issue.relative_positioning_parent_projects)
end
|
.simple_sorts ⇒ Object
398
399
400
401
402
403
404
405
406
407
408
409
410
|
# File 'app/models/issue.rb', line 398
def self.simple_sorts
super.merge(
{
'closest_future_date' => -> { order_closest_future_date },
'closest_future_date_asc' => -> { order_closest_future_date },
'due_date' => -> { order_due_date_asc.with_order_id_desc },
'due_date_asc' => -> { order_due_date_asc.with_order_id_desc },
'due_date_desc' => -> { order_due_date_desc.with_order_id_desc },
'relative_position' => -> { order_by_relative_position },
'relative_position_asc' => -> { order_by_relative_position }
}
)
end
|
.sort_by_attribute(method, excluded_labels: []) ⇒ Object
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
|
# File 'app/models/issue.rb', line 412
def self.sort_by_attribute(method, excluded_labels: [])
case method.to_s
when 'closest_future_date', 'closest_future_date_asc' then order_closest_future_date
when 'due_date', 'due_date_asc' then order_due_date_asc.with_order_id_desc
when 'due_date_desc' then order_due_date_desc.with_order_id_desc
when 'relative_position', 'relative_position_asc' then order_by_relative_position
when 'severity_asc' then order_severity_asc
when 'severity_desc' then order_severity_desc
when 'escalation_status_asc' then order_escalation_status_asc
when 'escalation_status_desc' then order_escalation_status_desc
when 'closed_at', 'closed_at_asc' then order_closed_at_asc
when 'closed_at_desc' then order_closed_at_desc
else
super
end
end
|
.to_branch_name(id, title, project: nil) ⇒ Object
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
|
# File 'app/models/issue.rb', line 450
def self.to_branch_name(id, title, project: nil)
params = {
'id' => id.to_s.parameterize(preserve_case: true),
'title' => title.to_s.parameterize
}
template = project&.issue_branch_template
branch_name =
if template.present?
Gitlab::StringPlaceholderReplacer.replace_string_placeholders(template, /(#{params.keys.join('|')})/) do |arg|
params[arg]
end
else
params.values.select(&:present?).join('-')
end
if branch_name.length > 100
truncated_string = branch_name[0, 100]
branch_name = truncated_string.sub(/-[^-]*\Z/, '')
end
branch_name
end
|
Instance Method Details
#allow_possible_spam?(user) ⇒ Boolean
Always enforce spam check for support bot but allow for other users when issue is not publicly visible
588
589
590
591
592
593
|
# File 'app/models/issue.rb', line 588
def allow_possible_spam?(user)
return true if Gitlab::CurrentSettings.allow_possible_spam
return false if user.support_bot?
!publicly_visible?
end
|
#as_json(options = {}) ⇒ Object
599
600
601
602
603
604
605
606
607
608
609
|
# File 'app/models/issue.rb', line 599
def as_json(options = {})
super(options).tap do |json|
if options.key?(:labels)
json[:labels] = labels.as_json(
project: project,
only: [:id, :title, :description, :color, :priority],
methods: [:text_color]
)
end
end
end
|
#banzai_render_context(field) ⇒ Object
637
638
639
|
# File 'app/models/issue.rb', line 637
def banzai_render_context(field)
super.merge(label_url_method: :project_issues_url)
end
|
#blocked_for_repositioning? ⇒ Boolean
484
485
486
|
# File 'app/models/issue.rb', line 484
def blocked_for_repositioning?
resource_parent.root_namespace&.issue_repositioning_disabled?
end
|
#can_be_worked_on? ⇒ Boolean
571
572
573
|
# File 'app/models/issue.rb', line 571
def can_be_worked_on?
!self.closed? && !self.project.forked?
end
|
#can_move?(user, to_project = nil) ⇒ Boolean
Also known as:
can_clone?
528
529
530
531
532
533
534
535
|
# File 'app/models/issue.rb', line 528
def can_move?(user, to_project = nil)
if to_project
return false unless user.can?(:admin_issue, to_project)
end
!moved? && persisted? &&
user.can?(:admin_issue, self.project)
end
|
#check_repositioning_allowed! ⇒ Object
478
479
480
481
482
|
# File 'app/models/issue.rb', line 478
def check_repositioning_allowed!
if blocked_for_repositioning?
raise ::Gitlab::RelativePositioning::IssuePositioningDisabled, "Issue relative position changes temporarily disabled."
end
end
|
#clear_closure_reason_references ⇒ Object
523
524
525
526
|
# File 'app/models/issue.rb', line 523
def clear_closure_reason_references
self.moved_to_id = nil
self.duplicated_to_id = nil
end
|
#design_collection ⇒ Object
#discussions_rendered_on_frontend? ⇒ Boolean
615
616
617
|
# File 'app/models/issue.rb', line 615
def discussions_rendered_on_frontend?
true
end
|
#duplicated? ⇒ Boolean
519
520
521
|
# File 'app/models/issue.rb', line 519
def duplicated?
!duplicated_to_id.nil?
end
|
#email_participants_emails ⇒ Object
675
676
677
|
# File 'app/models/issue.rb', line 675
def email_participants_emails
issue_email_participants.pluck(:email)
end
|
#email_participants_emails_downcase ⇒ Object
679
680
681
|
# File 'app/models/issue.rb', line 679
def email_participants_emails_downcase
issue_email_participants.pluck(IssueEmailParticipant.arel_table[:email].lower)
end
|
#expire_etag_cache ⇒ Object
#from_service_desk? ⇒ Boolean
645
646
647
|
# File 'app/models/issue.rb', line 645
def from_service_desk?
author.id == Users::Internal.support_bot.id
end
|
#hidden? ⇒ Boolean
715
716
717
|
# File 'app/models/issue.rb', line 715
def hidden?
author&.banned?
end
|
#issue_assignee_user_ids ⇒ Object
683
684
685
|
# File 'app/models/issue.rb', line 683
def issue_assignee_user_ids
issue_assignees.pluck(:user_id)
end
|
#issue_link_type ⇒ Object
649
650
651
652
653
654
655
656
657
|
# File 'app/models/issue.rb', line 649
def issue_link_type
link_class = self.class.related_link_class
return unless respond_to?(:issue_link_type_value) && respond_to?(:issue_link_source_id)
type = link_class.link_types.key(issue_link_type_value) || link_class::TYPE_RELATES_TO
return type if issue_link_source_id == id
link_class.inverse_link_type(type)
end
|
#issue_type ⇒ Object
748
749
750
|
# File 'app/models/issue.rb', line 748
def issue_type
work_item_type_with_default.base_type
end
|
#linked_items_count ⇒ Object
567
568
569
|
# File 'app/models/issue.rb', line 567
def linked_items_count
related_issues(authorize: false).size
end
|
#merge_requests_count(user = nil) ⇒ Object
rubocop: enable CodeReuse/ServiceClass
#moved? ⇒ Boolean
515
516
517
|
# File 'app/models/issue.rb', line 515
def moved?
!moved_to_id.nil?
end
|
#next_object_by_relative_position(ignoring: nil, order: :asc) ⇒ Object
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
|
# File 'app/models/issue.rb', line 328
def next_object_by_relative_position(ignoring: nil, order: :asc)
array_mapping_scope = -> (id_expression) do
relation = Issue.where(Issue.arel_table[:project_id].eq(id_expression))
if order == :asc
relation.where(Issue.arel_table[:relative_position].gt(relative_position))
else
relation.where(Issue.arel_table[:relative_position].lt(relative_position))
end
end
relation = Gitlab::Pagination::Keyset::InOperatorOptimization::QueryBuilder.new(
scope: Issue.order(relative_position: order, id: order),
array_scope: relative_positioning_parent_projects,
array_mapping_scope: array_mapping_scope,
finder_query: -> (_, id_expression) { Issue.where(Issue.arel_table[:id].eq(id_expression)) }
).execute
relation = exclude_self(relation, excluded: ignoring) if ignoring.present?
relation.take
end
|
#previous_updated_at ⇒ Object
633
634
635
|
# File 'app/models/issue.rb', line 633
def previous_updated_at
previous_changes['updated_at']&.first || updated_at
end
|
#readable_by?(user) ⇒ Boolean
Returns ‘true` if the given User can read the current Issue.
This method duplicates the same check of issue_policy.rb for performance reasons, check commit: 002ad215818450d2cbbc5fa065850a953dc7ada8 Make sure to sync this method with issue_policy.rb
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
|
# File 'app/models/issue.rb', line 697
def readable_by?(user)
if !project.issues_enabled?
false
elsif user.can_read_all_resources?
true
elsif project.personal? && project.team.owner?(user)
true
elsif confidential? && !assignee_or_author?(user)
project.member?(user, Gitlab::Access::REPORTER)
elsif hidden?
false
elsif project.public? || (project.internal? && !user.external?)
project.feature_available?(:issues, user)
else
project.member?(user)
end
end
|
#real_time_notes_enabled? ⇒ Boolean
611
612
613
|
# File 'app/models/issue.rb', line 611
def real_time_notes_enabled?
true
end
|
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
|
# File 'app/models/issue.rb', line 546
def related_issues(current_user = nil, authorize: true, preload: nil)
return [] if new_record?
related_issues =
linked_issues_select
.joins("INNER JOIN issue_links ON
(issue_links.source_id = issues.id AND issue_links.target_id = #{id})
OR
(issue_links.target_id = issues.id AND issue_links.source_id = #{id})")
.preload(preload)
.reorder('issue_link_id')
related_issues = yield related_issues if block_given?
return related_issues unless authorize
cross_project_filter = -> (issues) { issues.where(project: project) }
Ability.issues_readable_by_user(related_issues,
current_user,
filters: { read_cross_project: cross_project_filter })
end
|
#relative_positioning_parent_projects ⇒ Object
351
352
353
|
# File 'app/models/issue.rb', line 351
def relative_positioning_parent_projects
project.group&.root_ancestor&.all_projects&.select(:id) || Project.id_in(project).select(:id)
end
|
#relocation_target ⇒ Object
659
660
661
|
# File 'app/models/issue.rb', line 659
def relocation_target
moved_to || duplicated_to
end
|
#resource_parent ⇒ Object
738
739
740
|
# File 'app/models/issue.rb', line 738
def resource_parent
project || namespace
end
|
#source_project ⇒ Object
To allow polymorphism with MergeRequest.
511
512
513
|
# File 'app/models/issue.rb', line 511
def source_project
project
end
|
#suggested_branch_name ⇒ Object
495
496
497
498
499
500
501
502
503
504
505
506
507
508
|
# File 'app/models/issue.rb', line 495
def suggested_branch_name
return to_branch_name unless project.repository.branch_exists?(to_branch_name)
start_counting_from = 2
branch_name_generator = -> (counter) do
suffix = counter > 5 ? SecureRandom.hex(8) : counter
"#{to_branch_name}-#{suffix}"
end
Gitlab::Utils::Uniquify.new(start_counting_from).string(branch_name_generator) do |suggested_branch_name|
project.repository.branch_exists?(suggested_branch_name)
end
end
|
#supports_assignee? ⇒ Boolean
663
664
665
|
# File 'app/models/issue.rb', line 663
def supports_assignee?
work_item_type_with_default.supports_assignee?
end
|
#supports_confidentiality? ⇒ Boolean
728
729
730
|
# File 'app/models/issue.rb', line 728
def supports_confidentiality?
true
end
|
#supports_move_and_clone? ⇒ Boolean
671
672
673
|
# File 'app/models/issue.rb', line 671
def supports_move_and_clone?
issue_type_supports?(:move_and_clone)
end
|
#supports_recaptcha? ⇒ Boolean
595
596
597
|
# File 'app/models/issue.rb', line 595
def supports_recaptcha?
true
end
|
#supports_time_tracking? ⇒ Boolean
667
668
669
|
# File 'app/models/issue.rb', line 667
def supports_time_tracking?
issue_type_supports?(:time_tracking)
end
|
#to_branch_name ⇒ Object
538
539
540
541
542
543
544
|
# File 'app/models/issue.rb', line 538
def to_branch_name
if self.confidential?
"#{iid}-confidential-issue"
else
self.class.to_branch_name(iid, title, project: project)
end
end
|
#to_reference(from = nil, full: false) ⇒ Object
‘from` argument can be a Namespace or Project.
489
490
491
492
493
|
# File 'app/models/issue.rb', line 489
def to_reference(from = nil, full: false)
reference = "#{self.class.reference_prefix}#{iid}"
"#{namespace.to_reference_base(from, full: full)}#{reference}"
end
|
#to_work_item_global_id ⇒ Object
we want to have subscriptions working on work items only, legacy issues do not support graphql subscriptions, yet so we need sometimes GID of an issue instance to be represented as WorkItem GID. E.g. notes subscriptions.
#unsubscribe_email_participant(email) ⇒ Object
752
753
754
755
756
|
# File 'app/models/issue.rb', line 752
def unsubscribe_email_participant(email)
return if email.blank?
issue_email_participants.find_by_email(email)&.destroy
end
|
#update_project_counter_caches ⇒ Object
rubocop: disable CodeReuse/ServiceClass
#update_upvotes_count ⇒ Object
687
688
689
690
|
# File 'app/models/issue.rb', line 687
def update_upvotes_count
self.lock!
self.update_column(:upvotes_count, self.upvotes)
end
|
#visible_to_user?(user = nil) ⇒ Boolean
Returns ‘true` if the current issue can be viewed by either a logged in User or an anonymous user.
577
578
579
580
581
582
583
584
585
|
# File 'app/models/issue.rb', line 577
def visible_to_user?(user = nil)
return publicly_visible? unless user
return false unless readable_by?(user)
user.can_read_all_resources? ||
::Gitlab::ExternalAuthorization.access_allowed?(
user, project.external_authorization_classification_label)
end
|
#work_item_type_with_default ⇒ Object
Persisted records will always have a work_item_type. This method is useful in places where we use a non persisted issue to perform feature checks