Repository :
http://git.fedorahosted.org/cgit/fedocal.git
On branch : master
---------------------------------------------------------------
commit bbecc0bfd3114c83527138bf7d371c67cd3fe463
Author: Pierre-Yves Chibon <pingou(a)pingoured.fr>
Date: Sun Nov 25 14:52:26 2012 +0100
Move the API from the main controller to its own.
The controller of the API is moved to its own file instead of being in the main
controller.
Fix the tests accordingly, this meant fixing the test configuration file as well as
the
__init__ method.
Adding as well a new meeting (#11) in order to keep the coverage of the API at 100%.
In the meanwhile, change the setUp function for all tests to use scoped_session as in
the application.
---------------------------------------------------------------
fedocal/__init__.py | 168 +---------------------------------
fedocal/api.py | 192 +++++++++++++++++++++++++++++++++++++++
fedocal/tests/__init__.py | 9 ++-
fedocal/tests/fedocal_test.cfg | 4 +-
fedocal/tests/test_flask_api.py | 49 +++++++---
fedocal/tests/test_meeting.py | 14 +++
6 files changed, 257 insertions(+), 179 deletions(-)
diff --git a/fedocal/__init__.py b/fedocal/__init__.py
index 4991e49..470b338 100644
--- a/fedocal/__init__.py
+++ b/fedocal/__init__.py
@@ -40,10 +40,10 @@ import flask
from flask_fas import FAS, cla_plus_one_required
import forms as forms
-import fedocallib as fedocallib
+import fedocal.fedocallib as fedocallib
import fedocallib.dbaction
-from fedocallib.exceptions import FedocalException
-from fedocallib.model import (Calendar, Meeting, Reminder)
+from fedocal.fedocallib.exceptions import FedocalException
+from fedocal.fedocallib.model import (Calendar, Meeting, Reminder)
# Create the application.
APP = flask.Flask(__name__)
@@ -54,6 +54,9 @@ APP.config.from_envvar('FEDOCAL_CONFIG')
SESSION = fedocallib.create_session(APP.config['DB_URL'])
+import fedocal.api
+
+
@APP.context_processor
def inject_calendars():
""" With this decorator we add the list of all the calendars
@@ -458,165 +461,6 @@ def delete_meeting(meeting_id):
title=meeting.meeting_name)
-### API
-
-(a)APP.route('/api/')
-def api():
- """ Display the api information page. """
- auth_form = forms.LoginForm()
- admin = is_admin()
- return flask.render_template('api.html',
- auth_form=auth_form,
- admin=admin)
-
-
-(a)APP.route('/api/date/<calendar_name>/')
-def api_date_default(calendar_name):
- """ Returns all the meetings for the specified calendar for the
- time frame between today - 30 days to today + 180 days.
-
- :arg calendar_name: the name of the calendar to retrieve information
- from.
- """
- startd = datetime.date.today() - datetime.timedelta(days=30)
- endd = datetime.date.today() + datetime.timedelta(days=180)
- meetings = fedocallib.get_meetings_by_date(SESSION, calendar_name,
- startd, endd)
- if not meetings:
- output = '{ "retrieval": "notok", "meeting":
[]}'
- else:
- output = '{ "retrieval": "ok", "meeting":
[\n'
- cnt = 0
- for meeting in meetings:
- output = output + meeting.to_json()
- cnt = cnt + 1
- if cnt != len(meetings):
- output = output + ','
- output = output + '\n]}'
- return flask.Response(output)
-
-
-@APP.route('/api/date/<calendar_name>/<start_date>/<end_date>/')
-def api_date(calendar_name, start_date, end_date):
- """ Returns all the meetings for the specified calendar for the
- specified time frame.
-
- :arg calendar_name: the name of the calendar to retrieve information
- from.
- :arg start_date: the start date of the time frame for which one
- would like to retrieve the meetings.
- :arg end_date: the end date of the time frame for which one would
- like to retrieve the meetings.
- """
- start_date = start_date.split('-')
- end_date = end_date.split('-')
- if len(start_date) != 3 or len(end_date) != 3:
- output = '{ "retrieval": "notok", "meeting":
[], "error": '\
- '"Date format invalid"}'
- return flask.Response(output)
- try:
- start_date = [int(item) for item in start_date]
- end_date = [int(item) for item in end_date]
- startd = datetime.date(start_date[0], start_date[1],
- start_date[2])
- endd = datetime.date(end_date[0], end_date[1], end_date[2])
- except ValueError, error:
- output = '{ "retrieval": "notok", "meeting":
[], "error": '\
- '"Date format invalid: %s"}' % error
- return flask.Response(output)
-
- meetings = fedocallib.get_meetings_by_date(SESSION, calendar_name,
- startd, endd)
- if not meetings:
- output = '{ "retrieval": "notok", "meeting":
[]}'
- else:
- output = '{ "retrieval": "ok", "meeting":
[\n'
- cnt = 0
- for meeting in meetings:
- output = output + meeting.to_json()
- cnt = cnt + 1
- if cnt != len(meetings):
- output = output + ','
- output = output + '\n]}'
- return flask.Response(output)
-
-
-@APP.route('/api/place/<region>/<calendar_name>/')
-def api_place_default(region, calendar_name):
- """ Return all the meetings from an agenda in a specified region.
- The meetings are in the time range from today - 30 days to
- today + 180 days.
-
- :arg region: the name of the region in which the meetings will
- occur.
- :arg calendar_name: the name of the calendar to retrieve information
- from.
- """
- startd = datetime.date.today() - datetime.timedelta(days=30)
- endd = datetime.date.today() + datetime.timedelta(days=180)
- meetings = fedocallib.get_meetings_by_date_and_region(SESSION,
- calendar_name, startd, endd, region)
- if not meetings:
- output = '{ "retrieval": "notok", "meeting":
[]}'
- else:
- output = '{ "retrieval": "ok", "meeting":
[\n'
- cnt = 0
- for meeting in meetings:
- output = output + meeting.to_json()
- cnt = cnt + 1
- if cnt != len(meetings):
- output = output + ','
- output = output + '\n]}'
- return flask.Response(output)
-
-
-@APP.route('/api/place/<region>/<calendar_name>/<start_date>/<end_date>/')
-def api_place(region, calendar_name, start_date, end_date):
- """ Returns all the meetings occuring in a region from an agenda
- and for the specified time frame.
-
- :arg region: the name of the region in which the meetings will
- occur.
- :arg calendar_name: the name of the calendar to retrieve information
- from.
- :arg start_date: the start date of the time frame for which one
- would like to retrieve the meetings.
- :arg end_date: the end date of the time frame for which one would
- like to retrieve the meetings.
- """
- start_date = start_date.split('-')
- end_date = end_date.split('-')
- if len(start_date) != 3 or len(end_date) != 3:
- output = '{ "retrieval": "notok", "meeting":
[], "error": '\
- '"Date format invalid"}'
- return flask.Response(output)
- try:
- start_date = [int(item) for item in start_date]
- end_date = [int(item) for item in end_date]
- startd = datetime.date(start_date[0], start_date[1],
- start_date[2])
- endd = datetime.date(end_date[0], end_date[1], end_date[2])
- except ValueError, error:
- output = '{ "retrieval": "notok", "meeting":
[], "error": '\
- '"Date format invalid: %s"}' % error
- return flask.Response(output)
-
- meetings = fedocallib.get_meetings_by_date_and_region(SESSION,
- calendar_name, startd, endd, region)
- if not meetings:
- output = '{ "retrieval": "notok", "meeting":
[]}'
- else:
- output = '{ "retrieval": "ok", "meeting":
[\n'
- cnt = 0
- for meeting in meetings:
- output = output + meeting.to_json()
- cnt = cnt + 1
- if cnt != len(meetings):
- output = output + ','
- output = output + '\n]}'
- return flask.Response(output)
-
-
if __name__ == '__main__': # pragma: no cover
APP.debug = True
APP.run()
diff --git a/fedocal/api.py b/fedocal/api.py
new file mode 100644
index 0000000..a9dba39
--- /dev/null
+++ b/fedocal/api.py
@@ -0,0 +1,192 @@
+#!/usr/bin/python
+#-*- coding: UTF-8 -*-
+
+"""
+ (c) 2012 - Copyright Pierre-Yves Chibon <pingou(a)pingoured.fr>
+
+ Distributed under License GPLv3 or later
+ You can find a copy of this license on the website
+
http://www.gnu.org/licenses/gpl.html
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+"""
+
+
+import datetime
+import flask
+
+import fedocal.fedocallib as fedocallib
+import fedocal.forms as forms
+
+from fedocal import APP, SESSION
+import fedocal
+
+
+### API
+(a)APP.route('/api/')
+def api():
+ """ Display the api information page. """
+ auth_form = forms.LoginForm()
+ admin = fedocal.is_admin()
+ return flask.render_template('api.html', auth_form=auth_form,
+ admin=admin)
+
+
+(a)APP.route('/api/date/<calendar_name>/')
+def api_date_default(calendar_name):
+ """ Returns all the meetings for the specified calendar for the
+ time frame between today - 30 days to today + 180 days.
+
+ :arg calendar_name: the name of the calendar to retrieve information
+ from.
+ """
+ startd = datetime.date.today() - datetime.timedelta(days=30)
+ endd = datetime.date.today() + datetime.timedelta(days=180)
+ meetings = fedocallib.get_meetings_by_date(SESSION, calendar_name,
+ startd, endd)
+ if not meetings:
+ output = '{ "retrieval": "notok", "meeting":
[]}'
+ else:
+ output = '{ "retrieval": "ok", "meeting":
[\n'
+ cnt = 0
+ for meeting in meetings:
+ output = output + meeting.to_json()
+ cnt = cnt + 1
+ if cnt != len(meetings):
+ output = output + ','
+ output = output + '\n]}'
+ return flask.Response(output)
+
+
+@APP.route('/api/date/<calendar_name>/<start_date>/<end_date>/')
+def api_date(calendar_name, start_date, end_date):
+ """ Returns all the meetings for the specified calendar for the
+ specified time frame.
+
+ :arg calendar_name: the name of the calendar to retrieve information
+ from.
+ :arg start_date: the start date of the time frame for which one
+ would like to retrieve the meetings.
+ :arg end_date: the end date of the time frame for which one would
+ like to retrieve the meetings.
+ """
+ start_date = start_date.split('-')
+ end_date = end_date.split('-')
+ if len(start_date) != 3 or len(end_date) != 3:
+ output = '{ "retrieval": "notok", "meeting":
[], "error": '\
+ '"Date format invalid"}'
+ return flask.Response(output)
+ try:
+ start_date = [int(item) for item in start_date]
+ end_date = [int(item) for item in end_date]
+ startd = datetime.date(start_date[0], start_date[1],
+ start_date[2])
+ endd = datetime.date(end_date[0], end_date[1], end_date[2])
+ except ValueError, error:
+ output = '{ "retrieval": "notok", "meeting":
[], "error": '\
+ '"Date format invalid: %s"}' % error
+ return flask.Response(output)
+
+ meetings = fedocallib.get_meetings_by_date(SESSION, calendar_name,
+ startd, endd)
+ if not meetings:
+ output = '{ "retrieval": "notok", "meeting":
[]}'
+ else:
+ output = '{ "retrieval": "ok", "meeting":
[\n'
+ cnt = 0
+ for meeting in meetings:
+ output = output + meeting.to_json()
+ cnt = cnt + 1
+ if cnt != len(meetings):
+ output = output + ','
+ output = output + '\n]}'
+ return flask.Response(output)
+
+
+@APP.route('/api/place/<region>/<calendar_name>/')
+def api_place_default(region, calendar_name):
+ """ Return all the meetings from an agenda in a specified region.
+ The meetings are in the time range from today - 30 days to
+ today + 180 days.
+
+ :arg region: the name of the region in which the meetings will
+ occur.
+ :arg calendar_name: the name of the calendar to retrieve information
+ from.
+ """
+ startd = datetime.date.today() - datetime.timedelta(days=30)
+ endd = datetime.date.today() + datetime.timedelta(days=180)
+ meetings = fedocallib.get_meetings_by_date_and_region(SESSION,
+ calendar_name, startd, endd, region)
+ if not meetings:
+ output = '{ "retrieval": "notok", "meeting":
[]}'
+ else:
+ output = '{ "retrieval": "ok", "meeting":
[\n'
+ cnt = 0
+ for meeting in meetings:
+ output = output + meeting.to_json()
+ cnt = cnt + 1
+ if cnt != len(meetings):
+ output = output + ','
+ output = output + '\n]}'
+ return flask.Response(output)
+
+
+@APP.route('/api/place/<region>/<calendar_name>/<start_date>/<end_date>/')
+def api_place(region, calendar_name, start_date, end_date):
+ """ Returns all the meetings occuring in a region from an agenda
+ and for the specified time frame.
+
+ :arg region: the name of the region in which the meetings will
+ occur.
+ :arg calendar_name: the name of the calendar to retrieve information
+ from.
+ :arg start_date: the start date of the time frame for which one
+ would like to retrieve the meetings.
+ :arg end_date: the end date of the time frame for which one would
+ like to retrieve the meetings.
+ """
+ start_date = start_date.split('-')
+ end_date = end_date.split('-')
+ if len(start_date) != 3 or len(end_date) != 3:
+ output = '{ "retrieval": "notok", "meeting":
[], "error": '\
+ '"Date format invalid"}'
+ return flask.Response(output)
+ try:
+ start_date = [int(item) for item in start_date]
+ end_date = [int(item) for item in end_date]
+ startd = datetime.date(start_date[0], start_date[1],
+ start_date[2])
+ endd = datetime.date(end_date[0], end_date[1], end_date[2])
+ except ValueError, error:
+ output = '{ "retrieval": "notok", "meeting":
[], "error": '\
+ '"Date format invalid: %s"}' % error
+ return flask.Response(output)
+
+ meetings = fedocallib.get_meetings_by_date_and_region(SESSION,
+ calendar_name, startd, endd, region)
+ if not meetings:
+ output = '{ "retrieval": "notok", "meeting":
[]}'
+ else:
+ output = '{ "retrieval": "ok", "meeting":
[\n'
+ cnt = 0
+ for meeting in meetings:
+ output = output + meeting.to_json()
+ cnt = cnt + 1
+ if cnt != len(meetings):
+ output = output + ','
+ output = output + '\n]}'
+ return flask.Response(output)
diff --git a/fedocal/tests/__init__.py b/fedocal/tests/__init__.py
index a95652a..b3b31b9 100644
--- a/fedocal/tests/__init__.py
+++ b/fedocal/tests/__init__.py
@@ -38,6 +38,10 @@ from datetime import date
from datetime import time
from datetime import timedelta
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import scoped_session
+
sys.path.insert(0, os.path.join(os.path.dirname(
os.path.abspath(__file__)), '..'))
@@ -61,7 +65,10 @@ class Modeltests(unittest.TestCase):
# pylint: disable=C0103
def setUp(self):
""" Set up the environnment, ran before every tests.
"""
- self.session = model.create_tables('sqlite:///%s' % DB_PATH)
+ model.create_tables('sqlite:///%s' % DB_PATH)
+ engine = create_engine('sqlite:///%s' % DB_PATH)
+ scopedsession = scoped_session(sessionmaker(bind=engine))
+ self.session = scopedsession
# pylint: disable=C0103
def tearDown(self):
diff --git a/fedocal/tests/fedocal_test.cfg b/fedocal/tests/fedocal_test.cfg
index 7a8406d..d6d8b22 100644
--- a/fedocal/tests/fedocal_test.cfg
+++ b/fedocal/tests/fedocal_test.cfg
@@ -2,7 +2,9 @@
SECRET_KEY='<The web application secret key>'
### url to the database server:
-DB_URL='sqlite:////tmp/fedocal_dev.sqlite'
+import os
+DB_URL = 'sqlite:///%s/test.db' % (os.path.dirname(os.path.abspath(__file__)))
+#DB_URL='sqlite:////tmp/fedocal_dev.sqlite'
### The FAS group in which the admin of fedocal are
ADMIN_GROUP='packager'
diff --git a/fedocal/tests/test_flask_api.py b/fedocal/tests/test_flask_api.py
index 3849214..5ac90dc 100644
--- a/fedocal/tests/test_flask_api.py
+++ b/fedocal/tests/test_flask_api.py
@@ -61,8 +61,8 @@ class FlaskApitests(Modeltests):
super(FlaskApitests, self).setUp()
fedocal.APP.config['TESTING'] = True
- fedocal.SESSION = fedocallib.create_session(
- 'sqlite:///%s' % DB_PATH)
+ fedocal.APP.config['DB_URL'] = DB_PATH
+ fedocal.SESSION = self.session
self.app = fedocal.APP.test_client()
def test_api(self):
@@ -102,7 +102,7 @@ class FlaskApitests(Modeltests):
output = self.app.get('/api/date/test_calendar4/')
self.assertEqual(output.status_code, 200)
self.assertTrue('"retrieval": "ok"' in output.data)
- self.assertEqual(output.data.count('meeting_name'), 2)
+ self.assertEqual(output.data.count('meeting_name'), 3)
def test_api_date(self):
""" Test the api_date function. """
@@ -134,6 +134,24 @@ class FlaskApitests(Modeltests):
self.assertTrue('"retrieval": "ok"' in output.data)
self.assertEqual(output.data.count('meeting_name'), 2)
+ def test_api_date_error(self):
+ """ Test the api_date function with wrong input.
"""
+ self.__setup_db()
+
+ output = self.app.get('/api/date/test_calendar/%s/2012-09-aw/' %
+ (TODAY))
+ self.assertEqual(output.status_code, 200)
+ self.assertTrue('"retrieval": "notok"' in
output.data)
+ self.assertTrue('"error": "Date format invalid:' in \
+ output.data)
+
+ output = self.app.get('/api/date/test_calendar/%s/2012-09/' %
+ (TODAY))
+ self.assertEqual(output.status_code, 200)
+ self.assertTrue('"retrieval": "notok"' in
output.data)
+ self.assertTrue('"error": "Date format invalid"' in
\
+ output.data)
+
def test_api_place_default(self):
""" Test the api_place_default function. """
output = self.app.get('/api/place/EMEA/foobar')
@@ -159,7 +177,7 @@ class FlaskApitests(Modeltests):
output = self.app.get('/api/place/EMEA/test_calendar4/')
self.assertEqual(output.status_code, 200)
self.assertTrue('"retrieval": "ok"' in output.data)
- self.assertEqual(output.data.count('meeting_name'), 1)
+ self.assertEqual(output.data.count('meeting_name'), 2)
def test_api_place(self):
""" Test the api_place function. """
@@ -208,20 +226,21 @@ class FlaskApitests(Modeltests):
self.assertEqual(output.data,
'{ "retrieval": "notok", "meeting":
[]}')
- def test_api_date_place_error(self):
- """ Test the api_date and api_place functions with wrongly
- formated input. """
- output = self.app.get('/api/date/foobar/2000-01/2000-02/')
+ def test_api_place_error(self):
+ """ Test the api_date function with wrong input.
"""
+ self.__setup_db()
+
+ output = self.app.get('/api/place/EMEA/test_calendar4/%s/2012-12/' % (
+ TODAY))
self.assertEqual(output.status_code, 200)
- self.assertEqual(output.data,
- '{ "retrieval": "notok", "meeting": [],
"error": '\
- '"Date format invalid"}')
+ self.assertTrue('"error": "Date format invalid"' in
\
+ output.data)
- output = self.app.get('/api/place/EMEA/foobar/2000-01/2000-02/')
+ output = self.app.get('/api/place/EMEA/test_calendar4/%s/2012-12-ws/' %
(
+ TODAY))
self.assertEqual(output.status_code, 200)
- self.assertEqual(output.data,
- '{ "retrieval": "notok", "meeting": [],
"error": '\
- '"Date format invalid"}')
+ self.assertTrue('"error": "Date format invalid:' in \
+ output.data)
if __name__ == '__main__':
diff --git a/fedocal/tests/test_meeting.py b/fedocal/tests/test_meeting.py
index 5bd4496..f3ee5ec 100644
--- a/fedocal/tests/test_meeting.py
+++ b/fedocal/tests/test_meeting.py
@@ -211,6 +211,20 @@ class Meetingtests(Modeltests):
self.session.commit()
self.assertNotEqual(obj, None)
+ obj = model.Meeting( # id:11
+ meeting_name='test-meeting-11',
+ meeting_manager='test,',
+ meeting_date=TODAY + timedelta(days=20),
+ meeting_date_end=TODAY + timedelta(days=20),
+ meeting_time_start=time(17, 00),
+ meeting_time_stop=time(18, 00),
+ meeting_information='This is a second test meeting in EMEA',
+ calendar_name='test_calendar4',
+ meeting_region='EMEA')
+ obj.save(self.session)
+ self.session.commit()
+ self.assertNotEqual(obj, None)
+
def test_repr_meeting(self):
""" Test the Meeting string representation function.
"""
self.test_init_meeting()