def rebuildnotificationsdb(tabledict=['queuednotifications', 'sentnotifications']):
    from iiutilities.dblib import sqlitemultquery
    from cupid.pilib import dirs

    runquery = False
    querylist = []
    addentries = True

    table = 'queuednotifications'
    if table in tabledict:
        runquery = True

        querylist.append('drop table if exists ' + table)
        querylist.append(
            "create table " + table + " ( queuedtime text default '', type text default 'email', message text default '', options text default '')")

    table = 'sentnotifications'
    if table in tabledict:
        runquery = True

        querylist.append('drop table if exists ' + table)
        querylist.append(
            "create table " + table + " ( queuedtime text default '', senttime text default '', type text default 'email', message text default '', options text default '')")

    if runquery:
        print(querylist)

        sqlitemultquery(dirs.dbs.notifications, querylist)
def rebuildusersdata(argument=None):
    from pilib import gethashedentry, dirs
    from iiutilities.dblib import sqlitemultquery

    querylist = []
    runquery = True

    querylist.append('drop table if exists users')
    enteringusers = True
    runquery = False
    index = 1
    querylist.append(
        'create table users (id integer primary key not null, name text not null, password text not null, email text not null, temp text not null, authlevel integer default 0)')
    if argument == 'defaults':
        runquery = True
        entries = [{'user': '******', 'password': '******', 'email': '*****@*****.**', 'authlevel': 1},
                   {'user': '******', 'password': '******', 'email': '*****@*****.**', 'authlevel': 4},
                   {'user': '******', 'password': '******', 'email': '*****@*****.**',
                    'authlevel': 3}]
        index = 1
        for entry in entries:
            hashedentry = gethashedentry(entry['user'], entry['password'])
            querylist.append(
                "insert into users values(" + str(index) + ",'" + entry['user'] + "','" + hashedentry + "','" + entry[
                    'email'] + "',''," + str(entry['authlevel']) + ")")
            index += 1

    else:
        while enteringusers:
            validentry = True
            userinput = raw_input("Enter username or Q to stop: ")
            if userinput == 'Q':
                print('exiting ...')
                break
            passone = raw_input("Enter password: "******"Confirm password: "******"Enter user email")
            authlevelentry = raw_input("Enter authorization level (0-5)")

            if passone != passtwo:
                validentry = False
                print('passwords do not match')
            if not len(passone) >= 6:
                validentry = False
                print('passwords must be at least six characters')
            if not emailentry.find('@') > 0:
                validentry = False
                print('Email does not appear to be valid')

            if validentry:
                hashedentry = gethashedentry(userinput, passone)

                querylist.append("insert into users values(" + str(
                    index) + ",'" + userinput + "','" + hashedentry + "','" + emailentry + "',''," + authlevelentry + ")")
                index += 1
                runquery = True

    if runquery:
        print(querylist)
        sqlitemultquery(dirs.dbs.users, querylist)
def rebuildstockdb(tablelist=None):

    from iiutilities.dblib import sqlitemultquery
    from inventory.inventorylib import sysvars
    from iiutilities import datalib

    dbpath = sysvars.dirs.dbs.stock
    thetime = datalib.gettimestring()

    if not tablelist:
        tablelist = ['stock']

    # Create databases entries or leave them empty?
    addentries = True

    querylist = []
    runquery = False


    ### Stock
    table = 'stock'
    if table in tablelist:
        runquery = True
        querylist.append('drop table if exists ' + table)
        querylist.append(
            "create table " + table + " (partid text primary key, status text default 'active'," +
            "description text default '', qtyunit text default 'each', qtystock real default 0, qtyonorder real default 0," +
            "qtyreserved real default 0, qtyavailable real default 0, qtystatus text default '', cost real default 0," +
            "stockcost real default 0, onordercost real default 0, totalcost real default 0," +
            "stockprice real default 0, onorderprice real default 0, totalprice real default 0," +
            "costqty real default 1, costqtyunit text default 'each', supplier text default '', " +
            "supplierpart text default '', manufacturer text default '', manufacturerpart text default '', " +
            "notes text default '', partdata text default '', datasheet text default '', inuse integer default 1, datecreated text default '', " +
            "createdby text default '', inventory integer text default 'std', minqty text default 0, type text default parts," +
            "marginmethod text default 'type', margin real default 0, price real default 0 )")

        if addentries:
            querylist.append("insert into " + table + " values ('A001', 'active', 'WIEGMANN 12x12x6', 'each', 1, 1, 1, \
            0, '', 149.97, 0,0,0,0,0,0,1, 'each', \
            'Cascade Controls', 'N412121206C', 'Wiegmann', 'N412121206C', '', '', '', 1, '" + thetime + "', 'CCR', \
            'std', 0, 'parts', 'type', 0, 0)")
            querylist.append("insert into " + table + " values ('A002', 'active', 'WIEGMANN 16x16x6', 'each', 1, 1, 2, \
            0, '', 172, 0,0,0,0,0,0,1, 'each', \
            'Cascade Controls', 'N412121206C', 'Wiegmann', 'N412121206C', '', '', '', 1, '" + thetime + "', 'CCR', \
            'std', 0, 'parts', 'type', 0, 0)")
            querylist.append("insert into " + table + " values ('A003', 'active', 'WIEGMANN 20x20x6', 'each', 1, 1, 2, \
            0, '', 204, 0,0,0,0,0,0,1, 'each', \
            'Cascade Controls', 'N412121206C', 'Wiegmann', 'N412121206C', '', '', '', 1, '" + thetime + "', 'CCR', 'std', 0, 'parts', 'type', 0, 0)")
            querylist.append("insert into " + table + " values ('A004', 'active', 'WIEGMANN 20x24x6', 'each', 1, 1, 2,\
             0,'',  233, 0,0,0,0,0,0,1, 'each', \
            'Cascade Controls', 'N412121206C', 'Wiegmann', 'N412121206C', '', '', '', 1, '" + thetime + "', 'CCR', 'std', 0, 'parts', 'type', 0, 0)")
            querylist.append("insert into " + table + " values ('L001', 'active', 'Shop Labor', 'hour', 1, 1, 2,\
             0, '', 42, 0,0,0,0,0,0,1, 'hour', \
            '', '', '', '', '', '', '', 1, '" + thetime + "', 'CCR', 'std', 0, 'labor', 'type', 0, 0)")

    print(querylist)
    print(dbpath)
    sqlitemultquery(dbpath, querylist)
def rebuildsessiondb():
    from iiutilities.dblib import sqlitemultquery
    from inventorylib import sysvars

    querylist = []

    ### Session limits

    table = 'sessionlimits'
    querylist.append('drop table if exists ' + table)
    querylist.append("create table " + table + " (username text primary key, sessionsallowed real default 5 )")

    querylist.append("insert into " + table + " values ('viewer', 5)")
    querylist.append("insert into " + table + " values ('controller', 5)")
    querylist.append("insert into " + table + " values ('administrator', 5)")
    querylist.append("insert into " + table + " values ('owner', 3)")
    querylist.append("insert into " + table + " values ('admin', 3)")
    querylist.append("insert into " + table + " values ('colin', 5)")

    ### Settings table

    table = 'settings'
    querylist.append('drop table if exists ' + table)
    querylist.append(
        "create table " + table + " (sessionlength real default 600, sessionlimitsenabled real default 1, updatefrequency real)")

    querylist.append("insert into " + table + " values (600,1,30)")

    ### Session table

    table = 'sessions'
    querylist.append('drop table if exists ' + table)
    querylist.append(
        "create table " + table + " (username text, sessionid text, sessionlength real, timecreated text, apparentIP text , realIP text)")

    ### Sessions summary

    table = 'sessionsummary'
    querylist.append('drop table if exists ' + table)
    querylist.append("create table " + table + " (username text,  sessionsactive real)")

    querylist.append("insert into " + table + " values ('viewer', 0)")
    querylist.append("insert into " + table + " values ('controller', 0)")
    querylist.append("insert into " + table + " values ('administrator', 0)")

    ### Session log

    table = 'sessionlog'
    querylist.append('drop table if exists ' + table)
    querylist.append(
        "create table " + table + " (username text, sessionid text, time text, action text, apparentIP text, realIP text)")


    # print(querylist)
    sqlitemultquery(sysvars.dirs.dbs.authlog, querylist)
Esempio n. 5
0
def recordspidata(database, valuedict, execute=False):
    from iiutilities import dblib, datalib
    # This is incomplete and hardcoded partially
    querylist = []
    for key, value in valuedict.items():
        querylist.append(dblib.makesqliteinsert('inputs',
                                                valuelist=[key, 'SPI1', 'TC', '1', 'SPITC1', value, 'F', datalib.gettimestring(), 1,
                                                           '','']))
        querylist.append(dblib.makesqliteinsert('ioinfo', valuelist=[key, key, '']))
    if execute:
        dblib.sqlitemultquery(database, querylist)

    return querylist
Esempio n. 6
0
def updateowfstable(database, tablename, busdevices, execute=True):
    from iiutilities.dblib import sqlitemultquery
    from iiutilities.dblib import makesqliteinsert

    querylist = []
    for device in busdevices:
        # print(device.id)
        # print([device.address, device.family, device.id, device.type, device.crc8])
        querylist.append(
            makesqliteinsert(tablename, [device.address, device.family, device.id, device.type, device.crc8]))
    # print(querylist)
    if execute:
        # print(database)
        # print(querylist)
        sqlitemultquery(database, querylist)
    return querylist
Esempio n. 7
0
def updateowfstable(database, tablename, busdevices, execute=True):
    from iiutilities.dblib import sqlitemultquery
    from iiutilities.dblib import makesqliteinsert

    querylist = []
    for device in busdevices:
        # print(device.id)
        # print([device.address, device.family, device.id, device.type, device.crc8])
        querylist.append(
            makesqliteinsert(tablename, [
                device.address, device.family, device.id, device.type,
                device.crc8
            ]))
    # print(querylist)
    if execute:
        # print(database)
        # print(querylist)
        sqlitemultquery(database, querylist)
    return querylist
def rebuildsystemdb(tablelist=None):

    from iiutilities.dblib import sqlitemultquery
    from inventory.inventorylib import sysvars
    dbpath = sysvars.dirs.dbs.system

    if not tablelist:
        tablelist = ['calcs', 'uisettings']


    querylist = []
    runquery = False

    ### Calcs
    table = 'calcs'
    if table in tablelist:
        runquery = True
        querylist.append('drop table if exists ' + table)
        querylist.append(
            "create table " + table + " (item text primary key, value text, notes text, detail text)")

        addentries = True
        if addentries:
            querylist.append("insert into " + table + " values ('partsmargin', '0.25', '', '')")
            querylist.append("insert into " + table + " values ('labormargin', '0.25', '', '')")
            querylist.append("insert into " + table + " values ('panelsizeoverheadmultiplier', '0.15', 'Dollars per \
                inch for miscellaneous parts.', '')")


    ### UISettings
    table = 'uisettings'
    if table in tablelist:
        runquery = True
        querylist.append('drop table if exists ' + table)
        querylist.append(
            "create table " + table + " (item text primary key, value text, notes text, detail text)")

    if runquery:
        sqlitemultquery(dbpath, querylist)
Esempio n. 9
0
def getdatameta(database, **kwargs):
    settings = {
        'get_time_span':True
    }
    settings.update(kwargs)

    tablenames = dblib.gettablenames(database)
    if 'metadata' in tablenames:
        tablenames.remove('metadata')
    queryarray = []
    for tablename in tablenames:
        queryarray.append("select count(*) from '" + tablename + "'")
    results = dblib.sqlitemultquery(database, queryarray, **kwargs)['data']
    meta = []
    for result, tablename in zip(results, tablenames):
        this_meta = {}

        this_meta['tablename'] = tablename
        this_meta['numpoints'] = result[0][0]

        # Quick hacky way to know if this is an archive log or not
        if tablename == 'data':
            from os.path import split
            db_name = split(database)[1]
            types = table_name_to_type(db_name)
        else:
            types = table_name_to_type(tablename)

        this_meta['type'] = types['type']
        this_meta['subtype'] = types['subtype']
        this_meta['id'] = types['id']

        if settings['get_time_span']:
            timespan = dblib.gettimespan(database, tablename)['seconds']
            this_meta['timespan'] = timespan

        meta.append(this_meta)
    return meta
