Browse Source

#596: cut warnings

Rafał Pitoń 8 years ago
parent
commit
38a6847cb0

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

@@ -111,14 +111,6 @@ def create_default_roles(apps, schema_editor):
                 'can_see_hidden_users': 1,
                 'can_see_hidden_users': 1,
             },
             },
 
 
-            # warnings
-            'misago.users.permissions.warnings': {
-                'can_see_other_users_warnings': 1,
-                'can_warn_users': 1,
-                'can_cancel_warnings': 1,
-                'can_be_warned': 0,
-            },
-
             # attachments
             # attachments
             'misago.threads.permissions.attachments': {
             'misago.threads.permissions.attachments': {
                 'max_attachment_size': 8 * 1024,
                 'max_attachment_size': 8 * 1024,
@@ -155,16 +147,6 @@ def create_default_roles(apps, schema_editor):
     )
     )
 
 
     Role.objects.create(
     Role.objects.create(
-        name=_("See warnings"),
-        permissions={
-            # warnings
-            'misago.users.permissions.warnings': {
-                'can_see_other_users_warnings': 1,
-            },
-        }
-    )
-
-    Role.objects.create(
         name=_("Renaming users"),
         name=_("Renaming users"),
         permissions={
         permissions={
             # rename users
             # rename users

+ 0 - 1
misago/conf/defaults.py

@@ -116,7 +116,6 @@ DEFAULT_CONTEXT_PROCESSORS = (
 MISAGO_ACL_EXTENSIONS = (
 MISAGO_ACL_EXTENSIONS = (
     'misago.users.permissions.account',
     'misago.users.permissions.account',
     'misago.users.permissions.profiles',
     'misago.users.permissions.profiles',
-    'misago.users.permissions.warnings',
     'misago.users.permissions.moderation',
     'misago.users.permissions.moderation',
     'misago.users.permissions.delete',
     'misago.users.permissions.delete',
     'misago.categories.permissions',
     'misago.categories.permissions',

+ 4 - 31
misago/users/admin.py

@@ -5,17 +5,10 @@ from django.utils.translation import ugettext_lazy as _
 from .djangoadmin import User, UserAdminModel
 from .djangoadmin import User, UserAdminModel
 from .views.admin.bans import BansList, DeleteBan, EditBan, NewBan
 from .views.admin.bans import BansList, DeleteBan, EditBan, NewBan
 from .views.admin.ranks import (
 from .views.admin.ranks import (
-    DefaultRank,
-    DeleteRank,
-    EditRank,
-    MoveDownRank,
-    MoveUpRank,
-    NewRank,
-    RanksList,
-    RankUsers
-)
-from .views.admin.users import DeleteAccountStep, DeletePostsStep, DeleteThreadsStep, EditUser, NewUser, UsersList
-from .views.admin.warnings import DeleteWarning, EditWarning, MoveDownWarning, MoveUpWarning, NewWarning, WarningsList
+    DefaultRank, DeleteRank, EditRank, MoveDownRank, MoveUpRank, NewRank,
+    RanksList, RankUsers)
+from .views.admin.users import (
+    DeleteAccountStep, DeletePostsStep, DeleteThreadsStep, EditUser, NewUser, UsersList)
 
 
 
 
 # register misago user model in django admin panel
 # register misago user model in django admin panel
@@ -62,17 +55,6 @@ class MisagoAdminExtension(object):
             url(r'^delete/(?P<pk>\d+)/$', DeleteBan.as_view(), name='delete'),
             url(r'^delete/(?P<pk>\d+)/$', DeleteBan.as_view(), name='delete'),
         )
         )
 
 
-        # Warnings
-        urlpatterns.namespace(r'^warnings/', 'warnings', 'users')
-        urlpatterns.patterns('users:warnings',
-            url(r'^$', WarningsList.as_view(), name='index'),
-            url(r'^new/$', NewWarning.as_view(), name='new'),
-            url(r'^edit/(?P<pk>\d+)/$', EditWarning.as_view(), name='edit'),
-            url(r'^move/down/(?P<pk>\d+)/$', MoveDownWarning.as_view(), name='down'),
-            url(r'^move/up/(?P<pk>\d+)/$', MoveUpWarning.as_view(), name='up'),
-            url(r'^delete/(?P<pk>\d+)/$', DeleteWarning.as_view(), name='delete'),
-        )
-
     def register_navigation_nodes(self, site):
     def register_navigation_nodes(self, site):
         site.add_node(
         site.add_node(
             name=_("Users"),
             name=_("Users"),
@@ -108,12 +90,3 @@ class MisagoAdminExtension(object):
             namespace='misago:admin:users:bans',
             namespace='misago:admin:users:bans',
             link='misago:admin:users:bans:index',
             link='misago:admin:users:bans:index',
         )
         )
-
-        site.add_node(
-            name=_("Warning levels"),
-            icon='fa fa-exclamation-triangle',
-            parent='misago:admin:users',
-            after='misago:admin:users:bans:index',
-            namespace='misago:admin:users:warnings',
-            link='misago:admin:users:warnings:index',
-        )

+ 2 - 42
misago/users/forms/admin.py

@@ -8,13 +8,8 @@ from misago.core import forms, threadstore
 from misago.core.validators import validate_sluggable
 from misago.core.validators import validate_sluggable
 
 
 from ..models import (
 from ..models import (
-    AUTO_SUBSCRIBE_CHOICES,
-    BANS_CHOICES,
-    PRIVATE_THREAD_INVITES_LIMITS_CHOICES,
-    RESTRICTIONS_CHOICES,
-    Ban,
-    Rank,
-    WarningLevel
+    AUTO_SUBSCRIBE_CHOICES, BANS_CHOICES, PRIVATE_THREAD_INVITES_LIMITS_CHOICES,
+    Ban, Rank
 )
 )
 from ..validators import validate_email, validate_password, validate_username
 from ..validators import validate_email, validate_password, validate_username
 
 
@@ -603,38 +598,3 @@ class SearchBansForm(forms.Form):
             queryset = queryset.filter(is_checked=False)
             queryset = queryset.filter(is_checked=False)
 
 
         return queryset
         return queryset
-
-
-"""
-Warning levels
-"""
-class WarningLevelForm(forms.ModelForm):
-    name = forms.CharField(label=_("Level name"), max_length=255)
-    length_in_minutes = forms.IntegerField(
-        label=_("Length in minutes"),
-        min_value=0,
-        help_text=_(
-            "Enter number of minutes since this warning level was "
-            "imposed on member until it's reduced, or 0 to make "
-            "this warning level permanent."
-        )
-    )
-    restricts_posting_replies = forms.TypedChoiceField(
-        label=_("Posting replies"),
-        coerce=int,
-        choices=RESTRICTIONS_CHOICES
-    )
-    restricts_posting_threads = forms.TypedChoiceField(
-        label=_("Posting threads"),
-        coerce=int,
-        choices=RESTRICTIONS_CHOICES
-    )
-
-    class Meta:
-        model = WarningLevel
-        fields = [
-            'name',
-            'length_in_minutes',
-            'restricts_posting_replies',
-            'restricts_posting_threads',
-        ]

+ 0 - 15
misago/users/forms/moderation.py

@@ -11,21 +11,6 @@ from misago.core import forms
 from ..bans import ban_user
 from ..bans import ban_user
 
 
 
 
-class WarnUserForm(forms.Form):
-    reason = forms.CharField(label=_("Warning Reason"),
-                             help_text=_("Optional message explaining why "
-                                         "this warning was given."),
-                             widget=forms.Textarea(attrs={'rows': 8}),
-                             required=False)
-
-    def clean_reason(self):
-        data = self.cleaned_data['reason']
-        if len(data) > 2000:
-            message = _("Warning reason can't be longer than 2000 characters.")
-            raise forms.ValidationError(message)
-        return data
-
-
 class ModerateAvatarForm(forms.ModelForm):
 class ModerateAvatarForm(forms.ModelForm):
     is_avatar_locked = forms.YesNoSwitch()
     is_avatar_locked = forms.YesNoSwitch()
     avatar_lock_user_message = forms.CharField(required=False)
     avatar_lock_user_message = forms.CharField(required=False)

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

@@ -61,11 +61,8 @@ class Migration(migrations.Migration):
                 ('is_signature_locked', models.BooleanField(default=False)),
                 ('is_signature_locked', models.BooleanField(default=False)),
                 ('signature_lock_user_message', models.TextField(null=True, blank=True)),
                 ('signature_lock_user_message', models.TextField(null=True, blank=True)),
                 ('signature_lock_staff_message', models.TextField(null=True, blank=True)),
                 ('signature_lock_staff_message', models.TextField(null=True, blank=True)),
-                ('warning_level', models.PositiveIntegerField(default=0)),
-                ('warning_level_update_on', models.DateTimeField(null=True, blank=True)),
                 ('following', models.PositiveIntegerField(default=0)),
                 ('following', models.PositiveIntegerField(default=0)),
                 ('followers', models.PositiveIntegerField(default=0)),
                 ('followers', models.PositiveIntegerField(default=0)),
-                ('new_notifications', models.PositiveIntegerField(default=0)),
                 ('limits_private_thread_invites_to', models.PositiveIntegerField(default=0)),
                 ('limits_private_thread_invites_to', models.PositiveIntegerField(default=0)),
                 ('unread_private_threads', models.PositiveIntegerField(default=0)),
                 ('unread_private_threads', models.PositiveIntegerField(default=0)),
                 ('sync_unread_private_threads', models.BooleanField(default=False)),
                 ('sync_unread_private_threads', models.BooleanField(default=False)),
@@ -213,43 +210,4 @@ class Migration(migrations.Migration):
             },
             },
             bases=(models.Model,),
             bases=(models.Model,),
         ),
         ),
-        migrations.CreateModel(
-            name='WarningLevel',
-            fields=[
-                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
-                ('name', models.CharField(max_length=255)),
-                ('level', models.PositiveIntegerField(default=1, db_index=True)),
-                ('length_in_minutes', models.PositiveIntegerField(default=0)),
-                ('restricts_posting_replies', models.PositiveIntegerField(default=0)),
-                ('restricts_posting_threads', models.PositiveIntegerField(default=0)),
-            ],
-            options={
-            },
-            bases=(models.Model,),
-        ),
-        migrations.CreateModel(
-            name='UserWarning',
-            fields=[
-                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
-                ('reason', models.TextField(null=True, blank=True)),
-                ('given_on', models.DateTimeField(default=django.utils.timezone.now)),
-                ('giver_username', models.CharField(max_length=255)),
-                ('giver_slug', models.CharField(max_length=255)),
-                ('is_canceled', models.BooleanField(default=False)),
-                ('canceled_on', models.DateTimeField(null=True, blank=True)),
-                ('canceler_username', models.CharField(max_length=255)),
-                ('canceler_slug', models.CharField(max_length=255)),
-                ('canceler', models.ForeignKey(related_name='warnings_canceled', on_delete=django.db.models.deletion.SET_NULL, blank=True, to=settings.AUTH_USER_MODEL, null=True)),
-                ('giver', models.ForeignKey(related_name='warnings_given', on_delete=django.db.models.deletion.SET_NULL, blank=True, to=settings.AUTH_USER_MODEL, null=True)),
-                ('user', models.ForeignKey(related_name='warnings', to=settings.AUTH_USER_MODEL)),
-            ],
-            options={
-            },
-            bases=(models.Model,),
-        ),
-        CreatePartialIndex(
-            field='UserWarning.is_canceled',
-            index_name='misago_userwarning_is_canceled_partial',
-            condition='is_canceled = FALSE',
-        ),
     ]
     ]

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

