Просмотр исходного кода

Moved fixtures to django migrations

Rafał Pitoń 11 лет назад
Родитель
Сommit
1a59224f08
32 измененных файлов с 882 добавлено и 1597 удалено
  1. 25 50
      misago/acl/migrations/0001_initial.py
  2. 21 0
      misago/acl/migrations/0002_acl_version_tracker.py
  3. 0 39
      misago/acl/migrations/0002_register_cachebuster.py
  4. 0 34
      misago/acl/migrations/0003_auto__del_forumrole.py
  5. 105 0
      misago/acl/migrations/0003_default_roles.py
  6. 0 32
      misago/acl/migrations/0004_auto__add_field_role_special_role.py
  7. 0 34
      misago/acl/migrations/0005_default_roles.py
  8. 50 72
      misago/conf/migrations/0001_initial.py
  9. 21 31
      misago/conf/migrationutils.py
  10. 18 28
      misago/core/migrations/0001_initial.py
  11. 71 0
      misago/core/migrations/0002_basic_settings.py
  12. 0 77
      misago/core/migrations/0002_db_settings.py
  13. 11 31
      misago/core/migrationutils.py
  14. 12 6
      misago/core/utils.py
  15. 67 68
      misago/forums/migrations/0001_initial.py
  16. 0 59
      misago/forums/migrations/0002_auto__del_field_forum_description_preparsed__add_field_forum_descripti.py
  17. 79 0
      misago/forums/migrations/0002_default_forums.py
  18. 118 0
      misago/forums/migrations/0003_forums_roles.py
  19. 0 66
      misago/forums/migrations/0003_set_root_nodes.py
  20. 0 85
      misago/forums/migrations/0004_auto__add_forumrole__add_roleforumacl.py
  21. 0 72
      misago/forums/migrations/0005_auto__add_field_forumrole_special_role.py
  22. 61 121
      misago/users/migrations/0001_initial.py
  23. 0 213
      misago/users/migrations/0002_db_settings.py
  24. 158 0
      misago/users/migrations/0002_users_settings.py
  25. 29 87
      misago/users/migrations/0003_default_ranks.py
  26. 0 85
      misago/users/migrations/0004_auto.py
  27. 0 89
      misago/users/migrations/0005_auto__del_field_rank_style__add_field_rank_css_class.py
  28. 0 105
      misago/users/migrations/0006_auto__add_field_user_title__add_field_user_acl_key.py
  29. 0 87
      misago/users/migrations/0007_auto__chg_field_user_rank.py
  30. 1 1
      misago/users/models/rankmodel.py
  31. 33 23
      misago/users/models/usermodel.py
  32. 2 2
      misago/users/permissions/account.py

+ 25 - 50
misago/acl/migrations/0001_initial.py

@@ -1,51 +1,26 @@
 # -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-        # Adding model 'Role'
-        db.create_table(u'acl_role', (
-            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
-            ('pickled_permissions', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-        ))
-        db.send_create_signal(u'acl', ['Role'])
-
-        # Adding model 'ForumRole'
-        db.create_table(u'acl_forumrole', (
-            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
-            ('pickled_permissions', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-        ))
-        db.send_create_signal(u'acl', ['ForumRole'])
-
-
-    def backwards(self, orm):
-        # Deleting model 'Role'
-        db.delete_table(u'acl_role')
-
-        # Deleting model 'ForumRole'
-        db.delete_table(u'acl_forumrole')
-
-
-    models = {
-        u'acl.forumrole': {
-            'Meta': {'object_name': 'ForumRole'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
-        },
-        u'acl.role': {
-            'Meta': {'object_name': 'Role'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
-        }
-    }
-
-    complete_apps = ['acl']
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Role',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('name', models.CharField(max_length=255)),
+                ('special_role', models.CharField(max_length=255, null=True, blank=True)),
+                ('pickled_permissions', models.TextField(null=True, blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+    ]

+ 21 - 0
misago/acl/migrations/0002_acl_version_tracker.py

@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+from misago.core.migrationutils import cachebuster_register_cache
+
+
+def register_acl_version_tracker(apps, schema_editor):
+    cachebuster_register_cache(apps, 'misago_acl')
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('misago_acl', '0001_initial'),
+        ('misago_core', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.RunPython(register_acl_version_tracker),
+    ]

+ 0 - 39
misago/acl/migrations/0002_register_cachebuster.py

@@ -1,39 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import DataMigration
-from django.db import models
-from misago.core.migrationutils import (with_core_models,
-                                        cachebuster_register_cache)
-
-
-class Migration(DataMigration):
-
-    def forwards(self, orm):
-        cachebuster_register_cache(orm, 'misago_acl')
-
-    def backwards(self, orm):
-        pass
-
-    models = with_core_models('0001_initial', {
-        u'acl.forumrole': {
-            'Meta': {'object_name': 'ForumRole'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
-        },
-        u'acl.role': {
-            'Meta': {'object_name': 'Role'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
-        }
-    })
-
-    complete_apps = ['acl', 'core']
-
-    symmetrical = True
-
-    depends_on = (
-        ("core", "0001_initial"),
-    )

+ 0 - 34
misago/acl/migrations/0003_auto__del_forumrole.py

@@ -1,34 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-        # Deleting model 'ForumRole'
-        db.delete_table(u'acl_forumrole')
-
-
-    def backwards(self, orm):
-        # Adding model 'ForumRole'
-        db.create_table(u'acl_forumrole', (
-            ('pickled_permissions', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
-        ))
-        db.send_create_signal(u'acl', ['ForumRole'])
-
-
-    models = {
-        u'acl.role': {
-            'Meta': {'object_name': 'Role'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
-        }
-    }
-
-    complete_apps = ['acl']

+ 105 - 0
misago/acl/migrations/0003_default_roles.py

@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+from django.utils.translation import ugettext as _
+import base64
+try:
+    import cPickle as pickle
+except ImportError:
+    import pickle
+
+
+def pickle_permissions(role, permissions):
+    role.pickled_permissions = base64.encodestring(
+        pickle.dumps(permissions, pickle.HIGHEST_PROTOCOL))
+
+
+def create_default_roles(apps, schema_editor):
+    Role = apps.get_model('misago_acl', 'Role')
+
+    role = Role(name=_("Member"), special_role='authenticated')
+    pickle_permissions(role,
+        {
+            # account perms
+            'name_changes_allowed': 2,
+            'name_changes_expire': 180,
+            'can_use_signature': False,
+            'allow_signature_links': False,
+            'allow_signature_images': False,
+
+            # profiles perms
+            'can_search_users': True,
+            'can_see_users_emails': False,
+            'can_see_users_ips': False,
+            'can_see_hidden_users': False,
+
+            # destroy users perms
+            'can_destroy_user_newer_than': 0,
+            'can_destroy_users_with_less_posts_than': 0,
+        })
+    role.save()
+
+    role = Role(name=_("Guest"), special_role='anonymous')
+    pickle_permissions(role,
+        {
+            # account perms
+            'name_changes_allowed': 0,
+            'name_changes_expire': 0,
+            'can_use_signature': False,
+            'allow_signature_links': False,
+            'allow_signature_images': False,
+
+            # profiles perms
+            'can_search_users': True,
+            'can_see_users_emails': False,
+            'can_see_users_ips': False,
+            'can_see_hidden_users': False,
+
+            # destroy users perms
+            'can_destroy_user_newer_than': 0,
+            'can_destroy_users_with_less_posts_than': 0,
+        })
+    role.save()
+
+    role = Role(name=_("Moderator"))
+    pickle_permissions(role,
+        {
+            # account perms
+            'name_changes_allowed': 5,
+            'name_changes_expire': 14,
+            'can_use_signature': True,
+            'allow_signature_links': True,
+            'allow_signature_images': False,
+
+            # profiles perms
+            'can_search_users': True,
+            'can_see_users_emails': True,
+            'can_see_users_ips': True,
+            'can_see_hidden_users': True,
+
+            # destroy users perms
+            'can_destroy_user_newer_than': 0,
+            'can_destroy_users_with_less_posts_than': 0,
+        })
+    role.save()
+
+    role = Role(name=_("Spam destroyer"))
+    pickle_permissions(role,
+        {
+            # destroy users perms
+            'can_destroy_user_newer_than': 2,
+            'can_destroy_users_with_less_posts_than': 20,
+        })
+    role.save()
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('misago_acl', '0002_acl_version_tracker'),
+    ]
+
+    operations = [
+        migrations.RunPython(create_default_roles),
+    ]

+ 0 - 32
misago/acl/migrations/0004_auto__add_field_role_special_role.py

@@ -1,32 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-        # Adding field 'Role.special_role'
-        db.add_column(u'acl_role', 'special_role',
-                      self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True),
-                      keep_default=False)
-
-
-    def backwards(self, orm):
-        # Deleting field 'Role.special_role'
-        db.delete_column(u'acl_role', 'special_role')
-
-
-    models = {
-        u'acl.role': {
-            'Meta': {'object_name': 'Role'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'special_role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        }
-    }
-
-    complete_apps = ['acl']

+ 0 - 34
misago/acl/migrations/0005_default_roles.py

@@ -1,34 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import DataMigration
-from django.db import models
-from misago.core.migrationutils import ugettext_lazy as _
-
-
-class Migration(DataMigration):
-
-    def forwards(self, orm):
-        "Write your forwards methods here."
-        orm.Role.objects.create(name=_('Guest').message,
-                                special_role='anonymous')
-
-        orm.Role.objects.create(name=_('Member').message,
-                                special_role='member')
-
-        # Note: Don't use "from appname.models import ModelName".
-        # Use orm.ModelName to refer to models in this application,
-        # and orm['appname.ModelName'] for models in other applications.
-
-    models = {
-        u'acl.role': {
-            'Meta': {'object_name': 'Role'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'special_role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        }
-    }
-
-    complete_apps = ['acl']
-    symmetrical = True

+ 50 - 72
misago/conf/migrations/0001_initial.py

@@ -1,73 +1,51 @@
 # -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-        # Adding model 'SettingsGroup'
-        db.create_table(u'conf_settingsgroup', (
-            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('key', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
-            ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
-            ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-        ))
-        db.send_create_signal(u'conf', ['SettingsGroup'])
-
-        # Adding model 'Setting'
-        db.create_table(u'conf_setting', (
-            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['conf.SettingsGroup'])),
-            ('setting', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
-            ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
-            ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-            ('legend', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
-            ('order', self.gf('django.db.models.fields.IntegerField')(default=0, db_index=True)),
-            ('dry_value', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-            ('default_value', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-            ('python_type', self.gf('django.db.models.fields.CharField')(default='string', max_length=255)),
-            ('is_lazy', self.gf('django.db.models.fields.BooleanField')(default=False)),
-            ('form_field', self.gf('django.db.models.fields.CharField')(default='text', max_length=255)),
-            ('pickled_field_extra', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-        ))
-        db.send_create_signal(u'conf', ['Setting'])
-
-
-    def backwards(self, orm):
-        # Deleting model 'SettingsGroup'
-        db.delete_table(u'conf_settingsgroup')
-
-        # Deleting model 'Setting'
-        db.delete_table(u'conf_setting')
-
-
-    models = {
-        u'conf.setting': {
-            'Meta': {'object_name': 'Setting'},
-            'default_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'dry_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'form_field': ('django.db.models.fields.CharField', [], {'default': "'text'", 'max_length': '255'}),
-            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['conf.SettingsGroup']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_lazy': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'legend': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'order': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'}),
-            'pickled_field_extra': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'python_type': ('django.db.models.fields.CharField', [], {'default': "'string'", 'max_length': '255'}),
-            'setting': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
-        },
-        u'conf.settingsgroup': {
-            'Meta': {'object_name': 'SettingsGroup'},
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
-        }
-    }
-
-    complete_apps = ['conf']
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Setting',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('setting', models.CharField(unique=True, max_length=255)),
+                ('name', models.CharField(max_length=255)),
+                ('description', models.TextField(null=True, blank=True)),
+                ('legend', models.CharField(max_length=255, null=True, blank=True)),
+                ('order', models.IntegerField(default=0, db_index=True)),
+                ('dry_value', models.TextField(null=True, blank=True)),
+                ('default_value', models.TextField(null=True, blank=True)),
+                ('python_type', models.CharField(default=b'string', max_length=255)),
+                ('is_lazy', models.BooleanField(default=False)),
+                ('form_field', models.CharField(default=b'text', max_length=255)),
+                ('pickled_field_extra', models.TextField(null=True, blank=True)),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SettingsGroup',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('key', models.CharField(unique=True, max_length=255)),
+                ('name', models.CharField(max_length=255)),
+                ('description', models.TextField(null=True, blank=True)),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.AddField(
+            model_name='setting',
+            name='group',
+            field=models.ForeignKey(to='misago_conf.SettingsGroup', to_field='id'),
+            preserve_default=True,
+        ),
+    ]

+ 21 - 31
misago/conf/migrationutils.py

@@ -3,24 +3,20 @@ from importlib import import_module
 from misago.conf.dbsettings import CACHE_KEY
 from misago.conf.hydrators import dehydrate_value
 from misago.core.cache import cache as default_cache
-from misago.core.migrationutils import original_message
 try:
     import cPickle as pickle
 except ImportError:
     import pickle
 
 
-def with_conf_models(migration, this_migration=None):
-    module_name = 'misago.conf.migrations.%s' % migration
-    migration_module = import_module(module_name)
-    conf_models = migration_module.Migration.models
-
-    if this_migration:
-        conf_models.update(this_migration)
-    return conf_models
+def get_group(SettingsGroup, group_key):
+    try:
+        return SettingsGroup.objects.get(key=group_key)
+    except SettingsGroup.DoesNotExist:
+        return SettingsGroup()
 
 
-def get_custom_settings_values(orm, group):
+def get_custom_settings_values(group):
     custom_settings_values = {}
 
     for setting in group.setting_set.iterator():
@@ -30,21 +26,13 @@ def get_custom_settings_values(orm, group):
     return custom_settings_values
 
 
-def get_group(orm, group_key):
-    try:
-        return orm['conf.SettingsGroup'].objects.get(key=group_key)
-    except orm['conf.SettingsGroup'].DoesNotExist:
-        return orm['conf.SettingsGroup']()
-
-
-def migrate_setting(orm, group, setting_fixture, order, old_value):
+def migrate_setting(Setting, group, setting_fixture, order, old_value):
     setting_fixture['group'] = group
     setting_fixture['order'] = order
 
-    setting_fixture['name'] = original_message(setting_fixture['name'])
+    setting_fixture['name'] = setting_fixture['name']
     if setting_fixture.get('description'):
-        setting_fixture['description'] = original_message(
-            setting_fixture.get('description'))
+        setting_fixture['description'] = setting_fixture.get('description')
 
     if (setting_fixture.get('field_extra') and
             setting_fixture.get('field_extra').get('choices')):
@@ -54,7 +42,7 @@ def migrate_setting(orm, group, setting_fixture, order, old_value):
         else:
             translated_choices = []
             for val, name in untranslated_choices:
-                translated_choices.append((val, original_message(name)))
+                translated_choices.append((val, name))
             setting_fixture['field_extra']['choices'] = tuple(
                 translated_choices)
 
@@ -66,7 +54,7 @@ def migrate_setting(orm, group, setting_fixture, order, old_value):
 
     field_extra = setting_fixture.pop('field_extra', None)
 
-    setting = orm['conf.Setting'](**setting_fixture)
+    setting = Setting(**setting_fixture)
     setting.dry_value = dehydrate_value(setting.python_type, value)
 
     if setting_fixture.get("default_value"):
@@ -80,27 +68,29 @@ def migrate_setting(orm, group, setting_fixture, order, old_value):
     setting.save()
 
 
-def migrate_settings_group(orm, group_fixture, old_group_key=None):
+def migrate_settings_group(apps, group_fixture, old_group_key=None):
+    SettingsGroup = apps.get_model('misago_conf', 'SettingsGroup')
+    Setting = apps.get_model('misago_conf', 'Setting')
     group_key = group_fixture['key']
 
     # Fetch settings group
 
     if old_group_key:
-        group = get_group(orm, old_group_key)
-        custom_settings_values = get_custom_settings_values(orm, group)
+        group = get_group(SettingsGroup, old_group_key)
+        custom_settings_values = get_custom_settings_values(group)
     else:
-        group = get_group(orm, group_key)
+        group = get_group(SettingsGroup, group_key)
         if group.pk:
-            custom_settings_values = get_custom_settings_values(orm, group)
+            custom_settings_values = get_custom_settings_values(group)
         else:
             custom_settings_values = {}
 
     # Update group's attributes
 
     group.key = group_fixture['key']
-    group.name = original_message(group_fixture['name'])
+    group.name = group_fixture['name']
     if group_fixture.get('description'):
-        group.description = original_message(group_fixture.get('description'))
+        group.description = group_fixture.get('description')
     group.save()
 
     # Delete groups settings and make new ones
@@ -110,7 +100,7 @@ def migrate_settings_group(orm, group_fixture, old_group_key=None):
 
     for order, setting_fixture in enumerate(group_fixture['settings']):
         old_value = custom_settings_values.pop(setting_fixture['name'], None)
-        migrate_setting(orm, group, setting_fixture, order, old_value)
+        migrate_setting(Setting, group, setting_fixture, order, old_value)
 
 
 def delete_settings_cache():

+ 18 - 28
misago/core/migrations/0001_initial.py

@@ -1,34 +1,24 @@
 # -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
+from __future__ import unicode_literals
 
+from django.db import models, migrations
 
-class Migration(SchemaMigration):
 
-    def forwards(self, orm):
-        # Adding model 'CacheVersion'
-        db.create_table(u'core_cacheversion', (
-            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('cache', self.gf('django.db.models.fields.CharField')(max_length=128)),
-            ('version', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
-        ))
-        db.send_create_signal(u'core', ['CacheVersion'])
+class Migration(migrations.Migration):
 
+    dependencies = [
+    ]
 
-    def backwards(self, orm):
-        # Deleting model 'CacheVersion'
-        db.delete_table(u'core_cacheversion')
-
-
-    models = {
-        u'core.cacheversion': {
-            'Meta': {'object_name': 'CacheVersion'},
-            'cache': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'version': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
-        }
-    }
-
-    complete_apps = ['core']
+    operations = [
+        migrations.CreateModel(
+            name='CacheVersion',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('cache', models.CharField(max_length=128)),
+                ('version', models.PositiveIntegerField(default=0)),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+    ]

+ 71 - 0
misago/core/migrations/0002_basic_settings.py

@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+from django.utils.translation import ugettext as _
+from misago.conf.migrationutils import migrate_settings_group
+
+
+def create_basic_settings_group(apps, schema_editor):
+    migrate_settings_group(
+        apps,
+        {
+            'key': 'basic',
+            'name': _("Basic forum settings"),
+            'description': _("Those settings control most basic properties "
+                             "of your forum like its name or description."),
+            'settings': (
+                {
+                    'setting': 'forum_name',
+                    'name': _("Forum name"),
+                    'legend': _("General"),
+                    'value': "Misago",
+                    'field_extra': {
+                        'min_length': 2,
+                        'max_length': 255
+                    },
+                },
+                {
+                    'setting': 'forum_index_title',
+                    'name': _("Forum index title"),
+                    'description': _("You may set custon title on "
+                                     "forum index by typing it here."),
+                    'legend': _("Forum index"),
+                    'field_extra': {
+                        'max_length': 255
+                    },
+                },
+                {
+                    'setting': 'forum_index_meta_description',
+                    'name': _("Forum index Meta Description"),
+                    'description': _("Short description of your forum "
+                                     "for internet crawlers."),
+                    'field_extra': {
+                        'max_length': 255
+                    },
+                },
+                {
+                    'setting': 'email_footer',
+                    'name': _("E-mails footer"),
+                    'description': _("Optional short message included "
+                                     "at the end of e-mails sent by "
+                                     "forum"),
+                    'legend': _("Forum e-mails"),
+                    'field_extra': {
+                        'max_length': 255
+                    },
+                },
+            )
+        })
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('misago_core', '0001_initial'),
+        ('misago_conf', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.RunPython(create_basic_settings_group),
+    ]

+ 0 - 77
misago/core/migrations/0002_db_settings.py

@@ -1,77 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import DataMigration
-from django.db import models
-from misago.conf.migrationutils import migrate_settings_group, with_conf_models
-from misago.core.migrationutils import ugettext_lazy as _
-
-
-class Migration(DataMigration):
-
-    def forwards(self, orm):
-        "Write your forwards methods here."
-        migrate_settings_group(
-            orm,
-            {
-                'key': 'basic',
-                'name': _("Basic forum settings"),
-                'description': _("Those settings control most basic properties "
-                                 "of your forum like its name or description."),
-                'settings': (
-                    {
-                        'setting': 'forum_name',
-                        'name': _("Forum name"),
-                        'legend': _("General"),
-                        'value': "Misago",
-                        'field_extra': {
-                            'min_length': 2,
-                            'max_length': 255
-                        },
-                    },
-                    {
-                        'setting': 'forum_index_title',
-                        'name': _("Forum index title"),
-                        'description': _("You may set custon title on "
-                                         "forum index by typing it here."),
-                        'legend': _("Forum index"),
-                        'field_extra': {
-                            'max_length': 255
-                        },
-                    },
-                    {
-                        'setting': 'forum_index_meta_description',
-                        'name': _("Forum index Meta Description"),
-                        'description': _("Short description of your forum "
-                                         "for internet crawlers."),
-                        'field_extra': {
-                            'max_length': 255
-                        },
-                    },
-                    {
-                        'setting': 'email_footer',
-                        'name': _("E-mails footer"),
-                        'description': _("Optional short message included "
-                                         "at the end of e-mails sent by "
-                                         "forum"),
-                        'legend': _("Forum e-mails"),
-                        'field_extra': {
-                            'max_length': 255
-                        },
-                    },
-                )
-            },
-        )
-
-
-    def backwards(self, orm):
-        "Write your backwards methods here."
-
-    models = with_conf_models('0001_initial')
-
-    complete_apps = ['core']
-    symmetrical = True
-
-    depends_on = (
-        ("conf", "0001_initial"),
-    )

+ 11 - 31
misago/core/migrationutils.py

@@ -1,46 +1,26 @@
 from importlib import import_module
-from django.utils import translation
 from misago.core.cache import cache as default_cache
 from misago.core.cachebuster import CACHE_KEY
 
 
-def ugettext_lazy(string):
-    """
-    Custom wrapper that preserves untranslated message on lazy translation
-    string object, useful for db entries that should be found by makemessages
-    and stored untranslated
-    """
-    t = translation.ugettext_lazy(string)
-    t.message = string
-    return t
+"""
+cache versioning utils
+"""
+def _CacheVersion(apps):
+    return apps.get_model('misago_core', 'CacheVersion')
 
 
-def original_message(string):
-    try:
-        return unicode(string.message)
-    except AttributeError:
-        return unicode(string)
-
-
-def with_core_models(migration, this_migration=None):
-    module_name = 'misago.core.migrations.%s' % migration
-    migration_module = import_module(module_name)
-    core_models = migration_module.Migration.models
-
-    if this_migration:
-        core_models.update(this_migration)
-    return core_models
-
+def cachebuster_register_cache(apps, cache):
+    _CacheVersion(apps).objects.create(cache=cache)
 
-def cachebuster_register_cache(orm, cache):
-    orm['core.CacheVersion'].objects.create(cache=cache)
 
+def cachebuster_unregister_cache(apps, cache):
+    CacheVersion = _CacheVersion(apps)
 
-def cachebuster_unregister_cache(orm, cache):
     try:
-        cache = orm['core.CacheVersion'].objects.get(cache=cache)
+        cache = CacheVersion.objects.get(cache=cache)
         cache.delete()
-    except orm['core.CacheVersion'].DoesNotExist:
+    except CacheVersion.DoesNotExist:
         raise ValueError('Cache "%s" is not registered' % cache)
 
 

+ 12 - 6
misago/core/utils.py

@@ -5,6 +5,15 @@ from django.core.urlresolvers import reverse
 from django.template.defaultfilters import slugify as django_slugify
 
 
+def slugify(string):
+    string = unicode(string)
+    string = unidecode(string)
+    return django_slugify(string.replace('_', ' '))
+
+
+"""
+Utils for resolving requests destination
+"""
 def _is_request_path_under_misago(request):
     # We are assuming that forum_index link is root of all Misago links
     forum_index = reverse('misago:index')
@@ -23,12 +32,9 @@ def is_request_to_misago(request):
         return request._request_to_misago
 
 
-def slugify(string):
-    string = unicode(string)
-    string = unidecode(string)
-    return django_slugify(string.replace('_', ' '))
-
-
+"""
+MD subset for use for enchancing items descriptions
+"""
 MD_SUBSET_FORBID_SYNTAX = (
     # References are evil
     'reference', 'reference', 'image_reference', 'short_reference',

+ 67 - 68
misago/forums/migrations/0001_initial.py

@@ -1,74 +1,73 @@
 # -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
+from __future__ import unicode_literals
 
+from django.db import models, migrations
+import django.db.models.deletion
+import mptt.fields
 
-class Migration(SchemaMigration):
 
-    def forwards(self, orm):
-        # Adding model 'Forum'
-        db.create_table(u'forums_forum', (
-            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('parent', self.gf('mptt.fields.TreeForeignKey')(blank=True, related_name='children', null=True, to=orm['forums.Forum'])),
-            ('special_role', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
-            ('role', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
-            ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
-            ('slug', self.gf('django.db.models.fields.SlugField')(max_length=255)),
-            ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-            ('description_preparsed', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-            ('is_closed', self.gf('django.db.models.fields.BooleanField')(default=False)),
-            ('redirect_url', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
-            ('redirects_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
-            ('threads', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
-            ('threads_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
-            ('posts', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
-            ('posts_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
-            ('prune_started_after', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
-            ('prune_replied_after', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
-            ('archive_pruned_in', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='pruned_archive', null=True, on_delete=models.SET_NULL, to=orm['forums.Forum'])),
-            ('css_class', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
-            (u'lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
-            (u'rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
-            (u'tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
-            (u'level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
-        ))
-        db.send_create_signal(u'forums', ['Forum'])
+class Migration(migrations.Migration):
 
+    dependencies = [
+        ('misago_acl', '0001_initial'),
+    ]
 
-    def backwards(self, orm):
-        # Deleting model 'Forum'
-        db.delete_table(u'forums_forum')
-
-
-    models = {
-        u'forums.forum': {
-            'Meta': {'object_name': 'Forum'},
-            'archive_pruned_in': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pruned_archive'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['forums.Forum']"}),
-            'css_class': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'description_preparsed': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            u'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            u'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['forums.Forum']"}),
-            'posts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'posts_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'prune_replied_after': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'prune_started_after': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'redirect_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'redirects_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            u'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            'role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '255'}),
-            'special_role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'threads': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'threads_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            u'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
-        }
-    }
-
-    complete_apps = ['forums']
+    operations = [
+        migrations.CreateModel(
+            name='Forum',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('special_role', models.CharField(max_length=255, null=True, blank=True)),
+                ('role', models.CharField(max_length=255, null=True, blank=True)),
+                ('name', models.CharField(max_length=255)),
+                ('slug', models.SlugField(max_length=255)),
+                ('description', models.TextField(null=True, blank=True)),
+                ('description_as_html', models.TextField(null=True, blank=True)),
+                ('is_closed', models.BooleanField(default=False)),
+                ('redirect_url', models.CharField(max_length=255, null=True, blank=True)),
+                ('redirects_count', models.PositiveIntegerField(default=0)),
+                ('threads', models.PositiveIntegerField(default=0)),
+                ('threads_count', models.PositiveIntegerField(default=0)),
+                ('posts', models.PositiveIntegerField(default=0)),
+                ('posts_count', models.PositiveIntegerField(default=0)),
+                ('prune_started_after', models.PositiveIntegerField(default=0)),
+                ('prune_replied_after', models.PositiveIntegerField(default=0)),
+                ('css_class', models.CharField(max_length=255, null=True, blank=True)),
+                ('lft', models.PositiveIntegerField(editable=False, db_index=True)),
+                ('rght', models.PositiveIntegerField(editable=False, db_index=True)),
+                ('tree_id', models.PositiveIntegerField(editable=False, db_index=True)),
+                ('level', models.PositiveIntegerField(editable=False, db_index=True)),
+                ('archive_pruned_in', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to_field='id', blank=True, to='misago_forums.Forum', null=True)),
+                ('parent', mptt.fields.TreeForeignKey(to_field='id', blank=True, to='misago_forums.Forum', null=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ForumRole',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('name', models.CharField(max_length=255)),
+                ('special_role', models.CharField(max_length=255, null=True, blank=True)),
+                ('pickled_permissions', models.TextField(null=True, blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='RoleForumACL',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('forum', models.ForeignKey(to='misago_forums.Forum', to_field='id')),
+                ('forum_role', models.ForeignKey(to='misago_forums.ForumRole', to_field='id')),
+                ('role', models.ForeignKey(to='misago_acl.Role', to_field='id')),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+    ]

+ 0 - 59
misago/forums/migrations/0002_auto__del_field_forum_description_preparsed__add_field_forum_descripti.py

@@ -1,59 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-        # Deleting field 'Forum.description_preparsed'
-        db.delete_column(u'forums_forum', 'description_preparsed')
-
-        # Adding field 'Forum.description_as_html'
-        db.add_column(u'forums_forum', 'description_as_html',
-                      self.gf('django.db.models.fields.TextField')(null=True, blank=True),
-                      keep_default=False)
-
-
-    def backwards(self, orm):
-        # Adding field 'Forum.description_preparsed'
-        db.add_column(u'forums_forum', 'description_preparsed',
-                      self.gf('django.db.models.fields.TextField')(null=True, blank=True),
-                      keep_default=False)
-
-        # Deleting field 'Forum.description_as_html'
-        db.delete_column(u'forums_forum', 'description_as_html')
-
-
-    models = {
-        u'forums.forum': {
-            'Meta': {'object_name': 'Forum'},
-            'archive_pruned_in': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pruned_archive'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['forums.Forum']"}),
-            'css_class': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'description_as_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            u'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            u'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['forums.Forum']"}),
-            'posts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'posts_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'prune_replied_after': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'prune_started_after': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'redirect_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'redirects_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            u'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            'role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '255'}),
-            'special_role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'threads': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'threads_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            u'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
-        }
-    }
-
-    complete_apps = ['forums']

+ 79 - 0
misago/forums/migrations/0002_default_forums.py

@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+from django.utils.translation import ugettext as _
+from misago.core.utils import slugify
+
+
+def create_default_forums_tree(apps, schema_editor):
+    Forum = apps.get_model('misago_forums', 'Forum')
+
+    Forum.objects.create(
+        special_role='private_threads',
+        role='forum',
+        name='Private',
+        slug='private',
+        lft=1,
+        rght=2,
+        tree_id=0,
+        level=0,
+    )
+
+    root = Forum.objects.create(
+        special_role='root_category',
+        role='category',
+        name='Root',
+        slug='root',
+        lft=3,
+        rght=10,
+        tree_id=1,
+        level=0,
+    )
+
+    category_name = _("First category")
+    forum_name = _("First forum")
+    redirect_name = _("Project forums")
+    redirect_link = _("http://misago-project.org")
+
+    category = Forum.objects.create(
+        parent=root,
+        lft=4,
+        rght=9,
+        tree_id=1,
+        level=1,
+        role='category',
+        name=category_name,
+        slug=slugify(category_name))
+
+    Forum.objects.create(
+        parent=category,
+        lft=5,
+        rght=6,
+        tree_id=1,
+        level=2,
+        role='forum',
+        name=forum_name,
+        slug=slugify(forum_name))
+
+    Forum.objects.create(
+        parent=category,
+        lft=7,
+        rght=8,
+        tree_id=1,
+        level=2,
+        role='redirect',
+        name=redirect_name,
+        slug=slugify(redirect_name),
+        redirect_url=redirect_link)
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('misago_forums', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.RunPython(create_default_forums_tree),
+    ]

+ 118 - 0
misago/forums/migrations/0003_forums_roles.py

@@ -0,0 +1,118 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+from django.utils.translation import ugettext as _
+import base64
+try:
+    import cPickle as pickle
+except ImportError:
+    import pickle
+
+
+def pickle_permissions(role, permissions):
+    role.pickled_permissions = base64.encodestring(
+        pickle.dumps(permissions, pickle.HIGHEST_PROTOCOL))
+
+
+def create_default_forums_roles(apps, schema_editor):
+    """
+    Crete roles
+    """
+    ForumRole = apps.get_model('misago_forums', 'ForumRole')
+
+    see_only = ForumRole(name=_('See only'))
+    pickle_permissions(see_only,
+        {
+            # forums perms
+            'can_see': True,
+            'can_browse': False,
+        })
+    see_only.save()
+
+    read_only = ForumRole(name=_('Read only'))
+    pickle_permissions(read_only,
+        {
+            # forums perms
+            'can_see': True,
+            'can_browse': True,
+        })
+    read_only.save()
+
+    reply_only = ForumRole(name=_('Reply to threads'))
+    pickle_permissions(reply_only,
+        {
+            # forums perms
+            'can_see': True,
+            'can_browse': True,
+        })
+    reply_only.save()
+
+    standard = ForumRole(name=_('Start and reply threads'))
+    pickle_permissions(standard,
+        {
+            # forums perms
+            'can_see': True,
+            'can_browse': True,
+        })
+    standard.save()
+
+    standard_with_polls = ForumRole(
+        name=_('Start and reply threads, make pols'))
+    pickle_permissions(standard_with_polls,
+        {
+            # forums perms
+            'can_see': True,
+            'can_browse': True,
+        })
+    standard_with_polls.save()
+
+    moderator = ForumRole(name=_('Moderator'))
+    pickle_permissions(moderator,
+        {
+            # forums perms
+            'can_see': True,
+            'can_browse': True,
+        })
+    moderator.save()
+
+    """
+    Assign forum roles to roles
+    """
+    Forum = apps.get_model('misago_forums', 'Forum')
+    Role = apps.get_model('misago_acl', 'Role')
+    RoleForumACL = apps.get_model('misago_forums', 'RoleForumACL')
+
+    moderators = Role.objects.get(name=_('Moderator'))
+    members = Role.objects.get(special_role='authenticated')
+    guests = Role.objects.get(special_role='anonymous')
+
+    category = Forum.objects.filter(level__gt=0).get(role='category')
+    forum = Forum.objects.filter(level__gt=0).get(role='forum')
+    redirect = Forum.objects.filter(level__gt=0).get(role='redirect')
+
+    RoleForumACL.objects.bulk_create([
+        RoleForumACL(role=moderators, forum=category, forum_role=moderator),
+        RoleForumACL(role=moderators, forum=forum, forum_role=moderator),
+        RoleForumACL(role=moderators, forum=redirect, forum_role=moderator),
+
+        RoleForumACL(role=members, forum=category, forum_role=standard),
+        RoleForumACL(role=members, forum=forum, forum_role=standard),
+        RoleForumACL(role=members, forum=redirect, forum_role=standard),
+
+        RoleForumACL(role=guests, forum=category, forum_role=read_only),
+        RoleForumACL(role=guests, forum=forum, forum_role=read_only),
+        RoleForumACL(role=guests, forum=redirect, forum_role=read_only),
+    ])
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('misago_forums', '0002_default_forums'),
+        ('misago_acl', '0003_default_roles'),
+    ]
+
+    operations = [
+        migrations.RunPython(create_default_forums_roles),
+    ]

+ 0 - 66
misago/forums/migrations/0003_set_root_nodes.py

@@ -1,66 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import DataMigration
-from django.db import models
-
-class Migration(DataMigration):
-
-    def forwards(self, orm):
-        orm.Forum(
-            special_role='private_threads',
-            role='forum',
-            name='Private',
-            slug='private',
-            lft=1,
-            rght=2,
-            tree_id=0,
-            level=0,
-        ).save()
-
-        orm.Forum(
-            special_role='root_category',
-            role='category',
-            name='Root',
-            slug='root',
-            lft=3,
-            rght=4,
-            tree_id=1,
-            level=0,
-        ).save()
-
-
-    def backwards(self, orm):
-        "Write your backwards methods here."
-
-    models = {
-        u'forums.forum': {
-            'Meta': {'object_name': 'Forum'},
-            'archive_pruned_in': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pruned_archive'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['forums.Forum']"}),
-            'css_class': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'description_as_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            u'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            u'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['forums.Forum']"}),
-            'posts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'posts_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'prune_replied_after': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'prune_started_after': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'redirect_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'redirects_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            u'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            'role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '255'}),
-            'special_role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'threads': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'threads_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            u'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
-        }
-    }
-
-    complete_apps = ['forums']
-    symmetrical = True

+ 0 - 85
misago/forums/migrations/0004_auto__add_forumrole__add_roleforumacl.py

@@ -1,85 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-        # Adding model 'ForumRole'
-        db.create_table(u'forums_forumrole', (
-            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
-            ('pickled_permissions', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-        ))
-        db.send_create_signal(u'forums', ['ForumRole'])
-
-        # Adding model 'RoleForumACL'
-        db.create_table(u'forums_roleforumacl', (
-            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('role', self.gf('mptt.fields.TreeForeignKey')(to=orm['acl.Role'])),
-            ('forum', self.gf('mptt.fields.TreeForeignKey')(to=orm['forums.Forum'])),
-            ('forum_role', self.gf('mptt.fields.TreeForeignKey')(to=orm['forums.ForumRole'])),
-        ))
-        db.send_create_signal(u'forums', ['RoleForumACL'])
-
-
-    def backwards(self, orm):
-        # Deleting model 'ForumRole'
-        db.delete_table(u'forums_forumrole')
-
-        # Deleting model 'RoleForumACL'
-        db.delete_table(u'forums_roleforumacl')
-
-
-    models = {
-        u'acl.role': {
-            'Meta': {'object_name': 'Role'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
-        },
-        u'forums.forum': {
-            'Meta': {'object_name': 'Forum'},
-            'archive_pruned_in': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pruned_archive'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['forums.Forum']"}),
-            'css_class': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'description_as_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            u'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            u'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['forums.Forum']"}),
-            'posts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'posts_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'prune_replied_after': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'prune_started_after': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'redirect_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'redirects_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            u'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            'role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '255'}),
-            'special_role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'threads': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'threads_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            u'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
-        },
-        u'forums.forumrole': {
-            'Meta': {'object_name': 'ForumRole'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
-        },
-        u'forums.roleforumacl': {
-            'Meta': {'object_name': 'RoleForumACL'},
-            'forum': ('mptt.fields.TreeForeignKey', [], {'to': u"orm['forums.Forum']"}),
-            'forum_role': ('mptt.fields.TreeForeignKey', [], {'to': u"orm['forums.ForumRole']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'role': ('mptt.fields.TreeForeignKey', [], {'to': u"orm['acl.Role']"})
-        }
-    }
-
-    complete_apps = ['forums']

+ 0 - 72
misago/forums/migrations/0005_auto__add_field_forumrole_special_role.py

@@ -1,72 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-        # Adding field 'ForumRole.special_role'
-        db.add_column(u'forums_forumrole', 'special_role',
-                      self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True),
-                      keep_default=False)
-
-
-    def backwards(self, orm):
-        # Deleting field 'ForumRole.special_role'
-        db.delete_column(u'forums_forumrole', 'special_role')
-
-
-    models = {
-        u'acl.role': {
-            'Meta': {'object_name': 'Role'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'special_role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        },
-        u'forums.forum': {
-            'Meta': {'object_name': 'Forum'},
-            'archive_pruned_in': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pruned_archive'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['forums.Forum']"}),
-            'css_class': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'description_as_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            u'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            u'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['forums.Forum']"}),
-            'posts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'posts_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'prune_replied_after': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'prune_started_after': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'redirect_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'redirects_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            u'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
-            'role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '255'}),
-            'special_role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'threads': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            'threads_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
-            u'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
-        },
-        u'forums.forumrole': {
-            'Meta': {'object_name': 'ForumRole'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'special_role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        },
-        u'forums.roleforumacl': {
-            'Meta': {'object_name': 'RoleForumACL'},
-            'forum': ('mptt.fields.TreeForeignKey', [], {'to': u"orm['forums.Forum']"}),
-            'forum_role': ('mptt.fields.TreeForeignKey', [], {'to': u"orm['forums.ForumRole']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'role': ('mptt.fields.TreeForeignKey', [], {'related_name': "'forums_acls'", 'to': u"orm['acl.Role']"})
-        }
-    }
-
-    complete_apps = ['forums']

+ 61 - 121
misago/users/migrations/0001_initial.py

@@ -1,127 +1,67 @@
 # -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
+from __future__ import unicode_literals
 
+from django.db import models, migrations
+import django.utils.timezone
+import django.db.models.deletion
 
-class Migration(SchemaMigration):
 
-    def forwards(self, orm):
-        # Adding model 'User'
-        db.create_table(u'users_user', (
-            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('password', self.gf('django.db.models.fields.CharField')(max_length=128)),
-            ('last_login', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
-            ('is_superuser', self.gf('django.db.models.fields.BooleanField')(default=False)),
-            ('username', self.gf('django.db.models.fields.CharField')(max_length=30)),
-            ('username_slug', self.gf('django.db.models.fields.CharField')(unique=True, max_length=30)),
-            ('email', self.gf('django.db.models.fields.EmailField')(max_length=255, db_index=True)),
-            ('email_hash', self.gf('django.db.models.fields.CharField')(unique=True, max_length=32)),
-            ('joined_on', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
-            ('rank', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['users.Rank'], on_delete=models.PROTECT)),
-            ('is_staff', self.gf('django.db.models.fields.BooleanField')(default=False, db_index=True)),
-        ))
-        db.send_create_signal('users', ['User'])
+class Migration(migrations.Migration):
 
-        # Adding M2M table for field groups on 'User'
-        m2m_table_name = db.shorten_name(u'users_user_groups')
-        db.create_table(m2m_table_name, (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('user', models.ForeignKey(orm['users.user'], null=False)),
-            ('group', models.ForeignKey(orm[u'auth.group'], null=False))
-        ))
-        db.create_unique(m2m_table_name, ['user_id', 'group_id'])
+    dependencies = [
+        ('auth', '0002_auto_20140620_2207'),
+        ('misago_acl', '0001_initial'),
+    ]
 
-        # Adding M2M table for field user_permissions on 'User'
-        m2m_table_name = db.shorten_name(u'users_user_user_permissions')
-        db.create_table(m2m_table_name, (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('user', models.ForeignKey(orm['users.user'], null=False)),
-            ('permission', models.ForeignKey(orm[u'auth.permission'], null=False))
-        ))
-        db.create_unique(m2m_table_name, ['user_id', 'permission_id'])
-
-        # Adding model 'Rank'
-        db.create_table(u'users_rank', (
-            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
-            ('slug', self.gf('django.db.models.fields.CharField')(max_length=255)),
-            ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
-            ('style', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
-            ('title', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
-            ('is_default', self.gf('django.db.models.fields.BooleanField')(default=False)),
-            ('is_tab', self.gf('django.db.models.fields.BooleanField')(default=False)),
-            ('is_on_index', self.gf('django.db.models.fields.BooleanField')(default=False)),
-            ('order', self.gf('django.db.models.fields.IntegerField')(default=0)),
-        ))
-        db.send_create_signal('users', ['Rank'])
-
-
-    def backwards(self, orm):
-        # Deleting model 'User'
-        db.delete_table(u'users_user')
-
-        # Removing M2M table for field groups on 'User'
-        db.delete_table(db.shorten_name(u'users_user_groups'))
-
-        # Removing M2M table for field user_permissions on 'User'
-        db.delete_table(db.shorten_name(u'users_user_user_permissions'))
-
-        # Deleting model 'Rank'
-        db.delete_table(u'users_rank')
-
-
-    models = {
-        u'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        u'auth.permission': {
-            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        u'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'users.rank': {
-            'Meta': {'object_name': 'Rank'},
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_default': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_on_index': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_tab': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
-            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'style': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        },
-        'users.user': {
-            'Meta': {'object_name': 'User'},
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'db_index': 'True'}),
-            'email_hash': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'joined_on': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'rank': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.Rank']", 'on_delete': 'models.PROTECT'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
-            'username': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
-            'username_slug': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        }
-    }
-
-    complete_apps = ['users']
+    operations = [
+        migrations.CreateModel(
+            name='User',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('password', models.CharField(max_length=128, verbose_name='password')),
+                ('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')),
+                ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
+                ('username', models.CharField(max_length=30)),
+                ('username_slug', models.CharField(unique=True, max_length=30)),
+                ('email', models.EmailField(max_length=255, db_index=True)),
+                ('email_hash', models.CharField(unique=True, max_length=32)),
+                ('joined_on', models.DateTimeField(default=django.utils.timezone.now, verbose_name='joined on')),
+                ('title', models.CharField(max_length=255, null=True, blank=True)),
+                ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into admin sites.', db_index=True, verbose_name='staff status')),
+                ('acl_key', models.CharField(max_length=12, null=True, blank=True)),
+                ('groups', models.ManyToManyField(to='auth.Group', verbose_name='groups', blank=True)),
+                ('roles', models.ManyToManyField(to='misago_acl.Role')),
+                ('user_permissions', models.ManyToManyField(to='auth.Permission', verbose_name='user permissions', blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Rank',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('name', models.CharField(max_length=255)),
+                ('slug', models.CharField(max_length=255)),
+                ('description', models.TextField(null=True, blank=True)),
+                ('title', models.CharField(max_length=255, null=True, blank=True)),
+                ('css_class', models.CharField(max_length=255, null=True, blank=True)),
+                ('is_default', models.BooleanField(default=False)),
+                ('is_tab', models.BooleanField(default=False)),
+                ('is_on_index', models.BooleanField(default=False)),
+                ('order', models.IntegerField(default=0)),
+                ('roles', models.ManyToManyField(to='misago_acl.Role', null=True, blank=True)),
+            ],
+            options={
+                'get_latest_by': b'order',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.AddField(
+            model_name='user',
+            name='rank',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to_field='id', blank=True, to='misago_users.Rank', null=True),
+            preserve_default=True,
+        ),
+    ]

+ 0 - 213
misago/users/migrations/0002_db_settings.py

@@ -1,213 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-from misago.conf.migrationutils import migrate_settings_group, with_conf_models
-from misago.core.migrationutils import ugettext_lazy as _
-
-
-class Migration(SchemaMigration):
-    def forwards(self, orm):
-        migrate_settings_group(
-            orm,
-            {
-                'key': 'users',
-                'name': _("Users"),
-                'settings': (
-                    {
-                        'setting': 'account_activation',
-                        'name': _("New accounts activation"),
-                        'legend': _("New accounts"),
-                        'value': 'none',
-                        'form_field': 'select',
-                        'field_extra': {
-                            'choices': (
-                                ('none', _("No activation required")),
-                                ('user', _("Activation Token sent to User")),
-                                ('admin', _("Activation by Administrator")),
-                                ('block', _("Don't allow new registrations"))
-                            )
-                        },
-                    },
-                    {
-                        'setting': 'default_timezone',
-                        'name': _("Default timezone"),
-                        'description': _("Default timezone for newly "
-                                         "registered accouts as well as "
-                                         "unsigned users."),
-                        'value': 'utc',
-                        'form_field': 'select',
-                        'field_extra': {
-                            'choices': '#TZ#',
-                        },
-                    },
-                    {
-                        'setting': 'username_length_min',
-                        'name': _("Minimal allowed username length"),
-                        'legend': _("User names"),
-                        'python_type': 'int',
-                        'value': 3,
-                        'field_extra': {
-                            'min_value': 2,
-                            'max_value': 255,
-                        },
-                    },
-                    {
-                        'setting': 'username_length_max',
-                        'name': _("Maximal allowed username length"),
-                        'python_type': 'int',
-                        'value': 14,
-                        'field_extra': {
-                            'min_value': 2,
-                            'max_value': 255,
-                        },
-                    },
-                    {
-                        'setting': 'password_length_min',
-                        'name': _("Minimum user password length"),
-                        'legend': _("Passwords"),
-                        'python_type': 'int',
-                        'value': 5,
-                        'field_extra': {
-                            'min_value': 2,
-                            'max_value': 255,
-                        },
-                    },
-                    {
-                        'setting': 'avatars_types',
-                        'name': _("Available avatar types"),
-                        'legend': _("Avatars"),
-                        'python_type': 'list',
-                        'value': ['gravatar', 'upload'],
-                        'form_field': 'checkbox',
-                        'field_extra': {
-                            'choices': (
-                                ('gravatar', _("Gravatar")),
-                                ('upload', _("Uploaded avatar")),
-                                ('gallery', _("Avatars gallery"))
-                            ),
-                            'min': 1,
-                        },
-                    },
-                    {
-                        'setting': 'default_avatar',
-                        'name': _("Default avatar"),
-                        'value': 'gravatar',
-                        'form_field': 'select',
-                        'field_extra': {
-                            'choices': (
-                                ('gravatar', _("Gravatar")),
-                                ('gallery', _("Random avatar from gallery")),
-                            ),
-                        },
-                    },
-                    {
-                        'setting': 'avatar_upload_limit',
-                        'name': _("Maximum size of uploaded avatar"),
-                        'description': _("Enter maximum allowed file size "
-                                         "(in KB) for avatar uploads"),
-                        'python_type': 'int',
-                        'value': 128,
-                        'field_extra': {
-                            'min_value': 0,
-                        },
-                    },
-                    {
-                        'setting': 'subscribe_start',
-                        'name': _("Subscribe to started threads"),
-                        'legend': _("Default subscriptions settings"),
-                        'value': 'watch_email',
-                        'form_field': 'select',
-                        'field_extra': {
-                            'choices': (
-                                ('no', _("Don't watch")),
-                                ('', _("Put on watched threads list")),
-                                ('watch_email', _("Put on watched threads "
-                                                  "list and e-mail user when "
-                                                  "somebody replies")),
-                            ),
-                        },
-                    },
-                    {
-                        'setting': 'subscribe_reply',
-                        'name': _("Subscribe to replied threads"),
-                        'value': 'watch_email',
-                        'form_field': 'select',
-                        'field_extra': {
-                            'choices': (
-                                ('no', _("Don't watch")),
-                                ('', _("Put on watched threads list")),
-                                ('watch_email', _("Put on watched threads "
-                                                  "list and e-mail user when "
-                                                  "somebody replies")),
-                            ),
-                        },
-                    },
-                )
-            },
-        )
-
-    def backwards(self, orm):
-        pass
-
-    models = with_conf_models('0001_initial', {
-        u'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        u'auth.permission': {
-            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        u'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'users.rank': {
-            'Meta': {'object_name': 'Rank'},
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_default': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_on_index': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_tab': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
-            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'style': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        },
-        'users.user': {
-            'Meta': {'object_name': 'User'},
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'db_index': 'True'}),
-            'email_hash': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'joined_on': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'rank': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.Rank']", 'on_delete': 'models.PROTECT'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
-            'username': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
-            'username_slug': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        }
-    })
-
-    no_dry_run = True
-
-    complete_apps = ['users']
-
-    depends_on = (
-        ("conf", "0001_initial"),
-    )
-

+ 158 - 0
misago/users/migrations/0002_users_settings.py

@@ -0,0 +1,158 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+from django.utils.translation import ugettext as _
+from misago.conf.migrationutils import migrate_settings_group
+
+
+def create_users_settings_group(apps, schema_editor):
+    migrate_settings_group(
+        apps,
+        {
+            'key': 'users',
+            'name': _("Users"),
+            'settings': (
+                {
+                    'setting': 'account_activation',
+                    'name': _("New accounts activation"),
+                    'legend': _("New accounts"),
+                    'value': 'none',
+                    'form_field': 'select',
+                    'field_extra': {
+                        'choices': (
+                            ('none', _("No activation required")),
+                            ('user', _("Activation Token sent to User")),
+                            ('admin', _("Activation by Administrator")),
+                            ('block', _("Don't allow new registrations"))
+                        )
+                    },
+                },
+                {
+                    'setting': 'default_timezone',
+                    'name': _("Default timezone"),
+                    'description': _("Default timezone for newly "
+                                     "registered accouts as well as "
+                                     "unsigned users."),
+                    'value': 'utc',
+                    'form_field': 'select',
+                    'field_extra': {
+                        'choices': '#TZ#',
+                    },
+                },
+                {
+                    'setting': 'username_length_min',
+                    'name': _("Minimal allowed username length"),
+                    'legend': _("User names"),
+                    'python_type': 'int',
+                    'value': 3,
+                    'field_extra': {
+                        'min_value': 2,
+                        'max_value': 255,
+                    },
+                },
+                {
+                    'setting': 'username_length_max',
+                    'name': _("Maximal allowed username length"),
+                    'python_type': 'int',
+                    'value': 14,
+                    'field_extra': {
+                        'min_value': 2,
+                        'max_value': 255,
+                    },
+                },
+                {
+                    'setting': 'password_length_min',
+                    'name': _("Minimum user password length"),
+                    'legend': _("Passwords"),
+                    'python_type': 'int',
+                    'value': 5,
+                    'field_extra': {
+                        'min_value': 2,
+                        'max_value': 255,
+                    },
+                },
+                {
+                    'setting': 'avatars_types',
+                    'name': _("Available avatar types"),
+                    'legend': _("Avatars"),
+                    'python_type': 'list',
+                    'value': ['gravatar', 'upload'],
+                    'form_field': 'checkbox',
+                    'field_extra': {
+                        'choices': (
+                            ('gravatar', _("Gravatar")),
+                            ('upload', _("Uploaded avatar")),
+                            ('gallery', _("Avatars gallery"))
+                        ),
+                        'min': 1,
+                    },
+                },
+                {
+                    'setting': 'default_avatar',
+                    'name': _("Default avatar"),
+                    'value': 'gravatar',
+                    'form_field': 'select',
+                    'field_extra': {
+                        'choices': (
+                            ('gravatar', _("Gravatar")),
+                            ('gallery', _("Random avatar from gallery")),
+                        ),
+                    },
+                },
+                {
+                    'setting': 'avatar_upload_limit',
+                    'name': _("Maximum size of uploaded avatar"),
+                    'description': _("Enter maximum allowed file size "
+                                     "(in KB) for avatar uploads"),
+                    'python_type': 'int',
+                    'value': 128,
+                    'field_extra': {
+                        'min_value': 0,
+                    },
+                },
+                {
+                    'setting': 'subscribe_start',
+                    'name': _("Subscribe to started threads"),
+                    'legend': _("Default subscriptions settings"),
+                    'value': 'watch_email',
+                    'form_field': 'select',
+                    'field_extra': {
+                        'choices': (
+                            ('no', _("Don't watch")),
+                            ('', _("Put on watched threads list")),
+                            ('watch_email', _("Put on watched threads "
+                                              "list and e-mail user when "
+                                              "somebody replies")),
+                        ),
+                    },
+                },
+                {
+                    'setting': 'subscribe_reply',
+                    'name': _("Subscribe to replied threads"),
+                    'value': 'watch_email',
+                    'form_field': 'select',
+                    'field_extra': {
+                        'choices': (
+                            ('no', _("Don't watch")),
+                            ('', _("Put on watched threads list")),
+                            ('watch_email', _("Put on watched threads "
+                                              "list and e-mail user when "
+                                              "somebody replies")),
+                        ),
+                    },
+                },
+            )
+        })
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('misago_users', '0001_initial'),
+        ('misago_conf', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.RunPython(create_users_settings_group),
+    ]

+ 29 - 87
misago/users/migrations/0003_default_ranks.py

@@ -1,98 +1,40 @@
 # -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-from misago.core.migrationutils import ugettext_lazy as _
+from __future__ import unicode_literals
 
+from django.db import models, migrations
+from django.utils.translation import ugettext as _
+from misago.core.utils import slugify
 
-class Migration(SchemaMigration):
 
-    def forwards(self, orm):
-        Rank = orm['users.Rank']
+def create_default_ranks(apps, schema_editor):
+    Rank = apps.get_model('misago_users', 'Rank')
 
-        Rank.objects.create(
-                            name=_("Forum Team").message,
-                            slug='forum-team',
-                            title=_("Team").message,
-                            style='team',
-                            order=0,
-                            is_tab=True,
-                            is_on_index=True,
-                            )
+    team = Rank.objects.create(
+        name=_("Forum Team"),
+        slug=slugify(_("Forum Team")),
+        title=_("Team"),
+        css_class='team',
+        is_tab=True,
+        is_on_index=True,
+        order=0)
 
-        Rank.objects.create(
-                            name=_("Most Valuable Posters").message,
-                            slug='most-valuable-posters',
-                            title=_("MVP").message,
-                            style='mvp',
-                            order=1,
-                            is_tab=True,
-                            )
+    member = Rank.objects.create(
+        name=_("Members"),
+        slug=slugify(_("Members")),
+        is_default=True,
+        order=1)
 
+    Role = apps.get_model('misago_acl', 'Role')
+    team.roles.add(Role.objects.get(name=_("Moderator")))
 
-        Rank.objects.create(
-                            name=_("Members").message,
-                            slug='members',
-                            is_default=True,
-                            order=2,
-                            )
 
-    def backwards(self, orm):
-        pass
+class Migration(migrations.Migration):
 
-    models = {
-        u'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        u'auth.permission': {
-            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        u'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'users.rank': {
-            'Meta': {'object_name': 'Rank'},
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_default': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_on_index': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_tab': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
-            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'style': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        },
-        'users.user': {
-            'Meta': {'object_name': 'User'},
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'db_index': 'True'}),
-            'email_hash': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'joined_on': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'rank': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.Rank']", 'on_delete': 'models.PROTECT'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
-            'username': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
-            'username_slug': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        }
-    }
+    dependencies = [
+        ('misago_users', '0002_users_settings'),
+        ('misago_acl', '0003_default_roles'),
+    ]
 
-    no_dry_run = True
-
-    complete_apps = ['users']
+    operations = [
+        migrations.RunPython(create_default_ranks),
+    ]

+ 0 - 85
misago/users/migrations/0004_auto.py

@@ -1,85 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-        # Adding M2M table for field roles on 'Rank'
-        m2m_table_name = db.shorten_name(u'users_rank_roles')
-        db.create_table(m2m_table_name, (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('rank', models.ForeignKey(orm['users.rank'], null=False)),
-            ('role', models.ForeignKey(orm[u'acl.role'], null=False))
-        ))
-        db.create_unique(m2m_table_name, ['rank_id', 'role_id'])
-
-
-    def backwards(self, orm):
-        # Removing M2M table for field roles on 'Rank'
-        db.delete_table(db.shorten_name(u'users_rank_roles'))
-
-
-    models = {
-        u'acl.role': {
-            'Meta': {'object_name': 'Role'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
-        },
-        u'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        u'auth.permission': {
-            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        u'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'users.rank': {
-            'Meta': {'object_name': 'Rank'},
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_default': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_on_index': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_tab': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
-            'roles': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['acl.Role']", 'symmetrical': 'False'}),
-            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'style': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        },
-        'users.user': {
-            'Meta': {'object_name': 'User'},
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'db_index': 'True'}),
-            'email_hash': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'joined_on': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'rank': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.Rank']", 'on_delete': 'models.PROTECT'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
-            'username': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
-            'username_slug': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        }
-    }
-
-    complete_apps = ['users']

+ 0 - 89
misago/users/migrations/0005_auto__del_field_rank_style__add_field_rank_css_class.py

@@ -1,89 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-        # Deleting field 'Rank.style'
-        db.delete_column(u'users_rank', 'style')
-
-        # Adding field 'Rank.css_class'
-        db.add_column(u'users_rank', 'css_class',
-                      self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True),
-                      keep_default=False)
-
-
-    def backwards(self, orm):
-        # Adding field 'Rank.style'
-        db.add_column(u'users_rank', 'style',
-                      self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True),
-                      keep_default=False)
-
-        # Deleting field 'Rank.css_class'
-        db.delete_column(u'users_rank', 'css_class')
-
-
-    models = {
-        u'acl.role': {
-            'Meta': {'object_name': 'Role'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
-        },
-        u'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        u'auth.permission': {
-            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        u'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'users.rank': {
-            'Meta': {'object_name': 'Rank'},
-            'css_class': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_default': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_on_index': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_tab': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
-            'roles': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['acl.Role']", 'null': 'True', 'blank': 'True'}),
-            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        },
-        'users.user': {
-            'Meta': {'object_name': 'User'},
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'db_index': 'True'}),
-            'email_hash': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'joined_on': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'rank': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.Rank']", 'on_delete': 'models.PROTECT'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
-            'username': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
-            'username_slug': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        }
-    }
-
-    complete_apps = ['users']

+ 0 - 105
misago/users/migrations/0006_auto__add_field_user_title__add_field_user_acl_key.py

@@ -1,105 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-        # Adding field 'User.title'
-        db.add_column(u'users_user', 'title',
-                      self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True),
-                      keep_default=False)
-
-        # Adding field 'User.acl_key'
-        db.add_column(u'users_user', 'acl_key',
-                      self.gf('django.db.models.fields.CharField')(max_length=12, null=True, blank=True),
-                      keep_default=False)
-
-        # Adding M2M table for field roles on 'User'
-        m2m_table_name = db.shorten_name(u'users_user_roles')
-        db.create_table(m2m_table_name, (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('user', models.ForeignKey(orm['users.user'], null=False)),
-            ('role', models.ForeignKey(orm[u'acl.role'], null=False))
-        ))
-        db.create_unique(m2m_table_name, ['user_id', 'role_id'])
-
-
-    def backwards(self, orm):
-        # Deleting field 'User.title'
-        db.delete_column(u'users_user', 'title')
-
-        # Deleting field 'User.acl_key'
-        db.delete_column(u'users_user', 'acl_key')
-
-        # Removing M2M table for field roles on 'User'
-        db.delete_table(db.shorten_name(u'users_user_roles'))
-
-
-    models = {
-        u'acl.role': {
-            'Meta': {'object_name': 'Role'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'special_role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        },
-        u'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        u'auth.permission': {
-            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        u'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'users.rank': {
-            'Meta': {'object_name': 'Rank'},
-            'css_class': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_default': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_on_index': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_tab': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
-            'roles': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['acl.Role']", 'null': 'True', 'blank': 'True'}),
-            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        },
-        'users.user': {
-            'Meta': {'object_name': 'User'},
-            'acl_key': ('django.db.models.fields.CharField', [], {'max_length': '12', 'null': 'True', 'blank': 'True'}),
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'db_index': 'True'}),
-            'email_hash': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'joined_on': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'rank': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.Rank']", 'on_delete': 'models.PROTECT'}),
-            'roles': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['acl.Role']", 'symmetrical': 'False'}),
-            'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
-            'username': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
-            'username_slug': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        }
-    }
-
-    complete_apps = ['users']

+ 0 - 87
misago/users/migrations/0007_auto__chg_field_user_rank.py

@@ -1,87 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-
-        # Changing field 'User.rank'
-        db.alter_column(u'users_user', 'rank_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['users.Rank'], null=True, on_delete=models.PROTECT))
-
-    def backwards(self, orm):
-
-        # User chose to not deal with backwards NULL issues for 'User.rank'
-        raise RuntimeError("Cannot reverse this migration. 'User.rank' and its values cannot be restored.")
-        
-        # The following code is provided here to aid in writing a correct migration
-        # Changing field 'User.rank'
-        db.alter_column(u'users_user', 'rank_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['users.Rank'], on_delete=models.PROTECT))
-
-    models = {
-        u'acl.role': {
-            'Meta': {'object_name': 'Role'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'pickled_permissions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            'special_role': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        },
-        u'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        u'auth.permission': {
-            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        u'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'users.rank': {
-            'Meta': {'object_name': 'Rank'},
-            'css_class': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_default': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_on_index': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_tab': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
-            'roles': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['acl.Role']", 'null': 'True', 'blank': 'True'}),
-            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
-            'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
-        },
-        'users.user': {
-            'Meta': {'object_name': 'User'},
-            'acl_key': ('django.db.models.fields.CharField', [], {'max_length': '12', 'null': 'True', 'blank': 'True'}),
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'db_index': 'True'}),
-            'email_hash': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'joined_on': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'rank': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.Rank']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}),
-            'roles': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['acl.Role']", 'symmetrical': 'False'}),
-            'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
-            'username': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
-            'username_slug': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        }
-    }
-
-    complete_apps = ['users']

+ 1 - 1
misago/users/models/rankmodel.py

@@ -6,7 +6,7 @@ from misago.core.utils import slugify
 
 
 class RankManager(models.Manager):
-    def default(self):
+    def get_default(self):
         return self.get(is_default=True)
 
     def make_rank_default(self, rank):

+ 33 - 23
misago/users/models/usermodel.py

@@ -1,7 +1,7 @@
 from django.contrib.auth.models import (AbstractBaseUser, PermissionsMixin,
                                         UserManager as BaseUserManager,
                                         AnonymousUser as DjangoAnonymousUser)
-from django.db import models
+from django.db import models, transaction
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 from misago.acl import get_user_acl
@@ -16,35 +16,45 @@ from misago.users.validators import (validate_email, validate_password,
 
 class UserManager(BaseUserManager):
     def create_user(self, username, email, password=None, **extra_fields):
-        if not email:
-            raise ValueError(_("User must have an email address."))
-        if not password:
-            raise ValueError(_("User must have a password."))
+        with transaction.atomic():
+            if not email:
+                raise ValueError(_("User must have an email address."))
+            if not password:
+                raise ValueError(_("User must have a password."))
 
-        validate_username(username)
-        validate_email(email)
-        validate_password(password)
+            validate_username(username)
+            validate_email(email)
+            validate_password(password)
 
-        now = timezone.now()
-        user = self.model(is_staff=False, is_superuser=False, last_login=now,
-                          joined_on=now, **extra_fields)
+            now = timezone.now()
+            user = self.model(is_staff=False, is_superuser=False, last_login=now,
+                              joined_on=now, **extra_fields)
 
-        user.set_username(username)
-        user.set_email(email)
-        user.set_password(password)
+            user.set_username(username)
+            user.set_email(email)
+            user.set_password(password)
 
-        if not 'rank' in extra_fields:
-            user.rank = Rank.objects.default()
+            if not 'rank' in extra_fields:
+                user.rank = Rank.objects.get_default()
 
-        user.save(using=self._db)
-        return user
+            user.save(using=self._db)
+
+            authenticated_role = Role.objects.get(special_role='authenticated')
+            if authenticated_role not in user.roles.all():
+                user.roles.add(authenticated_role)
+
+            user.update_acl_key()
+            user.save(update_fields=['acl_key'])
+
+            return user
 
     def create_superuser(self, username, email, password):
-        user = self.create_user(username, email, password=password)
-        user.is_staff = True
-        user.is_superuser = True
-        user.save(update_fields=['is_staff', 'is_superuser'], using=self._db)
-        return user
+        with transaction.atomic():
+            user = self.create_user(username, email, password=password)
+            user.is_staff = True
+            user.is_superuser = True
+            user.save(update_fields=['is_staff', 'is_superuser'], using=self._db)
+            return user
 
     def get_by_username(self, username):
         return self.get(username_slug=slugify(username))

+ 2 - 2
misago/users/permissions/account.py

@@ -12,7 +12,7 @@ class PermissionsForm(forms.Form):
         label=_("Allowed username changes number"),
         min_value=0,
         initial=1)
-    changes_expire = forms.IntegerField(
+    name_changes_expire = forms.IntegerField(
         label=_("Don't count username changes older than"),
         help_text=_("Number of days since name change that makes that change no longer count to limit. Enter zero to make all changes count."),
         min_value=0,
@@ -29,7 +29,7 @@ class PermissionsForm(forms.Form):
 
 
 def change_permissions_form(role):
-    if isinstance(role, Role):
+    if isinstance(role, Role) and role.special_role != 'anonymous':
         return PermissionsForm
     else:
         return None