Repository :
http://git.fedorahosted.org/cgit/copr.git
On branch : master
---------------------------------------------------------------
commit 99528ea80089f17ef9dacd72df4ab9c42fbd1f0f
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Tue Jan 8 11:40:51 2013 +0100
Create the /api/ page providing the API token and information
The API page aims at providing information about the API itself and
how to use it.
Additionally, if you are logged-in, this page gives you your own
API token (needed to call the API), its expiration date (as each
token is valid only 30 days) and a way to generate a new token.
---------------------------------------------------------------
coprs_frontend/coprs/models.py | 3 ++
coprs_frontend/coprs/templates/api.html | 39 +++++++++++++++++++++++++++
coprs_frontend/coprs/views/misc.py | 44 ++++++++++++++++++++++++++++--
3 files changed, 83 insertions(+), 3 deletions(-)
diff --git a/coprs_frontend/coprs/models.py b/coprs_frontend/coprs/models.py
index 69f446e..4429554 100644
--- a/coprs_frontend/coprs/models.py
+++ b/coprs_frontend/coprs/models.py
@@ -54,6 +54,8 @@ class User(db.Model, Serializer):
mail = db.Column(db.String(150), nullable = False)
proven = db.Column(db.Boolean, default = False)
admin = db.Column(db.Boolean, default = False)
+ api_token = db.Column(db.String(40), nullable = False)
+ api_token_expiration = db.Column(db.Date, nullable = False)
@property
def name(self):
@@ -93,6 +95,7 @@ class User(db.Model, Serializer):
def serializable_attributes(self):
return super(User, self).serializable_attributes + ['name']
+
class Copr(db.Model, Serializer):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(100), nullable = False)
diff --git a/coprs_frontend/coprs/templates/api.html
b/coprs_frontend/coprs/templates/api.html
new file mode 100644
index 0000000..fb20f0d
--- /dev/null
+++ b/coprs_frontend/coprs/templates/api.html
@@ -0,0 +1,39 @@
+{% extends "layout.html" %}
+{% block title %}API for Coprs{% endblock %}
+{% block header %}API for the Coprs Build System{% endblock %}
+{% block body %}
+ {% if error %}<p class="error"><strong>Error:</strong> {{
error }}</p>{% endif %}
+
+ <div>
+ <h2>Coprs API</h2>
+
+ <h3> API Token </h3>
+ <p>In order to access the API, you will need to provide an API token.
+ This token is unique, specific to you and <span
style="font-weight:bold;">
+ should not be shared!</span>.
+ </p>
+
+ <p>The API token is valid for 30 days after you generated it, this
+ in order to ensure you are you every 30 days.
+ </p>
+
+ {% if user %}
+ <p>Your information:</p>
+ <pre style="font-size:120%">
+ API token : {{ user.api_token }}
+ Expiration date : {{ user.api_token_expiration }}
+ </pre>
+
+ <a href="{{ url_for('misc.api_new_token') }}">
+ <input type="button" value="Generate a new token" />
+ </a>
+ {% else %}
+ <p style="font-style:italic">You need to be logged in to see you API
token.</p>
+ {% endif %}
+
+ <h3>The API</h3>
+
+ <p>To come here, more information about the API itself.</p>
+
+ </div>
+{% endblock %}
diff --git a/coprs_frontend/coprs/views/misc.py b/coprs_frontend/coprs/views/misc.py
index be4be05..430604d 100644
--- a/coprs_frontend/coprs/views/misc.py
+++ b/coprs_frontend/coprs/views/misc.py
@@ -1,4 +1,7 @@
+import datetime
import functools
+import random
+import string
import flask
@@ -12,6 +15,18 @@ from coprs import oid
misc = flask.Blueprint('misc', __name__)
+def generate_api_token(size=30):
+ """ Generate a random string used as token to access the API
+ remotely.
+
+ :kwarg: size, the size of the token to generate, defaults to 30
+ chars.
+ :return: a string, the API token for the user.
+
+ """
+ return ''.join(random.choice(string.ascii_lowercase) for x in range(size))
+
+
@misc.route('/login/', methods=['GET', 'POST'])
@oid.loginhandler
def login():
@@ -31,13 +46,17 @@ def login():
next=oid.get_next_url(),
error=oid.fetch_error())
-
@oid.after_login
def create_or_login(resp):
flask.session['openid'] = resp.identity_url
- user = models.User.query.filter(models.User.openid_name ==
resp.identity_url).first()
+ user = models.User.query.filter(
+ models.User.openid_name == resp.identity_url).first()
if not user: # create if not created already
- user = models.User(openid_name = resp.identity_url, mail = resp.email)
+ expiration_date_token = datetime.date.today() \
+ + datetime.timedelta(days=30)
+ user = models.User(openid_name = resp.identity_url, mail = resp.email,
+ api_token = generate_api_token(),
+ api_token_expiration = expiration_date_token)
db.session.add(user)
db.session.commit()
flask.flash(u'Welcome, {0}'.format(user.name))
@@ -70,3 +89,22 @@ def backend_authenticated(f):
return 'You have to provide the correct password', 401
return f(*args, **kwargs)
return decorated_function
+
+
+(a)misc.route('/api/')
+def api():
+ return flask.render_template('api.html',
+ user=flask.g.user)
+
+
+(a)misc.route('/api/new')
+@login_required
+def api_new_token():
+ user = flask.g.user
+ user.api_token = generate_api_token()
+ user.api_token_expiration = datetime.date.today() \
+ + datetime.timedelta(days=30)
+ db.session.add(user)
+ db.session.commit()
+ flask.g.user = user
+ return flask.redirect(flask.url_for('misc.api'))