Browse Source

More advancements on warnings. #37

Rafał Pitoń 11 years ago
parent
commit
0898c81892

+ 6 - 3
misago/acl/permissions/warnings.py

@@ -73,13 +73,16 @@ class WarningsACL(BaseACL):
         except ACLError403:
         except ACLError403:
             return False
             return False
 
 
-    def allow_cancel_warning(self, user, warning):
+    def allow_cancel_warning(self, user, owner, warning):
         if not self.acl['can_cancel_warnings']:
         if not self.acl['can_cancel_warnings']:
             raise ACLError403(_("You can't cancel warnings."))
             raise ACLError403(_("You can't cancel warnings."))
 
 
         if warning.canceled:
         if warning.canceled:
             raise ACLError403(_("This warning is already canceled."))
             raise ACLError403(_("This warning is already canceled."))
 
 
+        if not owner.is_warning_active(warning):
+            raise ACLError403(_("This warning is no longer in effect."))
+
         try:
         try:
             if (self.acl['can_cancel_warnings'] == 1 and
             if (self.acl['can_cancel_warnings'] == 1 and
                     user.id != warning.giver_id):
                     user.id != warning.giver_id):
@@ -95,9 +98,9 @@ class WarningsACL(BaseACL):
                 self.acl['can_cancel_warnings_newer_than'] < warning_age):
                 self.acl['can_cancel_warnings_newer_than'] < warning_age):
             raise ACLError403(_("This warning can no longer be canceled."))
             raise ACLError403(_("This warning can no longer be canceled."))
 
 
-    def can_cancel_warning(self, user, warning):
+    def can_cancel_warning(self, user, owner, warning):
         try:
         try:
-            self.allow_cancel_warning(user, warning)
+            self.allow_cancel_warning(user, owner, warning)
             return True
             return True
         except ACLError403:
         except ACLError403:
             return False
             return False

+ 4 - 0
misago/apps/profiles/warnings/urls.py

@@ -7,10 +7,14 @@ def register_profile_urls(first=False):
             url(r'^$', 'warnings', name="user"),
             url(r'^$', 'warnings', name="user"),
             url(r'^$', 'warnings', name="user_warnings"),
             url(r'^$', 'warnings', name="user_warnings"),
             url(r'^(?P<page>[1-9]([0-9]+)?)/$', 'warnings', name="user_warnings"),
             url(r'^(?P<page>[1-9]([0-9]+)?)/$', 'warnings', name="user_warnings"),
+            url(r'^(?P<warning>\d+)/cancel/$', 'cancel_warning', name="user_warnings_cancel"),
+            url(r'^(?P<warning>\d+)/delete/$', 'delete_warning', name="user_warnings_delete"),
         )
         )
     else:
     else:
         urlpatterns += patterns('misago.apps.profiles.warnings.views',
         urlpatterns += patterns('misago.apps.profiles.warnings.views',
             url(r'^warnings/$', 'warnings', name="user_warnings"),
             url(r'^warnings/$', 'warnings', name="user_warnings"),
             url(r'^warnings/(?P<page>[1-9]([0-9]+)?)/$', 'warnings', name="user_warnings"),
             url(r'^warnings/(?P<page>[1-9]([0-9]+)?)/$', 'warnings', name="user_warnings"),
+            url(r'^warnings/(?P<warning>\d+)/cancel/$', 'cancel_warning', name="user_warnings_cancel"),
+            url(r'^warnings/(?P<warning>\d+)/delete/$', 'delete_warning', name="user_warnings_delete"),
         )
         )
     return urlpatterns
     return urlpatterns

+ 41 - 0
misago/apps/profiles/warnings/views.py

@@ -4,9 +4,13 @@ from django.core.urlresolvers import reverse
 from django.http import Http404
 from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.utils import timezone
 from django.utils import timezone
+from django.utils.translation import ugettext as _
+from misago.apps.errors import error404
 from misago.apps.profiles.decorators import profile_view
 from misago.apps.profiles.decorators import profile_view
 from misago.apps.profiles.template import RequestContext
 from misago.apps.profiles.template import RequestContext
 from misago.apps.profiles.warnings.warningstracker import WarningsTracker
 from misago.apps.profiles.warnings.warningstracker import WarningsTracker
+from misago.decorators import check_csrf
+from misago.models import Warn
 from misago.shortcuts import render_to_response
 from misago.shortcuts import render_to_response
 from misago.utils.pagination import make_pagination
 from misago.utils.pagination import make_pagination
 
 
@@ -31,3 +35,40 @@ def warnings(request, user, page=0):
                                   'items': queryset.order_by('-id')[pagination['start']:pagination['stop']],
                                   'items': queryset.order_by('-id')[pagination['start']:pagination['stop']],
                                   'pagination': pagination,
                                   'pagination': pagination,
                                   }));
                                   }));
