issues_controller.rb 7.8 KB
Newer Older
1
class Projects::IssuesController < Projects::ApplicationController
D
Douwe Maan 已提交
2
  include RendersNotes
3
  include ToggleSubscriptionAction
4
  include IssuableActions
5
  include ToggleAwardEmoji
6
  include IssuableCollections
7
  include SpammableActions
8

9 10
  prepend_before_action :authenticate_user!, only: [:new]

11
  before_action :redirect_to_external_issue_tracker, only: [:index, :new]
12
  before_action :module_enabled
13
  before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests,
R
Regis Boudinot 已提交
14
                               :related_branches, :can_create_branch, :rendered_title]
R
randx 已提交
15

D
Dmitriy Zaporozhets 已提交
16
  # Allow read any issue
R
Regis Boudinot 已提交
17
  before_action :authorize_read_issue!, only: [:show, :rendered_title]
D
Dmitriy Zaporozhets 已提交
18 19

  # Allow write(create) issue
D
Dmitriy Zaporozhets 已提交
20
  before_action :authorize_create_issue!, only: [:new, :create]
D
Dmitriy Zaporozhets 已提交
21 22

  # Allow modify issue
D
Dmitriy Zaporozhets 已提交
23
  before_action :authorize_update_issue!, only: [:edit, :update]
D
Dmitriy Zaporozhets 已提交
24

D
Dmitriy Zaporozhets 已提交
25
  respond_to :html
G
gitlabhq 已提交
26 27

  def index
28 29 30
    @collection_type    = "Issue"
    @issues             = issues_collection
    @issues             = @issues.page(params[:page])
31
    @issuable_meta_data = issuable_meta_data(@issues, @collection_type)
32

33
    if @issues.out_of_range? && @issues.total_pages != 0
34
      return redirect_to url_for(params.merge(page: @issues.total_pages, only_path: true))
35
    end
36

37
    if params[:label_name].present?
38 39
      @labels = LabelsFinder.new(current_user, project_id: @project.id, title: params[:label_name]).execute
    end
G
gitlabhq 已提交
40

41 42 43 44 45 46 47 48 49 50 51 52
    @users = []

    if params[:assignee_id].present?
      assignee = User.find_by_id(params[:assignee_id])
      @users.push(assignee) if assignee
    end

    if params[:author_id].present?
      author = User.find_by_id(params[:author_id])
      @users.push(author) if author
    end

G
gitlabhq 已提交
53
    respond_to do |format|
D
Dmitriy Zaporozhets 已提交
54
      format.html
55
      format.atom { render layout: false }
D
Dmitriy Zaporozhets 已提交
56 57
      format.json do
        render json: {
58
          html: view_to_html_string("projects/issues/_issues"),
P
Phil Hughes 已提交
59
          labels: @labels.as_json(methods: :text_color)
D
Dmitriy Zaporozhets 已提交
60 61
        }
      end
G
gitlabhq 已提交
62 63 64 65
    end
  end

  def new
66 67 68
    params[:issue] ||= ActionController::Parameters.new(
      assignee_id: ""
    )
69
    build_params = issue_params.merge(
B
Bob Van Landuyt 已提交
70
      merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of],
71
      discussion_to_resolve: params[:discussion_to_resolve]
72
    )
73
    service = Issues::BuildService.new(project, current_user, build_params)
74

75
    @issue = @noteable = service.execute
B
Bob Van Landuyt 已提交
76
    @merge_request_to_resolve_discussions_of = service.merge_request_to_resolve_discussions_of
77
    @discussion_to_resolve = service.discussions_to_resolve.first if params[:discussion_to_resolve]
78

G
gitlabhq 已提交
79 80 81 82 83 84 85 86
    respond_with(@issue)
  end

  def edit
    respond_with(@issue)
  end

  def show
87
    @noteable = @issue
88
    @note     = @project.notes.new(noteable: @issue)
G
gitlabhq 已提交
89

90 91
    @discussions = @issue.discussions
    @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
92

93 94 95
    respond_to do |format|
      format.html
      format.json do
96
        render json: IssueSerializer.new.represent(@issue)
97 98
      end
    end
G
gitlabhq 已提交
99 100 101
  end

  def create
102
    create_params = issue_params.merge(spammable_params).merge(
B
Bob Van Landuyt 已提交
103
      merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of],
104 105 106
      discussion_to_resolve: params[:discussion_to_resolve]
    )

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

110
    if service.discussions_to_resolve.count(&:resolved?) > 0
111
      flash[:notice] = if service.discussion_to_resolve_id
112 113 114 115
                         "Resolved 1 discussion."
                       else
                         "Resolved all discussions."
                       end
116
    end
G
gitlabhq 已提交
117

118
    respond_to do |format|
119
      format.html do
120
        recaptcha_check_with_fallback { render :new }
121
      end
122
      format.js do
123 124
        @link = @issue.attachment.url.to_js
      end
125
    end
G
gitlabhq 已提交
126 127 128
  end

  def update
129 130 131
    update_params = issue_params.merge(spammable_params)

    @issue = Issues::UpdateService.new(project, current_user, update_params).execute(issue)
G
gitlabhq 已提交
132

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

137
      move_service = Issues::MoveService.new(project, current_user)
138
      @issue = move_service.execute(@issue, new_project)
139
    end
G
gitlabhq 已提交
140 141

    respond_to do |format|
142
      format.html do
143
        recaptcha_check_with_fallback { render :edit }
144
      end
145

146
      format.json do
147 148 149 150 151 152 153 154
        if @issue.valid?
          render json: @issue.to_json(methods: [:task_status, :task_status_short],
                                      include: { milestone: {},
                                                 assignee: { only: [:name, :username], methods: [:avatar_url] },
                                                 labels: { methods: :text_color } })
        else
          render json: { errors: @issue.errors.full_messages }, status: :unprocessable_entity
        end
155
      end
G
gitlabhq 已提交
156
    end
157 158

  rescue ActiveRecord::StaleObjectError
159
    render_conflict_response
G
gitlabhq 已提交
160 161
  end

162 163 164 165 166 167 168 169 170 171 172 173 174 175
  def referenced_merge_requests
    @merge_requests = @issue.referenced_merge_requests(current_user)
    @closed_by_merge_requests = @issue.closed_by_merge_requests(current_user)

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

  def related_branches
176
    @related_branches = @issue.related_branches(current_user)
177 178 179 180 181 182 183 184 185 186

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

187 188 189 190 191 192 193 194 195 196 197 198
  def can_create_branch
    can_create = current_user &&
      can?(current_user, :push_code, @project) &&
      @issue.can_be_worked_on?(current_user)

    respond_to do |format|
      format.json do
        render json: { can_create_branch: can_create }
      end
    end
  end

R
Regis Boudinot 已提交
199 200 201 202 203
  def rendered_title
    Gitlab::PollingInterval.set_header(response, interval: 3_000)
    render json: { title: view_context.markdown_field(@issue, :title) }
  end

N
Nihad Abbasov 已提交
204
  protected
G
gitlabhq 已提交
205 206

  def issue
207 208
    # The Sortable default scope causes performance issues when used with find_by
    @noteable = @issue ||= @project.issues.where(iid: params[:id]).reorder(nil).take || redirect_old
G
gitlabhq 已提交
209
  end
210
  alias_method :subscribable_resource, :issue
211
  alias_method :issuable, :issue
212
  alias_method :awardable, :issue
213
  alias_method :spammable, :issue
D
Dmitriy Zaporozhets 已提交
214

215 216 217 218
  def authorize_read_issue!
    return render_404 unless can?(current_user, :read_issue, @issue)
  end

D
Dmitriy Zaporozhets 已提交
219
  def authorize_update_issue!
220
    return render_404 unless can?(current_user, :update_issue, @issue)
D
Dmitriy Zaporozhets 已提交
221 222
  end

D
Dmitriy Zaporozhets 已提交
223 224
  def authorize_admin_issues!
    return render_404 unless can?(current_user, :admin_issue, @project)
D
Dmitriy Zaporozhets 已提交
225
  end
226 227

  def module_enabled
F
Felipe Artur 已提交
228
    return render_404 unless @project.feature_available?(:issues, current_user) && @project.default_issues_tracker?
229
  end
230

231
  def redirect_to_external_issue_tracker
232
    external = @project.external_issue_tracker
233

234 235 236 237 238
    return unless external

    if action_name == 'new'
      redirect_to external.new_issue_path
    else
239
      redirect_to external.project_path
240
    end
241 242
  end

243 244 245 246 247 248
  # Since iids are implemented only in 6.1
  # user may navigate to issue page using old global ids.
  #
  # To prevent 404 errors we provide a redirect to correct iids until 7.0 release
  #
  def redirect_old
S
skv 已提交
249
    issue = @project.issues.find_by(id: params[:id])
250 251

    if issue
252
      redirect_to issue_path(issue)
253 254 255 256
    else
      raise ActiveRecord::RecordNotFound.new
    end
  end
257 258

  def issue_params
259
    params.require(:issue).permit(
260
      :title, :assignee_id, :position, :description, :confidential,
261
      :milestone_id, :due_date, :state_event, :task_num, :lock_version, label_ids: []
262 263
    )
  end
264 265 266 267 268 269 270 271 272

  def authenticate_user!
    return if current_user

    notice = "Please sign in to create the new issue."

    store_location_for :user, request.fullpath
    redirect_to new_user_session_path, notice: notice
  end
G
gitlabhq 已提交
273
end