From f347ff9c7f8e8ec776673e240fa0725fc8dcb72c Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 16 Jul 2024 10:42:34 -0600 Subject: [PATCH 01/40] Add endpoint for report --- src/registrar/config/urls.py | 6 ++++++ src/registrar/templates/home.html | 4 +--- src/registrar/utility/csv_export.py | 33 +++++++++++++++++++++-------- src/registrar/views/admin_views.py | 16 ++++++++++---- 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py index 2e5a531d1..2091b026c 100644 --- a/src/registrar/config/urls.py +++ b/src/registrar/config/urls.py @@ -19,6 +19,7 @@ from registrar.views.admin_views import ( ExportDataUnmanagedDomains, AnalyticsView, ExportDomainRequestDataFull, + ExportDataTypeUser, ) from registrar.views.domain_request import Step @@ -119,6 +120,11 @@ urlpatterns = [ name="analytics", ), path("admin/", admin.site.urls), + path( + "reports/export_data_type_user/", + ExportDataTypeUser.as_view(), + name="export_data_type_user", + ), path( "domain-request//edit/", views.DomainRequestWizard.as_view(), diff --git a/src/registrar/templates/home.html b/src/registrar/templates/home.html index a5ed4c86c..07148c632 100644 --- a/src/registrar/templates/home.html +++ b/src/registrar/templates/home.html @@ -40,15 +40,13 @@ --> - - {% endblock %} diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 334742d17..fe38bdb25 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -108,7 +108,7 @@ class BaseExport(ABC): return Q() @classmethod - def get_filter_conditions(cls, start_date=None, end_date=None): + def get_filter_conditions(cls, request=None, start_date=None, end_date=None): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -191,7 +191,7 @@ class BaseExport(ABC): return cls.update_queryset(queryset, **kwargs) @classmethod - def export_data_to_csv(cls, csv_file, start_date=None, end_date=None): + def export_data_to_csv(cls, csv_file, request=None, start_date=None, end_date=None): """ All domain metadata: Exports domains of all statuses plus domain managers. @@ -204,7 +204,7 @@ class BaseExport(ABC): prefetch_related = cls.get_prefetch_related() exclusions = cls.get_exclusions() annotations_for_sort = cls.get_annotations_for_sort() - filter_conditions = cls.get_filter_conditions(start_date, end_date) + filter_conditions = cls.get_filter_conditions(request, start_date, end_date) computed_fields = cls.get_computed_fields() related_table_fields = cls.get_related_table_fields() @@ -543,6 +543,21 @@ class DomainDataType(DomainExport): "federal_agency__agency", ] +class DomainDataTypeUser(DomainDataType): + """ + The DomainDataType report, but sliced on the current request user + """ + + @classmethod + def get_filter_conditions(cls, request=None, start_date=None, end_date=None): + """ + Get a Q object of filter conditions to filter when building queryset. + """ + user_domain_roles = UserDomainRole.objects.filter(user=request.user) + domain_ids = user_domain_roles.values_list("domain_id", flat=True) + return Q(id__in=domain_ids) + + class DomainDataFull(DomainExport): """ @@ -601,7 +616,7 @@ class DomainDataFull(DomainExport): return ["domain"] @classmethod - def get_filter_conditions(cls, start_date=None, end_date=None): + def get_filter_conditions(cls, request=None, start_date=None, end_date=None): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -696,7 +711,7 @@ class DomainDataFederal(DomainExport): return ["domain"] @classmethod - def get_filter_conditions(cls, start_date=None, end_date=None): + def get_filter_conditions(cls, request=None, start_date=None, end_date=None): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -794,7 +809,7 @@ class DomainGrowth(DomainExport): return ["domain"] @classmethod - def get_filter_conditions(cls, start_date=None, end_date=None): + def get_filter_conditions(cls, request=None, start_date=None, end_date=None): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -866,7 +881,7 @@ class DomainManaged(DomainExport): return ["permissions"] @classmethod - def get_filter_conditions(cls, start_date=None, end_date=None): + def get_filter_conditions(cls, request=None, start_date=None, end_date=None): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -1001,7 +1016,7 @@ class DomainUnmanaged(DomainExport): return ["permissions"] @classmethod - def get_filter_conditions(cls, start_date=None, end_date=None): + def get_filter_conditions(cls, request=None, start_date=None, end_date=None): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -1231,7 +1246,7 @@ class DomainRequestGrowth(DomainRequestExport): ] @classmethod - def get_filter_conditions(cls, start_date=None, end_date=None): + def get_filter_conditions(cls, request=None, start_date=None, end_date=None): """ Get a Q object of filter conditions to filter when building queryset. """ diff --git a/src/registrar/views/admin_views.py b/src/registrar/views/admin_views.py index 4d015ab37..af05330a4 100644 --- a/src/registrar/views/admin_views.py +++ b/src/registrar/views/admin_views.py @@ -157,6 +157,14 @@ class ExportDataType(View): csv_export.DomainDataType.export_data_to_csv(response) return response +class ExportDataTypeUser(View): + """Returns a domain report for a given user on the request""" + def get(self, request, *args, **kwargs): + # match the CSV example with all the fields + response = HttpResponse(content_type="text/csv") + response["Content-Disposition"] = 'attachment; filename="your-domains.csv"' + csv_export.DomainDataTypeUser.export_data_to_csv(response, request) + return response class ExportDataFull(View): def get(self, request, *args, **kwargs): @@ -194,7 +202,7 @@ class ExportDataDomainsGrowth(View): response = HttpResponse(content_type="text/csv") response["Content-Disposition"] = f'attachment; filename="domain-growth-report-{start_date}-to-{end_date}.csv"' - csv_export.DomainGrowth.export_data_to_csv(response, start_date, end_date) + csv_export.DomainGrowth.export_data_to_csv(response, start_date=start_date, end_date=end_date) return response @@ -206,7 +214,7 @@ class ExportDataRequestsGrowth(View): response = HttpResponse(content_type="text/csv") response["Content-Disposition"] = f'attachment; filename="requests-{start_date}-to-{end_date}.csv"' - csv_export.DomainRequestGrowth.export_data_to_csv(response, start_date, end_date) + csv_export.DomainRequestGrowth.export_data_to_csv(response, start_date=start_date, end_date=end_date) return response @@ -217,7 +225,7 @@ class ExportDataManagedDomains(View): end_date = request.GET.get("end_date", "") response = HttpResponse(content_type="text/csv") response["Content-Disposition"] = f'attachment; filename="managed-domains-{start_date}-to-{end_date}.csv"' - csv_export.DomainManaged.export_data_to_csv(response, start_date, end_date) + csv_export.DomainManaged.export_data_to_csv(response, start_date=start_date, end_date=end_date) return response @@ -228,6 +236,6 @@ class ExportDataUnmanagedDomains(View): end_date = request.GET.get("end_date", "") response = HttpResponse(content_type="text/csv") response["Content-Disposition"] = f'attachment; filename="unmanaged-domains-{start_date}-to-{end_date}.csv"' - csv_export.DomainUnmanaged.export_data_to_csv(response, start_date, end_date) + csv_export.DomainUnmanaged.export_data_to_csv(response, start_date=start_date, end_date=end_date) return response From 728a248d91387b5e099bed1b83189cd71a6a286a Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:15:14 -0600 Subject: [PATCH 02/40] Minor refactor --- src/registrar/utility/csv_export.py | 34 +++++++++++++++++++---------- src/registrar/views/admin_views.py | 3 ++- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index fe38bdb25..862f23876 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -108,7 +108,7 @@ class BaseExport(ABC): return Q() @classmethod - def get_filter_conditions(cls, request=None, start_date=None, end_date=None): + def get_filter_conditions(cls, **export_kwargs): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -144,7 +144,7 @@ class BaseExport(ABC): return queryset @classmethod - def write_csv_before(cls, csv_writer, start_date=None, end_date=None): + def write_csv_before(cls, csv_writer, **export_kwargs): """ Write to csv file before the write_csv method. Override in subclasses where needed. @@ -191,7 +191,7 @@ class BaseExport(ABC): return cls.update_queryset(queryset, **kwargs) @classmethod - def export_data_to_csv(cls, csv_file, request=None, start_date=None, end_date=None): + def export_data_to_csv(cls, csv_file, **export_kwargs): """ All domain metadata: Exports domains of all statuses plus domain managers. @@ -204,7 +204,7 @@ class BaseExport(ABC): prefetch_related = cls.get_prefetch_related() exclusions = cls.get_exclusions() annotations_for_sort = cls.get_annotations_for_sort() - filter_conditions = cls.get_filter_conditions(request, start_date, end_date) + filter_conditions = cls.get_filter_conditions(**export_kwargs) computed_fields = cls.get_computed_fields() related_table_fields = cls.get_related_table_fields() @@ -226,7 +226,7 @@ class BaseExport(ABC): models_dict = convert_queryset_to_dict(annotated_queryset, is_model=False) # Write to csv file before the write_csv - cls.write_csv_before(writer, start_date, end_date) + cls.write_csv_before(writer, **export_kwargs) # Write the csv file cls.write_csv(writer, columns, models_dict) @@ -273,6 +273,11 @@ class DomainExport(BaseExport): Second class in an inheritance tree of 3. """ + @classmethod + def export_data_to_csv(cls, csv_file, start_date=None, end_date=None): + """Pass in the start_date and end_date variables to the report""" + super().export_data_to_csv(csv_file, start_date=start_date, end_date=end_date) + @classmethod def model(cls): # Return the model class that this export handles @@ -549,7 +554,12 @@ class DomainDataTypeUser(DomainDataType): """ @classmethod - def get_filter_conditions(cls, request=None, start_date=None, end_date=None): + def export_data_to_csv(cls, csv_file, request=None): + """Pass in the start_date and end_date variables to the report""" + super().export_data_to_csv(csv_file, request=request) + + @classmethod + def get_filter_conditions(cls, request=None): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -616,7 +626,7 @@ class DomainDataFull(DomainExport): return ["domain"] @classmethod - def get_filter_conditions(cls, request=None, start_date=None, end_date=None): + def get_filter_conditions(cls): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -711,7 +721,7 @@ class DomainDataFederal(DomainExport): return ["domain"] @classmethod - def get_filter_conditions(cls, request=None, start_date=None, end_date=None): + def get_filter_conditions(cls): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -809,7 +819,7 @@ class DomainGrowth(DomainExport): return ["domain"] @classmethod - def get_filter_conditions(cls, request=None, start_date=None, end_date=None): + def get_filter_conditions(cls, start_date=None, end_date=None): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -881,7 +891,7 @@ class DomainManaged(DomainExport): return ["permissions"] @classmethod - def get_filter_conditions(cls, request=None, start_date=None, end_date=None): + def get_filter_conditions(cls, start_date=None, end_date=None): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -1016,7 +1026,7 @@ class DomainUnmanaged(DomainExport): return ["permissions"] @classmethod - def get_filter_conditions(cls, request=None, start_date=None, end_date=None): + def get_filter_conditions(cls, start_date=None, end_date=None): """ Get a Q object of filter conditions to filter when building queryset. """ @@ -1246,7 +1256,7 @@ class DomainRequestGrowth(DomainRequestExport): ] @classmethod - def get_filter_conditions(cls, request=None, start_date=None, end_date=None): + def get_filter_conditions(cls, start_date=None, end_date=None): """ Get a Q object of filter conditions to filter when building queryset. """ diff --git a/src/registrar/views/admin_views.py b/src/registrar/views/admin_views.py index af05330a4..aa67d88bd 100644 --- a/src/registrar/views/admin_views.py +++ b/src/registrar/views/admin_views.py @@ -163,7 +163,7 @@ class ExportDataTypeUser(View): # match the CSV example with all the fields response = HttpResponse(content_type="text/csv") response["Content-Disposition"] = 'attachment; filename="your-domains.csv"' - csv_export.DomainDataTypeUser.export_data_to_csv(response, request) + csv_export.DomainDataTypeUser.export_data_to_csv(response, request=request) return response class ExportDataFull(View): @@ -225,6 +225,7 @@ class ExportDataManagedDomains(View): end_date = request.GET.get("end_date", "") response = HttpResponse(content_type="text/csv") response["Content-Disposition"] = f'attachment; filename="managed-domains-{start_date}-to-{end_date}.csv"' + # Note: start_date doesn't appear to be used in the underlying report - is ths intentional? csv_export.DomainManaged.export_data_to_csv(response, start_date=start_date, end_date=end_date) return response From c5654abd7eaca9285de43c5c0d8a29d77cb458ea Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:26:25 -0600 Subject: [PATCH 03/40] Update csv_export.py --- src/registrar/utility/csv_export.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 862f23876..8054d28a7 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -273,11 +273,6 @@ class DomainExport(BaseExport): Second class in an inheritance tree of 3. """ - @classmethod - def export_data_to_csv(cls, csv_file, start_date=None, end_date=None): - """Pass in the start_date and end_date variables to the report""" - super().export_data_to_csv(csv_file, start_date=start_date, end_date=end_date) - @classmethod def model(cls): # Return the model class that this export handles @@ -553,11 +548,6 @@ class DomainDataTypeUser(DomainDataType): The DomainDataType report, but sliced on the current request user """ - @classmethod - def export_data_to_csv(cls, csv_file, request=None): - """Pass in the start_date and end_date variables to the report""" - super().export_data_to_csv(csv_file, request=request) - @classmethod def get_filter_conditions(cls, request=None): """ @@ -568,7 +558,6 @@ class DomainDataTypeUser(DomainDataType): return Q(id__in=domain_ids) - class DomainDataFull(DomainExport): """ Shows security contacts, filtered by state From 5e1b58823c8ace6e4f149f0a7d7ee9644b8afb63 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:27:34 -0600 Subject: [PATCH 04/40] Link to button --- src/registrar/templates/home.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/home.html b/src/registrar/templates/home.html index 07148c632..a2ede61d4 100644 --- a/src/registrar/templates/home.html +++ b/src/registrar/templates/home.html @@ -43,7 +43,7 @@