+
+def warning_decorator(f):
+    def decorator(*args, **kwargs):
+        request, user = args
+        request.acl.warnings.allow_member_warns_view(request.user, user)
+        warning_pk = kwargs['warning']
+        try:
+            warning = user.warning_set.get(pk=warning_pk)
+            return f(request, user, warning)
+        except Warn.DoesNotExist:
+            return error404(request, _("Requested warning could not be found."))
+    return decorator
+
+
+def todo_decorator(f):
+    def decorator(*args, **kwargs):
+        raise NotImplementedError("TODO: add decrease_warning_level function to user model, then do magic for cancel/delete warning")
+
+
+@check_csrf
+@profile_view('user_warnings_cancel')
+@warning_decorator
+@todo_decorator
+def cancel_warning(request, user, warning):
+    request.acl.warnings.allow_cancel_warning(
+        request.user, user, warning)
+
+
+@check_csrf
+@profile_view('user_warnings_delete')
+@warning_decorator
+@todo_decorator
+def delete_warning(request, user, warning):
+    request.acl.warnings.allow_delete_warning()
+
+    if user.is_warning_active(warning):
+        pass

+ 7 - 7
misago/apps/profiles/warnings/warningstracker.py

@@ -3,13 +3,6 @@ class WarningsTracker(object):
         self.warning_level = warning_level
         self.warning_level = warning_level
         self._checked = {}
         self._checked = {}
 
 
-    def is_warning_active(self, warning):
-        try:
-            return self._checked[warning.pk]
-        except KeyError:
-            self._checked[warning.pk] = self.check_warning(warning)
-            return self._checked[warning.pk]
-
     def check_warning(self, warning):
     def check_warning(self, warning):
         if self.warning_level > 0 and not warning.canceled:
         if self.warning_level > 0 and not warning.canceled:
             self.warning_level -= 1
             self.warning_level -= 1
@@ -17,5 +10,12 @@ class WarningsTracker(object):
         else:
         else:
             return False
             return False
 
 
+    def is_warning_active(self, warning):
+        try:
+            return self._checked[warning.pk]
+        except KeyError:
+            self._checked[warning.pk] = self.check_warning(warning)
+            return self._checked[warning.pk]
+
     def is_warning_expired(self, warning):
     def is_warning_expired(self, warning):
         return not self.is_warning_active(warning)
         return not self.is_warning_active(warning)

+ 11 - 0
misago/models/usermodel.py

@@ -13,6 +13,7 @@ from django.template import RequestContext
 from django.utils import timezone as tz_util
 from django.utils import timezone as tz_util
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from misago.acl.builder import acl
 from misago.acl.builder import acl
+from misago.apps.profiles.warnings.warningstracker import WarningsTracker
 from misago.conf import settings
 from misago.conf import settings
 from misago.monitor import monitor, UpdatingMonitor
 from misago.monitor import monitor, UpdatingMonitor
 from misago.signals import delete_user_content, rename_user, sync_user_profile
 from misago.signals import delete_user_content, rename_user, sync_user_profile
@@ -578,6 +579,16 @@ class User(models.Model):
 
 
         return self.get_warning_level()
         return self.get_warning_level()
 
 
+    def is_warning_active(self, warning):
+        warning_level = self.get_warning_level()
+        warnings_tracker = WarningsTracker(warning_level)
+
+        for db_warning in self.warning_set.order_by('-pk').iterator():
+            if warnings_tracker.is_warning_active(db_warning):
+                if warning.pk == db_warning.pk:
+                    return True
+        return False
+
     def timeline(self, qs, length=100):
     def timeline(self, qs, length=100):
         posts = {}
         posts = {}
         now = tz_util.now()
         now = tz_util.now()

+ 2 - 2
static/cranefly/css/cranefly.css

