Browse Source

Merge pull request #861 from rafalp/0.7

Misago 0.7
Rafał Pitoń 8 years ago
parent
commit
28abb929e3
43 changed files with 50 additions and 1872 deletions
  1. 1 0
      MANIFEST.in
  2. 4 2
      README.rst
  3. 7 6
      docs/SUMMARY.md
  4. 2 2
      docs/setup/README.md
  5. 24 0
      docs/setup/UpgradePath.md
  6. 9 2
      docs/setup/UpgradingFrom05.md
  7. 1 1
      misago/__init__.py
  8. 0 79
      misago/core/pgutils.py
  9. 0 10
      misago/datamover/__init__.py
  10. 0 99
      misago/datamover/attachments.py
  11. 0 68
      misago/datamover/avatars.py
  12. 0 38
      misago/datamover/bans.py
  13. 0 86
      misago/datamover/categories.py
  14. 0 4
      misago/datamover/conf.py
  15. 0 13
      misago/datamover/db.py
  16. 0 0
      misago/datamover/management/__init__.py
  17. 0 36
      misago/datamover/management/base.py
  18. 0 0
      misago/datamover/management/commands/__init__.py
  19. 0 36
      misago/datamover/management/commands/buildmovesindex.py
  20. 0 17
      misago/datamover/management/commands/movecategories.py
  21. 0 14
      misago/datamover/management/commands/movesettings.py
  22. 0 51
      misago/datamover/management/commands/movethreads.py
  23. 0 33
      misago/datamover/management/commands/moveusers.py
  24. 0 33
      misago/datamover/management/commands/runmigration.py
  25. 0 41
      misago/datamover/markup/__init__.py
  26. 0 50
      misago/datamover/markup/attachments.py
  27. 0 45
      misago/datamover/markup/quotes.py
  28. 0 45
      misago/datamover/migrations/0001_initial.py
  29. 0 0
      misago/datamover/migrations/__init__.py
  30. 0 23
      misago/datamover/models.py
  31. 0 15
      misago/datamover/movedids.py
  32. 0 72
      misago/datamover/polls.py
  33. 0 93
      misago/datamover/settings.py
  34. 0 266
      misago/datamover/threads.py
  35. 0 241
      misago/datamover/urls.py
  36. 0 138
      misago/datamover/users.py
  37. 0 50
      misago/datamover/views.py
  38. 0 3
      misago/project_template/project_name/settings.py
  39. 0 51
      misago/threads/migrations/0001_initial.py
  40. 0 81
      misago/threads/migrations/0006_redo_partial_indexes.py
  41. 0 11
      misago/users/migrations/0001_initial.py
  42. 0 17
      misago/users/migrations/0009_redo_partial_indexes.py
  43. 2 0
      upload

+ 1 - 0
MANIFEST.in

@@ -4,6 +4,7 @@ include README.rst
 include requirements.txt
 graft docs
 prune docs/build
+prune extras
 prune testproject
 graft misago
 global-exclude __pycache__

+ 4 - 2
README.rst

@@ -19,7 +19,7 @@ Misago
    :alt: Works on Python 2.7, 3.5, 3,6
 
 
-**Development Status:** 🍌 `Banans <https://en.wikipedia.org/wiki/Perpetual_beta>`_ 🍌
+**Development Status:** 🍌 `Bananas <https://en.wikipedia.org/wiki/Perpetual_beta>`_ 🍌
 
 Misago aims to be complete, featured and modern forum solution that has no fear to say 'NO' to common and outdated opinions about how forum software should be made and what it should do.
 
@@ -62,11 +62,13 @@ As of now Misago implements all features considered "must have" on live internet
 
 Even more features will follow in future releases:
 
-* Admin-manageable custom profile fields letting site admins to define custom fields for users to fill in without need to write any code.
+* Achievements and awards system.
+* Custom profile fields letting site owners to define custom fields for users to fill in.
 * Content reporting for users to report offensive content.
 * Forum-wide JS routing further reducing navigation times.
 * Notifications for users to notice content and events of concern faster.
 * Post accurate read tracker that lets moderators spot unapproved replies and non-moderators spot approved posts.
+* Sign in with Facebook/Google/Github/Steam/etc/ect.
 * Warning system for easy tracking users history of infractions and offenses.
 * WYSIWYM content editor for even easier post formatting.
 

+ 7 - 6
docs/SUMMARY.md

@@ -1,8 +1,12 @@
 # Table of contents
 
 * [Introduction](./README.md)
-* [Setup and maintenance](./SetupMaintenance.md)
-* [Upgrading from Misago 0.5](./UpgradingFrom05.md)
+* [Setup and maintenance](./setup/README.md)
+  * [Updating from Misago 0.5](./setup/UpdatingFrom05.md)
+  * [Update paths](./setup/UpdatePaths.md)
+* [Settings](./settings/README.md)
+  * [Core settings](./settings/Core.md)
+  * [Database settings](./settings/Database.md)
 * [Coding style](./CodingStyle.md)
 * [User rank styles](./UserRankStyles.md)
 * [Category styles](./CategoryStyles.md)
@@ -25,7 +29,4 @@
 * [Template tags](./TemplateTags.md)
 * [Shortcuts](./Shortcuts.md)
 * [Thread store](./ThreadStore.md)
-* [View errors](./ViewErrors.md)
-* [Settings](./settings/README.md)
-  * [Core settings](./settings/Core.md)
-  * [Database settings](./settings/Database.md)
+* [View errors](./ViewErrors.md)

+ 2 - 2
docs/SetupMaintenance.md → docs/setup/README.md

@@ -35,7 +35,7 @@ This error is caused by Misago being installed using setuptools older than 8.0 r
 
 To install Misago setup and activate virtual environment for your site and then fire following command:
 
-    pip install misago --pre
+    pip install misago
 
 This will install Misago in your virtual environment and make `misago-start.py` script available for you to use to create pre-configured Misago site.
 
@@ -43,7 +43,7 @@ Now decide on your site's module name. This name will be used for python module
 
 Once you've decided on your name, create your site configuration module. In example we assume your site will be named "misagoforumorg":
 
-	misago-start.py misagoforumorg
+    misago-start.py misagoforumorg
 
 This will create directory "misagoforumorg" in your working directory. Inside you will find following items:
 

+ 24 - 0
docs/setup/UpgradePath.md

