BigW Consortium Gitlab

issues.rb 10.8 KB
Newer Older
1
module API
Nihad Abbasov committed
2
  class Issues < Grape::API
3 4
    include PaginationParams

Nihad Abbasov committed
5 6
    before { authenticate! }

7
    helpers do
8 9 10 11 12
      def find_issues(args = {})
        args = params.merge(args)

        args.delete(:id)
        args[:milestone_title] = args.delete(:milestone)
13
        args[:label_name] = args.delete(:labels)
14

15
        issues = IssuesFinder.new(current_user, args).execute
16 17

        issues.reorder(args[:order_by] => args[:sort])
18 19
      end

20 21
      params :issues_params do
        optional :labels, type: String, desc: 'Comma-separated list of label names'
22
        optional :milestone, type: String, desc: 'Milestone title'
23 24 25 26
        optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at',
                            desc: 'Return issues ordered by `created_at` or `updated_at` fields.'
        optional :sort, type: String, values: %w[asc desc], default: 'desc',
                        desc: 'Return issues sorted in `asc` or `desc` order.'
27
        optional :milestone, type: String, desc: 'Return issues for a specific milestone'
28
        optional :iids, type: Array[Integer], desc: 'The IID array of issues'
29
        optional :search, type: String, desc: 'Search issues for text present in the title or description'
30 31
        optional :created_after, type: DateTime, desc: 'Return issues created after the specified time'
        optional :created_before, type: DateTime, desc: 'Return issues created before the specified time'
32 33
        optional :author_id, type: Integer, desc: 'Return issues which are authored by the user with the given ID'
        optional :assignee_id, type: Integer, desc: 'Return issues which are assigned to the user with the given ID'
34
        optional :scope, type: String, values: %w[created-by-me assigned-to-me all],
35
                         desc: 'Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all`'
36 37
        use :pagination
      end
38

39
      params :issue_params_ce do
40
        optional :description, type: String, desc: 'The description of an issue'
41 42
        optional :assignee_ids, type: Array[Integer], desc: 'The array of user IDs to assign issue'
        optional :assignee_id,  type: Integer, desc: '[Deprecated] The ID of a user to assign issue'
43 44
        optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign issue'
        optional :labels, type: String, desc: 'Comma-separated list of label names'
45
        optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY'
46
        optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential'
47
      end
48 49 50 51

      params :issue_params do
        use :issue_params_ce
      end
52 53
    end

Nihad Abbasov committed
54
    resource :issues do
55
      desc "Get currently authenticated user's issues" do
56
        success Entities::IssueBasic
57 58 59 60 61
      end
      params do
        optional :state, type: String, values: %w[opened closed all], default: 'all',
                         desc: 'Return opened, closed, or all issues'
        use :issues_params
62
        optional :scope, type: String, values: %w[created-by-me assigned-to-me all], default: 'created-by-me',
63
                         desc: 'Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all`'
64
      end
Nihad Abbasov committed
65
      get do
66
        issues = find_issues
Sean McGivern committed
67

68
        present paginate(issues), with: Entities::IssueBasic, current_user: current_user
Nihad Abbasov committed
69 70 71
      end
    end

72 73 74
    params do
      requires :id, type: String, desc: 'The ID of a group'
    end
75
    resource :groups, requirements: { id: %r{[^/]+} } do
76
      desc 'Get a list of group issues' do
77
        success Entities::IssueBasic
78 79
      end
      params do
80
        optional :state, type: String, values: %w[opened closed all], default: 'all',
81 82 83
                         desc: 'Return opened, closed, or all issues'
        use :issues_params
      end
84
      get ":id/issues" do
85
        group = find_group!(params[:id])
86

87
        issues = find_issues(group_id: group.id)
Sean McGivern committed
88

89
        present paginate(issues), with: Entities::IssueBasic, current_user: current_user
90 91 92
      end
    end

93 94 95
    params do
      requires :id, type: String, desc: 'The ID of a project'
    end
96
    resource :projects, requirements: { id: %r{[^/]+} } do
97 98
      include TimeTrackingEndpoints

99
      desc 'Get a list of project issues' do
100
        success Entities::IssueBasic
101 102 103 104 105 106
      end
      params do
        optional :state, type: String, values: %w[opened closed all], default: 'all',
                         desc: 'Return opened, closed, or all issues'
        use :issues_params
      end
Nihad Abbasov committed
107
      get ":id/issues" do
108
        project = find_project!(params[:id])
109

110
        issues = find_issues(project_id: project.id)
111

112
        present paginate(issues), with: Entities::IssueBasic, current_user: current_user, project: user_project
Nihad Abbasov committed
113 114
      end

115 116 117 118
      desc 'Get a single project issue' do
        success Entities::Issue
      end
      params do
119
        requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
120
      end
121
      get ":id/issues/:issue_iid", as: :api_v4_project_issue do
122
        issue = find_project_issue(params[:issue_iid])
123
        present issue, with: Entities::Issue, current_user: current_user, project: user_project
Nihad Abbasov committed
124 125
      end

126 127 128 129 130 131 132
      desc 'Create a new project issue' do
        success Entities::Issue
      end
      params do
        requires :title, type: String, desc: 'The title of an issue'
        optional :created_at, type: DateTime,
                              desc: 'Date time when the issue was created. Available only for admins and project owners.'