Esempio n. 10
0
def getdatameta(database, **kwargs):
    settings = {'get_time_span': True}
    settings.update(kwargs)

    tablenames = dblib.gettablenames(database)
    if 'metadata' in tablenames:
        tablenames.remove('metadata')
    queryarray = []
    for tablename in tablenames:
        queryarray.append("select count(*) from '" + tablename + "'")
    results = dblib.sqlitemultquery(database, queryarray, **kwargs)['data']
    meta = []
    for result, tablename in zip(results, tablenames):
        this_meta = {}

        this_meta['tablename'] = tablename
        this_meta['numpoints'] = result[0][0]

        # Quick hacky way to know if this is an archive log or not
        if tablename == 'data':
            from os.path import split
            db_name = split(database)[1]
            types = table_name_to_type(db_name)
        else:
            types = table_name_to_type(tablename)

        this_meta['type'] = types['type']
        this_meta['subtype'] = types['subtype']
        this_meta['id'] = types['id']

        if settings['get_time_span']:
            timespan = dblib.gettimespan(database, tablename)['seconds']
            this_meta['timespan'] = timespan

        meta.append(this_meta)
    return meta
def rebuildsafedb(tabledict={'usermeta':True, 'users':True, 'pathaliases':True}):

    """

    System safe database. Contains users and other info that we do not want in the web path.

    """

    from iiutilities import datalib, dblib
    from inventory import inventorylib

    table = 'usermeta'
    if table in tabledict:

        createentries = True
        querylist = ['drop table if exists ' + table]
        querylist.append(
            "create table " + table + " (user text primary key, data text)")

        if createentries:
            querylist.append("insert into " + table + " values('creese','pathalias:iiinventory')")
            querylist.append("insert into " + table + " values('demo','pathalias:demo')")
            querylist.append("insert into " + table + " values('iwalker','pathalias:isaac')")
            querylist.append("insert into " + table + " values('mbertram','pathalias:demo')")

        try:
            print(querylist)
            print(inventorylib.sysvars.dirs.dbs.safe)
            dblib.sqlitemultquery(inventorylib.sysvars.dirs.dbs.safe, querylist)
        except:
            print('ERROR in usermeta query')

    table = 'pathaliases'
    if table in tabledict:
        runquery = True

        createentries = True
        querylist =['drop table if exists ' + table]
        querylist.append(
            "create table " + table + " (alias text primary key, path text)")

        if createentries:
            querylist.append("insert into " + table + " values('iiinventory','iiinventory')")
            querylist.append("insert into " + table + " values('demo','demo')")

        try:
            print(querylist)
            print(inventorylib.sysvars.dirs.dbs.safe)
            dblib.sqlitemultquery(inventorylib.sysvars.dirs.dbs.safe, querylist)
        except:
            print('Error in ' + table + ' query')



    table = 'users'
    if table in tabledict:

        ### No default tables. Create a table as an example

        querylist=['drop table if exists ' + table,
                    "create table " + table + " ( id integer primary key not null, name text unique, password text, " +
                                              "email text, accesskeywords text, authlevel integer default 1, " +
                                              "temp text, admin integer default 0)"]

        addentries = True
        if addentries:
            entries = [{'name': 'creese', 'password': '******', 'email': '*****@*****.**', 'accesskeywords': 'iiinventory,demo', 'authlevel':5, 'temp': '', 'admin': 1},
                       {'name': 'iwalker', 'password': '******', 'email': '*****@*****.**', 'accesskeywords': 'demo', 'authlevel':4, 'temp':'', 'admin': 0},
                       {'name': 'demo', 'password': '******', 'email': '*****@*****.**', 'accesskeywords': 'demo', 'authlevel':2, 'temp':'', 'admin': 0},
                       {'name': 'mbertram', 'password': '******', 'email': '*****@*****.**', 'accesskeywords': 'demo', 'authlevel': 2, 'temp': '', 'admin': 0}]

            index = 1
            for entry in entries:
                hashedentry = datalib.gethashedentry(entry['name'], entry['password'], salt=inventorylib.sysvars.salt)
                querylist.append(dblib.makesqliteinsert(table, [index, entry['name'], hashedentry, entry['email'], entry['accesskeywords'], entry['authlevel'], '', entry['admin']]))
                index += 1

        try:
            print(querylist)
            print(inventorylib.sysvars.dirs.dbs.safe)
            dblib.sqlitemultquery(inventorylib.sysvars.dirs.dbs.safe, querylist)
        except:
            print('Error in ' + table + ' query')
Esempio n. 12
0
def application(environ, start_response):

    import cgi
    import json

    import os, sys, inspect

    # Set top folder to allow import of modules

    top_folder = os.path.split(
        os.path.realpath(
            os.path.abspath(
                os.path.split(inspect.getfile(inspect.currentframe()))[0])))[0]
    if top_folder not in sys.path:
        sys.path.insert(0, top_folder)

    from cupid import pilib, controllib
    from iiutilities import dblib, utility, datalib

    # post_env = environ.copy()
    # post_env['QUERY_STRING'] = ''
    # post = cgi.FieldStorage(
    #     fp=environ['wsgi.input'],
    #     environ=post_env,
    #     keep_blank_values=True
    # )
    #
    # formname=post.getvalue('name')
    # output = {}
    # output['message'] = 'Output Message: '
    # for k in post.keys():
    #     d[k] = post.getvalue(k)

    try:
        request_body_size = int(environ.get('CONTENT_LENGTH', 0))
    except ValueError:
        request_body_size = 0

    request_body = environ['wsgi.input'].read(request_body_size)
    post = json.loads(request_body.decode('utf-8'))

    output = {}
    output['message'] = ''

    status = '200 OK'
    wsgiauth = True
    authverified = False

    if wsgiauth:
        # Verfiy that session login information is legit: hashed password, with salt and username, match
        # hash stored in database.
        import hashlib

        safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.users)
        if 'username' in post and post['username']:
            output['message'] += 'Session user is ' + post['username'] + '. '
        else:
            output['message'] += 'No session user found. '
            post['username'] = ''

        if post['username']:
            try:
                condition = "name='" + post['username'] + "'"
                user_data = safe_database.read_table_row(
                    'users', condition=condition)[0]
            except:
                output[
                    'message'] += 'Error in user sqlite query for session user "' + post[
                        'username'] + '". '
                output[
                    'message'] += 'Condition: ' + condition + '. Path: ' + pilib.dirs.dbs.safe
                user_data = {'accesskeywords': 'demo', 'admin': False}
            else:
                # Get session hpass to verify credentials
                hashedpassword = post['hpass']
                hname = hashlib.new('sha1')
                hname.update(post['username'])
                hashedname = hname.hexdigest()
                hentry = hashlib.new('md5')
                hentry.update(hashedname + pilib.salt + hashedpassword)
                hashedentry = hentry.hexdigest()
                if hashedentry == user_data['password']:
                    # successful auth
                    output['message'] += 'Password verified. '
                    authverified = True

                    # TODO: implement usermeta
        else:
            # Demo status
            authverified = True
            user_data = {'authlevel': 0}

    else:
        output['message'] += 'WSGI authorization not enabled. '

    if authverified or not wsgiauth:
        output['authorized'] = True

    try:
        action = post['action']
    except KeyError:
        output['message'] = 'no action in request'
        action = ''
    else:
        output['message'] += '{} action keyword found'.format(action)

    if output['authorized'] and action:
        output['action_allowed'] = pilib.check_action_auths(
            action, user_data['authlevel'])
    else:
        output['action_allowed'] = False

    if output['authorized'] and output['action_allowed']:

        output['message'] += 'Found action. '

        if action == 'testdbvn':
            from iiutilities.dblib import dbvntovalue
            try:
                output['data'] = dbvntovalue(post['dbvn'])
            except:
                output['message'] += 'Error in dbvn evaluation. '
                output['data'] = 'error'
            else:
                output['message'] += 'Seems to have worked out. '
        elif action == 'testlogical':
            from iiutilities.datalib import evaldbvnformula
            try:
                output['data'] = evaldbvnformula(post['logical'])
            except:
                output['message'] += 'Error in logical evaluation. '
                output['data'] = 'error'
            else:
                output['message'] += 'Seems to have worked out. '

        elif action == 'testmodule':
            output['message'] += 'Testing module: '
            if 'modulename' in post:
                import cupid.cupidunittests
                output['message'] += post['modulename']
                output['data'] = cupid.cupidunittests.testmodule(
                    post['modulename'])
            else:
                output['message'] += 'Modulename not found. '
        elif action == 'testfunction':
            output['message'] += 'Testing function: '
            if 'testname' in post:
                import cupid.cupidunittests
                output['message'] += post['testname']
                # output['data'] = cupid.tests.testfunction(d['testname'])
                output['data'] = cupid.cupidunittests.testfunction(
                    post['testname'])
                # output['data'] = str(cupid.tests.testfunction('systemstatus'))
            else:
                output['message'] += 'Testname not found. '

        elif action == 'modifychannelalarm':
            controllib.handle_modify_channel_alarm(post, output)
            from cupid.actions import processactions

            # process only this action.
            processactions(name=post['actionname'])

        elif action == 'modifychannel':
            controllib.handle_modify_channel(post, output)

        elif action == 'getalarmscount':
            control_db = dblib.sqliteDatabase(pilib.dirs.dbs.control)
            actions = control_db.read_table('actions')
            output['data'] = {
                'totalalarms': len(actions),
                'channelalarms': 0,
                'activealarms': 0,
                'activechannelalarms': 0
            }
            for action in actions:
                if action['conditiontype'] == 'channel':
                    output['data']['channelalarms'] += 1
                    if action['active']:
                        output['data']['activechannelalarms'] += 1

                if action['active']:
                    output['data']['activealarms'] += 1

        elif action == 'copy_log_to_archive':
            pilib.app_copy_log_to_archive(post, output)

        elif action == 'getlogscount':
            logtablenames = dblib.sqliteDatabase(
                pilib.dirs.dbs.log).get_table_names()
            output['data'] = {'logscount': len(logtablenames)}

        elif action == 'test_action':
            output['message'] += 'Testing action. '
            controldb = dblib.sqliteDatabase(pilib.dirs.dbs.control)
            actiondict = controldb.read_table('actions',
                                              condition='"name"=\'' +
                                              post['actionname'] + "'")[0]
            from cupid.actions import action
            test_action = action(actiondict)
            test_action.test()

        elif action == 'update_network':
            safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe)
            safe_database.set_single_value('wireless', 'password',
                                           post['password'],
                                           "SSID='" + post['ssid'] + "'")

        elif action == 'add_network':
            safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe)
            insert = {'SSID': post['ssid'], 'auto': 1, 'priority': 1}
            if 'password' in post:
                insert['password'] = post['password']
            safe_database.insert('wireless', insert)

        elif action == 'delete_network':
            safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe)
            safe_database.delete('wireless', "SSID='" + post['ssid'] + "'")

        # elif action == 'dump':
        #     # this has to go.
        #     if 'database' in d:
        #         dbpath = pilib.dbnametopath(d['database'])
        #         if dbpath:
        #             if 'tablelist' in d and 'outputfile' in d:
        #                 dbpath = pilib.dbnametopath(d['database'])
        #                 dblib.sqlitedatadump(dbpath, d['tablelist'], d['outputfile'])
        #                 output['message'] = 'data dumped'
        #             elif 'tablename' in d and 'outputfile' in d:
        #                 dblib.sqlitedatadump(dbpath, [d['tablename']], d['outputfile'])
        #                 output['message'] = 'data dumped. '
        #             else:
        #                 output['message'] += 'keys not present for dump. '
        #         else:
        #             output['message'] += 'keys not present for dump. '
        #     else:
        #         output['message'] += 'keys not present for dump. '
        elif action in ['userdelete', 'useradd', 'usermodify']:
            """
            This needs to be consolidate with the other useradd, modify algorithm written already.
            Probably do this when we update the user permissions interface.
            """
            # Ensure that we are authorized for this action
            if action == 'userdelete':
                try:
                    dblib.sqlitequery(
                        pilib.dirs.dbs.users,
                        "delete from users where name='" +
                        post['usertodelete'] + "'")
                except:
                    output['message'] += 'Error in delete query. '
                else:
                    output['message'] += 'Successful delete query. '
            elif action == 'usermodify':

                if 'usertomodify' in post:
                    querylist = []
                    if 'newpass' in post:
                        from pilib import salt
                        # Get session hpass to verify credentials
                        hashedpassword = post['newpass']
                        hname = hashlib.new('sha1')
                        hname.update(post['usertomodify'])
                        hashedname = hname.hexdigest()
                        hentry = hashlib.new('md5')
                        hentry.update(hashedname + salt + hashedpassword)
                        hashedentry = hentry.hexdigest()
                        querylist.append('update users set password='******'" +
                                         post['usertomodify'] + "'")

                    if 'newemail' in post:
                        querylist.append("update users set email='" +
                                         post['newemail'] + "' where name='" +
                                         post['usertomodify'] + "'")
                    if 'newauthlevel' in post:
                        querylist.append("update users set authlevel='" +
                                         post['newauthlevel'] +
                                         "' where name='" +
                                         post['usertomodify'] + "'")

                    try:
                        dblib.sqlitemultquery(pilib.dirs.dbs.users, querylist)
                    except:
                        output[
                            'message'] += 'Error in modify/add query: ' + ",".join(
                                querylist)
                    else:
                        output[
                            'message'] += 'Successful modify/add query. ' + ",".join(
                                querylist)
                else:
                    output['message'] += 'Need usertomodify in query. '
            elif action == 'useradd':
                try:
                    username = post['newusername']
                except:
                    username = '******'
                try:
                    newemail = post['newemail']
                except:
                    newemail = '*****@*****.**'
                try:
                    newauthlevel = post['newauthlevel']
                except:
                    newauthlevel = 0
                    query = "insert into users values(NULL,'" + username + "','','" + newemail + "',''," + str(
                        newauthlevel) + ")"
                try:
                    dblib.sqlitequery(pilib.dirs.dbs.users, query)
                except:
                    output[
                        'message'] += "Error in useradd sqlite query: " + query + ' . '
                else:
                    output['message'] += "Successful query: " + query + ' . '
        elif action == 'getfiletext':
            try:
                filepath = post['filepath']
                if 'numlines' in post:
                    numlines = int(post['numlines'])
                else:
                    numlines = 9999
                output['message'] += 'Using numlines: ' + str(
                    numlines) + ' for read action. '
                if 'startposition' in post:
                    startposition = post['startposition']
                else:
                    startposition = 'end'
                output[
                    'message'] += 'Reading from position ' + startposition + '. '
            except KeyError:
                output[
                    'message'] += 'Sufficient keys for action getfile text do not exist. '
            except:
                output['message'] += 'Uncaught error in getfiletext. '
            else:
                try:
                    file = open(filepath)
                    lines = file.readlines()
                except:
                    output[
                        'message'] += 'Error reading file in getfiletext action. '
                else:
                    output['data'] = []
                    if startposition == 'end':
                        try:
                            output['data'] = datalib.tail(file, numlines)[0]
                        except:
                            output['message'] += 'Error in tail read. '
                    else:
                        linecount = 0
                        for line in lines:
                            linecount += 1
                            if linecount > numlines:
                                break
                            else:
                                output['data'].append(line)
        elif action == 'getmbtcpdata':
            try:
                clientIP = post['clientIP']
                register = post['register']
                length = post['length']
            except KeyError:
                output[
                    'message'] += 'Sufficient keys do not exist for the command. Requires clientIP, register, and length. '
            else:
                from iiutilities.netfun import readMBcodedaddresses
                # try:
                output['response'] = readMBcodedaddresses(
                    clientIP, int(register), int(length))
        elif action == 'queuemessage':
            output['message'] += 'Queue message. '
            if 'message' in post:
                try:
                    dblib.sqliteinsertsingle(
                        pilib.dirs.dbs.motes, 'queuedmessages',
                        [datalib.gettimestring(), post['message']])
                except:
                    import traceback
                    exc_type, exc_value, exc_traceback = sys.exc_info()
                    output[
                        'message'] += 'Error in queue insert query: {}. '.format(
                            traceback.format_exc())
                else:
                    output['message'] += 'Message insert successful'
            else:
                output['message'] += 'No message present. '

        elif action == 'setsystemflag' and 'systemflag' in post:
            database = pilib.dirs.dbs.system
            dblib.setsinglevalue(database, 'systemflags', 'value', 1,
                                 "name=\'" + post['systemflag'] + "'")
        elif action == 'rundaemon':
            from cupiddaemon import rundaemon
            rundaemon()

        # TODO: Eliminate this scary thing.
        elif action == 'setvalue':
            utility.log(pilib.dirs.logs.control, "Setting value in wsgi", 1, 1)

            # we use the auxiliary 'setsinglecontrolvalue' to add additional actions to update
            if all(k in post
                   for k in ('database', 'table', 'valuename', 'value')):
                dbpath = pilib.dbnametopath(post['database'])
                if dbpath:
                    output[
                        'message'] += 'Carrying out setvalue for value ' + post[
                            'valuename'] + ' on ' + post[
                                'table'] + ' in ' + dbpath
                    if 'condition' in post:
                        pilib.setsinglecontrolvalue(dbpath, post['table'],
                                                    post['valuename'],
                                                    post['value'],
                                                    post['condition'])
                    elif 'index' in post:
                        condition = 'rowid= ' + post['index']
                        pilib.setsinglecontrolvalue(dbpath, post['table'],
                                                    post['valuename'],
                                                    post['value'], condition)
                    else:
                        pilib.setsinglecontrolvalue(dbpath, post['table'],
                                                    post['valuename'],
                                                    post['value'])
                else:
                    output[
                        'message'] += 'Problem translating dbpath from friendly name: ' + post[
                            'database']
            else:
                output['message'] += 'Insufficient data for setvalue '
        elif action == 'updateioinfo':
            if all(k in post for k in ['database', 'ioid', 'value']):
                query = dblib.makesqliteinsert('ioinfo',
                                               [post['ioid'], post['value']],
                                               ['id', 'name'])
                try:
                    dblib.sqlitequery(pilib.dirs.dbs.control, query)
                except:
                    output[
                        'message'] += 'Error in updateioinfo query execution: ' + query + '. into database: ' + pilib.dirs.dbs.control
                    output['message'] += 'ioid: ' + post['ioid'] + ' . '
                else:
                    output['message'] += 'Executed updateioinfo query. '
            else:
                output[
                    'message'] += 'Insufficient data for updateioinfo query ! '

        # TODO: properly incorporate and test channel class functions here, and then sub it.
        elif action == 'modify_channel':
            controllib.app_modify_channel(post, output)

        elif action == 'deletechannelbyname' and 'database' in post and 'channelname' in post:
            dbpath = pilib.dbnametopath(post['database'])
            dblib.sqlitequery(
                dbpath, 'delete channelname from channels where name=\"' +
                post['channelname'] + '\"')
        elif action == 'updatecameraimage':
            output['message'] += 'Take camera image keyword. '
            import cupid.camera
            if 'width' in post:
                width = post['width']
            else:
                width = 800
            try:
                values = cupid.camera.takesnap(width=width)
            except:
                output['message'] += 'Error taking image. '
            else:
                output['message'] += 'Appears successful. Path : ' + values[
                    'imagepath'] + '. Timestamp : ' + values['timestamp'] + '. '
                output['data'] = values
        elif action == 'getcurrentcamtimestamp':
            output['message'] += 'getcurrentcamtimestamp keyword found. '
            try:
                with open('/var/www/webcam/images/current.jpg.timestamp') as f:
                    data = f.read()
            except:
                output['message'] += 'Error reading file as requested. '
            else:
                output['data'] = data
        else:
            output[
                'message'] += 'Action keyword present(' + action + '), but not handled. '
    else:
        output[
            'message'] += 'Authentication unsuccessful or action not authorized.'
        status = '401 Not Authorized'

    foutput = json.dumps(output, indent=1)

    response_headers = [('Content-type', 'application/json')]
    start_response(status, response_headers)

    return [foutput]
