[odrs-web] Revert "Move to a more flask-like project layout"



commit 9e6b60ff74bd082a0bf1d2c23dda9c3e88fc7c7a
Author: Richard Hughes <richard hughsie com>
Date:   Thu Jul 6 13:12:00 2017 +0100

    Revert "Move to a more flask-like project layout"
    
    This reverts commit b5a53727d9ad00acb123407ebd41065f9c848d69.

 app/views_admin.py => admin.py                |  116 +++++++++++++++----------
 app/views.py => api10.py                      |  117 +++++++++---------------
 app/__init__.py                               |   37 --------
 app/models.py                                 |   61 -------------
 app/db.py => database.py                      |   32 ++++----
 event.py                                      |   15 +++
 flaskapp.py                                   |   74 +++++++++++++++-
 odrs.wsgi                                     |    2 +-
 review.py                                     |   23 +++++
 {app/static => static}/Chart.js               |    0
 {app/static => static}/app-page.png           |  Bin 94032 -> 94032 bytes
 {app/static => static}/bar.png                |  Bin 154 -> 154 bytes
 {app/static => static}/favicon.ico            |  Bin 2550 -> 2550 bytes
 {app/static => static}/foot.png               |  Bin 699 -> 699 bytes
 {app/static => static}/general_bg.png         |  Bin 178 -> 178 bytes
 {app/static => static}/general_separator.png  |  Bin 212 -> 212 bytes
 {app/static => static}/gnome-16.png           |  Bin 650 -> 650 bytes
 {app/static => static}/gnome-odrs.png         |  Bin 14485 -> 14485 bytes
 {app/static => static}/layout.css             |    0
 {app/static => static}/review-submit.png      |  Bin 25010 -> 25010 bytes
 {app/static => static}/search-icon.png        |  Bin 395 -> 395 bytes
 {app/static => static}/style.css              |    0
 {app/static => static}/t.png                  |  Bin 317 -> 317 bytes
 {app/static => static}/top_bar-bg.png         |  Bin 185 -> 185 bytes
 {app/templates => templates}/default.html     |    1 +
 {app/templates => templates}/delete.html      |    0
 {app/templates => templates}/distros.html     |    0
 {app/templates => templates}/error.html       |    0
 {app/templates => templates}/graph-month.html |    0
 {app/templates => templates}/graph-year.html  |    0
 {app/templates => templates}/index.html       |    0
 {app/templates => templates}/login.html       |    0
 {app/templates => templates}/oars.html        |    0
 {app/templates => templates}/show-all.html    |    0
 {app/templates => templates}/show.html        |    0
 {app/templates => templates}/stats.html       |    0
 {app/templates => templates}/users.html       |    0
 user.py                                       |   31 +++++++
 38 files changed, 273 insertions(+), 236 deletions(-)
---
diff --git a/app/views_admin.py b/admin.py
similarity index 82%
rename from app/views_admin.py
rename to admin.py
index fffca83..fc58983 100644
--- a/app/views_admin.py
+++ b/admin.py
@@ -1,20 +1,20 @@
 #!/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
+# Copyright (C) 2016 Richard Hughes <richard hughsie com>
+# Licensed under the GNU General Public License Version 3
 
+import os
 import datetime
 import calendar
 from math import ceil
 
-from flask import abort, request, flash, render_template, redirect, url_for
+from flask import Blueprint, abort, request, flash, render_template, redirect, url_for
 from flask_login import login_required
 
-from app import app, db
-from .db import CursorError
+from database import ReviewsDatabase, CursorError
+
+admin = Blueprint('admin', __name__, url_prefix='/admin')
 
 def _get_chart_labels_months():
     """ Gets the chart labels """
@@ -68,25 +68,29 @@ class Pagination(object):
                 yield num
                 last = num
 
-@app.errorhandler(400)
+@admin.errorhandler(400)
 def error_internal(msg=None, errcode=400):
     """ Error handler: Internal """
     flash("Internal error: %s" % msg)
     return render_template('error.html'), errcode
 
-@app.errorhandler(401)
+@admin.errorhandler(401)
 def error_permission_denied(msg=None):
     """ Error handler: Permission Denied """
     flash("Permission denied: %s" % msg)
     return render_template('error.html'), 401
 
 