Bob Van Landuyt committed
133
        optional :merge_request_to_resolve_discussions_of, type: Integer,
134
                                                           desc: 'The IID of a merge request for which to resolve discussions'
135
        optional :discussion_to_resolve, type: String,
Bob Van Landuyt committed
136
                                         desc: 'The ID of a discussion to resolve, also pass `merge_request_to_resolve_discussions_of`'
137 138
        use :issue_params
      end
139
      post ':id/issues' do
140 141 142 143
        # Setting created_at time only allowed for admins and project owners
        unless current_user.admin? || user_project.owner == current_user
          params.delete(:created_at)
        end
144

145
        issue_params = declared_params(include_missing: false)
146

147 148
        issue_params = convert_parameters_from_legacy_format(issue_params)

149 150 151
        issue = ::Issues::CreateService.new(user_project,
                                            current_user,
                                            issue_params.merge(request: request, api: true)).execute
152
        if issue.spam?
153 154
          render_api_error!({ error: 'Spam detected' }, 400)
        end
155

156
        if issue.valid?
157
          present issue, with: Entities::Issue, current_user: current_user, project: user_project
158
        else
159
          render_validation_error!(issue)
Nihad Abbasov committed
160 161 162
        end
      end

163 164 165 166
      desc 'Update an existing issue' do
        success Entities::Issue
      end
      params do
167
        requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
168 169 170
        optional :title, type: String, desc: 'The title of an issue'
        optional :updated_at, type: DateTime,
                              desc: 'Date time when the issue was updated. Available only for admins and project owners.'
171
        optional :state_event, type: String, values: %w[reopen close], desc: 'State of the issue'
172
        use :issue_params
173
        at_least_one_of :title, :description, :assignee_ids, :assignee_id, :milestone_id,
174
                        :labels, :created_at, :due_date, :confidential, :state_event
175
      end
176 177
      put ':id/issues/:issue_iid' do
        issue = user_project.issues.find_by!(iid: params.delete(:issue_iid))
178
        authorize! :update_issue, issue
179

180 181 182 183
        # Setting created_at time only allowed for admins and project owners
        unless current_user.admin? || user_project.owner == current_user
          params.delete(:updated_at)
        end
184

185 186
        update_params = declared_params(include_missing: false).merge(request: request, api: true)

187 188
        update_params = convert_parameters_from_legacy_format(update_params)

189 190
        issue = ::Issues::UpdateService.new(user_project,
                                            current_user,
191 192 193
                                            update_params).execute(issue)

        render_spam_error! if issue.spam?
194

195
        if issue.valid?
196
          present issue, with: Entities::Issue, current_user: current_user, project: user_project
197
        else
198
          render_validation_error!(issue)
Nihad Abbasov committed
199 200 201
        end
      end

202 203 204 205
      desc 'Move an existing issue' do
        success Entities::Issue
      end
      params do
206
        requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
207 208
        requires :to_project_id, type: Integer, desc: 'The ID of the new project'
      end
209 210
      post ':id/issues/:issue_iid/move' do
        issue = user_project.issues.find_by(iid: params[:issue_iid])
211
        not_found!('Issue') unless issue
212

213 214
        new_project = Project.find_by(id: params[:to_project_id])
        not_found!('Project') unless new_project
215 216 217

        begin
          issue = ::Issues::MoveService.new(user_project, current_user).execute(issue, new_project)
218
          present issue, with: Entities::Issue, current_user: current_user, project: user_project
219 220 221 222 223
        rescue ::Issues::MoveService::MoveError => error
          render_api_error!(error.message, 400)
        end
      end

224 225
      desc 'Delete a project issue'
      params do
226
        requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
227
      end
228 229
      delete ":id/issues/:issue_iid" do
        issue = user_project.issues.find_by(iid: params[:issue_iid])
230
        not_found!('Issue') unless issue
231

232
        authorize!(:destroy_issue, issue)
Dmitriy Zaporozhets committed
233
        status 204
234
        issue.destroy
Nihad Abbasov committed
235
      end
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

      desc 'List merge requests closing issue'  do
        success Entities::MergeRequestBasic
      end
      params do
        requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
      end
      get ':id/issues/:issue_iid/closed_by' do
        issue = find_project_issue(params[:issue_iid])

        merge_request_ids = MergeRequestsClosingIssues.where(issue_id: issue).select(:merge_request_id)
        merge_requests = MergeRequestsFinder.new(current_user, project_id: user_project.id).execute.where(id: merge_request_ids)

        present paginate(merge_requests), with: Entities::MergeRequestBasic, current_user: current_user, project: user_project
      end
251 252 253 254 255 256 257 258 259 260 261 262 263 264

      desc 'Get the user agent details for an issue' do
        success Entities::UserAgentDetail
      end
      params do
        requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
      end
      get ":id/issues/:issue_iid/user_agent_detail" do
        authenticated_as_admin!

        issue = find_project_issue(params[:issue_iid])

        return not_found!('UserAgentDetail') unless issue.user_agent_detail

265
        present issue.user_agent_detail, with: Entities::UserAgentDetail
266
      end
Nihad Abbasov committed
267 268 269
    end
  end
end