aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--wqflask/wqflask/server_side.py4
-rw-r--r--wqflask/wqflask/templates/edit_trait.html72
-rw-r--r--wqflask/wqflask/views.py155
3 files changed, 168 insertions, 63 deletions
diff --git a/wqflask/wqflask/server_side.py b/wqflask/wqflask/server_side.py
index 7f68efad..e661c407 100644
--- a/wqflask/wqflask/server_side.py
+++ b/wqflask/wqflask/server_side.py
@@ -9,13 +9,11 @@ class ServerSideTable:
the client-side and reduces the size of data interchanged.
Usage:
- ServerSideTable(table_data, request_values)
+ ServerSideTable(rows_count, table_rows, header_data_names, request_values)
where,
- `table_data` must have data members
`rows_count` as number of rows in the table,
`table_rows` as data rows of the table,
`header_data_names` as headers names of the table.
-
`request_values` must have request arguments values
including the DataTables server-side processing arguments.
diff --git a/wqflask/wqflask/templates/edit_trait.html b/wqflask/wqflask/templates/edit_trait.html
index f01c497c..c6668683 100644
--- a/wqflask/wqflask/templates/edit_trait.html
+++ b/wqflask/wqflask/templates/edit_trait.html
@@ -5,10 +5,53 @@
Edit Trait for Published Database
Submit Trait | Reset
-{% if publish_xref.comments %}
-<h2>Update History:</h2>
+{% if diff %}
-{{ publish_xref.comments }}
+<div class="container">
+ <details class="col-sm-12 col-md-10 col-lg-12">
+ <summary>
+ <h2>Update History</h2>
+ </summary>
+ <table class="table">
+ <tbody>
+ <tr>
+ <th>Timestamp</th>
+ <th>Editor</th>
+ <th>Field</th>
+ <th>Diff</th>
+ </tr>
+ {% set ns = namespace(display_cell=True) %}
+
+ {% for timestamp, group in diff %}
+ {% set ns.display_cell = True %}
+ {% for i in group %}
+ <tr>
+ {% if ns.display_cell and i.timestamp == timestamp %}
+
+ {% set author = i.author %}
+ {% set field = i.diff.field %}
+ {% set timestamp_ = i.timestamp %}
+
+ {% else %}
+
+ {% set author = "" %}
+ {% set field = "" %}
+ {% set timestamp_ = "" %}
+
+ {% endif %}
+ <td>{{ timestamp_ }}</td>
+ <td>{{ author }} {{ display_cell }}</td>
+ <td>{{ field }}</td>
+ <td><pre>{{ i.diff.diff }}</pre></td>
+ {% set ns.display_cell = False %}
+ </tr>
+ {% endfor %}
+ {% endfor %}
+ </tbody>
+ </table>
+ </details>
+
+</div>
{% endif %}
@@ -23,12 +66,14 @@ Submit Trait | Reset
character in this field. -->
<div class="col-sm-8">
<textarea name="pubmed-id" class="form-control" rows="1">{{ publish_xref.publication_id |default('', true) }}</textarea>
+ <input name="old_id_" class="changed" type="hidden" value="{{ publish_xref.publication_id |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="pre-pub-desc" class="col-sm-2 control-label">Pre Publication Description:</label>
<div class="col-sm-8">
<textarea name="pre-pub-desc" class="form-control" rows="4">{{ phenotype.pre_pub_description |default('', true) }}</textarea>
+ <input name="old_pre_pub_description" class="changed" type="hidden" value="{{ phenotype.pre_pub_description |default('', true) }}"/>
</div>
<!-- If the PubMed ID is entered, the Post Publication Description
will be shown to all users. If there is no PubMed ID, and the
@@ -39,18 +84,21 @@ Submit Trait | Reset
<label for="post-pub-desc" class="col-sm-2 control-label">Post Publication Description:</label>
<div class="col-sm-8">
<textarea name="post-pub-desc" class="form-control" rows="4">{{ phenotype.post_pub_description |default('', true) }}</textarea>
+ <input name="old_post_pub_description" class="changed" type="hidden" value="{{ phenotype.post_pub_description |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="orig-desc" class="col-sm-2 control-label">Original Description:</label>
<div class="col-sm-8">
<textarea name="orig-desc" class="form-control" rows="4">{{ phenotype.original_description |default('', true) }}</textarea>
+ <input name="old_original_description" class="changed" type="hidden" value="{{ phenotype.original_description |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="units" class="col-sm-2 control-label">Units:</label>
<div class="col-sm-8">
<textarea name="units" class="form-control" rows="1">{{ phenotype.units |default('', true) }}</textarea>
+ <input name="old_units" class="changed" type="hidden" value="{{ phenotype.units |default('', true) }}"/>
</div>
</div>
<div class="form-group">
@@ -59,6 +107,7 @@ Submit Trait | Reset
</label>
<div class="col-sm-8">
<textarea name="pre-pub-abbrev" class="form-control" rows="1">{{ phenotype.pre_pub_abbreviation |default('', true) }}</textarea>
+ <input name="old_pre_pub_abbreviation" class="changed" type="hidden" value="{{ phenotype.pre_pub_abbreviation |default('', true) }}"/>
</div>
</div>
<div class="form-group">
@@ -67,6 +116,7 @@ Submit Trait | Reset
</label>
<div class="col-sm-8">
<textarea name="post-pub-abbrev" class="form-control" rows="1">{{ phenotype.post_pub_abbreviation |default('', true) }}</textarea>
+ <input name="old_post_pub_abbreviation" class="changed" type="hidden" value="{{ phenotype.post_pub_abbreviation |default('', true) }}"/>
</div>
</div>
<div class="form-group">
@@ -75,6 +125,7 @@ Submit Trait | Reset
</label>
<div class="col-sm-8">
<textarea name="labcode" class="form-control" rows="1">{{ phenotype.lab_code |default('', true) }}</textarea>
+ <input name="old_lab_code" class="changed" type="hidden" value="{{ phenotype.lab_code |default('', true) }}"/>
</div>
</div>
<div class="form-group">
@@ -83,68 +134,79 @@ Submit Trait | Reset
</label>
<div class="col-sm-8">
<textarea name="submitter" class="form-control" rows="1">{{ phenotype.submitter |default('', true) }}</textarea>
+ <input name="old_submitter" class="changed" type="hidden" value="{{ phenotype.submitter |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="owner" class="col-sm-2 control-label">Owner:</label>
<div class="col-sm-8">
<textarea name="owner" class="form-control" rows="1">{{ phenotype.owner |default('', true) }}</textarea>
+ <input name="old_owner" class="changed" type="hidden" value="{{ phenotype.owner |default('', true) }}"/>
</div>
</div>
<div class="form-group">
- <label for="owner" class="col-sm-2 control-label">
+ <label for="authorized-users" class="col-sm-2 control-label">
Authorized Users:
</label>
<div class="col-sm-8">
- <textarea name="owner" class="form-control" rows="1">{{ phenotype.authorized_users |default('', true) }}</textarea>
+ <textarea name="authorized-users" class="form-control" rows="1">{{ phenotype.authorized_users |default('', true) }}</textarea>
+ <input name="old_authorized_users" class="changed" type="hidden" value="{{ phenotype.authorized_users |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="authors" class="col-sm-2 control-label">Authors:</label>
<div class="col-sm-8">
<textarea name="authors" class="form-control" rows="2">{{ publication.authors |default('', true) }}</textarea>
+ <input name="old_authors" class="changed" type="hidden" value="{{ publication.authors |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="title" class="col-sm-2 control-label">Title:</label>
<div class="col-sm-8">
<textarea name="title" class="form-control" rows="2">{{ publication.title |default('', true) }}</textarea>
+ <input name="old_title" class="changed" type="hidden" value="{{ publication.title |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="abstract" class="col-sm-2 control-label">Abstract:</label>
<div class="col-sm-8">
<textarea name="abstract" class="form-control" rows="6">{{ publication.abstract |default('', true) }}</textarea>
+ <input name="old_abstract" class="changed" type="hidden" value="{{ publication.abstract |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="journal" class="col-sm-2 control-label">Journal:</label>
<div class="col-sm-8">
<textarea name="journal" class="form-control" rows="1">{{ publication.journal |default('', true) }}</textarea>
+ <input name="old_journal" class="changed" type="hidden" value="{{ publication.journal_ |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="pages" class="col-sm-2 control-label">Pages:</label>
<div class="col-sm-8">
<textarea name="pages" class="form-control" rows="1">{{ publication.pages |default('', true) }}</textarea>
+ <input name="old_pages" class="changed" type="hidden" value="{{ publication.pages |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="month" class="col-sm-2 control-label">Month:</label>
<div class="col-sm-8">
<textarea name="month" class="form-control" rows="1">{{ publication.month |default('', true) }}</textarea>
+ <input name="old_month" class="changed" type="hidden" value="{{ publication.month |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="year" class="col-sm-2 control-label">Year:</label>
<div class="col-sm-8">
<textarea name="year" class="form-control" rows="1">{{ publication.year |default('', true) }}</textarea>
+ <input name="old_year" class="changed" type="hidden" value="{{ publication.year |default('', true) }}"/>
</div>
</div>
<div class="form-group">
<label for="sequence" class="col-sm-2 control-label">Sequence:</label>
<div class="col-sm-8">
<textarea name="sequence" class="form-control" rows="6">{{ publish_xref.sequence |default('', true) }}</textarea>
+ <input name="old_sequence" class="changed" type="hidden" value="{{ publication.sequence |default('', true) }}"/>
</div>
</div>
<div class="controls" style="display:block; margin-left: 40%; margin-right: 20%;">
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 2c5b6c6b..ebe5303a 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -1,33 +1,41 @@
"""Main routing table for GN2"""
-import traceback # for error page
-import os # for error gifs
-import random # for random error gif
-import datetime # for errors
-import sys
+import MySQLdb
+import array
+import base64
import csv
-import simplejson as json
-import xlsxwriter
+import difflib
+import datetime
+import flask
import io # Todo: Use cStringIO?
-import MySQLdb
-
-from zipfile import ZipFile, ZIP_DEFLATED
+import json
import numpy as np
+import os
import pickle as pickle
+import random
+import sqlalchemy
+import sys
+import traceback
import uuid
+import xlsxwriter
+
+from itertools import groupby
+from collections import namedtuple
+from zipfile import ZipFile
+from zipfile import ZIP_DEFLATED
-import flask
-import base64
-import array
-import sqlalchemy
from wqflask import app
+from gn3.db import diff_from_dict
+from gn3.db import fetchall
from gn3.db import fetchone
+from gn3.db import insert
from gn3.db import update
+from gn3.db.metadata_audit import MetadataAudit
from gn3.db.phenotypes import Phenotype
-from gn3.db.phenotypes import PublishXRef
from gn3.db.phenotypes import Publication
+from gn3.db.phenotypes import PublishXRef
from flask import current_app
@@ -446,12 +454,41 @@ def edit_trait(name, inbred_set_id):
conn=conn,
table="Publication",
where=Publication(id_=publish_xref.publication_id))
+ json_data = fetchall(
+ conn,
+ "metadata_audit",
+ where=MetadataAudit(dataset_id=publish_xref.id_))
+
+ Edit = namedtuple("Edit", ["field", "old", "new", "diff"])
+ Diff = namedtuple("Diff", ["author", "diff", "timestamp"])
+ diff_data = []
+ for data in json_data:
+ json_ = json.loads(data.json_data)
+ timestamp = json_.get("timestamp")
+ author = json_.get("author")
+ for key, value in json_.items():
+ if isinstance(value, dict):
+ for field, data_ in value.items():
+ diff_data.append(
+ Diff(author=author,
+ diff=Edit(field,
+ data_.get("old"),
+ data_.get("new"),
+ "\n".join(difflib.ndiff(
+ [data_.get("old")],
+ [data_.get("new")]))),
+ timestamp=timestamp))
+ diff_data_ = None
+ if len(diff_data) > 0:
+ diff_data_ = groupby(diff_data, lambda x: x.timestamp)
return render_template(
"edit_trait.html",
+ diff=diff_data_,
publish_xref=publish_xref,
phenotype=phenotype_,
publication=publication_,
- version=GN_VERSION)
+ version=GN_VERSION,
+ )
@app.route("/trait/update", methods=["POST"])
@@ -460,51 +497,59 @@ def update_trait():
user=current_app.config.get("DB_USER"),
passwd=current_app.config.get("DB_PASS"),
host=current_app.config.get("DB_HOST"))
- # Filter out empty values
- data_ = {k: v for k, v in request.form.items() if v is not ''}
-
+ data_ = request.form.to_dict()
# Run updates:
+ phenotype_ = {
+ "pre_pub_description": data_.get("pre-pub-desc"),
+ "post_pub_description": data_.get("post-pub-desc"),
+ "original_description": data_.get("orig-desc"),
+ "units": data_.get("units"),
+ "pre_pub_abbreviation": data_.get("pre-pub-abbrev"),
+ "post_pub_abbreviation": data_.get("post-pub-abbrev"),
+ "lab_code": data_.get("labcode"),
+ "submitter": data_.get("submitter"),
+ "owner": data_.get("owner"),
+ "authorized_users": data_.get("authorized-users"),
+ }
updated_phenotypes = update(
conn, "Phenotype",
- data=Phenotype(
- pre_pub_description=data_.get("pre-pub-desc"),
- post_pub_description=data_.get("post-pub-desc"),
- original_description=data_.get("orig-desc"),
- units=data_.get("units"),
- pre_pub_abbreviation=data_.get("pre-pub-abbrev"),
- post_pub_abbreviation=data_.get("post-pub-abbrev"),
- lab_code=data_.get("labcode"),
- submitter=data_.get("submitter"),
- owner=data_.get("owner"),
- ),
+ data=Phenotype(**phenotype_),
where=Phenotype(id_=data_.get("phenotype-id")))
+ diff_data = {}
+ if updated_phenotypes:
+ diff_data.update({"Phenotype": diff_from_dict(old={
+ k: data_.get(f"old_{k}") for k, v in phenotype_.items()
+ if v is not None}, new=phenotype_)})
+ publication_ = {
+ "abstract": data_.get("abstract"),
+ "authors": data_.get("authors"),
+ "title": data_.get("title"),
+ "journal": data_.get("journal"),
+ "volume": data_.get("volume"),
+ "pages": data_.get("pages"),
+ "month": data_.get("month"),
+ "year": data_.get("year")
+ }
updated_publications = update(
conn, "Publication",
- data=Publication(
- abstract=data_.get("abstract"),
- authors=data_.get("authors"),
- title=data_.get("title"),
- journal=data_.get("journal"),
- volume=data_.get("volume"),
- pages=data_.get("pages"),
- month=data_.get("month"),
- year=data_.get("year")),
- where=Publication(id_=data_.get("pubmed-id")))
- if updated_phenotypes or updated_publications:
- comments = data_.get("comments")
- if comments:
- comments = (f"{comments}\r\n"
- f"{g.user_session.record.get(b'user_name')}")
- update(conn, "PublishXRef",
- data=PublishXRef(
- comments=(f"{data_.get('comments')}\r\n"
- "Modified by: "
- f"{g.user_session.record.get(b'user_name').decode('utf-8')} "
- f"on {str(datetime.datetime.now())}"),
- publication_id=data_.get("pubmed-id")),
- where=PublishXRef(
- id_=data_.get("dataset-name"),
- inbred_set_id=data_.get("inbred-set-id")))
+ data=Publication(**publication_),
+ where=Publication(id_=data_.get("pubmed-id",
+ data_.get("old_id_"))))
+ if updated_publications:
+ diff_data.update({"Publication": diff_from_dict(old={
+ k: data_.get(f"old_{k}") for k, v in publication_.items()
+ if v is not None}, new=publication_)})
+ author = g.user_session.record.get(b'user_name')
+ if diff_data:
+ diff_data.update({"dataset_id": data_.get("dataset-name")})
+ diff_data.update({"author": author.decode('utf-8')})
+ diff_data.update({"timestamp": datetime.datetime.now().strftime(
+ "%Y-%m-%d %H:%M:%S")})
+ insert(conn,
+ table="metadata_audit",
+ data=MetadataAudit(dataset_id=data_.get("dataset-name"),
+ editor=author.decode("utf-8"),
+ json_data=json.dumps(diff_data)))
return redirect("/trait/10007/edit/1")