[odrs-web/production] Move to a more flask-like project layout



commit b5a53727d9ad00acb123407ebd41065f9c848d69
Author: Richard Hughes <richard hughsie com>
Date:   Thu Jul 6 12:25:05 2017 +0100

    Move to a more flask-like project layout

 app/__init__.py                               |   37 ++++++++
 database.py => app/db.py                      |   32 ++++----
 app/models.py                                 |   61 +++++++++++++
 {static => app/static}/Chart.js               |    0
 {static => app/static}/app-page.png           |  Bin 94032 -> 94032 bytes
 {static => app/static}/bar.png                |  Bin 154 -> 154 bytes
 {static => app/static}/favicon.ico            |  Bin 2550 -> 2550 bytes
 {static => app/static}/foot.png               |  Bin 699 -> 699 bytes
 {static => app/static}/general_bg.png         |  Bin 178 -> 178 bytes
 {static => app/static}/general_separator.png  |  Bin 212 -> 212 bytes
 {static => app/static}/gnome-16.png           |  Bin 650 -> 650 bytes
 {static => app/static}/gnome-odrs.png         |  Bin 14485 -> 14485 bytes
 {static => app/static}/layout.css             |    0
 {static => app/static}/review-submit.png      |  Bin 25010 -> 25010 bytes
 {static => app/static}/search-icon.png        |  Bin 395 -> 395 bytes
 {static => app/static}/style.css              |    0
 {static => app/static}/t.png                  |  Bin 317 -> 317 bytes
 {static => app/static}/top_bar-bg.png         |  Bin 185 -> 185 bytes
 {templates => app/templates}/default.html     |    1 -
 {templates => app/templates}/delete.html      |    0
 {templates => app/templates}/distros.html     |    0
 {templates => app/templates}/error.html       |    0
 {templates => app/templates}/graph-month.html |    0
 {templates => app/templates}/graph-year.html  |    0
 {templates => app/templates}/index.html       |    0
 {templates => app/templates}/login.html       |    0
 {templates => app/templates}/oars.html        |    0
 {templates => app/templates}/show-all.html    |    0
 {templates => app/templates}/show.html        |    0
 {templates => app/templates}/stats.html       |    0
 {templates => app/templates}/users.html       |    0
 api10.py => app/views.py                      |  117 +++++++++++++++---------
 admin.py => app/views_admin.py                |  116 ++++++++++---------------
 event.py                                      |   15 ---
 flaskapp.py                                   |   74 +---------------
 odrs.wsgi                                     |    2 +-
 review.py                                     |   23 -----
 user.py                                       |   31 -------
 38 files changed, 236 insertions(+), 273 deletions(-)
---
diff --git a/app/__init__.py b/app/__init__.py
new file mode 100644
index 0000000..71d2920
--- /dev/null
+++ b/app/__init__.py
@@ -0,0 +1,37 @@
+#!/usr/bin/python2
+# -*- coding: utf-8 -*-
+#
+# pylint: disable=invalid-name,missing-docstring
+#
+# Copyright (C) 2015-2017 Richard Hughes <richard hughsie com>
+# Licensed under the GNU General Public License Version 2
+
+import os
+
+from flask import Flask, flash, render_template
+from flask_login import LoginManager
+
+from .db import Database
+
+app = Flask(__name__)
+app.config.from_object(__name__)
+app.secret_key = os.environ['ODRS_REVIEWS_SECRET']
+
+lm = LoginManager()
+lm.init_app(app)
+
+db = Database(app)
+
+@lm.user_loader
+def load_user(user_id):
+    user = db.user_get_by_id(user_id)
+    return user
+
+@app.errorhandler(404)
+def error_page_not_found(msg=None):
+    """ Error handler: File not found """
+    flash(msg)
+    return render_template('error.html'), 404
+
+from app import views
+from app import views_admin
diff --git a/database.py b/app/db.py
similarity index 97%
rename from database.py
rename to app/db.py
index 920cc05..a964091 100644
--- a/database.py
+++ b/app/db.py
@@ -1,18 +1,19 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2016 Richard Hughes <richard hughsie com>
+# pylint: disable=invalid-name,missing-docstring
+#
+# Copyright (C) 2016-2017 Richard Hughes <richard hughsie com>
 # Licensed under the GNU General Public License Version 3
 
-import pymysql as mdb
-import pymysql.cursors
+import os
 import cgi
 import datetime
 import hashlib
 
