Skip to content
Draft
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
217 changes: 118 additions & 99 deletions hypha/apply/funds/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from django.urls import re_path
from django.urls import reverse
from django.utils.safestring import mark_safe
from wagtail.contrib.modeladmin.helpers import PermissionHelper
from wagtail.contrib.modeladmin.options import ModelAdmin, ModelAdminGroup
from wagtail.admin.menu import MenuItem
from wagtail.contrib.modeladmin.options import (
ModelAdmin,
ModelAdminGroup,
modeladmin_register,
)
from wagtail.snippets.models import register_snippet
from wagtail.snippets.views.snippets import SnippetViewSet

from hypha.apply.categories.admin import CategoryAdmin, MetaTermAdmin
from hypha.apply.determinations.admin import (
Expand All @@ -11,33 +17,57 @@
)
from hypha.apply.funds.models import ReviewerRole, ReviewerSettings, ScreeningStatus
from hypha.apply.review.admin import ReviewFormAdmin
from hypha.apply.utils.admin import AdminIcon, ListRelatedMixin, RelatedFormsMixin
from hypha.apply.utils.admin import AdminIcon, RelatedFormsMixin
from hypha.core.wagtail.admin.options import SettingModelAdmin

from .admin_helpers import (
ApplicationFormButtonHelper,
ButtonsWithPreview,
FormsFundRoundListFilter,
RoundAdminURLHelper,
RoundFundChooserView,
RoundStateListFilter,
)
from .admin_views import (
CopyApplicationFormViewClass,
CreateApplicationFormView,
EditApplicationFormView,
)
from .models import (
ApplicationForm,
ApplicationSettings,
FundType,
LabType,
RequestForPartners,
Round,
SealedRound,
)


class ScreeningStatusAdmin(SnippetViewSet):
model = ScreeningStatus
icon = str(AdminIcon.SCREENING_STATUS)
list_display = ("title", "yes", "default")

def user_can_edit(self, user):
return user.is_superuser

def user_can_delete(self, user):
return user.is_superuser


class ReviewerRoleAdmin(SnippetViewSet):
model = ReviewerRole
icon = str(AdminIcon.REVIEWER_ROLE)
menu_label = "Reviewer Roles"


# having issues with Locale during save
# class FundAdmin(SnippetViewSet, RelatedFormsMixin):
# model = FundType
# icon = str(AdminIcon.FUND)
# menu_label = "Funds"
# list_display = ("title", "application_forms", "get_review_forms", "get_determination_forms")
#
#
# class LabAdmin(SnippetViewSet, RelatedFormsMixin):
# model = LabType
# icon = str(AdminIcon.LAB)
# menu_label = "Labs"
# list_display = ("title", "application_forms", "get_review_forms", "get_determination_forms")


class BaseRoundAdmin(ModelAdmin):
choose_parent_view_class = RoundFundChooserView
choose_parent_template_name = "funds/admin/parent_chooser.html"
Expand Down Expand Up @@ -67,106 +97,58 @@ def fund(self, obj):
return mark_safe(url_tag)


class ScreeningStatusPermissionHelper(PermissionHelper):
def user_can_edit_obj(self, user, obj):
"""
Return a boolean to indicate whether `user` is permitted to 'change'
a specific `self.model` instance.
"""
return user.is_superuser

def user_can_delete_obj(self, user, obj):
"""
Return a boolean to indicate whether `user` is permitted to 'delete'
a specific `self.model` instance.
"""
return user.is_superuser


class ScreeningStatusAdmin(ModelAdmin):
model = ScreeningStatus
menu_icon = str(AdminIcon.SCREENING_STATUS)
list_display = ("title", "yes", "default")
permission_helper_class = ScreeningStatusPermissionHelper
list_display = ("title", "yes", "default")


class SealedRoundAdmin(BaseRoundAdmin):
model = SealedRound
menu_icon = str(AdminIcon.SEALED_ROUND)
menu_label = "Sealed Rounds"
list_display = ("title", "fund", "start_date", "end_date")


class FundAdmin(ModelAdmin, RelatedFormsMixin):
model = FundType
menu_icon = str(AdminIcon.FUND)
menu_label = "Funds"
list_display = ("title", "application_forms", "review_forms", "determination_forms")


# class FundAdmin(ModelAdmin, RelatedFormsMixin):
# model = FundType
# menu_icon = str(AdminIcon.FUND)
# menu_label = "Funds"
# list_display = ("title", "application_forms", "review_forms", "determination_forms")
#
#
class RFPAdmin(ModelAdmin):
model = RequestForPartners
menu_icon = str(AdminIcon.REQUEST_FOR_PARTNERS)
menu_label = "Request For Partners"


class LabAdmin(ModelAdmin, RelatedFormsMixin):
model = LabType
menu_icon = str(AdminIcon.LAB)
menu_label = "Labs"
list_display = ("title", "application_forms", "review_forms", "determination_forms")
#
# class LabAdmin(ModelAdmin, RelatedFormsMixin):
# model = LabType
# menu_icon = str(AdminIcon.LAB)
# menu_label = "Labs"
# list_display = ("title", "application_forms", "review_forms", "determination_forms")
#


class ReviewerRoleAdmin(ModelAdmin):
model = ReviewerRole
menu_icon = str(AdminIcon.REVIEWER_ROLE)
menu_label = "Reviewer Roles"
class ApplicationFormAdmin(SnippetViewSet):
model = ApplicationForm
menu_icon = str(AdminIcon.APPLICATION_FORM)
list_display = ("name", "used_by")

def get_queryset(self, request):
# Explicitly define the queryset for this snippet
qs = self.model.objects.all()

class DeletePermission(PermissionHelper, ListRelatedMixin):
related_models = [
("applicationbaseform", "application"),
("roundbaseform", "round"),
("labbaseform", "lab"),
]
# Prefetch related fields for the 'used_by' logic
related = [
"applicationbaseform_set__application",
"roundbaseform_set__round",
"labbaseform_set__lab",
]
return qs.prefetch_related(*related)

def user_can_delete_obj(self, user, obj):
if str(self.used_by(obj)):
return False
return True


class ApplicationFormAdmin(ListRelatedMixin, ModelAdmin):
model = ApplicationForm
menu_icon = str(AdminIcon.APPLICATION_FORM)
list_display = ("name", "used_by")
list_filter = (FormsFundRoundListFilter,)
permission_helper_class = DeletePermission
button_helper_class = ApplicationFormButtonHelper
create_view_class = CreateApplicationFormView
edit_view_class = EditApplicationFormView

related_models = [
("applicationbaseform", "application"),
("roundbaseform", "round"),
("labbaseform", "lab"),
]

def copy_form_view(self, request, instance_pk):
kwargs = {"model_admin": self, "form_pk": instance_pk}
view_class = CopyApplicationFormViewClass
return view_class.as_view(**kwargs)(request)

def get_admin_urls_for_registration(self):
"""Add the url for creating form copy."""
urls = super().get_admin_urls_for_registration()
copy_form_url = re_path(
self.url_helper.get_action_url_pattern("copy_form"),
self.copy_form_view,
name=self.url_helper.get_action_url_name("copy_form"),
)
return urls + (copy_form_url,)
register_snippet(ApplicationFormAdmin)
register_snippet(ScreeningStatusAdmin)
register_snippet(ReviewerRoleAdmin)
# register_snippet(FundAdmin)
# register_snippet(LabAdmin)


class ApplicationSettingAdmin(SettingModelAdmin):
Expand All @@ -183,18 +165,55 @@ class ApplyAdminGroup(ModelAdminGroup):
items = (
RoundAdmin,
SealedRoundAdmin,
FundAdmin,
LabAdmin,
RFPAdmin,
ApplicationFormAdmin,
ApplicationSettingAdmin,
ReviewFormAdmin,
ReviewerSettingAdmin,
DeterminationFormAdmin,
DeterminationMessageSettingsAdmin,
DeterminationFormSettingsAdmin,
CategoryAdmin,
ScreeningStatusAdmin,
ReviewerRoleAdmin,
MetaTermAdmin,
)

def get_submenu_items(self):
# Get existing items
submenu_items = super().get_submenu_items()

snippets = [
{
"model": ReviewerRole,
"menu_label": "Reviewer Roles",
"icon_name": str(AdminIcon.REVIEWER_ROLE),
},
# {"model": FundType, "menu_label": "Funds", "icon_name": str(AdminIcon.FUND)},
# {"model": LabType, "menu_label": "Labs", "icon_name": str(AdminIcon.LAB)},
# {"model": RequestForPartners, "menu_label": "Request For Partners", "icon_name": str(AdminIcon.REQUEST_FOR_PARTNERS)},
{
"model": ScreeningStatus,
"menu_label": "Screening Decisions",
"icon_name": str(AdminIcon.SCREENING_STATUS),
},
{
"model": ApplicationForm,
"menu_label": "Application Forms",
"icon_name": str(AdminIcon.APPLICATION_FORM),
},
]

for snippet in snippets:
snippet_url = reverse(
f"wagtailsnippets_{snippet['model']._meta.app_label}_{snippet['model']._meta.model_name}:list",
)
submenu_items.append(
MenuItem(
snippet["menu_label"],
snippet_url,
icon_name=snippet["icon_name"],
)
)

return submenu_items


modeladmin_register(ApplyAdminGroup)
8 changes: 8 additions & 0 deletions hypha/apply/funds/edit_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@
from django.urls import reverse
from wagtail.admin.panels import FieldPanel, Panel
from wagtail.models import Page
from wagtail.snippets.models import get_snippet_models


def reverse_edit(obj):
if isinstance(obj, Page):
return reverse("wagtailadmin_pages:edit", args=(obj.id,))

snippet_models = get_snippet_models()
if obj.__class__ in snippet_models:
return reverse(
f"wagtailsnippets_{obj._meta.app_label}_{obj._meta.model_name}:edit",
args=(obj.id,),
)

url_name = f"{obj._meta.app_label}_{obj._meta.model_name}_modeladmin_edit"
return reverse(url_name, args=(obj.id,))

Expand Down
35 changes: 35 additions & 0 deletions hypha/apply/funds/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.contrib.admin import display
from django.utils.translation import gettext_lazy as _

from .application_revisions import ApplicationRevision
Expand Down Expand Up @@ -35,6 +36,23 @@ class FundType(ApplicationBase):
class Meta:
verbose_name = _("Fund")

@property
def application_forms(self):
# Return related forms as a comma-separated list
return ", ".join(form.form.name for form in self.forms.all())

@property
@display(description=_("Review Forms"))
def get_review_forms(self):
# Return related forms as a comma-separated list
return ", ".join(form.form.name for form in self.review_forms.all())

@property
@display(description=_("Determination Forms"))
def get_determination_forms(self):
# Return related forms as a comma-separated list
return ", ".join(form.form.name for form in self.determination_forms.all())


class RequestForPartners(ApplicationBase):
subpage_types = ["funds.Round", "funds.SealedRound"]
Expand All @@ -58,3 +76,20 @@ def __init__(self, *args, **kwargs):
class LabType(LabBase):
class Meta:
verbose_name = _("Lab")

@property
def application_forms(self):
# Return related forms as a comma-separated list
return ", ".join(form.form.name for form in self.forms.all())

@property
@display(description=_("Review Forms"))
def get_review_forms(self):
# Return related forms as a comma-separated list
return ", ".join(form.form.name for form in self.review_forms.all())

@property
@display(description=_("Determination Forms"))
def get_determination_forms(self):
# Return related forms as a comma-separated list
return ", ".join(form.form.name for form in self.determination_forms.all())
29 changes: 29 additions & 0 deletions hypha/apply/funds/models/forms.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from django.db import models
from django.urls import reverse
from django.utils.safestring import mark_safe
from modelcluster.fields import ParentalKey
from wagtail.admin.panels import FieldPanel
from wagtail.fields import StreamField
Expand All @@ -23,6 +25,33 @@ class ApplicationForm(models.Model):
def __str__(self):
return self.name

@property
def used_by(self):
rows = []
related_models = [
("applicationbaseform", "application"),
("roundbaseform", "round"),
("labbaseform", "lab"),
]

for form, field in related_models:
related_values = getattr(self, f"{form}_set").values(
f"{field}__title", f"{field}__id"
)
for value in related_values:
title = value.get(f"{field}__title")
obj_id = value.get(f"{field}__id")
if title and obj_id:
edit_url = reverse("wagtailadmin_pages:edit", args=(obj_id,))
rows.append(
f'<a href="{edit_url}">'
f'<svg width="0.85rem" height="0.85rem" aria-hidden="true">'
f'<use href="#icon-{field}"></use></svg> {title}</a>'
)
elif title:
rows.append(f"{title}")
return mark_safe(", ".join(rows))


class AbstractRelatedForm(Orderable):
FIRST_STAGE = 1
Expand Down
Loading