Esempio n. 13
0
def application(environ, start_response):
    import json
    import hashlib

    # Set top folder to allow import of modules

    import os, sys, inspect

    top_folder = \
        os.path.split(os.path.realpath(os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0])))[0]
    if top_folder not in sys.path:
        sys.path.insert(0, top_folder)

    import inventorylib
    from iiutilities import dblib, datalib
    from time import time

    try:
        request_body_size = int(environ.get('CONTENT_LENGTH', 0))
    except ValueError:
        request_body_size = 0

    request_body = environ['wsgi.input'].read(request_body_size)
    try:
        post = json.loads(request_body.decode('utf-8'))
    except:
        print('Error decoding: ')
        print(request_body.decode('utf-8'))
        post = {}

    output = {'message': ''}
    status = '200 OK'

    try:
        try:
            output['remote_ip'] = environ['HTTP_X_FORWARDED_FOR'].split(',')[-1].strip()
        except KeyError:
            output['remote_ip'] = environ['REMOTE_ADDR']
    except:
        output['remote_ip'] = 'Error getting IP address'


    """
    Here we verify credentials of session data against those in the database.
    While we authenticate in the browser, this does not stop POST queries to the API without the page provided
    So we take the hpass stored in the dictionary and verify.

    * Which databases are available are stored in users table, column accesskeywords
    * Which one is currently in use is stored in table usermeta, data where user=username. data is json-encoded metadata
        pathalias field

    * What path extension this corresponds to is stored in pathaliases

    """

    # I dont' think this will be used. We will get pathalias from database. Let's deal with changing it later.

    # First, let's get our pathalias and translate to a path, using our path reloader

    # if 'pathalias' in post:
    #     output['message'] += inventorylib.reloaddatapaths(pathalias=post['pathalias'])
    # else:
    #     output['message'] += 'No pathalias found in postictionary. '

    wsgiauth = True
    authverified = False

    if wsgiauth:

        # Verfiy that session login information is legit: hashed password, with salt and username, match
        # hash stored in postatabase.
        import hashlib

        safe_database = dblib.sqliteDatabase(inventorylib.sysvars.dirs.dbs.safe)
        if 'username' in post and post['username']:
            output['message'] += 'Session user is ' + post['username'] + '. '
        else:
            output['message'] += 'No session user found. '
            post['username'] = ''

        if post['username']:
            try:
                condition = "name='" + post['username'] + "'"
                user_data = safe_database.read_table_row('users', condition=condition)[0]
            except:
                output['message'] += 'error in user sqlite query for session user "' + post['username'] + '". '
                user_data = {'accesskeywords':'demo','admin':False}
            else:
                # Get session hpass to verify credentials

                hashedpassword = post['hpass']
                hname = hashlib.new('sha1')
                hname.update(post['username'].encode('utf-8'))
                hashedname = hname.hexdigest()
                hentry = hashlib.new('md5')
                hentry.update((hashedname + inventorylib.sysvars.salt + hashedpassword).encode('utf-8'))
                hashedentry = hentry.hexdigest()
                if hashedentry == user_data['password']:
                    # successful auth
                    output['message'] += 'Password verified. '
                    authverified = True
                    # output['message'] += 'accesskeywords : ' + str(userdata)
                    output['accesskeywords'] = user_data['accesskeywords']
                    if output['accesskeywords'].find(',') >= 0:
                        accesskeywords = output['accesskeywords'].split(',')
                        accesskeywords = [accesskeyword.strip() for accesskeyword in accesskeywords]
                    else:
                        accesskeywords = output['accesskeywords'].strip()

                    path_aliases = safe_database.read_table('pathaliases')

                    # Find usermeta entry and grab which database is selected. If one is not selected, update selection
                    # to first that user is allowed to access
                    try:
                        user_meta_row = safe_database.read_table_row('usermeta', condition="user='******'username'] + "'")[0]
                    except:
                        print('error getting usermeta for username ' + post['username'])
                        output['message'] += 'error getting usermeta for username ' + post['username']
                        user_meta_row = []
                        return

                    path_alias = ''
                    if not user_meta_row:
                        output['message'] += 'User meta entry not found. Attempting to create. '

                        # assign default database
                        default_database = accesskeywords[0]

                        output['message'] += 'Choosing pathalias from first in keywords: ' + default_database + '. '
                        if any(default_database == path_alias['alias'] for path_alias in path_aliases):
                            output['message'] += 'Verified that default alias exists in pathaliases database. '
                        else:
                            output['message'] += 'ERROR: first entry in keywords (' +default_database + ') not found in aliases. '

                        # Insert usermeta entry. This should never happen.
                        safe_database.insert('usermeta', {'user':post['username'], 'data':'pathalias:' + default_database})
                        path_alias = default_database
                    else:
                        output['message'] += 'User meta entry found with text ' + str(user_meta_row) + '. '

                        # Parse the string into json and ensure that the pathalias is in there
                        user_meta_dict = datalib.parseoptions(user_meta_row['data'])
                        if 'pathalias' in user_meta_dict:
                            path_alias = user_meta_dict['pathalias']
                            output['message'] += 'pathalias found: ' + user_meta_dict['pathalias'] + '. '

                            if any(path_alias == stored_path_alias['alias'] for stored_path_alias in path_aliases):
                                output['message'] += 'Verified that default alias exists in pathaliases database. '

                    if path_alias:
                        # reload datapaths with path alias
                        reload_message = inventorylib.reloaddatapaths(pathalias=path_alias)

                        # DEFINITELY COMMENT THIS OUT FOR SECURITY SAKE (absolute paths are secret!!)
                        output['message'] += reload_message

                else:
                    # successful auth
                    output['message'] += 'Failed password check. '
        else:
            # Demo status
            authverified = True
            user_data = {'authlevel':0}

    else:
        output['message'] += 'WSGI authorization not enabled. '

    if authverified or not wsgiauth:
        output['authorized'] = True
    else:
        output['authorized'] = False

    try:
        action = post['action']
    except KeyError:
        output['message'] = 'no action in request'
        action = ''

    if output['authorized'] and action:
        output['action_allowed'] = inventorylib.check_action_auths(action, user_data['authlevel'])
    else:
        output['action_allowed'] = False

    if output['authorized'] and output['action_allowed']:

        # Stock functions
        if action == 'addeditpart':
            output['message'] += 'addpart keyword found. '
            inventorylib.addeditstockpart(post, output)
            inventorylib.calcstockfromall()
        elif action == 'copypart':
            output['message'] += 'copypart keyword found. '
            inventorylib.copystockpart(post, output)
            inventorylib.calcstockfromall()
        elif action == 'deleteparts':
            output['message'] += 'deleteparts keyword found. '
            inventorylib.deletestockparts(post, output)
            inventorylib.calcstockfromall()
        elif action == 'gettrackedpartdata':
            output['message'] += 'gettrackedpartdata keyword found. '
            output['data'] = inventorylib.calcstockfromall(**post)['trackedpart']
        elif action =='generateorders':
            output['message'] += 'generate orders keyword found. '
            inventorylib.generateandaddorders()

        # Inventory functions
        # Edit and add are separated, as names are autogenerated
        elif action == 'editinventory':
            output['message'] += 'editinventory keyword found. '
            inventorylib.editinventory(post, output)
            inventorylib.calcstockfromall()
        elif action == 'addinventory':
            output['message'] += 'addinventory keyword found. '
            inventorylib.createnewinventory(post, output)
            inventorylib.makeinventorymetadata()
            inventorylib.calcstockfromall()
        elif action == 'deleteinventories':
            output['message'] += 'deleteinventories keyword found. '
            inventorylib.deleteinventories(post, output)
            inventorylib.makeinventorymetadata()
            inventorylib.calcstockfromall()
        elif action == 'addeditinventorypart':
            output['message'] += 'addeditinventorypart keyword found. '
            inventorylib.addeditpartlist(post, output)
            inventorylib.makeinventorymetadata()
            inventorylib.calcstockfromall()
        elif action == 'deletepartsfrominventory':
            output['message'] += 'deletepartsfrominventory keyword found. '
            inventorylib.deletepartsfrominventory(post, output)
            inventorylib.makeinventorymetadata()
            inventorylib.calcstockfromall()

        # Order functions
        elif action == 'editorder':
            output['message'] += 'editorder keyword found. '
            inventorylib.editorder(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()
        elif action == 'addorder':
            output['message'] += 'addorder keyword found. '
            inventorylib.createneworder(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()
        elif action == 'deleteorders':
            output['message'] += 'deleteorders keyword found. '
            inventorylib.deleteorders(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()
        elif action == 'addeditorderpart':
            output['message'] += 'addeditorderpart keyword found. '
            inventorylib.addeditpartlist(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()
        elif action == 'addeditorderparts':
            output['message'] += 'addeditorderparts keyword found. '
            if 'partsdata' in post:
                post['partsdata'] = json.loads(post['partsdata'])
                inventorylib.addeditpartlist(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()
        elif action == 'deletepartsfromorder':
            output['message'] += 'deletepartsfromorder keyword found. '
            inventorylib.deletepartsfromorder(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()

        # BOM functions
        elif action == 'copybom':
            output['message'] += 'copybom keyword found. '
            inventorylib.copybom(post, output)
            inventorylib.makebommetadata()
        elif action == 'addeditbom':
            output['message'] += 'addeditbom keyword found. '
            inventorylib.addeditbom(post, output)
            inventorylib.makebommetadata()
        elif action == 'addeditbomparts':
            output['message'] += 'addeditbomparts keyword found. '
            # Operate on partsdata
            post['partsdata'] = json.loads(post['partsdata'])
            inventorylib.addeditpartlist(post, output)
            inventorylib.makebommetadata()
        elif action == 'getbomcalcs':
            output['message'] += 'getbomcalcs keyword found. '
            inventorylib.calcbomprice(post, output)
        elif action == 'getquotecalcs':
            output['message'] += 'getquotecalcs keyword found. '
            output['message'] += 'function not written yet. '
            # inventorylib.calcbomprice(post, output)
        elif action == 'deletepartsfrombom':
            output['message'] += 'deletepartsfrombom keyword found. '
            inventorylib.deletepartsfrombom(post, output)
            inventorylib.makebommetadata()
        elif action == 'deleteboms':
            output['message'] += 'deleteboms keyword found. '
            inventorylib.deleteboms(post, output)
            inventorylib.makebommetadata()

        # Assembly functions
        elif action == 'copyassembly':
            output['message'] += 'copyassembly keyword found. '
            inventorylib.copyassembly(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()
        elif action == 'copybomintoassembly':
            output['message'] += 'copybomintoassembly keyword found. '
            inventorylib.copybomintoassembly(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()
        elif action == 'addeditassembly':
            output['message'] += 'addeditassembly keyword found. '
            inventorylib.addeditassembly(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()
        elif action == 'addeditassemblyparts':
            output['message'] += 'addeditassemblypart keyword found. '
            post['partsdata'] = json.loads(post['partsdata'])
            inventorylib.addeditpartlist(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()
            
        elif action == 'getassemblycalcs':
            output['message'] += 'getassemblycalcs keyword found. '
            inventorylib.calcassemblyprice(post, output)
        elif action == 'deletepartsfromassembly':
            output['message'] += 'deletepartsfromassembly keyword found. '
            inventorylib.deletepartsfromassembly(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()
        elif action == 'deleteassemblys':
            output['message'] += 'deleteassemblys keyword found. '
            inventorylib.deleteassemblies(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()

        # Quotes
        elif action == 'deletequotes':
            output['message'] += 'deletequotes keyword found. '
            inventorylib.deletequotes(post, output)
            inventorylib.makebommetadata(database=inventorylib.sysvars.dbs.quotes)
        elif action == 'copyquotetoboms':
            output['message'] += 'copyquotetoboms keyword found. '
            inventorylib.copyquotetoboms(post, output)
            inventorylib.makebommetadata()

        # Export functions

        elif action == 'exportbomtopdf':
            output['message'] += 'exportbomtopdf keyword found. '
            inventorylib.writepanelbomtopdf(post, output)

            thetime = datalib.gettimestring()
            cleantime = thetime.replace(' ', '_').replace(':', '_')

            # Get bom from boms database
            bom = inventorylib.sysvars.dbs.boms.read_table(post['name'])

            cleanbomname = post['name'].replace(' ','_').replace(':','_')
            filename = cleanbomname + '_' + cleantime
            outputroot = '/var/www/html/panelbuilder/data/downloads/'

            weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + filename

            inventorylib.writepanelbomtopdf(**{'bomdata': bom,
                                      'title': 'Bom generated from ' + post['name'] + ' ' + cleantime,
                                          'outputfile': outputroot + filename})

            output['data']['weblink'] = weblink

        elif action == 'exportassemblytopdf':
            output['message'] += 'exportassemblytopdf keyword found. '

            thetime = datalib.gettimestring()
            cleantime = thetime.replace(' ', '_').replace(':', '_')

            # Get bom from boms database
            assemblydata = inventorylib.sysvars.dbs.assemblies.read_table(post['name'])

            cleanname = post['name'].replace(' ','_').replace(':','_')
            filename = cleanname + '_' + cleantime + '.pdf'
            outputroot = '/var/www/html/panelbuilder/data/downloads/'

            weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + filename

            inventorylib.writepanelbomtopdf(**{'bomdata': assemblydata,
                                      'title': 'Bom generated from ' + post['name'] + ' ' + thetime,
                                          'format':'picklist','outputfile': outputroot + filename})

            output['data'] = {'assemblydata':assemblydata}
            output['weblink'] = weblink

        # Panel builder
        elif action in ['panelcalcs', 'panelcalcsgenquote']:
            output['message'] += 'panelcalc keyword found. '
            import panelbuilder
            for key,value in post.items():
                # print(key, value)
                pass

            if 'paneldesc' in post:
                import json
                post['paneldesc'] = json.loads(post['paneldesc'])

            bomresults = panelbuilder.paneltobom(**post)

            output['data'] = {}
            # d needs to have a 'paneldesc' key with the panel spec data in it.
            output['data']['bomdescription'] = bomresults['bomdescription']
            output['data']['options'] = bomresults['options']
            output['data']['bomcalcs'] = inventorylib.calcbomprice({'bomdictarray':bomresults['bom']})['data']
            output['message'] += bomresults['message']

            # We don't actually want to return the full boms by default. We don't want this in the client, and it's
            # lot of data anyway
            if 'returnfullboms' not in post:
                for option, value in output['data']['options'].items():
                    if 'bom' in value:
                        print('Deleting bom from option ' + str(option))

                        del output['data']['options'][option]['bom']
                    if 'flatbom' in value:
                        print('Deleting flatbom from option ' + str(option))
                        del output['data']['options'][option]['flatbom']

            if action == 'panelcalcsgenquote':
                thetime = datalib.gettimestring()
                cleantime = thetime.replace(' ','_').replace(':','_')
                outputroot = '/var/www/html/panelbuilder/data/downloads/'

                if 'paneltype' in post['paneldesc'] and post['paneldesc']['paneltype'] == 'brewpanel':
                    datedquotefilename = 'panelbuilder_brew_quote_' + cleantime + '.pdf'
                    datedbomfilename = 'panelbuilder_brew_bom_' + cleantime + '.pdf'
                    genericquotefilename = 'panelbuilder_brew_quote.pdf'
                    genericbomfilename = 'panelbuilder_brew_bom.pdf'
                elif 'paneltype' in post['paneldesc'] and post['paneldesc']['paneltype'] == 'temppanel':
                    datedquotefilename = 'panelbuilder_temp_quote_' + cleantime + '.pdf'
                    datedbomfilename = 'panelbuilder_temp_bom_' + cleantime + '.pdf'
                    genericquotefilename = 'panelbuilder_temp_quote.pdf'
                    genericbomfilename = 'panelbuilder_temp_bom.pdf'
                else:
                    datedquotefilename = 'panelbuilder_quote_' + cleantime + '.pdf'
                    datedbomfilename = 'panelbuilder_bom_' + cleantime + '.pdf'
                    genericquotefilename = 'panelbuilder_quote.pdf'
                    genericbomfilename = 'panelbuilder_bom.pdf'

                weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + datedquotefilename

                # until we can get this to format properly in the pdf, we are going to leave it generic
                # description = output['data']['bomdescription']
                description = 'Control panel quote generated by panelbuilder.'
                datedquotes = True

                # Create quote pdf from BOM
                if datedquotes:

                    inventorylib.writepanelquotetopdf(**{'bomdata': bomresults['bom'], 'options': bomresults['options'],
                        'title':'Quote auto-generated by panelbuilder   \t\t' +
                        datalib.gettimestring(), 'price': str(output['data']['bomcalcs']['totalprice']),
                    'outputfile': outputroot + datedquotefilename, 'description':description})

                inventorylib.writepanelquotetopdf(**{'bomdata': bomresults['bom'], 'options': bomresults['options'],
                        'title':'Quote auto-generated by panelbuilder '+ thetime,
                       'price': output['data']['bomcalcs']['totalprice'], 'outputfile':outputroot + genericquotefilename})

                # Create database entry BOM

                # Create table
                # print('** DATABASE')
                # print(panelbuilder.sysvars.dirs.dbs.quotes)

                bomname = 'quote_' + cleantime
                inventorylib.addeditbom({'bomdata':{'name':bomname}, 'database':panelbuilder.sysvars.dirs.dbs.quotes}, output)
                # print('** BOM **')
                # print(bomresults['bom'])
                inserts = []
                for part in bomresults['bom']:
                    inserts.append(dblib.makesqliteinsert(bomname, [part['partid'],part['qty']], ['partid','qty']))
                dblib.sqlitemultquery(inventorylib.sysvars.dirs.dbs.quotes, inserts)
                inventorylib.makebommetadata(database=inventorylib.sysvars.dbs.quotes)

                # inventorylib.addeditpartlist(post, output)


                # Create pdfs

                if datedquotes:
                    inventorylib.writepanelbomtopdf(**{'bomdata': bomresults['bom'], 'options': bomresults['options'],
                        'title':'Quote auto-generated by panelbuilder '
                      + thetime, 'outputfile': outputroot + datedbomfilename})

                inventorylib.writepanelbomtopdf(**{'bomdata': bomresults['bom'], 'title': 'panelbuilder BOM generated ' + thetime,
                                 'outputfile': outputroot + genericbomfilename, 'totalprice': output['data']['bomcalcs']['totalprice']})

                output['data']['quotelink'] = weblink
                from iiutilities.utility import gmail
                mymail = gmail(subject="Quote generated")
                mymail.message = 'Quote generated at ' + cleantime + '\r\n'

                if 'remote_ip' in output:
                    mymail.message = 'IP address ' + output['remote_ip'] + '\r\n'

                mymail.message += bomresults['bomdescription']
                mymail.recipient = '*****@*****.**'
                mymail.sender = 'II Panelbuilder'
                mymail.send()


        # Multi-use
        elif action == 'reloaditemdatafromstock':
            output['message'] += 'reloaditemdatafromstock keyword found. '
            inventorylib.refreshpartsfromstock(post, output)
            if 'bomname' in post:
                inventorylib.recalcpartdata(bomname=post['bomname'])
                inventorylib.makebommetadata()
            elif 'assemblyame' in post:
                inventorylib.recalcpartdata(assemblyname=post['assemblyname'])
                inventorylib.makeassemblymetadata()

        # Generic functions
        elif action == 'gettablenames':
            dbpath = inventorylib.dbnametopath(post['database'])
            try:
                output['data'] = dblib.gettablenames(dbpath)
            except:
                output['message'] += 'Error getting table names'
        elif action == 'switchtablerows':
            dbpath = inventorylib.dbnametopath(post['database'])
            dblib.switchtablerows(dbpath, post['tablename'], post['row1'], post['row2'], post['uniqueindex'])
        elif action == 'modwsgistatus':
            output['processgroup'] = repr(environ['mod_wsgi.process_group'])
            output['multithread'] = repr(environ['wsgi.multithread'])
        elif action == 'gettabledata':
            output['message']+='Gettabledata. '
            if 'database' in post:
                dbpath = inventorylib.dbnametopath(post['database'])
                if dbpath:
                    output['message'] += 'Friendly name ' + post['database'] + ' translated to path ' + dbpath + ' successfully. '

                    if 'tablenames' in post:  # Get multiple tables
                        output['message'] += 'Multiple tables. '
                        data = []
                        if 'start' in post:
                            fixedstart = int(post['start'])
                        else:
                            fixedstart = 0
                        if 'length' in post:
                            fixedlength = int(post['length'])
                        else:
                            fixedlength = 1
                        if 'lengths' in post:
                            lengths = map(int, post['lengths[]'])
                        else:
                            lengths = []
                        if 'starts' in post:
                            starts = map(int, post['starts'])
                        else:
                            starts = []

                        for index, table in enumerate(post['tablenames[]']):
                            try:
                                length = lengths[index]
                            except IndexError:
                                length = fixedlength
                            try:
                                start = starts[index]
                            except IndexError:
                                start = fixedstart

                            data.append(dblib.dynamicsqliteread(dbpath, table, start, length))
                            output['data']=data
                    elif 'length' in post:  # Handle table row subset
                        output['message']+='Length keyword. '
                        if not 'start' in post:
                            post['start'] = 0
                        thetime = time()
                        output['data'] = dblib.dynamicsqliteread(dbpath, post['tablename'], post['start'], post['length'])
                        output['querytime'] = time() - thetime
                    elif 'row' in post:  # Handle table row
                        output['message'] += 'Row keyword. ' + str(post['row'])
                        thetime = time()
                        output['data'] = dblib.dynamicsqliteread(dbpath, post['tablename'], post['row'])
                        output['querytime'] = time() - thetime
                    elif 'tablename' in post:  # Handle entire table
                        output['message'] += 'Tablename keyword: ' + post['tablename'] + '. '
                        thetime = time()
                        if 'condition' in post:
                            if not post['condition'] == '':
                                output['data'] = dblib.dynamicsqliteread(dbpath, post['tablename'], condition=post['condition'])
                            else:
                                output['data'] = dblib.dynamicsqliteread(dbpath, post['tablename'])
                        else:
                            try:
                                output['data'] = dblib.dynamicsqliteread(dbpath, post['tablename'])
                            except:
                                output['message'] += 'Error retrieving data. '
                            else:
                                output['message'] += 'Data query appears successful. '
                        output['querytime'] = time() - thetime
                else:
                    output['message'] += 'Friendly name ' + post['database'] + ' unsuccessfully translated. '
            else:
                output['message'] += 'No database present in action request'
        else:
            output['message'] = 'no command matched for action "' + action + '"'
    else:
        # status = '403 Forbidden'
        output['message'] += 'Not authorized for this action (or perhaps at all?) '

    if 'data' in output:
        if output['data']:
            newetag = hashlib.md5(str(output['data']).encode('utf-8')).hexdigest()
            if 'etag' in post:
                if newetag == post['etag']:
                    status = '304 Not Modified'
                    output['data'] = ''
        else:
            newetag=''
    else:
        newetag=''

    if 'datasize' in post:
        output['datasize'] = sys.getsizeof(output['data'])

    output['etag'] = newetag
    # try:
    foutput = json.dumps(output, indent=1)
    # except:
    #     import csv
    #     w = csv.writer(open("/usr/lib/iicontrollibs/inventory/dumperr.log", "w"))
    #     for key, val in output.items():
    #         w.writerow([key, val])
    response_headers = [('Content-type', 'application/json')]
    response_headers.append(('Etag',newetag))
    start_response(status, response_headers)

    return foutput.encode('utf-8')
Esempio n. 14
0
def application(environ, start_response):
    import json
    import hashlib

    # Set top folder to allow import of modules

    import os, sys, inspect

    top_folder = \
        os.path.split(os.path.realpath(os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0])))[0]
    if top_folder not in sys.path:
        sys.path.insert(0, top_folder)

    import inventorylib
    from iiutilities import dblib, datalib
    from time import time

    try:
        request_body_size = int(environ.get('CONTENT_LENGTH', 0))
    except ValueError:
        request_body_size = 0

    request_body = environ['wsgi.input'].read(request_body_size)
    try:
        post = json.loads(request_body.decode('utf-8'))
    except:
        print('Error decoding: ')
        print(request_body.decode('utf-8'))
        post = {}

    output = {'message': ''}
    status = '200 OK'

    try:
        try:
            output['remote_ip'] = environ['HTTP_X_FORWARDED_FOR'].split(
                ',')[-1].strip()
        except KeyError:
            output['remote_ip'] = environ['REMOTE_ADDR']
    except:
        output['remote_ip'] = 'Error getting IP address'
    """
    Here we verify credentials of session data against those in the database.
    While we authenticate in the browser, this does not stop POST queries to the API without the page provided
    So we take the hpass stored in the dictionary and verify.

    * Which databases are available are stored in users table, column accesskeywords
    * Which one is currently in use is stored in table usermeta, data where user=username. data is json-encoded metadata
        pathalias field

    * What path extension this corresponds to is stored in pathaliases

    """

    # I dont' think this will be used. We will get pathalias from database. Let's deal with changing it later.

    # First, let's get our pathalias and translate to a path, using our path reloader

    # if 'pathalias' in post:
    #     output['message'] += inventorylib.reloaddatapaths(pathalias=post['pathalias'])
    # else:
    #     output['message'] += 'No pathalias found in postictionary. '

    wsgiauth = True
    authverified = False

    if wsgiauth:

        # Verfiy that session login information is legit: hashed password, with salt and username, match
        # hash stored in postatabase.
        import hashlib

        safe_database = dblib.sqliteDatabase(
            inventorylib.sysvars.dirs.dbs.safe)
        if 'username' in post and post['username']:
            output['message'] += 'Session user is ' + post['username'] + '. '
        else:
            output['message'] += 'No session user found. '
            post['username'] = ''

        if post['username']:
            try:
                condition = "name='" + post['username'] + "'"
                user_data = safe_database.read_table_row(
                    'users', condition=condition)[0]
            except:
                output[
                    'message'] += 'error in user sqlite query for session user "' + post[
                        'username'] + '". '
                user_data = {'accesskeywords': 'demo', 'admin': False}
            else:
                # Get session hpass to verify credentials

                hashedpassword = post['hpass']
                hname = hashlib.new('sha1')
                hname.update(post['username'].encode('utf-8'))
                hashedname = hname.hexdigest()
                hentry = hashlib.new('md5')
                hentry.update((hashedname + inventorylib.sysvars.salt +
                               hashedpassword).encode('utf-8'))
                hashedentry = hentry.hexdigest()
                if hashedentry == user_data['password']:
                    # successful auth
                    output['message'] += 'Password verified. '
                    authverified = True
                    # output['message'] += 'accesskeywords : ' + str(userdata)
                    output['accesskeywords'] = user_data['accesskeywords']
                    if output['accesskeywords'].find(',') >= 0:
                        accesskeywords = output['accesskeywords'].split(',')
                        accesskeywords = [
                            accesskeyword.strip()
                            for accesskeyword in accesskeywords
                        ]
                    else:
                        accesskeywords = output['accesskeywords'].strip()

                    path_aliases = safe_database.read_table('pathaliases')

                    # Find usermeta entry and grab which database is selected. If one is not selected, update selection
                    # to first that user is allowed to access
                    try:
                        user_meta_row = safe_database.read_table_row(
                            'usermeta',
                            condition="user='******'username'] + "'")[0]
                    except:
                        print('error getting usermeta for username ' +
                              post['username'])
                        output[
                            'message'] += 'error getting usermeta for username ' + post[
                                'username']
                        user_meta_row = []
                        return

                    path_alias = ''
                    if not user_meta_row:
                        output[
                            'message'] += 'User meta entry not found. Attempting to create. '

                        # assign default database
                        default_database = accesskeywords[0]

                        output[
                            'message'] += 'Choosing pathalias from first in keywords: ' + default_database + '. '
                        if any(default_database == path_alias['alias']
                               for path_alias in path_aliases):
                            output[
                                'message'] += 'Verified that default alias exists in pathaliases database. '
                        else:
                            output[
                                'message'] += 'ERROR: first entry in keywords (' + default_database + ') not found in aliases. '

                        # Insert usermeta entry. This should never happen.
                        safe_database.insert(
                            'usermeta', {
                                'user': post['username'],
                                'data': 'pathalias:' + default_database
                            })
                        path_alias = default_database
                    else:
                        output[
                            'message'] += 'User meta entry found with text ' + str(
                                user_meta_row) + '. '

                        # Parse the string into json and ensure that the pathalias is in there
                        user_meta_dict = datalib.parseoptions(
                            user_meta_row['data'])
                        if 'pathalias' in user_meta_dict:
                            path_alias = user_meta_dict['pathalias']
                            output[
                                'message'] += 'pathalias found: ' + user_meta_dict[
                                    'pathalias'] + '. '

                            if any(path_alias == stored_path_alias['alias']
                                   for stored_path_alias in path_aliases):
                                output[
                                    'message'] += 'Verified that default alias exists in pathaliases database. '

                    if path_alias:
                        # reload datapaths with path alias
                        reload_message = inventorylib.reloaddatapaths(
                            pathalias=path_alias)

                        # DEFINITELY COMMENT THIS OUT FOR SECURITY SAKE (absolute paths are secret!!)
                        output['message'] += reload_message

                else:
                    # successful auth
                    output['message'] += 'Failed password check. '
        else:
            # Demo status
            authverified = True
            user_data = {'authlevel': 0}

    else:
        output['message'] += 'WSGI authorization not enabled. '

    if authverified or not wsgiauth:
        output['authorized'] = True
    else:
        output['authorized'] = False

    try:
        action = post['action']
    except KeyError:
        output['message'] = 'no action in request'
        action = ''

    if output['authorized'] and action:
        output['action_allowed'] = inventorylib.check_action_auths(
            action, user_data['authlevel'])
    else:
        output['action_allowed'] = False

    if output['authorized'] and output['action_allowed']:

        # Stock functions
        if action == 'addeditpart':
            output['message'] += 'addpart keyword found. '
            inventorylib.addeditstockpart(post, output)
            inventorylib.calcstockfromall()
        elif action == 'copypart':
            output['message'] += 'copypart keyword found. '
            inventorylib.copystockpart(post, output)
            inventorylib.calcstockfromall()
        elif action == 'deleteparts':
            output['message'] += 'deleteparts keyword found. '
            inventorylib.deletestockparts(post, output)
            inventorylib.calcstockfromall()
        elif action == 'gettrackedpartdata':
            output['message'] += 'gettrackedpartdata keyword found. '
            output['data'] = inventorylib.calcstockfromall(
                **post)['trackedpart']
        elif action == 'generateorders':
            output['message'] += 'generate orders keyword found. '
            inventorylib.generateandaddorders()

        # Inventory functions
        # Edit and add are separated, as names are autogenerated
        elif action == 'editinventory':
            output['message'] += 'editinventory keyword found. '
            inventorylib.editinventory(post, output)
            inventorylib.calcstockfromall()
        elif action == 'addinventory':
            output['message'] += 'addinventory keyword found. '
            inventorylib.createnewinventory(post, output)
            inventorylib.makeinventorymetadata()
            inventorylib.calcstockfromall()
        elif action == 'deleteinventories':
            output['message'] += 'deleteinventories keyword found. '
            inventorylib.deleteinventories(post, output)
            inventorylib.makeinventorymetadata()
            inventorylib.calcstockfromall()
        elif action == 'addeditinventorypart':
            output['message'] += 'addeditinventorypart keyword found. '
            inventorylib.addeditpartlist(post, output)
            inventorylib.makeinventorymetadata()
            inventorylib.calcstockfromall()
        elif action == 'deletepartsfrominventory':
            output['message'] += 'deletepartsfrominventory keyword found. '
            inventorylib.deletepartsfrominventory(post, output)
            inventorylib.makeinventorymetadata()
            inventorylib.calcstockfromall()

        # Order functions
        elif action == 'editorder':
            output['message'] += 'editorder keyword found. '
            inventorylib.editorder(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()
        elif action == 'addorder':
            output['message'] += 'addorder keyword found. '
            inventorylib.createneworder(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()
        elif action == 'deleteorders':
            output['message'] += 'deleteorders keyword found. '
            inventorylib.deleteorders(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()
        elif action == 'addeditorderpart':
            output['message'] += 'addeditorderpart keyword found. '
            inventorylib.addeditpartlist(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()
        elif action == 'addeditorderparts':
            output['message'] += 'addeditorderparts keyword found. '
            if 'partsdata' in post:
                post['partsdata'] = json.loads(post['partsdata'])
                inventorylib.addeditpartlist(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()
        elif action == 'deletepartsfromorder':
            output['message'] += 'deletepartsfromorder keyword found. '
            inventorylib.deletepartsfromorder(post, output)
            inventorylib.makeordermetadata()
            inventorylib.calcstockfromall()

        # BOM functions
        elif action == 'copybom':
            output['message'] += 'copybom keyword found. '
            inventorylib.copybom(post, output)
            inventorylib.makebommetadata()
        elif action == 'addeditbom':
            output['message'] += 'addeditbom keyword found. '
            inventorylib.addeditbom(post, output)
            inventorylib.makebommetadata()
        elif action == 'addeditbomparts':
            output['message'] += 'addeditbomparts keyword found. '
            # Operate on partsdata
            post['partsdata'] = json.loads(post['partsdata'])
            inventorylib.addeditpartlist(post, output)
            inventorylib.makebommetadata()
        elif action == 'getbomcalcs':
            output['message'] += 'getbomcalcs keyword found. '
            inventorylib.calcbomprice(post, output)
        elif action == 'getquotecalcs':
            output['message'] += 'getquotecalcs keyword found. '
            output['message'] += 'function not written yet. '
            # inventorylib.calcbomprice(post, output)
        elif action == 'deletepartsfrombom':
            output['message'] += 'deletepartsfrombom keyword found. '
            inventorylib.deletepartsfrombom(post, output)
            inventorylib.makebommetadata()
        elif action == 'deleteboms':
            output['message'] += 'deleteboms keyword found. '
            inventorylib.deleteboms(post, output)
            inventorylib.makebommetadata()

        # Assembly functions
        elif action == 'copyassembly':
            output['message'] += 'copyassembly keyword found. '
            inventorylib.copyassembly(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()
        elif action == 'copybomintoassembly':
            output['message'] += 'copybomintoassembly keyword found. '
            inventorylib.copybomintoassembly(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()
        elif action == 'addeditassembly':
            output['message'] += 'addeditassembly keyword found. '
            inventorylib.addeditassembly(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()
        elif action == 'addeditassemblyparts':
            output['message'] += 'addeditassemblypart keyword found. '
            post['partsdata'] = json.loads(post['partsdata'])
            inventorylib.addeditpartlist(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()

        elif action == 'getassemblycalcs':
            output['message'] += 'getassemblycalcs keyword found. '
            inventorylib.calcassemblyprice(post, output)
        elif action == 'deletepartsfromassembly':
            output['message'] += 'deletepartsfromassembly keyword found. '
            inventorylib.deletepartsfromassembly(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()
        elif action == 'deleteassemblys':
            output['message'] += 'deleteassemblys keyword found. '
            inventorylib.deleteassemblies(post, output)
            inventorylib.makeassemblymetadata()
            inventorylib.calcstockfromall()

        # Quotes
        elif action == 'deletequotes':
            output['message'] += 'deletequotes keyword found. '
            inventorylib.deletequotes(post, output)
            inventorylib.makebommetadata(
                database=inventorylib.sysvars.dbs.quotes)
        elif action == 'copyquotetoboms':
            output['message'] += 'copyquotetoboms keyword found. '
            inventorylib.copyquotetoboms(post, output)
            inventorylib.makebommetadata()

        # Export functions

        elif action == 'exportbomtopdf':
            output['message'] += 'exportbomtopdf keyword found. '
            inventorylib.writepanelbomtopdf(post, output)

            thetime = datalib.gettimestring()
            cleantime = thetime.replace(' ', '_').replace(':', '_')

            # Get bom from boms database
            bom = inventorylib.sysvars.dbs.boms.read_table(post['name'])

            cleanbomname = post['name'].replace(' ', '_').replace(':', '_')
            filename = cleanbomname + '_' + cleantime
            outputroot = '/var/www/html/panelbuilder/data/downloads/'

            weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + filename

            inventorylib.writepanelbomtopdf(
                **{
                    'bomdata': bom,
                    'title': 'Bom generated from ' + post['name'] + ' ' +
                    cleantime,
                    'outputfile': outputroot + filename
                })

            output['data']['weblink'] = weblink

        elif action == 'exportassemblytopdf':
            output['message'] += 'exportassemblytopdf keyword found. '

            thetime = datalib.gettimestring()
            cleantime = thetime.replace(' ', '_').replace(':', '_')

            # Get bom from boms database
            assemblydata = inventorylib.sysvars.dbs.assemblies.read_table(
                post['name'])

            cleanname = post['name'].replace(' ', '_').replace(':', '_')
            filename = cleanname + '_' + cleantime + '.pdf'
            outputroot = '/var/www/html/panelbuilder/data/downloads/'

            weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + filename

            inventorylib.writepanelbomtopdf(
                **{
                    'bomdata': assemblydata,
                    'title': 'Bom generated from ' + post['name'] + ' ' +
                    thetime,
                    'format': 'picklist',
                    'outputfile': outputroot + filename
                })

            output['data'] = {'assemblydata': assemblydata}
            output['weblink'] = weblink

        # Panel builder
        elif action in ['panelcalcs', 'panelcalcsgenquote']:
            output['message'] += 'panelcalc keyword found. '
            import panelbuilder
            for key, value in post.items():
                # print(key, value)
                pass

            if 'paneldesc' in post:
                import json
                post['paneldesc'] = json.loads(post['paneldesc'])

            bomresults = panelbuilder.paneltobom(**post)

            output['data'] = {}
            # d needs to have a 'paneldesc' key with the panel spec data in it.
            output['data']['bomdescription'] = bomresults['bomdescription']
            output['data']['options'] = bomresults['options']
            output['data']['bomcalcs'] = inventorylib.calcbomprice(
                {'bomdictarray': bomresults['bom']})['data']
            output['message'] += bomresults['message']

            # We don't actually want to return the full boms by default. We don't want this in the client, and it's
            # lot of data anyway
            if 'returnfullboms' not in post:
                for option, value in output['data']['options'].items():
                    if 'bom' in value:
                        print('Deleting bom from option ' + str(option))

                        del output['data']['options'][option]['bom']
                    if 'flatbom' in value:
                        print('Deleting flatbom from option ' + str(option))
                        del output['data']['options'][option]['flatbom']

            if action == 'panelcalcsgenquote':
                thetime = datalib.gettimestring()
                cleantime = thetime.replace(' ', '_').replace(':', '_')
                outputroot = '/var/www/html/panelbuilder/data/downloads/'

                if 'paneltype' in post['paneldesc'] and post['paneldesc'][
                        'paneltype'] == 'brewpanel':
                    datedquotefilename = 'panelbuilder_brew_quote_' + cleantime + '.pdf'
                    datedbomfilename = 'panelbuilder_brew_bom_' + cleantime + '.pdf'
                    genericquotefilename = 'panelbuilder_brew_quote.pdf'
                    genericbomfilename = 'panelbuilder_brew_bom.pdf'
                elif 'paneltype' in post['paneldesc'] and post['paneldesc'][
                        'paneltype'] == 'temppanel':
                    datedquotefilename = 'panelbuilder_temp_quote_' + cleantime + '.pdf'
                    datedbomfilename = 'panelbuilder_temp_bom_' + cleantime + '.pdf'
                    genericquotefilename = 'panelbuilder_temp_quote.pdf'
                    genericbomfilename = 'panelbuilder_temp_bom.pdf'
                else:
                    datedquotefilename = 'panelbuilder_quote_' + cleantime + '.pdf'
                    datedbomfilename = 'panelbuilder_bom_' + cleantime + '.pdf'
                    genericquotefilename = 'panelbuilder_quote.pdf'
                    genericbomfilename = 'panelbuilder_bom.pdf'

                weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + datedquotefilename

                # until we can get this to format properly in the pdf, we are going to leave it generic
                # description = output['data']['bomdescription']
                description = 'Control panel quote generated by panelbuilder.'
                datedquotes = True

                # Create quote pdf from BOM
                if datedquotes:

                    inventorylib.writepanelquotetopdf(
                        **{
                            'bomdata':
                            bomresults['bom'],
                            'options':
                            bomresults['options'],
                            'title':
                            'Quote auto-generated by panelbuilder   \t\t' +
                            datalib.gettimestring(),
                            'price':
                            str(output['data']['bomcalcs']['totalprice']),
                            'outputfile':
                            outputroot + datedquotefilename,
                            'description':
                            description
                        })

                inventorylib.writepanelquotetopdf(
                    **{
                        'bomdata': bomresults['bom'],
                        'options': bomresults['options'],
                        'title': 'Quote auto-generated by panelbuilder ' +
                        thetime,
                        'price': output['data']['bomcalcs']['totalprice'],
                        'outputfile': outputroot + genericquotefilename
                    })

                # Create database entry BOM

                # Create table
                # print('** DATABASE')
                # print(panelbuilder.sysvars.dirs.dbs.quotes)

                bomname = 'quote_' + cleantime
                inventorylib.addeditbom(
                    {
                        'bomdata': {
                            'name': bomname
                        },
                        'database': panelbuilder.sysvars.dirs.dbs.quotes
                    }, output)
                # print('** BOM **')
                # print(bomresults['bom'])
                inserts = []
                for part in bomresults['bom']:
                    inserts.append(
                        dblib.makesqliteinsert(bomname,
                                               [part['partid'], part['qty']],
                                               ['partid', 'qty']))
                dblib.sqlitemultquery(inventorylib.sysvars.dirs.dbs.quotes,
                                      inserts)
                inventorylib.makebommetadata(
                    database=inventorylib.sysvars.dbs.quotes)

                # inventorylib.addeditpartlist(post, output)

                # Create pdfs

                if datedquotes:
                    inventorylib.writepanelbomtopdf(
                        **{
                            'bomdata': bomresults['bom'],
                            'options': bomresults['options'],
                            'title': 'Quote auto-generated by panelbuilder ' +
                            thetime,
                            'outputfile': outputroot + datedbomfilename
                        })

                inventorylib.writepanelbomtopdf(
                    **{
                        'bomdata': bomresults['bom'],
                        'title': 'panelbuilder BOM generated ' + thetime,
                        'outputfile': outputroot + genericbomfilename,
                        'totalprice': output['data']['bomcalcs']['totalprice']
                    })

                output['data']['quotelink'] = weblink
                from iiutilities.utility import gmail
                mymail = gmail(subject="Quote generated")
                mymail.message = 'Quote generated at ' + cleantime + '\r\n'

                if 'remote_ip' in output:
                    mymail.message = 'IP address ' + output[
                        'remote_ip'] + '\r\n'

                mymail.message += bomresults['bomdescription']
                mymail.recipient = '*****@*****.**'
                mymail.sender = 'II Panelbuilder'
                mymail.send()

        # Multi-use
        elif action == 'reloaditemdatafromstock':
            output['message'] += 'reloaditemdatafromstock keyword found. '
            inventorylib.refreshpartsfromstock(post, output)
            if 'bomname' in post:
                inventorylib.recalcpartdata(bomname=post['bomname'])
                inventorylib.makebommetadata()
            elif 'assemblyame' in post:
                inventorylib.recalcpartdata(assemblyname=post['assemblyname'])
                inventorylib.makeassemblymetadata()

        # Generic functions
        elif action == 'gettablenames':
            dbpath = inventorylib.dbnametopath(post['database'])
            try:
                output['data'] = dblib.gettablenames(dbpath)
            except:
                output['message'] += 'Error getting table names'
        elif action == 'switchtablerows':
            dbpath = inventorylib.dbnametopath(post['database'])
            dblib.switchtablerows(dbpath, post['tablename'], post['row1'],
                                  post['row2'], post['uniqueindex'])
        elif action == 'modwsgistatus':
            output['processgroup'] = repr(environ['mod_wsgi.process_group'])
            output['multithread'] = repr(environ['wsgi.multithread'])
        elif action == 'gettabledata':
            output['message'] += 'Gettabledata. '
            if 'database' in post:
                dbpath = inventorylib.dbnametopath(post['database'])
                if dbpath:
                    output['message'] += 'Friendly name ' + post[
                        'database'] + ' translated to path ' + dbpath + ' successfully. '

                    if 'tablenames' in post:  # Get multiple tables
                        output['message'] += 'Multiple tables. '
                        data = []
                        if 'start' in post:
                            fixedstart = int(post['start'])
                        else:
                            fixedstart = 0
                        if 'length' in post:
                            fixedlength = int(post['length'])
                        else:
                            fixedlength = 1
                        if 'lengths' in post:
                            lengths = map(int, post['lengths[]'])
                        else:
                            lengths = []
                        if 'starts' in post:
                            starts = map(int, post['starts'])
                        else:
                            starts = []

                        for index, table in enumerate(post['tablenames[]']):
                            try:
                                length = lengths[index]
                            except IndexError:
                                length = fixedlength
                            try:
                                start = starts[index]
                            except IndexError:
                                start = fixedstart

                            data.append(
                                dblib.dynamicsqliteread(
                                    dbpath, table, start, length))
                            output['data'] = data
                    elif 'length' in post:  # Handle table row subset
                        output['message'] += 'Length keyword. '
                        if not 'start' in post:
                            post['start'] = 0
                        thetime = time()
                        output['data'] = dblib.dynamicsqliteread(
                            dbpath, post['tablename'], post['start'],
                            post['length'])
                        output['querytime'] = time() - thetime
                    elif 'row' in post:  # Handle table row
                        output['message'] += 'Row keyword. ' + str(post['row'])
                        thetime = time()
                        output['data'] = dblib.dynamicsqliteread(
                            dbpath, post['tablename'], post['row'])
                        output['querytime'] = time() - thetime
                    elif 'tablename' in post:  # Handle entire table
                        output['message'] += 'Tablename keyword: ' + post[
                            'tablename'] + '. '
                        thetime = time()
                        if 'condition' in post:
                            if not post['condition'] == '':
                                output['data'] = dblib.dynamicsqliteread(
                                    dbpath,
                                    post['tablename'],
                                    condition=post['condition'])
                            else:
                                output['data'] = dblib.dynamicsqliteread(
                                    dbpath, post['tablename'])
                        else:
                            try:
                                output['data'] = dblib.dynamicsqliteread(
                                    dbpath, post['tablename'])
                            except:
                                output['message'] += 'Error retrieving data. '
                            else:
                                output[
                                    'message'] += 'Data query appears successful. '
                        output['querytime'] = time() - thetime
                else:
                    output['message'] += 'Friendly name ' + post[
                        'database'] + ' unsuccessfully translated. '
            else:
                output['message'] += 'No database present in action request'
        else:
            output[
                'message'] = 'no command matched for action "' + action + '"'
    else:
        # status = '403 Forbidden'
        output[
            'message'] += 'Not authorized for this action (or perhaps at all?) '

    if 'data' in output:
        if output['data']:
            newetag = hashlib.md5(str(
                output['data']).encode('utf-8')).hexdigest()
            if 'etag' in post:
                if newetag == post['etag']:
                    status = '304 Not Modified'
                    output['data'] = ''
        else:
            newetag = ''
    else:
        newetag = ''

    if 'datasize' in post:
        output['datasize'] = sys.getsizeof(output['data'])

    output['etag'] = newetag
    # try:
    foutput = json.dumps(output, indent=1)
    # except:
    #     import csv
    #     w = csv.writer(open("/usr/lib/iicontrollibs/inventory/dumperr.log", "w"))
    #     for key, val in output.items():
    #         w.writerow([key, val])
    response_headers = [('Content-type', 'application/json')]
    response_headers.append(('Etag', newetag))
    start_response(status, response_headers)

    return foutput.encode('utf-8')
Esempio n. 15
0
def application(environ, start_response):

    import cgi
    import json

    import os, sys, inspect

    # Set top folder to allow import of modules

    top_folder = os.path.split(os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0])))[0]
    if top_folder not in sys.path:
        sys.path.insert(0,top_folder)

    from cupid import pilib, controllib
    from iiutilities import dblib, utility, datalib

    # post_env = environ.copy()
    # post_env['QUERY_STRING'] = ''
    # post = cgi.FieldStorage(
    #     fp=environ['wsgi.input'],
    #     environ=post_env,
    #     keep_blank_values=True
    # )
    #
    # formname=post.getvalue('name')
    # output = {}
    # output['message'] = 'Output Message: '
    # for k in post.keys():
    #     d[k] = post.getvalue(k)

    try:
        request_body_size = int(environ.get('CONTENT_LENGTH', 0))
    except ValueError:
        request_body_size = 0

    request_body = environ['wsgi.input'].read(request_body_size)
    post = json.loads(request_body.decode('utf-8'))

    output = {}
    output['message'] = ''

    status = '200 OK'
    wsgiauth = True
    authverified = False

    if wsgiauth:
        # Verfiy that session login information is legit: hashed password, with salt and username, match
        # hash stored in database.
        import hashlib

        safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.users)
        if 'username' in post and post['username']:
            output['message'] += 'Session user is ' + post['username'] + '. '
        else:
            output['message'] += 'No session user found. '
            post['username'] = ''

        if post['username']:
            try:
                condition = "name='" + post['username'] + "'"
                user_data = safe_database.read_table_row('users', condition=condition)[0]
            except:
                output['message'] += 'Error in user sqlite query for session user "' + post['username'] + '". '
                output['message'] += 'Condition: ' + condition + '. Path: ' + pilib.dirs.dbs.safe
                user_data = {'accesskeywords': 'demo', 'admin': False}
            else:
                # Get session hpass to verify credentials
                hashedpassword = post['hpass']
                hname = hashlib.new('sha1')
                hname.update(post['username'])
                hashedname = hname.hexdigest()
                hentry = hashlib.new('md5')
                hentry.update(hashedname + pilib.salt + hashedpassword)
                hashedentry = hentry.hexdigest()
                if hashedentry == user_data['password']:
                    # successful auth
                    output['message'] += 'Password verified. '
                    authverified = True

                    # TODO: implement usermeta
        else:
            # Demo status
            authverified = True
            user_data = {'authlevel':0}

    else:
        output['message'] += 'WSGI authorization not enabled. '

    if authverified or not wsgiauth:
        output['authorized'] = True

    try:
        action = post['action']
    except KeyError:
        output['message'] = 'no action in request'
        action = ''
    else:
        output['message'] += '{} action keyword found'.format(action)

    if output['authorized'] and action:
        output['action_allowed'] = pilib.check_action_auths(action, user_data['authlevel'])
    else:
        output['action_allowed'] = False

    if output['authorized'] and output['action_allowed']:

        output['message'] += 'Found action. '

        if action == 'testdbvn':
            from iiutilities.dblib import dbvntovalue
            try:
                output['data'] = dbvntovalue(post['dbvn'])
            except:
                output['message'] += 'Error in dbvn evaluation. '
                output['data'] = 'error'
            else:
                output['message'] += 'Seems to have worked out. '
        elif action == 'testlogical':
            from iiutilities.datalib import evaldbvnformula
            try:
                output['data'] = evaldbvnformula(post['logical'])
            except:
                output['message'] += 'Error in logical evaluation. '
                output['data'] = 'error'
            else:
                output['message'] += 'Seems to have worked out. '

        elif action == 'testmodule':
            output['message'] += 'Testing module: '
            if 'modulename' in post:
                import cupid.cupidunittests
                output['message'] += post['modulename']
                output['data'] = cupid.cupidunittests.testmodule(post['modulename'])
            else:
                output['message'] += 'Modulename not found. '
        elif action == 'testfunction':
            output['message'] += 'Testing function: '
            if 'testname' in post:
                import cupid.cupidunittests
                output['message'] += post['testname']
                # output['data'] = cupid.tests.testfunction(d['testname'])
                output['data'] = cupid.cupidunittests.testfunction(post['testname'])
                # output['data'] = str(cupid.tests.testfunction('systemstatus'))
            else:
                output['message'] += 'Testname not found. '

        elif action == 'modifychannelalarm':
            controllib.handle_modify_channel_alarm(post, output)
            from cupid.actions import processactions

            # process only this action.
            processactions(name=post['actionname'])

        elif action == 'modifychannel':
            controllib.handle_modify_channel(post, output)

        elif action == 'getalarmscount':
            control_db = dblib.sqliteDatabase(pilib.dirs.dbs.control)
            actions = control_db.read_table('actions')
            output['data'] = {'totalalarms':len(actions),'channelalarms':0, 'activealarms':0, 'activechannelalarms':0}
            for action in actions:
                if action['conditiontype'] == 'channel':
                    output['data']['channelalarms'] += 1
                    if action['active']:
                        output['data']['activechannelalarms'] += 1

                if action['active']:
                    output['data']['activealarms'] += 1

        elif action == 'copy_log_to_archive':
            pilib.app_copy_log_to_archive(post, output)

        elif action == 'getlogscount':
            logtablenames = dblib.sqliteDatabase(pilib.dirs.dbs.log).get_table_names()
            output['data'] = {'logscount':len(logtablenames)}


        elif action == 'test_action':
            output['message'] += 'Testing action. '
            controldb = dblib.sqliteDatabase(pilib.dirs.dbs.control)
            actiondict = controldb.read_table('actions',condition='"name"=\'' + post['actionname'] + "'")[0]
            from cupid.actions import action
            test_action = action(actiondict)
            test_action.test()

        elif action == 'update_network':
            safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe)
            safe_database.set_single_value('wireless', 'password', post['password'], "SSID='" + post['ssid'] + "'")

        elif action == 'add_network':
            safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe)
            insert = {'SSID':post['ssid'], 'auto':1, 'priority':1}
            if 'password' in post:
                insert['password'] = post['password']
            safe_database.insert('wireless',insert)

        elif action == 'delete_network':
            safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe)
            safe_database.delete('wireless', "SSID='" + post['ssid'] + "'")

        # elif action == 'dump':
        #     # this has to go.
        #     if 'database' in d:
        #         dbpath = pilib.dbnametopath(d['database'])
        #         if dbpath:
        #             if 'tablelist' in d and 'outputfile' in d:
        #                 dbpath = pilib.dbnametopath(d['database'])
        #                 dblib.sqlitedatadump(dbpath, d['tablelist'], d['outputfile'])
        #                 output['message'] = 'data dumped'
        #             elif 'tablename' in d and 'outputfile' in d:
        #                 dblib.sqlitedatadump(dbpath, [d['tablename']], d['outputfile'])
        #                 output['message'] = 'data dumped. '
        #             else:
        #                 output['message'] += 'keys not present for dump. '
        #         else:
        #             output['message'] += 'keys not present for dump. '
        #     else:
        #         output['message'] += 'keys not present for dump. '
        elif action in ['userdelete', 'useradd', 'usermodify']:
            """
            This needs to be consolidate with the other useradd, modify algorithm written already.
            Probably do this when we update the user permissions interface.
            """
            # Ensure that we are authorized for this action
            if action == 'userdelete':
                try:
                    dblib.sqlitequery(pilib.dirs.dbs.users, "delete from users where name='" + post['usertodelete'] + "'")
                except:
                    output['message'] += 'Error in delete query. '
                else:
                    output['message'] += 'Successful delete query. '
            elif action == 'usermodify':

                if 'usertomodify' in post:
                    querylist=[]
                    if 'newpass' in post:
                        from pilib import salt
                        # Get session hpass to verify credentials
                        hashedpassword = post['newpass']
                        hname = hashlib.new('sha1')
                        hname.update(post['usertomodify'])
                        hashedname = hname.hexdigest()
                        hentry = hashlib.new('md5')
                        hentry.update(hashedname + salt + hashedpassword)
                        hashedentry = hentry.hexdigest()
                        querylist.append('update users set password='******'" + post['usertomodify'] + "'")

                    if 'newemail' in post:
                        querylist.append("update users set email='" + post['newemail'] + "' where name='" + post['usertomodify'] + "'")
                    if 'newauthlevel' in post:
                        querylist.append("update users set authlevel='" + post['newauthlevel'] + "' where name='" + post['usertomodify'] + "'")

                    try:
                        dblib.sqlitemultquery(pilib.dirs.dbs.users, querylist)
                    except:
                        output['message'] += 'Error in modify/add query: ' + ",".join(querylist)
                    else:
                        output['message'] += 'Successful modify/add query. ' + ",".join(querylist)
                else:
                    output['message'] += 'Need usertomodify in query. '
            elif action == 'useradd':
                try:
                    username = post['newusername']
                except:
                    username = '******'
                try:
                    newemail = post['newemail']
                except:
                    newemail = '*****@*****.**'
                try:
                    newauthlevel = post['newauthlevel']
                except:
                    newauthlevel = 0
                    query = "insert into users values(NULL,'" + username + "','','" + newemail + "',''," + str(newauthlevel) + ")"
                try:
                    dblib.sqlitequery(pilib.dirs.dbs.users, query)
                except:
                    output['message'] += "Error in useradd sqlite query: " + query + ' . '
                else:
                    output['message'] += "Successful query: " + query + ' . '
        elif action == 'getfiletext':
            try:
                filepath = post['filepath']
                if 'numlines' in post:
                    numlines = int(post['numlines'])
                else:
                    numlines = 9999
                output['message'] += 'Using numlines: ' + str(numlines) + ' for read action. '
                if 'startposition' in post:
                    startposition = post['startposition']
                else:
                    startposition = 'end'
                output['message'] += 'Reading from position ' + startposition + '. '
            except KeyError:
                output['message'] += 'Sufficient keys for action getfile text do not exist. '
            except:
                output['message'] += 'Uncaught error in getfiletext. '
            else:
                try:
                    file = open(filepath)
                    lines = file.readlines()
                except:
                    output['message'] += 'Error reading file in getfiletext action. '
                else:
                    output['data'] = []
                    if startposition == 'end':
                        try:
                            output['data'] = datalib.tail(file, numlines)[0]
                        except:
                            output['message'] += 'Error in tail read. '
                    else:
                        linecount = 0
                        for line in lines:
                            linecount += 1
                            if linecount > numlines:
                                break
                            else:
                                output['data'].append(line)
        elif action == 'getmbtcpdata':
            try:
                clientIP = post['clientIP']
                register = post['register']
                length = post['length']
            except KeyError:
                output['message'] += 'Sufficient keys do not exist for the command. Requires clientIP, register, and length. '
            else:
                from iiutilities.netfun import readMBcodedaddresses
                # try:
                output['response'] = readMBcodedaddresses(clientIP, int(register), int(length))
        elif action == 'queuemessage':
            output['message'] += 'Queue message. '
            if 'message' in post:
                try:
                    dblib.sqliteinsertsingle(pilib.dirs.dbs.motes, 'queuedmessages', [datalib.gettimestring(), post['message']])
                except:
                    import traceback
                    exc_type, exc_value, exc_traceback = sys.exc_info()
                    output['message'] += 'Error in queue insert query: {}. '.format(traceback.format_exc())
                else:
                    output['message'] += 'Message insert successful'
            else:
                output['message'] += 'No message present. '

        elif action == 'setsystemflag' and 'systemflag' in post:
            database = pilib.dirs.dbs.system
            dblib.setsinglevalue(database, 'systemflags', 'value', 1, "name=\'" + post['systemflag'] + "'")
        elif action == 'rundaemon':
            from cupiddaemon import rundaemon
            rundaemon()

        # TODO: Eliminate this scary thing.
        elif action == 'setvalue':
            utility.log(pilib.dirs.logs.control, "Setting value in wsgi", 1, 1)

            # we use the auxiliary 'setsinglecontrolvalue' to add additional actions to update
            if all(k in post for k in ('database', 'table', 'valuename', 'value')):
                dbpath = pilib.dbnametopath(post['database'])
                if dbpath:
                    output['message'] += 'Carrying out setvalue for value ' + post['valuename'] + ' on ' + post['table'] + ' in '  + dbpath
                    if 'condition' in post:
                        pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value'], post['condition'])
                    elif 'index' in post:
                        condition = 'rowid= ' + post['index']
                        pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value'], condition)
                    else:
                        pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value'])
                else:
                    output['message'] += 'Problem translating dbpath from friendly name: ' + post['database']
            else:
                output['message'] += 'Insufficient data for setvalue '
        elif action == 'updateioinfo':
            if all(k in post for k in ['database', 'ioid', 'value']):
                query = dblib.makesqliteinsert('ioinfo', [post['ioid'], post['value']], ['id', 'name'])
                try:
                    dblib.sqlitequery(pilib.dirs.dbs.control, query)
                except:
                    output['message'] += 'Error in updateioinfo query execution: ' + query +'. into database: ' + pilib.dirs.dbs.control
                    output['message'] += 'ioid: ' + post['ioid'] + ' . '
                else:
                    output['message'] += 'Executed updateioinfo query. '
            else:
                output['message'] += 'Insufficient data for updateioinfo query ! '


        # TODO: properly incorporate and test channel class functions here, and then sub it.
        elif action == 'modify_channel':
            controllib.app_modify_channel(post, output)

        elif action == 'deletechannelbyname' and 'database' in post and 'channelname' in post:
            dbpath = pilib.dbnametopath(post['database'])
            dblib.sqlitequery(dbpath, 'delete channelname from channels where name=\"' + post['channelname'] + '\"')
        elif action == 'updatecameraimage':
            output['message'] += 'Take camera image keyword. '
            import cupid.camera
            if 'width' in post:
                width = post['width']
            else:
                width = 800
            try:
                values = cupid.camera.takesnap(width=width)
            except:
                output['message'] += 'Error taking image. '
            else:
                output['message'] += 'Appears successful. Path : ' + values['imagepath'] + '. Timestamp : ' + values['timestamp'] + '. '
                output['data'] = values
        elif action == 'getcurrentcamtimestamp':
            output['message'] += 'getcurrentcamtimestamp keyword found. '
            try:
                with open('/var/www/webcam/images/current.jpg.timestamp') as f:
                    data = f.read()
            except:
                output['message'] += 'Error reading file as requested. '
            else:
                output['data'] = data
        else:
            output['message'] += 'Action keyword present(' + action + '), but not handled. '
    else:
        output['message'] += 'Authentication unsuccessful or action not authorized.'
        status = '401 Not Authorized'

    foutput = json.dumps(output, indent=1)

    response_headers = [('Content-type', 'application/json')]
    start_response(status, response_headers)

    return [foutput]
Esempio n. 16
0
    #print('enabled')
    polltime = dblib.sqlitedatumquery(
        pilib.dirs.dbs.session, 'select updatefrequency from \'settings\'')

    # Go through sessions and delete expired ones
    sessions = pilib.dirs.dbs.session.read_table('sessions')
    arrayquery = []
    for session in sessions:
        sessionstart = datalib.timestringtoseconds(session['timecreated'])
        sessionlength = session['sessionlength']
        if time.time() - sessionstart > sessionlength:
            arrayquery.append('delete from sessions where sessionid=\'' +
                              session['sessionid'] + '\'')

    # Delete offensive sessions
    dblib.sqlitemultquery(pilib.dirs.dbs.session, arrayquery)

    # Reload surviving sessions and summarize
    sessions = pilib.dirs.dbs.session.read_table('sessions')
    sessiondictarray = []
    for session in sessions:
        found = 0
        for dict in sessiondictarray:
            if dict['username'] == session['username']:
                found = 1
                index = sessiondictarray.index(dict)
                dict['sessions'] += 1
                sessiondictarray[index] = dict
        if not found:
            sessiondictarray.append({
                'username': session['username'],
Esempio n. 17
0
while enabled:
    #print('enabled')
    polltime = dblib.sqlitedatumquery(pilib.dirs.dbs.session, 'select updatefrequency from \'settings\'')

    # Go through sessions and delete expired ones
    sessions = pilib.dirs.dbs.session.read_table('sessions')
    arrayquery = []
    for session in sessions:
        sessionstart = datalib.timestringtoseconds(session['timecreated'])
        sessionlength = session['sessionlength']
        if time.time() - sessionstart > sessionlength:
            arrayquery.append('delete from sessions where sessionid=\'' + session['sessionid'] + '\'')

    # Delete offensive sessions 
    dblib.sqlitemultquery(pilib.dirs.dbs.session, arrayquery)

    # Reload surviving sessions and summarize
    sessions = pilib.dirs.dbs.session.read_table('sessions')
    sessiondictarray = []
    for session in sessions:
        found = 0
        for dict in sessiondictarray:
            if dict['username'] == session['username']:
                found = 1
                index = sessiondictarray.index(dict)
                dict['sessions'] += 1
                sessiondictarray[index] = dict
        if not found:
            sessiondictarray.append({'username': session['username'], 'sessions': 1})