-from user import OdrsUser
-from event import OdrsEvent
-from review import OdrsReview
+import pymysql as mdb
+
+from .models import User, Event, Review
 
 class CursorError(Exception):
     def __init__(self, cur, e):
@@ -22,7 +23,7 @@ class CursorError(Exception):
 
 def _create_review(e):
     """ Parse a review """
-    review = OdrsReview()
+    review = Review()
     review.review_id = int(e[0])
     review.date_created = int(e[1].strftime("%s"))
     review.app_id = e[2]
@@ -43,7 +44,7 @@ def _create_review(e):
 
 def _create_event(e):
     """ Parse an event """
-    event = OdrsEvent()
+    event = Event()
     event.eventlog_id = int(e[0])
     event.date_created = int(e[1].strftime("%s"))
     event.user_addr = e[2]
@@ -55,7 +56,7 @@ def _create_event(e):
 
 def _create_user(e):
     """ Parse a user """
-    user = OdrsUser()
+    user = User()
     user.id = int(e[0])
     user.date_created = int(e[1].strftime("%s"))
     user.user_hash = e[2]
@@ -71,17 +72,16 @@ def _password_hash(value):
 def _get_datestr_from_dt(when):
     return int("%04i%02i%02i" % (when.year, when.month, when.day))
 
-class ReviewsDatabase(object):
+class Database(object):
 
-    def __init__(self, environ):
+    def __init__(self, app):
         """ Constructor for object """
-        assert environ
         self._db = None
         try:
-            if 'MYSQL_DB_HOST' in environ:
-                self._db = mdb.connect(environ['MYSQL_DB_HOST'],
-                                       environ['MYSQL_DB_USERNAME'],
-                                       environ['MYSQL_DB_PASSWORD'],
+            if 'MYSQL_DB_HOST' in os.environ:
+                self._db = mdb.connect(os.environ['MYSQL_DB_HOST'],
+                                       os.environ['MYSQL_DB_USERNAME'],
+                                       os.environ['MYSQL_DB_PASSWORD'],
                                        'odrs',
                                        use_unicode=True, charset='utf8')
             else:
diff --git a/app/models.py b/app/models.py
new file mode 100644
index 0000000..67a6cb6
--- /dev/null
+++ b/app/models.py
@@ -0,0 +1,61 @@
+#!/usr/bin/python2
+# -*- coding: utf-8 -*-
+#
+# pylint: disable=invalid-name,missing-docstring,too-few-public-methods
+#
+# Copyright (C) 2015-2017 Richard Hughes <richard hughsie com>
+# Licensed under the GNU General Public License Version 2
+
+class User(object):
+    def __init__(self):
+        self.id = None
+        self.karma = 0
+        self.date_created = 0
+        self.user_hash = 0
+        self.is_banned = 0
+
+    @property
+    def is_authenticated(self):
+        return True
+
+    @property
+    def is_active(self):
+        return True
+
+    @property
+    def is_anonymous(self):
+        return False
+
+    def get_id(self):
+        return str(self.id)
+
+    def __repr__(self):
+        return '<User %r>' % (self.id)
+
+class Review(object):
+    def __init__(self):
+        self.review_id = 0
+        self.date_created = 0
+        self.app_id = None
+        self.locale = None
+        self.summary = None
+        self.description = None
+        self.version = None
+        self.distro = None
+        self.karma_up = 0
+        self.karma_down = 0
+        self.user_hash = None
+        self.user_display = None
+        self.rating = 0
+        self.date_deleted = None
+        self.reported = None
+
+class Event(object):
+    def __init__(self):
+        self.eventlog_id = 0
+        self.date_created = 0
+        self.user_addr = None
+        self.user_hash = None
+        self.message = None
+        self.app_id = None
+        self.important = False
diff --git a/static/Chart.js b/app/static/Chart.js
similarity index 100%
rename from static/Chart.js
rename to app/static/Chart.js
diff --git a/static/layout.css b/app/static/layout.css
similarity index 100%
rename from static/layout.css
rename to app/static/layout.css
diff --git a/static/style.css b/app/static/style.css
similarity index 100%
rename from static/style.css
rename to app/static/style.css
diff --git a/templates/default.html b/app/templates/default.html
similarity index 99%
rename from templates/default.html
rename to app/templates/default.html
index 964ac16..383725f 100644
--- a/templates/default.html
+++ b/app/templates/default.html
@@ -6,7 +6,6 @@
 <head>
   <title>{% block title %}{% endblock %}</title>
   <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
-  <base href="https://odrs.gnome.org/"; />
   <link href="layout.css" rel="stylesheet" type="text/css" media="screen" />
   <link href="style.css" rel="stylesheet" type="text/css" media="all" />
   <link rel="icon" type="image/png" href="https://www.gnome.org/img/logo/foot-16.png"; />
diff --git a/templates/delete.html b/app/templates/delete.html
similarity index 100%
rename from templates/delete.html
rename to app/templates/delete.html
diff --git a/templates/distros.html b/app/templates/distros.html
similarity index 100%
rename from templates/distros.html
rename to app/templates/distros.html
diff --git a/templates/error.html b/app/templates/error.html
similarity index 100%
rename from templates/error.html
rename to app/templates/error.html
diff --git a/templates/graph-month.html b/app/templates/graph-month.html
similarity index 100%
rename from templates/graph-month.html
rename to app/templates/graph-month.html
diff --git a/templates/graph-year.html b/app/templates/graph-year.html
similarity index 100%
rename from templates/graph-year.html
rename to app/templates/graph-year.html
diff --git a/templates/index.html b/app/templates/index.html
similarity index 100%
rename from templates/index.html
rename to app/templates/index.html
diff --git a/templates/login.html b/app/templates/login.html
similarity index 100%
rename from templates/login.html
rename to app/templates/login.html
diff --git a/templates/oars.html b/app/templates/oars.html
similarity index 100%
rename from templates/oars.html
rename to app/templates/oars.html
diff --git a/templates/show-all.html b/app/templates/show-all.html
similarity index 100%
rename from templates/show-all.html
rename to app/templates/show-all.html
diff --git a/templates/show.html b/app/templates/show.html
similarity index 100%
rename from templates/show.html
rename to app/templates/show.html
diff --git a/templates/stats.html b/app/templates/stats.html
similarity index 100%
rename from templates/stats.html
rename to app/templates/stats.html
diff --git a/templates/users.html b/app/templates/users.html
similarity index 100%
rename from templates/users.html
rename to app/templates/users.html
diff --git a/api10.py b/app/views.py
similarity index 86%
rename from api10.py
rename to app/views.py
index f81d047..20f30f3 100644
--- a/api10.py
+++ b/app/views.py
@@ -1,22 +1,23 @@
 #!/usr/bin/python2
 # -*- coding: utf-8 -*-
 #
-# pylint: disable=invalid-name
+# pylint: disable=invalid-name,missing-docstring
 #
-# Copyright (C) 2016 Richard Hughes <richard hughsie com>
-# Licensed under the GNU General Public License Version 3
+# Copyright (C) 2015-2017 Richard Hughes <richard hughsie com>
+# Licensed under the GNU General Public License Version 2
 
 import json
 import os
 import hashlib
 import math
 
-from flask import Blueprint, Response, request
+from flask import request, url_for, redirect, flash, render_template, send_from_directory, Response
+from flask_login import login_user, logout_user
 
-from database import ReviewsDatabase, CursorError
-from review import OdrsReview
+from app import app, db
 
-api = Blueprint('api10', __name__, url_prefix='/')
+from .db import CursorError
+from .models import Review
 
 def _get_user_key(user_hash, app_id):
     salt = os.environ['ODRS_REVIEWS_SECRET']
@@ -114,7 +115,53 @@ def _sanitised_version(val):
 
     return val
 
-@api.errorhandler(400)
+@app.route('/login', methods=['GET', 'POST'])
+def login():
+    if request.method != 'POST':
+        return render_template('login.html')
+    username = request.form['username']
+    password = request.form['password']
+    try:
+        user = db.user_get_with_login(request.form['username'],
+                                      request.form['password'])
+    except CursorError as e:
+        flash(str(e))
+        return render_template('error.html'), 503
+    if not user:
+        flash('Credentials are not valid.')
+        return redirect(url_for('.login'))
+    login_user(user, remember=False)
+    flash('Logged in successfully.')
+    return redirect(url_for('.index'))
+
+@app.route("/logout")
+def logout():
+    logout_user()
+    flash('Logged out successfully.')
+    return redirect(url_for('.index'))
+
+@app.errorhandler(404)
+def error_page_not_found(msg=None):
+    """ Error handler: File not found """
+    flash(msg)
+    return render_template('error.html'), 404
+
+@app.route('/')
+def index():
+    """ start page """
+    return render_template('index.html')
+
+@app.route('/oars')
+def oars_index():
+    """ OARS page """
+    return render_template('oars.html')
+
+@app.route('/<path:resource>')
+def static_resource(resource):
+    """ Return a static image or resource """
+    return send_from_directory('static/', os.path.basename(resource))
+
+@app.errorhandler(400)
 def json_error(msg=None, errcode=400):
     """ Error handler: JSON output """
     item = {}
@@ -126,7 +173,7 @@ def json_error(msg=None, errcode=400):
                     status=errcode, \
                     mimetype="application/json")
 
