Class: Projects::IssuesController

Inherits:
ApplicationController show all
Includes:
IssuableActions, IssuableCollections, IssuesCalendar, RecordUserLastActivity, RendersNotes, SpammableActions, ToggleAwardEmoji, ToggleSubscriptionAction
Defined in:
app/controllers/projects/issues_controller.rb

Constant Summary collapse

ISSUES_EXCEPT_ACTIONS =
%i[index calendar new create bulk_update import_csv export_csv service_desk].freeze
SET_ISSUEABLES_INDEX_ONLY_ACTIONS =
%i[index calendar service_desk].freeze

Constants included from CookiesHelper

CookiesHelper::COOKIE_TYPE_ENCRYPTED, CookiesHelper::COOKIE_TYPE_PERMANENT

Constants inherited from ApplicationController

ApplicationController::DEFAULT_GITLAB_CACHE_CONTROL

Constants included from Gitlab::Logging::CloudflareHelper

Gitlab::Logging::CloudflareHelper::CLOUDFLARE_CUSTOM_HEADERS

Constants included from Gitlab::Experimentation::GroupTypes

Gitlab::Experimentation::GroupTypes::GROUP_CONTROL, Gitlab::Experimentation::GroupTypes::GROUP_EXPERIMENTAL

Constants included from Gitlab::NoCacheHeaders

Gitlab::NoCacheHeaders::DEFAULT_GITLAB_NO_CACHE_HEADERS

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from RecordUserLastActivity

#set_user_last_activity

Methods included from CookiesHelper

#set_secure_cookie

Methods included from SpammableActions

#mark_as_spam

Methods included from Gitlab::Utils::StrongMemoize

#clear_memoization, #strong_memoize, #strong_memoized?

Methods included from IssuesCalendar

#render_issues_calendar

Methods included from SortingPreference

#default_sort_order, #legacy_sort_cookie_name, #set_sort_order

Methods included from SortingHelper

#admin_groups_sort_options_hash, #audit_logs_sort_order_hash, #branches_sort_options_hash, #groups_sort_options_hash, #issuable_reverse_sort_order_hash, #issuable_sort_direction_button, #issuable_sort_option_overrides, #issuable_sort_option_title, #label_sort_options_hash, #member_sort_options_hash, #milestone_sort_options_hash, #packages_reverse_sort_order_hash, #packages_sort_direction_button, #packages_sort_option_title, #packages_sort_options_hash, #project_sort_direction_button, #projects_reverse_sort_options_hash, #projects_sort_option_titles, #projects_sort_options_hash, #search_reverse_sort_options_hash, #search_sort_direction_button, #search_sort_option_title, #sort_direction_button, #sort_direction_icon, #sort_options_hash, #sort_title_access_level_asc, #sort_title_access_level_desc, #sort_title_contacted_date, #sort_title_created_date, #sort_title_downvotes, #sort_title_due_date, #sort_title_due_date_later, #sort_title_due_date_soon, #sort_title_expire_date, #sort_title_label_priority, #sort_title_largest_group, #sort_title_largest_repo, #sort_title_last_joined, #sort_title_latest_activity, #sort_title_milestone, #sort_title_milestone_later, #sort_title_milestone_soon, #sort_title_most_stars, #sort_title_name, #sort_title_name_asc, #sort_title_name_desc, #sort_title_oldest_activity, #sort_title_oldest_created, #sort_title_oldest_joined, #sort_title_oldest_last_activity, #sort_title_oldest_signin, #sort_title_oldest_starred, #sort_title_oldest_updated, #sort_title_popularity, #sort_title_priority, #sort_title_recently_created, #sort_title_recently_last_activity, #sort_title_recently_signin, #sort_title_recently_starred, #sort_title_recently_updated, #sort_title_relative_position, #sort_title_relevant, #sort_title_size, #sort_title_stars, #sort_title_start_date_later, #sort_title_start_date_soon, #sort_title_upvotes, #sort_value_access_level_asc, #sort_value_access_level_desc, #sort_value_contacted_date, #sort_value_created_date, #sort_value_downvotes, #sort_value_due_date, #sort_value_due_date_later, #sort_value_due_date_soon, #sort_value_expire_date, #sort_value_label_priority, #sort_value_largest_group, #sort_value_largest_repo, #sort_value_last_joined, #sort_value_latest_activity, #sort_value_least_popular, #sort_value_milestone, #sort_value_milestone_later, #sort_value_milestone_soon, #sort_value_most_popular, #sort_value_name, #sort_value_name_desc, #sort_value_oldest_activity, #sort_value_oldest_created, #sort_value_oldest_joined, #sort_value_oldest_last_activity, #sort_value_oldest_signin, #sort_value_oldest_updated, #sort_value_popularity, #sort_value_priority, #sort_value_recently_created, #sort_value_recently_last_activity, #sort_value_recently_signin, #sort_value_recently_updated, #sort_value_relative_position, #sort_value_relevant, #sort_value_size, #sort_value_stars_asc, #sort_value_stars_desc, #sort_value_start_date_later, #sort_value_start_date_soon, #sort_value_upvotes, #sortable_item, #starrers_sort_options_hash, #subgroups_sort_options_hash, #tags_sort_options_hash, #users_sort_options_hash

Methods included from ToggleAwardEmoji

#toggle_award_emoji

Methods included from IssuableActions

#bulk_update, #check_destroy_confirmation!, #destroy, #discussions, #realtime_changes, #show, #update

Methods included from ToggleSubscriptionAction

#toggle_subscription

Methods included from RendersNotes

#prepare_notes_for_rendering

Methods included from ChecksCollaboration

#can_collaborate_with_project?, #user_access

Methods included from RoutableActions

#ensure_canonical_path, #find_routable!, #not_found_actions, #perform_not_found_actions, #routable_authorized?

Methods inherited from ApplicationController

#not_found, #redirect_back_or_default, #render, #route_not_found

Methods included from Gitlab::Logging::CloudflareHelper

#store_cloudflare_headers!, #valid_cloudflare_header?

Methods included from Impersonation

#current_user

Methods included from InitializesCurrentUserMode

#current_user_mode

Methods included from Gitlab::Experimentation::ControllerConcern

#experiment_enabled?, #experiment_tracking_category_and_group, #frontend_experimentation_tracking_data, #push_frontend_experiment, #record_experiment_conversion_event, #record_experiment_user, #set_experimentation_subject_id_cookie, #track_experiment_event

Methods included from SessionsHelper

#limit_session_time, #unconfirmed_email?

Methods included from SessionlessAuthentication

#authenticate_sessionless_user!, #sessionless_bypass_admin_mode!, #sessionless_sign_in, #sessionless_user?

Methods included from Gitlab::SearchContext::ControllerConcern

#search_context

Methods included from EnforcesTwoFactorAuthentication

#check_two_factor_requirement, #current_user_requires_two_factor?, #skip_two_factor?, #two_factor_authentication_reason, #two_factor_authentication_required?, #two_factor_grace_period, #two_factor_grace_period_expired?, #two_factor_skippable?, #two_factor_verifier

Methods included from WorkhorseHelper

#send_artifacts_entry, #send_git_archive, #send_git_blob, #send_git_diff, #send_git_patch, #set_workhorse_internal_api_content_type, #workhorse_set_content_type!

Methods included from SafeParamsHelper

#safe_params

Methods included from PageLayoutHelper

#blank_container, #container_class, #favicon, #fluid_layout, #header_title, #nav, #page_canonical_link, #page_card_attributes, #page_card_meta_tags, #page_description, #page_image, #page_itemtype, #page_title, #search_context, #sidebar, #user_status_properties

Methods included from GitlabRoutingHelper

