Skip to content

Commit

Permalink
Merge pull request #407 from UW-GAC/feature/partner-upload-workspaces
Browse files Browse the repository at this point in the history
Add partner upload workspaces
  • Loading branch information
amstilp authored Dec 18, 2023
2 parents 7140f5f + bf78a59 commit 1e9b5bd
Show file tree
Hide file tree
Showing 15 changed files with 752 additions and 2 deletions.
1 change: 1 addition & 0 deletions config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@
"gregor_django.gregor_anvil.adapters.ExampleWorkspaceAdapter",
"gregor_django.gregor_anvil.adapters.TemplateWorkspaceAdapter",
"gregor_django.gregor_anvil.adapters.UploadWorkspaceAdapter",
"gregor_django.gregor_anvil.adapters.PartnerUploadWorkspaceAdapter",
"gregor_django.gregor_anvil.adapters.CombinedConsortiumDataWorkspaceAdapter",
"gregor_django.gregor_anvil.adapters.ReleaseWorkspaceAdapter",
"gregor_django.gregor_anvil.adapters.DCCProcessingWorkspaceAdapter",
Expand Down
13 changes: 13 additions & 0 deletions gregor_django/gregor_anvil/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ def get_autocomplete_queryset(self, queryset, q, forwarded={}):
return queryset


class PartnerUploadWorkspaceAdapter(BaseWorkspaceAdapter):
"""Adapter for PartnerUploadWorkspaces."""

type = "partner_upload"
name = "Partner upload workspace"
description = "Workspaces that contain data uploaded by a Partner Group "
list_table_class = tables.PartnerUploadWorkspaceTable
workspace_data_model = models.PartnerUploadWorkspace
workspace_data_form_class = forms.PartnerUploadWorkspaceForm
workspace_form_class = WorkspaceForm
workspace_detail_template_name = "gregor_anvil/partneruploadworkspace_detail.html"


class ExampleWorkspaceAdapter(BaseWorkspaceAdapter):
"""Adapter for ExampleWorkspaces."""

Expand Down
24 changes: 24 additions & 0 deletions gregor_django/gregor_anvil/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,30 @@ class UploadWorkspaceAdmin(SimpleHistoryAdmin):
)


@admin.register(models.PartnerUploadWorkspace)
class PartnerUploadWorkspaceAdmin(SimpleHistoryAdmin):
"""Admin class for the PartnerUploadWorkspace model."""

list_display = (
"id",
"workspace",
"partner_group",
"consent_group",
"version",
)
list_filter = (
"partner_group",
"consent_group",
"version",
)
sortable_by = (
"id",
"workspace",
"partner_group",
"version",
)


@admin.register(models.ExampleWorkspace)
class ExampleWorkspaceAdmin(SimpleHistoryAdmin):
"""Admin class for the ExampleWorkspace model."""
Expand Down
20 changes: 20 additions & 0 deletions gregor_django/gregor_anvil/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,26 @@ class Meta:
)


class PartnerUploadWorkspaceForm(forms.ModelForm):
"""Form for a PartnerUploadWorkspace object."""

class Meta:
model = models.PartnerUploadWorkspace
fields = (
"partner_group",
"consent_group",
"version",
"date_completed",
"workspace",
)
help_texts = {
"date_completed": "Do not select a date until validation has been completed in this workspace.",
}
widgets = {
"date_completed": CustomDateInput(),
}


class ExampleWorkspaceForm(forms.ModelForm):
"""Form for a ExampleWorkspace object."""

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# Generated by Django 4.2.8 on 2023-12-15 23:55

from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import django_extensions.db.fields
import simple_history.models


class Migration(migrations.Migration):