@@ -993,8 +993,8 @@ a.btn-link:hover,a.btn-link:active,a.btn-link:focus{color:#333;text-decoration:n
 .user-profile .content-list.user-warnings .media .warning-icon .warning-canceled{margin-bottom:0;position:relative;bottom:5px;color:#999;font-size:43.75px}
 .user-profile .content-list.user-warnings .media .warning-icon .warning-canceled{margin-bottom:0;position:relative;bottom:5px;color:#999;font-size:43.75px}
 .user-profile .content-list.user-warnings .media .media-body .warning-reason>:first-child{margin-top:0;padding-top:0}
 .user-profile .content-list.user-warnings .media .media-body .warning-reason>:first-child{margin-top:0;padding-top:0}
 .user-profile .content-list.user-warnings .media .media-body .warning-reason>:last-child{margin-bottom:0;padding-bottom:0}
 .user-profile .content-list.user-warnings .media .media-body .warning-reason>:last-child{margin-bottom:0;padding-bottom:0}
-.user-profile .content-list.user-warnings .media .media-footer{overflow:auto}.user-profile .content-list.user-warnings .media .media-footer form,.user-profile .content-list.user-warnings .media .media-footer p{float:left;margin:0}
-.user-profile .content-list.user-warnings .media .media-footer form{padding:0;margin-top:-3px;margin-right:14px}
+.user-profile .content-list.user-warnings .media .media-footer form,.user-profile .content-list.user-warnings .media .media-footer p{float:left;margin:0}
+.user-profile .content-list.user-warnings .media .media-footer form{padding:0;margin-right:14px}
 .forum-subforums-list{background-color:#fff;border:1px solid #d5d5d5;border-radius:2px;-webkit-box-shadow:0 0 0 3px #eee;-moz-box-shadow:0 0 0 3px #eee;box-shadow:0 0 0 3px #eee;margin-bottom:20px}.forum-subforums-list .header{background-color:#fbfbfb;border:1px solid #d5d5d5;border-radius:2px 2px 0 0;margin:-1px;margin-bottom:0;padding:3.966666666666667px 9.9px}.forum-subforums-list .header h2{margin:0;padding:0;color:#333;font-size:11.9px;font-weight:bold;line-height:20px;text-align:left}.forum-subforums-list .header h2 small{margin-left:7px;color:#999;font-size:11.9px}
 .forum-subforums-list{background-color:#fff;border:1px solid #d5d5d5;border-radius:2px;-webkit-box-shadow:0 0 0 3px #eee;-moz-box-shadow:0 0 0 3px #eee;box-shadow:0 0 0 3px #eee;margin-bottom:20px}.forum-subforums-list .header{background-color:#fbfbfb;border:1px solid #d5d5d5;border-radius:2px 2px 0 0;margin:-1px;margin-bottom:0;padding:3.966666666666667px 9.9px}.forum-subforums-list .header h2{margin:0;padding:0;color:#333;font-size:11.9px;font-weight:bold;line-height:20px;text-align:left}.forum-subforums-list .header h2 small{margin-left:7px;color:#999;font-size:11.9px}
 .forum-subforums-list .forum{border-bottom:1px solid #d5d5d5;height:21px;overflow:visible;padding:14.75px 9.9px}.forum-subforums-list .forum.last{border-bottom:none}
 .forum-subforums-list .forum{border-bottom:1px solid #d5d5d5;height:21px;overflow:visible;padding:14.75px 9.9px}.forum-subforums-list .forum.last{border-bottom:none}
 .forum-subforums-list .forum .forum-icon{float:left;position:relative;bottom:1px;width:36px;color:#d5d5d5;font-size:24px;text-align:center}.forum-subforums-list .forum .forum-icon.forum-icon-new{color:#cf402e}
 .forum-subforums-list .forum .forum-icon{float:left;position:relative;bottom:1px;width:36px;color:#d5d5d5;font-size:24px;text-align:center}.forum-subforums-list .forum .forum-icon.forum-icon-new{color:#cf402e}

+ 9 - 12
static/cranefly/css/cranefly/profiles.less

@@ -264,18 +264,15 @@
         }
         }
 
 
         .media-footer {
         .media-footer {
-        	overflow: auto;
-
-        	form, p {
-        		float: left;
-        		margin: 0px;
-        	}
-
-        	form {
-        		padding: 0px;
-        		margin-top: -3px;
-        		margin-right: @baseFontSize;
-        	}
+          form, p {
+            float: left;
+            margin: 0px;
+          }
+
+          form {
+            padding: 0px;
+            margin-right: @baseFontSize;
+          }
         }
         }
       }
       }
     }
     }

+ 7 - 5
templates/cranefly/profiles/warnings.html

@@ -60,14 +60,16 @@
         {% endif %}
         {% endif %}
       </div>
       </div>
       <div class="media-footer">
       <div class="media-footer">
-        {% if acl.warnings.can_cancel_warning(user, item) and not warnings_tracker.is_warning_expired(item) %}
-        <form>
-          <button type="submit" class="btn btn-small"><i class="icon-ban"></i> {% trans %}Cancel{% endtrans %}</button>
+        {% if acl.warnings.can_cancel_warning(user, profile, item) and not warnings_tracker.is_warning_expired(item) %}
+        <form action="{{ url('user_warnings_cancel', user=profile.pk, username=profile.username_slug, warning=item.pk) }}" method="post">
+          <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+          <button type="submit" class="btn btn-mini"><i class="icon-ban"></i> {% trans %}Cancel{% endtrans %}</button>
         </form>
         </form>
         {% endif %}
         {% endif %}
         {% if acl.warnings.can_delete_warnings() %}
         {% if acl.warnings.can_delete_warnings() %}
-        <form>
-          <button type="submit" class="btn btn-small"><i class="icon-remove"></i> {% trans %}Delete{% endtrans %}</button>
+        <form action="{{ url('user_warnings_delete', user=profile.pk, username=profile.username_slug, warning=item.pk) }}" method="post">
+          <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+          <button type="submit" class="btn btn-mini"><i class="icon-remove"></i> {% trans %}Delete{% endtrans %}</button>
         </form>
         </form>
         {% endif %}
         {% endif %}
         <p>
         <p>