Skip to content
This repository has been archived by the owner on Dec 16, 2023. It is now read-only.

Commit

Permalink
Rework liberation app to make cleanups easier
Browse files Browse the repository at this point in the history
Fixes #107
  • Loading branch information
moggers87 committed Jun 25, 2021
1 parent c3cc5e7 commit 967729b
Show file tree
Hide file tree
Showing 10 changed files with 319 additions and 292 deletions.
46 changes: 9 additions & 37 deletions inboxen/liberation/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,57 +22,29 @@
from django.utils import timezone
from django.utils.translation import gettext as _

from inboxen import models
from inboxen.liberation import models
from inboxen.liberation.tasks import liberate as data_liberate


class LiberationForm(forms.ModelForm):
class Meta:
model = models.Liberation
fields = []
fields = ["compression_type", "storage_type"]

STORAGE_TYPES = (
(0, _("Maildir")),
(1, _("Mailbox .mbox")),
)

# Could we support zip files?
COMPRESSION_TYPES = (
(0, _("Tarball (gzip compressed)")),
(1, _("Tarball (bzip2 compression)")),
(2, _("Tarball (no compression)")),
)

storage_type = forms.ChoiceField(choices=STORAGE_TYPES)
compression_type = forms.ChoiceField(choices=COMPRESSION_TYPES)

def __init__(self, user, initial=None, *args, **kwargs):
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
self.instance.user = user
self.user = user
if not initial:
initial = {
"storage_type": 0,
"compression_type": 0,
}

super().__init__(initial=initial, *args, **kwargs)

def clean(self):
cleaned_data = super().clean()
if not self.user.liberation.can_request_another:
if not self.user.liberation_set.all().can_request_another():
raise ValidationError("You cannot request another archive so soon!")
return cleaned_data

def save(self):
lib_status = self.user.liberation
lib_status.running = True
lib_status.started = timezone.now()

result = data_liberate.apply_async(
kwargs={"user_id": self.user.id, "options": self.cleaned_data},
self.instance.save()
data_liberate.apply_async(
kwargs={"liberation_id": self.instance.id},
countdown=10
)

lib_status.async_result = result.id
lib_status.save()

return self.user
36 changes: 36 additions & 0 deletions inboxen/liberation/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 3.2.3 on 2021-06-13 10:12

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='Liberation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('compression_type', models.PositiveSmallIntegerField(choices=[(0, 'Tarball (gzip compressed)'), (1, 'Tarball (bzip2 compression)'), (2, 'Tarball (no compression)')])),
('storage_type', models.PositiveSmallIntegerField(choices=[(0, 'Maildir'), (1, 'Mailbox .mbox')])),
('created', models.DateTimeField(auto_now_add=True)),
('started', models.DateTimeField(null=True)),
('finished', models.DateTimeField(null=True)),
('errored', models.BooleanField(default=False)),
('error_message', models.CharField(max_length=255, null=True)),
('error_traceback', models.TextField(null=True)),
('deleted', models.BooleanField(default=False)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-created', 'id'],
},
),
]
Empty file.
115 changes: 115 additions & 0 deletions inboxen/liberation/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
##
# Copyright (C) 2021 Jessica Tallon & Matt Molyneaux
#
# This file is part of Inboxen.
#
# Inboxen is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Inboxen is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Inboxen. If not, see <http://www.gnu.org/licenses/>.
##

from datetime import timedelta

from django.conf import settings
from django.db import models
from django.db.models.query import QuerySet
from django.utils.functional import cached_property
from django.utils.translation import gettext as _

from inboxen import validators


class LiberationQuerySet(QuerySet):
def user_can_request_another(self, user):
time_after = timezone.now() - self.model.TIME_BETWEEN
last_run = self.filter(user=user, deleted=False).first()
if last_run is None:
return True
elif last_run.started is None or last_run.finished is None:
return False
else:
return last_run.started < time_after and last_run.finished < time_after

def pending(self):
return self.filter(finished__isnull=True, deleted=False, errored=False)


class Liberation(models.Model):
"""Liberation log"""
TIME_BETWEEN = timedelta(days=7)

TAR_GZ = 0
TAR_BZ = 1
TAR = 2
ARCHIVE_TYPES = {
TAR_GZ: {
"ext": "tar.gz",
"writer": "w:gz",
"mime-type": "application/x-gzip",
"label": _("Tarball (gzip compressed)"),
},
TAR_BZ: {
"ext": "tar.bz2",
"writer": "w:bz2",
"mime-type": "application/x-bzip2",
"label": _("Tarball (bzip2 compression)"),
},
TAR: {
"ext": "tar",
"writer": "w:",
"mime-type": "application/x-tar",
"label": _("Tarball (no compression)"),
}
}

COMPRESSION_TYPES = [(k, v["label"]) for k, v in ARCHIVE_TYPES.items()]

MAILDIR = 0
MAILBOX = 1
STORAGE_TYPES = (
(MAILDIR, _("Maildir")),
(MAILBOX, _("Mailbox .mbox")),
)

user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
compression_type = models.PositiveSmallIntegerField(choices=COMPRESSION_TYPES)
storage_type = models.PositiveSmallIntegerField(choices=STORAGE_TYPES)
created = models.DateTimeField(auto_now_add=True)
started = models.DateTimeField(null=True)
finished = models.DateTimeField(null=True)
errored = models.BooleanField(default=False)
error_message = models.CharField(max_length=255, null=True)
error_traceback = models.TextField(null=True)
deleted = models.BooleanField(default=False)

objects = LiberationQuerySet.as_manager()

class Meta:
ordering = ["-created", "id"]

def __str__(self):
return "Liberation for %s" % self.user

@cached_property
def path(self):
"""Path to final archive"""
return pathlib.Path(settings.SENDFILE_ROOT, "archives", self.pk)

@cached_property
def tmp_dir(self):
"""Path to temporary directory that can be removed once liberation is
finished"""
return pathlib.Path(settings.SENDFILE_ROOT, "tmp", self.pk)

@cached_property
def maildir(self):
return mailbox.Maildir(self.tmp_dir / "emails", factory=None)
Loading

0 comments on commit 967729b

Please sign in to comment.