fixup! 🧑‍💻(admin) export domain contact info

This commit is contained in:
Marie PUPO JEAMMET
2026-03-26 18:52:08 +01:00
parent 5fa9058c77
commit 485ab51019
6 changed files with 103 additions and 52 deletions
+1
View File
@@ -9,6 +9,7 @@ and this project adheres to
## [Unreleased]
### Added
- 🧑‍💻(admin) export domain contact info #1061
## [1.24.0] - 2026-03-24
+33 -27
View File
@@ -14,6 +14,34 @@ from requests import exceptions
from mailbox_manager import enums, models
from mailbox_manager.utils.dimail import DimailAPIClient
from import_export.admin import ImportExportModelAdmin
from import_export import resources
from import_export.fields import Field
from import_export.admin import ExportActionMixin
class DomainResource(resources.ModelResource):
""""""
owners = Field()
admins = Field()
class Meta:
model = models.MailDomain
fields = ["name", "slug", "status", "support_email", "owners", "admins"]
def get_queryset(self):
return super().get_queryset().prefetch_related("accesses__user")
# def filter_export(self, queryset, **kwargs):
# return self.get_queryset()
def dehydrate_owners(self, domain):
return [access.user.email for access in domain.accesses.all() if access.role=="owner"]
def dehydrate_admins(self, domain):
return [access.user.email for access in domain.accesses.all() if access.role=="administrator"]
class UserMailDomainAccessInline(admin.TabularInline):
"""Inline admin class for mail domain accesses."""
@@ -24,9 +52,9 @@ class UserMailDomainAccessInline(admin.TabularInline):
@admin.register(models.MailDomain)
class MailDomainAdmin(admin.ModelAdmin):
class MailDomainAdmin(ExportActionMixin, admin.ModelAdmin):
"""Mail domain admin interface declaration."""
resource_class = DomainResource
list_display = (
"name",
"organization",
@@ -49,9 +77,9 @@ class MailDomainAdmin(admin.ModelAdmin):
)
autocomplete_fields = ["organization"]
def get_queryset(self, request):
"""Restrict results to the current user's domain and prefetch accesses."""
return super().get_queryset(request).prefetch_related("accesses__user")
# def get_queryset(self, request):
# """Restrict results to the current user's domain and prefetch accesses."""
# return super().get_queryset(request).prefetch_related("accesses__user")
@admin.action(description=_("Import emails from dimail"))
def sync_mailboxes_from_dimail(self, request, queryset): # pylint: disable=unused-argument
@@ -255,28 +283,6 @@ class MailDomainAdmin(admin.ModelAdmin):
% {"domains": ", ".join(excluded_domains)},
)
@admin.action(description=_("Export a list of select domains support email"))
def export_domains_contact_list(self, request, queryset): # pylint: disable=unused-argument
"""Admin action to export."""
response = HttpResponse(
content_type="text/csv",
headers={
"Content-Disposition": f'attachment; filename="people_domains_infos-{date.today()}.csv"'
},
)
writer = csv.writer(response)
writer.writerow(["name", "status", "support_email", "admins_emails"])
for domain in queryset:
import pdb; pdb.set_trace()
','.join([access.user.email if access.role != "viewer" else None for access in domain.accesses.all()])
writer.writerow(
[domain.name,
domain.status,
domain.support_email]
)
return response
@admin.register(models.Mailbox)
class MailboxAdmin(UserAdmin):
"""Admin for mailbox model."""
@@ -13,6 +13,7 @@ from freezegun import freeze_time
from rest_framework import status
from core import factories as core_factories
from mailbox_manager.admin import DomainResource
from mailbox_manager import enums, factories, models
@@ -277,32 +278,38 @@ def test_export_domains_infos(client, django_assert_num_queries):
admin = core_factories.UserFactory(is_staff=True, is_superuser=True)
client.force_login(admin)
domains = factories.MailDomainFactory.create_batch(
10, status=enums.MailDomainStatusChoices.ENABLED
)
factories.MailDomainAccessFactory(domain=domains[0], role="owner")
factories.MailDomainAccessFactory(domain=domains[0], role="administrator")
factories.MailDomainAccessFactory(domain=domains[1], role="owner")
factories.MailDomainAccessFactory(domain=domains[3], role="owner")
factories.MailDomainAccessFactory.create_batch(3, domain=domains[6], role="owner")
data = {
"action": "export_domains_contact_list",
"_selected_action": [domain.id for domain in domains],
}
url = reverse("admin:mailbox_manager_maildomain_changelist")
domains = [
factories.MailDomainEnabledFactory(
users=[(core_factories.UserFactory(), "owner")]
), factories.MailDomainEnabledFactory(
users=[(core_factories.UserFactory(), "owner"),
(core_factories.UserFactory(), "administrator")]
),factories.MailDomainEnabledFactory(
users=[(core_factories.UserFactory(), "owner"),
(core_factories.UserFactory(), "viewer")]
)
]
resource = DomainResource()
with freeze_time("2025-12-16"):
with django_assert_num_queries(6):
response = client.post(url, data, follow=True)
with django_assert_num_queries(4):
export = resource.export()
domains_lines = response.content.decode("utf-8").split("\r\n")
assert (
response.headers["Content-Disposition"]
== f'attachment; filename="people_domains_infos-2025-12-16.csv"'
)
# domains.reverse()
import pdb; pdb.set_trace()
domains.reverse()
assert domains_lines[1:] == [
f'{domain.name},{domain.status},{domain.support_email}' + ','.join([access.user.email for access in domain.accesses.all()])
assert json.loads(export.json) == [{
'name': str(domain.name),
'slug': str(domain.slug),
'status': str(domain.status),
'support_email': domain.support_email,
'owners': [access.user.email for access in domain.accesses.filter(role='owner')],
'admins': [access.user.email for access in domain.accesses.filter(role='administrator')],
}
for domain in domains
]
+4 -2
View File
@@ -243,6 +243,7 @@ class Base(Configuration):
"rest_framework",
"treebeard",
"lasuite.admin", # must be before django.contrib.admin
"import_export",
# Django
"django.contrib.auth",
"django.contrib.contenttypes",
@@ -317,8 +318,9 @@ class Base(Configuration):
}
# Django Admin
ADMIN_HEADER_BACKGROUND = values.Value(None)
ADMIN_HEADER_COLOR = values.Value(None)
ADMIN_HEADER_BACKGROUND = "#32a852"
ADMIN_HEADER_COLOR = "#ffffff"
IMPORT_EXPORT_USE_TRANSACTIONS = True
# Mail
EMAIL_BACKEND = values.Value("django.core.mail.backends.smtp.EmailBackend")
+1
View File
@@ -35,6 +35,7 @@ dependencies = [
"django-cors-headers==4.9.0",
"django-countries==8.2.0",
"django-extensions==4.1",
"django-import-export>=4.4.0",
"django-lasuite==0.0.25",
"django-oauth-toolkit==3.2.0",
"django-parler==2.3",
+34
View File
@@ -361,6 +361,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" },
]
[[package]]
name = "diff-match-patch"
version = "20241021"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/0e/ad/32e1777dd57d8e85fa31e3a243af66c538245b8d64b7265bec9a61f2ca33/diff_match_patch-20241021.tar.gz", hash = "sha256:beae57a99fa48084532935ee2968b8661db861862ec82c6f21f4acdd6d835073", size = 39962, upload-time = "2024-10-21T19:41:21.094Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f7/bb/2aa9b46a01197398b901e458974c20ed107935c26e44e37ad5b0e5511e44/diff_match_patch-20241021-py3-none-any.whl", hash = "sha256:93cea333fb8b2bc0d181b0de5e16df50dd344ce64828226bda07728818936782", size = 43252, upload-time = "2024-10-21T19:41:19.914Z" },
]
[[package]]
name = "dill"
version = "0.4.1"
@@ -464,6 +473,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/64/96/d967ca440d6a8e3861120f51985d8e5aec79b9a8bdda16041206adfe7adc/django_extensions-4.1-py3-none-any.whl", hash = "sha256:0699a7af28f2523bf8db309a80278519362cd4b6e1fd0a8cd4bf063e1e023336", size = 232980, upload-time = "2025-04-11T01:15:37.701Z" },
]
[[package]]
name = "django-import-export"
version = "4.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "diff-match-patch" },
{ name = "django" },
{ name = "tablib" },
]
sdist = { url = "https://files.pythonhosted.org/packages/22/26/279bc8e6cb2c83d1b5dcdca07e932207c3352af11c6d305d6964a2d03ccc/django_import_export-4.4.0.tar.gz", hash = "sha256:9900e99c89027594941074fb4cd63a5f2964975e239021765c0f066003fcd412", size = 2237714, upload-time = "2026-01-10T20:57:35.128Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2f/e0/f4aa6d2374cc6b53b23f36bd0d5814e1db2769b25931b9908723fa295bb0/django_import_export-4.4.0-py3-none-any.whl", hash = "sha256:2d9b234c0f024d3377167f4d9c5a506e095c5bad98e06d30700e1d0752829e3d", size = 157449, upload-time = "2026-01-10T20:57:33.141Z" },
]
[[package]]
name = "django-lasuite"
version = "0.0.25"
@@ -1029,6 +1052,7 @@ dependencies = [
{ name = "django-cors-headers" },
{ name = "django-countries" },
{ name = "django-extensions" },
{ name = "django-import-export" },
{ name = "django-lasuite" },
{ name = "django-oauth-toolkit" },
{ name = "django-parler" },
@@ -1089,6 +1113,7 @@ requires-dist = [
{ name = "django-cors-headers", specifier = "==4.9.0" },
{ name = "django-countries", specifier = "==8.2.0" },
{ name = "django-extensions", specifier = "==4.1" },
{ name = "django-import-export", specifier = ">=4.4.0" },
{ name = "django-lasuite", specifier = "==0.0.25" },
{ name = "django-oauth-toolkit", specifier = "==3.2.0" },
{ name = "django-parler", specifier = "==2.3" },
@@ -1671,6 +1696,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" },
]
[[package]]
name = "tablib"
version = "3.9.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/11/00/416d2ba54d7d58a7f7c61bf62dfeb48fd553cf49614daf83312f2d2c156e/tablib-3.9.0.tar.gz", hash = "sha256:1b6abd8edb0f35601e04c6161d79660fdcde4abb4a54f66cc9f9054bd55d5fe2", size = 125565, upload-time = "2025-10-15T18:21:56.263Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/66/6b/32e51d847148b299088fc42d3d896845fd09c5247190133ea69dbe71ba51/tablib-3.9.0-py3-none-any.whl", hash = "sha256:eda17cd0d4dda614efc0e710227654c60ddbeb1ca92cdcfc5c3bd1fc5f5a6e4a", size = 49580, upload-time = "2025-10-15T18:21:44.185Z" },
]
[[package]]
name = "tomlkit"
version = "0.14.0"