Skip to content
Snippets Groups Projects
Commit 2915bb27 authored by blackst0ne's avatar blackst0ne
Browse files

Add API support for wiki pages

parent 367d3d97
No related branches found
No related tags found
No related merge requests found
---
title: Add API support for wiki pages
merge_request: 13372
author: Vitaliy @blackst0ne Klachkov
type: added
Loading
Loading
@@ -58,6 +58,7 @@ following locations:
- [Validate CI configuration](lint.md)
- [V3 to V4](v3_to_v4.md)
- [Version](version.md)
- [Wikis](wikis.md)
 
## Road to GraphQL
 
Loading
Loading
# Wikis API
> [Introduced][ce-13372] in GitLab 10.0.
Available only in APIv4.
## List wiki pages
Get all wiki pages for a given project.
```
GET /projects/:id/wikis
```
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `with_content` | boolean | no | Include pages' content |
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/wikis?with_content=1
```
Example response:
```json
[
{
"content" : "Here is an instruction how to deploy this project.",
"format" : "markdown",
"slug" : "deploy",
"title" : "deploy"
},
{
"content" : "Our development process is described here.",
"format" : "markdown",
"slug" : "development",
"title" : "development"
},{
"content" : "* [Deploy](deploy)\n* [Development](development)",
"format" : "markdown",
"slug" : "home",
"title" : "home"
}
]
```
## Get a wiki page
Get a wiki page for a given project.
```
GET /projects/:id/wikis/:slug
```
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `slug` | string | yes | The slug (a unique string) of the wiki page |
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/wikis/home
```
Example response:
```json
[
{
"content" : "home page",
"format" : "markdown",
"slug" : "home",
"title" : "home"
}
]
```
## Create a new wiki page
Creates a new wiki page for the given repository with the given title, slug, and content.
```
POST /projects/:id/wikis
```
| Attribute | Type | Required | Description |
| ------------- | ------- | -------- | ---------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `content` | string | yes | The content of the wiki page |
| `title` | string | yes | The title of the wiki page |
| `format` | string | no | The format of the wiki page. Available formats are: `markdown` (default), `rdoc`, and `asciidoc` |
```bash
curl --data "format=rdoc&title=Hello&content=Hello world" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/wikis"
```
Example response:
```json
{
"content" : "Hello world",
"format" : "markdown",
"slug" : "Hello",
"title" : "Hello"
}
```
## Edit an existing wiki page
Updates an existing wiki page. At least one parameter is required to update the wiki page.
```
PUT /projects/:id/wikis/:slug
```
| Attribute | Type | Required | Description |
| --------------- | ------- | --------------------------------- | ------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `content` | string | yes if `title` is not provided | The content of the wiki page |
| `title` | string | yes if `content` is not provided | The title of the wiki page |
| `format` | string | no | The format of the wiki page. Available formats are: `markdown` (default), `rdoc`, and `asciidoc` |
| `slug` | string | yes | The slug (a unique string) of the wiki page |
```bash
curl --request PUT --data "format=rdoc&content=documentation&title=Docs" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/wikis/foo"
```
Example response:
```json
{
"content" : "documentation",
"format" : "markdown",
"slug" : "Docs",
"title" : "Docs"
}
```
## Delete a wiki page
Deletes a wiki page with a given slug.
```
DELETE /projects/:id/wikis/:slug
```
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `slug` | string | yes | The slug (a unique string) of the wiki page |
```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/wikis/foo"
```
On success the HTTP status code is `204` and no JSON response is expected.
Loading
Loading
@@ -143,6 +143,7 @@ module API
mount ::API::Variables
mount ::API::GroupVariables
mount ::API::Version
mount ::API::Wikis
 
route :any, '*path' do
error!('404 Not Found', 404)
Loading
Loading
module API
module Entities
class WikiPageBasic < Grape::Entity
expose :format
expose :slug
expose :title
end
class WikiPage < WikiPageBasic
expose :content
end
class UserSafe < Grape::Entity
expose :name, :username
end
Loading
Loading
Loading
Loading
@@ -35,6 +35,12 @@ module API
@project ||= find_project!(params[:id])
end
 
