diff --git a/__init__.py b/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/app.py b/app.py index c392ef8..af0b1ca 100755 --- a/app.py +++ b/app.py @@ -11,13 +11,16 @@ from flask_migrate import Migrate from uuid import uuid4 import csv import validate +import secrets +from dotenv import load_dotenv +load_dotenv() # from datetime import date app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///project.db" -app.secret_key = '98d31240f9fbe14c8083586db49c19c3a8d3f726' +app.secret_key = os.getenv('SECRET_KEY', secrets.token_hex(16)) db: SQLAlchemy = SQLAlchemy() migrate = Migrate() db.init_app(app) @@ -72,20 +75,20 @@ def object_as_dict(obj): class Chemical(db.Model): query: db.Query id = db.Column(db.Integer, primary_key=True) + person_name = db.Column(db.String, nullable=False) standard_grp = db.Column(db.String, nullable=False) - uploaded_by = db.Column(db.String, nullable=False) # all fields after here are included in the database chemical_db_id = db.Column(db.String) library = db.Column(db.String) # important fields - name = db.Column(db.String, nullable=False) + metabolite_name = db.Column(db.String, nullable=False) formula = db.Column(db.String, nullable=False) mass = db.Column(db.Float, nullable=False) pubchem_cid = db.Column(db.Integer) pubmed_refcount = db.Column(db.Integer) standard_class = db.Column(db.String) - inchikey = db.Column(db.String) + inchikey = db.Column(db.String, nullable=False) inchikey14 = db.Column(db.String) final_mz = db.Column(db.Float, nullable=False) @@ -95,7 +98,7 @@ class Chemical(db.Model): adduct = db.Column(db.String) detected_adducts = db.Column(db.String) adduct_calc_mz = db.Column(db.String) - msms_detected = db.Column(db.Boolean) + msms_detected = db.Column(db.Boolean, nullable=False) msms_purity = db.Column(db.Float) # serialized into datetime.date @@ -275,7 +278,7 @@ def search_api(): data = [] for x in result: data.append({"url": url_for("chemical_view", id=x.id), - "name": x.name, "mz": x.final_mz, "rt": x.final_rt}) + "name": x.metabolite_name, "mz": x.final_mz, "rt": x.final_rt}) return jsonify(data) @@ -289,10 +292,10 @@ def batch_add_request(): if not session.get('admin'): abort(403) if request.method == "POST": - if "csv" not in request.files or request.files["csv"].filename == '': + if "input" not in request.files or request.files["input"].filename == '': return render_template("batchadd.html", invalid="Blank file included") # save the file to RAM - file = request.files["csv"] + file = request.files["input"] os.makedirs("/tmp/walkerdb", exist_ok=True) filename = os.path.join("/tmp/walkerdb", str(uuid4())) file.save(filename) @@ -320,10 +323,10 @@ def batch_query_request(): if not session.get('admin'): abort(403) if request.method == "POST": - if "csv" not in request.files or request.files["csv"].filename == '': + if "input" not in request.files or request.files["input"].filename == '': return render_template("batchadd.html", invalid="Blank file included") # save the file to RAM - file = request.files["csv"] + file = request.files["input"] os.makedirs("/tmp/walkerdb", exist_ok=True) filename = os.path.join("/tmp/walkerdb", str(uuid4())) file.save(filename) @@ -331,7 +334,7 @@ def batch_query_request(): def cleanup(): return os.remove(filename) # read it as a csv with open(filename, "r") as csvfile: - reader = csv.DictReader(csvfile) + reader = csv.DictReader(csvfile, delimiter="\t") queries, error = validate.validate_query_csv_fields(reader) if error: cleanup() @@ -351,7 +354,7 @@ def batch_query_request(): hits = [] for x in result: hits.append({"url": url_for("chemical_view", id=x.id), - "name": x.name, "mz": x.final_mz, "rt": x.final_rt}) + "name": x.metabolite_name, "mz": x.final_mz, "rt": x.final_rt}) data.append(dict( query=query, hits=hits, diff --git a/poetry.lock b/poetry.lock index 1a67079..143dd23 100644 --- a/poetry.lock +++ b/poetry.lock @@ -278,6 +278,17 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "python-dotenv" +version = "1.0.0" +description = "Read key-value pairs from a .env file and set them as environment variables" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.extras] +cli = ["click (>=5.0)"] + [[package]] name = "six" version = "1.16.0" @@ -473,7 +484,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "flake8 (<5)", "pytest-co [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "8595ab65ac1a098228335d1c012a7f266cea9014f71af835581a10debdf36230" +content-hash = "29c910c8ad182165233a27e0d14ba7a56f9bc8393e7ab8f081767bfa0a470dc9" [metadata.files] alembic = [ @@ -663,6 +674,10 @@ pycodestyle = [ {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, ] +python-dotenv = [ + {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, + {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, +] six = [] sqlalchemy = [ {file = "SQLAlchemy-1.4.46-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:7001f16a9a8e06488c3c7154827c48455d1c1507d7228d43e781afbc8ceccf6d"}, diff --git a/pyproject.toml b/pyproject.toml index 4b32abb..c85452d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ wtforms-alchemy = "^0.18.0" flask-wtf = "^1.0.1" gunicorn = "^20.1.0" Flask-Migrate = "^4.0.4" +python-dotenv = "^1.0.0" [tool.poetry.dev-dependencies] autopep8 = "^2.0.1" diff --git a/templates/admin.html b/templates/admin.html index ecd3ab7..0645cfb 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -53,8 +53,9 @@ session.post(baseurl + "/admin/login", {"username": (username), "password": (pas fields = { "chemical_db_id": <db id from another database>, "library": (library, is a string), + "person_name": (name of person who uploaded, string) # name, formula, and mass are required fields! - "name": (name of the chemical, is a string), + "metabolite_name": (name of the chemical, is a string), "formula": (molecular formula, is a string), "mass": (monoisotopic mass, is a float), "pubchem_cid": <string>, diff --git a/templates/batchadd.html b/templates/batchadd.html index d012923..652ce50 100644 --- a/templates/batchadd.html +++ b/templates/batchadd.html @@ -5,8 +5,8 @@ Source Code with required type definitions
- - + +
diff --git a/templates/batchquery.html b/templates/batchquery.html index edc958e..b7a20be 100644 --- a/templates/batchquery.html +++ b/templates/batchquery.html @@ -5,8 +5,8 @@ Source Code with required type definitions
- - + +
diff --git a/validate.py b/validate.py index e5061ee..9378688 100755 --- a/validate.py +++ b/validate.py @@ -6,8 +6,9 @@ Required fields when inserting into the database. _required_fields = [ # the "str" type means that this field can be any valid string. - ("name", "str"), + ("metabolite_name", "str"), ("formula", "str"), + ("person_name", "str"), # any field labeled a "float" needs to have a value in decimal notation. ("mass", "float"), @@ -15,7 +16,9 @@ _required_fields = [ ("final_rt", "float"), ("final_adduct", "str"), ("standard_grp", "str"), - ("uploaded_by", "str"), + ("person_name", "str"), + ("msms_detected", "yesno"), # Value can either be "Yes" or "No" + ("inchikey", "str"), ] @@ -30,13 +33,11 @@ _optional_fields = [ ("pubchem_cid", "int"), # Only integers are permitted. ("pubmed_refcount", "int"), ("standard_class", "str"), - ("inchikey", "str"), ("inchikey14", "str"), ("adduct", "str"), ("detected_adducts", "str"), ("adduct_calc_mz", "str"), - ("msms_detected", "yesno"), # Value can either be "Yes" or "No" ("msms_purity", "float"), ] @@ -89,6 +90,7 @@ def validate_insertion_csv_fields(reader: csv.DictReader) -> tuple[list[dict], s chemicals: list[dict] = [] for row in reader: chemical = {} + print("row", row) for field, t in _required_fields: if field not in row: return [], f"Required field \"{field}\" not present in csv"