@@ -0,0 +1,24 @@
+Update path
+===========
+
+Some versions of Misago contain migrations for deprecated features. 
+
+## 0.6 Alphas to 0.6
+
+### Some database indexes have changed
+
+Misago 0.6 final release contains special migrations that replace old database indexes with new ones using custom `PgPartialIndex` index class that uses custom index types feature that was introduced in the Django 1.11.
+
+
+## 0.6 to 0.7
+
+### `misago.datamover` has been removed
+
+`misago.datamover` entry in your `settings.py` `INSTALLED_APPS` setting is an error in Misago 0.7 and should be removed. Likewise the `url(r'^', include('misago.datamover.urls'))` entry in your `urls.py` will also error and has to be removed.
+
+If you have updated to Misago 0.6 from Misago 0.5 and you looking to preserve redirects from old links after update to 0.7, please use the [Misago 0.5 Redirects](https://github.com/rafalp/Misago-05-Redirects) app.
+
+
+### `CreatePartialIndex` and `CreatePartialCompositeIndex` migration utilities have been removed
+
+0.7 release finalizes deprecation of previous implementation of custom indexes via removal of old migration utilities as well as their migrations. Attempting the update from any of the 0.6's alphas to 0.7 and skipping the 0.6 final release on the way will lead to your database containing both old and new indexes which may be source of errors in future migrations.

+ 9 - 2
docs/UpgradingFrom05.md → docs/setup/UpgradingFrom05.md

@@ -1,7 +1,14 @@
-Upgrading from Misago 0.5
+Updating from Misago 0.5
 =========================
 
-Misago 0.6 comes with special utility that allows those upgrading from Misago 0.5 to move their data to new site. This utility, named `datamover`, provides set of management commands allowing you to move data over.
+Misago 0.6 comes with special utility that allows those updating from Misago 0.5 to move their data to new site. This utility, named `datamover`, provides set of management commands allowing you to move data over.
+
+
+##### Version support
+
+The `datamover` is only available in the Misago 0.6. If you are updating from Misago 0.5, make sure you've installed Misago 0.6 before moving on.
+
+If you have already updated to 0.6 and you looking to preserve redirects from old links after updating Misago to next version, please use the [Misago 0.5 Redirects](https://github.com/rafalp/Misago-05-Redirects) app.
 
 
 ##### Note:

+ 1 - 1
misago/__init__.py

@@ -1 +1 @@
-__version__ = '0.6.0'
+__version__ = '0.7.0'

+ 0 - 79
misago/core/pgutils.py

@@ -2,8 +2,6 @@ from __future__ import unicode_literals
 
 from django.core.paginator import Paginator
 from django.db.models import Index
-from django.db.migrations.operations import RunSQL
-from django.utils.six import text_type
 
 
 class PgPartialIndex(Index):
@@ -98,83 +96,6 @@ class PgPartialIndex(Index):
         return ' WHERE {}'.format(' AND '.join(sorted(clauses)))
 
 
-class CreatePartialIndex(RunSQL):
-    CREATE_SQL = """
-CREATE INDEX %(index_name)s ON %(table)s (%(field)s)
-WHERE %(condition)s;
-"""
-
-    REMOVE_SQL = """
-DROP INDEX %(index_name)s
-"""
-
-    def __init__(self, field, index_name, condition):
-        self.model, self.field = field.split('.')
-        self.index_name = index_name
-        self.condition = condition
-
-    @property
-    def reversible(self):
-        return True
-
-    def state_forwards(self, app_label, state):
-        pass
-
-    def database_forwards(self, app_label, schema_editor, from_state, to_state):
-        model = from_state.apps.get_model(app_label, self.model)
-
-        statement = self.CREATE_SQL % {
-            'index_name': self.index_name,
-            'table': model._meta.db_table,
-            'field': self.field,
-            'condition': self.condition,
-        }
-
-        schema_editor.execute(statement)
-
-    def database_backwards(self, app_label, schema_editor, from_state, to_state):
-        schema_editor.execute(self.REMOVE_SQL % {'index_name': self.index_name})
-
-    def describe(self):
-        message = "Create PostgreSQL partial index on field %s in %s for %s"
-        formats = (self.field, self.model_name, self.values)
-        return message % formats
-
-
-class CreatePartialCompositeIndex(CreatePartialIndex):
-    CREATE_SQL = """
-CREATE INDEX %(index_name)s ON %(table)s (%(fields)s)
-WHERE %(condition)s;
-"""
-
-    REMOVE_SQL = """
-DROP INDEX %(index_name)s
-"""
-
-    def __init__(self, model, fields, index_name, condition):
-        self.model = model
-        self.fields = fields
-        self.index_name = index_name
-        self.condition = condition
-
-    def database_forwards(self, app_label, schema_editor, from_state, to_state):
-        model = from_state.apps.get_model(app_label, self.model)
-
-        statement = self.CREATE_SQL % {
-            'index_name': self.index_name,
-            'table': model._meta.db_table,
-            'fields': ', '.join(self.fields),
-            'condition': self.condition,
-        }
-
-        schema_editor.execute(statement)
-
-    def describe(self):
-        message = ("Create PostgreSQL partial composite index on fields %s in %s for %s")
-        formats = (', '.join(self.fields), self.model_name, self.values)
-        return message % formats
-
-
 def batch_update(queryset, step=50):
     """util because psycopg2 iterators aren't memory effective in Dj<1.11"""
     paginator = Paginator(queryset.order_by('pk'), step)

+ 0 - 10
misago/datamover/__init__.py

@@ -1,10 +0,0 @@
-from django.utils.timezone import make_aware, utc
-
-from .conf import OLD_FORUM
-from .db import fetch_assoc
-
-
-def localise_datetime(datetime):
-    if datetime:
-        return make_aware(datetime, utc)
-    return None

+ 0 - 99
misago/datamover/attachments.py

@@ -1,99 +0,0 @@
-from __future__ import unicode_literals
-
-import os
-
-from django.contrib.auth import get_user_model
-from django.core.files import File
-
-from misago.threads.models import Attachment, AttachmentType, Post
-from misago.threads.serializers import AttachmentSerializer
-
-from . import OLD_FORUM, fetch_assoc, localise_datetime, movedids
-
-
-UserModel = get_user_model()
-
-IMAGE_TYPES = ('image/gif', 'image/jpeg', 'image/png', )
-
-
-def move_attachments(stdout, style):
-    query = 'SELECT * FROM misago_attachment ORDER BY id'
-
-    posts = []
-
-    attachment_types = {}
-    for attachment_type in AttachmentType.objects.all():
-        for mimetype in attachment_type.mimetypes_list:
-            attachment_types[mimetype] = attachment_type
-
-    for attachment in fetch_assoc(query):
-        if attachment['content_type'] not in attachment_types:
-            stdout.write(
-                style.WARNING("Skipping attachment: %s (invalid type)" % attachment['name'])
-            )
-            continue
-
-        if not attachment['post_id']:
-            stdout.write(style.WARNING("Skipping attachment: %s (orphaned)" % attachment['name']))
-            continue
-
-        filetype = attachment_types[attachment['content_type']]
-
-        post_pk = movedids.get('post', attachment['post_id'])
-        post = Post.objects.get(pk=post_pk)
-
-        if post_pk not in posts:
-            posts.append(post_pk)
-
-        uploader = None
-        if attachment['user_id']:
-            uploader_pk = movedids.get('user', attachment['user_id'])
-            uploader = UserModel.objects.get(pk=uploader_pk)
-
-        file_path = os.path.join(OLD_FORUM['ATTACHMENTS'], attachment['path'])
-        upload = OldAttachmentFile(open(file_path, 'rb'), attachment)
-
-        new_attachment = Attachment(
-            secret=Attachment.generate_new_secret(),
-            filetype=filetype,
-            post=post,
-            uploaded_on=localise_datetime(attachment['date']),
-            uploader=uploader,
-            uploader_name=attachment['user_name'],
-            uploader_slug=attachment['user_name_slug'],
-            uploader_ip=attachment['ip'],
-            filename=attachment['name'],
-            size=attachment['size'],
-        )
-
-        if attachment['content_type'] in IMAGE_TYPES:
-            new_attachment.set_image(upload)
-        else:
-            new_attachment.set_file(upload)
-
-        new_attachment.save()
-
-        movedids.set('attachment', attachment['id'], new_attachment.pk)
-
-    update_attachments_caches(posts)
-
-
-def update_attachments_caches(posts):
-    for post in Post.objects.filter(pk__in=posts).iterator():
-        attachments = post.attachment_set.order_by('id')
-        post.attachments_cache = AttachmentSerializer(attachments, many=True).data
-        for attachment in post.attachments_cache:
-            del attachment['acl']
-            del attachment['post']
-            del attachment['uploader_ip']
-        post.save()
-
-
-class OldAttachmentFile(File):
-    def __init__(self, file, attachment):
-        self._attachment = attachment
-        self.name = attachment['name']
-
-        self.file = file
-        if hasattr(file, 'mode'):
-            self.mode = file.mode

+ 0 - 68
misago/datamover/avatars.py

@@ -1,68 +0,0 @@
-from __future__ import unicode_literals
-
-import os
-
-from django.contrib.auth import get_user_model
-from django.core.exceptions import ValidationError
-
-from misago.conf import settings
-from misago.users.avatars import dynamic, gravatar, store, uploaded
-
-from . import OLD_FORUM, fetch_assoc, movedids
-
-
-UserModel = get_user_model()
-
-
-def move_avatars(stdout, style):
-    for old_user in fetch_assoc('SELECT * FROM misago_user ORDER BY id'):
-        user = UserModel.objects.get(pk=movedids.get('user', old_user['id']))
-
-        if old_user['avatar_ban'] or old_user['avatar_type'] == 'gallery':
-            dynamic.set_avatar(user)
-        else:
-            if old_user['avatar_type'] == 'gravatar':
-                try:
-                    gravatar.set_avatar(user)
-                except gravatar.GravatarError:
-                    dynamic.set_avatar(user)
-                    print_warning('%s: failed to download Gravatar' % user, stdout, style)
-            else:
-                try:
-                    if not old_user['avatar_original'] or not old_user['avatar_crop']:
-                        raise ValidationError("Invalid avatar upload data.")
-
-                    image_path = os.path.join(
-                        OLD_FORUM['MEDIA'], 'avatars', old_user['avatar_original']
-                    )
-                    image = uploaded.validate_dimensions(image_path)
-
-                    cleaned_crop = convert_crop(image, old_user)
-                    uploaded.clean_crop(image, cleaned_crop)
-
-                    store.store_temporary_avatar(user, image)
-                    uploaded.crop_source_image(user, 'tmp', cleaned_crop)
-                except ValidationError as e:
-                    dynamic.set_avatar(user)
-                    print_warning('%s: %s' % (user, e.args[0]), stdout, style)
-
-        user.save()
-
-
-def print_warning(warning, stdout, style):
-    stdout.write(style.ERROR(warning))
-
-
-def convert_crop(image, user):
-    min_size = max(settings.MISAGO_AVATARS_SIZES)
-    x, y, s = [float(v) for v in user['avatar_crop'].split(',')]
-
-    zoom = min_size / s
-
-    return {
-        'offset': {
-            'x': x * zoom * -1,
-            'y': y * zoom * -1,
-        },
-        'zoom': zoom,
-    }

+ 0 - 38
misago/datamover/bans.py

@@ -1,38 +0,0 @@
-from __future__ import unicode_literals
-
-from misago.users.models import Ban
-
-from . import fetch_assoc, localise_datetime
-
-
-CHECK_MAPPING = {1: 0, 2: 1, 3: 2}
-
-
-def move_bans():
-    for ban in fetch_assoc('SELECT * FROM misago_ban'):
-        if ban['test']:
-            Ban.objects.create(
-                check_type=CHECK_MAPPING[ban['test']],
-                banned_value=ban['ban'],
-                user_message=ban['reason_user'],
-                staff_message=ban['reason_admin'],
-                expires_on=localise_datetime(ban['expires']),
-            )
-        else:
-            Ban.objects.create(
-                check_type=0,
-                banned_value=ban['ban'],
-                user_message=ban['reason_user'],
-                staff_message=ban['reason_admin'],
-                expires_on=localise_datetime(ban['expires']),
-            )
-
-            Ban.objects.create(
-                check_type=1,
-                banned_value=ban['ban'],
-                user_message=ban['reason_user'],
-                staff_message=ban['reason_admin'],
-                expires_on=localise_datetime(ban['expires']),
-            )
-
-    Ban.objects.invalidate_cache()

+ 0 - 86
misago/datamover/categories.py

@@ -1,86 +0,0 @@
-from __future__ import unicode_literals
-
-from misago.categories.models import Category
-
-from . import fetch_assoc, movedids
-
-
-def move_categories(stdout, style):
-    query = '''
-        SELECT *
-        FROM
-            misago_forum
-        WHERE
-            tree_id = %s AND level > 0
-        ORDER BY
-            lft
-    '''
-
-    root = Category.objects.root_category()
-    for forum in fetch_assoc(query, [get_root_tree()]):
-        if forum['type'] == 'redirect':
-            stdout.write(style.ERROR('Skipping redirect: %s' % forum['name']))
-            continue
-
-        if forum['level'] == 1:
-            parent = root
-        else:
-            new_parent_id = movedids.get('category', forum['parent_id'])
-            parent = Category.objects.get(pk=new_parent_id)
-
-        category = Category.objects.insert_node(
-            Category(
-                name=forum['name'],
-                slug=forum['slug'],
-                description=forum['description'],
-                is_closed=forum['closed'],
-                prune_started_after=forum['prune_start'],
-                prune_replied_after=forum['prune_last'],
-            ),
-            parent,
-            save=True,
-        )
-
-        movedids.set('category', forum['id'], category.pk)
-
-    # second pass: move prune_archive_id
-    for forum in fetch_assoc(query, [get_root_tree()]):
-        if not forum['pruned_archive_id']:
-            continue
-
-        new_category_pk = movedids.get('category', forum['id'])
-        new_archive_pk = movedids.get('category', forum['pruned_archive_id'])
-
-        Category.objects.filter(pk=new_category_pk).update(
-            archive_pruned_in=Category.objects.get(pk=new_archive_pk),
-        )
-
-
-def get_root_tree():
-    query = 'SELECT tree_id FROM misago_forum WHERE special = %s'
-    for root in fetch_assoc(query, ['root']):
-        return root['tree_id']
-
-
-def move_labels():
-    labels = []
-    for label in fetch_assoc('SELECT * FROM misago_threadprefix ORDER BY slug'):
-        labels.append(label)
-
-    for label in labels:
-        query = 'SELECT * FROM misago_threadprefix_forums WHERE threadprefix_id= %s'
-        for parent_row in fetch_assoc(query, [label['id']]):
-            parent_id = movedids.get('category', parent_row['forum_id'])
-            parent = Category.objects.get(pk=parent_id)
-
-            category = Category.objects.insert_node(
-                Category(
-                    name=label['name'],
-                    slug=label['slug'],
-                ),
-                parent,
-                save=True,
-            )
-
-            label_id = '%s-%s' % (label['id'], parent_row['forum_id'])
-            movedids.set('label', label_id, category.pk)

+ 0 - 4
misago/datamover/conf.py

@@ -1,4 +0,0 @@
-from django.conf import settings
-
-
-OLD_FORUM = getattr(settings, 'MISAGO_OLD_FORUM', None)

+ 0 - 13
misago/datamover/db.py

@@ -1,13 +0,0 @@
-from django.db import connections
-
-
-def fetch_assoc(query, *args):
-    """return all rows from a cursor as a dict"""
-    with connections['misago05'].cursor() as cursor:
-        cursor.execute(query, *args)
-
-        columns = [col[0] for col in cursor.description]
-        row = cursor.fetchone()
-        while row:
-            yield dict(zip(columns, row))
-            row = cursor.fetchone()

+ 0 - 0
misago/datamover/management/__init__.py


+ 0 - 36
misago/datamover/management/base.py

@@ -1,36 +0,0 @@
-import time
-
-from django.conf import settings
-from django.core.management import base
-
-from misago.datamover import OLD_FORUM
-
-
-CommandError = base.CommandError
-
-
-class BaseCommand(base.BaseCommand):
-    def execute(self, *args, **options):
-        self.check_move_setup()
-
-        return super(BaseCommand, self).execute(*args, **options)
-
-    def check_move_setup(self):
-        if not 'misago05' in settings.DATABASES:
-            raise CommandError(
-                "You need to configure connection for your old database by "
-                "adding \"misago05\" connection to your DATABASES"
-            )
-
-        if not OLD_FORUM:
-            raise CommandError(
-                "You need to configure migration from old forum by defining "
-                "MISAGO_OLD_FORUM setting in your settings.py"
-            )
-
-    def start_timer(self):
-        self._timer = time.time()
-
-    def stop_timer(self):
-        total_time = time.time() - self._timer
-        return time.strftime('%H:%M:%S', time.gmtime(total_time))

+ 0 - 0
misago/datamover/management/commands/__init__.py


+ 0 - 36
misago/datamover/management/commands/buildmovesindex.py

@@ -1,36 +0,0 @@
-from misago.core.pgutils import batch_update
-from misago.datamover.management.base import BaseCommand
-from misago.datamover.models import MovedId, OldIdRedirect
-
-
-MAPPINGS = {
-    'category': OldIdRedirect.CATEGORY,
-    'post': OldIdRedirect.POST,
-    'thread': OldIdRedirect.THREAD,
-    'user': OldIdRedirect.USER,
-}
-
-
-class Command(BaseCommand):
-    help = ("Builds moves index for redirects from old urls to new ones.")
-
-    def handle(self, *args, **options):
-        self.stdout.write("Building moves index...")
-
-        counter = 1
-        self.start_timer()
-
-        for moved_id in batch_update(MovedId.objects):
-            counter += 1
-
-            if moved_id.model not in MAPPINGS:
-                continue
-
-            OldIdRedirect.objects.create(
-                model=MAPPINGS[moved_id.model],
-                old_id=moved_id.old_id,
-                new_id=moved_id.new_id,
-            )
-
-        summary = "Indexed %s items in %s" % (counter, self.stop_timer())
-        self.stdout.write(self.style.SUCCESS(summary))

+ 0 - 17
misago/datamover/management/commands/movecategories.py

@@ -1,17 +0,0 @@
-from misago.datamover import categories
-from misago.datamover.management.base import BaseCommand
-
-
-class Command(BaseCommand):
-    help = "Moves categories and labels from Misago 0.5"
-
-    def handle(self, *args, **options):
-        self.stdout.write("Moving categories from Misago 0.5:")
-
-        self.start_timer()
-        categories.move_categories(self.stdout, self.style)
-        self.stdout.write(self.style.SUCCESS("Moved categories in %s" % self.stop_timer()))
-
-        self.start_timer()
-        categories.move_labels()
-        self.stdout.write(self.style.SUCCESS("Moved labels in %s" % self.stop_timer()))

+ 0 - 14
misago/datamover/management/commands/movesettings.py

@@ -1,14 +0,0 @@
-from misago.datamover.management.base import BaseCommand
-from misago.datamover.settings import move_settings
-
-
-class Command(BaseCommand):
-    help = "Moves settings from Misago 0.5"
-
-    def handle(self, *args, **options):
-        self.stdout.write("Moving settings from Misago 0.5:")
-
-        self.start_timer()
-        move_settings(self.stdout)
-
-        self.stdout.write(self.style.SUCCESS("Moved settings in %s" % self.stop_timer()))

+ 0 - 51
misago/datamover/management/commands/movethreads.py

@@ -1,51 +0,0 @@
-from misago.datamover import attachments, markup, polls, threads
-from misago.datamover.management.base import BaseCommand
-
-
-class Command(BaseCommand):
-    help = "Moves threads and posts from Misago 0.5"
-
-    def handle(self, *args, **options):
-        self.stdout.write("Moving threads from Misago 0.5:")
-
-        self.start_timer()
-        threads.move_threads(self.stdout, self.style)
-        self.stdout.write(self.style.SUCCESS("Moved threads in %s" % self.stop_timer()))
-
-        self.start_timer()
-        threads.move_posts()
-        self.stdout.write(self.style.SUCCESS("Moved posts in %s" % self.stop_timer()))
-
-        self.start_timer()
-        threads.move_mentions()
-        self.stdout.write(self.style.SUCCESS("Moved mentions in %s" % self.stop_timer()))
-
-        self.start_timer()
-        threads.move_edits()
-        self.stdout.write(self.style.SUCCESS("Moved edits histories in %s" % self.stop_timer()))
-
-        self.start_timer()
-        threads.move_likes()
-        self.stdout.write(self.style.SUCCESS("Moved likes in %s" % self.stop_timer()))
-
-        self.start_timer()
-        attachments.move_attachments(self.stdout, self.style)
-        self.stdout.write(self.style.SUCCESS("Moved attachments in %s" % self.stop_timer()))
-
-        self.start_timer()
-        polls.move_polls()
-        self.stdout.write(self.style.SUCCESS("Moved polls in %s" % self.stop_timer()))
-
-        self.start_timer()
-        threads.move_participants()
-        self.stdout.write(
-            self.style.SUCCESS("Moved threads participants in %s" % self.stop_timer())
-        )
-
-        self.start_timer()
-        threads.clean_private_threads(self.stdout, self.style)
-        self.stdout.write(self.style.SUCCESS("Cleaned private threads in %s" % self.stop_timer()))
-
-        self.start_timer()
-        markup.clean_posts()
-        self.stdout.write(self.style.SUCCESS("Cleaned markup in %s" % self.stop_timer()))

+ 0 - 33
misago/datamover/management/commands/moveusers.py

@@ -1,33 +0,0 @@
-from misago.datamover import avatars, bans, users
-from misago.datamover.management.base import BaseCommand
-
-
-class Command(BaseCommand):
-    help = ("Moves users, avatars, followers, blocks and bans from Misago 0.5")
-
-    def handle(self, *args, **options):
-        self.stdout.write("Moving users from Misago 0.5:")
-
-        self.start_timer()
-        users.move_users(self.stdout, self.style)
-        self.stdout.write(self.style.SUCCESS("Moved users in %s" % self.stop_timer()))
-
-        self.start_timer()
-        avatars.move_avatars(self.stdout, self.style)
-        self.stdout.write(self.style.SUCCESS("Moved avatars in %s" % self.stop_timer()))
-
-        self.start_timer()
-        users.move_followers()
-        self.stdout.write(self.style.SUCCESS("Moved followers in %s" % self.stop_timer()))
-
-        self.start_timer()
-        users.move_blocks()
-        self.stdout.write(self.style.SUCCESS("Moved blocks in %s" % self.stop_timer()))
-
-        self.start_timer()
-        users.move_namehistory()
-        self.stdout.write(self.style.SUCCESS("Moved name history in %s" % self.stop_timer()))
-
-        self.start_timer()
-        bans.move_bans()
-        self.stdout.write(self.style.SUCCESS("Moved bans in %s" % self.stop_timer()))

+ 0 - 33
misago/datamover/management/commands/runmigration.py

@@ -1,33 +0,0 @@
-from django.core.management import call_command
-
-from misago.datamover.management.base import BaseCommand
-
-
-MOVE_COMMANDS = [
-    'movesettings',
-    'moveusers',
-    'movecategories',
-    'movethreads',
-    'buildmovesindex',
-    'synchronizethreads',
-    'synchronizecategories',
-    'rebuildpostssearch',
-    'invalidatebans',
-    'populateonlinetracker',
-    'synchronizeusers',
-]
-
-
-class Command(BaseCommand):
-    help = ("Executes complete migration from Misago 0.5 together with cleanups.")
-
-    def handle(self, *args, **options):
-        self.stdout.write("Running complete migration...")
-
-        self.start_timer()
-
-        for command_to_call in MOVE_COMMANDS:
-            call_command(command_to_call)
-
-        summary = "Migration was completed in %s" % self.stop_timer()
-        self.stdout.write(self.style.SUCCESS(summary))

+ 0 - 41
misago/datamover/markup/__init__.py

@@ -1,41 +0,0 @@
-from __future__ import unicode_literals
-
-from django.utils.crypto import get_random_string
-
-from misago.core.pgutils import batch_update
-from misago.markup import common_flavour
-from misago.threads.checksums import update_post_checksum
-from misago.threads.models import Post
-
-from .attachments import update_attachments_urls
-from .quotes import convert_quotes_to_bbcode
-
-
-def clean_posts():
-    for post in batch_update(Post.objects):
-        post.original = clean_original(post.original)
-
-        parsed_post = common_flavour(FakeRequest(), FakeUser(), post.original)
-        post.parsed = parsed_post['parsed_text']
-
-        update_post_checksum(post)
-        post.save()
-
-
-def clean_original(post):
-    post = convert_quotes_to_bbcode(post)
-    post = update_attachments_urls(post)
-
-    return post
-
-
-class FakeUser(object):
-    slug = get_random_string(40)
-
-
-class FakeRequest(object):
-    scheme = 'http'
-    user = FakeUser()
-
-    def get_host(self):
-        return '{}.com'.format(get_random_string(40))

+ 0 - 50
misago/datamover/markup/attachments.py

@@ -1,50 +0,0 @@
-from __future__ import unicode_literals
-
-import re
-
-from misago.datamover import fetch_assoc, movedids
-from misago.threads.models import Attachment
-
-
-ATTACHMENT_RE = re.compile(r'/attachment/(?P<hash>[a-z0-9]+)/')
-ATTACHMENT_THUMB_RE = re.compile(r'/attachment/thumb/(?P<hash>[a-z0-9]+)/')
-
-
-def update_attachments_urls(post):
-    if '/attachment/' not in post:
-        return post
-
-    post = ATTACHMENT_THUMB_RE.sub(update_thumb_url, post)
-    post = ATTACHMENT_RE.sub(update_full_url, post)
-
-    return post
-
-
-def update_thumb_url(matchobj):
-    hash = matchobj.group('hash')
-    attachment = get_attachment_for_hash(hash)
-    if attachment:
-        if attachment.thumbnail:
-            return attachment.get_thumbnail_url()
-        else:
-            return attachment.get_absolute_url()
-    return matchobj.group(0)
-
-
-def update_full_url(matchobj):
-    hash = matchobj.group('hash')
-    attachment = get_attachment_for_hash(hash)
-    if attachment:
-        return attachment.get_absolute_url()
-    return matchobj.group(0)
-
-
-def get_attachment_for_hash(hash):
-    query = 'SELECT * FROM misago_attachment WHERE hash_id = %s'
-    for attachment in fetch_assoc(query, [hash]):
-        attachment_pk = movedids.get('attachment', attachment['id'])
-        try:
-            return Attachment.objects.get(pk=attachment_pk)
-        except Attachment.DoesNotExist:
-            return None
-    return None

+ 0 - 45
misago/datamover/markup/quotes.py

@@ -1,45 +0,0 @@
-from __future__ import unicode_literals
-
-
-def convert_quotes_to_bbcode(post):
-    if not (post[0] == '>' or '\n>' in post):
-        return post
-
-    clean_lines = []
-
-    in_quote = False
-    quote_author = None
-    quote = []
-
-    for line in post.splitlines() + ['']:
-        if in_quote:
-            if line.startswith('>'):
-                quote.append(line[1:].lstrip())
-            else:
-                clean_lines.append('')
-
-                if quote_author:
-                    clean_lines.append('[quote="%s"]' % quote_author)
-                else:
-                    clean_lines.append('[quote]')
-
-                clean_lines += quote
-                clean_lines.append('[/quote]')
-                clean_lines.append('')
-
-                in_quote = False
-                quote_author = None
-                quote = []
-
-                clean_lines.append(line)
-        elif line.startswith('>'):
-            in_quote = True
-
-            if clean_lines and clean_lines[-1].startswith('@'):
-                quote_author = clean_lines.pop(-1)
-
-            quote.append(line[1:].lstrip())
-        else:
-            clean_lines.append(line)
-
-    return convert_quotes_to_bbcode('\n'.join(clean_lines))

+ 0 - 45
misago/datamover/migrations/0001_initial.py

@@ -1,45 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.10.4 on 2016-12-30 22:47
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    initial = True
-
-    dependencies = []
-
-    operations = [
-        migrations.CreateModel(
-            name='MovedId',
-            fields=[
-                (
-                    'id', models.AutoField(
-                        auto_created=True, primary_key=True, serialize=False, verbose_name='ID'
-                    )
-                ),
-                ('model', models.CharField(max_length=255)),
-                ('old_id', models.CharField(max_length=255)),
-                ('new_id', models.CharField(max_length=255)),
-            ],
-        ),
-        migrations.CreateModel(
-            name='OldIdRedirect',
-            fields=[
-                (
-                    'id', models.AutoField(
-                        auto_created=True, primary_key=True, serialize=False, verbose_name='ID'
-                    )
-                ),
-                ('model', models.PositiveIntegerField()),
-                ('old_id', models.PositiveIntegerField()),
-                ('new_id', models.PositiveIntegerField()),
-            ],
-        ),
-        migrations.AlterIndexTogether(
-            name='oldidredirect',
-            index_together=set([('model', 'old_id')]),
-        ),
-    ]

+ 0 - 0
misago/datamover/migrations/__init__.py


+ 0 - 23
misago/datamover/models.py

@@ -1,23 +0,0 @@
-from django.db import models
-
-
-class MovedId(models.Model):
-    model = models.CharField(max_length=255)
-    old_id = models.CharField(max_length=255)
-    new_id = models.CharField(max_length=255)
-
-
-class OldIdRedirect(models.Model):
-    CATEGORY = 0
-    POST = 1
-    THREAD = 2
-    USER = 3
-
-    model = models.PositiveIntegerField()
-    old_id = models.PositiveIntegerField()
-    new_id = models.PositiveIntegerField()
-
-    class Meta:
-        index_together = [
-            ['model', 'old_id'],
-        ]

+ 0 - 15
misago/datamover/movedids.py

@@ -1,15 +0,0 @@
-def get(model, id):
-    from .models import MovedId
-    try:
-        return MovedId.objects.get(model=model, old_id=id).new_id
-    except MovedId.DoesNotExist:
-        return None
-
-
-def set(model, old_id, new_id):
-    from .models import MovedId
-    MovedId.objects.create(
-        model=model,
-        old_id=old_id,
-        new_id=new_id,
-    )

+ 0 - 72
misago/datamover/polls.py

@@ -1,72 +0,0 @@
-from django.contrib.auth import get_user_model
-from django.utils.crypto import get_random_string
-
-from misago.threads.models import Poll, PollVote, Thread
-
-from . import fetch_assoc, localise_datetime, movedids
-
-
-UserModel = get_user_model()
-
-
-def move_polls():
-    for poll in fetch_assoc('SELECT * FROM misago_poll ORDER BY thread_id'):
-        thread_pk = movedids.get('thread', poll['thread_id'])
-        thread = Thread.objects.select_related().get(pk=thread_pk)
-
-        poster = None
-        if poll['user_id']:
-            poster_pk = movedids.get('user', poll['user_id'])
-            poster = UserModel.objects.get(pk=poster_pk)
-
-        choices = []
-        choices_map = {}
-
-        query = 'SELECT * FROM misago_polloption WHERE poll_id = %s ORDER BY id'
-        for choice in fetch_assoc(query, [poll['thread_id']]):
-            choices.append({
-                'hash': get_random_string(12),
-                'label': choice['name'],
-                'votes': choice['votes'],
-            })
-
-            choices_map[choice['id']] = choices[-1]['hash']
-
-        new_poll = Poll.objects.create(
-            category=thread.category,
-            thread=thread,
-            poster=poster,
-            poster_name=poll['user_name'],
-            poster_slug=poll['user_slug'],
-            poster_ip=thread.post_set.order_by('id').first().poster_ip,
-            posted_on=localise_datetime(poll['start_date']),
-            length=poll['length'],
-            question=poll['question'],
-            choices=choices,
-            allowed_choices=poll['max_choices'],
-            allow_revotes=poll['vote_changing'],
-            votes=poll['votes'],
-            is_public=poll['public'],
-        )
-
-        query = 'SELECT * FROM misago_pollvote WHERE poll_id = %s ORDER BY id'
-        for vote in fetch_assoc(query, [poll['thread_id']]):
-            if not vote['option_id']:
-                continue
-
-            voter = None
-            if vote['user_id']:
-                voter_pk = movedids.get('user', vote['user_id'])
-                voter = UserModel.objects.get(pk=voter_pk)
-
-            PollVote.objects.create(
-                category=thread.category,
-                thread=thread,
-                poll=new_poll,
-                voter=voter,
-                voter_name=vote['user_name'],
-                voter_slug=vote['user_slug'],
-                voter_ip=vote['ip'],
-                voted_on=localise_datetime(vote['date']),
-                choice_hash=choices_map[vote['option_id']],
-            )

+ 0 - 93
misago/datamover/settings.py

@@ -1,93 +0,0 @@
-from __future__ import unicode_literals
-
-from misago.conf import db_settings
-from misago.conf.models import Setting
-
-from . import fetch_assoc
-
-
-def copy_value(setting):
-    def closure(old_value):
-        setting_obj = Setting.objects.get(setting=setting)
-        setting_obj.value = old_value
-        setting_obj.save()
-        return setting_obj
-
-    return closure
-
-
-def map_value(setting, translation):
-    def closure(old_value):
-        setting_obj = Setting.objects.get(setting=setting)
-        setting_obj.value = translation[old_value]
-        setting_obj.save()
-        return setting_obj
-
-    return closure
-
-
-def convert_allow_custom_avatars(old_value):
-    setting_obj = Setting.objects.get(setting='allow_custom_avatars')
-    setting_obj.value = 'upload' in old_value.split(',')
-    setting_obj.save()
-    return setting_obj
-
-
-SETTING_CONVERTER = {
-    'board_name': copy_value('forum_name'),
-    'board_index_title': copy_value('forum_index_title'),
-    'board_index_meta': copy_value('forum_index_meta_description'),
-    'board_header': copy_value('forum_branding_text'),
-    'email_footnote_plain': copy_value('email_footer'),
-    'tos_title': copy_value('terms_of_service_title'),
-    'tos_url': copy_value('terms_of_service_link'),
-    'tos_content': copy_value('terms_of_service'),
-    'board_credits': copy_value('forum_footnote'),
-    'thread_name_min': copy_value('thread_title_length_min'),
-    'thread_name_max': copy_value('thread_title_length_max'),
-    'post_length_min': copy_value('post_length_min'),
-    'account_activation': map_value(
-        'account_activation', {
-            'none': 'none',
-            'user': 'user',
-            'admin': 'admin',
-            'block': 'closed',
-        }
-    ),
-    'username_length_min': copy_value('username_length_min'),
-    'username_length_max': copy_value('username_length_max'),
-    'password_length': copy_value('password_length_min'),
-    'avatars_types': convert_allow_custom_avatars,
-    'default_avatar': copy_value('default_avatar'),
-    'upload_limit': copy_value('avatar_upload_limit'),
-    'subscribe_start': map_value('subscribe_start', {
-        '0': 'no',
-        '1': 'watch',
-        '2': 'watch_email',
-    }),
-    'subscribe_reply': map_value('subscribe_reply', {
-        '0': 'no',
-        '1': 'watch',
-        '2': 'watch_email',
-    }),
-    'bots_registration': map_value('captcha_type', {
-        'no': 'no',
-        'recaptcha': 're',
-        'qa': 'qa',
-    }),
-    'recaptcha_public': copy_value('recaptcha_site_key'),
-    'recaptcha_private': copy_value('recaptcha_secret_key'),
-    'qa_test': copy_value('qa_question'),
-    'qa_test_help': copy_value('qa_help_text'),
-    'qa_test_answers': copy_value('qa_answers'),
-}
-
-
-def move_settings(stdout=None):
-    for row in fetch_assoc('SELECT * FROM misago_setting'):
-        setting_key = row['setting']
-        if setting_key in SETTING_CONVERTER:
-            convert_setting = SETTING_CONVERTER[setting_key]
-            setting_obj = convert_setting(row['value'])
-            stdout.write(setting_obj.name)
-    db_settings.flush_cache()

+ 0 - 266
misago/datamover/threads.py

@@ -1,266 +0,0 @@
-from __future__ import unicode_literals
-
-from django.contrib.auth import get_user_model
-from django.utils import timezone
-
-from misago.categories.models import Category
-from misago.threads.models import Post, PostEdit, PostLike, Thread, ThreadParticipant
-
-from . import fetch_assoc, localise_datetime, markup, movedids
-
-
-UserModel = get_user_model()
-
-
-def move_threads(stdout, style):
-    special_categories = get_special_categories_dict()
-
-    for thread in fetch_assoc('SELECT * FROM misago_thread ORDER BY id'):
-        if special_categories.get(thread['forum_id']) == 'reports':
-            stdout.write(style.WARNING("Skipping report: %s" % thread['name']))
-            continue
-
-        if not thread['start_post_id']:
-            stdout.write(style.ERROR("Corrupted thread: %s" % thread['name']))
-            continue
-
-        if special_categories.get(thread['forum_id']) == 'private_threads':
-            category = Category.objects.private_threads()
-        else:
-            if thread['prefix_id']:
-                label_id = '%s-%s' % (thread['prefix_id'], thread['forum_id'])
-                category_pk = movedids.get('label', label_id)
-            else:
-                category_pk = movedids.get('category', thread['forum_id'])
-            category = Category.objects.get(pk=category_pk)
-
-        new_thread = Thread.objects.create(
-            category=category,
-            title=thread['name'],
-            slug=thread['slug'],
-            started_on=timezone.now(),
-            last_post_on=timezone.now(),
-            starter_name='none',
-            starter_slug='none',
-            weight=thread['weight'],
-            is_hidden=thread['deleted'],
-            is_closed=thread['closed'],
-        )
-
-        movedids.set('thread', thread['id'], new_thread.pk)
-
-
-def move_posts():
-    special_categories = get_special_categories_dict()
-
-    for post in fetch_assoc('SELECT * FROM misago_post ORDER BY id'):
-        if special_categories.get(post['forum_id']) == 'reports':
-            continue
-
-        thread_pk = movedids.get('thread', post['thread_id'])
-        thread = Thread.objects.select_related('category').get(pk=thread_pk)
-
-        poster = None
-        last_editor = None
-
-        if post['user_id']:
-            poster_id = movedids.get('user', post['user_id'])
-            poster = UserModel.objects.get(pk=poster_id)
-
-        if post['edit_user_id']:
-            last_editor_id = movedids.get('user', post['edit_user_id'])
-            last_editor = UserModel.objects.get(pk=last_editor_id)
-
-        deleter = None
-        deleter_name = None
-        deleter_slug = None
-        if post['deleted']:
-            deleter = UserModel.objects.filter(is_staff=True).order_by('id').last()
-
-            if deleter:
-                deleter_name = deleter.username
-                deleter_slug = deleter.slug
-            else:
-                deleter = poster
-                deleter_name = poster.username
-                deleter_slug = poster.slug
-
-        new_post = Post.objects.create(
-            category=thread.category,
-            thread=thread,
-            poster=poster,
-            poster_name=post['user_name'],
-            poster_ip=post['ip'],
-            original=post['post'],
-            parsed=post['post_preparsed'],
-            posted_on=localise_datetime(post['date']),
-            updated_on=localise_datetime(post['current_date'] or post['date']),
-            hidden_on=localise_datetime(post['delete_date'] or post['date']),
-            edits=post['edits'],
-            last_editor=last_editor,
-            last_editor_name=post['edit_user_name'],
-            last_editor_slug=post['edit_user_slug'],
-            hidden_by=deleter,
-            hidden_by_name=deleter_name,
-            hidden_by_slug=deleter_slug,
-            is_hidden=post['deleted'],
-            is_protected=post['protected'],
-            likes=post['upvotes']
-        )
-
-        movedids.set('post', post['id'], new_post.pk)
-
-
-def move_mentions():
-    for metion in fetch_assoc('SELECT * FROM misago_post_mentions'):
-        try:
-            post_pk = movedids.get('post', metion['post_id'])
-            user_pk = movedids.get('user', metion['user_id'])
-
-            post = Post.objects.get(pk=post_pk)
-            user = UserModel.objects.get(pk=user_pk)
-
-            post.mentions.add(user)
-        except:
-            continue
-
-
-def move_edits():
-    query = 'SELECT DISTINCT post_id FROM misago_change ORDER BY post_id'
-    for edit in fetch_assoc(query):
-        post_pk = movedids.get('post', edit['post_id'])
-        post = Post.objects.select_related().get(pk=post_pk)
-
-        move_post_edits(post, edit['post_id'])
-
-
-def move_post_edits(post, old_id):
-    query = '''
-        SELECT *
-        FROM
-            misago_change
-        WHERE
-            post_id = %s AND `change` <> 0
-        ORDER BY
-            id
-    '''
-
-    changelog = []
-    for edit in fetch_assoc(query, [old_id]):
-        if edit['user_id']:
-            editor_pk = movedids.get('user', edit['user_id'])
-            editor = UserModel.objects.get(pk=editor_pk)
-        else:
-            editor = None
-
-        if changelog:
-            changelog[-1].edited_to = markup.clean_original(edit['post_content'])
-
-        changelog.append(
-            PostEdit(
-                category=post.category,
-                thread=post.thread,
-                post=post,
-                edited_on=localise_datetime(edit['date']),
-                editor=editor,
-                editor_name=edit['user_name'],
-                editor_slug=edit['user_slug'],
-                editor_ip=edit['ip'],
-                edited_from=markup.clean_original(edit['post_content']),
-                edited_to=markup.clean_original(post.original),
-            )
-        )
-
-    if changelog:
-        PostEdit.objects.bulk_create(changelog)
-
-
-def move_likes():
-    query = '''
-        SELECT *
-        FROM
-            misago_karma
-        WHERE
-            score > 0
-        ORDER BY
-            id
-    '''
-
-    posts = []
-    for karma in fetch_assoc(query):
-        post_pk = movedids.get('post', karma['post_id'])
-        post = Post.objects.select_related().get(pk=post_pk)
-
-        if karma['user_id']:
-            liker_pk = movedids.get('user', karma['user_id'])
-            liker = UserModel.objects.get(pk=liker_pk)
-        else:
-            liker = None
-
-        PostLike.objects.create(
-            category=post.category,
-            thread=post.thread,
-            post=post,
-            liker=liker,
-            liker_name=karma['user_name'],
-            liker_slug=karma['user_slug'],
-            liker_ip=karma['ip'],
-            liked_on=localise_datetime(karma['date']),
-        )
-
-        posts.append(post_pk)
-
-    for post in Post.objects.filter(id__in=posts).iterator():
-        post.last_likes = []
-        for like in post.postlike_set.all()[:4]:
-            post.last_likes.append({'id': like.liker_id, 'username': like.liker_name})
-        post.save(update_fields=['last_likes'])
-
-
-def move_participants():
-    for participant in fetch_assoc('SELECT * FROM misago_thread_participants'):
-        thread_pk = movedids.get('thread', participant['thread_id'])
-        thread = Thread.objects.get(pk=thread_pk)
-
-        user_pk = movedids.get('user', participant['user_id'])
-        user = UserModel.objects.get(pk=user_pk)
-
-        starter = thread.post_set.order_by('id').first().poster
-
-        ThreadParticipant.objects.create(thread=thread, user=user, is_owner=(user == starter))
-
-
-def clean_private_threads(stdout, style):
-    category = Category.objects.private_threads()
-
-    # prune threads without participants
-    participated_threads = ThreadParticipant.objects.values_list('thread_id', flat=True).distinct()
-    for thread in category.thread_set.exclude(pk__in=participated_threads):
-        thread.delete()
-
-    # close threads with single participant, delete empty ones
-    for thread in category.thread_set.iterator():
-        participants_count = thread.participants.count()
-        if participants_count == 1:
-            thread.is_closed = True
-            thread.save()
-        elif participants_count == 0:
-            thread.delete()
-            stdout.write(style.ERROR("Delete empty private thread: %s" % thread.title))
-
-
-def get_special_categories_dict():
-    special_categories = {}
-
-    query = '''
-        SELECT
-            id, special
-        FROM
-            misago_forum
-        WHERE
-            special IS NOT NULL
-    '''
-
-    for special in fetch_assoc(query):
-        special_categories[special['id']] = special['special']
-    return special_categories

+ 0 - 241
misago/datamover/urls.py

@@ -1,241 +0,0 @@
-from django.conf.urls import url
-
-from . import views
-
-
-urlpatterns = [
-    url(r'^category/(?P<slug>(\w|-)+)-(?P<forum>\d+)/$', views.category_redirect),
-    url(r'^forum/(?P<slug>(\w|-)+)-(?P<forum>\d+)/$', views.category_redirect),
-    url(
-        r'^forum/(?P<slug>(\w|-)+)-(?P<forum>\d+)/(?P<page>[1-9]([0-9]+)?)/$',
-        views.category_redirect
-    ),
-    url(
-        r'^forum/(?P<slug>(\w|-)+)-(?P<forum>\d+)/prefix/(?P<prefix>(\w|-)+)/$',
-        views.category_redirect
-    ),
-    url(
-        r'^forum/(?P<slug>(\w|-)+)-(?P<forum>\d+)/prefix/(?P<prefix>(\w|-)+)/(?P<page>[1-9]([0-9]+)?)/$',
-        views.category_redirect
-    ),
-    url(r'^forum/(?P<slug>(\w|-)+)-(?P<forum>\d+)/start/$', views.category_redirect),
-]
-
-urlpatterns += [
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/edit/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/reply/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/vote/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/poll/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/reply/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/edit/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/$', views.thread_redirect),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<page>[1-9]([0-9]+)?)/$',
-        views.thread_redirect
-    ),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/last/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/find-(?P<post>\d+)/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/new/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/moderated/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/reported/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/show-hidden/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/watch/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/watch/email/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/unwatch/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/unwatch/email/$', views.thread_redirect),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/upvote/$', views.thread_redirect
-    ),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/downvote/$',
-        views.thread_redirect
-    ),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/report/$', views.thread_redirect
-    ),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/show-report/$',
-        views.thread_redirect
-    ),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/delete/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/hide/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/show/$', views.thread_redirect),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/delete/$', views.thread_redirect
-    ),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/hide/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/show/$', views.thread_redirect),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/checkpoint/(?P<checkpoint>\d+)/delete/$',
-        views.thread_redirect
-    ),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/checkpoint/(?P<checkpoint>\d+)/hide/$',
-        views.thread_redirect
-    ),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/checkpoint/(?P<checkpoint>\d+)/show/$',
-        views.thread_redirect
-    ),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/info/$', views.thread_redirect),
-    url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/votes/$', views.thread_redirect),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/$',
-        views.thread_redirect
-    ),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/(?P<change>\d+)/$',
-        views.thread_redirect
-    ),
-    url(
-        r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/(?P<change>\d+)/revert/$',
-        views.thread_redirect
-    ),
-]
-
-urlpatterns += [
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/edit/$', views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/reply/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/vote/$', views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/poll/$', views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/reply/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/edit/$',
-        views.private_thread_redirect
-    ),
-    url(r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/$', views.private_thread_redirect),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<page>[1-9]([0-9]+)?)/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/last/$', views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/find-(?P<post>\d+)/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/new/$', views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/moderated/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/reported/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/show-hidden/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/watch/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/watch/email/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/unwatch/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/unwatch/email/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/upvote/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/downvote/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/report/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/show-report/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/delete/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/hide/$', views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/show/$', views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/delete/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/hide/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/show/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/checkpoint/(?P<checkpoint>\d+)/delete/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/checkpoint/(?P<checkpoint>\d+)/hide/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/checkpoint/(?P<checkpoint>\d+)/show/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/info/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/votes/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/(?P<change>\d+)/$',
-        views.private_thread_redirect
-    ),
-    url(
-        r'^private-threads/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/(?P<change>\d+)/revert/$',
-        views.private_thread_redirect
-    ),
-]
-
-urlpatterns += [
-    url(r'^users/(?P<username>\w+)-(?P<user>\d+)/', views.user_redirect),
-    url(r'^users/(?P<username>\w+)-(?P<user>\d+)/(?P<page>\d+)/', views.user_redirect),
-    url(r'^users/(?P<username>\w+)-(?P<user>\d+)/(?P<subpage>(\w|-)+)/', views.user_redirect),
-    url(
-        r'^users/(?P<username>\w+)-(?P<user>\d+)/(?P<subpage>(\w|-)+)/(?P<page>\d+)/',
-        views.user_redirect
-    ),
-]

