Skip to content
Snippets Groups Projects
Verified Commit 660c9401 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Add export function for pictures

parent e3b3933a
No related branches found
No related tags found
No related merge requests found
# Generated by Django 3.2.11 on 2022-01-25 17:55
import django.contrib.sites.managers
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('sites', '0002_alter_domain_unique'),
('abi', '0014_pictures'),
]
operations = [
migrations.CreateModel(
name='ExportedPictures',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extended_data', models.JSONField(default=dict, editable=False)),
('file', models.FileField(upload_to='abi/export/')),
('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
],
options={
'verbose_name': 'Exported pictures',
'verbose_name_plural': 'Exported pictures',
},
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
],
),
]
......@@ -373,3 +373,21 @@ class Quote(ExtensibleModel):
verbose_name = _("Quote")
verbose_name_plural = _("Quotes")
permissions = (("suggest_quote", _("Can suggest a quote")),)
class ExportedPictures(ExtensibleModel):
file = models.FileField(upload_to="abi/export/")
@classmethod
def get_current(cls):
return cls.objects.get().file
@classmethod
def save_file(cls, file):
obj = cls.objects.get_or_create()[0]
obj.file.save("pictures.zip", file)
return obj
class Meta:
verbose_name = _("Exported pictures")
verbose_name_plural = _("Exported pictures")
......@@ -96,16 +96,6 @@ edit_profile_questions_predicate = (
)
add_perm("abi.edit_profile_questions_rule", edit_profile_questions_predicate)
# Export profiles
export_profiles_predicate = has_person & view_abipersons_predicate
add_perm("abi.export_profiles_rule", export_profiles_predicate)
# Export rankings
export_rankings_predicate = has_person & view_abipersons_predicate
add_perm("abi.export_rankings_rule", export_rankings_predicate)
export_predicate = export_profiles_predicate | export_rankings_predicate
add_perm("abi.export_rule", export_predicate)
# Rank persons
rank_persons_predicate = has_person & has_abi_person & has_global_perm("abi.rank_persons")
......@@ -205,3 +195,27 @@ add_perm(
| view_comments_predicate
),
)
# Export profiles
export_profiles_predicate = has_person & view_abipersons_predicate
add_perm("abi.export_profiles_rule", export_profiles_predicate)
# Export rankings
export_rankings_predicate = has_person & view_abipersons_predicate
add_perm("abi.export_rankings_rule", export_rankings_predicate)
# Export quotes
export_quotes_predicate = has_person & view_quotes_predicate
add_perm("abi.export_quotes_rule", export_quotes_predicate)
# Export comments
export_comments_predicate = has_person & has_global_perm("abi.view_comment")
add_perm("abi.export_comments_rule", export_comments_predicate)
export_predicate = (
export_profiles_predicate
| export_rankings_predicate
| export_quotes_predicate
| export_comments_predicate
)
add_perm("abi.export_rule", export_predicate)
import os
import tempfile
import zipfile
from django.utils.text import slugify
from aleksis.core.util.celery_progress import ProgressRecorder, recorded_task
from .models import ExportedPictures, Profile
@recorded_task
def export_pictures(recorder: ProgressRecorder):
with tempfile.TemporaryDirectory() as tmp_dir:
zip_path = os.path.join(tmp_dir, "pictures.zip")
zip_file = zipfile.ZipFile(zip_path, "w")
picture_attrs = [
"current_picture",
"old_picture",
"additional_picture_1",
"additional_picture_2",
]
for profile in recorder.iterate(Profile.objects.all()):
prefix = slugify(profile.person.name)
for attr in picture_attrs:
picture = getattr(profile, attr, None)
if picture:
ext = os.path.splitext(picture.name)[1]
picture_path = os.path.join("pictures", f"{prefix}_{attr}_{ext}")
zip_file.write(picture.path, picture_path)
zip_file.close()
with open(zip_path, "rb") as f:
ExportedPictures.save_file(f)
......@@ -19,7 +19,7 @@
{% endblocktrans %}
</div>
<div class="card-action">
<a href="{% url export_thing.url %}" download="">
<a href="{% url export_thing.url %}">
<i class="material-icons left">file_download</i>
Download
</a>
......
......@@ -112,4 +112,10 @@ urlpatterns = [
path("export/profile/", views.ProfileExportView.as_view(), name="export_profile"),
path("export/quote/", views.QuoteExportView.as_view(), name="export_quote"),
path("export/ranking/", views.RankingExportView.as_view(), name="export_ranking"),
path("export/picture/", views.PictureExportView.as_view(), name="export_picture"),
path(
"export/picture/pictures.zip",
views.GetExportedPicturesView.as_view(),
name="get_exported_pictures",
),
]
......@@ -4,7 +4,7 @@ from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.db.models import Count, OuterRef, Q, Subquery
from django.forms import modelformset_factory
from django.http import HttpResponse
from django.http import Http404, HttpResponse
from django.shortcuts import redirect
from django.urls import reverse, reverse_lazy
from django.utils.decorators import method_decorator
......@@ -28,6 +28,7 @@ from aleksis.core.mixins import (
AdvancedEditView,
SuccessMessageMixin,
)
from aleksis.core.util.celery_progress import render_progress_page
from .abi_helper import get_date_filename
from .forms import (
......@@ -45,6 +46,7 @@ from .models import (
AbiPerson,
AdditionalProfileField,
Comment,
ExportedPictures,
Profile,
ProfileFieldValue,
Quote,
......@@ -59,6 +61,7 @@ from .tables import (
ReviewCommentTable,
WrittenCommentTable,
)
from .tasks import export_pictures
class AbiPersonListView(PermissionRequiredMixin, SingleTableView):
......@@ -534,7 +537,7 @@ class ConfigureProfileView(PermissionRequiredMixin, SuccessMessageMixin, ModelFo
@method_decorator(never_cache, name="dispatch")
class CommentExportView(CSVExportView):
model = Comment
permission_required = "export_rankings_predicate"
permission_required = "abi.export_comments_rule"
fields = ("person", "person__person__email", "text", "author", "author__person__email")
def get_filename(self, queryset):
......@@ -552,7 +555,7 @@ class CommentExportView(CSVExportView):
@method_decorator(never_cache, name="dispatch")
class ProfileExportView(PermissionRequiredMixin, CSVExportView):
model = Profile
permission_required = "export_profiles_rule"
permission_required = "abi.export_profiles_rule"
def get_filename(self, queryset):
return get_date_filename("profiles")
......@@ -610,7 +613,7 @@ class ProfileExportView(PermissionRequiredMixin, CSVExportView):
@method_decorator(never_cache, name="dispatch")
class RankingExportView(CSVExportView):
model = RankingCategory
permission_required = "export_rankings_predicate"
permission_required = "abi.export_rankings_rule"
fields = (
"name",
"number_of_persons",
......@@ -641,7 +644,7 @@ class RankingExportView(CSVExportView):
@method_decorator(never_cache, name="dispatch")
class QuoteExportView(CSVExportView):
model = Quote
permission_required = "export_rankings_predicate"
permission_required = "abi.export_quotes_rule"
fields = (
"authors",
"text",
......@@ -659,8 +662,9 @@ class QuoteExportView(CSVExportView):
@method_decorator(never_cache, name="dispatch")
class ExportOverviewView(TemplateView):
class ExportOverviewView(PermissionRequiredMixin, TemplateView):
template_name = "abi/export_overview.html"
permission_required = "abi.export_rule"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
......@@ -675,7 +679,46 @@ class ExportOverviewView(TemplateView):
(_("Profiles"), Profile.objects.all().count(), "export_profile"),
(_("Quotes"), Quote.objects.all().count(), "export_quote"),
(_("Rankings"), RankingCategory.objects.all().count(), "export_ranking"),
(_("Pictures"), Profile.objects.all().count(), "export_picture"),
]
]
return context
@method_decorator(never_cache, name="dispatch")
class PictureExportView(PermissionRequiredMixin, View):
permission_required = "abi.export_profiles_rule"
def get(self, request, *args, **kwargs):
result = export_pictures.delay()
file_url = reverse("get_exported_pictures")
# Render progress view
return render_progress_page(
request,
result,
title=_("Progress: Export pictures"),
back_url=reverse("export_overview"),
progress_title=_("Build ZIP file …"),
success_message=_("The ZIP file generation was done successfully."),
error_message=_("There was a problem while generating the ZIP file."),
redirect_on_success_url=file_url,
button_url=file_url,
button_title=_("Download ZIP file"),
button_icon="download",
)
@method_decorator(never_cache, name="dispatch")
class GetExportedPicturesView(PermissionRequiredMixin, View):
permission_required = "abi.export_profiles_rule"
def get(self, request, *args, **kwargs):
try:
zip_file = ExportedPictures.get_current()
except ExportedPictures.DoesNotExist:
raise Http404()
return HttpResponse(zip_file.file, content_type="application/zip")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment