From 4f5df6c1feef997fb3fa27a13bdc717c7a4a1ee3 Mon Sep 17 00:00:00 2001 From: willd Date: Mon, 28 Nov 2022 21:16:34 +0100 Subject: [PATCH] User editor, baseURL change, remove octopart autofill --- parts/server.py | 76 +++++++++++++++++++++------- parts/static/locationEditorScript.js | 0 parts/static/script.js | 44 +++++++++++----- parts/static/style-m.css | 0 parts/static/style.css | 0 parts/templates/locationEditor.html | 6 +-- parts/templates/partsearch.html | 12 ++--- 7 files changed, 98 insertions(+), 40 deletions(-) mode change 100644 => 100755 parts/server.py mode change 100644 => 100755 parts/static/locationEditorScript.js mode change 100644 => 100755 parts/static/script.js mode change 100644 => 100755 parts/static/style-m.css mode change 100644 => 100755 parts/static/style.css mode change 100644 => 100755 parts/templates/locationEditor.html mode change 100644 => 100755 parts/templates/partsearch.html diff --git a/parts/server.py b/parts/server.py old mode 100644 new mode 100755 index 2d37e50..1b8229a --- a/parts/server.py +++ b/parts/server.py @@ -20,6 +20,7 @@ db_engine = {} db_metadata = {} parts = {} octopartURL ="" +baseURL = "/parts-dev" def getContainers(): query = "select id, name from containers order by UPPER(name);" @@ -65,11 +66,11 @@ def serveImage(img): img_io.seek(0) return send_file(img_io, mimetype='image/png') -@app.route('/parts', strict_slashes=True) +@app.route(baseURL, strict_slashes=True) def index(): - return render_template('partsearch.html', containers=getContainers()) + return render_template('partsearch.html', containers=getContainers(), baseURL=baseURL) -@app.route('/parts/getlocationsInContainer/') +@app.route(baseURL+'/getlocationsInContainer/') def get_locations_in_container(containerID): s = 'select id, name from locations where container_id = :id order by name;' r = db_engine.execute(text(s), id=containerID) @@ -79,7 +80,7 @@ def get_locations_in_container(containerID): r.close() return json.dumps(l) -@app.route('/parts/getlocationURL/') +@app.route(baseURL+'/getlocationURL/') def get_locationURL(locationID): s = 'select map from locations where id = :id;' r = db_engine.execute(text(s), id=locationID) @@ -89,7 +90,7 @@ def get_locationURL(locationID): r.close() return l[0][0] -@app.route('/parts/locationEditor') +@app.route(baseURL+'/locationEditor') def locationEditor(): query = 'select c.name as container, l.name as name, l.id, c.id as container_id from locations as l inner join containers as c on l.container_id = c.id order by container, name;' r = db_engine.execute(text(query)) @@ -97,9 +98,20 @@ def locationEditor(): for row in r: locations.append(dict(row)) r.close() - return render_template('locationEditor.html', locations=locations, containers=getContainers()) + return render_template('locationEditor.html', locations=locations, containers=getContainers(),baseURL=baseURL) +@app.route(baseURL+'/userEditor') +def userEditor(): + query = 'select c.name as container, l.name as name, l.id, c.id as container_id from locations as l inner join containers as c on l.container_id = c.id order by container, name;' + query = 'select id, username from users;' + + r = db_engine.execute(text(query)) + users = [] + for row in r: + users.append(dict(row)) + r.close() + return render_template('userEditor.html', users=users, containers=getContainers(),baseURL=baseURL) -@app.route('/parts/alterLocation/', methods=['POST']) +@app.route(baseURL+'/alterLocation/', methods=['POST']) @requires_auth def alterLocation(locationID): locationID = int(locationID) @@ -121,8 +133,30 @@ def alterLocation(locationID): r = db_engine.execute(s, name=request.form['name'],container=request.form['container'],locationID=locationID); r.close() return '{"status":"ok"}' +@app.route(baseURL+'/alterUser/', methods=['POST']) +@requires_auth +def alterUser(userID): + userID = int(userID) + s = '' + if userID < 0: + # New entry + s = 'insert into users (username, password) ' + s += 'values (:name, :password);' + s = text(s) + r = db_engine.execute(s,username=request.form['name'],password=request.form['password']); + r.close() + return '{"status":"ok"}' + else: + # Modify entry + s = 'update users ' + s += 'set username=:name, password=:password ' + s += 'where id=:userID;' + s = text(s) + r = db_engine.execute(s, name=request.form['name'],password=request.form['password'],userID=userID); + r.close() + return '{"status":"ok"}' -@app.route('/parts/getpartinfo/') +@app.route(baseURL+'/getpartinfo/') def get_part_info(partID): s = 'select p.id,partno,description,notes, c.name || l.name as location_descriptor, location_id, container_id, datasheet from parts as p inner join locations as l on p.location_id = l.id inner join containers as c on l.container_id = c.id where p.id = :id;' r = db_engine.execute(text(s), id=partID) @@ -132,7 +166,7 @@ def get_part_info(partID): r.close() return json.dumps(l[0]) -@app.route('/parts/query//') # TODO: maybe change AND to OR or maybe not +@app.route(baseURL+'/query//') # TODO: maybe change AND to OR or maybe not def query(filter_dummy, query): filter = request.args.to_dict() keywords = query.split() # Default splits with spaces @@ -171,7 +205,7 @@ def query(filter_dummy, query): r.close() return json.dumps(l) -@app.route('/parts/map/') +@app.route(baseURL+'/map/') def getMap(containerID): s = 'select map, overlay from containers where id = :id;' r = db_engine.execute(text(s), id=containerID) @@ -196,14 +230,14 @@ def getMap(containerID): return serveImage(mapimage) -@app.route('/parts/getfile/') +@app.route(baseURL+'/getfile/') def getfile(filename): if(re.match('^[\w\-_]+.[p|P][d|D][f|F]$', filename) == None): return 'No injections pls.' return send_from_directory('/srv/datasheets/', filename) -@app.route('/parts/alter/', methods=['POST']) +@app.route(baseURL+'/alter/', methods=['POST']) @requires_auth def alter(partID): partID = int(partID) @@ -276,7 +310,7 @@ def alter(partID): r.close() return '{"status":"ok", "part_id" : ' + str(new_id) + '}' -@app.route('/parts/delete/') +@app.route(baseURL+'/delete/') @requires_auth def delete(partID): if int(partID) < 0: @@ -285,7 +319,7 @@ def delete(partID): r = db_engine.execute(s, id=partID) return '{"status":"ok"}' -@app.route('/parts/deleteLocation/') +@app.route(baseURL+'/deleteLocation/') @requires_auth def deleteLocation(locationID): if int(locationID) < 0: @@ -293,8 +327,16 @@ def deleteLocation(locationID): s = text('delete from locations where id=:id;') r = db_engine.execute(s, id=locationID) return '{"status":"ok"}' +@app.route(baseURL+'/deleteUser/') +@requires_auth +def deleteUser(userID): + if int(userID) < 0: + abort(400) + s = text('delete from users where id=:id;') + r = db_engine.execute(s, id=userID) + return '{"status":"ok"}' -@app.route('/parts/fetchOctopartSnippet/') +@app.route(baseURL+'/fetchOctopartSnippet/') def fetchOctopartSnippet(searchTerm): if octopartURL == '': return '{"result":"octopart integration not enabled"}' @@ -334,7 +376,7 @@ if __name__ == '__main__': app.config['SESSION_TYPE'] = 'memcached' with open('admin.json') as f: postgres_credentials = json.load(f) - db_engine, db_metadata = connect(postgres_credentials['username'], postgres_credentials['password'], 'parts_v2') + db_engine, db_metadata = connect(postgres_credentials['username'], postgres_credentials['password'], 'parts_v3') parts = sqlalchemy.Table('parts', db_metadata) try: with open('octopartAPIkey.json') as f: @@ -350,4 +392,4 @@ if __name__ == '__main__': '''s = select([parts]).where(parts.c.notes != '') for row in db_engine.execute(s): print row''' - app.run('0.0.0.0') + app.run(host='127.0.0.1', port='5001', debug=True) diff --git a/parts/static/locationEditorScript.js b/parts/static/locationEditorScript.js old mode 100644 new mode 100755 diff --git a/parts/static/script.js b/parts/static/script.js old mode 100644 new mode 100755 index d58a40d..56ec5ab --- a/parts/static/script.js +++ b/parts/static/script.js @@ -213,6 +213,10 @@ function show_part_info(partID) { }).fail(function() { console.log( "Fetching part info failed" ); }); + + // update URL and history + var query = $('.search-bar').val(); + window.history.pushState('searching', '', 'parts?q=' + query + '&p=' + partID) } function perform_query() { @@ -245,6 +249,9 @@ function perform_query() { $('#no-results').animate({opacity:1},2000); console.log( "Query failed" ); }); + + // update URL and history + window.history.pushState('searching', '', 'parts?q=' + query) } function container_onchange() { @@ -260,20 +267,20 @@ function container_onchange() { } } -function octopartFetch(){ - $('#magic-autofill-button').attr('disabled', 'disabled'); - $.getJSON(rootURL + 'fetchOctopartSnippet/' + $('#partno-input').val()).done(function(json){ - $('#magic-autofill-button').removeAttr('disabled'); - if (json['result']=='ok'){ - $('#description-input').val(json['snippet']); - }else{ - $('#description-input').val(''); - $('#description-input').attr('placeholder', json['result']); - } - }).fail(function() { - $('#magic-autofill-button').removeAttr('disabled'); - }); -} +// function octopartFetch(){ +// $('#magic-autofill-button').attr('disabled', 'disabled'); +// $.getJSON(rootURL + 'fetchOctopartSnippet/' + $('#partno-input').val()).done(function(json){ +// $('#magic-autofill-button').removeAttr('disabled'); +// if (json['result']=='ok'){ +// $('#description-input').val(json['snippet']); +// }else{ +// $('#description-input').val(''); +// $('#description-input').attr('placeholder', json['result']); +// } +// }).fail(function() { +// $('#magic-autofill-button').removeAttr('disabled'); +// }); +// } $(document).ready(function() { $.ajaxSetup({ cache: false }); @@ -291,6 +298,15 @@ $(document).ready(function() { perform_query(); }); + //For linking to a search query or specific part + const search_params = new URLSearchParams(window.location.search); + if(search_params.has('q')){ + $('.search-bar').val(search_params.get('q')); perform_query(); + } + if(search_params.has('p')){ + show_part_info(search_params.get('p')); + } + // $('#partno-input').bind('blur',function() { // if($('#partno-input').val().length > 0){ // octopartFetch(); diff --git a/parts/static/style-m.css b/parts/static/style-m.css old mode 100644 new mode 100755 diff --git a/parts/static/style.css b/parts/static/style.css old mode 100644 new mode 100755 diff --git a/parts/templates/locationEditor.html b/parts/templates/locationEditor.html old mode 100644 new mode 100755 index a32dfac..688185c --- a/parts/templates/locationEditor.html +++ b/parts/templates/locationEditor.html @@ -8,10 +8,10 @@ integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"> - + - - + +

LOCATION EDITOR

diff --git a/parts/templates/partsearch.html b/parts/templates/partsearch.html old mode 100644 new mode 100755 index 618529b..5ee9c8c --- a/parts/templates/partsearch.html +++ b/parts/templates/partsearch.html @@ -9,13 +9,13 @@ integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"> - - - + + + - - + +

ELAB Part Search Engine

@@ -58,7 +58,7 @@

DESCRIPTION

- powered by OctoPartâ„¢ + DATASHEET: OR: