Browse Source

WIP dataexport utilities

Rafał Pitoń 7 years ago
parent
commit
605fbc0bc6

+ 13 - 0
misago/users/api/users.py

@@ -17,6 +17,7 @@ from misago.core.rest_permissions import IsAuthenticatedOrReadOnly
 from misago.core.shortcuts import get_int_or_404
 from misago.threads.moderation import hide_post, hide_thread
 from misago.users.bans import get_user_ban
+from misago.users.dataexport import is_user_data_export_in_progress, start_data_export_for_user
 from misago.users.online.utils import get_user_status
 from misago.users.permissions import (
     allow_browse_users_list, allow_delete_user, allow_edit_profile_details, allow_follow_user,
@@ -216,6 +217,18 @@ class UserViewSet(viewsets.GenericViewSet):
 
         return moderate_username_endpoint(request, profile)
 
+    @detail_route(methods=['post'])
+    def start_data_export(self, request, pk=None):
+        get_int_or_404(pk)
+        allow_self_only(request.user, pk, _("You can't request data export for other users."))
+
+        if is_user_data_export_in_progress(request.user):
+            raise PermissionDenied(_("You already data export in progress."))
+            
+        start_data_export_for_user(request.user)
+
+        return Response({'detail': 'ok'})
+
     @detail_route(methods=['get', 'post'])
     def delete(self, request, pk=None):
         profile = self.get_user(request, pk)

+ 19 - 0
misago/users/dataexport.py

@@ -0,0 +1,19 @@
+from .models import DataExport
+
+
+STATUS_PROGRESS = (DataExport.STATUS_PENDING, DataExport.STATUS_PROCESSING)
+
+
+def is_user_data_export_in_progress(user):
+    queryset = DataExport.objects.filter(user=user, status__in=STATUS_PROGRESS)
+    return queryset.exists()
+
+
+def start_data_export_for_user(user, requester=None):
+    requester = requester or user
+
+    return DataExport.objects.create(
+        user=user,
+        requester=requester,
+        requester_name=requester.username,
+    )

+ 32 - 0
misago/users/migrations/0014_dataexport.py

@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.13 on 2018-06-17 14:25
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+import misago.users.models.dataexport
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('misago_users', '0013_auto_20180609_1523'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='DataExport',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('status', models.PositiveIntegerField(choices=[(0, 'Requested'), (1, 'Processing'), (2, 'Ready'), (3, 'Expired')], db_index=True, default=0)),
+                ('requester_name', models.CharField(max_length=255)),
+                ('requested_on', models.DateTimeField(default=django.utils.timezone.now)),
+                ('expires_on', models.DateTimeField(default=django.utils.timezone.now)),
+                ('export_file', models.FileField(blank=True, null=True, upload_to=misago.users.models.dataexport.get_export_upload_to)),
+                ('requester', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
+                ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+    ]

+ 1 - 0
misago/users/models/__init__.py

@@ -5,3 +5,4 @@ from .avatar import Avatar
 from .audittrail import AuditTrail
 from .avatargallery import AvatarGallery
 from .ban import Ban, BanCache
+from .dataexport import DataExport

+ 6 - 3
misago/users/models/dataexport.py

@@ -9,13 +9,13 @@ def get_export_upload_to(instance, filename):
 
 
 class DataExport(models.Model):
-    STATUS_REQUESTED = 0
+    STATUS_PENDING = 0
     STATUS_PROCESSING = 1
     STATUS_READY = 2
     STATUS_EXPIRED = 3
 
     STATUS_CHOICES = (
-        (STATUS_REQUESTED, _("Requested")),
+        (STATUS_PENDING, _("Pending")),
         (STATUS_PROCESSING, _("Processing")),
         (STATUS_READY, _("Ready")),
         (STATUS_EXPIRED, _("Expired")),
@@ -23,15 +23,18 @@ class DataExport(models.Model):
 
     user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
     status = models.PositiveIntegerField(
-        default=STATUS_REQUESTED,
+        default=STATUS_PENDING,
         choices=STATUS_CHOICES,
         db_index=True,
     )
     requester = models.ForeignKey(
         settings.AUTH_USER_MODEL,
         related_name='+',
+        null=True,
+        blank=True,
         on_delete=models.SET_NULL,
     )
+    requester_name = models.CharField(max_length=255)
     requested_on = models.DateTimeField(default=timezone.now)
     expires_on = models.DateTimeField(default=timezone.now)
     export_file = models.FileField(upload_to=get_export_upload_to, null=True, blank=True)

+ 62 - 0
misago/users/tests/test_dataexport.py

@@ -0,0 +1,62 @@
+from misago.users.dataexport import is_user_data_export_in_progress, start_data_export_for_user
+from misago.users.models import DataExport
+from misago.users.testutils import AuthenticatedUserTestCase
+
+
+class IsUserDataExportInProgressTests(AuthenticatedUserTestCase):
+    def test_util_returns_false_for_no_export(self):
+        """is_user_data_export_in_progress returns false if user has no export in progress"""
+        self.assertFalse(is_user_data_export_in_progress(self.user))
+
+    def test_util_returns_false_for_ready_export(self):
+        """is_user_data_export_in_progress returns false if user has ready export"""
+        data_export = start_data_export_for_user(self.user)
+        data_export.status = DataExport.STATUS_READY
+        data_export.save()
+
+        self.assertFalse(is_user_data_export_in_progress(self.user))
+
+    def test_util_returns_false_for_expired_export(self):
+        """is_user_data_export_in_progress returns false if user has expired export"""
+        data_export = start_data_export_for_user(self.user)
+        data_export.status = DataExport.STATUS_EXPIRED
+        data_export.save()
+        
+        self.assertFalse(is_user_data_export_in_progress(self.user))
+
+    def test_util_returns_true_for_pending_export(self):
+        """is_user_data_export_in_progress returns true if user has pending export"""
+        data_export = start_data_export_for_user(self.user)
+        data_export.status = DataExport.STATUS_PENDING
+        data_export.save()
+        
+        self.assertTrue(is_user_data_export_in_progress(self.user))
+
+    def test_util_returns_true_for_processing_export(self):
+        """is_user_data_export_in_progress returns true if user has processing export"""
+        data_export = start_data_export_for_user(self.user)
+        data_export.status = DataExport.STATUS_PROCESSING
+        data_export.save()
+        
+        self.assertTrue(is_user_data_export_in_progress(self.user))
+
+
+class StartDataExportForUserTests(AuthenticatedUserTestCase):
+    def test_util_creates_data_export_for_user(self):
+        """start_data_export_for_user created valid data export for user"""
+        data_export = start_data_export_for_user(self.user)
+
+        self.assertEqual(data_export.user, self.user)
+        self.assertEqual(data_export.requester, self.user)
+        self.assertEqual(data_export.requester_name, self.user.username)
+        self.assertEqual(data_export.status, DataExport.STATUS_PENDING)
+
+    def test_util_creates_data_export_for_user_with_request(self):
+        """start_data_export_for_user created valid data export for user with other requester"""
+        requester = self.get_superuser()
+        data_export = start_data_export_for_user(self.user, requester)
+
+        self.assertEqual(data_export.user, self.user)
+        self.assertEqual(data_export.requester, requester)
+        self.assertEqual(data_export.requester_name, requester.username)
+        self.assertEqual(data_export.status, DataExport.STATUS_PENDING)

+ 18 - 0
misago/users/tests/test_userdataexport_api.py

@@ -0,0 +1,18 @@
+from misago.users.testutils import AuthenticatedUserTestCase
+
+
+class UserDataExportApiTests(AuthenticatedUserTestCase):
+    def setUp(self):
+        super(UserDataExportApiTests, self).setUp()
+        self.link = '/api/users/%s/start-data-export/' % self.user.pk
+
+    def test_other_user_export(self):
+        """requests to api error if user tries to access other user"""
+        other_user = self.get_superuser()
+        link = '/api/users/%s/start-data-export/' % other_user.pk
+
+        response = self.client.post(link)
+        self.assertEqual(response.status_code, 403)
+        self.assertEqual(response.json(), {
+            'detail': "You can\'t request data export for other users.",
+        })