-@api.errorhandler(401)
+@app.errorhandler(401)
 def error_permission_denied(msg=None):
     """ Error handler: Permission Denied """
     return json_error(msg, 401)
@@ -150,7 +197,7 @@ def _check_str(val):
         return False
     return True
 
-@api.route('/api/submit', methods=['POST'])
+@app.route('/1.0/reviews/api/submit', methods=['POST'])
 def submit():
     """
     Submits a new review.
@@ -183,7 +230,6 @@ def submit():
         if not _check_str(item[key]):
             return json_error('%s is not a valid string' % key)
     try:
-        db = ReviewsDatabase(os.environ)
 
         # user has already reviewed
         if db.review_exists(item['app_id'], item['user_hash']):
@@ -199,7 +245,7 @@ def submit():
             return json_error('account has been disabled due to abuse')
 
         # create new
-        review = OdrsReview()
+        review = Review()
         review.app_id = item['app_id']
         review.locale = item['locale']
         review.summary = _sanitised_summary(item['summary'])
@@ -228,14 +274,13 @@ def submit():
         return json_error(str(e))
     return json_success()
 
-@api.route('/api/app/<app_id>/<user_hash>')
-@api.route('/api/app/<app_id>')
-def app(app_id, user_hash=None):
+@app.route('/1.0/reviews/api/app/<app_id>/<user_hash>')
+@app.route('/1.0/reviews/api/app/<app_id>')
+def show_app(app_id, user_hash=None):
     """
     Return details about an application.
     """
     try:
-        db = ReviewsDatabase(os.environ)
         db.event_info(_get_client_address(), user_hash, app_id, "getting")
         reviews = db.review_get_for_app_id(app_id)
     except CursorError as e:
@@ -256,7 +301,7 @@ def app(app_id, user_hash=None):
                     status=200, \
                     mimetype="application/json")
 
-@api.route('/api/fetch', methods=['POST'])
+@app.route('/1.0/reviews/api/fetch', methods=['POST'])
 def fetch():
     """
     Return details about an application.
@@ -276,7 +321,6 @@ def fetch():
         return json_error('the user_hash is invalid')
 
     try:
-        db = ReviewsDatabase(os.environ)
         db.analytics_inc_fetch(item['app_id'])
         reviews = db.review_get_for_app_id(item['app_id'])
     except CursorError as e:
@@ -336,14 +380,13 @@ def fetch():
                     status=200, \
                     mimetype="application/json")
 
-@api.route('/api/all/<user_hash>')
-@api.route('/api/all')
+@app.route('/1.0/reviews/api/all/<user_hash>')
+@app.route('/1.0/reviews/api/all')
 def all(user_hash=None):
     """
     Return all the reviews on the server as a JSON object.
     """
     try:
-        db = ReviewsDatabase(os.environ)
         db.event_info(_get_client_address(), user_hash, None, "getting all reviews")
         reviews = db.review_get_all()
     except CursorError as e:
@@ -362,14 +405,13 @@ def all(user_hash=None):
                     status=200, \
                     mimetype="application/json")
 
-@api.route('/api/moderate/<user_hash>')
-@api.route('/api/moderate/<user_hash>/<locale>')
+@app.route('/1.0/reviews/api/moderate/<user_hash>')
+@app.route('/1.0/reviews/api/moderate/<user_hash>/<locale>')
 def moderate(user_hash, locale=None):
     """
     Return all the reviews on the server the user can moderate.
     """
     try:
-        db = ReviewsDatabase(os.environ)
         db.event_info(_get_client_address(), user_hash, None, "getting moderatable reviews")
         reviews = db.review_get_all()
     except CursorError as e:
@@ -412,12 +454,6 @@ def vote(val):
     if not len(item['user_skey']) == 40:
         return json_error('the user_skey is invalid')
 