+ 0 - 138
misago/datamover/users.py

@@ -1,138 +0,0 @@
-from __future__ import unicode_literals
-
-from django.contrib.auth import get_user_model
-from django.core.exceptions import ValidationError
-from django.utils.crypto import get_random_string
-
-from misago.users.models import UsernameChange
-from misago.users.signatures import make_signature_checksum
-
-from . import fetch_assoc, localise_datetime, movedids
-
-
-UserModel = get_user_model()
-
-PRIVATE_THREAD_INVITES = {
-    0: 0,
-    1: 0,
-    2: 1,
-    3: 2,
-}
-
-
-def move_users(stdout, style):
-    existing_users = get_existing_users()
-
-    for user in fetch_assoc('SELECT * FROM misago_user ORDER BY id'):
-        if user['email'].lower() in existing_users:
-            user_new_pk = existing_users[user['email'].lower()]
-            new_user = UserModel.objects.get(pk=user_new_pk)
-        else:
-            try:
-                new_user = UserModel.objects.create_user(
-                    user['username'], user['email'], 'Pass.123'
-                )
-            except ValidationError:
-                new_name = ''.join([user['username'][:10], get_random_string(4)])
-                new_user = UserModel.objects.create_user(new_name, user['email'], 'Pass.123')
-
-                formats = (user['username'], new_name)
-                stdout.write(style.ERROR('"%s" has been registered as "%s"' % formats))
-
-            new_user.password = user['password']
-
-        new_user.joined_on = localise_datetime(user['join_date'])
-        new_user.joined_from_ip = user['join_ip']
-
-        new_user.last_login = localise_datetime(user['last_date'])
-        new_user.last_ip = user['last_ip']
-
-        new_user.is_hiding_presence = bool(user['hide_activity'])
-        new_user.title = user['title'] or None
-
-        new_user.requires_activation = user['activation']
-        if new_user.requires_activation > 2:
-            new_user.requires_activation = 1
-
-        new_user.is_avatar_locked = user['avatar_ban']
-        new_user.avatar_lock_user_message = user['avatar_ban_reason_user'] or None
-        new_user.avatar_lock_staff_message = user['avatar_ban_reason_admin'] or None
-
-        if user['signature'] and user['signature_preparsed']:
-            new_user.signature = user['signature']
-            new_user.signature_parsed = user['signature_preparsed']
-            new_user.signature_checksum = make_signature_checksum(
-                user['signature_preparsed'], new_user
-            )
-
-        new_user.is_signature_locked = user['signature_ban']
-        new_user.signature_lock_user_message = user['signature_ban_reason_user'] or None
-        new_user.signature_lock_staff_message = user['signature_ban_reason_admin'] or None
-
-        new_user.limits_private_thread_invites_to = PRIVATE_THREAD_INVITES[user['allow_pds']]
-
-        new_user.subscribe_to_started_threads = int(user['subscribe_start'])
-        new_user.subscribe_to_replied_threads = int(user['subscribe_reply'])
-
-        new_user.save()
-        movedids.set('user', user['id'], new_user.pk)
-
-
-def get_existing_users():
-    existing_users = {}
-
-    queryset = UserModel.objects.values_list('id', 'email')
-    for pk, email in queryset.iterator():
-        existing_users[email.lower()] = pk
-    return existing_users
-
-
-def move_followers():
-    for follow in fetch_assoc('SELECT * FROM misago_user_follows ORDER BY id'):
-        from_user_id = movedids.get('user', follow['from_user_id'])
-        to_user_id = movedids.get('user', follow['to_user_id'])
-
-        from_user = UserModel.objects.get(pk=from_user_id)
-        to_user = UserModel.objects.get(pk=to_user_id)
-
-        from_user.follows.add(to_user)
-
-
-def move_blocks():
-    for follow in fetch_assoc('SELECT * FROM misago_user_ignores ORDER BY id'):
-        from_user_id = movedids.get('user', follow['from_user_id'])
-        to_user_id = movedids.get('user', follow['to_user_id'])
-
-        from_user = UserModel.objects.get(pk=from_user_id)
-        to_user = UserModel.objects.get(pk=to_user_id)
-
-        from_user.blocks.add(to_user)
-
-
-def move_namehistory():
-    query = 'SELECT DISTINCT user_id FROM misago_usernamechange ORDER BY user_id'
-    for user in fetch_assoc(query):
-        new_id = movedids.get('user', user['user_id'])
-        new_user = UserModel.objects.get(pk=new_id)
-        move_users_namehistory(new_user, user['user_id'])
-
-
-def move_users_namehistory(user, old_id):
-    username_history = []
-    query = 'SELECT * FROM misago_usernamechange WHERE user_id = %s ORDER BY id'
-    for namechange in fetch_assoc(query, [old_id]):
-        if username_history:
-            username_history[-1].new_username = namechange['old_username']
-
-        username_history.append(
-            UsernameChange(
-                user=user,
-                changed_by=user,
-                changed_by_username=user.username,
-                changed_on=localise_datetime(namechange['date']),
-                new_username=user.username,
-                old_username=namechange['old_username']
-            )
-        )
-
-    UsernameChange.objects.bulk_create(username_history)

