#!/usr/bin/python # -*- coding: UTF-8 -*- from datetime import datetime from logging.config import dictConfig import logging from PIL import Image from flask import Flask from flask import jsonify from flask import request, has_request_context from flask import session from flask import url_for from flask_compress import Compress from flask_session import Session from werkzeug import redirect from werkzeug.http import http_date from werkzeug.middleware.proxy_fix import ProxyFix import re from PiAnoS import caseExistsInDB from utils.decorator import admin_required, login_required from utils.template import my_render_template import config ################################################################################ logrequestre = re.compile( "(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*\[[^\]]+\]\s(.*)" ) class RequestFormatter( logging.Formatter ): def format( self, record ): if has_request_context(): try: username = session[ "username" ] except: username = "-" record.msg = "{REMOTE_ADDR} (" + username + ") - " + record.msg record.msg = record.msg.format( **request.headers.environ ) m = logrequestre.match( record.msg ) if m: record.msg = m.group( 2 ) return super( RequestFormatter, self ).format( record ) class myFilter( object ): def filter( self, record ): if "{}/ping".format( config.baseurl ) in record.msg and " 200 " in record.msg: return 0 else: return 1 class myStreamHandler( logging.StreamHandler ): def __init__( self ): logging.StreamHandler.__init__( self ) self.addFilter( myFilter() ) dictConfig( { "version": 1, "formatters": { "default": { "()": "module.RequestFormatter", "format": "[%(asctime)s] %(levelname)s: \t%(message)s", } }, "handlers": { "console": { "class": "module.myStreamHandler", "formatter": "default" } }, "root": { "level": "INFO", "handlers": [ "console" ] } } ) ################################################################################ app = Flask( __name__ ) app.config.from_pyfile( "config.py" ) Compress( app ) Session( app ) if config.PROXY: app.wsgi_app = ProxyFix( app.wsgi_app ) ################################################################################ # Import the views from views.base import base app.register_blueprint( base, url_prefix = "/" ) app.register_blueprint( base, url_prefix = config.baseurl ) from views.files import files app.register_blueprint( files, url_prefix = config.baseurl ) from views.login import login_view app.register_blueprint( login_view, url_prefix = config.baseurl ) from views.newuser import newuser_view app.register_blueprint( newuser_view, url_prefix = config.baseurl ) from views.donor import donor_view app.register_blueprint( donor_view, url_prefix = config.baseurl ) from views.submission import submission_view app.register_blueprint( submission_view, url_prefix = config.baseurl ) from views.tp_template import tp_template_view app.register_blueprint( tp_template_view, url_prefix = config.baseurl ) from views.images import image_view app.register_blueprint( image_view, url_prefix = config.baseurl ) ################################################################################ # Headers @app.after_request def add_header( r ): for c in [ "/cdn", "/static" ]: if request.path.startswith( config.baseurl + c ): break else: r.headers[ "Last-Modified" ] = http_date( datetime.now() ) r.headers[ "Cache-Control" ] = "no-cache, no-store, must-revalidate, max-age=0, s-maxage=0" r.headers[ "Pragma" ] = "no-cache" r.headers[ "Expires" ] = "0" return r ################################################################################ # PiAnoS API @app.route( config.baseurl + "/pianos_api" ) @admin_required def pianos_actions(): """ Serve the page with all actions related to the dedicated PiAnoS server. """ app.logger.info( "Serve the PiAnoS actions page" ) return my_render_template( "PiAnoS/actions.html" ) @app.route( config.baseurl + "/pianos_api/add_user/all" ) @admin_required def pianos_update_all_accounts(): """ serve the function to update the users in PiAnoS """ app.logger.info( "Copy all accounts to PiAnoS" ) return jsonify( { "error": not do_pianos_update_all_accounts() } ) def do_pianos_update_all_accounts(): """ Copy/update the credentials for all users. This function keep the credentials in sync between ICNML and PiAnoS. """ try: sql = """ SELECT users.username, users.password, account_type.name as g FROM users LEFT JOIN account_type ON users.type = account_type.id WHERE users.password IS NOT NULL """ nb = 0 for user in config.db.query_fetchall( sql ): nb += 1 username, h, group_name = user app.logger.debug( "Copy the user '{}' to PiAnoS".format( username ) ) groupid = config.pianosdb.create_group( group_name ) pianos_user_id = config.pianosdb.create_user( username = username, hash = h, groupid = groupid ) config.pianosdb.reset_user( username, hash = h ) config.pianosdb.create_folder( "{}'s folder".format( username ), pianos_user_id, None, pianos_user_id ) config.pianosdb.commit() app.logger.info( "{} users copied to PiAnoS".format( nb ) ) return True except: return False @app.route( config.baseurl + "/pianos_api/add_segments/all" ) @admin_required def pianos_copy_all_segments(): """ Route to push all segments to PiAnoS. """ app.logger.info( "Copy all segments to PiAnoS" ) return jsonify( { "error": not do_pianos_copy_all_segments() } ) def do_pianos_copy_all_segments(): """ Copy all segments images to PiAnoS. If the case already exists, the image is not pushed to PiAnoS. """ try: folder_id = config.pianosdb.create_folder( "Annotation" ) img = Image.new( "L", ( 200, 200 ), 255 ) empty_img_res = 500 empty_img_id = config.pianosdb.create_image( "PRINT", img, empty_img_res, "empty" ) sql = """ SELECT files_segments.uuid, files_segments.data, files_v.resolution FROM files_segments LEFT JOIN files_v ON files_segments.tenprint = files_v.uuid """ for segment in config.db.query_fetchall( sql ): img = str2img( segment[ "data" ] ) app.logger.debug( "{}: {}".format( segment[ "uuid" ], img ) ) try: config.pianosdb.create_exercise( folder_id, segment[ "uuid" ], "", img, segment[ "resolution" ], empty_img_id, empty_img_res ) except caseExistsInDB: continue except: raise config.pianosdb.commit() return True except: return False ################################################################################ # Home page @app.route( config.baseurl + "/" ) @login_required def home(): """ Serve the homepage to all users. """ if session[ "account_type_name" ] == "Donor": return redirect( url_for( "donor.user_myprofile_dek" ) ) elif session[ "account_type_name" ] == "Submitter": return redirect( url_for( "submission.submission_list" ) ) else: return my_render_template( "index.html" )