Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/areg 126 #239

Merged
merged 14 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions applications/portal/backend/api/mappers/antibody_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@
def extract_base_url(url):
return urlsplit(url).hostname

@cache

def get_vendor_domains(vendor_id):
return [vd.base_url for vd in VendorDomain.objects.filter(
vendor_id=vendor_id)]
return [vd.base_url for vd in VendorDomain.objects.filter(vendor_id=vendor_id, status=STATUS.CURATED)]


class AntibodyMapper(IDAOMapper):

def from_dto(self, dto: AntibodyDTO) -> Antibody:
Expand Down Expand Up @@ -128,8 +129,7 @@ def to_dto(self, dao: Antibody) -> AntibodyDTO:
ab.sourceOrganism = dao.source_organism.name
if dao.species and not ab.targetSpecies:
ab.targetSpecies = [s.name for s in dao.species.all()]



ab.url = get_url_if_permitted(dao)

ab.showLink = dao.show_link if dao.show_link is not None else (dao.vendor and dao.vendor.show_link)
Expand Down
120 changes: 56 additions & 64 deletions applications/portal/backend/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def import_save(self):
if first_save:
super().save()
self._handle_duplicates()

if self.catalog_num:
self.catalog_num_search = catalog_number_chunked(self.catalog_num, self.cat_alt)

Expand Down Expand Up @@ -312,13 +312,11 @@ def save(self, *args, update_search=True, **kwargs):
if update_search and self.status == STATUS.CURATED:
refresh_search_view()


def _has_target_species_raw_changed(self, old_instance):
if old_instance:
return self.target_species_raw != old_instance.target_species_raw
return self.target_species_raw is not None


def delete(self, *args, **kwargs):
super(Antibody, self).delete(*args, **kwargs)
if self.status == STATUS.CURATED:
Expand Down Expand Up @@ -400,10 +398,6 @@ def _synchronize_target_species(self, old_species):

self._fill_target_species_raw_from_species()





def _target_species_from_raw(self):
species = []
if self.target_species_raw:
Expand Down Expand Up @@ -439,70 +433,68 @@ def get_duplicate(self) -> Optional['Antibody']:
return duplicate_antibodies[0]
return None

def set_vendor_from_name_url(self, url, name=None):
"""
Sets vendor from name and url.

if the name exists:
if the url exists:
return existing vendor
else:
create new vendor domain and associate to existing vendor
@staticmethod
def get_alt_url_with_and_without_www(url):
if "www." in url:
alt_url = url.replace("www.", "")
else:
if the url exists:
try to guess a vendor just by the url and add a vendor synonym
else if the url doesn't exist:
create a new vendor with the name from url
else:
do nothing
"""
alt_url = "www." + url
return alt_url

base_url = url and extract_base_url(url)
def check_vendor_name_or_create(self, name, base_url):
try:
# First, try to match by exact name
vendor = Vendor.objects.get(name__iexact=name or base_url)
self.vendor = vendor
if base_url:
self.add_vendor_domain(base_url, vendor)
except Vendor.MultipleObjectsReturned:
log.exception("Multiple vendors with name %s", name)
vendor = self.vendor = Vendor.objects.filter(name__iexact=name or base_url)[0]
if base_url:
self.add_vendor_domain(base_url, vendor)
vendor = Vendor.objects.filter(name__iexact=name)[0]
except Vendor.DoesNotExist:
# Then, try to match by domain

vds = VendorDomain.objects.filter(base_url__iexact=base_url, status=STATUS.CURATED)
if len(vds) == 0:
# If the domain is not matched, try to match by domain with and without www

if "www." in base_url:
alt_base_url = base_url.replace("www.", "")
else:
alt_base_url = "www." + base_url
vds = VendorDomain.objects.filter(base_url__iexact=alt_base_url, status=STATUS.CURATED)

if len(vds) == 0:
# As it doesn't match, create a new vendor
vendor_name = name or base_url
log.info("Creating new Vendor `%s` on domain to `%s`",
vendor_name, base_url)
vendor = Vendor(name=vendor_name,
commercial_type=self.commercial_type)
vendor.save()
self.vendor = vendor
if base_url:
self.add_vendor_domain(base_url, vendor)
return


# Vendor domain matched one way or the other, so associate to existing vendor
if len(vds) > 1:
log.error("Unexpectedly found multiple vendor domains for %s", base_url)

self.vendor = vds[0].vendor
if name:
VendorSynonym.objects.create(vendor=self.vendor, name=name)
if not self.vendor: ## if vendor is not set by vendor domain
vendor_name = name or base_url
log.info(
"Creating new Vendor `%s` on domain to `%s`", vendor_name, base_url
)
vendor = Vendor(name=vendor_name, commercial_type=self.commercial_type)
vendor.save()
self.vendor = vendor
self.add_vendor_domain(base_url, vendor)
return

if not self.vendor:
self.vendor = vendor
self.add_vendor_domain(base_url, vendor)

def set_vendor_from_name_url(self, url, name=None):
"""
If a new antibody is submitted with some vendor name and URL
should be treated with following rules:
- If both domain and vendor name are not recognized,
a new vendor is created and the new domain is attached to the vendor.
- If both domain and vendor name are recognized,
the domain is prioritized. And vendor name is added as a synonym.
- If the domain is not recognized but vendor name is recognized,
the new domain is attached to the vendor recognized.
- If domain is recognized and vendor name is not recognized,
we add a vendor synonym
"""

base_url = url and extract_base_url(url)
vds = VendorDomain.objects.filter(
base_url__iexact=base_url, status=STATUS.CURATED
)
alt_url = self.get_alt_url_with_and_without_www(url=base_url)
vds_alt = VendorDomain.objects.filter(
base_url__iexact=alt_url, status=STATUS.CURATED
)
vds_total = vds.union(vds_alt)

self.vendor = vds_total[0].vendor if len(vds_total) > 0 else None

self.check_vendor_name_or_create(name, base_url)
if len(vds_total) > 1:
log.error("Unexpectedly found multiple vendor domains for %s", base_url)

if len(vds_total) >= 1 and name:
VendorSynonym.objects.create(vendor=self.vendor, name=name)

def add_vendor_domain(self, base_url, vendor):
try:
Expand Down
10 changes: 9 additions & 1 deletion applications/portal/backend/api/services/antibody_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ def create_antibody(body: AddAntibodyDTO, userid: str) -> AntibodyDTO:
antibody.uid = userid
antibody.save()

if antibody.get_duplicate():
raise DuplicatedAntibody(antibody_mapper.to_dto(antibody))

return antibody_mapper.to_dto(antibody)


Expand All @@ -61,7 +64,12 @@ def get_antibody(antibody_id: int, status=STATUS.CURATED, filters=None) -> List[

def get_antibody_by_accession(accession: int) -> List[AntibodyDTO]:
try:
return antibody_mapper.to_dto(Antibody.objects.get(accession=accession).select_related("vendor", "source_organism").prefetch_related("species").prefetch_related("applications"))
return antibody_mapper.to_dto(
Antibody.objects.select_related("vendor", "source_organism")
.prefetch_related("species")
.prefetch_related("applications")
.get(accession=accession)
)
except Antibody.DoesNotExist:
raise
except Antibody.MultipleObjectsReturned:
Expand Down
Loading
Loading