-@app.route('/admin/graph_month')
+@admin.route('/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',
@@ -94,12 +98,16 @@ def graph_month():
                            data_requests=data_fetch[::-1],
                            data_submitted=data_review[::-1])
 
-@app.route('/admin/graph_year')
+@admin.route('/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',
@@ -107,13 +115,14 @@ def graph_year():
                            data_requests=data_fetch[::-1],
                            data_submitted=data_review[::-1])
 
-@app.route('/admin/stats')
+@admin.route('/stats')
 @login_required
-def show_stats():
+def 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))
@@ -137,13 +146,14 @@ def show_stats():
                            results_viewed=results_viewed,
                            results_submitted=results_submitted)
 
-@app.route('/admin/distros')
+@admin.route('/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))
@@ -158,7 +168,7 @@ def distros():
         data.append(s[1])
     return render_template('distros.html', labels=labels, data=data)
 
-@app.context_processor
+@admin.context_processor
 def utility_processor():
     def format_rating(rating):
         nr_stars = int(rating / 20)
@@ -189,12 +199,13 @@ def utility_processor():
                 format_timestamp=format_timestamp,
                 url_for_other_page=url_for_other_page)
 
-@app.route('/admin/review/<review_id>')
-def admin_show_review(review_id):
+@admin.route('/review/<review_id>')
+def 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))
@@ -202,11 +213,12 @@ def admin_show_review(review_id):
         return error_internal('no review with that ID')
     return render_template('show.html', r=review)
 
-@app.route('/admin/modify/<review_id>', methods=['POST'])
+@admin.route('/modify/<review_id>', methods=['POST'])
 @login_required
-def admin_modify(review_id):
+def 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))
@@ -225,21 +237,23 @@ def admin_modify(review_id):
     db.review_modify(review)
     return redirect(url_for('.review', review_id=review_id))
 
-@app.route('/admin/user_ban/<user_hash>')
+@admin.route('/user_ban/<user_hash>')
 @login_required
-def admin_user_ban(user_hash):
+def 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'))
 
-@app.route('/admin/unreport/<review_id>')
+@admin.route('/unreport/<review_id>')
 @login_required
-def admin_unreport(review_id):
+def 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))
@@ -249,11 +263,12 @@ def admin_unreport(review_id):
     db.review_modify(review)
     return redirect(url_for('.review', review_id=review_id))
 
-@app.route('/admin/unremove/<review_id>')
+@admin.route('/unremove/<review_id>')
 @login_required
-def admin_unremove(review_id):
+def 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))
@@ -263,11 +278,12 @@ def admin_unremove(review_id):
     db.review_modify(review)
     return redirect(url_for('.review', review_id=review_id))
 
-@app.route('/admin/englishify/<review_id>')
+@admin.route('/englishify/<review_id>')
 @login_required
-def admin_englishify(review_id):
+def 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))
@@ -281,11 +297,12 @@ def admin_englishify(review_id):
     db.review_modify(review)
     return redirect(url_for('.review', review_id=review_id))
 
-@app.route('/admin/anonify/<review_id>')
+@admin.route('/anonify/<review_id>')
 @login_required
-def admin_anonify(review_id):
+def 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))
@@ -295,11 +312,12 @@ def admin_anonify(review_id):
     db.review_modify(review)
     return redirect(url_for('.review', review_id=review_id))
 
-@app.route('/admin/delete/<review_id>/force')
+@admin.route('/delete/<review_id>/force')
 @login_required
-def admin_delete_force(review_id):
+def 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))
@@ -308,19 +326,20 @@ def admin_delete_force(review_id):
     db.review_delete(review)
     return redirect(url_for('.show_all'))
 
-@app.route('/admin/delete/<review_id>')
+@admin.route('/delete/<review_id>')
 @login_required
-def admin_delete(review_id):
+def delete(review_id):
     """ Ask for confirmation to delete a review """
     return render_template('delete.html', review_id=review_id)
 
-@app.route('/admin/show/all', defaults={'page': 1})
-@app.route('/admin/show/all/page/<int:page>')
-def admin_show_all(page):
+@admin.route('/show/all', defaults={'page': 1})
+@admin.route('/show/all/page/<int:page>')
+def 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))
@@ -334,13 +353,14 @@ def admin_show_all(page):
                            pagination=pagination,
                            reviews=reviews)
 