-    # connect to database early
-    try:
-        db = ReviewsDatabase(os.environ)
-    except CursorError as e:
-        return json_error(str(e))
-
     if item['user_skey'] != _get_user_key(item['user_hash'], item['app_id']):
         db.event_warn(_get_client_address(), item['user_hash'], None,
                       "invalid user_skey of %s" % item['user_skey'])
@@ -455,35 +491,35 @@ def vote(val):
         return json_error(str(e))
     return json_success('voted #%i %i' % (item['review_id'], val))
 
-@api.route('/api/upvote', methods=['POST'])
+@app.route('/1.0/reviews/api/upvote', methods=['POST'])
 def upvote():
     """
     Upvote an existing review by one karma point.
     """
     return vote(1)
 
-@api.route('/api/downvote', methods=['POST'])
+@app.route('/1.0/reviews/api/downvote', methods=['POST'])
 def downvote():
     """
     Downvote an existing review by one karma point.
     """
     return vote(-1)
 
-@api.route('/api/dismiss', methods=['POST'])
+@app.route('/1.0/reviews/api/dismiss', methods=['POST'])
 def dismiss():
     """
     Dismiss a review without rating it up or down.
     """
     return vote(0)
 
-@api.route('/api/report', methods=['POST'])
+@app.route('/1.0/reviews/api/report', methods=['POST'])
 def report():
     """
     Report a review for abuse.
     """
     return vote(-5)
 