@@ -5,4 +5,3 @@ from .activityranking import *
 from .avatar import *
 from .avatar import *
 from .avatargallery import *
 from .avatargallery import *
 from .ban import *
 from .ban import *
-from .warnings import *

+ 0 - 5
misago/users/models/user.py

@@ -253,9 +253,6 @@ class User(AbstractBaseUser, PermissionsMixin):
     signature_lock_user_message = models.TextField(null=True, blank=True)
     signature_lock_user_message = models.TextField(null=True, blank=True)
     signature_lock_staff_message = models.TextField(null=True, blank=True)
     signature_lock_staff_message = models.TextField(null=True, blank=True)
 
 
-    warning_level = models.PositiveIntegerField(default=0)
-    warning_level_update_on = models.DateTimeField(null=True, blank=True)
-
     followers = models.PositiveIntegerField(default=0)
     followers = models.PositiveIntegerField(default=0)
     following = models.PositiveIntegerField(default=0)
     following = models.PositiveIntegerField(default=0)
 
 
@@ -268,8 +265,6 @@ class User(AbstractBaseUser, PermissionsMixin):
         symmetrical=False,
         symmetrical=False,
     )
     )
 
 
-    new_notifications = models.PositiveIntegerField(default=0)
-
     limits_private_thread_invites_to = models.PositiveIntegerField(
     limits_private_thread_invites_to = models.PositiveIntegerField(
         default=LIMITS_PRIVATE_THREAD_INVITES_TO_NONE
         default=LIMITS_PRIVATE_THREAD_INVITES_TO_NONE
     )
     )