-@app.route('/admin/show/reported')
-def admin_show_reported():
+@admin.route('/show/reported')
+def 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:
@@ -349,13 +369,14 @@ def admin_show_reported():
         return error_internal(str(e))
     return render_template('show-all.html', reviews=reviews_filtered)
 
-@app.route('/admin/show/user/<user_hash>')
-def admin_show_user(user_hash):
+@admin.route('/show/user/<user_hash>')
+def 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:
@@ -364,13 +385,14 @@ def admin_show_user(user_hash):
         return error_internal(str(e))
     return render_template('show-all.html', reviews=reviews_filtered)
 
-@app.route('/admin/show/app/<app_id>')
-def admin_show_app(app_id):
+@admin.route('/show/app/<app_id>')
+def 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:
@@ -379,13 +401,14 @@ def admin_show_app(app_id):
         return error_internal(str(e))
     return render_template('show-all.html', reviews=reviews_filtered)
 
-@app.route('/admin/show/lang/<locale>')
-def admin_show_lang(locale):
+@admin.route('/show/lang/<locale>')
+def 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:
@@ -394,13 +417,14 @@ def admin_show_lang(locale):
         return error_internal(str(e))
     return render_template('show-all.html', reviews=reviews_filtered)
 
-@app.route('/admin/users/all')
+@admin.route('/users/all')
 @login_required
-def admin_users_all():
+def 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/app/views.py b/api10.py
similarity index 86%
rename from app/views.py
rename to api10.py
index 20f30f3..f81d047 100644
--- a/app/views.py
+++ b/api10.py
@@ -1,23 +1,22 @@
 #!/usr/bin/python2
 # -*- coding: utf-8 -*-
 #
-# pylint: disable=invalid-name,missing-docstring
+# pylint: disable=invalid-name
 #
-# Copyright (C) 2015-2017 Richard Hughes <richard hughsie com>
-# Licensed under the GNU General Public License Version 2
+# Copyright (C) 2016 Richard Hughes <richard hughsie com>
+# Licensed under the GNU General Public License Version 3
 
 import json
 import os
 import hashlib
 import math
 
-from flask import request, url_for, redirect, flash, render_template, send_from_directory, Response
-from flask_login import login_user, logout_user
+from flask import Blueprint, Response, request
 
-from app import app, db
+from database import ReviewsDatabase, CursorError
+from review import OdrsReview
 
-from .db import CursorError
-from .models import Review
+api = Blueprint('api10', __name__, url_prefix='/')
 
 def _get_user_key(user_hash, app_id):
     salt = os.environ['ODRS_REVIEWS_SECRET']
@@ -115,53 +114,7 @@ def _sanitised_version(val):
 
     return val
 
-@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)
+@api.errorhandler(400)
 def json_error(msg=None, errcode=400):
     """ Error handler: JSON output """
     item = {}
@@ -173,7 +126,7 @@ def json_error(msg=None, errcode=400):
                     status=errcode, \
                     mimetype="application/json")
 
-@app.errorhandler(401)
+@api.errorhandler(401)
 def error_permission_denied(msg=None):
     """ Error handler: Permission Denied """
     return json_error(msg, 401)
@@ -197,7 +150,7 @@ def _check_str(val):
         return False
     return True
 
-@app.route('/1.0/reviews/api/submit', methods=['POST'])
+@api.route('/api/submit', methods=['POST'])
 def submit():
     """
     Submits a new review.
@@ -230,6 +183,7 @@ 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']):
@@ -245,7 +199,7 @@ def submit():
             return json_error('account has been disabled due to abuse')
 
         # create new
-        review = Review()
+        review = OdrsReview()
         review.app_id = item['app_id']
         review.locale = item['locale']
         review.summary = _sanitised_summary(item['summary'])
@@ -274,13 +228,14 @@ def submit():
         return json_error(str(e))
     return json_success()
 
-@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):
+@api.route('/api/app/<app_id>/<user_hash>')
+@api.route('/api/app/<app_id>')
+def 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:
@@ -301,7 +256,7 @@ def show_app(app_id, user_hash=None):
                     status=200, \
                     mimetype="application/json")
 
-@app.route('/1.0/reviews/api/fetch', methods=['POST'])
+@api.route('/api/fetch', methods=['POST'])
 def fetch():
     """
     Return details about an application.
@@ -321,6 +276,7 @@ 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:
@@ -380,13 +336,14 @@ def fetch():
                     status=200, \
                     mimetype="application/json")
 
