Commit 68a087e7 authored by Gilbert Roulot's avatar Gilbert Roulot Committed by Sean McGivern
Browse files

Add License Management API to the backend

parent 63e4129d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -519,6 +519,10 @@
      # its preferable to keep it below all other project routes
      draw :wiki
      draw :repository

      ## EE-specific
      resources :managed_licenses, only: [:index, :show, :new, :create, :edit, :update, :destroy]
      ## EE-specific
    end

    resources(:projects,
+16 −0
Original line number Diff line number Diff line
@@ -2463,6 +2463,20 @@
  add_index "snippets", ["updated_at"], name: "index_snippets_on_updated_at", using: :btree
  add_index "snippets", ["visibility_level"], name: "index_snippets_on_visibility_level", using: :btree

  create_table "software_license_policies", force: :cascade do |t|
    t.integer "project_id", null: false
    t.integer "software_license_id", null: false
    t.integer "approval_status", default: 0, null: false
  end

  add_index "software_license_policies", ["project_id", "software_license_id"], name: "index_software_license_policies_unique_per_project", unique: true, using: :btree

  create_table "software_licenses", force: :cascade do |t|
    t.string "name", null: false
  end

  add_index "software_licenses", ["name"], name: "index_software_licenses_on_name", using: :btree

  create_table "spam_logs", force: :cascade do |t|
    t.integer "user_id"
    t.string "source_ip"
@@ -3021,6 +3035,8 @@
  add_foreign_key "services", "projects", name: "fk_71cce407f9", on_delete: :cascade
  add_foreign_key "slack_integrations", "services", on_delete: :cascade
  add_foreign_key "snippets", "projects", name: "fk_be41fd4bb7", on_delete: :cascade
  add_foreign_key "software_license_policies", "projects", on_delete: :cascade
  add_foreign_key "software_license_policies", "software_licenses", on_delete: :cascade
  add_foreign_key "subscriptions", "projects", on_delete: :cascade
  add_foreign_key "system_note_metadata", "notes", name: "fk_d83a918cb1", on_delete: :cascade
  add_foreign_key "term_agreements", "application_setting_terms", column: "term_id"
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ following locations:
- [Keys](keys.md)
- [Labels](labels.md)
- [License](license.md)
- [Managed licenses](managed_licenses.md) **[ULTIMATE]**
- [Markdown](markdown.md)
- [Merge Requests](merge_requests.md)
- [Merge Request Approvals](merge_request_approvals.md) **[STARTER]**
+136 −0
Original line number Diff line number Diff line
# Managed Licenses API **[ULTIMATE]**

## List managed licenses

Get all managed licenses for a given project.

```
GET /projects/:id/managed_licenses
```

| Attribute | Type    | Required | Description           |
| --------- | ------- | -------- | --------------------- |
| `id`      | integer/string    | yes      | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |

```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/managed_licenses
```

Example response:

```json
[
  {
    "id": 1,
    "name": "MIT",
    "approval_status": "approved"
  },
  {
    "id": 3,
    "name": "ISC",
    "approval_status": "blacklisted"
  }
]
```

## Show an existing managed license

Shows an existing managed license.

```
GET /projects/:id/managed_licenses/:managed_license_id
```

| Attribute       | Type    | Required                          | Description                      |
| --------------- | ------- | --------------------------------- | -------------------------------  |
| `id`      | integer/string    | yes      | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `managed_license_id`      | integer/string    | yes      | The ID or URL-encoded name of the license belonging to the project |

```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/managed_licenses/6"
```

Example response:

```json
{
  "id": 1,
  "name": "MIT",
  "approval_status": "blacklisted"
}
```

## Create a new managed license

Creates a new managed license for the given project with the given name and approval status.

```
POST /projects/:id/managed_licenses
```

| Attribute     | Type    | Required | Description                  |
| ------------- | ------- | -------- | ---------------------------- |
| `id`      | integer/string    | yes      | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `name`        | string  | yes      | The name of the managed license        |
| `approval_status`       | string  | yes      | The approval status. "approved" or "blacklisted" |

```bash
curl --data "name=MIT&approval_status=blacklisted" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/managed_licenses"
```

Example response:

```json
{
  "id": 1,
  "name": "MIT",
  "approval_status": "approved"
}
```

## Delete a managed license

Deletes a managed license with a given id.

```
DELETE /projects/:id/managed_licenses/:managed_license_id
```

| Attribute | Type    | Required | Description           |
| --------- | ------- | -------- | --------------------- |
| `id`      | integer/string    | yes      | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `managed_license_id`      | integer/string    | yes      | The ID or URL-encoded name of the license belonging to the project |

```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/managed_licenses/4"
```

When successful, it replies with an HTTP 204 response. 

## Edit an existing managed license

Updates an existing managed license with a new approval status.

```
PATCH /projects/:id/managed_licenses/:managed_license_id
```

| Attribute       | Type    | Required                          | Description                      |
| --------------- | ------- | --------------------------------- | -------------------------------  |
| `id`      | integer/string    | yes      | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `managed_license_id`      | integer/string    | yes      | The ID or URL-encoded name of the license belonging to the project |
| `approval_status`       | string  | yes      | The approval status. "approved" or "blacklisted" |

```bash
curl --request PATCH --data "approval_status=blacklisted" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/managed_licenses/6"
```

Example response:

```json
{
  "id": 1,
  "name": "MIT",
  "approval_status": "blacklisted"
}
```
+124 −0
Original line number Diff line number Diff line
# frozen_string_literal: true

class Projects::ManagedLicensesController < Projects::ApplicationController
  before_action :software_license_policy, only: [:show, :edit, :update, :destroy]
  before_action :authorize_can_read!, only: [:index, :show]
  before_action :authorize_can_admin!, only: [:new, :create, :edit, :update, :destroy]

  def index
    respond_to do |format|
      format.json do
        render_software_license_policies
      end
    end
  end

  def show
    respond_to do |format|
      format.json do
        render_software_license_policy
      end
    end
  end

  def new
    @software_license_policy = @project.software_license_policies.new
  end

  def create
    result = SoftwareLicensePolicies::CreateService.new(
      @project,
      current_user,
      software_license_policies_params
    ).execute

    if result[:status] == :success
      @software_license_policy = result[:software_license_policy]

      respond_to do |format|
        format.json { render_software_license_policy }
      end
    else
      respond_to do |format|
        format.json { render_error(result[:message], 400) }
      end
    end
  end

  def edit
  end

  def update
    result = SoftwareLicensePolicies::UpdateService.new(
      @project,
      current_user,
      software_license_policies_params
    ).execute(@software_license_policy)

    if result[:status] == :success
      respond_to do |format|
        format.json { render_software_license_policy }
      end
    else
      respond_to do |format|
        format.json { render_error(result[:message], 400) }
      end
    end
  end

  def destroy
    @software_license_policy.destroy!

    respond_to do |format|
      format.json { render_ok }
    end
  end

  private

  def respond_400
    head :bad_request
  end

  # Fetch the existing software license policy when given an id or name
  def software_license_policy
    id = params[:id]
    id = CGI.unescape(id) unless id.is_a?(Integer) || id =~ /^\d+$/
    @software_license_policy ||= SoftwareLicensePoliciesFinder.new(current_user, project).find_by_name_or_id(id)

    if @software_license_policy.nil?
      # The license was not found
      render_404
    end
  end

  def render_ok
    render status: :ok, nothing: true
  end

  def render_software_license_policy
    render status: :ok, json: ManagedLicenseSerializer.new.represent(@software_license_policy)
  end

  def render_software_license_policies
    render status: :ok, json: { software_license_policies: ManagedLicenseSerializer.new.represent(@project.software_license_policies) }
  end

  def render_error(error, status = 400)
    render json: error, status: status
  end

  def software_license_policies_params
    # Require the presence of an hash containing the software license policy fields
    params.require(:managed_license).permit(:name, :approval_status)
  end

  def authorize_can_read!
    render_404 unless can?(current_user, :read_software_license_policy, @project)
  end

  def authorize_can_admin!
    authorize_can_read!
    render_403 unless can?(current_user, :admin_software_license_policy, @project)
  end
end
Loading