Browse Source

Did some work on the rest api

sh4nks 10 years ago
parent
commit
2f48b70daa

+ 33 - 0
flaskbb/api/__init__.py

@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+"""
+    flaskbb.api
+    ~~~~~~~~~~~
+
+    The API provides the possibility to get the data in JSON format
+    for the views.
+
+    :copyright: (c) 2015 by the FlaskBB Team.
+    :license: BSD, see LICENSE for more details.
+"""
+from flask import jsonify, make_response
+
+from flask_httpauth import HTTPBasicAuth
+
+from flaskbb.user.models import User
+
+auth = HTTPBasicAuth()
+
+
+@auth.verify_password
+def verify_password(username, password):
+    user, authenticated = User.authenticate(username, password)
+    if user and authenticated:
+        return True
+    return False
+
+
+@auth.error_handler
+def unauthorized():
+    # return 403 instead of 401 to prevent browsers from displaying the default
+    # auth dialog
+    return make_response(jsonify({'message': 'Unauthorized access'}), 403)

+ 137 - 0
flaskbb/api/forums.py

@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+"""
+    flaskbb.api.forums
+    ~~~~~~~~~~~~~~~~~~
+
+    The Forum API.
+    TODO: Permission checks.
+
+    :copyright: (c) 2015 by the FlaskBB Team.
+    :license: BSD, see LICENSE for more details.
+"""
+from datetime import datetime
+
+from flask_restful import Resource, reqparse, fields, marshal, abort
+
+from flaskbb.api import auth
+from flaskbb.forum.models import Category, Forum, Topic, Post
+
+
+class CategoryListAPI(Resource):
+
+    def __init__(self):
+        self.reqparse = reqparse.RequestParser()
+        super(CategoryListAPI, self).__init__()
+
+    def get(self):
+        pass
+
+    @auth.login_required
+    def post(self):
+        pass
+
+
+class CategoryAPI(Resource):
+
+    def __init__(self):
+        self.reqparse = reqparse.RequestParser()
+        super(CategoryAPI, self).__init__()
+
+    def get(self, id):
+        pass
+
+    def put(self, id):
+        pass
+
+    def delete(self, id):
+        pass
+
+
+class ForumListAPI(Resource):
+
+    def __init__(self):
+        self.reqparse = reqparse.RequestParser()
+        super(ForumListAPI, self).__init__()
+
+    def get(self):
+        pass
+
+    @auth.login_required
+    def post(self):
+        pass
+
+
+class ForumAPI(Resource):
+
+    def __init__(self):
+        self.reqparse = reqparse.RequestParser()
+        super(ForumAPI, self).__init__()
+
+    def get(self, id):
+        pass
+
+    def put(self, id):
+        pass
+
+    def delete(self, id):
+        pass
+
+
+class TopicListAPI(Resource):
+
+    def __init__(self):
+        self.reqparse = reqparse.RequestParser()
+        super(TopicListAPI, self).__init__()
+
+    def get(self):
+        pass
+
+    @auth.login_required
+    def post(self):
+        pass
+
+
+class TopicAPI(Resource):
+
+    def __init__(self):
+        self.reqparse = reqparse.RequestParser()
+        super(TopicAPI, self).__init__()
+
+    def get(self, id):
+        pass
+
+    def put(self, id):
+        pass
+
+    def delete(self, id):
+        pass
+
+
+class PostListAPI(Resource):
+
+    def __init__(self):
+        self.reqparse = reqparse.RequestParser()
+        super(PostListAPI, self).__init__()
+
+    def get(self):
+        pass
+
+    @auth.login_required
+    def post(self):
+        pass
+
+
+class PostAPI(Resource):
+
+    def __init__(self):
+        self.reqparse = reqparse.RequestParser()
+        super(PostAPI, self).__init__()
+
+    def get(self, id):
+        pass
+
+    def put(self, id):
+        pass
+
+    def delete(self, id):
+        pass

+ 124 - 0
flaskbb/api/users.py

