diff options
Diffstat (limited to 'gn2')
-rw-r--r-- | gn2/utility/tools.py | 7 | ||||
-rw-r--r-- | gn2/wqflask/templates/generif.html | 101 | ||||
-rw-r--r-- | gn2/wqflask/templates/gn_editor.html | 238 | ||||
-rw-r--r-- | gn2/wqflask/templates/gn_editor_commit.html | 55 | ||||
-rw-r--r-- | gn2/wqflask/templates/gn_editor_results_page.html | 46 | ||||
-rw-r--r-- | gn2/wqflask/templates/gn_editor_settings.html | 195 | ||||
-rw-r--r-- | gn2/wqflask/templates/wiki/edit_wiki.html | 93 | ||||
-rw-r--r-- | gn2/wqflask/templates/wiki/genewiki.html | 31 | ||||
-rw-r--r-- | gn2/wqflask/views.py | 109 |
9 files changed, 757 insertions, 118 deletions
diff --git a/gn2/utility/tools.py b/gn2/utility/tools.py index d8e21bcd..26ed3a77 100644 --- a/gn2/utility/tools.py +++ b/gn2/utility/tools.py @@ -46,14 +46,11 @@ def get_setting(command_id, guess=None): """ def value(command): if command: - # sys.stderr.write("Found "+command+"\n") app_set(command_id, command) return command - else: - return app.config.get(command_id) + return app.config.get(command_id) # ---- Check whether environment exists - # print("Looking for "+command_id+"\n") command = value(os.environ.get(command_id)) if command is None or command == "": # ---- Check whether setting exists in app @@ -61,10 +58,8 @@ def get_setting(command_id, guess=None): if command is None: command = value(guess) if command is None or command == "": - # print command raise Exception( command_id + ' setting unknown or faulty (update default_settings.py?).') - # print("Set "+command_id+"="+str(command)) return command diff --git a/gn2/wqflask/templates/generif.html b/gn2/wqflask/templates/generif.html deleted file mode 100644 index ac815b43..00000000 --- a/gn2/wqflask/templates/generif.html +++ /dev/null @@ -1,101 +0,0 @@ -{% extends "base.html" %} - -{% block title %} -GeneWiki Entry for {{ symbol }} -{% endblock %} - -{% block css %} -<style> - - .badge { - vertical-align: top; - background-color: #336699; - } - - .list-group { - counter-reset: gnentries; - } - - summary::before { - counter-increment: gnentries; - content: counter(gnentries) "." " "; - } - - summary:hover { - cursor: zoom-in; - } -</style> - -{% endblock %} -{% block content %} - - -<div class="container"> - <h1 class="page-header">GeneWiki For {{ symbol }}</h1> - <p class="well"><strong>GeneWiki</strong> enables you to enrich the annotation of genes and transcripts.</p> - - <h3> - <strong>GeneNetwork</strong> - <span class="badge"> - {{ entries.gn_entries|length if entries.gn_entries[0] else 0 }} - </span>: - </h3> - {% if entries.gn_entries[0] %} - <ul class="list-group"> - {% for entry in entries.gn_entries %} - <li class="list-group-item"> - <details> - <summary> - {{ entry["entry"]["value"] }} - {% if entry.get("weburl") %} - <sup><small><a href="{{ entry.weburl.value }}" target="_blank"><span class="glyphicon glyphicon-globe" aria-hidden="true"></span> web</a></small></sup> - {% endif %} - </summary> - <dl class="dl-horizontal"> - <dt>Author:</dt> - <dd>{{ entry["author"]["value"] }}</dd> - - {% if entry.get("geneCategory") %} - <dt>Category:</dt> - <dd>{{ entry["geneCategory"]["value"]}}</dd> - {% endif %} - - <dt>Add Time:</dt> - <dd>{{ entry["created"]["value"]}}</dd> - </dl> - </details> - </li> - {% endfor %} - </ul> - - {% else %} - - <p class="well"><u>There are no GeneNetwork entries for <b>{{ symbol }}.</b></u></p> - - {% endif %} - - <h3> - <strong>GeneRIF from NCBI</strong> - <span class="badge"> - {{ entries.ncbi_entries|length if entries.ncbi_entries[0] else 0 }} - </span>: - </h3> - {% if entries.ncbi_entries[0] %} - <ol> - {% for entry in entries.ncbi_entries %} - <li> - {{ entry.entry.value }} - (<a href="{{ entry['generif']['value'] }}" target="_blank">{{ entry["speciesBinomialName"]["value"] }}</a>) - {% if entry.PubMedId.value != "" %} - {% set pmids = entry.PubMedId.value.split(",") %} - (PubMed: {% for id in pmids %} <a href="http://rdf.ncbi.nlm.nih.gov/pubmed/{{ id }}" target="_blank">{{ id }}</a>{% endfor %}) - <sup><small><em>{{ entry.createdOn.value }}</em></small></sup> - {% endif %} - </li> - {% endfor %} - </ol> - {% else %} - <p class="well"><u>There are no NCBI entries for <b>{{ symbol }}.</b></u></p> - {% endif %} -</div> -{% endblock %} diff --git a/gn2/wqflask/templates/gn_editor.html b/gn2/wqflask/templates/gn_editor.html new file mode 100644 index 00000000..e5c649d1 --- /dev/null +++ b/gn2/wqflask/templates/gn_editor.html @@ -0,0 +1,238 @@ +{% extends "base.html" %} +{% block title %}Genenetwork Files Editor{% endblock %} +{% block css %} + <style> + #diffBtn { + cursor:pointer + } + </style> + <link rel="stylesheet" + type="text/css" + href="{{ url_for('css', filename='diff2html/diff2html.min.css') }}" /> + <link rel="stylesheet" + type="text/css" + href="{{ url_for('css', filename='highlight/default.min.css') }}" /> +{% endblock %} +{% block search %}{% endblock %} +{% block content %} + <section class="container-fluid"> + <header class="row"> + <nav class="navbar" style="background-color:#ccc"> + <div class="container-fluid"> + <div class="navbar-header"> + <a class="navbar-brand" href="#"><strong>GN Editor</strong></a> + </div> + <div style="padding-right:3.6rem"> + <ul class="nav navbar-nav navbar-right"> + <li> + <a href="#" + hx-get="/editor/commit" + hx-target="#output" + hx-trigger="click" + hx-swap="innerHTML">Commit</a> + </li> + <li> + <a hx-trigger="click" id="diffBtn" hx-swap="innerHTML">Diff</a> + </li> + <li> + <a href="#" + hx-get="/editor/settings" + hx-target="#output" + hx-trigger="click" + hx-swap="innerHTML">Settings</a> + </li> + </ul> + </div> + </div> + </nav> + </header> + <div> + <div class="row" id="gn-editor"> + <section class="col-sm-6" id="editor" style="height:100vh"> + <textarea name="ckcontent" id="ckcontent" style='display:none'> + </textarea> + </section> + <section class="col-sm-6"> + <div class="row"> + <section class="col-sm-10 col-sm-offset-1" + id="output" + style="height:100vh; + overflow-y:scroll; + padding-top:2.5rem" + id="swap"> + </section> + </div> + </section> + </div> + </div> + </section> +{% endblock %} +{% block js %} + <script src="{{ url_for('js', filename='jquery/jquery.min.js') }}" + type="text/javascript"></script> + <script language="javascript" + type="text/javascript" + src="{{ url_for('js', filename='diff2html/diff2html.min.js') }}"></script> + <script language="javascript" + type="text/javascript" + src="{{ url_for('js', filename='jquery-ui/jquery-ui.min.js') }}"></script> + <script language="javascript" + type="text/javascript" + src="{{ url_for('js', filename='htmx.min.js') }}"></script> + <script language="javascript" + type="text/javascript" + src="{{ url_for('js', filename='jsdiff/diff.min.js') }}"></script> + <script language="javascript" + type="text/javascript" + src="{{ url_for('js', filename='ace/ace.js') }}"></script> + <script language="javascript" + type="text/javascript" + src="{{ url_for('js', filename='marked/marked.min.js') }}"></script> + <script language="javascript" + type="text/javascript" + src="{{ url_for('js', filename='marked/marked-highlight.js') }}"></script> + <script language="javascript" + type="text/javascript" + src="{{ url_for('js', filename='highlight/highlight.min.js') }}"></script> + <script language="javascript" + type="text/javascript" + src="{{ url_for('js', filename='ckeditor/ckeditor.js') }}"></script> + <script type="text/javascript"> + document.addEventListener('DOMContentLoaded', function() { + $('footer').hide() + var editor_configurations = { + selectionStyle: 'line',// "line"|"text" + highlightActiveLine: true, // boolean + highlightSelectedWord: true, // boolean + readOnly: false, // boolean: true if read only + cursorStyle: 'ace', // "ace"|"slim"|"smooth"|"wide" + mergeUndoDeltas: true, // false|true|"always" + behavioursEnabled: true, // boolean: true if enable custom behaviours + wrapBehavioursEnabled: true, // boolean + autoScrollEditorIntoView: undefined, // boolean: this is needed if editor is inside scrollable + keyboardHandler: null, + + // renderer options + animatedScroll: false, // boolean: true if scroll should be animated + displayIndentGuides: false, // boolean: true if the indent should be shown. See 'showInvisibles' + showInvisibles: false, // boolean -> displayIndentGuides: true if show the invisible tabs/spaces in indents + showPrintMargin: true, // boolean: true if show the vertical print margin + printMarginColumn: 80, // number: number of columns for vertical print margin + printMargin: undefined, // boolean | number: showPrintMargin | printMarginColumn + showGutter: true, // boolean: true if show line gutter + fadeFoldWidgets: false, // boolean: true if the fold lines should be faded + showFoldWidgets: true, // boolean: true if the fold lines should be shown ? + showLineNumbers: true, + highlightGutterLine: false, // boolean: true if the gutter line should be highlighted + hScrollBarAlwaysVisible: false, // boolean: true if the horizontal scroll bar should be shown regardless + vScrollBarAlwaysVisible: false, // boolean: true if the vertical scroll bar should be shown regardless + fontSize: 16, // number | string: set the font size to this many pixels + fontFamily: undefined, // string: set the font-family css value + maxLines: undefined, // number: set the maximum lines possible. This will make the editor height changes + minLines: undefined, // number: set the minimum lines possible. This will make the editor height changes + maxPixelHeight: 0, // number -> maxLines: set the maximum height in pixel, when 'maxLines' is defined. + scrollPastEnd: 0, // number -> !maxLines: if positive, user can scroll pass the last line and go n * editorHeight more distance + fixedWidthGutter: false, // boolean: true if the gutter should be fixed width + theme: "ace/theme/textmate", // theme string from ace/theme or custom? + scrollSpeed: 2, // number: the scroll speed index + dragDelay: 0, + dragEnabled: true, // boolean: enable dragging + focusTimout: 0, // number: the focus delay before focus starts. + tooltipFollowsMouse: true, // boolean: true if the gutter tooltip should follow mouse + // session options + firstLineNumber: 1, // number: the line number in first line + overwrite: false, // boolean + newLineMode: 'auto', // "auto" | "unix" | "windows" + useWorker: true, // boolean: true if use web worker for loading scripts + useSoftTabs: true, // boolean: true if we want to use spaces than tabs + tabSize: 4, // number + wrap: true, // boolean | string | number: true/'free' means wrap instead of horizontal scroll, false/'off' means horizontal scroll instead of wrap, and number means number of column before wrap. -1 means wrap at print margin + indentedSoftWrap: true, // boolean + foldStyle: 'markbegin', // enum: 'manual'/'markbegin'/'markbeginend'. + mode: 'ace/mode/markdown' + + } + let hash = {{ hash|tojson }} + let filePath = {{ file_path|tojson }} + let fileExt = (filePath.substring(filePath.lastIndexOf('.')+1, filePath.length) || "md").toLowerCase(); + let data = {{ content|tojson }} + + localStorage.setItem("gn_editor_sha" ,hash) + htmx.on("#output", "commitEvent", function(event){ + htmx.ajax("POST", "/editor/commit", {target: "#output", swap:"innerHTML",values: {'msg':event.detail.payload, 'content': editor.getValue(), "hash": localStorage.getItem("gn_editor_sha"), "file_path": filePath}}) + }) + + htmx.on("#output", "diffEvent", function(event){ + var fileName = "{{ file_path }}" + var diffContent = Diff.createTwoFilesPatch(fileName,fileName, data, editor.getValue()) + var diffHtml = Diff2Html.html(diffContent, { + drawFileList: true, + matching: 'lines', + outputFormat: 'line-by-line', + }); + htmx.find("#output").innerHTML = diffHtml + }) + + htmx.on("#output", "updateEditor", function(event){ + if (fileExt != 'rtf'){ + editor.setOptions({ + ...editor_configurations, + ...event.detail.payload + }) + editor.renderer.updateFull(); + } + + }) + + htmx.on("#diffBtn","click",function(event){ + //dispatch your event here + console.log("Clicked diff btn here") + htmx.find("#output").dispatchEvent( + new CustomEvent("diffEvent", { + bubbles: true, + detail: {}, + }), + ); + }) + function updatePreview(){ + const {markedHighlight} = globalThis.markedHighlight; + + let new_marked = new marked.Marked( + markedHighlight({ + langPrefix: 'hljs language-', + highlight(code, lang) { + const language = hljs.getLanguage(lang) ? lang : 'plaintext'; + return hljs.highlight(code, { language }).value; + }})); + new_marked.use({ + pedantic: false, + gfm: true, + }); + previewContent = document.querySelector("#output"); + var markdownContent = editor.getValue(); + var htmlContent = new_marked.parse(markdownContent) //work on error handling for invalid markdown + previewContent.innerHTML = htmlContent; + } + + if (fileExt == "rtf"){ + var editor = CKEDITOR.replace('ckcontent', { + height: '100vh', + }); + editor.setData(data) + editor.getValue = editor.getData + } + else { + var editor = ace.edit("editor"); + editor.setOptions(editor_configurations); + editor.container.style.resize = "horizontal"; + editor.getSession().on("change", function(e){ + updatePreview() + }) + editor.setValue(data, -1); + } + + }); + + + </script> +{% endblock %} diff --git a/gn2/wqflask/templates/gn_editor_commit.html b/gn2/wqflask/templates/gn_editor_commit.html new file mode 100644 index 00000000..84ebd818 --- /dev/null +++ b/gn2/wqflask/templates/gn_editor_commit.html @@ -0,0 +1,55 @@ +<section classs="row commit-content" style="padding-top:25px"> + <div class="col-sm-10 col-sm-offset-1"> + <div> + <div> + <h2> + <i>Commit your Changes</i> + </h2> + </div> + </div> + <br> + <div> + <div class="row"> + <label class="col-sm-8" for="message"> + <i>*Commit Message*</i> + </label> + </div> + <br> + <div class="row"> + <textarea style="white-space: normal" rows="12" class="col-sm-12" name="message" required id="commit-message"> + </textarea> + </div> + </div> + <br> + <br> + <div class="row"> + <button id="btn-commit" class="btn btn-primary col-lg-3 col-lg-offset-1 col-sm-4 col-sm-offset-1">Commit</button> + <button id="btn-diff" class="btn col-lg-3 col-lg-offset-1 col-sm-4 col-sm-offset-1">Show Diff</button> + </div> + <br> + <div id="diff_page"></div> + </div> +</section> +{% block js %} + <script> + htmx.on("#btn-commit", "click", function(event){ + let msg = htmx.find("#commit-message").value.trim() + if (msg != ""){ + htmx.find("#output").dispatchEvent( + new CustomEvent("commitEvent", { + bubbles: true, + detail: {action: 'didInitialize', payload: msg}, + }), + ); + } + }) + htmx.on("#btn-diff", "click", function(event){ + htmx.find("#output").dispatchEvent( + new CustomEvent("diffEvent", { + bubbles: true, + detail: {}, + }), + ); + }) + </script> +{% endblock %} diff --git a/gn2/wqflask/templates/gn_editor_results_page.html b/gn2/wqflask/templates/gn_editor_results_page.html new file mode 100644 index 00000000..666bd432 --- /dev/null +++ b/gn2/wqflask/templates/gn_editor_results_page.html @@ -0,0 +1,46 @@ +<section classs="row commit-content" style="padding-top:25px"> + <div class="col-sm-10 col-sm-offset-1"> + <div> + <div> + <h2> + <i>Results status - {{ status }}</i> + </h2> + </div> + </div> + <br> + {% if error %} + <h1> + Error-type: <mark style="font-family: 'Linux Libertine','Georgia','Times','Source Serif Pro',serif"><b><i>{{ error }}</i></b></mark> + </h1> + <h3> + Error-message: + <mark style="font-family: 'Linux Libertine','Georgia','Times','Source Serif Pro',serif"><b><i>{{ msg }}</i></b></mark> + </h3> + {% else %} + <div> + <h3> + New Commit Sha: <span class="lead"> + <mark style="font-family: 'Linux Libertine','Georgia','Times','Source Serif Pro',serif"><b><i>{{ commit_sha }}</i></b></mark> + </span> + </h3> + <br /> + <div class="lead"> + <h3> + Commit Message: + <mark style="font-family: 'Linux Libertine','Georgia','Times','Source Serif Pro',serif"><b><i>{{ message }}</i></b></mark> + </h3> + </div> + </div> + {% endif %} + <br> +</div> +</section> +{% block js %} + <script> + var commitSha = "{{ commit_sha }}"; + if (commitSha !="" && commitSha!= undefined){ + localStorage.setItem("gn_editor_sha", commitSha) + } + + </script> +{% endblock %} diff --git a/gn2/wqflask/templates/gn_editor_settings.html b/gn2/wqflask/templates/gn_editor_settings.html new file mode 100644 index 00000000..1e2cae10 --- /dev/null +++ b/gn2/wqflask/templates/gn_editor_settings.html @@ -0,0 +1,195 @@ +<section> + <h4> + <i>Select a theme</i> + </h4> + <form> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="theme" + id="twilightTheme" + value="twilight" + checked> + <label class="form-check-label" for="twilight">twilight</label> + </div> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="theme" + id="draculaTheme" + value="dracula"> + <label class="form-check-label" for="draculaTheme">dracula</label> + </div> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="theme" + id="normalTheme" + value="textmate" + checked> + <label class="form-check-label" for="normalTheme">Text</label> + </div> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="theme" + id="monokaiTheme" + value="monokai"> + <label class="form-check-label" for="monokaiTheme">Monokai</label> + </div> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="theme" + id="customTheme" + value="xcode"> + <label class="form-check-label" for="customTheme">xcode</label> + </div> + <br> + <div class="form-group" style="padding-top:10px"> + <h4> + <i>Select Font Size</i> + </h4> + <input type="range" + class="form-control-range" + id="fontSizeRange" + name="fontSizeRange" + min="10" + max="36" + step="1" + value="16"> + <em><span id="fontSizeValue">16</span> px</em> + </div> + <br> + <div> + <h4> + <i>Select Wrap Option:</i> + </h4> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="wrap" + id="normalTheme" + value="true" + checked> + <label class="form-check-label" for="normalTheme">True</label> + </div> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="wrap" + id="monokaiTheme" + value="false"> + <label class="form-check-label" for="monokaiTheme">False</label> + </div> + </div> + <div> + <h4> + <i>Cursor Styles:</i> + </h4> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="cursor" + id="aceCursor" + value="ace" + checked> + <label class="form-check-label" for="aceCursor">ace</label> + </div> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="cursor" + id="slimCursor" + value="slim"> + <label class="form-check-label" for="slimCursor">slim</label> + </div> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="cursor" + id="smoothCursor" + value="smooth"> + <label class="form-check-label" for="smoothCursor">smooth</label> + </div> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="cursor" + id="wideCursor" + value="wide"> + <label class="form-check-label" for="wideCursor">wide</label> + </div> + </div> + </form> + <br> + <h4> + <i>Choose KeyBoard Binding:</i> + </h4> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="keyboard" + id="default" + value="default" + checked> + <label class="form-check-label" for="default">Default</label> + </div> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="keyboard" + id="vscode" + value="vscode"> + <label class="form-check-label" for="vscode">Vscode</label> + </div> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="keyboard" + id="emacs" + value="emacs"> + <label class="form-check-label" for="emacs">Emacs</label> + </div> + <div class="form-check"> + <input class="form-check-input" + type="radio" + name="keyboard" + id="vim" + value="vim"> + <label class="form-check-label" for="vim">Vim</label> + </div> + <br> + <div class="row"> + <div class="col-sm-offset-1"> + <button class="btn btn-primary" id="settingBtn">Save Settings</button> + </div> + </div> +</section> +{% block js %} + <script> + $('#fontSizeRange').on('input', function () { + var fontSize = $(this).val(); + $('#fontSizeValue').text(fontSize); + }); + + htmx.on("#settingBtn", "click", function () { + var formData = { + theme: `ace/theme/${$('input[name="theme"]:checked').val()}`, + fontSize: parseInt($("#fontSizeRange").val()), + wrap:$('input[name="wrap"]:checked').val()== "false" ? false : true, + cursorStyle: $('input[name="cursor"]:checked').val(), + keyboardHandler:($('input[name="keyboard"]:checked').val() == "default"? + null: `ace/keyboard/${$('input[name="keyboard"]:checked').val()}` + ) + + } + htmx.find("#output").dispatchEvent( + new CustomEvent("updateEditor", { + bubbles: true, + detail: {action: 'didInitialize', payload: formData}, + }), + ); + }) + </script> +{% endblock %} diff --git a/gn2/wqflask/templates/wiki/edit_wiki.html b/gn2/wqflask/templates/wiki/edit_wiki.html new file mode 100644 index 00000000..242456c4 --- /dev/null +++ b/gn2/wqflask/templates/wiki/edit_wiki.html @@ -0,0 +1,93 @@ +{% extends "base.html" %} + +{% block css %} +<style> + .panel { + width: 90%; + margin: 2em; + } + .container { + align-content: center; + } +</style> +{% endblock %} + +{% block content %} + +{{ flash_me() }} +<section class="container center-block"> + <div class="row"> + <div class="col-md-3"></div> + <div class="col-md-9"> + <h2>Edit Wiki</h2> + <br> + <form class="form-horizontal" method="POST"> + <input type="hidden" name="symbol" value="{{ content["symbol"] }}"> + <div class="form-group"> + <label for="reason" class="col-sm-2">Reason for Modification: </label> + <input type="text" name="reason" size=45 maxlength=100 required> + </div> + <div class="form-group"> + <label for="species" class="col-sm-2">Species: </label> + <select name="species" id="species"> + {% for name, species_name in species_dict.items() %} + {% if name == content["species"] %} + <option selected="selected" value="{{ name }}">{{ species_name }}</option> + {% else %} + <option value="{{ name }}">{{ species_name }}</option> + {% endif %} + {% endfor %} + </select> + </div> + <div class="form-group"> + <label for="pubmed_ids" class="col-sm-2">PubMed IDS: </label> + <input type="text" name="pubmed_ids" size=25 maxlength=25 value="{{ " ".join(content["pubmed_ids"]) }}"> + (optional, separate by blank space only) + </div> + <div class="form-group"> + <label for="web_url" class="col-sm-2">Web resource URL: </label> + {% if content["weburl"] %} + <input type="text" name="web_url" value="{{ content["weburl"] }}" size=50 maxlength=255> + {% else %} + <input type="text" name="web_url" value="http://" size=50 maxlength=255> + {% endif %} + (optional) + </div> + <div class="form-group"> + <label for="comment" class="col-sm-2">Text: </label> + <textarea name="comment" rows=5 cols=60 required>{{ content["comment"] }}</textarea> + </div> + <div class="form-group"> + <label for="email" class="col-sm-2">Email: </label> + <input type="text" name="email" value="" required> + </div> + <div class="form-group"> + <label for="usercode" class="col-sm-2">User Code: </label> + <input type="text" name="initial" value="{{ content["initial"] }}"/> + (optional user or project code or your initials) + </div> + <div class="form-group"> + <label class="col-sm-2">Category of Gene<br>(Please select one or <br>many categories): </label> + <div class="col-sm-10"> + {% for group in grouped_categories %} + <div class="row"> + {% for cat in group %} + <label class="checkbox-inline col-sm-3"> + {% if cat in content["categories"] %} + <input checked type="checkbox" name="genecategory" value="{{ cat }}"> {{ cat }} + {% else %} + <input type="checkbox" name="genecategory" value="{{ cat }} "> {{ cat }} + {% endif %} + </label> + {% endfor %} + </div> + {% endfor %} + </div> + <div class="form-group"> + <button type="submit" name="submit" class="btn btn-primary">Update GeneWiki Entry</button> + <button type="reset" name="rest" class="btn btn-secondary" onClick="window.location.reload();">Reset</button> + </div> + </form> + </div> + </div> +{% endblock %} diff --git a/gn2/wqflask/templates/wiki/genewiki.html b/gn2/wqflask/templates/wiki/genewiki.html new file mode 100644 index 00000000..496f5e28 --- /dev/null +++ b/gn2/wqflask/templates/wiki/genewiki.html @@ -0,0 +1,31 @@ +{% extends "base.html" %} +{% block title %}GeneWiki Entry for {{ symbol }}{% endblock %} +{% block content %} + {{ flash_me() }} + <div class = "container"> + <h1 class = "page-header">GeneWiki Entries</h1> + <p> + GeneWiki enables you to enrich the annotation of genes and transcripts. Please submit or edit a GeneWiki note (500 characters max) related to a gene, its transcripts, or proteins. When possible include PubMed identifiers or web resource links (URL addresses). Please ensure that the additions will have widespread use. For additional information, check the GeneWiki <a href="https://gn1.genenetwork.org/GeneWikihelp.html" target="_blank">help document</a>. + </p> + <h3>GeneWiki For {{ symbol }}:</h3> + <h5> + <strong>GeneNetwork:</strong> + </h5> + {% if wiki %} + <ol> + {% for entry in wiki %} + <li> + {{ entry.get("comment") }} + {% if entry.get("web_url") %} + <sup> <small> <a href = "{{ entry.web_url }}" target = "_blank"> <span class = "glyphicon glyphicon-globe" aria-hidden = "true"></span>web</a></small></sup> + {% endif %} + </li> + {% endfor %} + </ol> + {% else %} + <p class = "well"> + <u> There are no GeneNetwork entries for <b> {{ symbol }}.</b></u> + </p> + {% endif %} + </div> +{% endblock %} diff --git a/gn2/wqflask/views.py b/gn2/wqflask/views.py index 993c6f0c..4421011b 100644 --- a/gn2/wqflask/views.py +++ b/gn2/wqflask/views.py @@ -1,4 +1,5 @@ """Main routing table for GN2""" + import array import base64 import csv @@ -44,6 +45,7 @@ from flask import flash from gn2.wqflask import search_results from gn2.wqflask import server_side + # Used by YAML in marker_regression from gn2.base.data_set import create_dataset from gn2.base.trait import fetch_symbols @@ -288,6 +290,38 @@ def gnqna(): return render_template("gnqa.html") +@app.route("/editor/edit", methods=["GET"]) +@require_oauth2 +def edit_gn_doc_file(): + file_path = request.args.get("file-path", "") + response = requests.get(f"http://localhost:8091/edit?file_path={file_path}") + response.raise_for_status() + return render_template("gn_editor.html", **response.json()) + + +@app.route("/editor/settings", methods=["GET"]) +@require_oauth2 +def configure_gn_editor(): + return render_template("gn_editor_settings.html") + + +@app.route("/editor/commit", methods=["GET", "POST"]) +@require_oauth2 +def commit_gn_doc(): + # TODO add env variable for gn-guile web server + if request.method == "GET": + return render_template("gn_editor_commit.html") + results = requests.post("http://localhost:8091/commit", json={ + "content": request.form.get("content"), + "filename": request.form.get("file_path"), + "username": session_info()["user"]["name"], + "email": session_info()["user"]["email"], + "commit_message": request.form.get("msg"), + "prev_commit": request.form.get("hash")}) + data = results.json() + data["filename"] = request.form.get("file_path") + return render_template("gn_editor_results_page.html", **data) + @app.route("/gnqna/hist", methods=["GET", "DELETE"]) @require_oauth2 @@ -1039,7 +1073,8 @@ def corr_compute_page(): with Redis.from_url(REDIS_URL, decode_responses=True) as rconn: if request.method == "POST": request_received = datetime.datetime.utcnow() - filename = hmac.hmac_creation(f"request_form_{request_received.isoformat()}") + filename = hmac.hmac_creation( + f"request_form_{request_received.isoformat()}") filepath = f"{TMPDIR}{filename}" with open(filepath, "wb") as pfile: pickle.dump(request.form, pfile, @@ -1201,19 +1236,25 @@ def display_diffs_users(): files=files) -@app.route("/genewiki/<symbol>") -def display_generif_page(symbol): +@app.route("/genewiki/<string:symbol>") +def display_genewiki_page(symbol: str): """Fetch GeneRIF metadata from GN3 and display it""" - entries = requests.get( - urljoin( - GN3_LOCAL_URL, - f"/api/metadata/genewiki/{symbol}" + wiki = {} + try: + wiki = requests.get( + urljoin( + GN3_LOCAL_URL, + f"/api/metadata/wiki/{symbol}" + ) ) - ).json() + wiki.raise_for_status() + wiki = wiki.json() + except requests.RequestException as excp: + flash(excp, "alert-warning") return render_template( - "generif.html", + "wiki/genewiki.html", symbol=symbol, - entries=entries + wiki=wiki ) @@ -1346,7 +1387,8 @@ def edit_case_attributes(inbredset_id: int) -> Response: def flash_success(resp): def __succ__(remote_resp): - flash(f"Success: {remote_resp.json()['message']}", "alert-success") + flash( + f"Success: {remote_resp.json()['message']}", "alert-success") return resp return __succ__ return monad_requests.post( @@ -1472,3 +1514,48 @@ def approve_reject_diff() -> Response: return redirect(url_for("view_diff", inbredset_id=inbredset_id, diff_id=form["diff_id"])) + + +@app.route("/metadata/wiki/<int:comment_id>/edit", methods=["GET", "POST"]) +def edit_wiki(comment_id: int): + """fetch generif metadata from gn3 and display it""" + # FIXME: better error handling + if request.method == "GET": + last_wiki_resp = requests.get(urljoin(GN3_LOCAL_URL, f"/api/metadata/wiki/{comment_id}")) + last_wiki_resp.raise_for_status() + last_wiki_content = last_wiki_resp.json() + + species_dict_resp = requests.get(urljoin(GN3_LOCAL_URL, "/api/metadata/wiki/species")) + species_dict_resp.raise_for_status() + species_dict = species_dict_resp.json() + + categories_resp = requests.get(urljoin(GN3_LOCAL_URL, "/api/metadata/wiki/categories")) + categories_resp.raise_for_status() + categories = list(categories_resp.json().keys()) + grouped_categories = [categories[i : i + 3] for i in range(0, len(categories), 3)] + + return render_template( + "wiki/edit_wiki.html", + content=last_wiki_content, + species_dict=species_dict, + grouped_categories=grouped_categories, + ) + if request.method == "POST": + post_data = request.form + payload = { + "symbol": post_data["symbol"], + "pubmed_ids": [x.strip() for x in post_data["pubmed_ids"].split()], + "species": post_data["species"], + "comment": post_data["comment"], + "email": post_data["email"], + "web_url": post_data["web_url"], + "initial": post_data["initial"], + "categories": post_data.getlist("genecategory"), + "reason": post_data["reason"], + } + post_response = requests.post(urljoin(GN3_LOCAL_URL, f"api/metadata/wiki/{comment_id}/edit"), json=payload) + post_response.raise_for_status() + post_res = post_response.json() + + flash(f"Success: {post_res}", "alert-success") + return redirect(url_for("edit_wiki", comment_id=comment_id)) |