+ 0 - 148
misago/users/models/warnings.py

@@ -1,148 +0,0 @@
-from collections import OrderedDict
-from datetime import timedelta
-
-from django.conf import settings
-from django.db import models
-from django.utils import timezone
-from django.utils.encoding import python_2_unicode_compatible
-from django.utils.translation import ugettext_lazy as _
-
-from misago.core import threadstore
-from misago.core.cache import cache
-
-
-__all__ = [
-    'RESTRICT_NO', 'RESTRICT_MODERATOR_REVIEW', 'RESTRICT_DISALLOW',
-    'RESTRICTIONS_CHOICES', 'WarningLevel', 'UserWarning'
-]
-
-
-CACHE_NAME = 'misago_warning_levels'
-
-RESTRICT_NO = 0
-RESTRICT_MODERATOR_REVIEW = 1
-RESTRICT_DISALLOW = 2
-
-
-RESTRICTIONS_CHOICES = (
-    (RESTRICT_NO, _("No restrictions")),
-    (RESTRICT_MODERATOR_REVIEW, _("Review by moderator")),
-    (RESTRICT_DISALLOW, _("Disallowed")),
-)
-
-
-class WarningLevelManager(models.Manager):
-    def dict(self):
-        return self.get_levels_from_threadstore()
-
-    def get_levels_from_threadstore(self):
-        levels = threadstore.get(CACHE_NAME, 'nada')
-        if levels == 'nada':
-            levels = self.get_levels_from_cache()
-            threadstore.set(CACHE_NAME, levels)
-        return levels
-
-    def get_levels_from_cache(self):
-        levels = cache.get(CACHE_NAME, 'nada')
-        if levels == 'nada':
-            levels = self.get_levels_from_database()
-            cache.set(CACHE_NAME, levels)
-        return levels
-
-    def get_levels_from_database(self):
-        levels = [(0, None)]
-        for level, obj in enumerate(self.order_by('level')):
-            levels.append((level + 1, obj))
-        return OrderedDict(levels)
-
-
-@python_2_unicode_compatible
-class WarningLevel(models.Model):
-    name = models.CharField(max_length=255)
-    level = models.PositiveIntegerField(default=1, db_index=True)
-    length_in_minutes = models.PositiveIntegerField(default=0)
-    restricts_posting_replies = models.PositiveIntegerField(
-        default=RESTRICT_NO)
-    restricts_posting_threads = models.PositiveIntegerField(
-        default=RESTRICT_NO)
-
-    objects = WarningLevelManager()
-
-    def __str__(self):
-        return self.name
-
-    def save(self, *args, **kwargs):
-        if not self.pk:
-            self.set_level()
-
-        super(WarningLevel, self).save(*args, **kwargs)
-        cache.delete(CACHE_NAME)
-
-    def delete(self, *args, **kwargs):
-        super(WarningLevel, self).delete(*args, **kwargs)
-        cache.delete(CACHE_NAME)
-
-    @property
-    def has_restrictions(self):
-        return self.restricts_posting_replies or self.restricts_posting_threads
-
-    @property
-    def is_replying_moderated(self):
-        return self.restricts_posting_replies == RESTRICT_MODERATOR_REVIEW
-
-    @property
-    def is_replying_disallowed(self):
-        return self.restricts_posting_replies == RESTRICT_DISALLOW
-
-    @property
-    def is_starting_threads_moderated(self):
-        return self.restricts_posting_threads == RESTRICT_MODERATOR_REVIEW
-
-    @property
-    def is_starting_threads_disallowed(self):
-        return self.restricts_posting_threads == RESTRICT_DISALLOW
-
-    def set_level(self):
-        try:
-            self.level = WarningLevel.objects.latest('level').level + 1
-        except WarningLevel.DoesNotExist:
-            self.level = 1
-
-
-class UserWarning(models.Model):
-    user = models.ForeignKey(settings.AUTH_USER_MODEL,
-                             related_name="warnings")
-    reason = models.TextField(null=True, blank=True)
-    given_on = models.DateTimeField(default=timezone.now)
-    giver = models.ForeignKey(settings.AUTH_USER_MODEL,
-                              null=True, blank=True,
-                              on_delete=models.SET_NULL,
-                              related_name="warnings_given")
-    giver_username = models.CharField(max_length=255)
-    giver_slug = models.CharField(max_length=255)
-    is_canceled = models.BooleanField(default=False)
-    canceled_on = models.DateTimeField(null=True, blank=True)
-    canceler = models.ForeignKey(settings.AUTH_USER_MODEL,
-                                 null=True, blank=True,
-                                 on_delete=models.SET_NULL,
-                                 related_name="warnings_canceled")
-    canceler_username = models.CharField(max_length=255)
-    canceler_slug = models.CharField(max_length=255)
-
-    def cancel(self, canceler):
-        self.is_canceled = True
-        self.canceled_on = timezone.now()
-        self.canceler = canceler
-        self.canceler_username = canceler.username
-        self.canceler_slug = canceler.slug
-
-        self.save(update_fields=(
-            'is_canceled',
-            'canceled_on',
-            'canceler',
-            'canceler_username',
-            'canceler_slug',
-        ))
-
-    def is_expired(self, valid_for):
-        return timezone.now() > self.given_on + timedelta(minutes=valid_for)

