From feac17bc5ca30f4b5fb5b5894dd9173745014e1f Mon Sep 17 00:00:00 2001 From: Yaman Qalieh Date: Sun, 28 Jan 2018 23:27:09 -0500 Subject: [PATCH 01/10] models, get, post --- SmearcarDB/.gitignore | 2 + SmearcarDB/server.py | 97 ++++++++++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 38 deletions(-) diff --git a/SmearcarDB/.gitignore b/SmearcarDB/.gitignore index 3ce1870..6e71737 100644 --- a/SmearcarDB/.gitignore +++ b/SmearcarDB/.gitignore @@ -108,3 +108,5 @@ venv.bak/ # Other *.p +*.txt +*.db diff --git a/SmearcarDB/server.py b/SmearcarDB/server.py index 0c035d7..ca004e9 100644 --- a/SmearcarDB/server.py +++ b/SmearcarDB/server.py @@ -1,72 +1,93 @@ import pickle from flask import Flask from flask import render_template, jsonify, request +from flask_sqlalchemy import SQLAlchemy import ulid app = Flask(__name__) +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data.db' app.config.update( DEBUG=True, TEMPLATES_AUTO_RELOAD=True ) +db = SQLAlchemy(app) -try: - with open("save.p", "rb") as f: - database = pickle.load(f) - # Can be commented out after non-id languages are all converted - for item in database['values']: - if not 'id' in item: - item['id'] = ulid.new().str -except (FileNotFoundError) as e: - database = {'languages': [], - 'phonemes': [], - 'values': []} -def saveDatabase(): - # Save copy under separate name - with open("newestsave.p", "wb") as f: - pickle.dump(database, f) +class Frequency(db.Model): + language_id = db.Column(db.Integer, db.ForeignKey('language.id'), primary_key=True) + phoneme_id = db.Column(db.Integer, db.ForeignKey('phoneme.id'), primary_key=True) + value = db.Column(db.Float(6), nullable=False) + phoneme = db.relationship('Phoneme') + + +class Language(db.Model): + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + name = db.Column(db.String(100), nullable=False) + source = db.Column(db.LargeBinary) + phonemes = db.relationship('Frequency') + + +class Phoneme(db.Model): + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + name = db.Column(db.String(5), nullable=False) + + +def database(): + final = {'values': []} + final['languages'] = [f.name for f in Language.query.all()] + final['phonemes'] = [f.name for f in Phoneme.query.all()] + for language in Language.query.all(): + languageobject = {'name': language.name, + 'source': language.source, + 'phonemes': {}} + languageobject['name'] = language.name + for frequency in language.phonemes: + languageobject['phonemes'][frequency.phoneme.name] = frequency.value + final['values'].append(languageobject) + return final + # Render the client at the default URL @app.route("/") def initial(): return render_template('index.html') + # Place for client to communicate with the server @app.route("/server", methods=["GET", "POST", "PATCH"]) # TODO add more methods def backend(): # GET method returns the latest database if request.method == "GET": - return jsonify(database) + return jsonify(database()) # POST method appends input to database['values'] elif request.method == "POST": - newlanguage = request.get_json() - newlanguage['id'] = ulid.new().str - database['values'].append(newlanguage) + recieved = request.get_json() + language = Language(name=recieved['name'], source=recieved['source']) + db.session.add(language) - # Add new phonemes - newphonemes = list(newlanguage[ 'phonemes' ]) - uniquephonemes = list(set(newphonemes) - set(database[ 'phonemes' ])) - database['phonemes'] = database['phonemes'] + uniquephonemes + for phoneme, value in recieved['phonemes'].items(): + with db.session.no_autoflush: + search = Phoneme.query.filter_by(name=phoneme).first() + print(search) + if not search: + search = Phoneme(name=phoneme) + db.session.add(search) + link = Frequency(value=value, phoneme=search) + language.phonemes.append(link) + db.session.add(link) + db.session.commit() + return jsonify(database()) - # Add new language - newlangname = {newlanguage['name']} - uniquelanguages = list(newlangname - set(database['languages'])) - database['languages'] = database['languages'] + uniquelanguages - saveDatabase() - return jsonify(database) + # # PATCH method inputs edited language and returns updated database + # elif request.method == "PATCH": + # newlanguage = request.get_json() + # database['values'] = [newlanguage if language['id'] == newlanguage['id'] else language for language in database['values']] + # saveDatabase() + # return jsonify(database()) - # PATCH method inputs edited language and returns updated database - elif request.method == "PATCH": - newlanguage = request.get_json() - database['values'] = [newlanguage if language['id'] == newlanguage['id'] else language for language in database['values']] - saveDatabase() - return jsonify(database) - - else: - return if __name__ == "__main__": app.run(host="0.0.0.0") From fdefd2732d416f56c3cdb5c1e1822c569a28ba39 Mon Sep 17 00:00:00 2001 From: yamanq Date: Mon, 29 Jan 2018 16:35:37 -0500 Subject: [PATCH 02/10] Start patch method --- SmearcarDB/server.py | 77 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/SmearcarDB/server.py b/SmearcarDB/server.py index ca004e9..081d982 100644 --- a/SmearcarDB/server.py +++ b/SmearcarDB/server.py @@ -12,6 +12,8 @@ app.config.update( ) db = SQLAlchemy(app) +# TODO Updates table (add, edit, delete) (author, date, title, content) +# TODO convert pickle to db class Frequency(db.Model): language_id = db.Column(db.Integer, db.ForeignKey('language.id'), primary_key=True) @@ -29,7 +31,7 @@ class Language(db.Model): class Phoneme(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) - name = db.Column(db.String(5), nullable=False) + name = db.Column(db.String(5), nullable=False, unique=True) def database(): @@ -46,6 +48,44 @@ def database(): final['values'].append(languageobject) return final +patch_functions = { + "phoneme_add": phoneme_add, # Add and edit value + "phoneme_remove": phoneme_remove, # Remove association and phoneme if necessary + # "language_name_edit": language_name_edit, # Change language name + # "language_source_add": language_source_add # Add/edit source +} + + +def phoneme_add(info): + """Add or edit value associated with phoneme.""" + # info = { + # language_id: language_id, + # phoneme: phoneme_name, + # value: phoneme_value + # } + phoneme = Phoneme.query.filter_by(name=info['phoneme']).first() + language = Language.query.filter_by(id=info['language_id']).first() + if phoneme: + link = Frequency.query.filter_by(language_id=language.id, phoneme_id=phoneme.id).first() + link.value = info['value'] + else: + phoneme = Phoneme(name=info['phoneme']) + link = Frequency(value=info['value']) + link.phoneme = phoneme + language.phonemes.append(link) + db.session.add_all([phoneme, link]) + + +def phoneme_remove(info): + """Remove a phoneme from a language.""" + # info = { + # language_id: language_id, + # phoneme_id: phoneme_id + # } + pass + + + # Render the client at the default URL @app.route("/") @@ -53,16 +93,22 @@ def initial(): return render_template('index.html') +# GET method for files +@app.route("/server/") +def file_return(lang_id): + return Language.query.filter_by(id=lang_id).first().source + + # Place for client to communicate with the server @app.route("/server", methods=["GET", "POST", "PATCH"]) # TODO add more methods def backend(): - # GET method returns the latest database - if request.method == "GET": - return jsonify(database()) + # # GET method returns the latest database + # if request.method == "GET": + # return jsonify(database()) # POST method appends input to database['values'] - elif request.method == "POST": + if request.method == "POST": recieved = request.get_json() language = Language(name=recieved['name'], source=recieved['source']) db.session.add(language) @@ -78,16 +124,19 @@ def backend(): language.phonemes.append(link) db.session.add(link) db.session.commit() - return jsonify(database()) + # return jsonify(database()) - # # PATCH method inputs edited language and returns updated database - # elif request.method == "PATCH": - # newlanguage = request.get_json() - # database['values'] = [newlanguage if language['id'] == newlanguage['id'] else language for language in database['values']] - # saveDatabase() - # return jsonify(database()) + # PATCH method inputs edited language and returns updated database + elif request.method == "PATCH": + recieved = request.get_json() + patch_functions[recieved['action']](recieved['data']) + db.session.commit() + # database['values'] = [newlanguage if language['id'] == newlanguage['id'] else language for language in database['values']] + # saveDatabase() + + return jsonify(database()) -if __name__ == "__main__": - app.run(host="0.0.0.0") +# if __name__ == "__main__": +# app.run(host="0.0.0.0") From b6c87fa506579757c749237500331ba126bebc8b Mon Sep 17 00:00:00 2001 From: Yaman Qalieh Date: Mon, 29 Jan 2018 19:36:10 -0500 Subject: [PATCH 03/10] finish PATCH and add Updates with approute --- SmearcarDB/server.py | 88 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 17 deletions(-) diff --git a/SmearcarDB/server.py b/SmearcarDB/server.py index 081d982..eb6e247 100644 --- a/SmearcarDB/server.py +++ b/SmearcarDB/server.py @@ -1,8 +1,7 @@ -import pickle from flask import Flask from flask import render_template, jsonify, request from flask_sqlalchemy import SQLAlchemy -import ulid +import time app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data.db' @@ -12,8 +11,6 @@ app.config.update( ) db = SQLAlchemy(app) -# TODO Updates table (add, edit, delete) (author, date, title, content) -# TODO convert pickle to db class Frequency(db.Model): language_id = db.Column(db.Integer, db.ForeignKey('language.id'), primary_key=True) @@ -34,6 +31,15 @@ class Phoneme(db.Model): name = db.Column(db.String(5), nullable=False, unique=True) +class Update(db.Model): + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + author = db.Column(db.String(30), nullable=False) + title = db.Column(db.String(100), nullable=False) + content = db.Column(db.Text, nullable=False) + date = db.Column(db.BigInteger, nullable=False, + default=int(time.time()*1000)) + + def database(): final = {'values': []} final['languages'] = [f.name for f in Language.query.all()] @@ -48,13 +54,6 @@ def database(): final['values'].append(languageobject) return final -patch_functions = { - "phoneme_add": phoneme_add, # Add and edit value - "phoneme_remove": phoneme_remove, # Remove association and phoneme if necessary - # "language_name_edit": language_name_edit, # Change language name - # "language_source_add": language_source_add # Add/edit source -} - def phoneme_add(info): """Add or edit value associated with phoneme.""" @@ -66,7 +65,9 @@ def phoneme_add(info): phoneme = Phoneme.query.filter_by(name=info['phoneme']).first() language = Language.query.filter_by(id=info['language_id']).first() if phoneme: - link = Frequency.query.filter_by(language_id=language.id, phoneme_id=phoneme.id).first() + link = Frequency.query.filter_by( + language_id=language.id, + phoneme_id=phoneme.id).first() link.value = info['value'] else: phoneme = Phoneme(name=info['phoneme']) @@ -82,9 +83,44 @@ def phoneme_remove(info): # language_id: language_id, # phoneme_id: phoneme_id # } - pass + phoneme = Phoneme.query.filter_by(id=info['phoneme_id']).first() + language = Language.query.filter_by(id=info['language_id']).first() + frequency = Frequency.query.filter_by( + phoneme_id=info['phoneme_id'], language_id=info['language_id']).first() + + if Frequency.query.filter_by(phoneme_id=info['phoneme_id']).count() == 1: + # Delete phoneme + db.session.delete(phoneme) + + language.phonemes = [frequency for frequency in language.phonemes + if frequency.phoneme_id != info['phoneme_id']] + db.session.delete(frequency) +def language_name_edit(info): + """Edit the name of a Language.""" + # info = { + # language_id: language_id, + # language_name: name + # } + Language.query.filter_by(id=info['language_id']).first().name = info['language_name'] + + +def language_source_add(info): + """Add or replace a source""" + # info = { + # language_id: language_id, + # language_source = source + # } + Language.query.filter_by(id=info['language_id']).first().source = info['language_source'] + + +patch_functions = { + "phoneme_add": phoneme_add, # Add and edit value + "phoneme_remove": phoneme_remove, # Remove association and/or phoneme + "language_name_edit": language_name_edit, # Change language name + "language_source_add": language_source_add # Add/edit source +} # Render the client at the default URL @@ -101,7 +137,6 @@ def file_return(lang_id): # Place for client to communicate with the server @app.route("/server", methods=["GET", "POST", "PATCH"]) -# TODO add more methods def backend(): # # GET method returns the latest database # if request.method == "GET": @@ -126,17 +161,36 @@ def backend(): db.session.commit() # return jsonify(database()) - # PATCH method inputs edited language and returns updated database elif request.method == "PATCH": recieved = request.get_json() patch_functions[recieved['action']](recieved['data']) db.session.commit() - # database['values'] = [newlanguage if language['id'] == newlanguage['id'] else language for language in database['values']] - # saveDatabase() return jsonify(database()) +# Manipulate Updates +@app.route("/updates", methods=["GET", "POST", "PATCH"]) +def updates(): + if request.method == "POST": + recieved = request.get_json() + update = Update(author=recieved['author'], + title=recieved['title'], + content=recieved['content']) + db.session.add(update) + elif request.method == "PATCH": + update = Update.query.filter_by(id=recieved['id']).first() + update.name = recieved['author'] + update.title = recieved['title'] + update.content = recieved['content'] + db.session.commit() + return jsonify([{"author": update.name, + "id": update.id, + "title": update.title, + "content": update.content, + "date": update.date} + for update in Update.query.all()]) + # if __name__ == "__main__": # app.run(host="0.0.0.0") From 6b9df945d3ebfe6c9fe660b7a9dcd991d7487d8c Mon Sep 17 00:00:00 2001 From: Yaman Qalieh Date: Wed, 31 Jan 2018 17:12:54 -0500 Subject: [PATCH 04/10] working post on js --- SmearcarDB/server.py | 9 ++++++--- SmearcarDB/static/index.js | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/SmearcarDB/server.py b/SmearcarDB/server.py index eb6e247..87c22fe 100644 --- a/SmearcarDB/server.py +++ b/SmearcarDB/server.py @@ -151,7 +151,6 @@ def backend(): for phoneme, value in recieved['phonemes'].items(): with db.session.no_autoflush: search = Phoneme.query.filter_by(name=phoneme).first() - print(search) if not search: search = Phoneme(name=phoneme) db.session.add(search) @@ -173,17 +172,20 @@ def backend(): # Manipulate Updates @app.route("/updates", methods=["GET", "POST", "PATCH"]) def updates(): + if request.method == "POST": recieved = request.get_json() update = Update(author=recieved['author'], title=recieved['title'], content=recieved['content']) db.session.add(update) + elif request.method == "PATCH": update = Update.query.filter_by(id=recieved['id']).first() update.name = recieved['author'] update.title = recieved['title'] update.content = recieved['content'] + db.session.commit() return jsonify([{"author": update.name, "id": update.id, @@ -192,5 +194,6 @@ def updates(): "date": update.date} for update in Update.query.all()]) -# if __name__ == "__main__": -# app.run(host="0.0.0.0") + +if __name__ == "__main__": + app.run(host="0.0.0.0") diff --git a/SmearcarDB/static/index.js b/SmearcarDB/static/index.js index 83039f2..20697e2 100644 --- a/SmearcarDB/static/index.js +++ b/SmearcarDB/static/index.js @@ -22,6 +22,28 @@ var dropOp = { var dropOpStore = {}; +// Left This so that the post function can be reused + +// function temporary(data) { +// for(var i = 0; i < data.length; i++) { +// $.ajax({ +// url: serverURL + '/server', +// type: 'POST', +// data: JSON.stringify(data[i]), +// dataType: "json", +// contentType: 'application/json;charset=UTF-8' +// }) +// .then( +// function success(data) { +// console.log(data); +// }, +// function error(e) { +// console.log(e); +// } +// ); +// } +// } + function createNav() { for (var i = 0; i < navi.length; i++) { // Create navigation tabs. var side = document.getElementById("sidebar"); From 5551469c94414a5dd95d801a2fcde592bb5d415d Mon Sep 17 00:00:00 2001 From: Kenneth Jao Date: Sat, 3 Feb 2018 23:00:40 -0500 Subject: [PATCH 05/10] added chart --- SmearcarDB/static/index.css | 29 +++++++++++++++++---------- SmearcarDB/static/index.js | 35 ++++++++++++++++++++++++++++----- SmearcarDB/templates/index.html | 21 +++++++++++--------- 3 files changed, 61 insertions(+), 24 deletions(-) diff --git a/SmearcarDB/static/index.css b/SmearcarDB/static/index.css index e74b6d0..8d8b57a 100644 --- a/SmearcarDB/static/index.css +++ b/SmearcarDB/static/index.css @@ -203,11 +203,6 @@ a { grid-gap: 2vh; } - #dataValues { - grid-template-columns: 1fr 1fr; - grid-template-rows: 2fr 5fr 2fr; -} - #home { display: block; @@ -267,6 +262,25 @@ a { font-weight: 300; } +.row { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: 100%; + grid-gap: 2vh; +} + +#dataValues > div { + margin-bottom: 2vh; +} + +#dataValues .row { + height: 20%; +} + +#dataValues #dataTable { + height: 42%; +} + #langSelect { grid-column: 1; grid-row: 1; @@ -290,11 +304,6 @@ a { margin: auto 0 auto 4vh; } -#dataTable { - grid-column: 1 / 3; - grid-row: 2; -} - #dataTableCont { display: grid; font-weight: 300; diff --git a/SmearcarDB/static/index.js b/SmearcarDB/static/index.js index 2f607ed..aab606b 100644 --- a/SmearcarDB/static/index.js +++ b/SmearcarDB/static/index.js @@ -50,11 +50,7 @@ function updateMain(op) { // Updates the actual page. setTimeout(function() { console.log(op); document.getElementById(navSelect).style.display = "none"; - if(op === "home") { - document.getElementById(op).style.display = "block"; - } else { - document.getElementById(op).style.display = "grid"; - } + document.getElementById(op).style.display = "block"; setTimeout(function() { document.getElementById(op).style.opacity = "1"; }, 30); @@ -134,6 +130,7 @@ function generateDropOp() { // For options that change based on data. } info.appendChild(p); info.appendChild(p2); + // Generate data box material. var phonemes = Object.keys(langInfo.phonemes); @@ -171,6 +168,34 @@ function generateDropOp() { // For options that change based on data. } info.style.opacity = "1"; dataBox.style.opacity = "1"; + var graphData = Object.entries(langInfo.phonemes).sort(function(a,b) { + return b[1] - a[1]; + }); + graphData = [graphData.map(function(a,b) { + return a[0]; + }), graphData.map(function(a,b) { + return a[1]; + })]; + // Generate graphs. + var ctx = document.getElementById("dataGraph1").getContext("2d"); + var chart = new Chart(ctx, { + // The type of chart we want to create + type: 'bar', + + // The data for our dataset + data: { + labels: graphData[0], + datasets: [{ + label: "Phoneme Prevalence", + backgroundColor: 'rgb(255, 99, 132)', + borderColor: 'rgb(255, 99, 132)', + data: graphData[1], + }] + }, + + // Configuration options go here + options: {} + }); }, 300); }].concat(["Select language..."].concat(data.languages)); } diff --git a/SmearcarDB/templates/index.html b/SmearcarDB/templates/index.html index 00ac2a1..d56a405 100644 --- a/SmearcarDB/templates/index.html +++ b/SmearcarDB/templates/index.html @@ -27,14 +27,16 @@
-
-

Language

-