From 233ff83d19f75a08acb78b292787f117821650d8 Mon Sep 17 00:00:00 2001 From: Stanislav Panasik Date: Wed, 16 Jun 2010 00:27:26 +0600 Subject: [PATCH 01/18] Added optional register parameter 'moderator_list'. If this is a function, it will be called with a model instance as a parameter to get moderator list instead of hardcoded settings MODERATOR_LIST --- gatekeeper/__init__.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gatekeeper/__init__.py b/gatekeeper/__init__.py index 48b952c..3ba8dd4 100644 --- a/gatekeeper/__init__.py +++ b/gatekeeper/__init__.py @@ -59,7 +59,7 @@ def _default_long_desc(obj): def register(model, import_unmoderated=False, auto_moderator=None, long_desc=None, manager_name='objects', status_name='moderation_status', flagged_name='flagged', moderation_object_name='moderation_object', - base_manager=None): + base_manager=None,moderator_list=None): if not model in registered_models: signals.post_save.connect(save_handler, sender=model) signals.pre_delete.connect(delete_handler, sender=model) @@ -69,6 +69,7 @@ def register(model, import_unmoderated=False, auto_moderator=None, long_desc=Non registered_models[model] = { 'auto_moderator': auto_moderator, 'long_desc': long_desc or _default_long_desc, + 'moderator_list': moderator_list, } if import_unmoderated: try: @@ -203,7 +204,13 @@ def save_handler(sender, instance, **kwargs): if user and user.has_perm('gatekeeper.change_moderatedobject'): mo.approve(user) + moderator_list = None if MODERATOR_LIST: + moderator_list = MODERATOR_LIST + if callable(registered_models[instance.__class__]['moderator_list']): + moderator_list = registered_models[instance.__class__]['moderator_list'](instance) + + if moderator_list: from django.contrib.sites.models import Site domain = Site.objects.get(id=settings.SITE_ID).domain @@ -226,7 +233,7 @@ def save_handler(sender, instance, **kwargs): # sender from_addr = settings.DEFAULT_FROM_EMAIL - send_mail(subject, message, from_addr, MODERATOR_LIST, fail_silently=True) + send_mail(subject, message, from_addr, moderator_list, fail_silently=True) def delete_handler(sender, instance, **kwargs): try: From 934d6124e119bf0899bbe6880d0301666919a0ef Mon Sep 17 00:00:00 2001 From: Stanislav Panasik Date: Thu, 17 Jun 2010 18:04:58 +0600 Subject: [PATCH 02/18] Added callback function to get model ready-to-notify-moderators status. Sometimes model should be saved several times before notify moderators about event. Also, notification code now executed each time model is saved, not only after creation. This way moderators will see also edit events. --- gatekeeper/__init__.py | 57 ++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/gatekeeper/__init__.py b/gatekeeper/__init__.py index 3ba8dd4..177edcb 100644 --- a/gatekeeper/__init__.py +++ b/gatekeeper/__init__.py @@ -59,7 +59,7 @@ def _default_long_desc(obj): def register(model, import_unmoderated=False, auto_moderator=None, long_desc=None, manager_name='objects', status_name='moderation_status', flagged_name='flagged', moderation_object_name='moderation_object', - base_manager=None,moderator_list=None): + base_manager=None,moderator_list=None,notify_moderators=None): if not model in registered_models: signals.post_save.connect(save_handler, sender=model) signals.pre_delete.connect(delete_handler, sender=model) @@ -70,6 +70,7 @@ def register(model, import_unmoderated=False, auto_moderator=None, long_desc=Non 'auto_moderator': auto_moderator, 'long_desc': long_desc or _default_long_desc, 'moderator_list': moderator_list, + 'notify_moderators': notify_moderators, } if import_unmoderated: try: @@ -203,37 +204,45 @@ def save_handler(sender, instance, **kwargs): user = get_current_user() if user and user.has_perm('gatekeeper.change_moderatedobject'): mo.approve(user) + else: + mo = ModeratedObject.objects.get(object_id=instance.id, + content_type=ContentType.objects.get_for_model(instance)) - moderator_list = None - if MODERATOR_LIST: - moderator_list = MODERATOR_LIST - if callable(registered_models[instance.__class__]['moderator_list']): - moderator_list = registered_models[instance.__class__]['moderator_list'](instance) + + if callable(registered_models[instance.__class__]['notify_moderators']): + if not registered_models[instance.__class__]['notify_moderators'](instance): + return - if moderator_list: + moderator_list = None + if MODERATOR_LIST: + moderator_list = MODERATOR_LIST + if callable(registered_models[instance.__class__]['moderator_list']): + moderator_list = registered_models[instance.__class__]['moderator_list'](instance) + + if moderator_list: - from django.contrib.sites.models import Site - domain = Site.objects.get(id=settings.SITE_ID).domain + from django.contrib.sites.models import Site + domain = Site.objects.get(id=settings.SITE_ID).domain - status = mo.get_moderation_status_display() - instance_class = instance.__class__.__name__ - long_desc = registered_models[instance.__class__]['long_desc'] + status = mo.get_moderation_status_display() + instance_class = instance.__class__.__name__ + long_desc = registered_models[instance.__class__]['long_desc'] - # message - message = _long_desc(instance, long_desc) - if status == 'Pending': - message += "\n\nTo moderate, go to http://%s/admin/gatekeeper/moderatedobject/?ot=desc&o=2" % (message, domain) + # message + message = _long_desc(instance, long_desc) + if status == 'Pending': + message += "\n\nTo moderate, go to http://%s/admin/gatekeeper/moderatedobject/?ot=desc&o=2" % domain - # subject - key = "%s:%s" % (instance_class, status) - if mo.moderation_status_by and mo.moderation_status_by.username == 'gatekeeper_automod': - key = "%s:auto" % key - subject = "[%s] New gatekeeper object on %s" % (key, domain) + # subject + key = "%s:%s" % (instance_class, status) + if mo.moderation_status_by and mo.moderation_status_by.username == 'gatekeeper_automod': + key = "%s:auto" % key + subject = "[%s] New gatekeeper object on %s" % (key, domain) - # sender - from_addr = settings.DEFAULT_FROM_EMAIL + # sender + from_addr = settings.DEFAULT_FROM_EMAIL - send_mail(subject, message, from_addr, moderator_list, fail_silently=True) + send_mail(subject, message, from_addr, moderator_list, fail_silently=True) def delete_handler(sender, instance, **kwargs): try: From ed02184f3401c485f33ea357662ca7b113e7ff3a Mon Sep 17 00:00:00 2001 From: Stanislav Panasik Date: Thu, 17 Jun 2010 19:06:36 +0600 Subject: [PATCH 03/18] Fixed notification URL to filter only Pending objects --- gatekeeper/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gatekeeper/__init__.py b/gatekeeper/__init__.py index 177edcb..e3cf2ad 100644 --- a/gatekeeper/__init__.py +++ b/gatekeeper/__init__.py @@ -231,7 +231,7 @@ def save_handler(sender, instance, **kwargs): # message message = _long_desc(instance, long_desc) if status == 'Pending': - message += "\n\nTo moderate, go to http://%s/admin/gatekeeper/moderatedobject/?ot=desc&o=2" % domain + message += "\n\nTo moderate, go to http://%s/admin/gatekeeper/moderatedobject/?ot=desc&moderation_status__exact=0&o=2" % domain # subject key = "%s:%s" % (instance_class, status) From 153a05cf2cc1007590d475d2d12c9dc4b8cfbda4 Mon Sep 17 00:00:00 2001 From: Stanislav Panasik Date: Thu, 17 Jun 2010 22:35:40 +0600 Subject: [PATCH 04/18] If instance have get_absolute_url it will be used to put view link in the notification message --- gatekeeper/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gatekeeper/__init__.py b/gatekeeper/__init__.py index e3cf2ad..f8c3a68 100644 --- a/gatekeeper/__init__.py +++ b/gatekeeper/__init__.py @@ -231,8 +231,10 @@ def save_handler(sender, instance, **kwargs): # message message = _long_desc(instance, long_desc) if status == 'Pending': + if callable(getattr(instance, 'get_absolute_url', None)): + message += "\n\nTo view, go to http://%s%s" % (domain, instance.get_absolute_url()) message += "\n\nTo moderate, go to http://%s/admin/gatekeeper/moderatedobject/?ot=desc&moderation_status__exact=0&o=2" % domain - + # subject key = "%s:%s" % (instance_class, status) if mo.moderation_status_by and mo.moderation_status_by.username == 'gatekeeper_automod': From fdfdd042b41b35c328c0a339dfcb3f830c53352b Mon Sep 17 00:00:00 2001 From: Alex Kamedov Date: Fri, 27 Aug 2010 15:46:26 +0600 Subject: [PATCH 05/18] add not_rejected method to GatekeeperQuerySet for getting approved and unmoderated objects --- README.rst | 3 ++- gatekeeper/__init__.py | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 59b48ce..fe66c96 100644 --- a/README.rst +++ b/README.rst @@ -76,7 +76,8 @@ The custom manager returns a special GatekeeperQuerySet with a few extra filters >>> MyModel.objects.all().approved() # approved by moderator >>> MyModel.objects.all().pending() # pending in moderation queue >>> MyModel.objects.all().rejected() # rejected by moderator - >>> MyModel.objects.all().flagged() # flagged + >>> MyModel.objects.all().not_rejected() # approved by moderator and pending in moderation queue + >>> MyModel.objects.all().flagged() # flagged >>> MyModel.objects.all().not_flagged() # not flagged These are implemented on the `GatekeeperQuerySet` itself so that they can be chained: diff --git a/gatekeeper/__init__.py b/gatekeeper/__init__.py index f8c3a68..303d7bd 100644 --- a/gatekeeper/__init__.py +++ b/gatekeeper/__init__.py @@ -121,6 +121,10 @@ def pending(self): def rejected(self): return self._by_status(status_name, REJECTED_STATUS) + def not_rejected(self): + where_clause = '%s != %%s' % (status_name) + return self.extra(where=[where_clause], params=[REJECTED_STATUS]) + def flagged(self): return self._by_status(flagged_name, True) From 3cc4a168ce2c1644bc6400ab7ca0a269f77c9c14 Mon Sep 17 00:00:00 2001 From: Alex Kamedov Date: Fri, 27 Aug 2010 15:55:06 +0600 Subject: [PATCH 06/18] Add ModerationMixin for moderated models. It adds is_approved, is_rejected and is_pending methods for moderated objects witch is useful in templates. --- gatekeeper/models.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/gatekeeper/models.py b/gatekeeper/models.py index dd51e39..b7e54b5 100644 --- a/gatekeeper/models.py +++ b/gatekeeper/models.py @@ -80,3 +80,17 @@ def approve(self, user, reason=''): def reject(self, user, reason=''): self._moderate(-1, user, reason) + + +class ModerationMixin(object): + """ + Chek object moderation status + """ + def is_approved(self): + return self.moderation_status == gatekeeper.APPROVED_STATUS + + def is_rejected(self): + return self.moderation_status == gatekeeper.REJECTED_STATUS + + def is_pending(self): + return self.moderation_status == gatekeeper.PENDING_STATUS From dda8c461f259e9ecae7eba1ec308bd374b1d9d91 Mon Sep 17 00:00:00 2001 From: Alex Kamedov Date: Wed, 15 Sep 2010 23:40:07 +0600 Subject: [PATCH 07/18] add link to object change form in admin to object moderation list --- gatekeeper/admin.py | 3 ++- gatekeeper/models.py | 26 +++++++++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/gatekeeper/admin.py b/gatekeeper/admin.py index 6666d79..1732962 100644 --- a/gatekeeper/admin.py +++ b/gatekeeper/admin.py @@ -2,7 +2,8 @@ from gatekeeper.models import ModeratedObject class ModeratedObjectAdmin(admin.ModelAdmin): - list_display = ('object_name', 'timestamp', 'moderation_status', 'flagged') + list_display = ('object_name', 'timestamp', 'moderation_status', \ + 'flagged', 'object_change_admin_link') list_editable = ('moderation_status','flagged') list_filter = ['moderation_status','flagged','content_type'] diff --git a/gatekeeper/models.py b/gatekeeper/models.py index b7e54b5..8641887 100644 --- a/gatekeeper/models.py +++ b/gatekeeper/models.py @@ -1,8 +1,9 @@ from django.conf import settings -from django.db import models from django.contrib.auth.models import User -from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes import generic +from django.contrib.contenttypes.models import ContentType +from django.db import models +from django.utils.translation import ugettext as _ import datetime import gatekeeper @@ -48,7 +49,7 @@ class Meta: ordering = ['timestamp'] def __unicode__(self): - return "[%s] %s" % (self.get_moderation_status_display(), + return "[%s] %s" % (self.get_moderation_status_display(), self.content_object) def get_absolute_url(self): @@ -81,6 +82,21 @@ def approve(self, user, reason=''): def reject(self, user, reason=''): self._moderate(-1, user, reason) + @models.permalink + def object_change_admin_url(self): + return ('admin:%s_%s_change' % (self.content_type.app_label, + self.content_type.model), + [self.object_id, ]) + + def object_change_admin_link(self): + try: + return u'%s' % \ + (self.object_change_admin_url(), _('View')) + except: + return self.get_absolute_url() + object_change_admin_link.allow_tags = True + object_change_admin_link.short_description = _('link') + class ModerationMixin(object): """ @@ -88,9 +104,9 @@ class ModerationMixin(object): """ def is_approved(self): return self.moderation_status == gatekeeper.APPROVED_STATUS - + def is_rejected(self): return self.moderation_status == gatekeeper.REJECTED_STATUS - + def is_pending(self): return self.moderation_status == gatekeeper.PENDING_STATUS From 1c6e3d9207e05d31636504e55af5e3a3498ef88f Mon Sep 17 00:00:00 2001 From: Alex Kamedov Date: Wed, 15 Sep 2010 23:55:53 +0600 Subject: [PATCH 08/18] add i18n support --- gatekeeper/models.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/gatekeeper/models.py b/gatekeeper/models.py index 8641887..05e6ed1 100644 --- a/gatekeeper/models.py +++ b/gatekeeper/models.py @@ -3,14 +3,14 @@ from django.contrib.contenttypes import generic from django.contrib.contenttypes.models import ContentType from django.db import models -from django.utils.translation import ugettext as _ +from django.utils.translation import ugettext_lazy as _ import datetime import gatekeeper STATUS_CHOICES = ( - (1, "Approved"), - (0, "Pending"), - (-1, "Rejected"), + (1, _("Approved")), + (0, _("Pending")), + (-1, _("Rejected")), ) STATUS_ON_FLAG = getattr(settings, "GATEKEEPER_STATUS_ON_FLAG", None) @@ -31,18 +31,25 @@ class ModeratedObject(models.Model): timestamp = models.DateTimeField(auto_now_add=True, blank=True, null=True) - moderation_status = models.IntegerField(choices=STATUS_CHOICES) - moderation_status_by = models.ForeignKey(User, blank=True, null=True) - moderation_status_date = models.DateTimeField(blank=True, null=True) - moderation_reason = models.CharField(max_length=100, blank=True) + moderation_status = models.IntegerField(choices=STATUS_CHOICES, + verbose_name=_('moderation status')) + moderation_status_by = models.ForeignKey(User, blank=True, null=True, + verbose_name=_('moderation status by')) + moderation_status_date = models.DateTimeField(blank=True, null=True, + verbose_name=_('moderation status date')) + moderation_reason = models.CharField(max_length=100, blank=True, + verbose_name=_('moderation reason')) - flagged = models.BooleanField(default=False) + flagged = models.BooleanField(default=False, verbose_name=_('flagged')) flagged_by = models.ForeignKey(User, blank=True, null=True, - related_name='flagged_objects') - flagged_date = models.DateTimeField(blank=True, null=True) - - content_type = models.ForeignKey(ContentType) - object_id = models.PositiveIntegerField() + related_name='flagged objects', + verbose_name=_('flagged by')) + flagged_date = models.DateTimeField(blank=True, null=True, + verbose_name=_('flagged date')) + + content_type = models.ForeignKey(ContentType, + verbose_name=_('content type')) + object_id = models.PositiveIntegerField(verbose_name=_('object id')) content_object = generic.GenericForeignKey('content_type', 'object_id') class Meta: From e06331887d3467acd86c2089d2d78523428c6b72 Mon Sep 17 00:00:00 2001 From: Alex Kamedov Date: Wed, 15 Sep 2010 23:56:11 +0600 Subject: [PATCH 09/18] add Russian translation --- gatekeeper/locale/ru/LC_MESSAGES/django.mo | Bin 0 -> 1396 bytes gatekeeper/locale/ru/LC_MESSAGES/django.po | 79 +++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 gatekeeper/locale/ru/LC_MESSAGES/django.mo create mode 100644 gatekeeper/locale/ru/LC_MESSAGES/django.po diff --git a/gatekeeper/locale/ru/LC_MESSAGES/django.mo b/gatekeeper/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..03f6e5695999cda631fee61b577dd3a142c57cb2 GIT binary patch literal 1396 zcmZ{i+iwg}9LJA4<6go8;)u93a@I^+w`mtu)s!twt;XwV_jC=@na#{>wTTB^LV}PG zi3cH`ye?Wcy*_$$Ch_8hKY;&0B)-4dtv10)&VJ7CcYc@e@63L!Tl$n?ZNT1+{TzEM zofqK;YZzP!j({t`Qq8^xE`|LBTn9b_*MP4tBaH{722vYoKa3lDo#_!-}*uTIn zVBKQIR)O{4C-@pc(zXQ2o50Or9k?GPe>1on%z!(GAz7`3 zLf{Xn9P3tI&hhfBM_pC@5gfgay3YE2FH&B_{XX*kF{6=!Vgs(s=Mh*V?;H7Z%*jYG z*YU2gK|iMg89Bbk10_S>Tj&WR85P67JydEzVl|8>MXN%%1Hpk$nnY(#^r|342b*`d zww-J3Xy?7{Jr_GKoHu$@!4D$Q73Q6sI91GtBJ11S=)RB@ZIDB<#A#@?d4p-0!aOFd zL%gBUZaQ+nJZzc>6g_Ilq2m9HJJeK-%g8Vi*+6=sD)6#R8jg;_KY|>A4jSNR3O^DexJUu&5!muk2fg5r{%(37~Bo(p>kV*(K$bU7}?4_H#<9&RV%5|2k=j_Gk!rAkw<-k~, 2010. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-09-15 23:47+0600\n" +"PO-Revision-Date: 2010-09-15 23:54+0600\n" +"Last-Translator: Volf \n" +"Language-Team: LANGUAGE \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%" +"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Virtaal 0.6.1\n" + +#: models.py:11 +msgid "Approved" +msgstr "Одобрено" + +#: models.py:12 +msgid "Pending" +msgstr "В ожидании" + +#: models.py:13 +msgid "Rejected" +msgstr "Отклонено" + +#: models.py:35 +msgid "moderation status" +msgstr "состояние" + +#: models.py:37 +msgid "moderation status by" +msgstr "статус установил" + +#: models.py:39 +msgid "moderation status date" +msgstr "дата модерации" + +#: models.py:41 +msgid "moderation reason" +msgstr "причина" + +#: models.py:43 +msgid "flagged" +msgstr "отмечено" + +#: models.py:46 +msgid "flagged by" +msgstr "отметил пользователь" + +#: models.py:48 +msgid "flagged date" +msgstr "дата отметки" + +#: models.py:51 +msgid "content type" +msgstr "тип содержимого" + +#: models.py:52 +msgid "object id" +msgstr "Идентификатор объекта" + +#: models.py:54 +msgid "content object" +msgstr "объект содержимого" + +#: models.py:102 +msgid "View" +msgstr "Показать" + +#: models.py:106 +msgid "link" +msgstr "Ссылка" From 76c03c2009d3ab7e3994930f50b1de3e5adbbd88 Mon Sep 17 00:00:00 2001 From: Alex Kamedov Date: Sat, 5 Feb 2011 00:30:24 +0500 Subject: [PATCH 10/18] store info about user and user ip --- gatekeeper/__init__.py | 28 +++--- gatekeeper/locale/ru/LC_MESSAGES/django.mo | Bin 1396 -> 1667 bytes gatekeeper/locale/ru/LC_MESSAGES/django.po | 51 ++++++---- gatekeeper/middleware.py | 6 +- gatekeeper/migrations/0001_initial.py | 87 ++++++++++++++++++ ..._created_ip__add_field_moderatedobject_.py | 82 +++++++++++++++++ gatekeeper/migrations/__init__.py | 0 gatekeeper/models.py | 14 ++- 8 files changed, 233 insertions(+), 35 deletions(-) create mode 100644 gatekeeper/migrations/0001_initial.py create mode 100644 gatekeeper/migrations/0002_add_field_moderatedobject_created_ip__add_field_moderatedobject_.py create mode 100644 gatekeeper/migrations/__init__.py diff --git a/gatekeeper/__init__.py b/gatekeeper/__init__.py index 303d7bd..8e7972b 100644 --- a/gatekeeper/__init__.py +++ b/gatekeeper/__init__.py @@ -10,12 +10,12 @@ from django.core.urlresolvers import reverse from django.db.models import Manager, signals from django.dispatch import Signal -from gatekeeper.middleware import get_current_user +from gatekeeper.middleware import get_current_user, get_current_user_ip from gatekeeper.models import ModeratedObject import datetime REJECTED_STATUS = -1 -PENDING_STATUS = 0 +PENDING_STATUS = 0 APPROVED_STATUS = 1 ENABLE_AUTOMODERATION = getattr(settings, "GATEKEEPER_ENABLE_AUTOMODERATION", False) @@ -59,12 +59,12 @@ def _default_long_desc(obj): def register(model, import_unmoderated=False, auto_moderator=None, long_desc=None, manager_name='objects', status_name='moderation_status', flagged_name='flagged', moderation_object_name='moderation_object', - base_manager=None,moderator_list=None,notify_moderators=None): + base_manager=None, moderator_list=None, notify_moderators=None): if not model in registered_models: signals.post_save.connect(save_handler, sender=model) signals.pre_delete.connect(delete_handler, sender=model) # pass extra params onto add_fields to define what fields are named - add_fields(model, manager_name, status_name, flagged_name, + add_fields(model, manager_name, status_name, flagged_name, moderation_object_name, base_manager) registered_models[model] = { 'auto_moderator': auto_moderator, @@ -152,9 +152,9 @@ def get_query_set(self): '_moderation_status':'%s.moderation_status' % GATEKEEPER_TABLE, '_flagged':'%s.flagged' % GATEKEEPER_TABLE} where = ['%s.content_type_id=%s' % (GATEKEEPER_TABLE, content_type), - '%s.object_id=%s.%s' % (GATEKEEPER_TABLE, db_table, + '%s.object_id=%s.%s' % (GATEKEEPER_TABLE, db_table, pk_name)] - tables=[GATEKEEPER_TABLE] + tables = [GATEKEEPER_TABLE] # build extra query then copy model/query to a GatekeeperQuerySet q = super(GatekeeperManager, self).get_query_set().extra( @@ -185,11 +185,14 @@ def _get_moderation_object(self): def save_handler(sender, instance, **kwargs): if kwargs.get('created', None): + user = get_current_user() mo = ModeratedObject( moderation_status=DEFAULT_STATUS, content_object=instance, - timestamp=datetime.datetime.now()) + timestamp=datetime.datetime.now(), + created_by=user if user and not user.is_anonymous() else None, + created_ip=get_current_user_ip()) mo.save() # do automoderation @@ -205,24 +208,23 @@ def save_handler(sender, instance, **kwargs): # do old-style automoderation if automoderator did nothing if ENABLE_AUTOMODERATION and mo.moderation_status == PENDING_STATUS: - user = get_current_user() if user and user.has_perm('gatekeeper.change_moderatedobject'): mo.approve(user) else: - mo = ModeratedObject.objects.get(object_id=instance.id, + mo = ModeratedObject.objects.get(object_id=instance.id, content_type=ContentType.objects.get_for_model(instance)) if callable(registered_models[instance.__class__]['notify_moderators']): if not registered_models[instance.__class__]['notify_moderators'](instance): return - + moderator_list = None if MODERATOR_LIST: moderator_list = MODERATOR_LIST if callable(registered_models[instance.__class__]['moderator_list']): - moderator_list = registered_models[instance.__class__]['moderator_list'](instance) - + moderator_list = registered_models[instance.__class__]['moderator_list'](instance) + if moderator_list: from django.contrib.sites.models import Site @@ -238,7 +240,7 @@ def save_handler(sender, instance, **kwargs): if callable(getattr(instance, 'get_absolute_url', None)): message += "\n\nTo view, go to http://%s%s" % (domain, instance.get_absolute_url()) message += "\n\nTo moderate, go to http://%s/admin/gatekeeper/moderatedobject/?ot=desc&moderation_status__exact=0&o=2" % domain - + # subject key = "%s:%s" % (instance_class, status) if mo.moderation_status_by and mo.moderation_status_by.username == 'gatekeeper_automod': diff --git a/gatekeeper/locale/ru/LC_MESSAGES/django.mo b/gatekeeper/locale/ru/LC_MESSAGES/django.mo index 03f6e5695999cda631fee61b577dd3a142c57cb2..d54d2a6ba08018d682545ce0397626d0ef406bdc 100644 GIT binary patch delta 739 zcmZwDziU%b6u|M5_*ymEHnw658v8mF6)n67MG+jNB6KKZ=^(g7^9VvQA&o+&*QhuM z8u2N(C^)$JqtZr0N%JS@xr>8?tKi@uLI)SW=Ou0)xbJg+o%_zczcY76qHp8gQy~u0 zj?lWa9PLVq523gR9gg8w+>Jlb!(W)eoxyxM-QS- zP{0GYJg|&bTmui`L)?q6@H0PshgrrE$%pX~&fsf2j-PNAcW?r8Ln7mt$E-vm7wOoI zm+=IyCJQ3Z@fhQ`IEi1-Zt@dH@ekTTnPHJ>%%K%<9_^gVNPWqz=_X+pv#>%evix60 zX!f-B%ocXI-H`K>r`m_RX#c`q!@`QOup+pe@DTmDP_5P~x5APv)WTvtEcrKA! H1MmA^H?FE# delta 497 zcmZY5zfZzI6u|N0NBx0-Sct|5fy6|Jadb9- zF^1sC=rwV1(a}LiH)G=Wu$wP={oK9YweRjc@)fdQ_28u-Vq}tRl2dBz<3XI_2v%_z z>)yP9LFNud@e0FugKAwHL)i7|eN^k8aROidw8aO51ce`*MBOjMC}#1AS^-sa0d~hR zfjZ8ks_)<|?qdo~uYQ4Z%&$=$sE?|_H&hLOqAqM9z8Rz`L^UC1a1pb(hy4FvsLf+u zRW(X~gOl=^L8#kes~9H(WP}_d)vc(8RTG2QHO-S?xndkSK7Tr1K0G#xmME4>mQk`Y zR@F3|CBGZX=ki;*<+aR8VS9CBA-~>=1!_JgrEP{~Pu{u>*^v)!-8s;vlXZD7A2aS5 UFWR!>*5n<9F0+>GIZf^T7hkAMT>t<8 diff --git a/gatekeeper/locale/ru/LC_MESSAGES/django.po b/gatekeeper/locale/ru/LC_MESSAGES/django.po index fcc8dfe..fccebe1 100644 --- a/gatekeeper/locale/ru/LC_MESSAGES/django.po +++ b/gatekeeper/locale/ru/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-09-15 23:47+0600\n" +"POT-Creation-Date: 2011-02-05 00:17+0500\n" "PO-Revision-Date: 2010-09-15 23:54+0600\n" "Last-Translator: Volf \n" "Language-Team: LANGUAGE \n" @@ -14,10 +14,22 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%" -"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Virtaal 0.6.1\n" +#: admin.py:16 +msgid "Moderation" +msgstr "Состояние модерации" + +#: admin.py:19 +msgid "Flagged" +msgstr "Отметки модерации" + +#: admin.py:22 +msgid "Meta" +msgstr "Информация об объекте" + #: models.py:11 msgid "Approved" msgstr "Одобрено" @@ -30,50 +42,55 @@ msgstr "В ожидании" msgid "Rejected" msgstr "Отклонено" -#: models.py:35 +#: models.py:36 msgid "moderation status" msgstr "состояние" -#: models.py:37 +#: models.py:38 msgid "moderation status by" msgstr "статус установил" -#: models.py:39 +#: models.py:40 msgid "moderation status date" msgstr "дата модерации" -#: models.py:41 +#: models.py:42 msgid "moderation reason" msgstr "причина" -#: models.py:43 +#: models.py:44 msgid "flagged" msgstr "отмечено" -#: models.py:46 +#: models.py:47 msgid "flagged by" msgstr "отметил пользователь" -#: models.py:48 +#: models.py:49 msgid "flagged date" msgstr "дата отметки" -#: models.py:51 +#: models.py:52 msgid "content type" msgstr "тип содержимого" -#: models.py:52 +#: models.py:53 msgid "object id" msgstr "Идентификатор объекта" -#: models.py:54 -msgid "content object" -msgstr "объект содержимого" +#: models.py:56 +msgid "Created user IP" +msgstr "IP пользователя" + +#: models.py:59 +msgid "created by" +msgstr "создано пользователем" -#: models.py:102 +#: models.py:107 msgid "View" msgstr "Показать" -#: models.py:106 +#: models.py:111 msgid "link" msgstr "Ссылка" + diff --git a/gatekeeper/middleware.py b/gatekeeper/middleware.py index 5438059..c34239b 100644 --- a/gatekeeper/middleware.py +++ b/gatekeeper/middleware.py @@ -8,6 +8,10 @@ def get_current_user(): return getattr(_thread_locals, 'gatekeeper_user', None) +def get_current_user_ip(): + return getattr(_thread_locals, 'gatekeeper_user_ip', None) + class GatekeeperMiddleware(object): def process_request(self, request): - _thread_locals.gatekeeper_user = getattr(request, 'user', None) \ No newline at end of file + _thread_locals.gatekeeper_user = getattr(request, 'user', None) + _thread_locals.gatekeeper_user_ip = request.META['REMOTE_ADDR'] diff --git a/gatekeeper/migrations/0001_initial.py b/gatekeeper/migrations/0001_initial.py new file mode 100644 index 0000000..981f17d --- /dev/null +++ b/gatekeeper/migrations/0001_initial.py @@ -0,0 +1,87 @@ +# encoding: utf-8 +import 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 'ModeratedObject' + db.create_table('gatekeeper_moderatedobject', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('timestamp', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, null=True, blank=True)), + ('moderation_status', self.gf('django.db.models.fields.IntegerField')()), + ('moderation_status_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), + ('moderation_status_date', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), + ('moderation_reason', self.gf('django.db.models.fields.CharField')(max_length=100, blank=True)), + ('flagged', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('flagged_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='flagged objects', null=True, to=orm['auth.User'])), + ('flagged_date', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), + ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])), + ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()), + )) + db.send_create_signal('gatekeeper', ['ModeratedObject']) + + + def backwards(self, orm): + + # Deleting model 'ModeratedObject' + db.delete_table('gatekeeper_moderatedobject') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + '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'}), + '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'}) + }, + 'gatekeeper.moderatedobject': { + 'Meta': {'ordering': "['timestamp']", 'object_name': 'ModeratedObject'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'flagged': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'flagged_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'flagged objects'", 'null': 'True', 'to': "orm['auth.User']"}), + 'flagged_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'moderation_reason': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'moderation_status': ('django.db.models.fields.IntegerField', [], {}), + 'moderation_status_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'moderation_status_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['gatekeeper'] diff --git a/gatekeeper/migrations/0002_add_field_moderatedobject_created_ip__add_field_moderatedobject_.py b/gatekeeper/migrations/0002_add_field_moderatedobject_created_ip__add_field_moderatedobject_.py new file mode 100644 index 0000000..6e7de51 --- /dev/null +++ b/gatekeeper/migrations/0002_add_field_moderatedobject_created_ip__add_field_moderatedobject_.py @@ -0,0 +1,82 @@ +# encoding: utf-8 +import 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 'ModeratedObject.created_ip' + db.add_column('gatekeeper_moderatedobject', 'created_ip', self.gf('django.db.models.fields.IPAddressField')(max_length=15, null=True, blank=True), keep_default=False) + + # Adding field 'ModeratedObject.created_by' + db.add_column('gatekeeper_moderatedobject', 'created_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='created_moderated_objects', null=True, to=orm['auth.User']), keep_default=False) + + + def backwards(self, orm): + + # Deleting field 'ModeratedObject.created_ip' + db.delete_column('gatekeeper_moderatedobject', 'created_ip') + + # Deleting field 'ModeratedObject.created_by' + db.delete_column('gatekeeper_moderatedobject', 'created_by_id') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + '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'}), + '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'}) + }, + 'gatekeeper.moderatedobject': { + 'Meta': {'ordering': "['timestamp']", 'object_name': 'ModeratedObject'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'created_moderated_objects'", 'null': 'True', 'to': "orm['auth.User']"}), + 'created_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'flagged': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'flagged_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'flagged objects'", 'null': 'True', 'to': "orm['auth.User']"}), + 'flagged_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'moderation_reason': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'moderation_status': ('django.db.models.fields.IntegerField', [], {}), + 'moderation_status_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'moderation_status_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['gatekeeper'] diff --git a/gatekeeper/migrations/__init__.py b/gatekeeper/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gatekeeper/models.py b/gatekeeper/models.py index 05e6ed1..bff3d67 100644 --- a/gatekeeper/models.py +++ b/gatekeeper/models.py @@ -29,13 +29,14 @@ class ModeratedObject(models.Model): objects = ModeratedObjectManager() - timestamp = models.DateTimeField(auto_now_add=True, blank=True, null=True) + timestamp = models.DateTimeField(auto_now_add=True, blank=True, null=True, \ + verbose_name="created date") - moderation_status = models.IntegerField(choices=STATUS_CHOICES, + moderation_status = models.IntegerField(choices=STATUS_CHOICES, verbose_name=_('moderation status')) - moderation_status_by = models.ForeignKey(User, blank=True, null=True, + moderation_status_by = models.ForeignKey(User, blank=True, null=True, verbose_name=_('moderation status by')) - moderation_status_date = models.DateTimeField(blank=True, null=True, + moderation_status_date = models.DateTimeField(blank=True, null=True, verbose_name=_('moderation status date')) moderation_reason = models.CharField(max_length=100, blank=True, verbose_name=_('moderation reason')) @@ -52,6 +53,11 @@ class ModeratedObject(models.Model): object_id = models.PositiveIntegerField(verbose_name=_('object id')) content_object = generic.GenericForeignKey('content_type', 'object_id') + created_ip = models.IPAddressField(_('Created user IP'), blank=True, null=True) + created_by = models.ForeignKey(User, blank=True, null=True, \ + related_name="created_moderated_objects", + verbose_name=_('created by')) + class Meta: ordering = ['timestamp'] From 3585e60bd22b99f57291774ac01aa7424e66a003 Mon Sep 17 00:00:00 2001 From: Alex Kamedov Date: Sat, 5 Feb 2011 00:31:26 +0500 Subject: [PATCH 11/18] show more info in ChangeList, improve moderation object ChangeForm --- gatekeeper/admin.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/gatekeeper/admin.py b/gatekeeper/admin.py index 1732962..dc97f41 100644 --- a/gatekeeper/admin.py +++ b/gatekeeper/admin.py @@ -1,11 +1,30 @@ from django.contrib import admin from gatekeeper.models import ModeratedObject +from django.utils.translation import ugettext_lazy as _ + class ModeratedObjectAdmin(admin.ModelAdmin): - list_display = ('object_name', 'timestamp', 'moderation_status', \ + list_display = ('object_name', 'timestamp', 'created_by', 'created_ip', \ + 'moderation_status', 'moderation_status_by', \ 'flagged', 'object_change_admin_link') - list_editable = ('moderation_status','flagged') - list_filter = ['moderation_status','flagged','content_type'] + list_editable = ('moderation_status', 'flagged') + list_filter = ['moderation_status', 'flagged', 'content_type', ] + ordering = ['-timestamp', ] + raw_id_fields = ['created_by', 'flagged_by', 'moderation_status_by'] + #readonly_fields = ['created_by', 'created_ip', 'timestamp'] + radio_fields = {'moderation_status': admin.HORIZONTAL} + fieldsets = ( + (_('Moderation'), { + 'fields': ['moderation_status', 'moderation_status_by', 'moderation_status_date', 'moderation_reason'], + }), + (_('Flagged'), { + 'fields': ['flagged', 'flagged_by', 'flagged_date'], + }), + (_('Meta'), { + 'fields': [ ('content_type', 'object_id'), ('created_ip', 'created_by',)], + }) + ) + def object_name(self, obj): return "%s" % obj From 9d41735e0f9b80f09c38b711139a80101035a175 Mon Sep 17 00:00:00 2001 From: Aaron Bassett Date: Fri, 17 Jun 2011 13:16:44 +0100 Subject: [PATCH 12/18] Remove content type from admin list filter --- gatekeeper/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gatekeeper/admin.py b/gatekeeper/admin.py index 6666d79..e93309a 100644 --- a/gatekeeper/admin.py +++ b/gatekeeper/admin.py @@ -4,7 +4,7 @@ class ModeratedObjectAdmin(admin.ModelAdmin): list_display = ('object_name', 'timestamp', 'moderation_status', 'flagged') list_editable = ('moderation_status','flagged') - list_filter = ['moderation_status','flagged','content_type'] + list_filter = ['moderation_status','flagged',] def object_name(self, obj): return "%s" % obj From 5dfaf216bc6d8bcfa50945c99bad0bbed95cdc0c Mon Sep 17 00:00:00 2001 From: Aaron Bassett Date: Fri, 17 Jun 2011 13:18:45 +0100 Subject: [PATCH 13/18] Fix error with email notifications --- gatekeeper/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gatekeeper/__init__.py b/gatekeeper/__init__.py index 48b952c..6f3d4d0 100644 --- a/gatekeeper/__init__.py +++ b/gatekeeper/__init__.py @@ -215,7 +215,7 @@ def save_handler(sender, instance, **kwargs): # message message = _long_desc(instance, long_desc) if status == 'Pending': - message += "\n\nTo moderate, go to http://%s/admin/gatekeeper/moderatedobject/?ot=desc&o=2" % (message, domain) + message += "\n\nTo moderate, go to http://%s/admin/gatekeeper/moderatedobject/?ot=desc&o=2" % domain # subject key = "%s:%s" % (instance_class, status) From 6b8b9e3c76f981a6fef9f8d52ec4ec559c8becfc Mon Sep 17 00:00:00 2001 From: Aaron Bassett Date: Fri, 17 Jun 2011 13:21:52 +0100 Subject: [PATCH 14/18] Improve Email subject wording --- gatekeeper/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gatekeeper/__init__.py b/gatekeeper/__init__.py index 6f3d4d0..8c19b39 100644 --- a/gatekeeper/__init__.py +++ b/gatekeeper/__init__.py @@ -221,7 +221,7 @@ def save_handler(sender, instance, **kwargs): key = "%s:%s" % (instance_class, status) if mo.moderation_status_by and mo.moderation_status_by.username == 'gatekeeper_automod': key = "%s:auto" % key - subject = "[%s] New gatekeeper object on %s" % (key, domain) + subject = "[%s] Item requires moderation on %s" % (key, domain) # sender from_addr = settings.DEFAULT_FROM_EMAIL From 24199ccca31f57bdb5f07ff3fe977071563dfb6c Mon Sep 17 00:00:00 2001 From: Joshua Jonah Date: Tue, 23 Apr 2013 11:41:26 -0400 Subject: [PATCH 15/18] Added object information in admin. --- gatekeeper/admin.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/gatekeeper/admin.py b/gatekeeper/admin.py index e93309a..366bacf 100644 --- a/gatekeeper/admin.py +++ b/gatekeeper/admin.py @@ -1,10 +1,18 @@ from django.contrib import admin +from django.template.loader import render_to_string + from gatekeeper.models import ModeratedObject + class ModeratedObjectAdmin(admin.ModelAdmin): - list_display = ('object_name', 'timestamp', 'moderation_status', 'flagged') - list_editable = ('moderation_status','flagged') - list_filter = ['moderation_status','flagged',] + list_display = ('object_name', 'timestamp', 'moderation_status', 'flagged', 'long_desc') + list_editable = ('moderation_status', 'flagged') + list_filter = ['moderation_status', 'flagged'] + + def long_desc(self, obj): + return "%s" % render_to_string('moderation/long_desc.html', {'obj': obj.content_object}) + long_desc.short_description = 'Object Description' + long_desc.allow_tags = True def object_name(self, obj): return "%s" % obj From e425e5d6b8673ca92f55b75b5a3c4da6e847f2f5 Mon Sep 17 00:00:00 2001 From: Nick Jones Date: Wed, 19 Mar 2014 11:04:34 +0000 Subject: [PATCH 16/18] Updating for custom user model --- gatekeeper/models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gatekeeper/models.py b/gatekeeper/models.py index bff3d67..4771ddc 100644 --- a/gatekeeper/models.py +++ b/gatekeeper/models.py @@ -1,5 +1,5 @@ from django.conf import settings -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes import generic from django.contrib.contenttypes.models import ContentType from django.db import models @@ -15,6 +15,8 @@ STATUS_ON_FLAG = getattr(settings, "GATEKEEPER_STATUS_ON_FLAG", None) +User = get_user_model() + class ModeratedObjectManager(models.Manager): def get_for_instance(self, obj): From 0e7b508b5cb6fcf59205a90228100ffbf95a68b1 Mon Sep 17 00:00:00 2001 From: Nick Jones Date: Wed, 19 Mar 2014 11:23:39 +0000 Subject: [PATCH 17/18] Updating for custom user model --- gatekeeper/__init__.py | 4 +++- gatekeeper/models.py | 8 +++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gatekeeper/__init__.py b/gatekeeper/__init__.py index 8e7972b..b80b6e2 100644 --- a/gatekeeper/__init__.py +++ b/gatekeeper/__init__.py @@ -4,7 +4,7 @@ __license__ = "BSD" from django.conf import settings -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.core.mail import send_mail from django.core.urlresolvers import reverse @@ -27,6 +27,8 @@ post_flag = Signal(providing_args=["instance"]) def _get_automod_user(): + User = get_user_model() + try: return User.objects.get(username__exact="gatekeeper_automod") except User.DoesNotExist: diff --git a/gatekeeper/models.py b/gatekeeper/models.py index 4771ddc..72ecb16 100644 --- a/gatekeeper/models.py +++ b/gatekeeper/models.py @@ -15,8 +15,6 @@ STATUS_ON_FLAG = getattr(settings, "GATEKEEPER_STATUS_ON_FLAG", None) -User = get_user_model() - class ModeratedObjectManager(models.Manager): def get_for_instance(self, obj): @@ -36,7 +34,7 @@ class ModeratedObject(models.Model): moderation_status = models.IntegerField(choices=STATUS_CHOICES, verbose_name=_('moderation status')) - moderation_status_by = models.ForeignKey(User, blank=True, null=True, + moderation_status_by = models.ForeignKey(get_user_model(), blank=True, null=True, verbose_name=_('moderation status by')) moderation_status_date = models.DateTimeField(blank=True, null=True, verbose_name=_('moderation status date')) @@ -44,7 +42,7 @@ class ModeratedObject(models.Model): verbose_name=_('moderation reason')) flagged = models.BooleanField(default=False, verbose_name=_('flagged')) - flagged_by = models.ForeignKey(User, blank=True, null=True, + flagged_by = models.ForeignKey(get_user_model(), blank=True, null=True, related_name='flagged objects', verbose_name=_('flagged by')) flagged_date = models.DateTimeField(blank=True, null=True, @@ -56,7 +54,7 @@ class ModeratedObject(models.Model): content_object = generic.GenericForeignKey('content_type', 'object_id') created_ip = models.IPAddressField(_('Created user IP'), blank=True, null=True) - created_by = models.ForeignKey(User, blank=True, null=True, \ + created_by = models.ForeignKey(get_user_model(), blank=True, null=True, \ related_name="created_moderated_objects", verbose_name=_('created by')) From 8f204430cfe3e003f6e2f6af2460bb41481a6165 Mon Sep 17 00:00:00 2001 From: Nick Jones Date: Wed, 19 Mar 2014 11:24:53 +0000 Subject: [PATCH 18/18] Updating for custom user model --- gatekeeper/models.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gatekeeper/models.py b/gatekeeper/models.py index 72ecb16..5e7313e 100644 --- a/gatekeeper/models.py +++ b/gatekeeper/models.py @@ -1,5 +1,4 @@ from django.conf import settings -from django.contrib.auth import get_user_model from django.contrib.contenttypes import generic from django.contrib.contenttypes.models import ContentType from django.db import models @@ -34,7 +33,7 @@ class ModeratedObject(models.Model): moderation_status = models.IntegerField(choices=STATUS_CHOICES, verbose_name=_('moderation status')) - moderation_status_by = models.ForeignKey(get_user_model(), blank=True, null=True, + moderation_status_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, verbose_name=_('moderation status by')) moderation_status_date = models.DateTimeField(blank=True, null=True, verbose_name=_('moderation status date')) @@ -42,7 +41,7 @@ class ModeratedObject(models.Model): verbose_name=_('moderation reason')) flagged = models.BooleanField(default=False, verbose_name=_('flagged')) - flagged_by = models.ForeignKey(get_user_model(), blank=True, null=True, + flagged_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name='flagged objects', verbose_name=_('flagged by')) flagged_date = models.DateTimeField(blank=True, null=True, @@ -54,7 +53,7 @@ class ModeratedObject(models.Model): content_object = generic.GenericForeignKey('content_type', 'object_id') created_ip = models.IPAddressField(_('Created user IP'), blank=True, null=True) - created_by = models.ForeignKey(get_user_model(), blank=True, null=True, \ + created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, \ related_name="created_moderated_objects", verbose_name=_('created by'))