#approve_access_request_group_member_path, #approve_access_request_project_member_path, #artifacts_action_path, #commit_url, #commits_url, #edit_milestone_path, #edit_pipeline_schedule_path, #environment_delete_path, #environment_metrics_path, #environment_path, #expose_fast_artifacts_path, #fast_browse_project_job_artifacts_path, #fast_download_project_job_artifacts_path, #fast_keep_project_job_artifacts_path, #gitlab_dashboard_snippets_path, #gitlab_raw_snippet_blob_path, #gitlab_raw_snippet_blob_url, #gitlab_raw_snippet_path, #gitlab_raw_snippet_url, #gitlab_snippet_note_path, #gitlab_snippet_note_url, #gitlab_snippet_notes_path, #gitlab_snippet_notes_url, #gitlab_snippet_path, #gitlab_snippet_url, #gitlab_toggle_award_emoji_snippet_note_path, #gitlab_toggle_award_emoji_snippet_note_url, #gitlab_toggle_award_emoji_snippet_path, #gitlab_toggle_award_emoji_snippet_url, #group_member_path, #group_members_url, #issue_path, #issue_url, #leave_group_members_path, #leave_project_members_path, #merge_request_path, #merge_request_url, #pipeline_job_url, #pipeline_path, #pipeline_schedule_path, #pipeline_schedules_path, #pipeline_url, #play_pipeline_schedule_path, #preview_markdown_path, #project_commits_path, #project_member_path, #project_members_url, #project_ref_path, #project_tree_path, #release_url, #request_access_group_members_path, #request_access_project_members_path, #resend_invite_group_member_path, #resend_invite_project_member_path, #take_ownership_pipeline_schedule_path, #toggle_award_emoji_personal_snippet_path, #toggle_award_emoji_project_project_snippet_path, #toggle_award_emoji_project_project_snippet_url, #toggle_subscription_path, #wiki_page_path, #wiki_path

Methods included from API::Helpers::RelatedResourcesHelpers

#expose_path, #expose_url, #issues_available?, #mrs_available?

Methods included from Gitlab::NoCacheHeaders

#no_cache_headers

Methods included from Gitlab::GonHelper

#add_gon_variables, #default_avatar_url, #push_frontend_feature_flag, #push_to_gon_features

Methods included from WebpackHelper

#webpack_bundle_tag, #webpack_controller_bundle_tags, #webpack_entrypoint_paths, #webpack_public_host, #webpack_public_path

Methods included from StartupCssHelper

#use_startup_css?

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Projects::ApplicationController

Instance Attribute Details

#vulnerability_idObject

Returns the value of attribute vulnerability_id


76
77
78
# File 'app/controllers/projects/issues_controller.rb', line 76

def vulnerability_id
  @vulnerability_id
end

Instance Method Details

#calendarObject


93
94
95
# File 'app/controllers/projects/issues_controller.rb', line 93

def calendar
  render_issues_calendar(@issuables)
end

#can_create_branchObject


194
195
196
197
198
199
200
201
202
203
204
# File 'app/controllers/projects/issues_controller.rb', line 194

def can_create_branch
  can_create = current_user &&
    can?(current_user, :push_code, @project) &&
    @issue.can_be_worked_on?

  respond_to do |format|
    format.json do
      render json: { can_create_branch: can_create, suggested_branch_name: @issue.suggested_branch_name }
    end
  end
end

#createObject


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
# File 'app/controllers/projects/issues_controller.rb', line 120

def create
  create_params = issue_create_params.merge(spammable_params).merge(
    merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of],
    discussion_to_resolve: params[:discussion_to_resolve]
  )

  service = ::Issues::CreateService.new(project, current_user, create_params)
  @issue = service.execute

  create_vulnerability_issue_link(issue)

  if service.discussions_to_resolve.count(&:resolved?) > 0
    flash[:notice] = if service.discussion_to_resolve_id
                       _("Resolved 1 discussion.")
                     else
                       _("Resolved all discussions.")
                     end
  end

  respond_to do |format|
    format.html do
      recaptcha_check_with_fallback { render :new }
    end
    format.js do
      @link = @issue.attachment.url.to_js
    end
  end
end

#create_merge_requestObject


206
207
208
209
210
211
212
213
214
215
216
# File 'app/controllers/projects/issues_controller.rb', line 206

