BigW Consortium Gitlab

issues.rb 7.49 KB
Newer Older
1
module API
Nihad Abbasov committed
2 3 4 5
  # Issues API
  class Issues < Grape::API
    before { authenticate! }

6 7
    helpers ::Gitlab::AkismetHelper

8
    helpers do
9
      def filter_issues_state(issues, state)
10
        case state
11 12
        when 'opened' then issues.opened
        when 'closed' then issues.closed
13
        else issues
14 15
        end
      end
16 17

      def filter_issues_labels(issues, labels)
18 19 20 21 22
        issues.includes(:labels).where('labels.title' => labels.split(','))
      end

      def filter_issues_milestone(issues, milestone)
        issues.includes(:milestone).where('milestones.title' => milestone)
23
      end
24 25

      def create_spam_log(project, current_user, attrs)
26 27 28 29 30 31 32
        params = attrs.merge({
          source_ip: env['REMOTE_ADDR'],
          user_agent: env['HTTP_USER_AGENT'],
          noteable_type: 'Issue',
          via_api: true
        })

33 34
        ::CreateSpamLogService.new(project, current_user, params).execute
      end
35 36
    end

Nihad Abbasov committed
37 38 39
    resource :issues do
      # Get currently authenticated user's issues
      #
40 41
      # Parameters:
      #   state (optional) - Return "opened" or "closed" issues
42
      #   labels (optional) - Comma-separated list of label names
43 44 45
      #   order_by (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
      #   sort (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
      #
46
      # Example Requests:
Nihad Abbasov committed
47
      #   GET /issues
48 49
      #   GET /issues?state=opened
      #   GET /issues?state=closed
50 51 52
      #   GET /issues?labels=foo
      #   GET /issues?labels=foo,bar
      #   GET /issues?labels=foo,bar&state=opened
Nihad Abbasov committed
53
      get do
54 55 56
        issues = current_user.issues
        issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
        issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
57
        issues.reorder(issuable_order_by => issuable_sort)
58
        present paginate(issues), with: Entities::Issue
Nihad Abbasov committed
59 60 61 62 63 64 65
      end
    end

    resource :projects do
      # Get a list of project issues
      #
      # Parameters:
66
      #   id (required) - The ID of a project
67
      #   iid (optional) - Return the project issue having the given `iid`
68
      #   state (optional) - Return "opened" or "closed" issues
69
      #   labels (optional) - Comma-separated list of label names
70
      #   milestone (optional) - Milestone title
71 72
      #   order_by (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
      #   sort (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
73 74
      #
      # Example Requests:
Nihad Abbasov committed
75
      #   GET /projects/:id/issues
76 77
      #   GET /projects/:id/issues?state=opened
      #   GET /projects/:id/issues?state=closed
78 79 80
      #   GET /projects/:id/issues?labels=foo
      #   GET /projects/:id/issues?labels=foo,bar
      #   GET /projects/:id/issues?labels=foo,bar&state=opened
81 82
      #   GET /projects/:id/issues?milestone=1.0.0
      #   GET /projects/:id/issues?milestone=1.0.0&state=closed
83
      #   GET /issues?iid=42
Nihad Abbasov committed
84
      get ":id/issues" do
85 86 87
        issues = user_project.issues
        issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
        issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
88
        issues = filter_by_iid(issues, params[:iid]) unless params[:iid].nil?
89

90 91 92
        unless params[:milestone].nil?
          issues = filter_issues_milestone(issues, params[:milestone])
        end
93

94
        issues.reorder(issuable_order_by => issuable_sort)
95
        present paginate(issues), with: Entities::Issue
Nihad Abbasov committed
96 97 98 99 100
      end

      # Get a single project issue
      #
      # Parameters:
101
      #   id (required) - The ID of a project
Nihad Abbasov committed
102 103 104 105 106
      #   issue_id (required) - The ID of a project issue
      # Example Request:
      #   GET /projects/:id/issues/:issue_id
      get ":id/issues/:issue_id" do
        @issue = user_project.issues.find(params[:issue_id])
