Skip to content
module.py 7.81 KiB
Newer Older
#!/usr/bin/python
# -*- coding: UTF-8 -*-

from datetime import datetime
from logging.config import dictConfig
import logging
Marco De Donno's avatar
Marco De Donno committed
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
Marco De Donno's avatar
Marco De Donno committed
from werkzeug.middleware.proxy_fix import ProxyFix
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" )
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 )
Marco De Donno's avatar
Marco De Donno committed

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" )
    
        "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
        for user in config.db.query_fetchall( sql ):
            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 ) )
        
    except:
@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()
################################################################################
#    Home page

@app.route( config.baseurl + "/" )
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" )