@@ -0,0 +1,124 @@
+# -*- coding: utf-8 -*-
+"""
+    flaskbb.api.users
+    ~~~~~~~~~~~~~~~~~
+
+    The User API.
+    TODO: Permission checks.
+
+    :copyright: (c) 2015 by the FlaskBB Team.
+    :license: BSD, see LICENSE for more details.
+"""
+from datetime import datetime
+
+from flask_restful import Resource, reqparse, fields, marshal, abort
+
+from flaskbb.api import auth
+from flaskbb.user.models import User
+
+# CREATE NEW USER
+# curl -u test:test1 -i -H "Content-Type: application/json" -X POST -d '{"username":"test6", "password": "test", "email": "test6@example.org"}' http://localhost:8080/api/users
+
+# UPDATE USER
+# curl -u test1:test -i -H "Content-Type: application/json" -X PUT -d '{"email": "test7@example.org"}' http://localhost:8080/api/users/5
+
+# GET USER
+# curl -i http://localhost:8080/api/users
+
+user_fields = {
+    'id': fields.Integer,
+    'username': fields.String,
+    'email': fields.String,
+    'date_joined': fields.DateTime,
+    'lastseen': fields.DateTime,
+    'birthday': fields.DateTime,
+    'gender': fields.String,
+    'website': fields.String,
+    'location': fields.String,
+    'signature': fields.String,
+    'notes': fields.String,
+    'theme': fields.String,
+    'language': fields.String,
+    'post_count': fields.Integer,
+    'primary_group': fields.String(attribute="primary_group.name")
+}
+
+
+class UserListAPI(Resource):
+
+    def __init__(self):
+        self.reqparse = reqparse.RequestParser()
+        self.reqparse.add_argument('username', type=str, required=True,
+                                   location="json")
+        self.reqparse.add_argument('email', type=str, required=True,
+                                   location='json')
+        self.reqparse.add_argument('password', type=str, required=True,
+                                   location='json')
+        self.user_fields = user_fields
+        super(UserListAPI, self).__init__()
+
+    def get(self):
+        users = {'users': [marshal(user, user_fields)
+                           for user in User.query.all()]}
+        return users
+
+    @auth.login_required
+    def post(self):
+        args = self.reqparse.parse_args()
+        user = User(username=args['username'],
+                    password=args['password'],
+                    email=args['email'],
+                    date_joined=datetime.utcnow(),
+                    primary_group_id=4)
+        user.save()
+
+        return {'user': marshal(user, user_fields)}, 201
+
+
+class UserAPI(Resource):
+
+    def __init__(self):
+        self.reqparse = reqparse.RequestParser()
+        self.reqparse.add_argument('email', type=str, location='json')
+        self.reqparse.add_argument('birthday', type=str, location='json')
+        self.reqparse.add_argument('gender', type=str, location='json')
+        self.reqparse.add_argument('website', type=str, location='json')
+        self.reqparse.add_argument('location', type=str, location='json')
+        self.reqparse.add_argument('signature', type=str, location='json')
+        self.reqparse.add_argument('notes', type=str, location='json')
+        self.reqparse.add_argument('theme', type=str, location='json')
+        self.reqparse.add_argument('language', type=str, location='json')
+
+        super(UserAPI, self).__init__()
+
+    def get(self, id):
+        user = User.query.filter_by(id=id).first()
+
+        if not user:
+            abort(404)
+
+        return {'user': marshal(user, user_fields)}
+
+    @auth.login_required
+    def put(self, id):
+        user = User.query.filter_by(id=id).first()
+
+        if not user:
+            abort(404)
+
+        args = self.reqparse.parse_args()
+        for k, v in args.items():
+            if v is not None:
+                setattr(user, k, v)
+        user.save()
+        return {'user': marshal(user, user_fields)}
+
+    @auth.login_required
+    def delete(self, id):
+        user = User.query.filter_by(id=id).first()
+
+        if not user:
+            abort(404)
+
+        user.delete()
+        return {'result': True}

+ 67 - 1
flaskbb/app.py

@@ -32,7 +32,7 @@ from flaskbb.forum.views import forum
 from flaskbb.forum.models import Post, Topic, Category, Forum
 # extensions
 from flaskbb.extensions import db, login_manager, mail, cache, redis_store, \
-    debugtoolbar, migrate, themes, plugin_manager, babel
+    debugtoolbar, migrate, themes, plugin_manager, babel, restful
 # various helpers
 from flaskbb.utils.helpers import format_date, time_since, crop_title, \
     is_online, render_markup, mark_online, forum_is_unread, topic_is_unread, \
@@ -60,6 +60,7 @@ def create_app(config=None):
     # try to update the config via the environment variable
     app.config.from_envvar("FLASKBB_SETTINGS", silent=True)
 