+ 0 - 147
misago/users/permissions/warnings.py

@@ -1,147 +0,0 @@
-from django.contrib.auth import get_user_model
-from django.core.exceptions import PermissionDenied
-from django.utils.translation import ugettext_lazy as _
-
-from misago.acl import algebra
-from misago.acl.decorators import return_boolean
-from misago.acl.models import Role
-from misago.core import forms
-
-from ..models import UserWarning
-from .decorators import authenticated_only
-
-
-"""
-Admin Permissions Form
-"""
-NO_OWNED_ALL = ((0, _("No")), (1, _("Owned")), (2, _("All")))
-
-
-class LimitedPermissionsForm(forms.Form):
-    legend = _("Warnings")
-
-    can_see_other_users_warnings = forms.YesNoSwitch(label=_("Can see other users warnings"))
-
-
-class PermissionsForm(LimitedPermissionsForm):
-    can_warn_users = forms.YesNoSwitch(label=_("Can warn users"))
-    can_be_warned = forms.YesNoSwitch(label=_("Can be warned"), initial=False)
-    can_cancel_warnings = forms.TypedChoiceField(
-        label=_("Can cancel warnings"),
-        coerce=int,
-        choices=NO_OWNED_ALL,
-        initial=0
-    )
-    can_delete_warnings = forms.TypedChoiceField(
-        label=_("Can delete warnings"),
-        coerce=int,
-        choices=NO_OWNED_ALL,
-        initial=0
-    )
-
-
-def change_permissions_form(role):
-    if isinstance(role, Role):
-        if role.special_role == 'anonymous':
-            return LimitedPermissionsForm
-        else:
-            return PermissionsForm
-    else:
-        return None
-
-
-"""
-ACL Builder
-"""
-def build_acl(acl, roles, key_name):
-    new_acl = {
-        'can_see_other_users_warnings': 0,
-        'can_warn_users': 0,
-        'can_cancel_warnings': 0,
-        'can_delete_warnings': 0,
-        'can_be_warned': 1,
-    }
-    new_acl.update(acl)
-
-    return algebra.sum_acls(new_acl, roles=roles, key=key_name,
-        can_see_other_users_warnings=algebra.greater,
-        can_warn_users=algebra.greater,
-        can_cancel_warnings=algebra.greater,
-        can_delete_warnings=algebra.greater,
-        can_be_warned=algebra.lower
-    )
-
-
-"""
-ACL's for targets
-"""
-def add_acl_to_user(user, target):
-    target_acl = target.acl_
-
-    target_acl['can_see_warnings'] = can_see_warnings(user, target)
-    target_acl['can_warn'] = can_warn_user(user, target)
-    target_acl['can_cancel_warnings'] = False
-    target_acl['can_delete_warnings'] = False
-
-    if target_acl['can_warn']:
-        target_acl['can_moderate'] = True
-
-
-def add_acl_to_warning(user, target):
-    target.acl['can_cancel'] = can_cancel_warning(user, target)
-    target.acl['can_delete'] = can_delete_warning(user, target)
-
-    can_moderate = target.acl['can_cancel'] or target.acl['can_delete']
-    target.acl['can_moderate'] = can_moderate
-
-
-def register_with(registry):
-    registry.acl_annotator(get_user_model(), add_acl_to_user)
-    registry.acl_annotator(UserWarning, add_acl_to_warning)
-
-
-"""
-ACL tests
-"""
-def allow_see_warnings(user, target):
-    if user.is_authenticated() and user.pk == target.pk:
-        return None
-    if not user.acl['can_see_other_users_warnings']:
-        raise PermissionDenied(_("You can't see other users warnings."))
-can_see_warnings = return_boolean(allow_see_warnings)
-
-
-@authenticated_only
-def allow_warn_user(user, target):
-    if not user.acl['can_warn_users']:
-        raise PermissionDenied(_("You can't warn users."))
-    if not user.is_superuser and (target.is_staff or target.is_superuser):
-        raise PermissionDenied(_("You can't warn administrators."))
-    if not target.acl['can_be_warned']:
-        message = _("%(user)s can't be warned.")
-        raise PermissionDenied(message % {'user': target.username})
-can_warn_user = return_boolean(allow_warn_user)
-
-
-@authenticated_only
-def allow_cancel_warning(user, target):
-    if user.is_anonymous() or not user.acl['can_cancel_warnings']:
-        raise PermissionDenied(_("You can't cancel warnings."))
-    if user.acl['can_cancel_warnings'] == 1:
-        if target.giver_id != user.pk:
-            message = _("You can't cancel warnings issued by other users.")
-            raise PermissionDenied(message)
-    if target.is_canceled:
-        raise PermissionDenied(_("This warning is already canceled."))
-can_cancel_warning = return_boolean(allow_cancel_warning)
-
-
-@authenticated_only
-def allow_delete_warning(user, target):
-    if user.is_anonymous() or not user.acl['can_delete_warnings']:
-        raise PermissionDenied(_("You can't delete warnings."))
-    if user.acl['can_delete_warnings'] == 1:
-        if target.giver_id != user.pk:
-            message = _("You can't delete warnings issued by other users.")
-            raise PermissionDenied(message)
-can_delete_warning = return_boolean(allow_delete_warning)

