Class: WorkItem

Inherits:
Issue show all
Includes:
Gitlab::Utils::StrongMemoize
Defined in:
app/models/work_item.rb

Constant Summary collapse

COMMON_QUICK_ACTIONS_COMMANDS =
[
  :title, :reopen, :close, :cc, :tableflip, :shrug, :type, :promote_to, :checkin_reminder,
  :subscribe, :unsubscribe, :confidential, :award
].freeze

Constants inherited from Issue

Issue::AnyDueDate, Issue::DEFAULT_ISSUE_TYPE, Issue::DueDateStruct, Issue::DueNextMonthAndPreviousTwoWeeks, Issue::DueThisMonth, Issue::DueThisWeek, Issue::DueToday, Issue::DueTomorrow, Issue::IssueTypeOutOfSyncError, Issue::MAX_BRANCH_TEMPLATE, Issue::NoDueDate, Issue::Overdue, Issue::SORTING_PREFERENCE_FIELD, Issue::TYPES_FOR_BOARD_LIST, Issue::TYPES_FOR_LIST

Constants included from PgFullTextSearchable

PgFullTextSearchable::LONG_WORDS_REGEX, PgFullTextSearchable::TEXT_SEARCH_DICTIONARY, PgFullTextSearchable::TSQUERY_DISALLOWED_CHARACTERS_REGEX, PgFullTextSearchable::TSVECTOR_MAX_LENGTH, PgFullTextSearchable::URL_SCHEME_REGEX

Constants included from ThrottledTouch

ThrottledTouch::TOUCH_INTERVAL

Constants included from Gitlab::RelativePositioning

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

Constants included from CacheMarkdownField

CacheMarkdownField::INVALIDATED_BY

Constants included from Redactable

Redactable::UNSUBSCRIBE_PATTERN

Constants included from Gitlab::SQL::Pattern

Gitlab::SQL::Pattern::MIN_CHARS_FOR_PARTIAL_MATCHING, Gitlab::SQL::Pattern::REGEX_QUOTED_TERM

Constants included from AtomicInternalId

AtomicInternalId::MissingValueError

Constants inherited from ApplicationRecord

ApplicationRecord::MAX_PLUCK

Constants included from ResetOnUnionError

ResetOnUnionError::MAX_RESET_PERIOD

Instance Attribute Summary

Attributes included from Noteable

#system_note_timestamp

Attributes included from Transitionable

#transitioning

Attributes included from Importable

#imported, #importing

Attributes included from CacheMarkdownField

#skip_markdown_cache_validation

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Issue

#allow_possible_spam?, alternative_reference_prefix, #as_json, #banzai_render_context, #blocked_for_repositioning?, #can_be_worked_on?, #can_move?, #check_repositioning_allowed!, #clear_closure_reason_references, column_order_id_asc, column_order_relative_position, #design_collection, #discussions_rendered_on_frontend?, #duplicated?, #email_participants_emails, #email_participants_emails_downcase, #expire_etag_cache, #from_service_desk?, full_search, #hidden?, #hook_attrs, #issue_assignee_user_ids, #issue_link_type, #issue_type, #merge_requests_count, #moved?, #next_object_by_relative_position, order_by_relative_position, order_upvotes_asc, order_upvotes_desc, participant_includes, #previous_updated_at, project_foreign_key, #readable_by?, #real_time_notes_enabled?, reference_pattern, reference_prefix, reference_valid?, #related_issues, relative_positioning_parent_column, #relative_positioning_parent_projects, relative_positioning_query_base, #relocation_target, #resource_parent, simple_sorts, sort_by_attribute, #source_project, #suggested_branch_name, #supports_assignee?, #supports_confidentiality?, #supports_move_and_clone?, #supports_recaptcha?, #supports_time_tracking?, #to_branch_name, to_branch_name, #to_reference, #to_work_item_global_id, #unsubscribe_email_participant, #update_project_counter_caches, #update_upvotes_count, #visible_to_user?, #work_item_type_with_default

Methods included from Gitlab::Utils::Override

#extended, extensions, #included, #method_added, #override, #prepended, #queue_verification, verify!

Methods included from PgFullTextSearchable

#update_search_data!

Methods included from IssueAvailableFeatures

#issue_type_supports?

Methods included from Presentable

#present

Methods included from ThrottledTouch

#touch

Methods included from TimeTrackable

#human_time_change, #human_time_estimate, #human_total_time_spent, #set_time_estimate_default_value, #spend_time, #time_change, #time_estimate=, #total_time_spent

Methods included from RelativePositioning

#check_repositioning_allowed!, #could_not_move, #exclude_self, #model_class, #move_after, #move_before, #move_between, #move_to_end, #move_to_start, mover, #next_object_by_relative_position, #relative_positioning_scoped_items, #reset_relative_position, #update_relative_siblings

Methods included from Gitlab::RelativePositioning

range

Methods included from FasterCacheKeys

#cache_key

Methods included from Spammable

#allow_possible_spam?, #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?, #supports_recaptcha?, #unrecoverable_spam_error!

Methods included from Referable

#referable_inspect, #reference_link_text, #to_reference, #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_rendered_on_frontend?, #discussions_resolvable?, #discussions_resolved?, #discussions_to_be_resolved, #grouped_diff_discussions, #has_any_diff_note_positions?, #human_class_name, #lockable?, #preloads_discussion_diff_highlighting?, #real_time_notes_enabled?, #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?, #can_move?, #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, #resource_parent, #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

Methods included from AfterCommitQueue

#run_after_commit, #run_after_commit_or_now

Methods included from Editable

#edited?, #last_edited_by

Methods included from Transitionable

#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?

Methods included from StripAttribute

#strip_attributes!

Methods included from Subscribable

