Skip to content
module.py 130 KiB
Newer Older
def submission_tenprint_segments_list( submission_id, tenprint_id ):
    """
        Serve the page with the list of segments for a tenprint image.
    """
    app.logger.info( "Get the list of segments for tenprint '{}', submission id '{}'".format( tenprint_id, submission_id ) )
    sql = "SELECT id, nickname FROM submissions WHERE uuid = %s"
    r = config.db.query( sql, ( submission_id, ) )
    submission_folder_id, nickname = r.fetchone()
    
    sql = "SELECT uuid, filename FROM files WHERE folder = %s AND files.uuid = %s"
    
    r = config.db.query( sql, ( submission_folder_id, tenprint_id, ) )
    filename = do_decrypt_user_session( tenprint_file[ "filename" ] )
    tenprint_id = tenprint_file[ "uuid" ]
    
    ############################################################################
    
    sql = """
        SELECT files_segments.pc, files_segments.data, pc.name
        FROM files_segments
        LEFT JOIN pc ON pc.id = files_segments.pc
        WHERE tenprint = %s
    """
    segments = config.db.query( sql, ( tenprint_id, ) ).fetchall()
    
    app.logger.debug( "{} segments stored in database".format( nb_segments ) )
    
    ############################################################################
    
Marco De Donno's avatar
Marco De Donno committed
    return my_render_template( 
        submission_id = submission_id,
        tenprint_id = tenprint_id,
        nickname = nickname,
        filename = filename,
        segments = segments,
@app.route( baseurl + "/submission/<submission_id>/tenprint/<tenprint_id>/segment/<pc>" )
def submission_segment( submission_id, tenprint_id, pc ):
    """
        Serve the page to edit the information relative to a segment image.
    """
    app.logger.info( "Serve the edit page for segment '{}'".format( pc ) )
    
    pc = int( pc )
    pc_list = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 25, 27 ]
        app.logger.error( "'{}' not in the pc_list".format( pc ) )
        return redirect( url_for( "submission_tenprint_segments_list", submission_id = submission_id, tenprint_id = tenprint_id ) )
        app.logger.debug( "Retrieving data for submission '{}', pc '{}'".format( submission_id, pc ) )
        
        sql = "SELECT id, nickname FROM submissions WHERE uuid = %s"
        r = config.db.query( sql, ( submission_id, ) )
        submission_folder_id, nickname = r.fetchone()
        
        sql = "SELECT uuid, filename, type FROM files WHERE folder = %s AND files.uuid = %s"
        r = config.db.query( sql, ( submission_folder_id, tenprint_id, ) )
        tp_filename = do_decrypt_user_session( tp_file[ "filename" ] )
        
        sql = "SELECT name FROM pc WHERE id = %s"
        pc_name = config.db.query( sql, ( pc, ) ).fetchone()[ 0 ]
        
Marco De Donno's avatar
Marco De Donno committed
        sql = """
            SELECT gp.div_name
            FROM donor_fingers_gp
            LEFT JOIN submissions ON donor_fingers_gp.donor_id = submissions.donor_id
            LEFT JOIN gp ON donor_fingers_gp.gp = gp.id
            
            WHERE submissions.uuid = %s AND donor_fingers_gp.fpc = %s
Marco De Donno's avatar
Marco De Donno committed
        """
        try:
            current_gp = config.db.query( sql, ( submission_id, pc, ) ).fetchone()[ 0 ]
        except:
            current_gp = None
        if pc in xrange( 1, 10 ):
            next_pc = pc + 1
            tp_type = "finger"
        elif pc == 10:
            next_pc = None
            tp_type = "finger"
        elif pc == 25:
            next_pc = 27
            tp_type = "palm"
        elif pc == 27:
            tp_type = "palm"
        else:
            return abort( 404 )
        app.logger.debug( "pc: {}".format( pc ) )
        app.logger.debug( "tp_type: {}".format( tp_type ) )
        app.logger.debug( "next pc: {}".format( next_pc ) )
        
