From 3ad7b968370279f284952ab09de0a12708505afd Mon Sep 17 00:00:00 2001 From: Jacob Coffee Date: Tue, 8 Oct 2024 15:28:50 -0500 Subject: [PATCH] fix: links are direct to asset (#2593) * fix: links are direct to assett Closes: #2577 * test: add them * chore: remove unused imports --- static/sass/style.css | 125 ++++++++++--- static/sass/style.scss | 166 +++++++++++++++-- templates/users/base.html | 3 +- templates/users/sponsorship_detail.html | 226 +++++++++++------------- users/tests/test_views.py | 33 +++- users/views.py | 1 + 6 files changed, 393 insertions(+), 161 deletions(-) diff --git a/static/sass/style.css b/static/sass/style.css index c3af6444f..09c849482 100644 --- a/static/sass/style.css +++ b/static/sass/style.css @@ -2350,7 +2350,7 @@ table tfoot { /* ! ===== Success Stories landing page ===== */ .featured-success-story { padding: 1.3125em 0; - background: center -230px no-repeat url('../img/success-glow2.png?1646853871') transparent; + background: center -230px no-repeat url('../img/success-glow2.png?1726783859') transparent; /*blockquote*/ } .featured-success-story img { padding: 10px 30px; } @@ -3354,11 +3354,11 @@ span.highlighted { .python .site-headline a:before { width: 290px; height: 82px; - content: url('../img/python-logo_print.png?1646853871'); } + content: url('../img/python-logo_print.png?1726783859'); } .psf .site-headline a:before { width: 334px; height: 82px; - content: url('../img/psf-logo_print.png?1646853871'); } } + content: url('../img/psf-logo_print.png?1726783859'); } } /* * When we want to review the markup for W3 and similar errors, turn some of these on * Uses :not selectors a bunch, so only modern browsers will support them @@ -3979,25 +3979,106 @@ span.highlighted { .hidden { display: none; } -#sponsorship-detail-container .info-cards { - display: flex; - width: 100%; - align-content: center; - flex-wrap: wrap; } -#sponsorship-detail-container .card { - flex: 1 0 48%; } -#sponsorship-detail-container .card-info { - margin: .5em .5em; - padding: 1em 1em; - border: 1px solid #caccce; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - -ms-border-radius: 6px; - -o-border-radius: 6px; - border-radius: 6px; - background: #e6e8ea; } - #sponsorship-detail-container .card-info h3 { - margin: 0; } +#sponsorship-detail-container { + max-width: 1200px; + margin: 0 auto; + padding: 2rem; } + #sponsorship-detail-container .info-cards { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1.5rem; } + @media (max-width: 768px) { + #sponsorship-detail-container .info-cards { + grid-template-columns: 1fr; } } + #sponsorship-detail-container .card { + background-color: #fff; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + padding: 0.75rem; } + #sponsorship-detail-container .card h3 { + margin-top: 0; + margin-bottom: 1rem; } + #sponsorship-detail-container .card ul li { + margin-bottom: 0.5rem; } + #sponsorship-detail-container .wide-column { + grid-column: 1 / -1; } + #sponsorship-detail-container .assets-list { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1rem; + margin-top: 1rem; } + #sponsorship-detail-container .asset-item { + background-color: #f8f9fa; + border: 1px solid #e9ecef; + border-radius: 6px; + padding: 1rem; } + #sponsorship-detail-container .asset-item h4 { + margin-top: 0; + margin-bottom: 0.5rem; + font-size: 1rem; } + #sponsorship-detail-container .asset-item p { + margin-bottom: 0.75rem; + font-size: 0.9rem; } + #sponsorship-detail-container .asset-item.incomplete { + border-left: 3px solid #dc3545; } + #sponsorship-detail-container .asset-item.fulfilled { + border-left: 3px solid #28a745; } + #sponsorship-detail-container .due-date { + font-weight: bold; + color: #dc3545; } + #sponsorship-detail-container .btn { + display: inline-block; + padding: 0.375rem 0.75rem; + font-size: 0.9rem; + text-align: center; + text-decoration: none; + border-radius: 4px; + transition: background-color 0.2s ease; } + #sponsorship-detail-container .btn-link { + color: #007bff; } + #sponsorship-detail-container .edit-all-assets { + margin-top: 1.5rem; + text-align: right; } + #sponsorship-detail-container .benefits-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 1rem; + margin-top: 1rem; } + #sponsorship-detail-container .benefit-item { + display: flex; + flex-direction: column; + background-color: #ffffff; + border: 1px solid #e9ecef; + border-radius: 4px; + padding: 0.75rem; + transition: background-color 0.2s ease; } + #sponsorship-detail-container .benefit-item:hover { + background-color: #f8f9fa; } + #sponsorship-detail-container .benefit-content { + flex-grow: 1; } + #sponsorship-detail-container .benefit-name { + display: block; + font-weight: 500; + font-size: 0.9rem; + line-height: 1.2; + margin-bottom: 0.25rem; } + #sponsorship-detail-container .benefit-description { + color: #6c757d; + cursor: help; + font-size: 0.8rem; } + #sponsorship-detail-container .benefit-category { + display: inline-block; + background-color: #e9ecef; + color: #495057; + font-size: 0.75rem; + padding: 0.25rem 0.5rem; + border-radius: 4px; + margin-top: 0.5rem; } + @media (max-width: 768px) { + #sponsorship-detail-container .info-cards { + grid-template-columns: 1fr; } + #sponsorship-detail-container .assets-list { + grid-template-columns: 1fr; } } #update-sponsorship-assets input { padding: 0.25em; diff --git a/static/sass/style.scss b/static/sass/style.scss index 4fd9a3efd..cb78d9a4d 100644 --- a/static/sass/style.scss +++ b/static/sass/style.scss @@ -2943,28 +2943,158 @@ $breakpoint-desktop: 1200px; #sponsorship-detail-container { - .info-cards { - display: flex; - width: 100%; - align-content: center; - flex-wrap: wrap; - } + max-width: 1200px; + margin: 0 auto; + padding: 2rem; - .card { - flex: 1 0 48%; - } + .info-cards { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1.5rem; + } - .card-info { - margin: .5em .5em; - padding: 1em 1em; - border: 1px solid $default-border-color; - @include border-radius(); - background: $grey-lightest; + @media (max-width: 768px) { + .info-cards { + grid-template-columns: 1fr; + } + } - h3 { - margin: 0; + + .card { + background-color: #fff; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); + padding: 0.75rem; + } + + .card h3 { + margin-top: 0; + margin-bottom: 1rem; + } + + .card ul li { + margin-bottom: 0.5rem; + } + + .wide-column { + grid-column: 1 / -1; + } + + .assets-list { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1rem; + margin-top: 1rem; + } + + .asset-item { + background-color: #f8f9fa; + border: 1px solid #e9ecef; + border-radius: 6px; + padding: 1rem; + } + + .asset-item h4 { + margin-top: 0; + margin-bottom: 0.5rem; + font-size: 1rem; + } + + .asset-item p { + margin-bottom: 0.75rem; + font-size: 0.9rem; + } + + .asset-item.incomplete { + border-left: 3px solid #dc3545; + } + + .asset-item.fulfilled { + border-left: 3px solid #28a745; + } + + .due-date { + font-weight: bold; + color: #dc3545; + } + + .btn { + display: inline-block; + padding: 0.375rem 0.75rem; + font-size: 0.9rem; + text-align: center; + text-decoration: none; + border-radius: 4px; + transition: background-color 0.2s ease; + } + + .btn-link { + color: #007bff; + } + + .edit-all-assets { + margin-top: 1.5rem; + text-align: right; + } + + .benefits-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 1rem; + margin-top: 1rem; + } + + .benefit-item { + display: flex; + flex-direction: column; + background-color: #ffffff; + border: 1px solid #e9ecef; + border-radius: 4px; + padding: 0.75rem; + transition: background-color 0.2s ease; + } + + .benefit-item:hover { + background-color: #f8f9fa; + } + + .benefit-content { + flex-grow: 1; + } + + .benefit-name { + display: block; + font-weight: 500; + font-size: 0.9rem; + line-height: 1.2; + margin-bottom: 0.25rem; + } + + .benefit-description { + color: #6c757d; + cursor: help; + font-size: 0.8rem; + } + + .benefit-category { + display: inline-block; + background-color: #e9ecef; + color: #495057; + font-size: 0.75rem; + padding: 0.25rem 0.5rem; + border-radius: 4px; + margin-top: 0.5rem; + } + + @media (max-width: 768px) { + .info-cards { + grid-template-columns: 1fr; + } + + .assets-list { + grid-template-columns: 1fr; + } } - } } #update-sponsorship-assets { diff --git a/templates/users/base.html b/templates/users/base.html index f4e217675..5c11bb471 100644 --- a/templates/users/base.html +++ b/templates/users/base.html @@ -10,7 +10,8 @@ {% endblock %} -{% block content_attributes %}with-right-sidebar{% endblock %} +{# This added an unnecessarily large gap on every user/ page. #} +{#{% block content_attributes %}with-right-sidebar{% endblock %}#} {% block content %} diff --git a/templates/users/sponsorship_detail.html b/templates/users/sponsorship_detail.html index 447b4245c..a2d587d89 100644 --- a/templates/users/sponsorship_detail.html +++ b/templates/users/sponsorship_detail.html @@ -2,11 +2,11 @@ {% load humanize pipeline %} {% block head %} - {% stylesheet 'font-awesome' %} + {% stylesheet 'font-awesome' %} {% endblock %} {% block page_title %} - {{ sponsorship.sponsor.name }} Sponsorship Application | {{ SITE_INFO.site_name }} + {{ sponsorship.sponsor.name }} Sponsorship Application | {{ SITE_INFO.site_name }} {% endblock %} {% block body_attributes %}class="psf signup default-page"{% endblock %} @@ -15,131 +15,119 @@ {% block main-nav_attributes %}psf-navigation{% endblock %} {% block user_content %} -
-

{{ sponsorship.sponsor.name }} Sponsorship Application

+
+

{{ sponsorship.sponsor.name }} Sponsorship Application

-
+
+ -
- +
+

Application Data

+
    +
  • Status: {{ sponsorship.get_status_display }}
  • +
  • Application date: {{ sponsorship.applied_on|default_if_none:"---" }}
  • +
  • Approval date: {{ sponsorship.approved_on|default_if_none:"---" }}
  • +
  • Start date: {{ sponsorship.start_date|default_if_none:"---" }}
  • +
  • End date: {{ sponsorship.end_date|default_if_none:"---" }}
  • + {% if sponsorship.finalized_on %} +
  • Finalized date: {{ sponsorship.finalized_on }}
  • + {% endif %} +
  • Level: {{ sponsorship.level_name }}
  • +
  • Agreed sponsorship fee: {% if sponsorship.agreed_fee %}$ + {{ sponsorship.agreed_fee|intcomma }}{% else %}To be determined{% endif %}
  • +
+
-
-

Application Data

-
    -
  • - Status: {{ sponsorship.get_status_display }} -
  • -
  • - Application date: {{ sponsorship.applied_on|default_if_none:"---" }} -
  • -
  • - Approval date: {{ sponsorship.approved_on|default_if_none:"---" }} -
  • -
  • - Start date: {{ sponsorship.start_date|default_if_none:"---" }} -
  • -
  • - End date: {{ sponsorship.end_date|default_if_none:"---" }} -
  • - {% if sponsorship.finalized_on %} -
  • - Finalized date: {{ sponsorship.finalized_on }} -
  • + {% if provided_assets %} +
    +

    Provided Assets

    +

    Assets from the PSF related to your sponsorship.

    +
      + {% for asset in provided_assets %} +

      {{ asset.sponsor_benefit }} benefit provides you with {{ asset.label }}:

      + {% if asset.polymorphic_ctype.name == "Provided Text" %} +
      {{ asset.value|urlize }}
      + {% elif asset.polymorphic_ctype.name == "Provided File" %} + View File + {% else %} + {{ asset.value }} + {% endif %} + {{ asset.help_text }} +

      + {% endfor %} +
    + View all + assets +
    {% endif %} -
  • - Level: {{ sponsorship.level_name }} -
  • -
  • - Agreed sponsorship fee: {% if sponsorship.agreed_fee %}${{ sponsorship.agreed_fee|intcomma }}{% else %} - To - be determined{% endif %} -
  • -
-
- -
- -
- {% if required_assets or fulfilled_assets %} -
-

Required Assets

-

You've selected benefits which requires extra assets (logos, slides etc) in order to be fulfilled.

-
-
    - {% for asset in required_assets %} -
  • {{ asset.label }}
    Incomplete{% if asset.due_date %} Required by {{ asset.due_date }}{% endif %}: Add asset.
  • - {% endfor %} - {% for asset in fulfilled_assets %} -
  • {{ asset.label }}
    Fulfilled: Edit asset.
  • - {% endfor %} -
-
- Or you can also click here to edit all the assets under the same page. -
- {% endif %} - {% if provided_assets %} -
-

Provided Assets

-

Assets from the PSF related to your sponsorship.

-
-
    - {% for asset in provided_assets %} -
  • {{ asset.label }}: View asset.
  • - {% endfor %} -
-
- Or you can also click here to view all the assets under the same page. -
- {% endif %} + {% if required_assets or fulfilled_assets %} +
+

Required Assets

+

You've selected benefits which require extra assets (logos, slides etc) in order to be + fulfilled.

+
+ {% for asset in required_assets %} +
+

{{ asset.label }}

+

Incomplete{% if asset.due_date %} - + Required by {{ asset.due_date }}{% endif %}

+ Add asset +
+ {% endfor %} + {% for asset in fulfilled_assets %} +
+

{{ asset.label }}

+

Fulfilled

+ Edit asset +
+ {% endfor %} +
+ +
+ {% endif %} -
-

Sponsorship Benefits

-
    - {% for benefit in sponsorship.benefits.all %} -
  • - {% if benefit.description %} - - {% endif %} {{ benefit.name_for_display }} -
  • - {% endfor %} -
+
+

Sponsorship Benefits

+
+ {% for benefit in sponsorship.benefits.all %} +
+
+ {{ benefit.name_for_display }} + {% if benefit.description %} + + + + {% endif %} + {{ benefit.program.name }} +
+
+ {% endfor %} +
+
-
-
{% endblock %} {% block javascript %} - {{ block.super }} - {% javascript 'sponsors' %} -{% endblock %} + {{ block.super }} + {% javascript 'sponsors' %} +{% endblock %} \ No newline at end of file diff --git a/users/tests/test_views.py b/users/tests/test_views.py index 83b8330f9..28fc649ca 100644 --- a/users/tests/test_views.py +++ b/users/tests/test_views.py @@ -1,8 +1,9 @@ +from django.core.files.uploadedfile import SimpleUploadedFile from model_bakery import baker from django.conf import settings from django.contrib.auth import get_user_model from django.urls import reverse -from django.test import TestCase, override_settings +from django.test import TestCase from sponsors.forms import SponsorUpdateForm, SponsorRequiredAssetsForm from sponsors.models import Sponsorship, RequiredTextAssetConfiguration, SponsorBenefit @@ -448,6 +449,36 @@ def test_fulfilled_assets(self): self.assertEqual(1, len(context["fulfilled_assets"])) self.assertIn(asset, context["fulfilled_assets"]) + def test_asset_links_are_direct(self) -> None: + """Ensure that assets listed under 'Provided Assets' in `/users/sponsorships/#/` are directly accessible.""" + # Create a sponsorship with a provided file asset + cfg = baker.make( + "sponsors.ProvidedFileAssetConfiguration", + internal_name="test_provided_file_asset", + related_to="sponsorship", + ) + benefit = baker.make("sponsors.SponsorBenefit",sponsorship=self.sponsorship) + asset = cfg.create_benefit_feature(benefit) + file_content = b"This is a test file." + test_file = SimpleUploadedFile( + "test_file.pdf", + file_content, + content_type="application/pdf" + ) + asset.value = test_file + asset.save() + + # Then we can read the page + response = self.client.get(self.url) + content = response.content.decode("utf-8") + expected_asset_link = f'href="{asset.value.url}"' + + # and finally check that the asset link is ACTUALLY pointing to the asset and not the list view page + self.assertIn("View File", content, "View file text not found.") + self.assertIn(expected_asset_link, content, "Asset link not found in the page.") + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "users/sponsorship_detail.html") + class UpdateSponsorInfoViewTests(TestCase): diff --git a/users/views.py b/users/views.py index 23140853e..f73172296 100644 --- a/users/views.py +++ b/users/views.py @@ -324,6 +324,7 @@ def form_valid(self, form): @method_decorator(login_required(login_url=settings.LOGIN_URL), name="dispatch") class ProvidedSponsorshipAssetsView(DetailView): + """TODO: Deprecate this view now that everything lives in the SponsorshipDetailView""" object_name = "sponsorship" template_name = 'users/sponsorship_assets_view.html'