#lazy_subscription, #set_subscription, #subscribe, #subscribed?, #subscribed_without_subscriptions?, #subscribers, #toggle_subscription, #unsubscribe

Methods included from Milestoneable

#milestone_available?, #supports_milestone?

Methods included from Mentionable

#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

Methods included from Participable

#participant?, #participants, #visible_participants

Methods included from CacheMarkdownField

#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?, #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

Methods included from Gitlab::SQL::Pattern

split_query_to_search_terms

Methods included from IidRoutes

#to_param

Methods included from AtomicInternalId

group_init, #internal_id_read_scope, #internal_id_scope_attrs, #internal_id_scope_usage, namespace_init, project_init, scope_attrs, scope_usage

Methods inherited from ApplicationRecord

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, #readable_by?, 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

Methods included from SensitiveSerializableHash

#serializable_hash

Class Method Details

.assignee_association_nameObject



40
41
42
# File 'app/models/work_item.rb', line 40

def assignee_association_name
  'issue'
end

def reference_pattern

# no-op: We currently only support link_reference_pattern parsing

end



52
53
54
# File 'app/models/work_item.rb', line 52

def link_reference_pattern
  @link_reference_pattern ||= compose_link_reference_pattern('work_items', Gitlab::Regex.work_item)
end


77
78
79
# File 'app/models/work_item.rb', line 77

def related_link_class
  WorkItems::RelatedWorkItemLink
end

.test_reports_join_columnObject



44
45
46
# File 'app/models/work_item.rb', line 44

def test_reports_join_column
  'issues.id'
end

.work_item_children_keyset_orderObject



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'app/models/work_item.rb', line 56

def work_item_children_keyset_order
  keyset_order = Gitlab::Pagination::Keyset::Order.build([
    Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
      attribute_name: :relative_position,
      column_expression: WorkItems::ParentLink.arel_table[:relative_position],
      order_expression: WorkItems::ParentLink.arel_table[:relative_position].asc.nulls_last,
      nullable: :nulls_last,
      distinct: false
    ),
    Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
      attribute_name: :created_at,
      order_expression: WorkItem.arel_table[:created_at].asc,
      nullable: :not_nullable,
      distinct: false
    )
  ])

  includes(:parent_link).order(keyset_order)
end

Instance Method Details

#ancestorsObject



110
111
112
# File 'app/models/work_item.rb', line 110

def ancestors
  hierarchy.ancestors(hierarchy_order: :asc)
end

#get_widget(type) ⇒ Object

Returns widget object if available type parameter can be a symbol, for example, ‘:description`.



102
103
104
105
106
107
108
# File 'app/models/work_item.rb', line 102

def get_widget(type)
  widgets.find do |widget|
    widget.instance_of?(WorkItems::Widgets.const_get(type.to_s.camelize, false))
  end
rescue NameError
  nil
end

#linked_items_countObject



164
165
166
# File 'app/models/work_item.rb', line 164

def linked_items_count
  linked_work_items(authorize: false).size
end

#linked_work_items(current_user = nil, authorize: true, preload: nil, link_type: nil) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'app/models/work_item.rb', line 150

def linked_work_items(current_user = nil, authorize: true, preload: nil, link_type: nil)
  return [] if new_record?

  linked_work_items = linked_work_items_query(link_type).preload(preload).reorder('issue_link_id')
  return linked_work_items unless authorize

  cross_project_filter = ->(work_items) { work_items.where(project: project) }
  Ability.work_items_readable_by_user(
    linked_work_items,
    current_user,
    filters: { read_cross_project: cross_project_filter }
  )
end

#noteable_target_type_nameObject



82
83
84
# File 'app/models/work_item.rb', line 82

def noteable_target_type_name
  'issue'
end

#same_type_base_and_ancestorsObject



114
115
116
# File 'app/models/work_item.rb', line 114

def same_type_base_and_ancestors
  hierarchy(same_type: true).base_and_ancestors(hierarchy_order: :asc)
end

#same_type_descendants_depthObject



118
119
120
# File 'app/models/work_item.rb', line 118

def same_type_descendants_depth
  hierarchy(same_type: true).max_descendants_depth.to_i
end

#supported_quick_action_commandsObject



122
123
124
125
126
# File 'app/models/work_item.rb', line 122

def supported_quick_action_commands
  commands_for_widgets = work_item_type.widgets.flat_map(&:quick_action_commands).uniq

  COMMON_QUICK_ACTIONS_COMMANDS + commands_for_widgets
end

#todoable_target_type_nameObject

Todo: remove method after target_type cleanup See gitlab.com/gitlab-org/gitlab/-/issues/416009



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

def todoable_target_type_name
  %w[Issue WorkItem]
end

#transform_quick_action_params(command_params) ⇒ Object

Widgets have a set of quick action params that they must process. Map them to widget_params so they can be picked up by widget services.



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'app/models/work_item.rb', line 130

def transform_quick_action_params(command_params)
  common_params = command_params.dup
  widget_params = {}

  work_item_type.widgets
        .filter { |widget| widget.respond_to?(:quick_action_params) }
        .each do |widget|
          widget.quick_action_params
            .filter { |param_name| common_params.key?(param_name) }
            .each do |param_name|
              widget_params[widget.api_symbol] ||= {}
              param_value = common_params.delete(param_name)

              widget_params[widget.api_symbol].merge!(widget.process_quick_action_param(param_name, param_value))
            end
        end

  { common: common_params, widgets: widget_params }
end

#widgetsObject



92
93
94
95
96
97
98
# File 'app/models/work_item.rb', line 92

def widgets
  strong_memoize(:widgets) do
    work_item_type.widgets.map do |widget_class|
      widget_class.new(self)
    end
  end
end