Export domains

Download a list of your domains and their statuses as a csv file.

- + Export domains as csv
From 3372c02d1a2e225727ed3289662171ab58532fe9 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:04:44 -0600 Subject: [PATCH 05/40] Add button --- src/registrar/assets/sass/_theme/_base.scss | 6 +++++ .../assets/sass/_theme/_buttons.scss | 3 +-- src/registrar/templates/home.html | 9 -------- .../templates/includes/domains_table.html | 23 +++++++++++++++++++ 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/registrar/assets/sass/_theme/_base.scss b/src/registrar/assets/sass/_theme/_base.scss index b2bad1edb..cc060ee01 100644 --- a/src/registrar/assets/sass/_theme/_base.scss +++ b/src/registrar/assets/sass/_theme/_base.scss @@ -223,3 +223,9 @@ abbr[title] { .padding--8-8-9 { padding: 8px 8px 9px !important; } + +.usa-icon.usa-icon--big { + margin: 0; + height: 1.5em; + width: 1.5em; +} \ No newline at end of file diff --git a/src/registrar/assets/sass/_theme/_buttons.scss b/src/registrar/assets/sass/_theme/_buttons.scss index 92556556b..94eaecc3d 100644 --- a/src/registrar/assets/sass/_theme/_buttons.scss +++ b/src/registrar/assets/sass/_theme/_buttons.scss @@ -175,5 +175,4 @@ a.usa-button--unstyled:visited { &:hover { box-shadow: none; } -} - \ No newline at end of file +} \ No newline at end of file diff --git a/src/registrar/templates/home.html b/src/registrar/templates/home.html index a2ede61d4..33329c268 100644 --- a/src/registrar/templates/home.html +++ b/src/registrar/templates/home.html @@ -39,15 +39,6 @@

You don't have any archived domains

--> - -
-

Export domains

-

Download a list of your domains and their statuses as a csv file.

- - Export domains as csv - -
- {% endblock %} diff --git a/src/registrar/templates/includes/domains_table.html b/src/registrar/templates/includes/domains_table.html index 8fbfd44e8..dd8201ce3 100644 --- a/src/registrar/templates/includes/domains_table.html +++ b/src/registrar/templates/includes/domains_table.html @@ -32,6 +32,17 @@ + {% if portfolio %} +
+
+ + Export as csv + +
+
+ {% endif %} {% if portfolio %}
@@ -167,6 +178,18 @@ + + {% if not portfolio %} + + {% endif %}