107
        present @issue, with: Entities::Issue
Nihad Abbasov committed
108 109 110 111 112
      end

      # Create a new project issue
      #
      # Parameters:
113
      #   id (required) - The ID of a project
Nihad Abbasov committed
114 115 116 117 118 119 120 121
      #   title (required) - The title of an issue
      #   description (optional) - The description of an issue
      #   assignee_id (optional) - The ID of a user to assign issue
      #   milestone_id (optional) - The ID of a milestone to assign issue
      #   labels (optional) - The labels of an issue
      # Example Request:
      #   POST /projects/:id/issues
      post ":id/issues" do
122 123
        required_attributes! [:title]
        attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id]
124

125
        # Validate label names in advance
126 127
        if (errors = validate_label_params(params)).any?
          render_api_error!({ labels: errors }, 400)
128 129
        end

130
        project = user_project
131
        text = [attrs[:title], attrs[:description]].reject(&:blank?).join("\n")
132 133 134 135 136 137 138

        if check_for_spam?(project, current_user) && is_spam?(env, current_user, text)
          create_spam_log(project, current_user, attrs)
          render_api_error!({ error: 'Spam detected' }, 400)
        end

        issue = ::Issues::CreateService.new(project, current_user, attrs).execute
139 140

        if issue.valid?
141 142
          # Find or create labels and attach to issue. Labels are valid because
          # we already checked its name, so there can't be an error here
143
          if params[:labels].present?
144
            issue.add_labels_by_names(params[:labels].split(','))
145 146
          end

147 148
          present issue, with: Entities::Issue
        else
149
          render_validation_error!(issue)
Nihad Abbasov committed
150 151 152 153 154 155
        end
      end

      # Update an existing issue
      #
      # Parameters:
156
      #   id (required) - The ID of a project
Nihad Abbasov committed
157 158 159 160 161 162
      #   issue_id (required) - The ID of a project issue
      #   title (optional) - The title of an issue
      #   description (optional) - The description of an issue
      #   assignee_id (optional) - The ID of a user to assign issue
      #   milestone_id (optional) - The ID of a milestone to assign issue
      #   labels (optional) - The labels of an issue
163
      #   state_event (optional) - The state event of an issue (close|reopen)
Nihad Abbasov committed
164 165 166
      # Example Request:
      #   PUT /projects/:id/issues/:issue_id
      put ":id/issues/:issue_id" do
167
        issue = user_project.issues.find(params[:issue_id])
168
        authorize! :update_issue, issue
169 170
        attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event]

171
        # Validate label names in advance
172 173
        if (errors = validate_label_params(params)).any?
          render_api_error!({ labels: errors }, 400)
174 175
        end

176
        issue = ::Issues::UpdateService.new(user_project, current_user, attrs).execute(issue)
177

178
        if issue.valid?
179 180
          # Find or create labels and attach to issue. Labels are valid because
          # we already checked its name, so there can't be an error here
181
          if params[:labels] && can?(current_user, :admin_issue, user_project)
182
            issue.remove_labels
183 184
            # Create and add labels to the new created issue
            issue.add_labels_by_names(params[:labels].split(','))
185 186
          end

187 188
          present issue, with: Entities::Issue
        else
189
          render_validation_error!(issue)
Nihad Abbasov committed
190 191 192
        end
      end

193
      # Delete a project issue (deprecated)
Nihad Abbasov committed
194 195
      #
      # Parameters:
196
      #   id (required) - The ID of a project
Nihad Abbasov committed
197 198 199 200
      #   issue_id (required) - The ID of a project issue
      # Example Request:
      #   DELETE /projects/:id/issues/:issue_id
      delete ":id/issues/:issue_id" do
201
        not_allowed!
Nihad Abbasov committed
202 203 204 205
      end
    end
  end
end