-@api.route('/api/remove', methods=['POST'])
+@app.route('/1.0/reviews/api/remove', methods=['POST'])
 def remove():
     """
     Remove a review.
@@ -504,11 +540,6 @@ def remove():
     if not len(item['user_skey']) == 40:
         return json_error('the user_skey is invalid')
 
-    # connect to database early
-    try:
-        db = ReviewsDatabase(os.environ)
-    except CursorError as e:
-        return json_error(str(e))
     if item['user_skey'] != _get_user_key(item['user_hash'], item['app_id']):
         db.event_warn(_get_client_address(), item['user_hash'], None,
                       "invalid user_skey of %s" % item['user_skey'])
@@ -524,13 +555,12 @@ def remove():
         return json_error(str(e))
     return json_success('removed review #%i' % item['review_id'])
 
-@api.route('/api/ratings/<app_id>')
+@app.route('/1.0/reviews/api/ratings/<app_id>')
 def rating_for_id(app_id):
     """
     Get the star ratings for a specific application.
     """
     try:
-        db = ReviewsDatabase(os.environ)
         ratings = db.reviews_get_rating_for_app_id(app_id)
     except CursorError as e:
         return json_error(str(e))
@@ -540,14 +570,13 @@ def rating_for_id(app_id):
                     status=200, \
                     mimetype="application/json")
 
-@api.route('/api/ratings')
+@app.route('/1.0/reviews/api/ratings')
 def ratings():
     """
     Get the star ratings for a specific application.
     """
     item = {}
     try:
-        db = ReviewsDatabase(os.environ)
         app_ids = db.get_all_apps()
         for app_id in app_ids:
             ratings = db.reviews_get_rating_for_app_id(app_id, 2)
diff --git a/admin.py b/app/views_admin.py
similarity index 82%
rename from admin.py
rename to app/views_admin.py
index fc58983..fffca83 100644
--- a/admin.py
+++ b/app/views_admin.py
@@ -1,20 +1,20 @@
 #!/usr/bin/python2
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2016 Richard Hughes <richard hughsie com>
-# Licensed under the GNU General Public License Version 3
+# pylint: disable=invalid-name,missing-docstring
+#
+# Copyright (C) 2015-2017 Richard Hughes <richard hughsie com>
+# Licensed under the GNU General Public License Version 2
 
-import os
 import datetime
 import calendar
 from math import ceil
 
-from flask import Blueprint, abort, request, flash, render_template, redirect, url_for
+from flask import abort, request, flash, render_template, redirect, url_for
 from flask_login import login_required
 
-from database import ReviewsDatabase, CursorError
-
-admin = Blueprint('admin', __name__, url_prefix='/admin')
+from app import app, db
+from .db import CursorError
 
 def _get_chart_labels_months():
     """ Gets the chart labels """
@@ -68,29 +68,25 @@ class Pagination(object):
                 yield num
                 last = num
 
-@admin.errorhandler(400)
+@app.errorhandler(400)
 def error_internal(msg=None, errcode=400):
     """ Error handler: Internal """
     flash("Internal error: %s" % msg)
     return render_template('error.html'), errcode
 
-@admin.errorhandler(401)
+@app.errorhandler(401)
 def error_permission_denied(msg=None):
     """ Error handler: Permission Denied """
     flash("Permission denied: %s" % msg)
     return render_template('error.html'), 401
 
 
-@admin.route('/graph_month')
+@app.route('/admin/graph_month')
 @login_required
 def graph_month():
     """
     Show nice graph graphs.
     """
-    try:
-        db = ReviewsDatabase(os.environ)
-    except CursorError as e:
-        return error_internal(str(e))
     data_fetch = db.get_analytics_by_interval(30, 1)
     data_review = db.get_stats_by_interval(30, 1, 'reviewed')
     return render_template('graph-month.html',
@@ -98,16 +94,12 @@ def graph_month():
                            data_requests=data_fetch[::-1],
                            data_submitted=data_review[::-1])
 
-@admin.route('/graph_year')
+@app.route('/admin/graph_year')
 @login_required
 def graph_year():
     """
     Show nice graph graphs.
     """
-    try:
-        db = ReviewsDatabase(os.environ)
-    except CursorError as e:
-        return error_internal(str(e))
     data_fetch = db.get_analytics_by_interval(12, 30)
     data_review = db.get_stats_by_interval(12, 30, 'reviewed')
     return render_template('graph-year.html',
@@ -115,14 +107,13 @@ def graph_year():
                            data_requests=data_fetch[::-1],
                            data_submitted=data_review[::-1])
 
-@admin.route('/stats')
+@app.route('/admin/stats')
 @login_required
-def stats():
+def show_stats():
     """
     Return the statistics page as HTML.
     """
     try:
-        db = ReviewsDatabase(os.environ)
         stats = db.get_stats()
     except CursorError as e:
         return error_internal(str(e))
@@ -146,14 +137,13 @@ def stats():
                            results_viewed=results_viewed,
                            results_submitted=results_submitted)
 
-@admin.route('/distros')
+@app.route('/admin/distros')
 @login_required
 def distros():
     """
     Return the statistics page as HTML.
     """
     try:
-        db = ReviewsDatabase(os.environ)
         stats = db.get_stats_distro(8)
     except CursorError as e:
         return error_internal(str(e))
@@ -168,7 +158,7 @@ def distros():
         data.append(s[1])
     return render_template('distros.html', labels=labels, data=data)
 
-@admin.context_processor
+@app.context_processor
 def utility_processor():
     def format_rating(rating):
         nr_stars = int(rating / 20)
@@ -199,13 +189,12 @@ def utility_processor():
                 format_timestamp=format_timestamp,
                 url_for_other_page=url_for_other_page)
 
-@admin.route('/review/<review_id>')
-def review(review_id):
+@app.route('/admin/review/<review_id>')
+def admin_show_review(review_id):
     """
     Show a specific review as HTML.
     """
     try:
-        db = ReviewsDatabase(os.environ)
         review = db.review_get_for_id(review_id)
     except CursorError as e:
         return error_internal(str(e))
@@ -213,12 +202,11 @@ def review(review_id):
         return error_internal('no review with that ID')
     return render_template('show.html', r=review)
 
-@admin.route('/modify/<review_id>', methods=['POST'])
+@app.route('/admin/modify/<review_id>', methods=['POST'])
 @login_required
-def modify(review_id):
+def admin_modify(review_id):
     """ Change details about a review """
     try:
-        db = ReviewsDatabase(os.environ)
         review = db.review_get_for_id(review_id)
     except CursorError as e:
         return error_internal(str(e))
@@ -237,23 +225,21 @@ def modify(review_id):
     db.review_modify(review)
     return redirect(url_for('.review', review_id=review_id))
 
-@admin.route('/user_ban/<user_hash>')
+@app.route('/admin/user_ban/<user_hash>')
 @login_required
-def user_ban(user_hash):
+def admin_user_ban(user_hash):
     """ Change details about a review """
     try:
-        db = ReviewsDatabase(os.environ)
         db.user_ban(user_hash)
     except CursorError as e:
         return error_internal(str(e))
     return redirect(url_for('.show_reported'))
 
-@admin.route('/unreport/<review_id>')
+@app.route('/admin/unreport/<review_id>')
 @login_required
-def unreport(review_id):
+def admin_unreport(review_id):
     """ Unreport a perfectly valid review """
     try:
-        db = ReviewsDatabase(os.environ)
         review = db.review_get_for_id(review_id)
     except CursorError as e:
         return error_internal(str(e))
@@ -263,12 +249,11 @@ def unreport(review_id):
     db.review_modify(review)
     return redirect(url_for('.review', review_id=review_id))
 
-@admin.route('/unremove/<review_id>')
+@app.route('/admin/unremove/<review_id>')
 @login_required
-def unremove(review_id):
+def admin_unremove(review_id):
     """ Unreport a perfectly valid review """
     try:
-        db = ReviewsDatabase(os.environ)
         review = db.review_get_for_id(review_id)
     except CursorError as e:
         return error_internal(str(e))
@@ -278,12 +263,11 @@ def unremove(review_id):
     db.review_modify(review)
     return redirect(url_for('.review', review_id=review_id))
 
-@admin.route('/englishify/<review_id>')
+@app.route('/admin/englishify/<review_id>')
 @login_required
-def englishify(review_id):
+def admin_englishify(review_id):
     """ Marks a review as writen in English """
     try:
-        db = ReviewsDatabase(os.environ)
         review = db.review_get_for_id(review_id)
     except CursorError as e:
         return error_internal(str(e))
@@ -297,12 +281,11 @@ def englishify(review_id):
     db.review_modify(review)
     return redirect(url_for('.review', review_id=review_id))
 
-@admin.route('/anonify/<review_id>')
+@app.route('/admin/anonify/<review_id>')
 @login_required
-def anonify(review_id):
+def admin_anonify(review_id):
     """ Removes the username from the review """
     try:
-        db = ReviewsDatabase(os.environ)
         review = db.review_get_for_id(review_id)
     except CursorError as e:
         return error_internal(str(e))
@@ -312,12 +295,11 @@ def anonify(review_id):
     db.review_modify(review)
     return redirect(url_for('.review', review_id=review_id))
 
-@admin.route('/delete/<review_id>/force')
+@app.route('/admin/delete/<review_id>/force')
 @login_required
-def delete_force(review_id):
+def admin_delete_force(review_id):
     """ Delete a review """
     try:
-        db = ReviewsDatabase(os.environ)
         review = db.review_get_for_id(review_id)
     except CursorError as e:
         return error_internal(str(e))
@@ -326,20 +308,19 @@ def delete_force(review_id):
     db.review_delete(review)
     return redirect(url_for('.show_all'))
 
-@admin.route('/delete/<review_id>')
+@app.route('/admin/delete/<review_id>')
 @login_required
-def delete(review_id):
+def admin_delete(review_id):
     """ Ask for confirmation to delete a review """
     return render_template('delete.html', review_id=review_id)
 
-@admin.route('/show/all', defaults={'page': 1})
-@admin.route('/show/all/page/<int:page>')
-def show_all(page):
+@app.route('/admin/show/all', defaults={'page': 1})
+@app.route('/admin/show/all/page/<int:page>')
+def admin_show_all(page):
     """
     Return all the reviews on the server as HTML.
     """
     try:
-        db = ReviewsDatabase(os.environ)
         reviews = db.review_get_all()
     except CursorError as e:
         return error_internal(str(e))
@@ -353,14 +334,13 @@ def show_all(page):
                            pagination=pagination,
                            reviews=reviews)
 
-@admin.route('/show/reported')
-def show_reported():
+@app.route('/admin/show/reported')
+def admin_show_reported():
     """
     Return all the reported reviews on the server as HTML.
     """
     reviews_filtered = []
     try:
-        db = ReviewsDatabase(os.environ)
         reviews = db.review_get_all()
         for review in reviews:
             if review.reported > 0:
@@ -369,14 +349,13 @@ def show_reported():
         return error_internal(str(e))
     return render_template('show-all.html', reviews=reviews_filtered)
 
-@admin.route('/show/user/<user_hash>')
-def show_user(user_hash):
+@app.route('/admin/show/user/<user_hash>')
+def admin_show_user(user_hash):
     """
     Return all the reviews from a user on the server as HTML.
     """
     reviews_filtered = []
     try:
-        db = ReviewsDatabase(os.environ)
         reviews = db.review_get_all()
         for review in reviews:
             if review.user_hash == user_hash:
@@ -385,14 +364,13 @@ def show_user(user_hash):
         return error_internal(str(e))
     return render_template('show-all.html', reviews=reviews_filtered)
 
-@admin.route('/show/app/<app_id>')
-def show_app(app_id):
+@app.route('/admin/show/app/<app_id>')
+def admin_show_app(app_id):
     """
     Return all the reviews from a user on the server as HTML.
     """
     reviews_filtered = []
     try:
-        db = ReviewsDatabase(os.environ)
         reviews = db.review_get_all()
         for review in reviews:
             if review.app_id == app_id:
@@ -401,14 +379,13 @@ def show_app(app_id):
         return error_internal(str(e))
     return render_template('show-all.html', reviews=reviews_filtered)
 
-@admin.route('/show/lang/<locale>')
-def show_lang(locale):
+@app.route('/admin/show/lang/<locale>')
+def admin_show_lang(locale):
     """
     Return all the reviews from a user on the server as HTML.
     """
     reviews_filtered = []
     try:
-        db = ReviewsDatabase(os.environ)
         reviews = db.review_get_all()
         for review in reviews:
             if review.locale == locale:
@@ -417,14 +394,13 @@ def show_lang(locale):
         return error_internal(str(e))
     return render_template('show-all.html', reviews=reviews_filtered)
 
-@admin.route('/users/all')
+@app.route('/admin/users/all')
 @login_required
-def users_all():
+def admin_users_all():
     """
     Return all the users as HTML.
     """
     try:
-        db = ReviewsDatabase(os.environ)
         users_awesome = db.get_users_by_karma(best=True)
         users_haters = db.get_users_by_karma(best=False)
     except CursorError as e:
diff --git a/flaskapp.py b/flaskapp.py
index 626b221..f9c087b 100755
--- a/flaskapp.py
+++ b/flaskapp.py
@@ -1,80 +1,10 @@
 #!/usr/bin/python2
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2016 Richard Hughes <richard hughsie com>
+# Copyright (C) 2016-2017 Richard Hughes <richard hughsie com>
 # Licensed under the GNU General Public License Version 3
 
-import os
-from flask import Flask, request, url_for, redirect, flash, render_template, send_from_directory, abort
-from flask.ext.login import LoginManager
-from flask.ext.login import login_required, login_user, logout_user
-
-from api10 import api as api10
-from admin import admin
-from database import ReviewsDatabase, CursorError
-from user import OdrsUser
-
-app = Flask(__name__)
-app.config.from_object(__name__)
-app.secret_key = os.environ['ODRS_REVIEWS_SECRET']
-app.register_blueprint(api10, url_prefix='/1.0/reviews')
-app.register_blueprint(admin, url_prefix='/admin')
-
-login_manager = LoginManager()
-login_manager.init_app(app)
-
-@login_manager.user_loader
-def load_user(user_id):
-    db = ReviewsDatabase(os.environ)
-    user = db.user_get_by_id(user_id)
-    return user
-
-@app.route('/login', methods=['GET', 'POST'])
-def login():
-    if request.method != 'POST':
-        return render_template('login.html')
-    username = request.form['username']
-    password = request.form['password']
-    try:
-        db = ReviewsDatabase(os.environ)
-        user = db.user_get_with_login(request.form['username'],
-                                      request.form['password'])
-    except CursorError as e:
-        flash(str(e))
-        return render_template('error.html'), 503
-    if not user:
-        flash('Credentials are not valid.')
-        return redirect(url_for('.login'))
-    login_user(user, remember=False)
-    flash('Logged in successfully.')
-    return redirect(url_for('.index'))
-
-@app.route("/logout")
-def logout():
-    logout_user()
-    flash('Logged out successfully.')
-    return redirect(url_for('.index'))
-
-@app.errorhandler(404)
-def error_page_not_found(msg=None):
-    """ Error handler: File not found """
-    flash(msg)
-    return render_template('error.html'), 404
-
-@app.route('/')
-def index():
-    """ start page """
-    return render_template('index.html')
-
-@app.route('/oars')
-def oars_index():
-    """ OARS page """
-    return render_template('oars.html')
-
-@app.route('/<path:resource>')
-def static_resource(resource):
-    """ Return a static image or resource """
-    return send_from_directory('static/', resource)
+from app import app
 
 if __name__ == '__main__':
     app.debug = True
diff --git a/odrs.wsgi b/odrs.wsgi
index c9de12a..855747a 100644
--- a/odrs.wsgi
+++ b/odrs.wsgi
@@ -15,5 +15,5 @@ def application(environ, start_response):
                 'MYSQL_DB_PASSWORD',
                 'ODRS_REVIEWS_SECRET']:
         os.environ[key] = environ[key]
-    from flaskapp import app as _application
+    from app import app as _application
     return _application(environ, start_response)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]