Commit 72bfe69f authored by Fabien  MAREUIL's avatar Fabien MAREUIL
Browse files

Merge branch 'master' into 'release'

Prepare for v1.1.1

See merge request !30
parents 5ffda6b7 0de4e879
Pipeline #52340 passed with stages
in 16 minutes and 51 seconds
......@@ -18,6 +18,7 @@ test-ansible:
- pip3.5 install ansible
- cd ansible
- whoami
- ansible-galaxy collection install ansible.posix
- ansible-playbook system.yaml --syntax-check
- ansible-playbook deploy.yaml --syntax-check
......@@ -98,6 +99,7 @@ deploy-webserver-targetcentric:
- pip3.5 install ansible
- cd ansible
- whoami
- ansible-galaxy collection install ansible.posix
- ansible-playbook -vvv -i ./hosts_master deploy.yaml
--extra-vars "deploy_user_name=ippidb repo_api_token=JZS-4cH7bWkFkHa2rAVf marvinjs_apikey=$MARVINJS_APIKEY_targetcentric galaxy_base_url=$GALAXY_BASE_URL_targetcentric galaxy_apikey=$GALAXY_APIKEY_targetcentric galaxy_compoundproperties_workflowid=$GALAXY_COMPOUNDPROPERTIES_WORKFLOWID_targetcentric secret_key=$SECRET_KEY_targetcentric dbname=$DBNAME_targetcentric dbuser=$DBUSER_targetcentric dbpassword=$DBPASSWORD_targetcentric dbhost=$DBHOST_targetcentric dbport=$DBPORT_targetcentric http_port=$HTTP_PORT_targetcentric branch=$CI_COMMIT_REF_NAME gacode=$GACODE_targetcentric ippidb_media=$IPPIDB_MEDIA_targetcentric"
only:
......@@ -121,6 +123,7 @@ deploy-webserver-test:
- pip3.5 install ansible
- cd ansible
- whoami
- ansible-galaxy collection install ansible.posix
- ansible-playbook -vvv -i ./hosts_master deploy.yaml
--extra-vars "deploy_user_name=ippidb repo_api_token=JZS-4cH7bWkFkHa2rAVf marvinjs_apikey=$MARVINJS_APIKEY_master galaxy_base_url=$GALAXY_BASE_URL_master galaxy_apikey=$GALAXY_APIKEY_master galaxy_compoundproperties_workflowid=$GALAXY_COMPOUNDPROPERTIES_WORKFLOWID_master secret_key=$SECRET_KEY_master dbname=$DBNAME_master dbuser=$DBUSER_master dbpassword=$DBPASSWORD_master dbhost=$DBHOST_master dbport=$DBPORT_master http_port=$HTTP_PORT_master branch=$CI_COMMIT_REF_NAME gacode=$GACODE_master ippidb_media=$IPPIDB_MEDIA_master"
only:
......@@ -144,6 +147,7 @@ deploy-webserver-production:
- pip3.5 install ansible
- cd ansible
- whoami
- ansible-galaxy collection install ansible.posix
- ansible-playbook -vvv -i ./hosts_release deploy.yaml
--extra-vars "deploy_user_name=ippidb repo_api_token=JZS-4cH7bWkFkHa2rAVf marvinjs_apikey=$MARVINJS_APIKEY_release galaxy_base_url=$GALAXY_BASE_URL_release galaxy_apikey=$GALAXY_APIKEY_release galaxy_compoundproperties_workflowid=$GALAXY_COMPOUNDPROPERTIES_WORKFLOWID_release secret_key=$SECRET_KEY_release dbname=$DBNAME_release dbuser=$DBUSER_release dbpassword=$DBPASSWORD_release dbhost=$DBHOST_release dbport=$DBPORT_release http_port=$HTTP_PORT_release branch=$CI_COMMIT_REF_NAME gacode=$GACODE_release ippidb_media=$IPPIDB_MEDIA_release"
only:
......
......@@ -7,7 +7,7 @@
gather_facts: yes
tasks:
- name: Disable SELinux
selinux:
ansible.posix.selinux:
state: disabled
- name: Create celery user
user: name=celery-{{ http_port }} groups={{ deploy_user_name }} append=yes state=present createhome=yes
......@@ -350,14 +350,14 @@
- name: Enable firewalld
service: name=firewalld state=started enabled=yes
- name: open http firewall service
firewalld:
ansible.posix.firewalld:
service: http
zone: public
immediate: yes
permanent: true
state: enabled
- name: open http firewall port
firewalld:
ansible.posix.firewalld:
port: "{{ http_port }}/tcp"
zone: public
permanent: true
......
......@@ -42,16 +42,16 @@
# disable SELinux, and open firewall to incoming http
- name: disable SELinux
become: true
selinux:
ansible.posix.selinux:
state: disabled
- name: Open firewall to HTTP traffic
firewalld:
ansible.posix.firewalld:
service: http
permanent: true
state: enabled
become: true
- name: Open firwall to port 80 81 traffic
firewalld:
ansible.posix.firewalld:
port: "{{ http_port }}/tcp"
permanent: true
state: enabled
......@@ -18,6 +18,17 @@ def dir_path(string):
raise NotADirectoryError(string)
def isolevel_float(arg):
""" Type function for argparse - a float within some predefined bounds """
try:
f = float(arg)
except ValueError:
raise CommandError("Must be a floating point number")
if f < 0 or f > 1.0:
raise CommandError("Argument must be < 1.0 and > 0")
return f
class Command(AppCommand):
"""
Command to update mrc files
......@@ -26,7 +37,12 @@ class Command(AppCommand):
help = "liste all mrc files in a directory and update files in the database"
def __init__(
self, stdout=None, stderr=None, no_color=False, force_color=False, task=None,
self,
stdout=None,
stderr=None,
no_color=False,
force_color=False,
task=None,
):
super(Command, self).__init__(
stdout=stdout, stderr=stderr, no_color=no_color, force_color=force_color
......@@ -38,7 +54,10 @@ class Command(AppCommand):
def add_arguments(self, parser):
parser.add_argument(
"-mp", "--mrcpath", type=dir_path, help="root directory with all mrc files",
"-mp",
"--mrcpath",
type=dir_path,
help="root directory with all mrc files",
)
parser.add_argument(
"-pa",
......@@ -61,6 +80,14 @@ class Command(AppCommand):
dest="label",
help="label for files, used as label in the interface",
)
parser.add_argument(
"-di",
"--default_isolevel",
dest="default_isolevel",
help="isolevel default value",
default=0.7,
type=isolevel_float,
)
def handle(self, *args, **options):
"""
......@@ -75,7 +102,9 @@ class Command(AppCommand):
if typefile == "druggability":
storage_path = Chain.mrc_file.field.storage.path("content/mrc_files")
else:
storage_path = InteractFile.interact_file.field.storage.path("content/interact_files")
storage_path = InteractFile.interact_file.field.storage.path(
"content/interact_files"
)
if not os.path.exists(storage_path):
os.makedirs(storage_path)
list_files = glob.glob(os.path.join(mrcpath, pattern))
......@@ -108,13 +137,18 @@ class Command(AppCommand):
with open(data, "rb") as f:
dbchains[0].mrc_file.delete()
dbchains[0].mrc_file.save(os.path.basename(data), File(f))
dbchains[0].default_isolevel = options["default_isolevel"]
dbchains[0].save()
else:
interactfile, created = InteractFile.objects.get_or_create(
chain=dbchains[0], label=label
chain=dbchains[0],
label=label,
)
with open(data, "rb") as f:
interactfile.interact_file.delete()
interactfile.interact_file.save(os.path.basename(data), File(f))
interactfile.default_isolevel = options["default_isolevel"]
interactfile.save()
self.stdout.write(
self.style.SUCCESS(
"File mrc {}, have been saved in Chain, pdb: {}, chain: {}".format(
......@@ -126,7 +160,8 @@ class Command(AppCommand):
self.stdout.write(
self.style.WARNING(
"WARNING: Chain, pdb: {}, chain: {} doesn't exist".format(
pdb, chain,
pdb,
chain,
)
)
)
# Generated by Django 2.2.1 on 2021-03-10 10:52
from django.db import migrations, models
def init_isolevel(apps, schema_editor):
Chain = apps.get_model("ippidb", "Chain")
InteractFile = apps.get_model("ippidb", "InteractFile")
Chain.objects.all().update(default_isolevel=0.5)
InteractFile.objects.filter(label="all").update(default_isolevel=0.7)
InteractFile.objects.filter(label="hydrophobic").update(default_isolevel=0.3)
InteractFile.objects.filter(label="hbond donor-acceptor").update(
default_isolevel=0.3
)
InteractFile.objects.filter(label="negative").update(default_isolevel=0.08)
InteractFile.objects.filter(label="positive").update(default_isolevel=0.05)
InteractFile.objects.filter(label="backbone").update(default_isolevel=0.18)
class Migration(migrations.Migration):
dependencies = [
("ippidb", "0067_metainformation_normalize_factor"),
]
operations = [
migrations.AddField(
model_name="chain",
name="default_isolevel",
field=models.FloatField(default=0.7, verbose_name="Default isolevel value"),
),
migrations.AddField(
model_name="interactfile",
name="default_isolevel",
field=models.FloatField(default=0.7, verbose_name="Default isolevel value"),
),
migrations.RunPython(init_isolevel, reverse_code=migrations.RunPython.noop),
]
......@@ -132,9 +132,13 @@ class Chain(models.Model):
verbose_name="pdb file content with only one chain", default="no pdb file"
)
mrc_file = models.FileField(upload_to=content, blank=True)
default_isolevel = models.FloatField(
default=0.7, verbose_name="Default isolevel value"
)
class Meta:
unique_together = ("pdb", "pdb_chain_id")
ordering = ["pdb", "pdb_chain_id"]
def is_partner(self):
return self.partner_set.count()
......@@ -156,6 +160,9 @@ class InteractFile(models.Model):
chain = models.ForeignKey(Chain, on_delete=models.CASCADE)
label = models.CharField(max_length=250, blank=False, null=False)
interact_file = models.FileField(upload_to=contentinteract, blank=True)
default_isolevel = models.FloatField(
default=0.7, verbose_name="Default isolevel value"
)
def __unicode__(self):
return "{}".format(self.interact_file)
......@@ -356,6 +363,7 @@ class Cavity(models.Model):
class Meta:
unique_together = ("full_name", "chain", "cavity_number", "partner")
verbose_name_plural = "Cavities"
ordering = ["chain", "cavity_number"]
@property
def near_cavities(self):
......@@ -415,22 +423,35 @@ class MetaInformation(models.Model):
"""
average = models.DecimalField(
verbose_name="Average", max_digits=11, decimal_places=8
verbose_name="Average",
max_digits=11,
decimal_places=8,
help_text="partial matrix mean value",
)
std = models.DecimalField(
verbose_name="Standard Deviation", max_digits=11, decimal_places=8
verbose_name="Standard Deviation",
max_digits=11,
decimal_places=8,
help_text="partial matrix standard deviation",
)
maximum = models.DecimalField(
verbose_name="Maximum", max_digits=11, decimal_places=8
verbose_name="Maximum",
max_digits=11,
decimal_places=8,
help_text="partial matrix maximum value",
)
minimum = models.DecimalField(
verbose_name="Minimum", max_digits=11, decimal_places=8
verbose_name="Minimum",
max_digits=11,
decimal_places=8,
help_text="partial matrix minimum value",
)
normalize_factor = models.DecimalField(
blank=True,
null=True,
default=4.58599730,
verbose_name="Normalize Factor",
help_text="complet matrix standard deviation",
max_digits=11,
decimal_places=8,
)
......
......@@ -57,7 +57,7 @@ class ChainDistanceSerializer(serializers.ModelSerializer):
class Meta:
model = Chain
fields = ("id", "pdb_chain_id", "protein", "pdb")
fields = ("id", "pdb_chain_id", "protein", "pdb", "default_isolevel")
class PartnerDistanceSerializer(serializers.ModelSerializer):
......@@ -121,6 +121,7 @@ class ChainSerializer(serializers.ModelSerializer):
"cavity_set",
"partner_set",
"mrc_file",
"default_isolevel",
"interactfile_set",
)
......
......@@ -356,10 +356,47 @@ div.hidden {
/* -- Home page choices -- */
.background_choices {
margin: 40px;
.compound_choices {
position: relative;
background: #e3e9eb url(/static/images/Other/cross.png) 50px 100px no-repeat;
background: #E3E9EB url(/static/images/Other/cross.png) 50px 100px no-repeat;
text-align: center;
height: fit-content;
box-shadow: 0 3px 11px 0 rgb(0 0 0 / 20%);
}
.compound_background {
position: relative;
background: #E3E9EB url(/static/images/Other/cross.png) 50px 100px no-repeat;
text-align: center;
height: fit-content;
}
.compound_choices:hover{
background: #D1DBDE url(/static/images/Other/cross.png) 50px 100px no-repeat;
}
.pocket_choices {
position: relative;
background: #AABDC3 url(/static/images/Other/cross.png) 50px 100px no-repeat;
text-align: center;
height: fit-content;
box-shadow: 0 3px 11px 0 rgb(0 0 0 / 20%);
}
.pocket_choices:hover {
background: #97ADB5 url(/static/images/Other/cross.png) 50px 100px no-repeat;
}
.pocket_background {
position: relative;
background: #AABDC3 url(/static/images/Other/cross.png) 50px 100px no-repeat;
text-align: center;
height: fit-content;
}
.icons {
padding: 10%;
font-size: 1.5em;
}
.choices_background {
......@@ -448,6 +485,15 @@ div.hidden {
display:block;
}
.front-vertical-align {
padding-top: 80px;
}
.back-vertical-align {
padding-top: 25px;
}
/* -- Breadcrumb -- */
.breadNav {
......@@ -1220,4 +1266,48 @@ div.hidden {
.btn.float-right+.btn.float-right {
margin-right: 5px
}
\ No newline at end of file
}
/* Modal */
.modal-xl {
width: 100%;
max-width:1200px;
height: fit-content;
max-height: 1200px;
}
.close_choices_modal {
margin: 0px !important;
right: 32px !important;
top: 32px !important;
width: 32px !important;
height: 32px !important;
opacity: 0.5;
border: none !important;
color: #495057 !important;
cursor: pointer;
float: right;
text-align: right;
font-size: 2em;
background-color: white !important;
}
.close_choices_modal:hover {
opacity: 1;
}
.align_modal {
display: inline-block;
}
.modal_choices_title {
float: left;
text-align: right;
font-family: "PlayfairDisplayReg";
font-size: 2em;
}
.fade_index {
transition: opacity 1s linear;
}
\ No newline at end of file
......@@ -134,7 +134,18 @@ Description: IPPI-DB targetcentric Theme
.dropbtn {
font-size: 14px;
color: #007bff
color: #2D96FA;
border-radius: 5px;
border-color: #97ADB5;
background-color: #eff3f5;
padding-right: 3px;
padding-left: 3px;
padding-bottom: 1px;
padding-top: 1px;
border-style: solid;
border-width: 2px;
min-width: 25px;
text-align: center;
}
.dropdown {
......@@ -145,12 +156,16 @@ Description: IPPI-DB targetcentric Theme
.dropdown-content {
display: none;
position: absolute;
bottom: 24px;
left: 14px;
background-color: #f1f1f1;
bottom: 22px;
left: 12px;
background-color: #eff3f5;
min-width: 100px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.4);
z-index: 3;
border-radius: 5px;
border-color: #97adb5 !important;
border: 2px;
border-style: solid;
}
.dropdown-content a {
......@@ -161,25 +176,28 @@ Description: IPPI-DB targetcentric Theme
display: block;
}
.dropdown-content a:hover {background-color: #ddd;}
.dropdown-content a:hover {
background-color: #d3dee2;
color: black;
border-radius: 5px;
}
.dropdown:hover .dropdown-content {display: block;}
.dropdown:hover .dropbtn {background-color: #ddd;}
a.infobulle{
color:#ccc;
.dropdown:hover .dropbtn {
background-color: #d3dee2;
color: black;
}
a.infobulle:hover, a.infobulle:focus{
color:#17a2b8;
.infobulle svg{
color: rgb(45, 150, 250);
}
a.infobulle span{
.infobulle span{
position:absolute;
color:white;
margin-top:23px;
margin-left:0px;
color:white;
bottom: 100%;
background:rgba(0,0,0,.9);
padding:15px;
border-radius:3px;
......@@ -190,7 +208,7 @@ a.infobulle span{
z-index: 3;
}
a.infobulle:hover span, a.infobulle:focus span{
.infobulle:hover span, .infobulle:focus span{
transform:scale(1) rotate(0);
opacity:1;
}
......@@ -206,4 +224,13 @@ table.gradiant td{
border-right: none;
white-space: nowrap;
text-align: left;
}
.fa-plus-square {
box-shadow: 0 0 2px rgba(0,0,0,.5);
}
th .fa-plus-square:hover {
background-color: black;
color: rgb(255, 255, 255);
}
\ No newline at end of file
......@@ -277,4 +277,11 @@ var toggleCheckBox = function (id) {
} else {
queryUrl.changeSelection(id, null);
}
}
\ No newline at end of file
}
$(document).ready(function () {
$(".modalhref").click(function(e){
$(".modal").modal('hide');
window.open($(this).find("a").last()[0].href, '_self');
});
});
\ No newline at end of file
This diff is collapsed.
......@@ -366,20 +366,29 @@ function loadNGL(url, callback){
// Handle window resizing
var divflex = createElement("div",{},{},"d-flex justify-content-between flex-row-reverse bd-highlight");
var divmultiButtonright = createElement("div",{role: "group"},{},"d-flex align-items-end flex-column");
var divcavitiesButton = createElement("div",{role: "group"},{},"btn-group-vertical btn-group-sm btn-group-toggle p-2");
var divcavitiesButton = createElement("div",{role: "group"},{},"infobulle btn-group-vertical btn-group-sm btn-group-toggle p-2");
var spaninfocav = createElement("span", {}, {}, '');
spaninfocav.innerHTML = "Load a pocket detected with Volsite (Desaphy et al., 2012).";
divcavitiesButton.appendChild(spaninfocav);
divmultiButtonright.appendChild(divcavitiesButton);
var divmultiButtoncenter = createElement("div",{},{}, "btn-group-vertical align-self-start");
var divmultiButtonleft = createElement("div", {}, {}, "btn-group align-self-start");
divflex.appendChild(divmultiButtonright);
divflex.appendChild(divmultiButtoncenter);
divflex.appendChild(divmultiButtonleft);
var divslider = createElement("div", {}, {}, 'form-group border border-info rounded p-2');
var divslider = createElement("div", {}, {}, 'infobulle form-group border border-info rounded p-2');
var spaninfodrug = createElement("span", {}, {}, '');
spaninfodrug.innerHTML = "Druggability has been determined by our Deep Learning tool InDeep trained on protein/ligand interactions. They are represented as isolevel probabilities, which you can adjust with the slider (0,1)."
divslider.appendChild(spaninfodrug);
titledruggable = createElement("strong", {}, {}, '');
titledruggable.innerHTML = "Predictive Druggability";
titledruggable.innerHTML = "Predicted druggability";
divslider.appendChild(titledruggable);
var divsliderinteractibility = createElement("div", {}, {}, 'form-group border border-info rounded p-2 mr-2');
var divsliderinteractibility = createElement("div", {}, {}, 'infobulle form-group border border-info rounded p-2 mr-2');
var spaninfoint = createElement("span", {}, {"right":"50%"}, '');
spaninfoint.innerHTML = "Interactability has been determined by our Deep Learning tool InDeep trained on protein-protein interactions. They are represented as isolevel probabilities, which you can adjust with the slider (0,1)."
divsliderinteractibility.appendChild(spaninfoint);
titleinteractible = createElement("strong", {}, {}, '');
titleinteractible.innerHTML = "Predictive Interactibility";
titleinteractible.innerHTML = "Predicted Interactability";
divsliderinteractibility.appendChild(titleinteractible);
divmultiButtonleft.appendChild(divsliderinteractibility);
divmultiButtonleft.appendChild(divslider);
......@@ -388,7 +397,7 @@ function loadNGL(url, callback){
}, false );
var hasmrc = 0
var hasinteract = 0
pdb.chain_set.reverse().forEach(function(chain, indexchain){
pdb.chain_set.forEach(function(chain, indexchain){
var blobchain = new Blob( [ chain.file_content ], {type: 'text/plain'} );
var componentname = pdb.code + '_' + chain.pdb_chain_id;
stage.loadFile( blobchain, {ext:"pdb", name: componentname}).then( function( o ){
......@@ -410,7 +419,7 @@ function loadNGL(url, callback){
hasinteract = 1;
var labelsliderinterac = createElement("label", {}, {}, "", {'for':'isolevel' + chain.pdb_chain_id});
labelsliderinterac.innerHTML = 'Adjust predictive interactibility surface on chain ' + chain.pdb_chain_id;
labelsliderinterac.innerHTML = 'Adjust predicted interactability surface on chain ' + chain.pdb_chain_id;
divchain.appendChild(labelsliderinterac);
divchain.appendChild(createElement('br'));
var divdropdowninterac = createElement("div",{},{},"dropdown");
......@@ -419,7 +428,7 @@ function loadNGL(url, callback){
"data-toggle":"dropdown",
"aria-haspopup":"true",
"aria-expanded":"false"});
buttondorpdowninterac.append("Select interactibility model, chain ".concat(chain.pdb_chain_id ));
buttondorpdowninterac.append("Select interactability model, chain ".concat(chain.pdb_chain_id ));
divdropdowninterac.appendChild(buttondorpdowninterac);
var dropdowninteracmenu = createElement("div",{},{},"dropdown-menu",{'aria-labelledby': componentname + "_interact"});
divdropdowninterac.appendChild(dropdowninteracmenu);
......@@ -448,13 +457,13 @@ function loadNGL(url, callback){