+ 0 - 1
misago/users/serializers/user.py

@@ -51,7 +51,6 @@ class AuthenticatedUserSerializer(serializers.ModelSerializer):
             'short_title',
             'short_title',
             'rank',
             'rank',
             'avatars',
             'avatars',
-            'new_notifications',
             'limits_private_thread_invites_to',
             'limits_private_thread_invites_to',
             'unread_private_threads',
             'unread_private_threads',
             'subscribe_to_started_threads',
             'subscribe_to_started_threads',

+ 0 - 8
misago/users/signals.py

@@ -13,11 +13,3 @@ def handle_name_change(sender, **kwargs):
     sender.user_renames.update(
     sender.user_renames.update(
         changed_by_username=sender.username
         changed_by_username=sender.username
     )
     )
-    sender.warnings_given.update(
-        giver_username=sender.username,
-        giver_slug=sender.slug
-    )
-    sender.warnings_canceled.update(
-        canceler_username=sender.username,
-        canceler_slug=sender.slug
-    )

+ 0 - 170
misago/users/tests/test_warningadmin_views.py

@@ -1,170 +0,0 @@
-from django.urls import reverse
-
-from misago.admin.testutils import AdminTestCase
-
-from ..models import WarningLevel
-
-
-class WarningsAdminViewsTests(AdminTestCase):
-    def test_link_registered(self):
-        """admin nav contains warning levels link"""
-        response = self.client.get(
-            reverse('misago:admin:users:accounts:index'))
-
-        response = self.client.get(response['location'])
-        self.assertContains(response, reverse('misago:admin:users:warnings:index'))
-
-    def test_list_view(self):
-        """warning levels list view returns 200"""
-        response = self.client.get(
-            reverse('misago:admin:users:warnings:index'))
-
-        self.assertEqual(response.status_code, 200)
-        self.assertContains(response, 'No warning levels')
-
-    def test_new_view(self):
-        """new warning level view has no showstoppers"""
-        response = self.client.get(
-            reverse('misago:admin:users:warnings:new'))
-        self.assertEqual(response.status_code, 200)
-
-        response = self.client.post(
-            reverse('misago:admin:users:warnings:new'),
-            data={
-                'name': 'Test Level',
-                'length_in_minutes': 60,
-                'restricts_posting_replies': '1',
-                'restricts_posting_threads': '1',
-            })
-        self.assertEqual(response.status_code, 302)
-
-        response = self.client.get(
-            reverse('misago:admin:users:warnings:index'))
-        self.assertEqual(response.status_code, 200)
-        self.assertContains(response, 'Test Level')
-
-    def test_edit_view(self):
-        """edit warning level view has no showstoppers"""
-        self.client.post(
-            reverse('misago:admin:users:warnings:new'),
-            data={
-                'name': 'Test Level',
-                'length_in_minutes': 60,
-                'restricts_posting_replies': '1',
-                'restricts_posting_threads': '1',
-            })
-
-        test_level = WarningLevel.objects.get(level=1)
-
-        response = self.client.get(
-            reverse('misago:admin:users:warnings:edit',
-                    kwargs={'pk': test_level.pk}))
-        self.assertEqual(response.status_code, 200)
-        self.assertContains(response, test_level.name)
-
-        response = self.client.post(
-            reverse('misago:admin:users:warnings:edit',
-                    kwargs={'pk': test_level.pk}),
-            data={
-                'name': 'Edited Level',
-                'length_in_minutes': 5,
-                'restricts_posting_replies': '0',
-                'restricts_posting_threads': '0',
-            })
-        self.assertEqual(response.status_code, 302)
-
-        test_level = WarningLevel.objects.get(level=1)
-        response = self.client.get(
-            reverse('misago:admin:users:warnings:index'))
-        self.assertEqual(response.status_code, 200)
-        self.assertContains(response, test_level.name)
-        self.assertNotContains(response, 'Test Level')
-
-    def test_move_up_view(self):
-        """move warning level up view has no showstoppers"""
-        self.client.post(
-            reverse('misago:admin:users:warnings:new'),
-            data={
-                'name': 'Level 1',
-                'length_in_minutes': 5,
-                'restricts_posting_replies': '0',
-                'restricts_posting_threads': '0',
-            })
-        self.client.post(
-            reverse('misago:admin:users:warnings:new'),
-            data={
-                'name': 'Level 2',
-                'length_in_minutes': 5,
-                'restricts_posting_replies': '0',
-                'restricts_posting_threads': '0',
-            })
-
-        test_level_1 = WarningLevel.objects.get(level=1)
-        test_level_2 = WarningLevel.objects.get(level=2)
-
-        response = self.client.post(
-            reverse('misago:admin:users:warnings:up',
-                    kwargs={'pk': test_level_2.pk}))
-        self.assertEqual(response.status_code, 302)
-
-        changed_level_1 = WarningLevel.objects.get(id=test_level_1.pk)
-        changed_level_2 = WarningLevel.objects.get(id=test_level_2.pk)
-        self.assertEqual(test_level_1.level, changed_level_2.level)
-        self.assertEqual(test_level_2.level, changed_level_1.level)
-
-    def test_move_down_view(self):
-        """move warning level down view has no showstoppers"""
-        self.client.post(
-            reverse('misago:admin:users:warnings:new'),
-            data={
-                'name': 'Level 1',
-                'length_in_minutes': 5,
-                'restricts_posting_replies': '0',
-                'restricts_posting_threads': '0',
-            })
-        self.client.post(
-            reverse('misago:admin:users:warnings:new'),
-            data={
-                'name': 'Level 2',
-                'length_in_minutes': 5,
-                'restricts_posting_replies': '0',
-                'restricts_posting_threads': '0',
-            })
-
-        test_level_1 = WarningLevel.objects.get(level=1)
-        test_level_2 = WarningLevel.objects.get(level=2)
-
-        response = self.client.post(
-            reverse('misago:admin:users:warnings:down',
-                    kwargs={'pk': test_level_1.pk}))
-        self.assertEqual(response.status_code, 302)
-
-        changed_level_1 = WarningLevel.objects.get(id=test_level_1.pk)
-        changed_level_2 = WarningLevel.objects.get(id=test_level_2.pk)
-        self.assertEqual(test_level_1.level, changed_level_2.level)
-        self.assertEqual(test_level_2.level, changed_level_1.level)
-
-    def test_delete_view(self):
-        """delete warning level view has no showstoppers"""
-        self.client.post(
-            reverse('misago:admin:users:warnings:new'),
-            data={
-                'name': 'Test Level',
-                'length_in_minutes': 60,
-                'restricts_posting_replies': '1',
-                'restricts_posting_threads': '1',
-            })
-
-        test_level = WarningLevel.objects.get(level=1)
-
-        response = self.client.post(
-            reverse('misago:admin:users:warnings:delete',
-                    kwargs={'pk': test_level.pk}))
-        self.assertEqual(response.status_code, 302)
-
-        self.client.get(reverse('misago:admin:users:warnings:index'))
-        response = self.client.get(
-            reverse('misago:admin:users:warnings:index'))
-        self.assertEqual(response.status_code, 200)
-
-        self.assertNotContains(response, test_level.name)

