diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1756242fc2512b415845ea5b4bf37e878569467a..812cfe615eee8823129b9a9251414ce578c3e2e3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,6 +9,7 @@ test-centos7: - yum install install -y python34-pip python34-devel - yum install -y gcc graphviz graphviz-devel - yum install -y httpd httpd-devel + - yum install -y gcc-c++ - cd ippisite - pip3 install -r requirements.txt - python3 manage.py test diff --git a/ippisite/db.sqlite3.REMOVED.git-id b/ippisite/db.sqlite3.REMOVED.git-id index 2c160ba5e8a42d7ed1f83cb3609b5134cd87a0be..1e8b356813e3c25ccb49abc3c792bf6064131654 100644 --- a/ippisite/db.sqlite3.REMOVED.git-id +++ b/ippisite/db.sqlite3.REMOVED.git-id @@ -1 +1 @@ -9a436afcb3cc2a25d2cb6b1f8cc0665b3f466d06 \ No newline at end of file +1068c5d524bfec4a3fbb0bbd2a3b88063451db93 \ No newline at end of file diff --git a/ippisite/ippidb/models.py b/ippisite/ippidb/models.py index 4daa47324126d647e9d2abc93a7b2d5b033e9f74..232e595e92ef3807ff99b21fa2cabed997f7de95 100644 --- a/ippisite/ippidb/models.py +++ b/ippisite/ippidb/models.py @@ -112,6 +112,7 @@ class Protein(AutoFillableModel): self.recommended_name_long = info['recommended_name'] self.gene_name = info['gene'] self.entry_name = info['entry_name'] + self.short_name = info['short_name'] try: taxonomy = Taxonomy.objects.get(taxonomy_id=info['organism']) except Taxonomy.DoesNotExist: @@ -219,6 +220,17 @@ class Ppi(models.Model): # this is the less efficient query ever seen, FIXME return PpiComplex.objects.filter(ppi=self, complex__in=ProteinDomainBoundComplex.objects.all()) + @property + def name(self): + all_protein_names = set([ppi_complex.complex.protein.short_name for ppi_complex in self.get_ppi_complexes()]) + bound_protein_names = set([ppi_complex.complex.protein.short_name for ppi_complex in self.get_ppi_bound_complexes()]) + partner_protein_names = all_protein_names - bound_protein_names + bound_str = ','.join(bound_protein_names) + partner_str = ','.join(partner_protein_names) + name = bound_str + if partner_str!='': + name += ' / ' + partner_str + return name class PpiComplex(models.Model): ppi = models.ForeignKey(Ppi) @@ -308,6 +320,12 @@ class Compound(models.Model): mddr_compound = models.ForeignKey( 'MDDRCompoundImport', blank=True, null=True) + @property + def biblio_refs(self): + """ + return all RefCompoundBiblio related to this complex + """ + return RefCompoundBiblio.objects.filter(compound=self) class MDDRActivityClass(models.Model): name = models.CharField('Activity Class', max_length=100, unique=True) diff --git a/ippisite/ippidb/templates/biblio_card.html b/ippisite/ippidb/templates/biblio_card.html index df853adc33a9eb2f82a65a30f0bc1c789b7087df..8977f704bff3cf08743e25036dce32a1d19f70b4 100644 --- a/ippisite/ippidb/templates/biblio_card.html +++ b/ippisite/ippidb/templates/biblio_card.html @@ -9,6 +9,10 @@ function display(smiles_id, viewer_id) { var smi = document.getElementById(smiles_id).value; var chemViewer = new Kekule.ChemWidget.Viewer(document.getElementById(viewer_id)); + chemViewer.setEnableToolbar(false) + .setEnableDirectInteraction(false) + .setEnableEdit(false) + .setToolButtons([]); var mol = Kekule.IO.loadFormatData(smi, "smi"); chemViewer.setChemObj(mol); console.log(smi); @@ -57,7 +61,7 @@ <div class="card"> <div class="card-body"> <div id="{{ compound_biblio.id }}_smilesdisplay" - data-widget="Kekule.ChemWidget.Viewer2D" data-enable-toolbar="true" data-auto-size="true" data-padding="20" + data-widget="Kekule.ChemWidget.Viewer2D" data-auto-size="true" data-padding="20" data-toolbar-evoke-modes="[0]"> </div> <textarea rows="10" cols="50" id="{{ compound_biblio.id }}_smilesvalue" style="display:none;">{{ compound_biblio.compound.canonical_smile }}</textarea> diff --git a/ippisite/ippidb/templates/biblio_citation.html b/ippisite/ippidb/templates/biblio_citation.html new file mode 100644 index 0000000000000000000000000000000000000000..a7cc6b8f961c94568fa7c306be44128621024620 --- /dev/null +++ b/ippisite/ippidb/templates/biblio_citation.html @@ -0,0 +1 @@ +<a target="_blank" class="card-link" href="https://www.ncbi.nlm.nih.gov/pubmed/{{ bibliography.id_source }}">{{ bibliography.authors_list }}. {{ authors.biblio_year }}. {{ bibliography.title }} {{ bibliography.journal_name }}. </a> diff --git a/ippisite/ippidb/templates/biblio_list.html b/ippisite/ippidb/templates/biblio_list.html index 833a9cd98a81e63ec408876ace54020f13ba459b..2981c29f482e1f164eb79a7493e746cbed43dad1 100644 --- a/ippisite/ippidb/templates/biblio_list.html +++ b/ippisite/ippidb/templates/biblio_list.html @@ -12,11 +12,20 @@ <div id="content" class="main-content"> <main role="main"> {% if bibliographies %} - <ul> +<table class="table"> + <thead class="thead-light"> + <tr> + <th scope="col">Title</th> + </tr> + </thead> + <tbody> {% for biblio in bibliographies %} - <li><a href="/biblio/{{ biblio.source }}{{ biblio.id_source}}">{{ biblio.title }}</a></li> + <tr> + <td><a href="/biblio/{{ biblio.source }}{{ biblio.id_source}}">{{ biblio.title }}</a></td> + </tr> {% endfor %} - </ul> + </tbody> +</table> {% else %} <p>No bibliographies available.</p> {% endif %} diff --git a/ippisite/ippidb/templates/compound_abstract.html b/ippisite/ippidb/templates/compound_abstract.html new file mode 100644 index 0000000000000000000000000000000000000000..a8094c2741faac61dc5108baf4e510c57c1eb6fb --- /dev/null +++ b/ippisite/ippidb/templates/compound_abstract.html @@ -0,0 +1,47 @@ +<div class="row m-2 border border-info bg-light"> + <div class="col-sm-3 bg-info"> + <div id="{{ compound.id }}_smilesdisplay" + data-widget="Kekule.ChemWidget.Viewer2D" data-auto-fit="true" + data-toolbar-evoke-modes="[0]" style="width: 200px; height: 200px;"> + </div> + <textarea rows="10" cols="50" id="{{ compound.id }}_smilesvalue" style="display:none;">{{ compound.canonical_smile }}</textarea> + <script> + $(window).on('load', function(){ + kekule_display('{{ compound.id }}_smilesvalue','{{ compound.id }}_smilesdisplay') + }); + </script> + </div> + <div class="col-sm-9"> + <ul class="list-group"> + {% if compound.common_name %} + <li class="list-group-item">Common name: {{ compound.common_name }}</li> + {% endif %} + {% if compound.canonical_smile %} + <li class="list-group-item">Canonical SMILES: {{ compound.canonical_smile }}</li> + {% endif %} + {% if compound.iupac_name %} + <li class="list-group-item">IUPAC name: {{ compound.iupac_name }}</li> + {% endif %} + </ul> + <p>in bibliography</p> + <ul class="list-group"> + {% for biblio_ref in compound.biblio_refs %} + <li class="list-group-item">Mentionned in {% include "biblio_citation.html" with bibliography=biblio_ref.bibliography%} as <i>{{ biblio_ref.compound_name }}</i></li> + {% endfor %} + </ul> + {%if compound.pubchem_id or compound.chembl_id or compound.chemspider_id %} + <p>in other databases</p> + <ul class="list-group"> + {% if compound.pubchem_id %} + <li class="list-group-item">PubChem: <a href="https://pubchem.ncbi.nlm.nih.gov/compound/{{ compound.pubchem_id }}" target="_blank">{{ compound.pubchem_id }}</a></li> + {% endif %} + {% if compound.chembl_id %} + <li class="list-group-item">ChEMBL: <a href="https://www.ebi.ac.uk/chembldb/compound/inspect/{{ compound.chembl_id}}" target="_blank">{{ compound.chembl_id}}</a></li> + {% endif %} + {% if compound.chemspider_id %} + <li class="list-group-item">ChemSpider: <a href="http://www.chemspider.com/Chemical-Structure.{{ compound.chemspider_id}}.html" target="_blank">{{ compound.chemspider_id}}</a></li> + {% endif %} + </ul> + {% endif %} + </div> +</div> diff --git a/ippisite/ippidb/templates/compound_list.html b/ippisite/ippidb/templates/compound_list.html new file mode 100644 index 0000000000000000000000000000000000000000..92cec141dc5deee1bc98f556dad7eae55839c60a --- /dev/null +++ b/ippisite/ippidb/templates/compound_list.html @@ -0,0 +1,57 @@ +{% extends "base.html" %} + + +{% block title %}compound{% endblock %} + +{% block content %} + +{% include "kekule_display.html" %} +<div class="container-fluid"> +<div class="row flex-xl-nowrap"> + <div class="col-12 col-md-3 col-xl-2 bd-sidebar"> +<form> + <fieldset class="form-group row border border-info m-2"> + <div class="bg-info col-12"><legend>PPI</legend></div> + {% for ppi in ppis|slice:":5" %} + <div class="form-check col-12"> + <label class="form-check-label"> + <input class="form-check-input text-right" type="checkbox" value="{{ ppi.id }}" onchange="this.form.submit()" name="ppi" style="width: auto; margin-right: inherit!;"> + {{ ppi.name }} + </label> + </div> + {% endfor %} + </fieldset> +</form> +</div> +<main class="col-12 col-md-9 col-xl-10 pl-md-5 bd-content" role="main"> +{% if compounds %} + {% for compound in compounds %} + {% include "compound_abstract.html" with compound=compound %} + {% endfor %} +{% else %} + <p>No bibliographies available.</p> +{% endif %} + </main> +</div> +</div> + +<nav> + <ul class="pagination justify-content-end"> + {% if compounds.has_previous %} + <li class="page-item"> + <a class="page-link" href="?page={{ compounds.previous_page_number }}" tabindex="-1">Previous</a> + </li> + {% endif %} + + <li class="page-item disabled"> + <span class="page-link">Page {{ compounds.number }} of {{ compounds.paginator.num_pages }}.</span> + </li> + + {% if compounds.has_next %} + <li class="page-item"> + <a class="page-link" href="?page={{ compounds.next_page_number }}" tabindex="-1">Next</a> + </li> + {% endif %} + </ul> +</nav> +{% endblock %} diff --git a/ippisite/ippidb/templates/kekule_display.html b/ippisite/ippidb/templates/kekule_display.html new file mode 100644 index 0000000000000000000000000000000000000000..c6184e1ed6fbfde21ed9df13b65d654b76af1708 --- /dev/null +++ b/ippisite/ippidb/templates/kekule_display.html @@ -0,0 +1,13 @@ +<script> + Kekule.Indigo.enable(); + function kekule_display(smiles_id, viewer_id) { + var smi = document.getElementById(smiles_id).value; + var chemViewer = new Kekule.ChemWidget.Viewer(document.getElementById(viewer_id)); + chemViewer.setEnableToolbar(false) + .setEnableDirectInteraction(false) + .setEnableEdit(false) + .setToolButtons([]); + var mol = Kekule.IO.loadFormatData(smi, "smi"); + chemViewer.setChemObj(mol); + } +</script> diff --git a/ippisite/ippidb/urls.py b/ippisite/ippidb/urls.py index 0d502b8d7f981584d4b2a5e38141efbe4f0a1dde..5c1215153fb21041bf994d6e7f3ef5a38294ae18 100644 --- a/ippisite/ippidb/urls.py +++ b/ippisite/ippidb/urls.py @@ -21,6 +21,7 @@ urlpatterns = [ url(r'^query/chemical/$', views.chemical, name='chemical'), url(r'^biblio/(?P<source>\w{2})(?P<id_source>\w+)$', views.biblio_card, name='biblio_card'), url(r'^biblio/$', views.biblio_list, name='biblio_list'), + url(r'^compound/$', views.compound_list, name='compound_list'), url(r'^tutorials$', views.tutorials, name='tutorials'), url(r'^admin-session$', views.adminSession, name='admin-session'), url(r'^admin-session/add/(?P<step>.+)/$', diff --git a/ippisite/ippidb/views.py b/ippisite/ippidb/views.py index 2dc8e49860b084145d3685bd52c4a53ecf182167..bc416a80a5d21f24cb3eff70ff9aabcd89443598 100644 --- a/ippisite/ippidb/views.py +++ b/ippisite/ippidb/views.py @@ -2,9 +2,10 @@ import ippidb from django.shortcuts import render from django.http import HttpResponseRedirect, Http404 +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from formtools.wizard.views import SessionWizardView, NamedUrlSessionWizardView from .forms import IdForm, BibliographyForm, PDBForm, ProteinForm, ProteinDomainComplexTypeForm, ProteinDomainComplexForm, PpiForm, ProteinFormSet -from .models import Protein, Bibliography, ProteinDomainComplex, RefCompoundBiblio, TestActivityDescription +from .models import Protein, Bibliography, ProteinDomainComplex, RefCompoundBiblio, TestActivityDescription, Compound, Ppi from .ws import get_pdb_uniprot_mapping @@ -179,3 +180,18 @@ def biblio_card(request, source, id_source): return render(request, 'biblio_card.html', {'bibliography': bibliography, 'compound_biblios': refs, 'tad_ppis': tad_ppis}) + +def compound_list(request): + compounds = Compound.objects.all() + paginator = Paginator(compounds, 5) + ppis = Ppi.objects.all() + page = request.GET.get('page') + try: + compounds = paginator.page(page) + except PageNotAnInteger: + # If page is not an integer, deliver first page. + compounds = paginator.page(1) + except EmptyPage: + # If page is out of range (e.g. 9999), deliver last page of results. + compounds = paginator.page(paginator.num_pages) + return render(request, 'compound_list.html', {'compounds': compounds, 'ppis': ppis}) diff --git a/ippisite/ippidb/ws.py b/ippisite/ippidb/ws.py index c7341d5962e0098e1b3ec401c243c48583b01b54..7f699d49064549ae9893e3e35f87535d0509634a 100644 --- a/ippisite/ippidb/ws.py +++ b/ippisite/ippidb/ws.py @@ -49,6 +49,9 @@ def get_uniprot_info(uniprot_id): uniprot_client = UniProt() ns = {'u': 'http://uniprot.org/uniprot'} resp = uniprot_client.retrieve(uniprot_id) + f = open('/tmp/'+uniprot_id+'.xml','w') + f.write(str(resp)) + f.close() recommended_name = resp.root.findall( 'u:entry/u:protein/u:recommendedName/u:fullName', ns)[0].text organism = resp.root.findall( @@ -67,6 +70,7 @@ def get_uniprot_info(uniprot_id): 'organism': int(organism), 'gene': gene, 'entry_name': entry_name, + 'short_name': entry_name.split('_')[0], 'molecular_functions': molecular_functions }