+ 0 - 50
misago/datamover/views.py

@@ -1,50 +0,0 @@
-from django.contrib.auth import get_user_model
-from django.shortcuts import get_object_or_404, redirect
-
-from misago.threads.viewmodels import ForumThread, PrivateThread, ThreadPost, ThreadsCategory
-
-from .models import OldIdRedirect
-
-
-UserModel = get_user_model()
-
-
-def category_redirect(request, **kwargs):
-    category_pk = get_new_id_or_404(OldIdRedirect.CATEGORY, kwargs['forum'])
-    category = ThreadsCategory(request, pk=category_pk)
-    return redirect(category.get_absolute_url(), permanent=True)
-
-
-def thread_redirect(request, **kwargs):
-    thread_pk = get_new_id_or_404(OldIdRedirect.THREAD, kwargs['thread'])
-    thread = ForumThread(request, pk=thread_pk)
-
-    if 'post' in kwargs:
-        post_pk = get_new_id_or_404(OldIdRedirect.POST, kwargs['post'])
-        post = ThreadPost(request, thread, pk=post_pk)
-        return redirect(post.get_absolute_url(), permanent=True)
-
-    return redirect(thread.get_absolute_url(), permanent=True)
-
-
-def private_thread_redirect(request, **kwargs):
-    thread_pk = get_new_id_or_404(OldIdRedirect.THREAD, kwargs['thread'])
-    thread = PrivateThread(request, pk=thread_pk)
-
-    if 'post' in kwargs:
-        post_pk = get_new_id_or_404(OldIdRedirect.POST, kwargs['post'])
-        post = ThreadPost(request, thread, pk=post_pk)
-        return redirect(post.get_absolute_url(), permanent=True)
-
-    return redirect(thread.get_absolute_url(), permanent=True)
-
-
-def user_redirect(request, **kwargs):
-    user_pk = get_new_id_or_404(OldIdRedirect.USER, kwargs['user'])
-    user = get_object_or_404(UserModel, pk=user_pk)
-
-    return redirect(user.get_absolute_url(), permanent=True)
-
-
-def get_new_id_or_404(model, old_id):
-    return get_object_or_404(OldIdRedirect, model=model, old_id=old_id).new_id