+ 0 - 72
misago/users/tests/test_warnings.py

@@ -1,72 +0,0 @@
-from datetime import timedelta
-
-from django.contrib.auth import get_user_model
-from django.test import TestCase
-from django.utils import timezone
-
-from misago.core import threadstore
-from misago.core.cache import cache
-
-from .. import warnings
-from ..models import UserWarning, WarningLevel
-
-
-class WarningsTests(TestCase):
-    def setUp(self):
-        User = get_user_model()
-        self.test_mod = User.objects.create_user('Modo', 'mod@mod.com',
-                                                 'Pass.123')
-        self.test_user = User.objects.create_user('Bob', 'bob@bob.com',
-                                                  'Pass.123')
-
-    def test_warnings(self):
-        """user warning levels is obtained"""
-        threadstore.clear()
-        cache.clear()
-
-        self.assertTrue(warnings.is_user_warning_level_max(self.test_user))
-
-        levels = (
-            WarningLevel.objects.create(name="Level 1"),
-            WarningLevel.objects.create(name="Level 2"),
-            WarningLevel.objects.create(name="Level 3"),
-            WarningLevel.objects.create(name="Level 4"),
-            WarningLevel.objects.create(name="Level 5"),
-            WarningLevel.objects.create(name="Level 6"),
-            WarningLevel.objects.create(name="Level 7"),
-            WarningLevel.objects.create(name="Level 8")
-        )
-
-        self.assertEqual(WarningLevel.objects.count(), 8)
-
-        threadstore.clear()
-        cache.clear()
-
-        for level, warning in enumerate(levels):
-            warnings.warn_user(self.test_mod, self.test_user, "bawww")
-
-            user_level = warnings.get_user_warning_level(self.test_user)
-            user_level_obj = warnings.get_user_warning_obj(self.test_user)
-
-            self.assertEqual(user_level, level + 1)
-            self.assertEqual(user_level_obj.name, levels[level].name)
-            self.assertEqual(self.test_user.warning_level, level + 1)
-
-        self.assertTrue(warnings.is_user_warning_level_max(self.test_user))
-
-        previous_level = user_level
-        for warning in self.test_user.warnings.all():
-            warnings.cancel_warning(self.test_mod, self.test_user, warning)
-            user_level = warnings.get_user_warning_level(self.test_user)
-            self.assertEqual(user_level + 1, previous_level)
-            previous_level = user_level
-
-        self.assertEqual(0, warnings.get_user_warning_level(self.test_user))
-
-
-class WarningModelTests(TestCase):
-    def test_warning_is_expired(self):
-        """warning knows wheter or not its expired"""
-        warning = UserWarning(given_on=timezone.now() - timedelta(days=6))
-        self.assertTrue(warning.is_expired(60))
-        self.assertFalse(warning.is_expired(14 * 24 * 3600))

+ 0 - 72
misago/users/views/admin/warnings.py

@@ -1,72 +0,0 @@
-from django.contrib import messages
-from django.utils.translation import ugettext_lazy as _
-
-from misago.admin.views import generic
-
-from ...forms.admin import WarningLevelForm
-from ...models import WarningLevel
-
-
-class WarningsAdmin(generic.AdminBaseMixin):
-    root_link = 'misago:admin:users:warnings:index'
-    Model = WarningLevel
-    Form = WarningLevelForm
-    templates_dir = 'misago/admin/warnings'
-    message_404 = _("Requested warning level does not exist.")
-
-
-class WarningsList(WarningsAdmin, generic.ListView):
-    ordering = (('level', None),)
-
-
-class NewWarning(WarningsAdmin, generic.ModelFormView):
-    message_submit = _('New warning level "%(name)s" has been saved.')
-
-
-class EditWarning(WarningsAdmin, generic.ModelFormView):
-    message_submit = _('Warning level "%(name)s" has been edited.')
-
-
-class DeleteWarning(WarningsAdmin, generic.ButtonView):
-    def button_action(self, request, target):
-        target.delete()
-        message = _('Warning level "%(name)s" has been deleted.')
-        messages.success(request, message % {'name': target.name})
-
-
-class MoveDownWarning(WarningsAdmin, generic.ButtonView):
-    def button_action(self, request, target):
-        try:
-            other_target = WarningLevel.objects.filter(level__gt=target.level)
-            other_target = other_target.earliest('level')
-        except WarningLevel.DoesNotExist:
-            other_target = None
-
-        if other_target:
-            other_target.level, target.level = target.level, other_target.level
-            other_target.save(update_fields=['level'])
-            target.save(update_fields=['level'])
-
-            message = _('Warning level "%(name)s" has '
-                        'been moved below "%(other)s".')
-            targets_names = {'name': target.name, 'other': other_target.name}
-            messages.success(request, message % targets_names)
-
-
-class MoveUpWarning(WarningsAdmin, generic.ButtonView):
-    def button_action(self, request, target):
-        try:
-            other_target = WarningLevel.objects.filter(level__lt=target.level)
-            other_target = other_target.latest('level')
-        except WarningLevel.DoesNotExist:
-            other_target = None
-
-        if other_target:
-            other_target.level, target.level = target.level, other_target.level
-            other_target.save(update_fields=['level'])
-            target.save(update_fields=['level'])
-
-            message = _('Warning level "%(name)s" has '
-                        'been moved above "%(other)s".')
-            targets_names = {'name': target.name, 'other': other_target.name}
-            messages.success(request, message % targets_names)

