Skip to content
Open
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
11 changes: 5 additions & 6 deletions hypha/apply/activity/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,13 @@ def get_related_activities_for_user(obj, user):
Returns:
[`Activity`][hypha.apply.activity.models.Activity] queryset
"""
if hasattr(obj, "project") and obj.project:
if (
obj.co_applicants.filter(user=user).exists()
and not obj.co_applicants.filter(user=user).first().project_permission
):
if hasattr(obj, "projects"):
# obj is an ApplicationSubmission, which may have several projects.
co_applicant = obj.co_applicants.filter(user=user).first()
if co_applicant and not co_applicant.project_permission:
source_filter = Q(submission=obj)
else:
source_filter = Q(submission=obj) | Q(project=obj.project)
source_filter = Q(submission=obj) | Q(project__in=obj.projects.all())
elif hasattr(obj, "submission") and obj.submission:
source_filter = Q(submission=obj.submission) | Q(project=obj)
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
{% trans "Project documents are ready to be assigned for approval." %}

{% trans "Title" %}: {{ source.title_text_display }}
{% trans "Link" %}: {{ request.scheme }}://{{ request.get_host }}{% url 'apply:projects:approval' pk=source.submission.pk %}
{% trans "Link" %}: {{ request.scheme }}://{{ request.get_host }}{% url 'apply:projects:approval' pk=source.pk %}

{% blocktrans with lead=source.lead email=source.lead.email %}Please contact {{ lead }} - {{ email }} if you have any questions.{% endblocktrans %}
{% endblock %}{# fmt:on #}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
{% block content %}{# fmt:off #}
{% blocktrans with title=source.title_text_display %}The {{ title }} project is awaiting your review.{% endblocktrans %}

{% trans "View the project here" %}: {{ request.scheme }}://{{ request.get_host }}{% url 'apply:projects:approval' pk=source.submission.pk %}
{% trans "View the project here" %}: {{ request.scheme }}://{{ request.get_host }}{% url 'apply:projects:approval' pk=source.pk %}

{% blocktrans with lead=source.lead email=source.lead.email %}Please contact {{ lead }} - {{ email }} if you have any questions.{% endblocktrans %}
{% endblock %}{# fmt:on #}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
{% block content %}{# fmt:off #}
{% blocktrans with title=source.title_text_display %}The project "{{title}}" is awaiting final approval.{% endblocktrans %}

{% trans "Approve the project here" %}: {{ request.scheme }}://{{ request.get_host }}{% url 'apply:projects:approval' pk=source.submission.pk %}
{% trans "Approve the project here" %}: {{ request.scheme }}://{{ request.get_host }}{% url 'apply:projects:approval' pk=source.pk %}

{% blocktrans with lead=source.lead email=source.lead.email %}Please contact {{ lead }} - {{ email }} if you have any questions.{% endblocktrans %}
{% endblock %}{# fmt:on #}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
{% block content %}{# fmt:off #}
{% blocktrans with title=source.title_text_display %}The project "{{ title }}" is awaiting your review.{% endblocktrans %}

{% trans "View the project here" %}: {{ request.scheme }}://{{ request.get_host }}{% url 'apply:projects:approval' pk=source.submission.pk %}
{% trans "View the project here" %}: {{ request.scheme }}://{{ request.get_host }}{% url 'apply:projects:approval' pk=source.pk %}

{% blocktrans with lead=source.lead email=source.lead.email %}Please contact {{ lead }} - {{ email }} if you have any questions.{% endblocktrans %}
{% endblock %}{# fmt:on #}
32 changes: 18 additions & 14 deletions hypha/apply/determinations/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,10 @@ def test_first_stage_accepted_determination_does_not_create_project(self):

# Confirm a Project was not created for either submission since it's
# not in the final stage of its workflow.
self.assertFalse(hasattr(submission_original, "project"))
self.assertFalse(hasattr(submission_next, "project"))
self.assertFalse(submission_original.projects.exists())
self.assertFalse(
submission_next.projects.exists() if submission_next else False
)

def test_first_stage_rejected_determination_does_not_create_project(self):
submission = ApplicationSubmissionFactory(
Expand Down Expand Up @@ -232,7 +234,7 @@ def test_first_stage_rejected_determination_does_not_create_project(self):

# Confirm a Project was not created for the original
# ApplicationSubmission.
self.assertFalse(hasattr(submission_original, "project"))
self.assertFalse(submission_original.projects.exists())

def test_second_stage_accepted_determination_creates_project(self):
submission = ApplicationSubmissionFactory(
Expand Down Expand Up @@ -260,8 +262,10 @@ def test_second_stage_accepted_determination_creates_project(self):
# applications flow.
self.assertIsNone(submission_next)

self.assertTrue(hasattr(submission_original, "project"))
self.assertFalse(hasattr(submission_next, "project"))
self.assertTrue(submission_original.projects.exists())
self.assertFalse(
submission_next.projects.exists() if submission_next else False
)

def test_second_stage_rejected_determination_does_not_create_project(self):
submission = ApplicationSubmissionFactory(
Expand All @@ -288,7 +292,7 @@ def test_second_stage_rejected_determination_does_not_create_project(self):
# applications flow.
self.assertIsNone(submission_next)

self.assertFalse(hasattr(submission_original, "project"))
self.assertFalse(submission_original.projects.exists())

def test_single_stage_accepted_determination_creates_project(self):
submission = ApplicationSubmissionFactory(
Expand All @@ -312,7 +316,7 @@ def test_single_stage_accepted_determination_creates_project(self):
submission_next = submission_original.next

self.assertIsNone(submission_next)
self.assertTrue(hasattr(submission_original, "project"))
self.assertTrue(submission_original.projects.exists())

def test_single_stage_rejected_determination_does_not_create_project(self):
submission = ApplicationSubmissionFactory(
Expand All @@ -336,7 +340,7 @@ def test_single_stage_rejected_determination_does_not_create_project(self):
submission_next = submission_original.next

self.assertIsNone(submission_next)
self.assertFalse(hasattr(submission_original, "project"))
self.assertFalse(submission_original.projects.exists())

@override_settings(PROJECTS_DEFAULT_STATUS="contracting")
def test_auto_creation_uses_status_settings(self):
Expand All @@ -357,8 +361,8 @@ def test_auto_creation_uses_status_settings(self):
)

submission_original = self.refresh(submission)
self.assertTrue(hasattr(submission_original, "project"))
self.assertEqual(submission.project.status, CONTRACTING)
self.assertTrue(submission_original.projects.exists())
self.assertEqual(submission.projects.first().status, CONTRACTING)

@override_settings(PROJECTS_DEFAULT_STATUS="garbage")
def test_auto_creation_uses_draft_when_invalid_status_settings(self):
Expand All @@ -379,8 +383,8 @@ def test_auto_creation_uses_draft_when_invalid_status_settings(self):
)

submission_original = self.refresh(submission)
self.assertTrue(hasattr(submission_original, "project"))
self.assertEqual(submission.project.status, DRAFT)
self.assertTrue(submission_original.projects.exists())
self.assertEqual(submission.projects.first().status, DRAFT)

@override_settings(PROJECTS_AUTO_CREATE=False)
def test_disabling_project_auto_creation_stops_projects_being_created(self):
Expand All @@ -405,7 +409,7 @@ def test_disabling_project_auto_creation_stops_projects_being_created(self):
submission_next = submission_original.next

self.assertIsNone(submission_next)
self.assertFalse(hasattr(submission_original, "project"))
self.assertFalse(submission_original.projects.exists())

@override_settings(PROJECTS_ENABLED=False, PROJECTS_AUTO_CREATE=True)
def test_disabling_projects_ignores_auto_creation_setting(self):
Expand All @@ -430,7 +434,7 @@ def test_disabling_projects_ignores_auto_creation_setting(self):
submission_next = submission_original.next

self.assertIsNone(submission_next)
self.assertFalse(hasattr(submission_original, "project"))
self.assertFalse(submission_original.projects.exists())


class BatchDeterminationTestCase(BaseViewTestCase):
Expand Down
6 changes: 5 additions & 1 deletion hypha/apply/determinations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,11 @@ def form_valid(self, form):
proposal_form=proposal_form,
)

if self.submission.accepted_for_funding and settings.PROJECTS_AUTO_CREATE:
if (
self.submission.accepted_for_funding
and settings.PROJECTS_AUTO_CREATE
and not self.submission.projects.exists()
):
Project.create_from_submission(self.submission)
messages.success(
self.request, _("A project was automatically created.")
Expand Down
4 changes: 2 additions & 2 deletions hypha/apply/funds/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ def __init__(self, *args, submission, user=None, **kwargs):

if submission:
self.fields["submission"].initial = submission.id
if not hasattr(submission, "project"):
if not submission.projects.exists():
self.fields.pop("project_permission", None)

class Meta:
Expand All @@ -497,7 +497,7 @@ class EditCoApplicantForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
instance = kwargs.get("instance", None)
if not hasattr(instance.submission, "project"):
if not instance.submission.projects.exists():
self.fields.pop("project_permission", None)

class Meta:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@

{% block hero %}
<c-hero padding="pt-4">
{% if object.project %}
{% include "application_projects/includes/project_header.html" with object=object.project %}
{% else %}
{% include "funds/includes/application_header.html" %}
{% endif %}
{% include "funds/includes/application_header.html" %}

<div role="tablist" class="font-medium tabs tabs-lg tabs-lift text-base-content print-hidden">
<a
Expand All @@ -22,16 +18,8 @@
{% trans "Application" %}
</a>

{% if PROJECTS_ENABLED and object.project %}
{% user_can_access_project object.project user as can_access_project %}
{% if can_access_project %}
<a
class="tab [--color-base-content:var(--color-neutral-content)]"
href="{% url 'funds:submissions:project' pk=object.id %}"
>
{% trans "Project" %}
</a>
{% endif %}
{% if PROJECTS_ENABLED %}
{% include "funds/includes/projects_tab.html" with submission=object user=user %}
{% endif %}

<a
Expand Down
20 changes: 4 additions & 16 deletions hypha/apply/funds/templates/funds/comments.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@

{% block hero %}
<c-hero padding="pt-4">
{% if object.project %}
{% include "application_projects/includes/project_header.html" with object=object.project %}
{% else %}
{% include "funds/includes/application_header.html" %}
{% endif %}
{% include "funds/includes/application_header.html" %}

<div role="tablist" class="font-medium tabs tabs-lg tabs-lift text-base-content print-hidden">
<a
Expand All @@ -18,16 +14,8 @@
{% trans "Application" %}
</a>

{% if PROJECTS_ENABLED and object.project %}
{% user_can_access_project object.project user as can_access_project %}
{% if can_access_project %}
<a
class="tab [--color-base-content:var(--color-neutral-content)]"
href="{% url 'funds:submissions:project' pk=object.id %}"
>
{% trans "Project" %}
</a>
{% endif %}
{% if PROJECTS_ENABLED %}
{% include "funds/includes/projects_tab.html" with submission=object user=user %}
{% endif %}

<a class="tab tab-active"
Expand All @@ -53,7 +41,7 @@
{% block content %}
<div class="my-4">
{% if form %}
{% if not object.is_archive or object.project %}
{% if not object.is_archive or object.projects.exists %}
<h2 class="sr-only">{% trans "Add communication" %}</h2>
<div class="pb-6 mb-4 w-full border-b border-base-300">
<form
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,18 @@ <h2 class="mb-2 card-title">{% trans "Actions to take" %}</h2>
</a>
{% else %}
<div class="flex flex-col gap-2">
{% if PROJECTS_ENABLED %}
{% if object.accepted_for_funding and not object.project %}
{% if PROJECTS_ENABLED and object.accepted_for_funding %}
{% if not object.projects.exists or PROJECTS_ALLOW_MULTIPLE %}
<button
class="btn btn-primary btn-block"
hx-get="{% url 'funds:submissions:create_project' pk=object.pk %}"
hx-target="#htmx-modal"
>
{% trans "Create project" %}
{% if object.projects.exists %}
{% trans "Add another project" %}
{% else %}
{% trans "Create project" %}
{% endif %}
</button>
{% endif %}
{% endif %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ <h2 class="card-title">

<div class="list">

{% if object.project %}
{% if object.projects.exists %}
<p class="mb-2 text-sm text-fg-muted">
{% trans "Project permissions are enabled and can be updated for each co-applicant." %}
</p>
Expand Down
53 changes: 53 additions & 0 deletions hypha/apply/funds/templates/funds/includes/projects_tab.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{% load i18n heroicons project_tags %}
{% comment %}
Renders the "Project(s)" tab inside a submission/project tablist.

Params:
submission – the ApplicationSubmission
user – the current user (for access filtering)
current_project – the project being viewed, if any (for active item highlight)
active – whether this tab is the active one
{% endcomment %}
Comment on lines +2 to +10

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this format of kinda docstringing a template! super useful when trying to track down what the variables used are & where they come from

{% accessible_projects submission user as projects %}
{% if projects %}
{% if projects|length == 1 %}
<a
class="tab {% if active %}tab-active{% else %}[--color-base-content:var(--color-neutral-content)]{% endif %}"
href="{{ projects.0.get_absolute_url }}"
>
{% trans "Project" %}
</a>
{% else %}
<div class="relative tab {% if active %}tab-active{% endif %}" x-data="{ open: false }">
<button
type="button"
class="flex gap-1 items-center cursor-pointer {% if not active %}text-neutral-content/50 hover:text-neutral-content{% endif %}"
@click="open = ! open"
@click.away="open = false"
@keydown.escape="open = false"
:aria-expanded="open"
>
{% blocktrans count counter=projects|length %}Project{% plural %}Projects ({{ counter }}){% endblocktrans %}
{% heroicon_micro "chevron-down" aria_hidden="true" size=16 class="inline-block size-4" %}
</button>
<ul
x-show="open"
x-cloak
x-transition.origin.top
role="menu"
class="absolute top-full z-20 mt-1 min-w-max border shadow-lg start-0 menu bg-base-100 rounded-box border-base-300 text-base-content"
>
{% for project in projects %}
<li>
<a
href="{{ project.get_absolute_url }}"
{% if current_project and project.pk == current_project.pk %}class="menu-active"{% endif %}
>
{{ project.title }}
</a>
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@
{% endif %}
{% endif %}

{% if s.project %}
• <a href="{% url "funds:submissions:project" s.id %}" class="link link-muted text-inherit">{% trans "Project" %}</a>
{% if s.projects.exists %}
• <a href="{% url "funds:submissions:projects" s.id %}" class="link link-muted text-inherit">{% trans "Project" %}</a>
{% endif %}
</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
#{{ s.application_id }}
submitted <relative-time datetime="{{ s.submit_time|date:"c" }}">{{ s.submit_time|date:"SHORT_DATE_FORMAT" }}</relative-time>
• {{ s.stage }}
{% if s.project %}
• <a href="{% url "funds:submissions:project" s.id %}" class="link link-muted text-inherit">{% trans "Project" %}</a>
{% if s.projects.exists %}
• <a href="{% url "funds:submissions:projects" s.id %}" class="link link-muted text-inherit">{% trans "Project" %}</a>
{% endif %}
</div>
</td>
Expand Down
Loading