[PATCH 1/3] Create the /api/ page providing the API token and information

Pierre-Yves Chibon pingou at pingoured.fr
Tue Jan 8 09:25:47 UTC 2013


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(-)
 create mode 100644 coprs_frontend/coprs/templates/api.html

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
+
+
+ at misc.route('/api/')
+def api():
+    return flask.render_template('api.html',
+                                 user=flask.g.user)
+
+
+ at misc.route('/api/new')
+ at 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'))
-- 
1.7.1



More information about the copr-devel mailing list