def create_merge_request
  create_params = params.slice(:branch_name, :ref).merge(issue_iid: issue.iid)
  create_params[:target_project_id] = params[:target_project_id]
  result = ::MergeRequests::CreateFromIssueService.new(project, current_user, create_params).execute

  if result[:status] == :success
    render json: MergeRequestCreateSerializer.new.represent(result[:merge_request])
  else
    render json: result[:message], status: :unprocessable_entity
  end
end

#editObject


116
117
118
# File 'app/controllers/projects/issues_controller.rb', line 116

def edit
  respond_with(@issue)
end

#export_csvObject


218
219
220
221
222
223
224
# File 'app/controllers/projects/issues_controller.rb', line 218

def export_csv
  IssuableExportCsvWorker.perform_async(:issue, current_user.id, project.id, finder_options.to_h) # rubocop:disable CodeReuse/Worker

  index_path = project_issues_path(project)
  message = _('Your CSV export has started. It will be emailed to %{email} when complete.') % { email: current_user.notification_email }
  redirect_to(index_path, notice: message)
end

#import_csvObject


226
227
228
229
230
231
232
233
234
235
236
# File 'app/controllers/projects/issues_controller.rb', line 226

def import_csv
  if uploader = UploadService.new(project, params[:file]).execute
    ImportIssuesCsvWorker.perform_async(current_user.id, project.id, uploader.upload.id) # rubocop:disable CodeReuse/Worker

    flash[:notice] = _("Your issues are being imported. Once finished, you'll get a confirmation email.")
  else
    flash[:alert] = _("File upload error.")
  end

  redirect_to project_issues_path(project)
end

#indexObject


78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'app/controllers/projects/issues_controller.rb', line 78

def index
  @issues = @issuables

  respond_to do |format|
    format.html
    format.atom { render layout: 'xml.atom' }
    format.json do
      render json: {
        html: view_to_html_string("projects/issues/_issues"),
        labels: @labels.as_json(methods: :text_color)
      }
    end
  end
end

#moveObject


149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'app/controllers/projects/issues_controller.rb', line 149

def move
  params.require(:move_to_project_id)

  if params[:move_to_project_id].to_i > 0
    new_project = Project.find(params[:move_to_project_id])
    return render_404 unless issue.can_move?(current_user, new_project)

    @issue = ::Issues::UpdateService.new(project, current_user, target_project: new_project).execute(issue)
  end

  respond_to do |format|
    format.json do
      render_issue_json
    end
  end

rescue ActiveRecord::StaleObjectError
  render_conflict_response
end

#newObject


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'app/controllers/projects/issues_controller.rb', line 97

def new
  params[:issue] ||= ActionController::Parameters.new(
    assignee_ids: ""
  )
  build_params = issue_create_params.merge(
    merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of],
    discussion_to_resolve: params[:discussion_to_resolve],
    confidential: !!Gitlab::Utils.to_boolean(params[:issue][:confidential])
  )
  service = ::Issues::BuildService.new(project, current_user, build_params)

  @issue = @noteable = service.execute

  @merge_request_to_resolve_discussions_of = service.merge_request_to_resolve_discussions_of
  @discussion_to_resolve = service.discussions_to_resolve.first if params[:discussion_to_resolve]

  respond_with(@issue)
end

179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'app/controllers/projects/issues_controller.rb', line 179

def related_branches
  @related_branches = ::Issues::RelatedBranchesService
    .new(project, current_user)
    .execute(issue)
    .map { |branch| branch.merge(link: branch_link(branch)) }

  respond_to do |format|
    format.json do
      render json: {
        html: view_to_html_string('projects/issues/_related_branches')
      }
    end
  end
end

#reorderObject


169
170
171
172
173
174
175
176
177
# File 'app/controllers/projects/issues_controller.rb', line 169

def reorder
  service = ::Issues::ReorderService.new(project, current_user, reorder_params)

  if service.execute(issue)
    head :ok
  else
    head :unprocessable_entity
  end
end

#service_deskObject


238
239
240
241
# File 'app/controllers/projects/issues_controller.rb', line 238

def service_desk
  @issues = @issuables # rubocop:disable Gitlab/ModuleWithInstanceVariables
  @users.push(User.support_bot) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end