Marco De Donno's avatar
Marco De Donno committed
        return my_render_template( 
            submission_id = submission_id,
            nickname = nickname,
            pc_name = pc_name,
            tp_filename = tp_filename,
            tenprint_id = tenprint_id,
@app.route( baseurl + "/submission/<submission_id>/tenprint/segment/<pc>/set/gp", methods = [ "POST" ] )
def submission_segment_set_gp( submission_id, pc ):
    """
        Set the general pattern of a fingerprint segment image (FPC 1-10).
    """
    gp = request.form.get( "gp" )
    
    app.logger.info( "Set general pattern for '{}', pc '{}' to '{}'".format( submission_id, pc, gp ) )
    
    sql = "SELECT id FROM gp WHERE name = %s"
    r = config.db.query( sql, ( gp, ) ).fetchone()
    if r == None:
        app.logger.error( "General pattern not recognized" )
        return jsonify( {
            "error": True,
            "message": "General patter not recognized"
    gp_id = r[ "id" ]
    
    sql = """
        SELECT count( * )
        FROM donor_fingers_gp
        LEFT JOIN submissions ON donor_fingers_gp.donor_id = submissions.donor_id
        WHERE submissions.uuid = %s AND donor_fingers_gp.fpc = %s
        GROUP BY donor_fingers_gp.id
    """
    nb = config.db.query_fetchone( sql, ( submission_id, pc, ) )
    
    sql = "SELECT donor_id FROM submissions WHERE uuid = %s"
    donor_id = config.db.query_fetchone( sql, ( submission_id, ) )[ "donor_id" ]
    
    if nb == 0 or nb == None:
        app.logger.debug( "Insert general pattern in database" )
        sql = utils.sql.sql_insert_generate( "donor_fingers_gp", [ "donor_id", "fpc", "gp" ] )
        config.db.query( sql, ( donor_id, pc, gp_id, ) )
    
    else:
        app.logger.debug( "Update general patern in database" )
        sql = "UPDATE donor_fingers_gp SET gp = %s WHERE donor_id = %s AND fpc = %s"
        config.db.query( sql, ( gp_id, donor_id, pc, ) )
    
    config.db.commit()
    
    return jsonify( {
        "error": False
################################################################################
#    User profile

@app.route( baseurl + "/user/myprofile/dek" )
@login_required
def user_myprofile_dek():
    app.logger.info( "Serve the donor DEK page" )
    
        FROM donor_dek
        WHERE donor_name = %s
    """
    data = config.db.query_fetchone( sql, ( session[ "username" ], ) )
    
    has_dek = data[ "dek" ] != None
    has_salt = data[ "salt" ] != None
    app.logger.debug( "username: {}".format( session[ "username" ] ) )
    app.logger.debug( "has_dek:  {}".format( has_dek ) )
    app.logger.debug( "has_salt: {}".format( has_salt ) )
    
    return my_render_template( 
        "users/profile/dek.html",
        has_dek = has_dek,
        has_salt = has_salt
@app.route( baseurl + "/user/myprofile/tenprint" )
@login_required
def user_myprofile_tenprint():
    """
        Serve the page to see all the information related to the current user.

        This page is the summary of all informations related to the current logged user,
        i.e. the tenprint cards and latent images. The consent form, beeing mendatory to
        upload the tenprint and latent images, and beeing encrypted in the database, is
        not accessible by the user via this interface. The consent form has been sent the 
        the donor by email anyways before uploading any of the images.
    """
    app.logger.info( "Serve the page with all tenprint to the donor" )
    
    sql = """
        SELECT files.id, files.uuid
        FROM users
        LEFT JOIN submissions ON users.email = submissions.email_hash
        LEFT JOIN files ON files.folder = submissions.id
        WHERE users.id = %s AND ( files.type = 1 OR files.type = 2 OR files.type = 5 )
    """
    tenprint_cards = config.db.query_fetchall( sql, ( session[ "user_id" ], ) )
    
    app.logger.debug( "{} tenprint(s) stored in database".format( len( tenprint_cards ) ) )
    
Marco De Donno's avatar
Marco De Donno committed
    return my_render_template( 
        "users/profile/tenprint.html",
################################################################################
#    Tenprint templates

@app.route( baseurl + "/template/tenprint/list" )
@admin_required
def template_tenprint_list():
    """
        Serve the page with the list of templates.
    """
    app.logger.info( "Serve the list of tenprint templates" )
    
    sql = "SELECT id, country_code, name FROM tenprint_cards ORDER BY name ASC"
    tp_templates = config.db.query( sql ).fetchall()
    
    app.logger.debug( "{} tenmplates found".format( len( tp_templates ) ) )
    
Marco De Donno's avatar
Marco De Donno committed
    return my_render_template( 
        "tp_template/list.html",
@app.route( baseurl + "/template/tenprint/new" )
@admin_required
def template_tenprint_new_meta():
    """
        Serve the page to create a new tenprint template.
    """
    app.logger.info( "Create a new tenprint template" )
    
    return my_render_template( "tp_template/new_meta.html" )
@app.route( baseurl + "/template/tenprint/new/<template_id>/images" )
def template_tenprint_new_images( template_id ):
    """
        Add new images to a tenprint template.
    """
    app.logger.info( "Add a new image to the tenprint template '{}'".format( template_id ) )
     
    sql = "SELECT id, name, country_code FROM tenprint_cards WHERE id = %s"
    card = config.db.query( sql, ( template_id, ) ).fetchone()
Marco De Donno's avatar
Marco De Donno committed
    return my_render_template( 
@app.route( baseurl + "/template/tenprint/new/insert", methods = [ "POST" ] )
@admin_required
def template_tenprint_new_do():
    """
        Save the tenprint template to the database.
    """
    app.logger.info( "Save the tenprint template to the database" )
    name = request.form.get( "name" )
    country_code = request.form.get( "country_code" )
    
    app.logger.debug( "name: {}".format( name ) )
    app.logger.debug( "country code: {}".format( country_code ) )
    
    sql = utils.sql.sql_insert_generate( "tenprint_cards", [ "name", "country_code" ] )
    q = config.db.query( sql, ( name, country_code, ) )
    template_id = q.fetchone()[ 0 ]
    pc_list = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 25, 27 ]
    app.logger.debug( "Set all zones values to 0 for FPC in {}".format( pc_list ) )
    for pc in pc_list:
        sql = utils.sql.sql_insert_generate( "tenprint_zones", [ "card", "pc", "angle", "tl_x", "tl_y", "br_x", "br_y" ] )
        config.db.query( sql, ( template_id, pc, 0, 0, 0, 0, 0 ) )
        "error": False,
@app.route( baseurl + "/template/tenprint/new/<template_id>/upload_image", methods = [ "POST" ] )
def template_tenprint_new_uploadimage( template_id ):
    """
        Save the front and back images for a tenprint template to the databse.
    """
    app.logger.info( "Upload new image for the tenprint template '{}'".format( template_id ) )
    
    face = request.form.get( "card_face" )
    
    if face in [ "front", "back" ]:
        data = request.files[ "file" ]
        image_width, image_height = img.size
            res = img.info[ "dpi" ][ 0 ]
            width = round( image_width * 2.54 / float( res ) )
            height = round( image_height * 2.54 / float( res ) )
        except:
            res = 0
            width = 0
            height = 0
        app.logger.debug( "face: {}".format( face ) )
        app.logger.debug( "image: {}".format( img ) )
        app.logger.debug( "width: {}".format( width ) )
        app.logger.debug( "height: {}".format( height ) )
        app.logger.debug( "resolution: {}".format( res ) )
        
        fp = StringIO()
        img.save( fp, format = "JPEG" )
        fp.seek( 0 )
        data = fp.getvalue()
        data = base64.b64encode( data )
        
        app.logger.debug( "Saving the image to the database" )
        
        sql = """
            UPDATE tenprint_cards
            SET
                image_{0} = %s,
                image_{0}_width = %s,
                image_{0}_height = %s,
                image_resolution = %s,
                image_format = %s,
                width = %s,
                height = %s
            
            WHERE id = %s""".format( face )
        
        config.db.query( sql, ( data, image_width, image_height, res, "JPEG", width, height, template_id, ) )
                "error": False
                "need_action": True,
                "action": "set_resolution"
@app.route( baseurl + "/template/tenprint/<template_id>/set/resolution", methods = [ "POST" ] )
def template_tenprint_new_setresolution( template_id ):
    """
        Set the resolution for a tenprint template image.
    """
    app.logger.info( "Set the resolution of the tenprint template '{}' to '{}'".format( template_id, res ) )
    
    try:
        sql = "UPDATE tenprint_cards SET image_resolution = %s WHERE id = %s"
        config.db.query( sql, ( res, template_id, ) )
            "error": False
            "error": True
def get_tenprint_template_zones( template_id, t ):
    """
        Get all the segments zones for a template passed in parameter.
    """
    app.logger.info( "Get all zones for the tenprint template '{}'".format( template_id, t ) )
    
    sql = """
        SELECT
            tenprint_zones.pc, tl_x, tl_y, br_x, br_y, angle, pc.name
        FROM tenprint_zones
        JOIN tenprint_zones_location ON tenprint_zones.pc = tenprint_zones_location.pc
        JOIN pc ON tenprint_zones.pc = pc.id
        WHERE
            card = %s AND
            tenprint_zones_location.side = %s
        ORDER BY pc
    """
    r = config.db.query( sql, ( template_id, t, ) ).fetchall()
    
    zones = []
    for pc, tl_x, tl_y, br_x, br_y, angle, pc_name in r:
        tl_x = utils.misc.float_or_null( tl_x )
        tl_y = utils.misc.float_or_null( tl_y )
        br_x = utils.misc.float_or_null( br_x )
        br_y = utils.misc.float_or_null( br_y )
        
        zones.append( {
            "pc": pc,
            "tl_x": tl_x,
            "tl_y": tl_y,
            "br_x": br_x,
            "br_y": br_y,
            "angle": angle,
            "pc_name": pc_name
        } )
    
    app.logger.debug( "{} zones for the tenprint template '{}'".format( len( zones ), template_id ) )
    
@app.route( baseurl + "/template/tenprint/<template_id>/<side>" )
@login_required
def template_tenprint( template_id, side ):
    """
        Serve the tenprint template page.
    """
    app.logger.info( "Serve the tenprint template edit page for '{}', '{}'".format( template_id, side ) )
    
    if side in [ "front", "back" ]:
Marco De Donno's avatar
Marco De Donno committed
        sql = """
            SELECT
                tenprint_zones.pc, tl_x, tl_y, br_x, br_y, angle, pc.name
            FROM tenprint_zones
            JOIN tenprint_zones_location ON tenprint_zones.pc = tenprint_zones_location.pc
            JOIN pc ON tenprint_zones.pc = pc.id
            WHERE card = %s AND tenprint_zones_location.side = %s ORDER BY pc
        """
        r = config.db.query( sql, ( template_id, side, ) ).fetchall()
        for pc, tl_x, tl_y, br_x, br_y, angle, pc_name in r:
            tl_x = utils.misc.float_or_null( tl_x )
            tl_y = utils.misc.float_or_null( tl_y )
            br_x = utils.misc.float_or_null( br_x )
            br_y = utils.misc.float_or_null( br_y )
            
            zones.append( {
                "pc": pc,
                "tl_x": tl_x,
                "tl_y": tl_y,
                "br_x": br_x,
                "br_y": br_y,
                "angle": angle,
                "pc_name": pc_name
        app.logger.debug( "{} zones for '{}'".format( len( zones ), template_id ) )
        
        datacolumns = [ "tl_x", "tl_y", "br_x", "br_y", "angle" ]
Marco De Donno's avatar
Marco De Donno committed
        sql = """
            SELECT
                id,
                name, country_code,
                width, height, size_display,
                image_{0}_width, image_{0}_height,
                image_resolution
            FROM tenprint_cards
            WHERE id = %s LIMIT 1
        """.format( side )
Marco De Donno's avatar
Marco De Donno committed

        r = config.db.query( sql, ( template_id, ) )
        img_info = r.fetchone()
        
        card_info = {
            "width": int( round( float( img_info[ "width" ] ) / 2.54 * img_info[ "image_resolution" ] ) ),
            "height": int( round( float( img_info[ "height" ] ) / 2.54 * img_info[ "image_resolution" ] ) ),
        app.logger.debug( "card width:  {}".format( card_info[ "width" ] ) )
        app.logger.debug( "card height: {}".format( card_info[ "height" ] ) )
        
        svg_h = float( img_info[ "image_{}_height".format( side ) ] )
        svg_w = float( img_info[ "image_{}_width".format( side ) ] )
        svg_hw_factor = svg_w / svg_h
        app.logger.debug( "svg width:  {}".format( svg_w ) )
        app.logger.debug( "svg height: {}".format( svg_h ) )
        
Marco De Donno's avatar
Marco De Donno committed
        return my_render_template( 
            "tp_template/template.html",
            zones = zones,
            img_info = img_info,
            card_info = card_info,
            side = side,
        app.logger.error( "{} not allowed".format( side ) )
        return abort( 403 )

@app.route( baseurl + "/template/tenprint/<template_id>/set/zones", methods = [ "POST" ] )
def update_zone_coordinates( template_id ):
    """
        Update the segments zones coordinates in the database.
    """
    app.logger.info( "Set zones for '{}'".format( template_id ) )
    
    template_id = int( template_id )
    data = request.form.get( "data" )
    if data != None:
        data = json.loads( data )
        
        for pc, value in data.iteritems():
            pc = int( pc )
            
            app.logger.debug( "{}: {}".format( pc, value ) )
            
            for coordinate, v in value.iteritems():
Marco De Donno's avatar
Marco De Donno committed
                sql = "UPDATE tenprint_zones SET {} = %s WHERE card = %s AND pc = %s".format( coordinate )
            "error": False
@app.route( baseurl + "/template/tenprint/<template_id>/delete/zone", methods = [ "POST" ] )
def delete_zone_coordinates( template_id ):
    """
        Delete a unused segment zone for a template (for example FPC 25 and 27 on the front-page, ...)
    """
    app.logger.info( "Delete zone '{}' for template '{}'".format( pc, template_id ) )
    
    try:
        sql = "DELETE FROM tenprint_zones WHERE card = %s AND pc = %s"
        config.db.query( sql, ( template_id, pc, ) )
            "error": False
            "error": True
@app.route( baseurl + "/template/tenprint/<template_id>/set/<varname>", methods = [ "POST" ] )
def update_tptemplate_var( template_id, varname ):
    """
        Update the name, country_code or displayed size variable for a tenprint template.
    """
    app.logger.info( "Setting variable '{}' to template '{}'".format( varname, template_id ) )
    
    if not varname in [ "name", "country_code", "size_display" ]:
        app.logger.error( "'{}' not allowed".format( varname ) )
    
    else:
        try:
            data = request.form.get( varname )
            data = str( data )
            
Marco De Donno's avatar
Marco De Donno committed
            sql = "UPDATE tenprint_cards SET {} = %s WHERE id = %s".forat( varname )
            config.db.query( sql, ( data, template_id, ) )
                "error": False
                "error": True
@app.route( baseurl + "/template/tenprint/<template_id>/set/hw", methods = [ "POST" ] )
def update_tptemplate_hw( template_id ):
    """
        Set the image size of a template.
    """
    app.logger.info( "Setting the height and width for tenprint template '{}'".format( template_id ) )
    
    try:
        h = request.form.get( "height" )
        w = request.form.get( "width" )
        
        h = float( h )
        w = float( w )
        
        app.logger.debug( "height: {}".format( h ) )
        app.logger.debug( "wigth:  {}".format( w ) )
        
        sql = "UPDATE tenprint_cards SET height = %s, width = %s WHERE id = %s"
        config.db.query( sql, ( h, w, template_id, ) )
            "error": False
            "error": True
@app.route( baseurl + "/template/tenprint/<template_id>/set/resolution" )
def update_tptemplate_res( template_id ):
    """
        Update the resolution of the image for a template.
    """
    app.logger.info( "Setting the resolution for tenprint template '{}'".format( template_id ) )
    
    try:
        res = request.form.get( "resolution" )
        res = float( res )
        
        app.logger.debug( "resolution: {}".format( res ) )
        
        sql = "UPDATE tenprint_cards SET image_resolution = %s WHERE id = %s"
        config.db.query( sql, ( res, template_id, ) )
            "error": False
            "error": True
################################################################################
#    PiAnoS API

@app.route( 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( 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 ) )
        
@app.route( 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( baseurl + "/" )
def home():
    """
        Serve the homepage to all users.
    """
    return my_render_template( "index.html" )
################################################################################
#    Main application configuration
gpg = gnupg.GPG( **config.gpg_options )

for key_file in os.listdir( config.keys_folder ):
    with open( config.keys_folder + "/" + key_file, "r" ) as fp:
        gpg.import_keys( fp.read() )

account_type_id_name = {}
sql = "SELECT id, name FROM account_type"
for at in config.db.query_fetchall( sql ):
    account_type_id_name[ at[ "id" ] ] = at[ "name" ]