dependencies = [
("anvil_consortium_manager", "0015_add_new_permissions"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("gregor_anvil", "0017_remove_releaseworkspace_upload_workspaces"),
]

operations = [
migrations.CreateModel(
name="PartnerUploadWorkspace",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"created",
django_extensions.db.fields.CreationDateTimeField(
auto_now_add=True, verbose_name="created"
),
),
(
"modified",
django_extensions.db.fields.ModificationDateTimeField(
auto_now=True, verbose_name="modified"
),
),
(
"version",
models.IntegerField(
help_text="The version of this workspace for this PartnerGroup and ConsentGroup.",
validators=[django.core.validators.MinValueValidator(1)],
),
),
(
"date_completed",
models.DateField(
blank=True,
help_text="The date when uploads to this workspace and data validation were completed.",
null=True,
),
),
(
"consent_group",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="gregor_anvil.consentgroup",
),
),
(
"partner_group",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="gregor_anvil.partnergroup",
),
),
(
"workspace",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
to="anvil_consortium_manager.workspace",
),
),
],
),
migrations.CreateModel(
name="HistoricalPartnerUploadWorkspace",
fields=[
(
"id",
models.BigIntegerField(
auto_created=True, blank=True, db_index=True, verbose_name="ID"
),
),
(
"created",
django_extensions.db.fields.CreationDateTimeField(
auto_now_add=True, verbose_name="created"
),
),
(
"modified",
django_extensions.db.fields.ModificationDateTimeField(
auto_now=True, verbose_name="modified"
),
),
(
"version",
models.IntegerField(
help_text="The version of this workspace for this PartnerGroup and ConsentGroup.",
validators=[django.core.validators.MinValueValidator(1)],
),
),
(
"date_completed",
models.DateField(
blank=True,
help_text="The date when uploads to this workspace and data validation were completed.",
null=True,
),
),
("history_id", models.AutoField(primary_key=True, serialize=False)),
("history_date", models.DateTimeField(db_index=True)),
("history_change_reason", models.CharField(max_length=100, null=True)),
(
"history_type",
models.CharField(
choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")],
max_length=1,
),
),
(
"consent_group",
models.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="gregor_anvil.consentgroup",
),
),
(
"history_user",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to=settings.AUTH_USER_MODEL,
),
),
(
"partner_group",
models.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="gregor_anvil.partnergroup",
),
),
(
"workspace",
models.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="anvil_consortium_manager.workspace",
),
),
],
options={
"verbose_name": "historical partner upload workspace",
"verbose_name_plural": "historical partner upload workspaces",
"ordering": ("-history_date", "-history_id"),
"get_latest_by": ("history_date", "history_id"),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.AddConstraint(
model_name="partneruploadworkspace",
constraint=models.UniqueConstraint(
fields=("partner_group", "consent_group", "version"),
name="unique_partner_upload_workspace_data",
),
),
]
49 changes: 49 additions & 0 deletions gregor_django/gregor_anvil/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,26 @@ def get_absolute_url(self):
"""Return the absolute url for this object."""
return reverse("gregor_anvil:upload_cycles:detail", args=[self.cycle])

def get_partner_upload_workspaces(self):
"""Return a queryset of PartnerUploadWorkspace objects that are included in this upload cycle.
For a given PartnerGroup and ConsentGroup, the workspace with the highest version that also has a date_completed
that is before the end_date of this upload cycle is included.
"""
qs = PartnerUploadWorkspace.objects.filter(
date_completed__lte=self.end_date
).order_by("-version")
# This is not ideal, but we can't use .distinct on fields.
pks_to_keep = []
for partner_group in PartnerGroup.objects.all():
for consent_group in ConsentGroup.objects.all():
instance = qs.filter(
partner_group=partner_group, consent_group=consent_group
).first()
if instance:
pks_to_keep.append(instance.pk)
return qs.filter(pk__in=pks_to_keep)


class UploadWorkspace(TimeStampedModel, BaseWorkspaceData):
"""A model to track additional data about an upload workspace."""
Expand All @@ -137,6 +157,35 @@ class Meta:
]


class PartnerUploadWorkspace(TimeStampedModel, BaseWorkspaceData):
"""A model to track additional data about a partner workspace."""

partner_group = models.ForeignKey(PartnerGroup, on_delete=models.PROTECT)
"""The PartnerGroup providing data for this Workspace."""

consent_group = models.ForeignKey(ConsentGroup, on_delete=models.PROTECT)
"""The ConsentGroup associated with this workspace."""

version = models.IntegerField(
validators=[MinValueValidator(1)],
help_text="The version of this workspace for this PartnerGroup and ConsentGroup.",
)
date_completed = models.DateField(
help_text="The date when uploads to this workspace and data validation were completed.",
null=True,
blank=True,
)

class Meta:
constraints = [
# Model uniqueness.
models.UniqueConstraint(
name="unique_partner_upload_workspace_data",
fields=["partner_group", "consent_group", "version"],
),
]


class ExampleWorkspace(TimeStampedModel, BaseWorkspaceData):
"""A model to track example workspaces."""

Expand Down
18 changes: 18 additions & 0 deletions gregor_django/gregor_anvil/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,24 @@ class Meta:
)


class PartnerUploadWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table):
"""A table for Workspaces that includes fields from PartnerUploadWorkspace."""

name = tables.columns.Column(linkify=True)
partneruploadworkspace__partner_group = tables.columns.Column(linkify=True)

class Meta:
model = Workspace
fields = (
"name",
"partneruploadworkspace__partner_group",
"partneruploadworkspace__consent_group",
"partneruploadworkspace__version",
"partneruploadworkspace__date_completed",
"consortium_access",
)


class TemplateWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table):
"""A table for Workspaces that includes fields from TemplateWorkspace."""

Expand Down
13 changes: 12 additions & 1 deletion gregor_django/gregor_anvil/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,18 @@ class UploadWorkspaceFactory(DjangoModelFactory):

class Meta:
model = models.UploadWorkspace
django_get_or_create = ["research_center", "consent_group"]


class PartnerUploadWorkspaceFactory(DjangoModelFactory):
"""A factory for the UploadWorkspace model."""

partner_group = SubFactory(PartnerGroupFactory)
consent_group = SubFactory(ConsentGroupFactory)
version = Faker("random_int", min=1)
workspace = SubFactory(WorkspaceFactory, workspace_type="partner_upload")

class Meta:
model = models.PartnerUploadWorkspace


class ExampleWorkspaceFactory(DjangoModelFactory):
Expand Down
Loading

0 comments on commit 1e9b5bd

Please sign in to comment.