-@app.route('/1.0/reviews/api/all/<user_hash>')
-@app.route('/1.0/reviews/api/all')
+@api.route('/api/all/<user_hash>')
+@api.route('/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:
@@ -405,13 +362,14 @@ def all(user_hash=None):
                     status=200, \
                     mimetype="application/json")
 
-@app.route('/1.0/reviews/api/moderate/<user_hash>')
-@app.route('/1.0/reviews/api/moderate/<user_hash>/<locale>')
+@api.route('/api/moderate/<user_hash>')
+@api.route('/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:
@@ -454,6 +412,12 @@ 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'])
@@ -491,35 +455,35 @@ def vote(val):
         return json_error(str(e))
     return json_success('voted #%i %i' % (item['review_id'], val))
 
-@app.route('/1.0/reviews/api/upvote', methods=['POST'])
+@api.route('/api/upvote', methods=['POST'])
 def upvote():
     """
     Upvote an existing review by one karma point.
     """
     return vote(1)
 
-@app.route('/1.0/reviews/api/downvote', methods=['POST'])
+@api.route('/api/downvote', methods=['POST'])
 def downvote():
     """
     Downvote an existing review by one karma point.
     """
     return vote(-1)
 
-@app.route('/1.0/reviews/api/dismiss', methods=['POST'])
+@api.route('/api/dismiss', methods=['POST'])
 def dismiss():
     """
     Dismiss a review without rating it up or down.
     """
     return vote(0)
 
-@app.route('/1.0/reviews/api/report', methods=['POST'])
+@api.route('/api/report', methods=['POST'])
 def report():
     """
     Report a review for abuse.
     """
     return vote(-5)
 
-@app.route('/1.0/reviews/api/remove', methods=['POST'])
+@api.route('/api/remove', methods=['POST'])
 def remove():
     """
     Remove a review.
@@ -540,6 +504,11 @@ 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'])
@@ -555,12 +524,13 @@ def remove():
         return json_error(str(e))
     return json_success('removed review #%i' % item['review_id'])
 
-@app.route('/1.0/reviews/api/ratings/<app_id>')
+@api.route('/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))
@@ -570,13 +540,14 @@ def rating_for_id(app_id):
                     status=200, \
                     mimetype="application/json")
 
-@app.route('/1.0/reviews/api/ratings')
+@api.route('/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/app/db.py b/database.py
similarity index 97%
rename from app/db.py
rename to database.py
index a964091..920cc05 100644
--- a/app/db.py
+++ b/database.py
@@ -1,19 +1,18 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 #
-# pylint: disable=invalid-name,missing-docstring
-#
-# Copyright (C) 2016-2017 Richard Hughes <richard hughsie com>
+# Copyright (C) 2016 Richard Hughes <richard hughsie com>
 # Licensed under the GNU General Public License Version 3
 
-import os
+import pymysql as mdb
+import pymysql.cursors
 import cgi
 import datetime
 import hashlib
 
-import pymysql as mdb
-
-from .models import User, Event, Review
+from user import OdrsUser
+from event import OdrsEvent
+from review import OdrsReview
 
 class CursorError(Exception):
     def __init__(self, cur, e):
@@ -23,7 +22,7 @@ class CursorError(Exception):
 
 def _create_review(e):
     """ Parse a review """
-    review = Review()
+    review = OdrsReview()
     review.review_id = int(e[0])
     review.date_created = int(e[1].strftime("%s"))
     review.app_id = e[2]
@@ -44,7 +43,7 @@ def _create_review(e):
 
 def _create_event(e):
     """ Parse an event """
-    event = Event()
+    event = OdrsEvent()
     event.eventlog_id = int(e[0])
     event.date_created = int(e[1].strftime("%s"))
     event.user_addr = e[2]
@@ -56,7 +55,7 @@ def _create_event(e):
 
 def _create_user(e):
     """ Parse a user """
-    user = User()
+    user = OdrsUser()
     user.id = int(e[0])
     user.date_created = int(e[1].strftime("%s"))
     user.user_hash = e[2]
@@ -72,16 +71,17 @@ def _password_hash(value):
 def _get_datestr_from_dt(when):
     return int("%04i%02i%02i" % (when.year, when.month, when.day))
 
-class Database(object):
+class ReviewsDatabase(object):
 
-    def __init__(self, app):
+    def __init__(self, environ):
         """ Constructor for object """
+        assert environ
         self._db = None
         try:
-            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'],
+            if 'MYSQL_DB_HOST' in environ:
+                self._db = mdb.connect(environ['MYSQL_DB_HOST'],
+                                       environ['MYSQL_DB_USERNAME'],
+                                       environ['MYSQL_DB_PASSWORD'],
                                        'odrs',
                                        use_unicode=True, charset='utf8')
             else:
diff --git a/event.py b/event.py
new file mode 100644
index 0000000..6d91ef9
--- /dev/null
+++ b/event.py
@@ -0,0 +1,15 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2016 Richard Hughes <richard hughsie com>
+# Licensed under the GNU General Public License Version 3
+
+class OdrsEvent(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/flaskapp.py b/flaskapp.py
index f9c087b..626b221 100755
--- a/flaskapp.py
+++ b/flaskapp.py
@@ -1,10 +1,80 @@
 #!/usr/bin/python2
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2016-2017 Richard Hughes <richard hughsie com>
+# Copyright (C) 2016 Richard Hughes <richard hughsie com>
 # Licensed under the GNU General Public License Version 3
 
-from app import app
+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)
 
 if __name__ == '__main__':
     app.debug = True
diff --git a/odrs.wsgi b/odrs.wsgi
index 855747a..c9de12a 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 app import app as _application
+    from flaskapp import app as _application
     return _application(environ, start_response)
diff --git a/review.py b/review.py
new file mode 100644
index 0000000..7118d03
--- /dev/null
+++ b/review.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2016 Richard Hughes <richard hughsie com>
+# Licensed under the GNU General Public License Version 3
+
+class OdrsReview(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
diff --git a/app/static/Chart.js b/static/Chart.js
similarity index 100%
rename from app/static/Chart.js
rename to static/Chart.js
diff --git a/app/static/layout.css b/static/layout.css
similarity index 100%
rename from app/static/layout.css
rename to static/layout.css
diff --git a/app/static/style.css b/static/style.css
similarity index 100%
rename from app/static/style.css
rename to static/style.css
diff --git a/app/templates/default.html b/templates/default.html
similarity index 99%
rename from app/templates/default.html
rename to templates/default.html
index 383725f..964ac16 100644
--- a/app/templates/default.html
+++ b/templates/default.html
@@ -6,6 +6,7 @@
 <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/app/templates/delete.html b/templates/delete.html
similarity index 100%
rename from app/templates/delete.html
rename to templates/delete.html
diff --git a/app/templates/distros.html b/templates/distros.html
similarity index 100%
rename from app/templates/distros.html
rename to templates/distros.html
diff --git a/app/templates/error.html b/templates/error.html
similarity index 100%
rename from app/templates/error.html
rename to templates/error.html
diff --git a/app/templates/graph-month.html b/templates/graph-month.html
similarity index 100%
rename from app/templates/graph-month.html
rename to templates/graph-month.html
diff --git a/app/templates/graph-year.html b/templates/graph-year.html
similarity index 100%
rename from app/templates/graph-year.html
rename to templates/graph-year.html
diff --git a/app/templates/index.html b/templates/index.html
similarity index 100%
rename from app/templates/index.html
rename to templates/index.html
diff --git a/app/templates/login.html b/templates/login.html
similarity index 100%
rename from app/templates/login.html
rename to templates/login.html
diff --git a/app/templates/oars.html b/templates/oars.html
similarity index 100%
rename from app/templates/oars.html
rename to templates/oars.html
diff --git a/app/templates/show-all.html b/templates/show-all.html
similarity index 100%
rename from app/templates/show-all.html
rename to templates/show-all.html
diff --git a/app/templates/show.html b/templates/show.html
similarity index 100%
rename from app/templates/show.html
rename to templates/show.html
diff --git a/app/templates/stats.html b/templates/stats.html
similarity index 100%
rename from app/templates/stats.html
rename to templates/stats.html
diff --git a/app/templates/users.html b/templates/users.html
similarity index 100%
rename from app/templates/users.html
rename to templates/users.html
diff --git a/user.py b/user.py
new file mode 100644
index 0000000..2897c57
--- /dev/null
+++ b/user.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2016 Richard Hughes <richard hughsie com>
+# Licensed under the GNU General Public License Version 3
+
+class OdrsUser(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)


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