Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge in other people's commits #11

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
72 changes: 49 additions & 23 deletions gatekeeper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
__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
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)
Expand All @@ -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:
Expand Down Expand Up @@ -59,16 +61,18 @@ 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, 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,
'long_desc': long_desc or _default_long_desc,
'moderator_list': moderator_list,
'notify_moderators': notify_moderators,
}
if import_unmoderated:
try:
Expand Down Expand Up @@ -119,6 +123,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)

Expand Down Expand Up @@ -146,9 +154,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(
Expand Down Expand Up @@ -179,11 +187,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
Expand All @@ -199,34 +210,49 @@ 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,
content_type=ContentType.objects.get_for_model(instance))


if MODERATOR_LIST:
if callable(registered_models[instance.__class__]['notify_moderators']):
if not registered_models[instance.__class__]['notify_moderators'](instance):
return

from django.contrib.sites.models import Site
domain = Site.objects.get(id=settings.SITE_ID).domain
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

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':
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':
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
# 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:
Expand Down
31 changes: 29 additions & 2 deletions gatekeeper/admin.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,37 @@
from django.contrib import admin
from django.template.loader import render_to_string

from gatekeeper.models import ModeratedObject
from django.utils.translation import ugettext_lazy as _



class ModeratedObjectAdmin(admin.ModelAdmin):
list_display = ('object_name', 'timestamp', 'moderation_status', 'flagged')
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_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 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
Expand Down
Binary file added gatekeeper/locale/ru/LC_MESSAGES/django.mo
Binary file not shown.
96 changes: 96 additions & 0 deletions gatekeeper/locale/ru/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Volf <[email protected]>, 2010.
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-02-05 00:17+0500\n"
"PO-Revision-Date: 2010-09-15 23:54+0600\n"
"Last-Translator: Volf <[email protected]>\n"
"Language-Team: LANGUAGE <[email protected]>\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"

#: admin.py:16
msgid "Moderation"
msgstr "Состояние модерации"

#: admin.py:19
msgid "Flagged"
msgstr "Отметки модерации"

#: admin.py:22
msgid "Meta"
msgstr "Информация об объекте"

#: models.py:11
msgid "Approved"
msgstr "Одобрено"

#: models.py:12
msgid "Pending"
msgstr "В ожидании"

#: models.py:13
msgid "Rejected"
msgstr "Отклонено"

#: models.py:36
msgid "moderation status"
msgstr "состояние"

#: models.py:38
msgid "moderation status by"
msgstr "статус установил"

#: models.py:40
msgid "moderation status date"
msgstr "дата модерации"

#: models.py:42
msgid "moderation reason"
msgstr "причина"

#: models.py:44
msgid "flagged"
msgstr "отмечено"

#: models.py:47
msgid "flagged by"
msgstr "отметил пользователь"

#: models.py:49
msgid "flagged date"
msgstr "дата отметки"

#: models.py:52
msgid "content type"
msgstr "тип содержимого"

#: models.py:53
msgid "object id"
msgstr "Идентификатор объекта"

#: models.py:56
msgid "Created user IP"
msgstr "IP пользователя"

#: models.py:59
msgid "created by"
msgstr "создано пользователем"

#: models.py:107
msgid "View"
msgstr "Показать"

#: models.py:111
msgid "link"
msgstr "Ссылка"

6 changes: 5 additions & 1 deletion gatekeeper/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
_thread_locals.gatekeeper_user = getattr(request, 'user', None)
_thread_locals.gatekeeper_user_ip = request.META['REMOTE_ADDR']
Loading