+ 0 - 3
misago/project_template/project_name/settings.py

@@ -192,9 +192,6 @@ INSTALLED_APPS = [
     'misago.readtracker',
     'misago.search',
     'misago.faker',
-
-    # Utility for moving data from Misago 0.5
-    'misago.datamover',
 ]
 
 INTERNAL_IPS = [

+ 0 - 51
misago/threads/migrations/0001_initial.py

@@ -9,7 +9,6 @@ from django.contrib.postgres.search import SearchVectorField
 from django.db import migrations, models
 
 import misago.threads.models.attachment
-from misago.core.pgutils import CreatePartialIndex
 
 
 class Migration(migrations.Migration):
@@ -97,16 +96,6 @@ class Migration(migrations.Migration):
             options={},
             bases=(models.Model, ),
         ),
-        CreatePartialIndex(
-            field='Post.has_open_reports',
-            index_name='misago_post_has_open_reports_partial',
-            condition='has_open_reports = TRUE',
-        ),
-        CreatePartialIndex(
-            field='Post.is_hidden',
-            index_name='misago_post_is_hidden_partial',
-            condition='is_hidden = FALSE',
-        ),
         migrations.CreateModel(
             name='Thread',
             fields=[
@@ -139,16 +128,6 @@ class Migration(migrations.Migration):
             options={},
             bases=(models.Model, ),
         ),
-        CreatePartialIndex(
-            field='Thread.weight',
-            index_name='misago_thread_is_global',
-            condition='weight = 2',
-        ),
-        CreatePartialIndex(
-            field='Thread.weight',
-            index_name='misago_thread_is_local',
-            condition='weight < 2',
-        ),
         migrations.CreateModel(
             name='ThreadParticipant',
             fields=[
@@ -184,36 +163,6 @@ class Migration(migrations.Migration):
             ),
             preserve_default=True,
         ),
-        CreatePartialIndex(
-            field='Thread.has_reported_posts',
-            index_name='misago_thread_has_reported_posts_partial',
-            condition='has_reported_posts = TRUE',
-        ),
-        CreatePartialIndex(
-            field='Thread.has_unapproved_posts',
-            index_name='misago_thread_has_unapproved_posts_partial',
-            condition='has_unapproved_posts = TRUE',
-        ),
-        CreatePartialIndex(
-            field='Thread.is_hidden',
-            index_name='misago_thread_is_hidden_partial',
-            condition='is_hidden = FALSE',
-        ),
-        CreatePartialIndex(
-            field='Thread.weight',
-            index_name='misago_thread_is_pinned_globally_partial',
-            condition='weight = 2',
-        ),
-        CreatePartialIndex(
-            field='Thread.weight',
-            index_name='misago_thread_is_pinned_locally_partial',
-            condition='weight = 1',
-        ),
-        CreatePartialIndex(
-            field='Thread.weight',
-            index_name='misago_thread_is_unpinned_partial',
-            condition='weight = 0',
-        ),
         migrations.AddField(
             model_name='post',
             name='thread',

+ 0 - 81
misago/threads/migrations/0006_redo_partial_indexes.py

@@ -16,87 +16,6 @@ class Migration(migrations.Migration):
     ]
 
     operations = [
-        migrations.RunSQL(
-            "DROP INDEX misago_post_has_open_reports_partial",
-            """
-                CREATE INDEX misago_post_has_open_reports_partial
-                ON misago_threads_post(has_open_reports)
-                WHERE has_open_reports = TRUE
-            """,
-        ),
-        migrations.RunSQL(
-            "DROP INDEX misago_post_is_hidden_partial",
-            """
-                CREATE INDEX misago_post_is_hidden_partial
-                ON misago_threads_post(is_hidden)
-                WHERE is_hidden = FALSE
-            """,
-        ),
-        migrations.RunSQL(
-            "DROP INDEX misago_thread_is_global",
-            """
-                CREATE INDEX misago_thread_is_global
-                ON misago_threads_thread(weight)
-                WHERE weight = 2
-            """,
-        ),
-        migrations.RunSQL(
-            "DROP INDEX misago_thread_is_local",
-            """
-                CREATE INDEX misago_thread_is_local
-                ON misago_threads_thread(weight)
-                WHERE weight < 2
-            """,
-        ),
-        migrations.RunSQL(
-            "DROP INDEX misago_thread_has_reported_posts_partial",
-            """
-                CREATE INDEX misago_thread_has_reported_posts_partial
-                ON misago_threads_thread(has_reported_posts)
-                WHERE has_reported_posts = TRUE
-            """,
-        ),
-        migrations.RunSQL(
-            "DROP INDEX misago_thread_has_unapproved_posts_partial",
-            """
-                CREATE INDEX misago_thread_has_unapproved_posts_partial
-                ON misago_threads_thread(has_unapproved_posts)
-                WHERE has_unapproved_posts = TRUE
-            """,
-        ),
-        migrations.RunSQL(
-            "DROP INDEX misago_thread_is_hidden_partial",
-            """
-                CREATE INDEX misago_thread_is_hidden_partial
-                ON misago_threads_thread(is_hidden)
-                WHERE is_hidden = FALSE
-            """,
-        ),
-        migrations.RunSQL(
-            "DROP INDEX misago_thread_is_pinned_globally_partial",
-            """
-                CREATE INDEX misago_thread_is_pinned_globally_partial
-                ON misago_threads_thread(weight)
-                WHERE weight = 2
-            """,
-        ),
-        migrations.RunSQL(
-            "DROP INDEX misago_thread_is_pinned_locally_partial",
-            """
-                CREATE INDEX misago_thread_is_pinned_locally_partial
-                ON misago_threads_thread(weight)
-                WHERE weight = 1
-            """,
-        ),
-        migrations.RunSQL(
-            "DROP INDEX misago_thread_is_unpinned_partial",
-            """
-                CREATE INDEX misago_thread_is_unpinned_partial
-                ON misago_threads_thread(weight)
-                WHERE weight = 0
-            """,
-        ),
-
         migrations.AddIndex(
             model_name='post',
             index=misago.core.pgutils.PgPartialIndex(fields=['has_open_reports'], name='misago_thre_has_ope_479906_part', where={'has_open_reports': True}),

+ 0 - 11
misago/users/migrations/0001_initial.py

@@ -8,7 +8,6 @@ from django.contrib.postgres.fields import JSONField
 from django.db import migrations, models
 
 import misago.users.avatars.store
-from misago.core.pgutils import CreatePartialIndex
 
 
 class Migration(migrations.Migration):
@@ -139,16 +138,6 @@ class Migration(migrations.Migration):
             },
             bases=(models.Model, ),
         ),
-        CreatePartialIndex(
-            field='User.is_staff',
-            index_name='misago_users_user_is_staff_partial',
-            condition='is_staff = TRUE',
-        ),
-        CreatePartialIndex(
-            field='User.requires_activation',
-            index_name='misago_users_user_requires_activation_partial',
-            condition='requires_activation > 0',
-        ),
         migrations.CreateModel(
             name='Online',
             fields=[

+ 0 - 17
misago/users/migrations/0009_redo_partial_indexes.py

@@ -13,23 +13,6 @@ class Migration(migrations.Migration):
     ]
 
     operations = [
-        migrations.RunSQL(
-            "DROP INDEX misago_users_user_is_staff_partial",
-            """
-                CREATE INDEX misago_users_user_is_staff_partial
-                ON misago_users_user(is_staff)
-                WHERE is_staff = TRUE
-            """,
-        ),
-        migrations.RunSQL(
-            "DROP INDEX misago_users_user_requires_activation_partial",
-            """
-                CREATE INDEX misago_users_user_requires_activation_partial
-                ON misago_users_user(requires_activation)
-                WHERE requires_activation > 0
-            """,
-        ),
-
         migrations.AddIndex(
             model_name='user',
             index=misago.core.pgutils.PgPartialIndex(fields=['is_staff'], name='misago_user_is_staf_bf68aa_part', where={'is_staff': True}),

+ 2 - 0
upload

@@ -0,0 +1,2 @@
+#!/bin/sh
+python setup.py sdist upload