Browse Source

#675: PostRead model and migrations for it

Rafał Pitoń 7 years ago
parent
commit
1b2d6a9e33

+ 32 - 0
misago/readtracker/migrations/0002_postread.py

@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.5 on 2017-10-07 14:32
+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
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('misago_categories', '0006_moderation_queue_roles'),
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('misago_threads', '0006_redo_partial_indexes'),
+        ('misago_readtracker', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='PostRead',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('last_read_on', models.DateTimeField(default=django.utils.timezone.now)),
+                ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='misago_categories.Category')),
+                ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='misago_threads.Post')),
+                ('thread', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='misago_threads.Thread')),
+                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+    ]

+ 87 - 0
misago/readtracker/migrations/0003_migrate_reads_to_posts.py

@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.5 on 2017-10-07 14:49
+from __future__ import unicode_literals
+
+from datetime import timedelta
+
+from django.db import migrations
+from django.conf import settings
+from django.utils import timezone
+
+from misago.conf import defaults
+
+
+try:
+    READS_CUTOFF = settings.MISAGO_READTRACKER_CUTOFF
+except AttributeError:
+    READS_CUTOFF = defaults.MISAGO_READTRACKER_CUTOFF
+
+
+def populate_posts_reads(apps, schema_editor):
+    reads_cutoff = timezone.now() - timedelta(days=READS_CUTOFF)
+
+    Post = apps.get_model('misago_threads', 'Post')
+
+    CategoryRead = apps.get_model('misago_readtracker', 'CategoryRead')
+    ThreadRead = apps.get_model('misago_readtracker', 'ThreadRead')
+    PostRead = apps.get_model('misago_readtracker', 'PostRead')
+
+    migrated_reads = {}
+
+    # read posts by category reads
+    queryset = CategoryRead.objects.select_related().iterator()
+    for category_read in queryset:
+        posts_queryset = Post.objects.filter(
+            category=category_read.category,
+            posted_on__gte=reads_cutoff,
+        )
+
+        for post in posts_queryset.iterator():
+            PostRead.objects.create(
+                user=category_read.user,
+                category=post.category,
+                thread=post.thread,
+                post=post,
+                last_read_on=post.posted_on,
+            )
+
+            if category_read.user.pk in migrated_reads:
+                migrated_reads[category_read.user.pk].append(post.pk)
+            else:
+                migrated_reads[category_read.user.pk] = [post.pk]
+
+    # read posts by thread reads
+    queryset = ThreadRead.objects.select_related().iterator()
+    for thread_read in queryset:
+        posts_queryset = Post.objects.filter(
+            thread=thread_read.thread,
+            posted_on__gte=reads_cutoff,
+        )
+
+        for post in posts_queryset.iterator():
+            if post.pk in migrated_reads.get(thread_read.user.pk, []):
+                continue
+
+            PostRead.objects.create(
+                user=thread_read.user,
+                category=post.category,
+                thread=post.thread,
+                post=post,
+                last_read_on=post.posted_on,
+            )
+
+
+def noop_reverse(apps, schema_editor):
+    PostRead = apps.get_model('misago_readtracker', 'PostRead')
+    PostRead.objects.all().delete()
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('misago_readtracker', '0002_postread'),
+    ]
+
+    operations = [
+        migrations.RunPython(populate_posts_reads, noop_reverse),
+    ]

+ 31 - 0
misago/readtracker/models.py

@@ -1,5 +1,6 @@
 from django.conf import settings
 from django.db import models
+from django.utils import timezone
 
 
 class CategoryRead(models.Model):
@@ -13,6 +14,11 @@ class CategoryRead(models.Model):
     )
     last_read_on = models.DateTimeField()
 
+    def __init__(self, *args, **kwargs):
+        from misago.core import deprecations
+        deprecations.warn("CategoryRead has been deprecated")
+        super(CategoryRead, self).__init__(*args, **kwargs)
+
 
 class ThreadRead(models.Model):
     user = models.ForeignKey(
@@ -28,3 +34,28 @@ class ThreadRead(models.Model):
         on_delete=models.CASCADE,
     )
     last_read_on = models.DateTimeField()
+
+    def __init__(self, *args, **kwargs):
+        from misago.core import deprecations
+        deprecations.warn("ThreadRead has been deprecated")
+        super(ThreadRead, self).__init__(*args, **kwargs)
+
+
+class PostRead(models.Model):
+    user = models.ForeignKey(
+        settings.AUTH_USER_MODEL,
+        on_delete=models.CASCADE,
+    )
+    category = models.ForeignKey(
+        'misago_categories.Category',
+        on_delete=models.CASCADE,
+    )
+    thread = models.ForeignKey(
+        'misago_threads.Thread',
+        on_delete=models.CASCADE,
+    )
+    post = models.ForeignKey(
+        'misago_threads.Post',
+        on_delete=models.CASCADE,
+    )
+    last_read_on = models.DateTimeField(default=timezone.now)