mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-15 17:17:02 +02:00
Merge pull request #2463 from cisagov/za/2323-domain-manager-csv-export
Ticket #2323: Domain manager csv export
This commit is contained in:
commit
279fca4979
8 changed files with 173 additions and 44 deletions
|
@ -72,6 +72,29 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.section--outlined__header--no-portfolio {
|
||||||
|
.section--outlined__search,
|
||||||
|
.section--outlined__utility-button {
|
||||||
|
margin-top: units(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include at-media(tablet) {
|
||||||
|
display: flex;
|
||||||
|
column-gap: units(3);
|
||||||
|
|
||||||
|
.section--outlined__search,
|
||||||
|
.section--outlined__utility-button {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.section--outlined__search {
|
||||||
|
flex-grow: 4;
|
||||||
|
// Align right
|
||||||
|
max-width: 383px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.break-word {
|
.break-word {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,4 +204,13 @@ a.usa-button--unstyled:visited {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.usa-icon.usa-icon--big {
|
||||||
|
margin: 0;
|
||||||
|
height: 1.5em;
|
||||||
|
width: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.margin-right-neg-4px {
|
||||||
|
margin-right: -4px;
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django.urls import include, path
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
|
|
||||||
from registrar import views
|
from registrar import views
|
||||||
from registrar.views.admin_views import (
|
from registrar.views.report_views import (
|
||||||
ExportDataDomainsGrowth,
|
ExportDataDomainsGrowth,
|
||||||
ExportDataFederal,
|
ExportDataFederal,
|
||||||
ExportDataFull,
|
ExportDataFull,
|
||||||
|
@ -19,6 +19,7 @@ from registrar.views.admin_views import (
|
||||||
ExportDataUnmanagedDomains,
|
ExportDataUnmanagedDomains,
|
||||||
AnalyticsView,
|
AnalyticsView,
|
||||||
ExportDomainRequestDataFull,
|
ExportDomainRequestDataFull,
|
||||||
|
ExportDataTypeUser,
|
||||||
)
|
)
|
||||||
|
|
||||||
from registrar.views.domain_request import Step
|
from registrar.views.domain_request import Step
|
||||||
|
@ -124,6 +125,11 @@ urlpatterns = [
|
||||||
name="analytics",
|
name="analytics",
|
||||||
),
|
),
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
|
path(
|
||||||
|
"reports/export_data_type_user/",
|
||||||
|
ExportDataTypeUser.as_view(),
|
||||||
|
name="export_data_type_user",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"domain-request/<id>/edit/",
|
"domain-request/<id>/edit/",
|
||||||
views.DomainRequestWizard.as_view(),
|
views.DomainRequestWizard.as_view(),
|
||||||
|
|
|
@ -170,18 +170,11 @@ class CreateOrUpdateOrganizationTypeHelper:
|
||||||
# There is no avenue for this to occur in the UI,
|
# There is no avenue for this to occur in the UI,
|
||||||
# as such - this can only occur if the object is initialized in this way.
|
# as such - this can only occur if the object is initialized in this way.
|
||||||
# Or if there are pre-existing data.
|
# Or if there are pre-existing data.
|
||||||
logger.debug(
|
|
||||||
"create_or_update_organization_type() -> is_election_board "
|
|
||||||
f"cannot exist for {generic_org_type}. Setting to None."
|
|
||||||
)
|
|
||||||
self.instance.is_election_board = None
|
self.instance.is_election_board = None
|
||||||
self.instance.organization_type = generic_org_type
|
self.instance.organization_type = generic_org_type
|
||||||
else:
|
else:
|
||||||
# This can only happen with manual data tinkering, which causes these to be out of sync.
|
# This can only happen with manual data tinkering, which causes these to be out of sync.
|
||||||
if self.instance.is_election_board is None:
|
if self.instance.is_election_board is None:
|
||||||
logger.warning(
|
|
||||||
"create_or_update_organization_type() -> is_election_board is out of sync. Updating value."
|
|
||||||
)
|
|
||||||
self.instance.is_election_board = False
|
self.instance.is_election_board = False
|
||||||
|
|
||||||
if self.instance.is_election_board:
|
if self.instance.is_election_board:
|
||||||
|
@ -218,10 +211,6 @@ class CreateOrUpdateOrganizationTypeHelper:
|
||||||
# There is no avenue for this to occur in the UI,
|
# There is no avenue for this to occur in the UI,
|
||||||
# as such - this can only occur if the object is initialized in this way.
|
# as such - this can only occur if the object is initialized in this way.
|
||||||
# Or if there are pre-existing data.
|
# Or if there are pre-existing data.
|
||||||
logger.warning(
|
|
||||||
"create_or_update_organization_type() -> is_election_board "
|
|
||||||
f"cannot exist for {current_org_type}. Setting to None."
|
|
||||||
)
|
|
||||||
self.instance.is_election_board = None
|
self.instance.is_election_board = None
|
||||||
else:
|
else:
|
||||||
# if self.instance.organization_type is set to None, then this means
|
# if self.instance.organization_type is set to None, then this means
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
<section class="section--outlined domains{% if portfolio is not None %} margin-top-0{% endif %}" id="domains">
|
<section class="section--outlined domains{% if portfolio is not None %} margin-top-0{% endif %}" id="domains">
|
||||||
<div class="grid-row">
|
<div class="section--outlined__header margin-bottom-3 {% if portfolio is None %} section--outlined__header--no-portfolio justify-content-space-between{% else %} grid-row{% endif %}">
|
||||||
<!-- Use portfolio_base_permission when merging into 2366 then delete this comment -->
|
<!-- Use portfolio_base_permission when merging into 2366 then delete this comment -->
|
||||||
{% if portfolio is None %}
|
{% if portfolio is None %}
|
||||||
<div class="mobile:grid-col-12 desktop:grid-col-6">
|
<h2 id="domains-header" class="display-inline-block">Domains</h2>
|
||||||
<h2 id="domains-header" class="flex-6">Domains</h2>
|
<span class="display-none" id="no-portfolio-js-flag"></span>
|
||||||
</div>
|
|
||||||
<span class="display-none" id="no-portfolio-js-flag"></span>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="mobile:grid-col-12 desktop:grid-col-6">
|
<div class="section--outlined__search {% if portfolio %} mobile:grid-col-12 desktop:grid-col-6{% endif %}">
|
||||||
<section aria-label="Domains search component" class="flex-6 margin-y-2">
|
<section aria-label="Domains search component" class="margin-top-2">
|
||||||
<form class="usa-search usa-search--small" method="POST" role="search">
|
<form class="usa-search usa-search--small" method="POST" role="search">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<button class="usa-button usa-button--unstyled margin-right-3 domains__reset-search display-none" type="button">
|
<button class="usa-button usa-button--unstyled margin-right-3 domains__reset-search display-none" type="button">
|
||||||
|
@ -37,10 +35,19 @@
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="section--outlined__utility-button mobile-lg:padding-right-105 {% if portfolio %} mobile:grid-col-12 desktop:grid-col-6 desktop:padding-left-3{% endif %}">
|
||||||
|
<section aria-label="Domains report component" class="mobile-lg:margin-top-205">
|
||||||
|
<a href="{% url 'export_data_type_user' %}" class="usa-button usa-button--unstyled" role="button">
|
||||||
|
<svg class="usa-icon usa-icon--big margin-right-neg-4px" aria-hidden="true" focusable="false" role="img" width="24" height="24">
|
||||||
|
<use xlink:href="{%static 'img/sprite.svg'%}#file_download"></use>
|
||||||
|
</svg>Export as CSV
|
||||||
|
</a>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Use portfolio_base_permission when merging into 2366 then delete this comment -->
|
<!-- Use portfolio_base_permission when merging into 2366 then delete this comment -->
|
||||||
{% if portfolio %}
|
{% if portfolio %}
|
||||||
<div class="display-flex flex-align-center margin-top-1">
|
<div class="display-flex flex-align-center">
|
||||||
<span class="margin-right-2 margin-top-neg-1 usa-prose text-base-darker">Filter by</span>
|
<span class="margin-right-2 margin-top-neg-1 usa-prose text-base-darker">Filter by</span>
|
||||||
<div class="usa-accordion usa-accordion--select margin-right-2">
|
<div class="usa-accordion usa-accordion--select margin-right-2">
|
||||||
<div class="usa-accordion__heading">
|
<div class="usa-accordion__heading">
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
import io
|
import io
|
||||||
from django.test import Client, RequestFactory
|
from django.test import Client, RequestFactory
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from registrar.models.domain_request import DomainRequest
|
from registrar.models import (
|
||||||
from registrar.models.domain import Domain
|
DomainRequest,
|
||||||
|
Domain,
|
||||||
|
UserDomainRole,
|
||||||
|
)
|
||||||
from registrar.utility.csv_export import (
|
from registrar.utility.csv_export import (
|
||||||
DomainDataFull,
|
DomainDataFull,
|
||||||
DomainDataType,
|
DomainDataType,
|
||||||
DomainDataFederal,
|
DomainDataFederal,
|
||||||
|
DomainDataTypeUser,
|
||||||
DomainGrowth,
|
DomainGrowth,
|
||||||
DomainManaged,
|
DomainManaged,
|
||||||
DomainUnmanaged,
|
DomainUnmanaged,
|
||||||
|
@ -27,7 +31,7 @@ import boto3_mocking
|
||||||
from registrar.utility.s3_bucket import S3ClientError, S3ClientErrorCodes # type: ignore
|
from registrar.utility.s3_bucket import S3ClientError, S3ClientErrorCodes # type: ignore
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from api.tests.common import less_console_noise_decorator
|
from api.tests.common import less_console_noise_decorator
|
||||||
from .common import MockDb, MockEppLib, less_console_noise, get_time_aware_date
|
from .common import MockDb, MockEppLib, less_console_noise, get_time_aware_date, create_user
|
||||||
|
|
||||||
|
|
||||||
class CsvReportsTest(MockDb):
|
class CsvReportsTest(MockDb):
|
||||||
|
@ -199,8 +203,11 @@ class CsvReportsTest(MockDb):
|
||||||
|
|
||||||
|
|
||||||
class ExportDataTest(MockDb, MockEppLib):
|
class ExportDataTest(MockDb, MockEppLib):
|
||||||
|
"""Tests our data exports for admin"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super().tearDown()
|
super().tearDown()
|
||||||
|
@ -208,7 +215,7 @@ class ExportDataTest(MockDb, MockEppLib):
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_domain_data_type(self):
|
def test_domain_data_type(self):
|
||||||
"""Shows security contacts, domain managers, so"""
|
"""Shows security contacts, domain managers, so"""
|
||||||
self.maxDiff = None
|
|
||||||
# Add security email information
|
# Add security email information
|
||||||
self.domain_1.name = "defaultsecurity.gov"
|
self.domain_1.name = "defaultsecurity.gov"
|
||||||
self.domain_1.save()
|
self.domain_1.save()
|
||||||
|
@ -260,6 +267,58 @@ class ExportDataTest(MockDb, MockEppLib):
|
||||||
self.maxDiff = None
|
self.maxDiff = None
|
||||||
self.assertEqual(csv_content, expected_content)
|
self.assertEqual(csv_content, expected_content)
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
def test_domain_data_type_user(self):
|
||||||
|
"""Shows security contacts, domain managers, so for the current user"""
|
||||||
|
|
||||||
|
# Add security email information
|
||||||
|
self.domain_1.name = "defaultsecurity.gov"
|
||||||
|
self.domain_1.save()
|
||||||
|
# Invoke setter
|
||||||
|
self.domain_1.security_contact
|
||||||
|
self.domain_2.security_contact
|
||||||
|
self.domain_3.security_contact
|
||||||
|
# Add a first ready date on the first domain. Leaving the others blank.
|
||||||
|
self.domain_1.first_ready = get_default_start_date()
|
||||||
|
self.domain_1.save()
|
||||||
|
|
||||||
|
# Create a user and associate it with some domains
|
||||||
|
user = create_user()
|
||||||
|
UserDomainRole.objects.create(user=user, domain=self.domain_1)
|
||||||
|
UserDomainRole.objects.create(user=user, domain=self.domain_2)
|
||||||
|
|
||||||
|
# Create a request object
|
||||||
|
request = self.factory.get("/")
|
||||||
|
request.user = user
|
||||||
|
|
||||||
|
# Create a CSV file in memory
|
||||||
|
csv_file = StringIO()
|
||||||
|
# Call the export functions
|
||||||
|
DomainDataTypeUser.export_data_to_csv(csv_file, request=request)
|
||||||
|
# Reset the CSV file's position to the beginning
|
||||||
|
csv_file.seek(0)
|
||||||
|
# Read the content into a variable
|
||||||
|
csv_content = csv_file.read()
|
||||||
|
|
||||||
|
# We expect only domains associated with the user
|
||||||
|
expected_content = (
|
||||||
|
"Domain name,Status,First ready on,Expiration date,Domain type,Agency,Organization name,"
|
||||||
|
"City,State,SO,SO email,"
|
||||||
|
"Security contact email,Domain managers,Invited domain managers\n"
|
||||||
|
"defaultsecurity.gov,Ready,2023-11-01,(blank),Federal - Executive,World War I Centennial Commission,,,, ,,"
|
||||||
|
'(blank),"meoward@rocks.com, info@example.com, big_lebowski@dude.co, staff@example.com",'
|
||||||
|
"woofwardthethird@rocks.com\n"
|
||||||
|
"adomain2.gov,Dns needed,(blank),(blank),Interstate,,,,, ,,(blank),"
|
||||||
|
'"meoward@rocks.com, staff@example.com",squeaker@rocks.com\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Normalize line endings and remove commas,
|
||||||
|
# spaces and leading/trailing whitespace
|
||||||
|
csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
|
||||||
|
expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
|
||||||
|
self.maxDiff = None
|
||||||
|
self.assertEqual(csv_content, expected_content)
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_domain_data_full(self):
|
def test_domain_data_full(self):
|
||||||
"""Shows security contacts, filtered by state"""
|
"""Shows security contacts, filtered by state"""
|
||||||
|
@ -370,8 +429,8 @@ class ExportDataTest(MockDb, MockEppLib):
|
||||||
# Call the export functions
|
# Call the export functions
|
||||||
DomainGrowth.export_data_to_csv(
|
DomainGrowth.export_data_to_csv(
|
||||||
csv_file,
|
csv_file,
|
||||||
self.start_date.strftime("%Y-%m-%d"),
|
start_date=self.start_date.strftime("%Y-%m-%d"),
|
||||||
self.end_date.strftime("%Y-%m-%d"),
|
end_date=self.end_date.strftime("%Y-%m-%d"),
|
||||||
)
|
)
|
||||||
# Reset the CSV file's position to the beginning
|
# Reset the CSV file's position to the beginning
|
||||||
csv_file.seek(0)
|
csv_file.seek(0)
|
||||||
|
@ -412,8 +471,8 @@ class ExportDataTest(MockDb, MockEppLib):
|
||||||
# Call the export functions
|
# Call the export functions
|
||||||
DomainManaged.export_data_to_csv(
|
DomainManaged.export_data_to_csv(
|
||||||
csv_file,
|
csv_file,
|
||||||
self.start_date.strftime("%Y-%m-%d"),
|
start_date=self.start_date.strftime("%Y-%m-%d"),
|
||||||
self.end_date.strftime("%Y-%m-%d"),
|
end_date=self.end_date.strftime("%Y-%m-%d"),
|
||||||
)
|
)
|
||||||
# Reset the CSV file's position to the beginning
|
# Reset the CSV file's position to the beginning
|
||||||
csv_file.seek(0)
|
csv_file.seek(0)
|
||||||
|
@ -449,7 +508,7 @@ class ExportDataTest(MockDb, MockEppLib):
|
||||||
# Create a CSV file in memory
|
# Create a CSV file in memory
|
||||||
csv_file = StringIO()
|
csv_file = StringIO()
|
||||||
DomainUnmanaged.export_data_to_csv(
|
DomainUnmanaged.export_data_to_csv(
|
||||||
csv_file, self.start_date.strftime("%Y-%m-%d"), self.end_date.strftime("%Y-%m-%d")
|
csv_file, start_date=self.start_date.strftime("%Y-%m-%d"), end_date=self.end_date.strftime("%Y-%m-%d")
|
||||||
)
|
)
|
||||||
|
|
||||||
# Reset the CSV file's position to the beginning
|
# Reset the CSV file's position to the beginning
|
||||||
|
@ -496,8 +555,8 @@ class ExportDataTest(MockDb, MockEppLib):
|
||||||
# Call the export functions
|
# Call the export functions
|
||||||
DomainRequestGrowth.export_data_to_csv(
|
DomainRequestGrowth.export_data_to_csv(
|
||||||
csv_file,
|
csv_file,
|
||||||
self.start_date.strftime("%Y-%m-%d"),
|
start_date=self.start_date.strftime("%Y-%m-%d"),
|
||||||
self.end_date.strftime("%Y-%m-%d"),
|
end_date=self.end_date.strftime("%Y-%m-%d"),
|
||||||
)
|
)
|
||||||
# Reset the CSV file's position to the beginning
|
# Reset the CSV file's position to the beginning
|
||||||
csv_file.seek(0)
|
csv_file.seek(0)
|
||||||
|
|
|
@ -109,7 +109,7 @@ class BaseExport(ABC):
|
||||||
return Q()
|
return Q()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_filter_conditions(cls, 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.
|
Get a Q object of filter conditions to filter when building queryset.
|
||||||
"""
|
"""
|
||||||
|
@ -145,7 +145,7 @@ class BaseExport(ABC):
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
@classmethod
|
@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.
|
Write to csv file before the write_csv method.
|
||||||
Override in subclasses where needed.
|
Override in subclasses where needed.
|
||||||
|
@ -192,7 +192,7 @@ class BaseExport(ABC):
|
||||||
return cls.update_queryset(queryset, **kwargs)
|
return cls.update_queryset(queryset, **kwargs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def export_data_to_csv(cls, csv_file, start_date=None, end_date=None):
|
def export_data_to_csv(cls, csv_file, **export_kwargs):
|
||||||
"""
|
"""
|
||||||
All domain metadata:
|
All domain metadata:
|
||||||
Exports domains of all statuses plus domain managers.
|
Exports domains of all statuses plus domain managers.
|
||||||
|
@ -205,7 +205,7 @@ class BaseExport(ABC):
|
||||||
prefetch_related = cls.get_prefetch_related()
|
prefetch_related = cls.get_prefetch_related()
|
||||||
exclusions = cls.get_exclusions()
|
exclusions = cls.get_exclusions()
|
||||||
annotations_for_sort = cls.get_annotations_for_sort()
|
annotations_for_sort = cls.get_annotations_for_sort()
|
||||||
filter_conditions = cls.get_filter_conditions(start_date, end_date)
|
filter_conditions = cls.get_filter_conditions(**export_kwargs)
|
||||||
computed_fields = cls.get_computed_fields()
|
computed_fields = cls.get_computed_fields()
|
||||||
related_table_fields = cls.get_related_table_fields()
|
related_table_fields = cls.get_related_table_fields()
|
||||||
|
|
||||||
|
@ -227,10 +227,13 @@ class BaseExport(ABC):
|
||||||
models_dict = convert_queryset_to_dict(annotated_queryset, is_model=False)
|
models_dict = convert_queryset_to_dict(annotated_queryset, is_model=False)
|
||||||
|
|
||||||
# Write to csv file before the write_csv
|
# 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
|
# Write the csv file
|
||||||
cls.write_csv(writer, columns, models_dict)
|
rows = cls.write_csv(writer, columns, models_dict)
|
||||||
|
|
||||||
|
# Return rows that for easier parsing and testing
|
||||||
|
return rows
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def write_csv(
|
def write_csv(
|
||||||
|
@ -257,6 +260,9 @@ class BaseExport(ABC):
|
||||||
|
|
||||||
writer.writerows(rows)
|
writer.writerows(rows)
|
||||||
|
|
||||||
|
# Return rows for easier parsing and testing
|
||||||
|
return rows
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def parse_row(cls, columns, model):
|
def parse_row(cls, columns, model):
|
||||||
|
@ -554,6 +560,25 @@ class DomainDataType(DomainExport):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class DomainDataTypeUser(DomainDataType):
|
||||||
|
"""
|
||||||
|
The DomainDataType report, but sliced on the current request user
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_filter_conditions(cls, request=None):
|
||||||
|
"""
|
||||||
|
Get a Q object of filter conditions to filter when building queryset.
|
||||||
|
"""
|
||||||
|
if request is None or not hasattr(request, "user") or not request.user:
|
||||||
|
# Return nothing
|
||||||
|
return Q(id__in=[])
|
||||||
|
|
||||||
|
user_domain_roles = UserDomainRole.objects.filter(user=request.user)
|
||||||
|
domain_ids = user_domain_roles.values_list("domain_id", flat=True)
|
||||||
|
return Q(domain__id__in=domain_ids)
|
||||||
|
|
||||||
|
|
||||||
class DomainDataFull(DomainExport):
|
class DomainDataFull(DomainExport):
|
||||||
"""
|
"""
|
||||||
Shows security contacts, filtered by state
|
Shows security contacts, filtered by state
|
||||||
|
@ -611,7 +636,7 @@ class DomainDataFull(DomainExport):
|
||||||
return ["domain"]
|
return ["domain"]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_filter_conditions(cls, start_date=None, end_date=None):
|
def get_filter_conditions(cls):
|
||||||
"""
|
"""
|
||||||
Get a Q object of filter conditions to filter when building queryset.
|
Get a Q object of filter conditions to filter when building queryset.
|
||||||
"""
|
"""
|
||||||
|
@ -706,7 +731,7 @@ class DomainDataFederal(DomainExport):
|
||||||
return ["domain"]
|
return ["domain"]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_filter_conditions(cls, start_date=None, end_date=None):
|
def get_filter_conditions(cls):
|
||||||
"""
|
"""
|
||||||
Get a Q object of filter conditions to filter when building queryset.
|
Get a Q object of filter conditions to filter when building queryset.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -158,6 +158,17 @@ class ExportDataType(View):
|
||||||
return 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=request)
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
class ExportDataFull(View):
|
class ExportDataFull(View):
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
# Smaller export based on 1
|
# Smaller export based on 1
|
||||||
|
@ -194,7 +205,7 @@ class ExportDataDomainsGrowth(View):
|
||||||
|
|
||||||
response = HttpResponse(content_type="text/csv")
|
response = HttpResponse(content_type="text/csv")
|
||||||
response["Content-Disposition"] = f'attachment; filename="domain-growth-report-{start_date}-to-{end_date}.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
|
return response
|
||||||
|
|
||||||
|
@ -206,7 +217,7 @@ class ExportDataRequestsGrowth(View):
|
||||||
|
|
||||||
response = HttpResponse(content_type="text/csv")
|
response = HttpResponse(content_type="text/csv")
|
||||||
response["Content-Disposition"] = f'attachment; filename="requests-{start_date}-to-{end_date}.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
|
return response
|
||||||
|
|
||||||
|
@ -217,7 +228,7 @@ class ExportDataManagedDomains(View):
|
||||||
end_date = request.GET.get("end_date", "")
|
end_date = request.GET.get("end_date", "")
|
||||||
response = HttpResponse(content_type="text/csv")
|
response = HttpResponse(content_type="text/csv")
|
||||||
response["Content-Disposition"] = f'attachment; filename="managed-domains-{start_date}-to-{end_date}.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
|
return response
|
||||||
|
|
||||||
|
@ -228,6 +239,6 @@ class ExportDataUnmanagedDomains(View):
|
||||||
end_date = request.GET.get("end_date", "")
|
end_date = request.GET.get("end_date", "")
|
||||||
response = HttpResponse(content_type="text/csv")
|
response = HttpResponse(content_type="text/csv")
|
||||||
response["Content-Disposition"] = f'attachment; filename="unmanaged-domains-{start_date}-to-{end_date}.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
|
return response
|
Loading…
Add table
Add a link
Reference in a new issue