diff --git a/README.md b/README.md index 27b5d1c..819fd4d 100644 --- a/README.md +++ b/README.md @@ -15,44 +15,44 @@ #### Courses ``` -/courses// +/v0/courses// ``` #### Classes ``` -/class// +/v0/class// ``` #### Lab Status ``` -/lab_status/ +/v0/lab_status/ ``` #### Laundry Status For simple laundry status: ``` -/laundry/simple/ +/v0/laundry/simple/ ``` For detailed laundry status: ``` -/laundry/detailed/ +/v0/laundry/detailed/ ``` #### People ``` -/people/ +/v0/people/ ``` #### Shuttles For shuttle routes: ``` -/shuttle/routes +/v0/shuttle/routes ``` For shuttle vehicle points: ``` -/shuttle/points +/v0/shuttle/points ``` For shuttle arrivals: @@ -68,17 +68,12 @@ For shuttle stop estimates: #### Textbooks If the term is to be specified: ``` -/textbook//// -``` - -If the term is not to be specified: -``` -/textbook/// +/v0/textbook//// ``` #### News ``` -/news// +/v0/news// ``` diff --git a/apiwrapper/PittAPI b/apiwrapper/PittAPI index 13056f1..c1bf27e 160000 --- a/apiwrapper/PittAPI +++ b/apiwrapper/PittAPI @@ -1 +1 @@ -Subproject commit 13056f1ddae2ba3c5d97fa0ba294368bfe98d07b +Subproject commit c1bf27e754607083d609cc6c73195f9fce95fb94 diff --git a/apiwrapper/__init__.py b/apiwrapper/__init__.py new file mode 100644 index 0000000..516fa5d --- /dev/null +++ b/apiwrapper/__init__.py @@ -0,0 +1,30 @@ +""" +Web Wrapper for PittAPI, web app for REST endpoints for the PittAPI +Copyright (C) 2015 Ritwik Gupta + +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 2 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. +""" +from flask import Flask +from flask_cors import CORS + +from apiwrapper.v0 import apiv0_bp + +cors = CORS() + + +def create_app(): + app = Flask(__name__) + cors.init_app(app) + app.register_blueprint(apiv0_bp, url_prefix='/v0') + return app diff --git a/apiwrapper/v0/__init__.py b/apiwrapper/v0/__init__.py new file mode 100644 index 0000000..6a77434 --- /dev/null +++ b/apiwrapper/v0/__init__.py @@ -0,0 +1,26 @@ +""" +Web Wrapper for PittAPI, web app for REST endpoints for the PittAPI +Copyright (C) 2015 Ritwik Gupta + +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 2 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. +""" +from flask import Blueprint +from flask_restful import Api + +from apiwrapper.v0.views import add_resources + +apiv0_bp = Blueprint('rest_api', __name__) +apiv0 = Api(apiv0_bp) + +add_resources() diff --git a/apiwrapper/views.py b/apiwrapper/v0/views.py similarity index 54% rename from apiwrapper/views.py rename to apiwrapper/v0/views.py index 35b72e1..90f7c9e 100644 --- a/apiwrapper/views.py +++ b/apiwrapper/v0/views.py @@ -1,4 +1,4 @@ -''' +""" Web Wrapper for PittAPI, web app for REST endpoints for the PittAPI Copyright (C) 2015 Ritwik Gupta @@ -14,31 +14,18 @@ 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. -''' -from flask import Flask, make_response -from flask_restful import Api, Resource -from flask_cors import CORS, cross_origin -from .PittAPI.PittAPI import course, lab, laundry, people, shuttle, textbook, news -import json +""" +import inspect +import sys -app = Flask(__name__) -CORS(app) -api = Api(app) +from flask_restful import Resource -@api.representation('application/json') -def output_json(data, code, headers=None): - """Makes a Flask response with a JSON encoded body""" - resp = make_response(json.dumps(data), code) - resp.headers.extend(headers or {}) - return resp +from apiwrapper.PittAPI.PittAPI import course, lab, laundry, people, shuttle, textbook, news -@app.errorhandler(404) -def page_not_found(e): - return output_json({'error': 'Invalid request'}, 404) +class CourseGet(Resource): + PATH = '/courses//' - -class CourseGetAPI(Resource): def get(self, term, code): try: return course.get_courses(term, code) @@ -46,7 +33,9 @@ def get(self, term, code): return {'error': str(e)} -class ClassAPI(Resource): +class Class(Resource): + PATH = '/class//' + def get(self, term, class_number): try: return course.get_class(term, class_number) @@ -54,7 +43,9 @@ def get(self, term, class_number): return {'error': str(e)} -class LabStatusAPI(Resource): +class LabStatus(Resource): + PATH = '/lab_status/' + def get(self, lab_name): try: return lab.get_status(lab_name) @@ -62,7 +53,9 @@ def get(self, lab_name): return {'error': str(e)} -class LaundryStatusAPI(Resource): +class LaundryStatus(Resource): + PATH = '/laundry/simple/' + def get(self, location): try: return laundry.get_status_simple(location) @@ -70,7 +63,9 @@ def get(self, location): return {'error': str(e)} -class LaundryStatusDetailedAPI(Resource): +class LaundryStatusDetailed(Resource): + PATH = '/laundry/detailed/' + def get(self, location): try: return laundry.get_status_detailed(location) @@ -78,56 +73,70 @@ def get(self, location): return {'error': str(e)} -class PeopleAPI(Resource): +class People(Resource): + PATH = '/people/' + def get(self, query): try: return people.get_person(query) except Exception as e: return {'error': str(e)} -class TextbookAPI(Resource): + +class Textbook(Resource): + PATH = '/textbook////' + def get(self, department_code, course_name, instructor, term): try: - return textbook.get_books_data([{'department_code': department_code, 'course_name': course_name, 'instructor': instructor, 'term': term}]) + return textbook.get_books_data([{'department_code': department_code, 'course_name': course_name, + 'instructor': instructor, 'term': term}]) except Exception as e: return {'error': str(e)} -class TextbookNoTermAPI(Resource): - def get(self, department_code, course_name, instructor, term='2600'): - try: - return textbook.get_books_data([{'department_code': department_code, 'course_name': course_name, 'instructor': instructor, 'term': term}]) - except Exception as e: - return {'error': str(e)} -class ShuttleRoutesAPI(Resource): +class ShuttleRoutes(Resource): + PATH = '/shuttle/routes' + def get(self): try: return shuttle.get_routes() except Exception as e: return {'error': str(e)} -class ShuttleVehiclePointsAPI(Resource): + +class ShuttleVehiclePoints(Resource): + PATH = '/shuttle/points' + def get(self): try: return shuttle.get_map_vehicle_points() except Exception as e: return {'error': str(e)} -class ShuttleStopArrivalsAPI(Resource): + +class ShuttleStopArrivals(Resource): + PATH = '/shuttle/arrivals/' + def get(self, times_per_stop=1): try: - return shuttle.get_route_stop_arrivals("8882812681",times_per_stop) + return shuttle.get_route_stop_arrivals("8882812681", times_per_stop) except Exception as e: return {'error': str(e)} -class ShuttleStopEstimatesAPI(Resource): + +class ShuttleStopEstimates(Resource): + PATH = '/shuttle/estimates//' + def get(self, vehicle_id, quantity=2): try: return shuttle.get_vehicle_route_stop_estimates(vehicle_id, quantity) except Exception as e: return {'error': str(e)} -class NewsAPI(Resource): + +class News(Resource): + PATH = '/news//' + def get(self, feed, max_news_items): try: max_news_items = int(max_news_items) @@ -136,19 +145,9 @@ def get(self, feed, max_news_items): return {'error': str(e)} -api.add_resource(CourseGetAPI, '/courses//') -api.add_resource(ClassAPI, '/class//') -api.add_resource(LabStatusAPI, '/lab_status/') -api.add_resource(LaundryStatusAPI, '/laundry/simple/') -api.add_resource(LaundryStatusDetailedAPI, '/laundry/detailed/') -api.add_resource(PeopleAPI, '/people/') -api.add_resource(ShuttleRoutesAPI, '/shuttle/routes') -api.add_resource(ShuttleVehiclePointsAPI, '/shuttle/points') -api.add_resource(ShuttleStopArrivalsAPI, '/shuttle/arrivals/') -api.add_resource(ShuttleStopEstimatesAPI, '/shuttle/estimates//') -api.add_resource(TextbookAPI, '/textbook////') -api.add_resource(TextbookNoTermAPI, '/textbook////') -api.add_resource(NewsAPI, '/news//') - -if __name__ is '__main__': - app.run(debug=True, port=8000) +def add_resources(): + from apiwrapper.v0 import apiv0 + clsmembers = inspect.getmembers(sys.modules[__name__], inspect.isclass) + clsmembers = [cls[1] for cls in clsmembers if cls[0] != 'Resource'] + for cls in clsmembers: + apiv0.add_resource(cls, cls.PATH) diff --git a/server.py b/server.py index 056a1b3..dbeb86f 100644 --- a/server.py +++ b/server.py @@ -1,4 +1,4 @@ -''' +""" Web Wrapper for PittAPI, web app for REST endpoints for the PittAPI Copyright (C) 2015 Ritwik Gupta @@ -14,7 +14,8 @@ 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. -''' -from apiwrapper.views import app +""" +from apiwrapper import create_app +app = create_app() app.run(host="0.0.0.0", port=5000) diff --git a/tests/test_api.py b/tests/test_api.py index 133c288..2c2107e 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -16,16 +16,18 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ''' -from apiwrapper.views import app import unittest +from apiwrapper import create_app + + class APITest(unittest.TestCase): def setUp(self): - self.app = app.test_client() + self.app = create_app().test_client() self.app.testing = True def test_lab_status_cath_g62(self): - result = self.app.get("/lab_status/cath_g62") + result = self.app.get("/v0/lab_status/cath_g62") self.assertEqual(result.status_code, 200) self.assertTrue("status" in result.get_data(True))