+    configure_api(app)
     configure_blueprints(app)
     configure_extensions(app)
     configure_template_filters(app)
@@ -80,10 +81,75 @@ def configure_blueprints(app):
     )
 
 
+def configure_api(app):
+    from flaskbb.api.users import UserAPI, UserListAPI
+    from flaskbb.api.forums import (CategoryListAPI, CategoryAPI,
+                                    ForumListAPI, ForumAPI,
+                                    TopicListAPI, TopicAPI,
+                                    PostListAPI, PostAPI)
+    # User API
+    restful.add_resource(
+        UserListAPI,
+        "{}/users".format(app.config["API_URL_PREFIX"]),
+        endpoint='tasks'
+    )
+    restful.add_resource(
+        UserAPI,
+        '{}/users/<int:id>'.format(app.config["API_URL_PREFIX"]),
+        endpoint='task'
+    )
+
+    # Forum API
+    restful.add_resource(
+        CategoryListAPI,
+        "{}/categories".format(app.config["API_URL_PREFIX"]),
+        endpoint='categories'
+    )
+    restful.add_resource(
+        CategoryAPI,
+        '{}/categories/<int:id>'.format(app.config["API_URL_PREFIX"]),
+        endpoint='category'
+    )
+    restful.add_resource(
+        ForumListAPI,
+        "{}/forums".format(app.config["API_URL_PREFIX"]),
+        endpoint='forums'
+    )
+    restful.add_resource(
+        ForumAPI,
+        '{}/forums/<int:id>'.format(app.config["API_URL_PREFIX"]),
+        endpoint='forum'
+    )
+    restful.add_resource(
+        TopicListAPI,
+        "{}/topics".format(app.config["API_URL_PREFIX"]),
+        endpoint='topics'
+    )
+    restful.add_resource(
+        TopicAPI,
+        '{}/topics/<int:id>'.format(app.config["API_URL_PREFIX"]),
+        endpoint='topic'
+    )
+    restful.add_resource(
+        PostListAPI,
+        "{}/posts".format(app.config["API_URL_PREFIX"]),
+        endpoint='posts'
+    )
+    restful.add_resource(
+        PostAPI,
+        '{}/posts/<int:id>'.format(app.config["API_URL_PREFIX"]),
+        endpoint='post'
+    )
+
+    # Management API
+
+
 def configure_extensions(app):
     """
     Configures the extensions
     """
+    # Flask-Restful
+    restful.init_app(app)
 
     # Flask-Plugins
     plugin_manager.init_app(app)

+ 1 - 0
flaskbb/configs/default.py

@@ -88,3 +88,4 @@ class DefaultConfig(object):
     USER_URL_PREFIX = "/user"
     AUTH_URL_PREFIX = "/auth"
     ADMIN_URL_PREFIX = "/admin"
+    API_URL_PREFIX = "/api"

+ 2 - 1
flaskbb/configs/production.py.example

@@ -85,8 +85,9 @@ class ProductionConfig(DefaultConfig):
     REDIS_URL = "redis://:password@localhost:6379"
     REDIS_DATABASE = 0
 
-    # URL Prefixes.
+    # URL Prefixes. Only change it when you know what you are doing.
     FORUM_URL_PREFIX = ""
     USER_URL_PREFIX = "/user"
     AUTH_URL_PREFIX = "/auth"
     ADMIN_URL_PREFIX = "/admin"
+    API_URL_PREFIX = "/api"

+ 7 - 0
flaskbb/extensions.py

@@ -18,6 +18,9 @@ from flask_migrate import Migrate
 from flask_themes2 import Themes
 from flask_plugins import PluginManager
 from flask_babelex import Babel
+from flask_restful import Api
+from flask_httpauth import HTTPBasicAuth
+
 
 # Database
 db = SQLAlchemy()
@@ -48,3 +51,7 @@ plugin_manager = PluginManager()
 
 # Babel
 babel = Babel()
+
+# Flask-Restful with Auth
+restful = Api()
+auth = HTTPBasicAuth()

+ 1 - 1
flaskbb/templates/forum/forum.html

@@ -114,7 +114,7 @@
         {% else %}
         <tr>
             <td colspan="5">
-                {% trans %}No topics.{% endtrans %}
+                {% trans %}No Topics.{% endtrans %}
             </td>
         </tr>
         {% endfor %}