+ 0 - 1
misago/users/views/profile.py

@@ -24,7 +24,6 @@ from ..permissions.profiles import allow_block_user, allow_follow_user
 from ..serializers import BanDetailsSerializer, UserProfileSerializer, UserSerializer
 from ..serializers import BanDetailsSerializer, UserProfileSerializer, UserSerializer
 from ..serializers.usernamechange import UsernameChangeSerializer
 from ..serializers.usernamechange import UsernameChangeSerializer
 from ..viewmodels import UserPosts, UserThreads
 from ..viewmodels import UserPosts, UserThreads
-from ..warnings import get_user_warning_level, get_user_warning_obj, get_warning_levels
 
 
 
 
 def profile_view(f):
 def profile_view(f):

+ 0 - 106
misago/users/warnings.py

@@ -1,106 +0,0 @@
-from datetime import timedelta
-
-from django.utils import timezone
-
-from .models import WarningLevel
-
-
-def get_warning_levels():
-    return WarningLevel.objects.dict()
-
-
-def fetch_user_valid_warnings(user):
-    levels = get_warning_levels()
-    max_level = len(levels) - 1
-
-    if not max_level:
-        return []
-
-    # build initial list of valid exceptions
-    queryset = user.warnings.exclude(is_canceled=True)
-    warnings = [w for w in queryset.order_by('-id')[:max_level]]
-
-    if not warnings:
-        return []
-
-    # expire levels
-    active_warnings = []
-    for length, level in enumerate(list(levels.values())[1:]):
-        length += 1
-        level_warnings = []
-        if level.length_in_minutes:
-            cutoff_date = timezone.now()
-            cutoff_date -= timedelta(minutes=level.length_in_minutes)
-            for warning in warnings:
-                if warning.given_on >= cutoff_date:
-                    level_warnings.append(warning)
-            if len(level_warnings) == length:
-                active_warnings = level_warnings[:length]
-            else:
-                break
-        else:
-            active_warnings = warnings[:length]
-    return active_warnings
-
-
-def update_user_warning_level(user):
-    warnings = fetch_user_valid_warnings(user)
-    user.warning_level = len(warnings)
-
-    levels = get_warning_levels()
-
-    if user.warning_level and levels[user.warning_level].length_in_minutes:
-        level_length = levels[user.warning_level].length_in_minutes
-        next_check_date = warnings[-1].given_on
-        next_check_date += timedelta(minutes=level_length)
-        user.warning_level_update_on = next_check_date
-    else:
-        user.warning_level_update_on = None
-
-    user.save(update_fields=('warning_level', 'warning_level_update_on'))
-
-
-def get_user_warning_level(user):
-    warning_level_expiration = user.warning_level_update_on
-    if warning_level_expiration and warning_level_expiration < timezone.now():
-        update_user_warning_level(user)
-    return user.warning_level
-
-
-def get_user_warning_obj(user):
-    warning_level = get_user_warning_level(user)
-    if warning_level:
-        return get_warning_levels()[warning_level]
-    else:
-        return None
-
-
-def is_user_warning_level_max(user):
-    user_level = get_user_warning_level(user)
-    levels = len(get_warning_levels())
-    return user_level == levels - 1
-
-
-def warn_user(moderator, user, reason=''):
-    warning = user.warnings.create(reason=reason,
-                                   giver=moderator,
-                                   giver_username=moderator.username,
-                                   giver_slug=moderator.slug)
-
-    user.warning_level_update_on = timezone.now()
-    update_user_warning_level(user)
-    return warning
-
-
-def cancel_warning(moderator, user, warning):
-    warning.cancel(moderator)
-
-    user.warning_level_update_on = timezone.now()
-    update_user_warning_level(user)
-
-
-def delete_warning(moderator, user, warning):
-    warning.delete()
-
-    user.warning_level_update_on = timezone.now()
-    update_user_warning_level(user)