def wiki_page
page = user_project.wiki.find_page(params[:slug])
page || not_found!('Wiki Page')
end
def available_labels
@available_labels ||= LabelsFinder.new(current_user, project_id: user_project.id).execute
end
Loading
Loading
module API
class Wikis < Grape::API
helpers do
params :wiki_page_params do
requires :content, type: String, desc: 'Content of a wiki page'
requires :title, type: String, desc: 'Title of a wiki page'
optional :format,
type: String,
values: ProjectWiki::MARKUPS.values.map(&:to_s),
default: 'markdown',
desc: 'Format of a wiki page. Available formats are markdown, rdoc, and asciidoc'
end
end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a list of wiki pages' do
success Entities::WikiPageBasic
end
params do
optional :with_content, type: Boolean, default: false, desc: "Include pages' content"
end
get ':id/wikis' do
authorize! :read_wiki, user_project
entity = params[:with_content] ? Entities::WikiPage : Entities::WikiPageBasic
present user_project.wiki.pages, with: entity
end
desc 'Get a wiki page' do
success Entities::WikiPage
end
params do
requires :slug, type: String, desc: 'The slug of a wiki page'
end
get ':id/wikis/:slug' do
authorize! :read_wiki, user_project
present wiki_page, with: Entities::WikiPage
end
desc 'Create a wiki page' do
success Entities::WikiPage
end
params do
use :wiki_page_params
end
post ':id/wikis' do
authorize! :create_wiki, user_project
page = WikiPages::CreateService.new(user_project, current_user, params).execute
if page.valid?
present page, with: Entities::WikiPage
else
render_validation_error!(page)
end
end
desc 'Update a wiki page' do
success Entities::WikiPage
end
params do
use :wiki_page_params
end
put ':id/wikis/:slug' do
authorize! :create_wiki, user_project
page = WikiPages::UpdateService.new(user_project, current_user, params).execute(wiki_page)
if page.valid?
present page, with: Entities::WikiPage
else
render_validation_error!(page)
end
end
desc 'Delete a wiki page'
params do
requires :slug, type: String, desc: 'The slug of a wiki page'
end
delete ':id/wikis/:slug' do
authorize! :admin_wiki, user_project
status 204
WikiPages::DestroyService.new(user_project, current_user).execute(wiki_page)
end
end
end
end
require 'spec_helper'
# For every API endpoint we test 3 states of wikis:
# - disabled
# - enabled only for team members
# - enabled for everyone who has access
# Every state is tested for 3 user roles:
# - guest
# - developer
# - master
# because they are 3 edge cases of using wiki pages.
describe API::Wikis do
let(:user) { create(:user) }
let(:payload) { { content: 'content', format: 'rdoc', title: 'title' } }
let(:expected_keys_with_content) { %w(content format slug title) }
let(:expected_keys_without_content) { %w(format slug title) }
shared_examples_for 'returns list of wiki pages' do
context 'when wiki has pages' do
let!(:pages) do
[create(:wiki_page, wiki: project.wiki, attrs: { title: 'page1', content: 'content of page1' }),
create(:wiki_page, wiki: project.wiki, attrs: { title: 'page2', content: 'content of page2' })]
end
it 'returns the list of wiki pages without content' do
get api(url, user)
expect(response).to have_http_status(200)
expect(json_response.size).to eq(2)
json_response.each_with_index do |page, index|
expect(page.keys).to match_array(expected_keys_without_content)
expect(page['slug']).to eq(pages[index].slug)
expect(page['title']).to eq(pages[index].title)
end
end
it 'returns the list of wiki pages with content' do
get api(url, user), with_content: 1
expect(response).to have_http_status(200)
expect(json_response.size).to eq(2)
json_response.each_with_index do |page, index|
expect(page.keys).to match_array(expected_keys_with_content)
expect(page['content']).to eq(pages[index].content)
expect(page['slug']).to eq(pages[index].slug)
expect(page['title']).to eq(pages[index].title)
end
end
end
it 'return the empty list of wiki pages' do
get api(url, user)
expect(response).to have_http_status(200)
expect(json_response.size).to eq(0)
end
end
shared_examples_for 'returns wiki page' do
it 'returns the wiki page' do
expect(response).to have_http_status(200)
expect(json_response.size).to eq(4)
expect(json_response.keys).to match_array(expected_keys_with_content)
expect(json_response['content']).to eq(page.content)
expect(json_response['slug']).to eq(page.slug)
expect(json_response['title']).to eq(page.title)
end
end
shared_examples_for 'creates wiki page' do
it 'creates the wiki page' do
post(api(url, user), payload)
expect(response).to have_http_status(201)
expect(json_response.size).to eq(4)
expect(json_response.keys).to match_array(expected_keys_with_content)
expect(json_response['content']).to eq(payload[:content])
expect(json_response['slug']).to eq(payload[:title].tr(' ', '-'))
expect(json_response['title']).to eq(payload[:title])
expect(json_response['rdoc']).to eq(payload[:rdoc])
end
[:title, :content].each do |part|
it "responds with validation error on empty #{part}" do
payload.delete(part)
post(api(url, user), payload)
expect(response).to have_http_status(400)
expect(json_response.size).to eq(1)
expect(json_response['error']).to eq("#{part} is missing")
end
end
end
shared_examples_for 'updates wiki page' do
it 'updates the wiki page' do
expect(response).to have_http_status(200)
expect(json_response.size).to eq(4)
expect(json_response.keys).to match_array(expected_keys_with_content)
expect(json_response['content']).to eq(payload[:content])
expect(json_response['slug']).to eq(payload[:title].tr(' ', '-'))
expect(json_response['title']).to eq(payload[:title])
end
end
shared_examples_for '403 Forbidden' do
it 'returns 403 Forbidden' do
expect(response).to have_http_status(403)
expect(json_response.size).to eq(1)
expect(json_response['message']).to eq('403 Forbidden')
end
end
shared_examples_for '404 Wiki Page Not Found' do
it 'returns 404 Wiki Page Not Found' do
expect(response).to have_http_status(404)
expect(json_response.size).to eq(1)
expect(json_response['message']).to eq('404 Wiki Page Not Found')
end
end
shared_examples_for '404 Project Not Found' do
it 'returns 404 Project Not Found' do
expect(response).to have_http_status(404)
expect(json_response.size).to eq(1)
expect(json_response['message']).to eq('404 Project Not Found')
end
end
shared_examples_for '204 No Content' do
it 'returns 204 No Content' do
expect(response).to have_http_status(204)
end
end
describe 'GET /projects/:id/wikis' do
let(:url) { "/projects/#{project.id}/wikis" }
context 'when wiki is disabled' do
let(:project) { create(:project, :wiki_disabled) }
context 'when user is guest' do
before do
get api(url)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
get api(url, user)
end
include_examples '403 Forbidden'
end
context 'when user is master' do
before do
project.add_master(user)
get api(url, user)
end
include_examples '403 Forbidden'
end
end
context 'when wiki is available only for team members' do
let(:project) { create(:project, :wiki_private) }
context 'when user is guest' do
before do
get api(url)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
end
include_examples 'returns list of wiki pages'
end
context 'when user is master' do
before do
project.add_master(user)
end
include_examples 'returns list of wiki pages'
end
end
context 'when wiki is available for everyone with access' do
let(:project) { create(:project) }
context 'when user is guest' do
before do
get api(url)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
end
include_examples 'returns list of wiki pages'
end
context 'when user is master' do
before do
project.add_master(user)
end
include_examples 'returns list of wiki pages'
end
end
end
describe 'GET /projects/:id/wikis/:slug' do
let(:page) { create(:wiki_page, wiki: project.wiki) }
let(:url) { "/projects/#{project.id}/wikis/#{page.slug}" }
context 'when wiki is disabled' do
let(:project) { create(:project, :wiki_disabled) }
context 'when user is guest' do
before do
get api(url)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
get api(url, user)
end
include_examples '403 Forbidden'
end
context 'when user is master' do
before do
project.add_master(user)
get api(url, user)
end
include_examples '403 Forbidden'
end
end
context 'when wiki is available only for team members' do
let(:project) { create(:project, :wiki_private) }
context 'when user is guest' do
before do
get api(url)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
get api(url, user)
end
include_examples 'returns wiki page'
context 'when page is not existing' do
let(:url) { "/projects/#{project.id}/wikis/unknown" }
include_examples '404 Wiki Page Not Found'
end
end
context 'when user is master' do
before do
project.add_master(user)
get api(url, user)
end
include_examples 'returns wiki page'
context 'when page is not existing' do
let(:url) { "/projects/#{project.id}/wikis/unknown" }
include_examples '404 Wiki Page Not Found'
end
end
end
context 'when wiki is available for everyone with access' do
let(:project) { create(:project) }
context 'when user is guest' do
before do
get api(url)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
get api(url, user)
end
include_examples 'returns wiki page'
context 'when page is not existing' do
let(:url) { "/projects/#{project.id}/wikis/unknown" }
include_examples '404 Wiki Page Not Found'
end
end
context 'when user is master' do
before do
project.add_master(user)
get api(url, user)
end
include_examples 'returns wiki page'
context 'when page is not existing' do
let(:url) { "/projects/#{project.id}/wikis/unknown" }
include_examples '404 Wiki Page Not Found'
end
end
end
end
describe 'POST /projects/:id/wikis' do
let(:payload) { { title: 'title', content: 'content' } }
let(:url) { "/projects/#{project.id}/wikis" }
context 'when wiki is disabled' do
let(:project) { create(:project, :wiki_disabled) }
context 'when user is guest' do
before do
post(api(url), payload)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
post(api(url, user), payload)
end
include_examples '403 Forbidden'
end
context 'when user is master' do
before do
project.add_master(user)
post(api(url, user), payload)
end
include_examples '403 Forbidden'
end
end
context 'when wiki is available only for team members' do
let(:project) { create(:project, :wiki_private) }
context 'when user is guest' do
before do
post(api(url), payload)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
end
include_examples 'creates wiki page'
end
context 'when user is master' do
before do
project.add_master(user)
end
include_examples 'creates wiki page'
end
end
context 'when wiki is available for everyone with access' do
let(:project) { create(:project) }
context 'when user is guest' do
before do
post(api(url), payload)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
end
include_examples 'creates wiki page'
end
context 'when user is master' do
before do
project.add_master(user)
end
include_examples 'creates wiki page'
end
end
end
describe 'PUT /projects/:id/wikis/:slug' do
let(:page) { create(:wiki_page, wiki: project.wiki) }
let(:payload) { { title: 'new title', content: 'new content' } }
let(:url) { "/projects/#{project.id}/wikis/#{page.slug}" }
context 'when wiki is disabled' do
let(:project) { create(:project, :wiki_disabled) }
context 'when user is guest' do
before do
put(api(url), payload)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
put(api(url, user), payload)
end
include_examples '403 Forbidden'
end
context 'when user is master' do
before do
project.add_master(user)
put(api(url, user), payload)
end
include_examples '403 Forbidden'
end
end
context 'when wiki is available only for team members' do
let(:project) { create(:project, :wiki_private) }
context 'when user is guest' do
before do
put(api(url), payload)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
put(api(url, user), payload)
end
include_examples 'updates wiki page'
context 'when page is not existing' do
let(:url) { "/projects/#{project.id}/wikis/unknown" }
include_examples '404 Wiki Page Not Found'
end
end
context 'when user is master' do
before do
project.add_master(user)
put(api(url, user), payload)
end
include_examples 'updates wiki page'
context 'when page is not existing' do
let(:url) { "/projects/#{project.id}/wikis/unknown" }
include_examples '404 Wiki Page Not Found'
end
end
end
context 'when wiki is available for everyone with access' do
let(:project) { create(:project) }
context 'when user is guest' do
before do
put(api(url), payload)
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
put(api(url, user), payload)
end
include_examples 'updates wiki page'
context 'when page is not existing' do
let(:url) { "/projects/#{project.id}/wikis/unknown" }
include_examples '404 Wiki Page Not Found'
end
end
context 'when user is master' do
before do
project.add_master(user)
put(api(url, user), payload)
end
include_examples 'updates wiki page'
context 'when page is not existing' do
let(:url) { "/projects/#{project.id}/wikis/unknown" }
include_examples '404 Wiki Page Not Found'
end
end
end
end
describe 'DELETE /projects/:id/wikis/:slug' do
let(:page) { create(:wiki_page, wiki: project.wiki) }
let(:url) { "/projects/#{project.id}/wikis/#{page.slug}" }
context 'when wiki is disabled' do
let(:project) { create(:project, :wiki_disabled) }
context 'when user is guest' do
before do
delete(api(url))
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
delete(api(url, user))
end
include_examples '403 Forbidden'
end
context 'when user is master' do
before do
project.add_master(user)
delete(api(url, user))
end
include_examples '403 Forbidden'
end
end
context 'when wiki is available only for team members' do
let(:project) { create(:project, :wiki_private) }
context 'when user is guest' do
before do
delete(api(url))
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
delete(api(url, user))
end
include_examples '403 Forbidden'
end
context 'when user is master' do
before do
project.add_master(user)
delete(api(url, user))
end
include_examples '204 No Content'
end
end
context 'when wiki is available for everyone with access' do
let(:project) { create(:project) }
context 'when user is guest' do
before do
delete(api(url))
end
include_examples '404 Project Not Found'
end
context 'when user is developer' do
before do
project.add_developer(user)
delete(api(url, user))
end
include_examples '403 Forbidden'
end
context 'when user is master' do
before do
project.add_master(user)
delete(api(url, user))
end
include_examples '204 No Content'
context 'when page is not existing' do
let(:url) { "/projects/#{project.id}/wikis/unknown" }
include_examples '404 Wiki Page Not Found'
end
end
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment