Allura API

APIs at SourceForge

URL Endpoints

All url endpoints are prefixed with /rest/ and the path to the project and tool. For example, in order to access a wiki installed in the 'test' project with the mount point 'docs' the API endpoint would be /rest/p/test/docs.

Project

Endpoint: /rest/p/project_name/

  • GET: returns the following fields
    • _id: internal id string
    • name: string
    • shortname: string
    • creation_date: date this project was registered, as a string formatted YYYY-MM-DD
    • url: URL to project
    • summary: one-line string
    • short_description: string
    • external_homepage: URL
    • labels: list of strings
    • private: boolean
    • status: string (active, moved, abandoned, deleted)
    • moved_to_url: URL, if status is "moved"
    • preferred_support_tool: string (corresponding to mount point)
    • preferred_support_url: full URL if preferred_support_tool is set to "_url"
    • socialnetworks: list of dicts having socialnetwork and accounturl values
    • icon_url: URL
    • tools: list of tools installed on the project
      • name: specifies the type of tool
      • label: the label specified by the project admin
      • mount_point: the URL component of the tool. It can be used for constructing further API queries to specific tools, as follows.
    • categories: group of project categorizations (developmentstatus, topic, language, etc) with each individual category containing:
      • fullpath: string, category hierarchy
      • fullname: string, name of category
      • shortname: string, short form of category
      • id: int, unique identifier
    • screenshots
      • url: URL to image
      • caption: string
      • thumbnail_url: URL to smaller thumbnail version of image
    • developers: list of project members
      • url: URL to user profile page
      • name: public full name
      • username: username string

Project DOAP (RDF/XML)

Endpoint: /rest/p/project_name?doap

DOAP is an RDF/XML specification for "Description of a Project"

Project information is available in DOAP format with additional custom RDF fields at /rest/p/project_name?doap

Wiki

Endpoint: /rest/p/project_name/mount_point/

  • GET /rest/p/project_name/mount_point/ - returns a list of page titles
  • GET /rest/p/project_name/mount_point/title - returns a JSON representation of a page
  • POST /rest/p/project_name/mount_point/title - creates or updates the titled page
    • parameter text: page text
    • parameter labels: comma-separated list of page labels

Discussion Forums

Endpoint: /rest/p/project_name/mount_point/

  • GET /rest/p/project_name/mount_point/ - returns a list of forums, including name, description, num_posts, API URL, and last_post details
  • GET /rest/p/project_name/mount_point/forum/ - returns a limited list of topics in the forum, with fields for subject, num_replies, API URL, and last_post
  • GET /rest/p/project_name/mount_point/forum/thread/slug/ - returns a limited list of posts in the thread, with fields for author, text, and timestamp. Nested posts (i.e. a reply to a post) can be determined by the slug structure. For example, "slug": "0a0b/9f00" is a reply to the post with "slug": "0a0b"

To view more than 100 threads, or 100 posts in a thread, use the pagination support of the API by adding ?page=1 etc. to the URL.

Tracker

Endpoint: /rest/p/project_name/mount_point/

  • GET /rest/p/project_name/mount_point/ - returns a list of ticket numbers
  • GET /rest/p/project_name/mount_point/search?q=query - returns search results. Query is same syntax as the non-API ticket search
  • GET /rest/p/project_name/mount_point/number - returns a JSON representation of a ticket
  • POST /rest/p/project_name/mount_point/new - creates a new ticket
    • parameter ticket_form.summary - ticket title
    • parameter ticket_form.description - ticket description
    • parameter ticket_form.status - ticket status
    • parameter ticket_form.assigned_to - username of ticket assignee
    • parameter ticket_form.labels - comma-separated list of ticket labels
    • parameter ticket_form.attachment - (optional) attachment
    • parameter ticket_form.custom field name - custom field value
  • POST /rest/p/project_name/mount_point/number/save - updates an existing ticket
    • parameters are the same as /rest/p/project_name/mount_point/new

Endpoint: /rest/p/project_name/mount_point/_discuss/

  • GET /rest/p/project_name/mount_point/_discuss/ - returns summary information about the tool discussion, including the threads in the discussion (there is one thread per ticket)
  • GET /rest/p/project_name/mount_point/_discuss/thread/thread id/ - returns summary information about a thread, including the posts in a thread
  • GET /rest/p/project_name/mount_point/_discuss/thread/thread id/post slug/ - returns detailed information about a post
  • POST /rest/p/project_name/mount_point/_discuss/thread/thread id/new - create a post in the given thread
    • parameter text - the text of the post
  • POST /rest/p/project_name/mount_point/_discuss/thread/thread id/post slug/reply - create a threaded reply to the given post
    • parameter text - the text of the reply

Blog

Endpoint: /rest/p/project_name/mount_point/

  • GET /rest/p/project_name/mount_point/ - returns a list of posts, including title and API url
  • GET /rest/p/project_name/mount_point/year/month/title - returns a JSON representation of a post
  • POST /rest/p/project_name/mount_point/ - creates a post
    • parameter title - the title of the post
    • parameter text - the text of the post
    • parameter labels - labels of the post
    • parameter state - 'draft' or 'published'
  • POST /rest/p/project_name/mount_point/year/month/title - updates an existing post
    • parameter parameters:
    • parameter title - the title of the post
    • parameter text - the text of the post
    • parameter labels - labels of the post
    • parameter state - 'draft' or 'published'

Endpoint: /rest/p/project_name/mount_point/

  • GET /rest/p/project_name/mount_point/ - returns the url
  • POST /rest/p/project_name/mount_point/ - updates the url (authentication required)
    • parameter url: the url (for example "http://google.com")

Project Export

Endpoint: /rest/p/project_name/admin/export

Generates a full bulk export of your tool(s) in the same format as the API for individual access. Authentication required. An example shell script using these APIs, suitable to run in a cron, is at https://forge-allura.apache.org/p/allura/git/ci/master/tree/scripts/project_export

  • POST /rest/p/project_name/admin/export - submits an export job

    • parameter tools: comma-separated list (or repeated parameter) of tool mount points to export
    • returns
      • 400 Bad Request: tools parameter not provided or is invalid
      • 503 Service Unavailable: an export job is already running
      • 200 OK: job submitted. Body will be: {"status": "in progress", "filename": FILENAME}
  • GET /rest/p/project_name/admin/export_status - check status of a bulk export job

    • returns status: busy or ready

Installing a new Tool

Endpoint: /rest/p/project_name/admin/install_tool

Adds a new tool to the project. Authentication Required.

  • POST /rest/p/project_name/admin/install_tool
    • parameter tool: tool name you want to install (e.g. "tickets")
    • parameter mount_point: tool mount point
    • parameter mount_label: tool mount label
    • parameter order: "first", "last", or "alpha_tool" for position with respect to existing tools (or existing tools of the same type for "alpha_tool")
    • returns dict with two fields:
      • success: False if error is occurred, otherwise True
      • info: success or error message

User

Endpoint: /rest/u/username/

This is a user's personal project, so it contains the same information as a project, although many fields may not be useful. The profile_api_url field is a link to the user's profile endpoint which is documented next.

Endpoint: /rest/u/username/profile

  • GET: returns the following fields
    • username: string
    • name: string
    • joined: date the user joined the site, as a string
    • localization:
      • city: string
      • country: string
    • webpages: list of URL strings
    • socialnetworks: list of:
      • accounturl: URL
      • socialnetwork: string, name of site
    • telnumbers: list of strings
    • skypeaccount: string
    • sex: string
    • skills: list of:
      • comment: string
      • level: "low", "medium" or "high"
      • skill:
        • fullpath: string, category hierarchy
        • fullname: string, name of category
        • shortname: string, short form of category
        • id: int, unique identifier
    • availability: list of:
      • week_day: string, day of week
      • start_time: h integer, m integer
      • end_time: h integer, m integer
    • projects: list of projects the user is part of
      • url: string
      • last_updated: string formatted timestamp
      • name: string
      • summary: string

Authenticating requests

In order to use the API for authenticated actions, you should use the OAuth account page to create a consumer key for your application. Once you have a consumer key, you must have a SourceForge user (e.g. your own account, if you're writing a single script) authorize your application to act on his or her behalf.

You can also use your normal browser session as authentication for the API. This is useful for manually testing API calls or for in-browser applications (such as extensions or user-scripts). It is not recommended for programatic access, however, as it would require you to store your account username and password, and thus cannot be easily managed or revoked.

Without authentication, all API requests have the permissions of an anonymous visitor. To view or change anything that requires a login, you must authenticate to the API using OAuth. You must first register for an OAuth consumer token at https://sourceforge.net/auth/oauth/. Once you have registered, you will be be able to see your consumer key and consumer secret, or generate a bearer token, at https://sourceforge.net/auth/oauth/.

OAuth With Bearer Tokens

The easiest way to use the API with your own account is to use a bearer token. Once you have generated a bearer token at https://sourceforge.net/auth/oauth/, you just include it in the request to the API via the access_token parameter and your requests will be authenticated. Note, however, that to use bearer tokens, you must use HTTPS/SSL for the request.

Simple URL example to access a private ticket:

https://sourceforge.net/rest/p/theproject/tickets/35/?access_token=MY_BEARER_TOKEN

Python code example:

import requests
from pprint import pprint

BEARER_TOKEN = '<bearer token from oauth page>'

r = requests.post('https://sourceforge.net/rest/p/test-project/new', params={
        'access_token': BEARER_TOKEN,
        'ticket_form.summary': 'Test ticket',
        'ticket_form.description': 'This is a test ticket',
        'ticket_form.labels': 'test',
        'ticket_form.custom_fields._my_num': '7',  # custom field with label "My Num"
                                                   # must be created first
    })
if r.status_code == 200:
    print 'Ticket created at: %s' % r.url
    pprint(r.json())
else:
    print 'Error [%s]:\n%s' % (r.status_code, r.text)

OAuth 1.0 Application Authorization (Third-Party Apps)

If you want your application to be able to use the API on behalf of another user, that user must authorize your application to act on their behalf. This is usually accomplished by obtaining a request token and directing the user authorize the request. The following is an example of how one would authorize an application in Python using the python-oauth2 library. First, run pip install oauth2 and pip install certifi.

CONSUMER_KEY = '<consumer key from registration>'
CONSUMER_SECRET = '<consumer secret from registration>'
REQUEST_TOKEN_URL = 'https://sourceforge.net/rest/oauth/request_token'
AUTHORIZE_URL = 'https://sourceforge.net/rest/oauth/authorize'
ACCESS_TOKEN_URL = 'https://sourceforge.net/rest/oauth/access_token'

import oauth2 as oauth  # misleading package name, oauth2 implements OAuth 1.0 spec
import certifi
from urllib2 import urlparse
import webbrowser

consumer = oauth.Consumer(CONSUMER_KEY, CONSUMER_SECRET)
client = oauth.Client(consumer)
client.ca_certs = certifi.where()

# Step 1: Get a request token. This is a temporary token that is used for 
# having the user authorize an access token and to sign the request to obtain 
# said access token.

resp, content = client.request(REQUEST_TOKEN_URL, 'GET')
if resp['status'] != '200':
    raise Exception("Invalid response %s." % resp['status'])

request_token = dict(urlparse.parse_qsl(content))

# these are intermediate tokens and not needed later
#print "Request Token:"
#print "    - oauth_token        = %s" % request_token['oauth_token']
#print "    - oauth_token_secret = %s" % request_token['oauth_token_secret']
#print 

# Step 2: Redirect to the provider. Since this is a CLI script we do not 
# redirect. In a web application you would redirect the user to the URL
# below, specifying the additional parameter oauth_callback=<your callback URL>.

webbrowser.open("%s?oauth_token=%s" % (
        AUTHORIZE_URL, request_token['oauth_token']))

# Since we didn't specify a callback, the user must now enter the PIN displayed in 
# their browser.  If you had specified a callback URL, it would have been called with 
# oauth_token and oauth_verifier parameters, used below in obtaining an access token.
oauth_verifier = raw_input('What is the PIN? ')

# Step 3: Once the consumer has redirected the user back to the oauth_callback
# URL you can request the access token the user has approved. You use the 
# request token to sign this request. After this is done you throw away the
# request token and use the access token returned. You should store this 
# access token somewhere safe, like a database, for future use.
token = oauth.Token(request_token['oauth_token'],
    request_token['oauth_token_secret'])
token.set_verifier(oauth_verifier)
client = oauth.Client(consumer, token)
client.ca_certs = certifi.where()

resp, content = client.request(ACCESS_TOKEN_URL, "GET")
access_token = dict(urlparse.parse_qsl(content))

print "Access Token:"
print "    - oauth_token        = %s" % access_token['oauth_token']
print "    - oauth_token_secret = %s" % access_token['oauth_token_secret']
print
print "You may now access protected resources using the access tokens above." 
print

You can then use your access token with the REST API. For instance script to create a wiki page might look like this:

from urllib import urlencode
import oauth2 as oauth
import certifi

PROJECT='test'

CONSUMER_KEY='<consumer key from app registration>'
CONSUMER_SECRET='<consumer secret from app registration>'

ACCESS_KEY='<access key from previous script>'
ACCESS_SECRET='<access secret from previous script>'

URL_BASE='https://sourceforge.net/rest/'

consumer = oauth.Consumer(CONSUMER_KEY, CONSUMER_SECRET)
access_token = oauth.Token(ACCESS_KEY, ACCESS_SECRET)
client = oauth.Client(consumer, access_token)
client.ca_certs = certifi.where()

response = client.request(
    URL_BASE + 'p/' + PROJECT + '/wiki/TestPage', 'POST',
    body=urlencode(dict(
            text='This is a test page')))
print "Done.  Response was:"
print response

Related

Documentation: API - Beta
Documentation: API
Documentation: Tickets
Documentation: Wiki
Site Support: #3708