From 74984d34208cd2d9b733c3d86f95f75c5ac38769 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 21 Apr 2022 18:13:08 +0200 Subject: [PATCH] Import / export features --- Dockerfile.dev | 4 +- docker-compose.yml | 2 +- frontend/src/api/domains.js | 10 +++ frontend/src/api/identities.js | 10 +++ frontend/src/components/tools/ImportForm.vue | 95 ++++++++++++++++++++ frontend/src/mixins/importExport.js | 24 +++++ frontend/src/views/domains/Domains.vue | 50 +++++++++-- frontend/src/views/identities/Identities.vue | 49 ++++++++-- modoboa/admin/api/v1/serializers.py | 3 +- modoboa/admin/api/v1/viewsets.py | 3 +- modoboa/admin/api/v2/serializers.py | 8 ++ modoboa/admin/api/v2/viewsets.py | 57 +++++++++++- modoboa/admin/lib.py | 51 ++++++++++- modoboa/admin/models/alias.py | 8 +- modoboa/admin/models/domain.py | 28 +++--- modoboa/admin/models/domain_alias.py | 8 +- modoboa/admin/views/import_.py | 47 ++-------- modoboa/core/models.py | 20 +++-- modoboa/lib/renderers.py | 17 +--- modoboa/lib/viewsets.py | 32 ------- requirements.txt | 1 - setup.py | 6 +- 22 files changed, 403 insertions(+), 130 deletions(-) create mode 100644 frontend/src/components/tools/ImportForm.vue create mode 100644 frontend/src/mixins/importExport.js diff --git a/Dockerfile.dev b/Dockerfile.dev index 0c058cf80..edbb1d704 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,4 +1,4 @@ -FROM python:3.7-alpine as base +FROM python:3.9-alpine as base MAINTAINER Antoine Nguyen ENV VIRTUAL_ENV=/opt/venv @@ -13,7 +13,7 @@ RUN python3 -m venv $VIRTUAL_ENV WORKDIR /tmp COPY requirements.txt /tmp COPY test-requirements.txt /tmp -RUN python -m pip install -U pip +RUN python -m pip install -U pip RUN pip install -r requirements.txt -r test-requirements.txt FROM base as run diff --git a/docker-compose.yml b/docker-compose.yml index e7009ea76..5630bfb11 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,6 +13,6 @@ services: PYTHONPATH: ".." DB: "SQLITE" DEBUG: "True" - command: sh -c "python3 setup.py develop && cd test_project && python3 manage.py migrate && python3 manage.py load_initial_data && python3 manage.py runserver 0:8000" + command: sh -c "cd test_project && python3 manage.py migrate && python3 manage.py load_initial_data && python3 manage.py runserver 0:8000" volumes: - .:/code diff --git a/frontend/src/api/domains.js b/frontend/src/api/domains.js index f24bdade8..7482b05a9 100644 --- a/frontend/src/api/domains.js +++ b/frontend/src/api/domains.js @@ -46,5 +46,15 @@ export default { }, deleteDomainAlias (aliasId) { return repository.delete(`/${domainAliasResource}/${aliasId}/`) + }, + exportAll () { + return repository.get(`/${domainResource}/export/`) + }, + importFromCSV (data) { + return repository.post(`/${domainResource}/import/`, data, { + headers: { + 'Content-Type': 'multipart/form-data' + } + }) } } diff --git a/frontend/src/api/identities.js b/frontend/src/api/identities.js index e2b74e5d2..250770df9 100644 --- a/frontend/src/api/identities.js +++ b/frontend/src/api/identities.js @@ -5,5 +5,15 @@ const resource = 'identities' export default { getAll () { return repository.get(`${resource}/`) + }, + exportAll () { + return repository.get(`/${resource}/export/`) + }, + importFromCSV (data) { + return repository.post(`/${resource}/import/`, data, { + headers: { + 'Content-Type': 'multipart/form-data' + } + }) } } diff --git a/frontend/src/components/tools/ImportForm.vue b/frontend/src/components/tools/ImportForm.vue new file mode 100644 index 000000000..8496db65e --- /dev/null +++ b/frontend/src/components/tools/ImportForm.vue @@ -0,0 +1,95 @@ + + + diff --git a/frontend/src/mixins/importExport.js b/frontend/src/mixins/importExport.js new file mode 100644 index 000000000..66fbe8f3f --- /dev/null +++ b/frontend/src/mixins/importExport.js @@ -0,0 +1,24 @@ +import { bus } from '@/main' + +export const importExportMixin = { + methods: { + exportContent (content, name) { + const blob = new Blob([content], { type: 'text/csv' }) + const link = document.createElement('a') + link.href = URL.createObjectURL(blob) + link.download = `modoboa-${name}.csv` + link.click() + URL.revokeObjectURL(link.href) + }, + importContent (api, data) { + api.importFromCSV(data).then(resp => { + if (resp.data.status) { + bus.$emit('notification', { msg: resp.data.message }) + this.$refs.importForm.close() + } else { + bus.$emit('notification', { msg: resp.data.message, type: 'error' }) + } + }) + } + } +} diff --git a/frontend/src/views/domains/Domains.vue b/frontend/src/views/domains/Domains.vue index db05e19e3..4611dc8be 100644 --- a/frontend/src/views/domains/Domains.vue +++ b/frontend/src/views/domains/Domains.vue @@ -3,10 +3,18 @@ Domains - + mdi-file-import-outline - + mdi-file-export-outline @@ -41,28 +49,60 @@ max-width="800px"> + + + + + + diff --git a/frontend/src/views/identities/Identities.vue b/frontend/src/views/identities/Identities.vue index 91628a81b..0e8ded0a1 100644 --- a/frontend/src/views/identities/Identities.vue +++ b/frontend/src/views/identities/Identities.vue @@ -3,10 +3,18 @@ Identities - + mdi-file-import-outline - + mdi-file-export-outline @@ -37,7 +45,7 @@ > - + + + + +