Commit 102b015a by benjaoming

south migration and django 1.7 transitional support, remove django_notify and use django_nyt

parent bb82b468
...@@ -5,4 +5,3 @@ include setup.cfg ...@@ -5,4 +5,3 @@ include setup.cfg
include requirements.txt include requirements.txt
include model_chart_wiki.pdf include model_chart_wiki.pdf
recursive-include wiki *.html *.txt *.png *.js *.css *.gif *.less *.mo *.po *.otf *.svg *.woff *.eot *.ttf recursive-include wiki *.html *.txt *.png *.js *.css *.gif *.less *.mo *.po *.otf *.svg *.woff *.eot *.ttf
recursive-include django_notify *.html *.txt *.png *.js *.css *.gif *.mo *.po
django_notify
=============
NB! This application is not the same as the PyPi project by the very same name,
nor is an integral part of django-wiki, it's a standalone project.
That PyPi project by the same name has been long dead (but seemed nice),
and we will try to get the keys for their PyPi repo or something... but meanwhile!
django_notify does this:
```python
from django_notify import notify
EVENT_KEY = "my_key"
notify(_("OMG! Something happened"), EVENT_KEY)
```
All users subscribing to `EVENT_KEY` will have a notification created in their
stack. If you have emails enabled, they may get a summary of notifications at an
interval of their choice.
Why should you do this?
-----------------------
Users need an cleverly sifted stream of events. Ensure that they have the
possibility of customizing what they deem fit for their stream.
What do you need to do?
-----------------------
You need to do a lot. Firstly, you need to write some javascript that will
fetch the latest notifications and display them in some area of the screen.
Upon clicking that icon, the latest notifications are displayed. Something like
this:
![Javascript drop-down](./docs/misc/screenshot_dropdown.png)
Here is a snippet example to get you started, but you need to get ui.js from [django-wiki/plugins/notifications](https://github.com/benjaoming/django-wiki/tree/master/wiki/plugins/notifications/static/wiki/plugins/notifications/js)
which is a couple of utility functions that use JQuery to get notifications from
a JSON view and display them in the right DOM element.
```html
<h2>Notifications:</h2>
<ul>
<li class="notifications-empty"><a href="#"><em>{% trans "No notifications" %}</em></a></li>
<li class="divider"></li>
<li>
<a href="#" onclick="notify_mark_read()">
<i class="icon-check"></i>
{% trans "Clear notifications list" %}
</a>
</li>
<!-- Example of a settings page linked directly under the notifications -->
<li>
<a href="{% url 'wiki:notification_settings' %}">
<i class="icon-wrench"></i>
{% trans "Notification settings" %}
</a>
</li>
</ul>
<script type="text/javascript">
URL_NOTIFY_GET_NEW = "{% url "notify:json_get" %}";
URL_NOTIFY_MARK_READ = "{% url "notify:json_mark_read_base" %}";
URL_NOTIFY_GOTO = "{% url "notify:goto_base" %}";
</script>
<script type="text/javascript" src="{{ STATIC_URL }}wiki/plugins/notifications/js/ui.js"></script>
```
Usage
-----
### Adding a notification
```python
from django_notify import notify
EVENT_KEY = "my_key"
notify(_("OMG! Something happened"), EVENT_KEY)
```
### Adding a notification with a certain target object
The Notification model has a GenericForeignKey which can link it to any other
object. This is nice, because you might have an intention to go the other way
around and ask "for this object, are there any notifications?"
```python
notify(_("OMG! Something happened"), EVENT_KEY, target_object=my_model_instance)
```
### Excluding certain recepients
By setting the kwarg `filter_exclude` to a dictionary of lookup fields for
`models.Subscription`, you may exclude certain users from getting a notification.
For instance, if a notification is solely for staff members:
```python
notify(
_("OMG! Something happened"), EVENT_KEY,
filter_exclude={'settings__user__is_staff': True}
)
```
### Disabling notifications
Use `decorators.disable_notify` to ensure that all notifications within a function are disabled.
For instance:
```python
from django_notify.decorators import disable_notify
@disable_notify
def my_view(request):
...
```
*This is a work in progress*
----------------------------
This application should live outside django-wiki.
It will! But only as soon as there's time to package it separately...
TODO:
* Missing email functionality
* Functions to easily retrive notifications and mark them as read
* Some easy-to-use template tags and templates to override.
* Examples of how to extend
# -*- coding: utf-8 -*-
# This package and all its sub-packages are part of django_notify,
# except where otherwise stated.
#
# django_notify is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# django_notify is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with django_notify. If not, see <http://www.gnu.org/licenses/>.
# Unused feature, atm. everything is bundled with django-wiki
from __future__ import unicode_literals
VERSION = "0.0.4"
from django.contrib.contenttypes.models import ContentType
from django.db.models import Model
from django.utils.translation import ugettext as _
from . import models
_disable_notifications = False
def notify(message, key, target_object=None, url=None, filter_exclude={}):
"""
Notify subscribing users of a new event. Key can be any kind of string,
just make sure to reuse it where applicable! Object_id is some identifier
of an object, for instance if a user subscribes to a specific comment thread,
you could write:
notify("there was a response to your comment", "comment_response",
target_object=PostersObject,
url=reverse('comments:view', args=(PostersObject.id,)))
The below example notifies everyone subscribing to the "new_comments" key
with the message "New comment posted".
notify("New comment posted", "new_comments")
filter_exclude: a dictionary to exclude special elements of subscriptions
in the queryset, for instance filter_exclude={''}
"""
if _disable_notifications:
return 0
if target_object:
if not isinstance(target_object, Model):
raise TypeError(_("You supplied a target_object that's not an instance of a django Model."))
object_id = target_object.id
else:
object_id = None
objects = models.Notification.create_notifications(
key,
object_id=object_id,
message=message,
url=url,
filter_exclude=filter_exclude,
)
return len(objects)
from django.contrib import admin
from django_notify import models
from django_notify import settings
if settings.ENABLE_ADMIN:
admin.site.register(models.NotificationType)
admin.site.register(models.Notification)
admin.site.register(models.Settings)
admin.site.register(models.Subscription)
\ No newline at end of file
# -*- coding: utf-8 -*-
from django.utils import simplejson as json
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
import django_notify
def disable_notify(func):
"""Disable notifications. Example:
@disable_notify
def your_function():
notify("no one will be notified", ...)
"""
def wrap(request, *args, **kwargs):
django_notify._disable_notifications = True
response = func(request, *args, **kwargs)
django_notify._disable_notifications = False
return response
return wrap
def login_required_ajax(func):
"""Similar to login_required. But if the request is an ajax request, then
it returns an error in json with a 403 status code."""
def wrap(request, *args, **kwargs):
if request.is_ajax():
if not request.user or not request.user.is_authenticated():
return json_view(lambda *a, **kw: {'error': 'not logged in'})(request, status=403)
return func(request, *args, **kwargs)
else:
return login_required(func)(request, *args, **kwargs)
return wrap
def json_view(func):
def wrap(request, *args, **kwargs):
obj = func(request, *args, **kwargs)
data = json.dumps(obj, ensure_ascii=False)
status = kwargs.get('status', 200)
response = HttpResponse(mimetype='application/json', status=status)
response.write(data)
return response
return wrap
# THE GERMAN TRANSLATION OF DJANGO-NOTIFY.
# Copyright (C) 2013 THOMAS LOTTERMANN
# This file is distributed under the same license as the DJANGO-WIKI package.
# THOMAS LOTTERMANN <TomLottermann@googlemail.com>, 2013.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 0.18\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-06-06 20:37+0200\n"
"Last-Translator: Thomas Lottermann <TomLottermann@googlemail.com>\n"
"Language-Team: \n"
"Language: German\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: __init__.py:52
msgid "You supplied a target_object that's not an instance of a django Model."
msgstr "Das gegebene \"target_object\" ist keine Instanz eines Django Models."
#: models.py:14
msgid "unique key"
msgstr "eindeutiger Schlüssel"
#: models.py:16
msgid "verbose name"
msgstr "sprechender Name"
#: models.py:25
msgid "type"
msgstr "Typ"
#: models.py:26
msgid "types"
msgstr "Typen"
#: models.py:31
msgid "interval"
msgstr "Interval"
#: models.py:35
#, python-format
msgid "Settings for %s"
msgstr "Einstellungen für %s"
#: models.py:40 models.py:41
msgid "settings"
msgstr "Einstellungen"
#: models.py:48
msgid "Leave this blank to subscribe to any kind of object"
msgstr "Leerlassen um beliebiges Object zu abonnieren"
#: models.py:53
#, python-format
msgid "Subscription for: %s"
msgstr "Abonnement von: %s"
#: models.py:58
msgid "subscription"
msgstr "Abonnement"
#: models.py:59
msgid "subscriptions"
msgstr "Abonnements"
#: models.py:65
msgid "link for notification"
msgstr "Link zur Benachrichtigung"
#: models.py:71
msgid "occurrences"
msgstr "Häufigkeit"
#: models.py:72
msgid ""
"If the same notification was fired multiple times with no intermediate "
"notifications"
msgstr ""
"Wenn die gleiche Benachrichtigung öfter aufgetreten ist ohne "
"zwischenzeitiges senden"
#: models.py:125
msgid "notification"
msgstr "Benachrichtigung"
#: models.py:126
msgid "notifications"
msgstr "Benachrichtigungen"
#: settings.py:19
msgid "You have new notifications"
msgstr "Du hast neue Benachrichtigungen"
#: settings.py:38
msgid "instant"
msgstr "sofort"
#: settings.py:39
msgid "daily"
msgstr "täglich"
#: settings.py:40
msgid "weekly"
msgstr "wöchentlich"
#: views.py:32
#, python-format
msgid "%d times"
msgstr "%d mal"
#: templates/emails/notification_email_message.txt:2
#, python-format
msgid "Dear %(username)s,"
msgstr "Hallo %(username)s,"
#: templates/emails/notification_email_message.txt:4
#, python-format
msgid " These are the %(digest)s notifications from %(site)s."
msgstr " Dies sind die %(digest)s versendeten Benachrichtigungen von %(site)s."
#: templates/emails/notification_email_message.txt:10
msgid "Thanks for using our site!"
msgstr "Danke, dass du unsere Seite nutzt!"
#: templates/emails/notification_email_message.txt:12
msgid "Sincerely"
msgstr "Viele Grüße"
#: templates/emails/notification_email_subject.txt:2
#, python-format
msgid " %(digest)s Notifications %(site)s."
msgstr " Benachrichtigungen von %(site)s (%(digest)s versendet)."
# THE RUSSIAN TRANSLATION OF DJANGO-NOTIFY.
# Copyright (C) 2013 ROSTISLAV GRIGORIEV
# This file is distributed under the same license as the DJANGO-WIKI package.
# Rostislav Grigoriev <hjcnbckfd@gmail.com>, 2013.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 0.18\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-10-25 15:45+0400\n"
"PO-Revision-Date: 2013-03-17 19:30+CET\n"
"Last-Translator: Rostislav Grigoriev <hjcnbckfd@gmail.com>\n"
"Language-Team: \n"
"Language: Russian\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"
#: __init__.py:55
msgid "You supplied a target_object that's not an instance of a django Model."
msgstr "Указанный вами target_object не экземляр django-модели"
#: models.py:18
msgid "unique key"
msgstr "уникальный ключ"
#: models.py:23
msgid "verbose name"
msgstr "наименование"
#: models.py:34
msgid "type"
msgstr "тип"
#: models.py:35
msgid "types"
msgstr "типы"
#: models.py:47
msgid "interval"
msgstr "интервал"
#: models.py:52
#, python-format
msgid "Settings for %s"
msgstr "Настройки для %s"
#: models.py:57 models.py:58
msgid "settings"
msgstr "настройки"
#: models.py:68
msgid "Leave this blank to subscribe to any kind of object"
msgstr "Оставьте это поле пустым, чтобы подписаться на любой объект"
#: models.py:78
#, python-format
msgid "Subscription for: %s"
msgstr "Подписка для: %s"
#: models.py:83
msgid "subscription"
msgstr "подписка"
#: models.py:84
msgid "subscriptions"
msgstr "подписки"
#: models.py:96
msgid "link for notification"
msgstr "ссылка уведомления"
#: models.py:106
msgid "occurrences"
msgstr "вхождения"
#: models.py:108
msgid ""
"If the same notification was fired multiple times with no intermediate "
"notifications"
msgstr ""
"Если уведомление было вызвано несколько раз без промежуточного уведомления."
#: models.py:170
msgid "notification"
msgstr "уведомление"
#: models.py:171
msgid "notifications"
msgstr "уведомления"
#: settings.py:19
msgid "You have new notifications"
msgstr "Нет новых уведомлений"
#: settings.py:38
msgid "instantly"
msgstr "немедленно"
#: settings.py:39
msgid "daily"
msgstr "раз в день"
#: settings.py:40
msgid "weekly"
msgstr "раз в неделю"
#: views.py:32
#, python-format
msgid "%d times"
msgstr "%d раз"
#: templates/emails/notification_email_message.txt:1
#, python-format
msgid "Dear %(username)s,"
msgstr "Дорогой %(username)s,"
#: templates/emails/notification_email_message.txt:3
#, python-format
msgid "These are the %(digest)s notifications from %(site)s."
msgstr " Для вас %(digest)s уведомлений от %(site)s."
#: templates/emails/notification_email_message.txt:9
msgid "Thanks for using our site!"
msgstr "Спасибо, что пользуетесь сайтом!"
#: templates/emails/notification_email_message.txt:11
msgid "Sincerely"
msgstr "Искренне"
#: templates/emails/notification_email_subject.txt:2
#, python-format
msgid " %(digest)s Notifications %(site)s."
msgstr " %(digest)s уведомлений от %(site)s."
from __future__ import print_function
from __future__ import unicode_literals
import os
import sys
import time
from datetime import datetime
from optparse import make_option
from django_notify import settings as notify_settings
from django.contrib.sites.models import Site
from django.core import mail
from django.core.management.base import BaseCommand
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _, activate, deactivate
from django.conf import settings
from django_notify import models
import smtplib
import logging
class Command(BaseCommand):
can_import_settings = True
help = 'Sends notification emails to subscribed users taking into account the subscription interval' #@ReservedAssignment
option_list = BaseCommand.option_list + (
make_option('--daemon','-d',
action='store_true',
dest='daemon',
default=False,
help='Go to daemon mode and exit'),
)
def _send_user_notifications(self, context, connection):
subject = _(notify_settings.EMAIL_SUBJECT)
message = render_to_string(
'emails/notification_email_message.txt',
context
)
email = mail.EmailMessage(
subject, message, notify_settings.EMAIL_SENDER,
[context['user'].email], connection=connection
)
self.logger.info("Sending to: %s" % context['user'].email)
email.send(fail_silently=False)
def handle(self, *args, **options):
# activate the language
activate(settings.LANGUAGE_CODE)
daemon = options['daemon']
self.logger = logging.getLogger('django_notify')
if not self.logger.handlers:
if daemon:
handler = logging.FileHandler(filename=notify_settings.NOTIFY_LOG)
else:
handler = logging.StreamHandler(self.stdout)
self.logger.addHandler(handler)
self.logger.setLevel(logging.INFO)
self.logger.info("Starting django_notify e-mail dispatcher")
if not notify_settings.SEND_EMAILS:
print("E-mails disabled - quitting.")
sys.exit()
# Run as daemon, ie. fork the process
if daemon:
self.logger.info("Daemon mode enabled, forking")
try:
fpid = os.fork()
if fpid > 0:
# Running as daemon now. PID is fpid
self.logger.info("PID: %s" % str(fpid))
pid_file = file(notify_settings.NOTIFY_PID, "w")
pid_file.write(str(fpid))
pid_file.close()
sys.exit(0)
except OSError as e:
sys.stderr.write("fork failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)
try:
self.send_loop()
except KeyboardInterrupt:
print("\nQuitting...")
# deactivate the language
deactivate()
def send_loop(self):
# This could be /improved by looking up the last notified person
last_sent = None
context = {'user': None,
'notifications': None,
'digest': None,
'site': Site.objects.get_current()}
#create a connection to smtp server for reuse
try:
connection = mail.get_connection()
except:
self.logger.error("Could get a mail connection")
raise
while True:
try:
connection.open()
except:
self.logger.error("Could not use e-mail connection")
raise
started_sending_at = datetime.now()
self.logger.info("Starting send loop at %s" % str(started_sending_at))
if last_sent:
settings = models.Settings.objects.filter(
interval__lte=((started_sending_at-last_sent).seconds // 60) // 60
).order_by('user')
else:
settings = models.Settings.objects.all().order_by('user')
for setting in settings:
context['user'] = setting.user
context['notifications']= []
#get the index of the tuple corresponding to the interval and get the string name
context['digest'] = notify_settings.INTERVALS[[y[0] for y in notify_settings.INTERVALS].index(setting.interval)][1]
for subscription in setting.subscription_set.filter(
send_emails=True,
latest__is_emailed=False
):
context['notifications'].append(subscription.latest)
if len(context['notifications']) > 0:
try:
self._send_user_notifications(context, connection)
for n in context['notifications']:
n.is_emailed=True
n.save()
except smtplib.SMTPException:
# TODO: Only quit on certain errors, retry on others.
self.logger.error("You have an error with your SMTP server connection, quitting.")
raise
connection.close()
last_sent = datetime.now()
elapsed_seconds = (last_sent - started_sending_at).seconds
time.sleep(
max(
(min(notify_settings.INTERVALS)[0] - elapsed_seconds) * 60,
notify_settings.NOTIFY_SLEEP_TIME,
0
)
)
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
try:
from django.contrib.auth import get_user_model
except ImportError: # django < 1.5
from django.contrib.auth.models import User
else:
User = get_user_model()
user_orm_label = '%s.%s' % (User._meta.app_label, User._meta.object_name)
user_model_label = '%s.%s' % (User._meta.app_label, User._meta.module_name)
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'NotificationType'
db.create_table('notify_notificationtype', (
('key', self.gf('django.db.models.fields.CharField')(unique=True, max_length=128, primary_key=True)),
('label', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'], null=True, blank=True)),
))
db.send_create_signal('django_notify', ['NotificationType'])
# Adding model 'Settings'
db.create_table('notify_settings', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_orm_label])),
('interval', self.gf('django.db.models.fields.SmallIntegerField')(default=0)),
))
db.send_create_signal('django_notify', ['Settings'])
# Adding model 'Subscription'
db.create_table('notify_subscription', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('settings', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['django_notify.Settings'])),
('notification_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['django_notify.NotificationType'])),
('object_id', self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True)),
('send_emails', self.gf('django.db.models.fields.BooleanField')(default=True)),
))
db.send_create_signal('django_notify', ['Subscription'])
# Adding model 'Notification'
db.create_table('notify_notification', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('subscription', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['django_notify.Subscription'], null=True, on_delete=models.SET_NULL, blank=True)),
('message', self.gf('django.db.models.fields.TextField')()),
('url', self.gf('django.db.models.fields.URLField')(max_length=200, null=True, blank=True)),
('is_viewed', self.gf('django.db.models.fields.BooleanField')(default=False)),
('is_emailed', self.gf('django.db.models.fields.BooleanField')(default=False)),
('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
))
db.send_create_signal('django_notify', ['Notification'])
def backwards(self, orm):
# Deleting model 'NotificationType'
db.delete_table('notify_notificationtype')
# Deleting model 'Settings'
db.delete_table('notify_settings')
# Deleting model 'Subscription'
db.delete_table('notify_subscription')
# Deleting model 'Notification'
db.delete_table('notify_notification')
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'})
},
user_model_label: {
'Meta': {'object_name': User.__name__, 'db_table': "'%s'" % User._meta.db_table},
'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'})
},
'django_notify.notification': {
'Meta': {'object_name': 'Notification', 'db_table': "'notify_notification'"},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_emailed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'message': ('django.db.models.fields.TextField', [], {}),
'subscription': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.Subscription']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
},
'django_notify.notificationtype': {
'Meta': {'object_name': 'NotificationType', 'db_table': "'notify_notificationtype'"},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128', 'primary_key': 'True'}),
'label': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'})
},
'django_notify.settings': {
'Meta': {'object_name': 'Settings', 'db_table': "'notify_settings'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'interval': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_orm_label})
},
'django_notify.subscription': {
'Meta': {'object_name': 'Subscription', 'db_table': "'notify_subscription'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'notification_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.NotificationType']"}),
'object_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'send_emails': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'settings': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.Settings']"})
}
}
complete_apps = ['django_notify']
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
try:
from django.contrib.auth import get_user_model
except ImportError: # django < 1.5
from django.contrib.auth.models import User
else:
User = get_user_model()
user_orm_label = '%s.%s' % (User._meta.app_label, User._meta.object_name)
user_model_label = '%s.%s' % (User._meta.app_label, User._meta.module_name)
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Notification.occurrences'
db.add_column('notify_notification', 'occurrences',
self.gf('django.db.models.fields.PositiveIntegerField')(default=1),
keep_default=False)
def backwards(self, orm):
# Deleting field 'Notification.occurrences'
db.delete_column('notify_notification', 'occurrences')
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'})
},
user_model_label: {
'Meta': {'object_name': User.__name__, 'db_table': "'%s'" % User._meta.db_table},
'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'})
},
'django_notify.notification': {
'Meta': {'ordering': "('-id',)", 'object_name': 'Notification', 'db_table': "'notify_notification'"},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_emailed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'message': ('django.db.models.fields.TextField', [], {}),
'occurrences': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
'subscription': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.Subscription']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
},
'django_notify.notificationtype': {
'Meta': {'object_name': 'NotificationType', 'db_table': "'notify_notificationtype'"},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128', 'primary_key': 'True'}),
'label': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'})
},
'django_notify.settings': {
'Meta': {'object_name': 'Settings', 'db_table': "'notify_settings'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'interval': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_orm_label})
},
'django_notify.subscription': {
'Meta': {'object_name': 'Subscription', 'db_table': "'notify_subscription'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'notification_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.NotificationType']"}),
'object_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'send_emails': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'settings': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.Settings']"})
}
}
complete_apps = ['django_notify']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
try:
from django.contrib.auth import get_user_model
except ImportError: # django < 1.5
from django.contrib.auth.models import User
else:
User = get_user_model()
user_orm_label = '%s.%s' % (User._meta.app_label, User._meta.object_name)
user_model_label = '%s.%s' % (User._meta.app_label, User._meta.module_name)
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Subscription.latest'
db.add_column('notify_subscription', 'latest',
self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='latest_for', null=True, to=orm['django_notify.Notification']),
keep_default=False)
def backwards(self, orm):
# Deleting field 'Subscription.latest'
db.delete_column('notify_subscription', 'latest_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'})
},
user_model_label: {
'Meta': {'object_name': User.__name__, 'db_table': "'%s'" % User._meta.db_table},
'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'})
},
'django_notify.notification': {
'Meta': {'ordering': "('-id',)", 'object_name': 'Notification', 'db_table': "'notify_notification'"},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_emailed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'message': ('django.db.models.fields.TextField', [], {}),
'occurrences': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
'subscription': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.Subscription']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
},
'django_notify.notificationtype': {
'Meta': {'object_name': 'NotificationType', 'db_table': "'notify_notificationtype'"},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128', 'primary_key': 'True'}),
'label': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'})
},
'django_notify.settings': {
'Meta': {'object_name': 'Settings', 'db_table': "'notify_settings'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'interval': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_orm_label})
},
'django_notify.subscription': {
'Meta': {'object_name': 'Subscription', 'db_table': "'notify_subscription'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'latest': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'latest_for'", 'null': 'True', 'to': "orm['django_notify.Notification']"}),
'notification_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.NotificationType']"}),
'object_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'send_emails': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'settings': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.Settings']"})
}
}
complete_apps = ['django_notify']
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
try:
from django.contrib.auth import get_user_model
except ImportError: # django < 1.5
from django.contrib.auth.models import User
else:
User = get_user_model()
user_orm_label = '%s.%s' % (User._meta.app_label, User._meta.object_name)
user_model_label = '%s.%s' % (User._meta.app_label, User._meta.module_name)
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'Notification.url'
db.alter_column('notify_notification', 'url', self.gf('django.db.models.fields.CharField')(max_length=200, null=True))
def backwards(self, orm):
# Changing field 'Notification.url'
db.alter_column('notify_notification', 'url', self.gf('django.db.models.fields.URLField')(max_length=200, null=True))
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'})
},
user_model_label: {
'Meta': {'object_name': User.__name__, 'db_table': "'%s'" % User._meta.db_table},
'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'})
},
'django_notify.notification': {
'Meta': {'ordering': "('-id',)", 'object_name': 'Notification', 'db_table': "'notify_notification'"},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_emailed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'message': ('django.db.models.fields.TextField', [], {}),
'occurrences': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
'subscription': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.Subscription']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
},
'django_notify.notificationtype': {
'Meta': {'object_name': 'NotificationType', 'db_table': "'notify_notificationtype'"},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128', 'primary_key': 'True'}),
'label': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'})
},
'django_notify.settings': {
'Meta': {'object_name': 'Settings', 'db_table': "'notify_settings'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'interval': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_orm_label})
},
'django_notify.subscription': {
'Meta': {'object_name': 'Subscription', 'db_table': "'notify_subscription'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'latest': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'latest_for'", 'null': 'True', 'to': "orm['django_notify.Notification']"}),
'notification_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.NotificationType']"}),
'object_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'send_emails': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'settings': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_notify.Settings']"})
}
}
complete_apps = ['django_notify']
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from django.contrib.contenttypes.models import ContentType
from django_notify import settings
class NotificationType(models.Model):
"""
Notification types are added on-the-fly by the
applications adding new notifications
"""
key = models.CharField(
max_length=128,
primary_key=True,
verbose_name=_('unique key'),
unique=True
)
label = models.CharField(
max_length=128,
verbose_name=_('verbose name'),
blank=True,
null=True
)
content_type = models.ForeignKey(ContentType, blank=True, null=True)
def __unicode__(self):
return self.key
class Meta:
db_table = settings.DB_TABLE_PREFIX + '_notificationtype'
verbose_name = _('type')
verbose_name_plural = _('types')
class Settings(models.Model):
"""
Reusable settings object for a subscription
"""
user = models.ForeignKey(
settings.USER_MODEL
)
interval = models.SmallIntegerField(
choices=settings.INTERVALS,
verbose_name=_('interval'),
default=settings.INTERVALS_DEFAULT
)
def __unicode__(self):
obj_name = _("Settings for %s") % self.user.username
return unicode(obj_name)
class Meta:
db_table = settings.DB_TABLE_PREFIX + '_settings'
verbose_name = _('settings')
verbose_name_plural = _('settings')
class Subscription(models.Model):
settings = models.ForeignKey(Settings)
notification_type = models.ForeignKey(NotificationType)
object_id = models.CharField(
max_length=64,
null=True,
blank=True,
help_text=_('Leave this blank to subscribe to any kind of object')
)
send_emails = models.BooleanField(default=True)
latest = models.ForeignKey('Notification',
null=True,
blank=True,
related_name='latest_for'
)
def __unicode__(self):
obj_name = _("Subscription for: %s") % str(self.settings.user.username)
return unicode(obj_name)
class Meta:
db_table = settings.DB_TABLE_PREFIX + '_subscription'
verbose_name = _('subscription')
verbose_name_plural = _('subscriptions')
class Notification(models.Model):
subscription = models.ForeignKey(
Subscription,
null=True,
blank=True,
on_delete=models.SET_NULL
)
message = models.TextField()
url = models.CharField(
verbose_name=_('link for notification'),
blank=True,
null=True,
max_length=200
)
is_viewed = models.BooleanField(default=False)
is_emailed = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
occurrences = models.PositiveIntegerField(
default=1,
verbose_name=_('occurrences'),
help_text=_(
'If the same notification was fired multiple '
'times with no intermediate notifications'
)
)
@classmethod
def create_notifications(cls, key, **kwargs):
if not key or not isinstance(key, str):
raise KeyError('No notification key (string) specified.')
object_id = kwargs.pop('object_id', None)
filter_exclude = kwargs.pop('filter_exclude', {})
objects_created = []
subscriptions = Subscription.objects.filter(
Q(notification_type__key=key) |
Q(notification_type__key=None),
**filter_exclude
)
if object_id:
subscriptions = subscriptions.filter(
Q(object_id=object_id) |
Q(object_id=None)
)
subscriptions = subscriptions.prefetch_related('latest', 'settings')
subscriptions = subscriptions.order_by('settings__user')
prev_user = None
for subscription in subscriptions:
# Don't alert the same user several times even though overlapping
# subscriptions occur.
if subscription.settings.user == prev_user:
continue
# Check if it's the same as the previous message
latest = subscription.latest
if latest and (latest.message == kwargs.get('message', None) and
latest.url == kwargs.get('url', None) and
latest.is_viewed == False):
# Both message and URL are the same, and it hasn't been viewed
# so just increment occurrence count.
latest.occurrences = latest.occurrences + 1
latest.is_emailed = False
latest.save()
else:
# Insert a new notification
new_obj = cls.objects.create(subscription=subscription, **kwargs)
objects_created.append(
new_obj
)
subscription.latest = new_obj
subscription.save()
prev_user = subscription.settings.user
return objects_created
def __unicode__(self):
return "%s: %s" % (str(self.subscription.settings.user), self.message)
class Meta:
db_table = settings.DB_TABLE_PREFIX + '_notification'
verbose_name = _('notification')
verbose_name_plural = _('notifications')
ordering = ('-id',)
from __future__ import unicode_literals
from django.conf import settings as django_settings
from django import VERSION as DJANGO_VERSION
from django.utils.translation import ugettext_lazy as _
DB_TABLE_PREFIX = 'notify'
# You need to switch this setting on, otherwise nothing will happen :)
ENABLED = getattr(django_settings, 'NOTIFY_ENABLED', True)
# Enable django-admin registration
ENABLE_ADMIN = getattr(django_settings, 'NOTIFY_ENABLE_ADMIN', False)
# Email notifications won't get sent unless you run
# python manage.py notifymail
SEND_EMAILS = getattr(django_settings, 'NOTIFY_SEND_EMAILS', True)
EMAIL_SUBJECT = getattr(django_settings,
'NOTIFY_EMAIL_SUBJECT', _("You have new notifications"))
EMAIL_SENDER = getattr(django_settings,
'NOTIFY_EMAIL_SENDER', "notifications@example.com")
# Seconds to sleep between each database poll
# (leave high unless you really want to send extremely real time
# notifications)
NOTIFY_SLEEP_TIME = 120
# You can always make up more numbers... they simply identify which notifications
# to send when invoking the script, and the number indicates how many hours
# to minimum pass between each notification.
INSTANTLY = 0
DAILY = (24 - 1) * 60 # Subtract 1, because the job finishes less than 24h before the next...
WEEKLY = 7 * (24 - 1) * 60
# List of intervals available. In minutes
INTERVALS = getattr(django_settings, 'NOTIFY_INTERVALS',
[(INSTANTLY, _('instantly')),
(DAILY, _('daily')),
(WEEKLY, _('weekly'))]
)
INTERVALS_DEFAULT = INSTANTLY
# Django 1.5+
if DJANGO_VERSION >= (1,5):
USER_MODEL = getattr(django_settings, 'AUTH_USER_MODEL', 'auth.User')
else:
USER_MODEL = 'auth.User'
####################
# PLANNED SETTINGS #
####################
# Minimum logging and digital garbage! Don't save too much crap!
# After how many days should viewed notifications be deleted?
AUTO_DELETE = getattr(django_settings, 'NOTIFY_AUTO_DELETE', 120)
# After how many days should all types of notifications be deleted?
AUTO_DELETE_ALL = getattr(django_settings, 'NOTIFY_AUTO_DELETE_ALL', 120)
NOTIFY_LOG = getattr(django_settings, 'NOTIFY_LOG', '/tmp/daemon_notify.log')
NOTIFY_PID = getattr(django_settings, 'NOTIFY_PID', '/tmp/daemon_notify.pid')
{% load i18n %}{% autoescape off %}{% load url from future %}{% blocktrans with user.username as username %}Dear {{ username }},{% endblocktrans %}
{% blocktrans with site.name as site %}These are the {{ digest }} notifications from {{ site }}.{% endblocktrans %}
{% for n in notifications %}
* {{ n.message }}
http://{{ site.domain }}{{n.url}}
{% endfor %}
{% trans "Thanks for using our site!" %}
{% trans "Sincerely" %},
{{ site.name }}
{% endautoescape %}
{% load i18n %}
{% blocktrans with site.name as site %} {{ digest }} Notifications {{ site }}.{% endblocktrans %}
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
urlpatterns = patterns('',
url('^json/get/$', 'django_notify.views.get_notifications', name='json_get'),
url('^json/get/(?P<latest_id>\d+)/$', 'django_notify.views.get_notifications', name='json_get'),
url('^json/mark-read/$', 'django_notify.views.mark_read', name='json_mark_read_base'),
url('^json/mark-read/(\d+)/$', 'django_notify.views.mark_read', name='json_mark_read'),
url('^json/mark-read/(?P<id_lte>\d+)/(?P<id_gte>\d+)/$', 'django_notify.views.mark_read', name='json_mark_read'),
url('^goto/(?P<notification_id>\d+)/$', 'django_notify.views.goto', name='goto'),
url('^goto/$', 'django_notify.views.goto', name='goto_base'),
)
def get_pattern(app_name="notify", namespace="notify"):
"""Every url resolution takes place as "notify:view_name".
https://docs.djangoproject.com/en/dev/topics/http/urls/#topics-http-reversing-url-namespaces
"""
return urlpatterns, app_name, namespace
\ No newline at end of file
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django_notify.decorators import json_view, login_required_ajax
from django_notify import models
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, get_object_or_404
from django.utils.translation import ugettext as _
@login_required_ajax
@json_view
def get_notifications(request, latest_id=None, is_viewed=False, max_results=10):
notifications = models.Notification.objects.filter(subscription__settings__user=request.user,)
if not is_viewed is None:
notifications = notifications.filter(is_viewed=is_viewed)
if not latest_id is None:
notifications = notifications.filter(id__gt=latest_id)
notifications = notifications.order_by('-id')
notifications = notifications.prefetch_related('subscription', 'subscription__notification_type')
from django.contrib.humanize.templatetags.humanize import naturaltime
return {'success': True,
'total_count': notifications.count(),
'objects': [{'pk': n.pk,
'message': n.message,
'url': n.url,
'occurrences': n.occurrences,
'occurrences_msg': _('%d times') % n.occurrences,
'type': n.subscription.notification_type.key,
'since': naturaltime(n.created)} for n in notifications[:max_results]]}
@login_required
def goto(request, notification_id=None):
referer = request.META.get('HTTP_REFERER', '')
if not notification_id:
return redirect(referer)
notification = get_object_or_404(models.Notification,
subscription__settings__user=request.user,
id=notification_id)
notification.is_viewed=True
notification.save()
if not notification.url is None:
return redirect(notification.url)
return redirect(referer)
@login_required_ajax
@json_view
def mark_read(request, id_lte, notification_type_id=None, id_gte=None):
notifications = models.Notification.objects.filter(subscription__settings__user=request.user,
id__lte=id_lte)
if notification_type_id:
notifications = notifications.filter(notification_type__id=notification_type_id)
if id_gte:
notifications = notifications.filter(id__gte=id_gte)
notifications.update(is_viewed=True)
return {'success': True}
...@@ -101,7 +101,7 @@ maintain the order due to database relational constraints: ...@@ -101,7 +101,7 @@ maintain the order due to database relational constraints:
'django.contrib.sites', # django 1.6.2 'django.contrib.sites', # django 1.6.2
'django.contrib.humanize', 'django.contrib.humanize',
'south', 'south',
'django_notify', 'django_nyt',
'mptt', 'mptt',
'sekizai', 'sekizai',
'sorl.thumbnail', 'sorl.thumbnail',
...@@ -165,9 +165,9 @@ following lines at the end of your project's ``urls.py``. ...@@ -165,9 +165,9 @@ following lines at the end of your project's ``urls.py``.
:: ::
from wiki.urls import get_pattern as get_wiki_pattern from wiki.urls import get_pattern as get_wiki_pattern
from django_notify.urls import get_pattern as get_notify_pattern from django_nyt.urls import get_pattern as get_nyt_pattern
urlpatterns += patterns('', urlpatterns += patterns('',
(r'^notify/', get_notify_pattern()), (r'^notifications/', get_nyt_pattern()),
(r'', get_wiki_pattern()) (r'', get_wiki_pattern())
) )
......
django>=1.4 django>=1.4
South
Markdown>2.2.0 Markdown>2.2.0
django-sekizai>=0.7 django-sekizai>=0.7
django-mptt>=0.5.3 django-mptt>=0.5.3
sorl-thumbnail==11.12.1b sorl-thumbnail>=11.12.1b
Pillow Pillow
six six
# Notification system
django-nyt>=0.9
\ No newline at end of file
...@@ -22,7 +22,7 @@ settings.configure( ...@@ -22,7 +22,7 @@ settings.configure(
'django.contrib.humanize', 'django.contrib.humanize',
'django.contrib.sites', 'django.contrib.sites',
'south', 'south',
'django_notify', 'django_nyt',
'mptt', 'mptt',
'sekizai', 'sekizai',
'sorl.thumbnail', 'sorl.thumbnail',
......
...@@ -8,19 +8,37 @@ from setuptools import setup, find_packages ...@@ -8,19 +8,37 @@ from setuptools import setup, find_packages
# Used for the long_description. It's nice, because now 1) we have a top level # Used for the long_description. It's nice, because now 1) we have a top level
# README file and 2) it's easier to type in the README file than to put a raw # README file and 2) it's easier to type in the README file than to put a raw
# string in below ... # string in below ...
def get_path(fname): def get_path(fname):
return os.path.join(os.path.dirname(__file__), fname) return os.path.join(os.path.dirname(__file__), fname)
def read(fname): def read(fname):
return open(get_path(fname)).read() return open(get_path(fname)).read()
def dynamic_requirements(requirements):
try:
from django import VERSION
if VERSION < (1, 7):
requirements.append("South>=0.8,!=0.8.3")
except ImportError:
# No django so assuming that a new one will
# get installed...
pass
return requirements
packages = find_packages() packages = find_packages()
try: try:
import pypandoc import pypandoc
long_description = pypandoc.convert(get_path('README.md'), 'rst') long_description = pypandoc.convert(get_path('README.md'), 'rst')
long_description = long_description.split('<!---Illegal PyPi RST data -->')[0] long_description = long_description.split(
'<!---Illegal PyPi RST data -->')[0]
f = open(get_path('README.rst'), 'w') f = open(get_path('README.rst'), 'w')
f.write(long_description) f.write(long_description)
f.close() f.close()
...@@ -29,18 +47,18 @@ except (IOError, ImportError): ...@@ -29,18 +47,18 @@ except (IOError, ImportError):
long_description = "" long_description = ""
setup( setup(
name = "wiki", name="wiki",
version = VERSION, version=VERSION,
author = "Benjamin Bach", author="Benjamin Bach",
author_email = "benjamin@overtag.dk", author_email="benjamin@overtag.dk",
url = "http://www.django-wiki.org", url="http://www.django-wiki.org",
description = "A wiki system written for the Django framework.", description="A wiki system written for the Django framework.",
license = "GPLv3", license="GPLv3",
keywords = "django wiki markdown", keywords="django wiki markdown",
packages=find_packages(exclude=["testproject","testproject.*"]), packages=find_packages(exclude=["testproject", "testproject.*"]),
#long_description=long_description, # long_description=long_description,
zip_safe=False, zip_safe=False,
install_requires=read('requirements.txt').split("\n"), install_requires=dynamic_requirements(read('requirements.txt').split("\n")),
classifiers=[ classifiers=[
'Development Status :: 3 - Alpha', 'Development Status :: 3 - Alpha',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
......
../django_notify
\ No newline at end of file
...@@ -14,7 +14,7 @@ MANAGERS = ADMINS ...@@ -14,7 +14,7 @@ MANAGERS = ADMINS
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': os_path.join(PROJECT_PATH, 'db', 'prepopulated.db'), # Or path to database file if using sqlite3. 'NAME': 'prepopulated.db', # Or path to database file if using sqlite3.
} }
} }
...@@ -91,10 +91,9 @@ INSTALLED_APPS = [ ...@@ -91,10 +91,9 @@ INSTALLED_APPS = [
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.admindocs', 'django.contrib.admindocs',
'south',
'sekizai', 'sekizai',
'sorl.thumbnail', 'sorl.thumbnail',
'django_notify', 'django_nyt',
'wiki', 'wiki',
'wiki.plugins.macros', 'wiki.plugins.macros',
'wiki.plugins.help', 'wiki.plugins.help',
...@@ -105,6 +104,15 @@ INSTALLED_APPS = [ ...@@ -105,6 +104,15 @@ INSTALLED_APPS = [
'mptt', 'mptt',
] ]
from django import VERSION
if VERSION <= (1, 6):
INSTALLED_APPS.append('south')
SOUTH_MIGRATION_MODULES = {
'django_nyt': 'django_nyt.south_migrations',
}
else:
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
# A sample logging configuration. The only tangible logging # A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to # performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False. # the site admins on every HTTP 500 error when DEBUG=False.
...@@ -162,4 +170,3 @@ try: ...@@ -162,4 +170,3 @@ try:
from testproject.settings.local import * from testproject.settings.local import *
except ImportError: except ImportError:
pass pass
...@@ -19,7 +19,7 @@ if settings.DEBUG: ...@@ -19,7 +19,7 @@ if settings.DEBUG:
) )
from wiki.urls import get_pattern as get_wiki_pattern from wiki.urls import get_pattern as get_wiki_pattern
from django_notify.urls import get_pattern as get_notify_pattern from django_nyt.urls import get_pattern as get_notify_pattern
urlpatterns += patterns('', urlpatterns += patterns('',
(r'^notify/', get_notify_pattern()), (r'^notify/', get_notify_pattern()),
(r'', get_wiki_pattern()) (r'', get_wiki_pattern())
......
...@@ -15,4 +15,4 @@ ...@@ -15,4 +15,4 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with django-wiki. If not, see <http://www.gnu.org/licenses/>. # along with django-wiki. If not, see <http://www.gnu.org/licenses/>.
VERSION = "0.0.23" VERSION = "0.0.3"
...@@ -4,7 +4,7 @@ from django import VERSION as DJANGO_VERSION ...@@ -4,7 +4,7 @@ from django import VERSION as DJANGO_VERSION
from django.db import transaction from django.db import transaction
from django.conf import settings as django_settings from django.conf import settings as django_settings
# Django 1.5+ # Django 1.5+
if DJANGO_VERSION >= (1,5): if DJANGO_VERSION >= (1,5):
USER_MODEL = getattr(django_settings, 'AUTH_USER_MODEL', 'auth.User') USER_MODEL = getattr(django_settings, 'AUTH_USER_MODEL', 'auth.User')
......
...@@ -22,8 +22,8 @@ if not 'mptt' in django_settings.INSTALLED_APPS: ...@@ -22,8 +22,8 @@ if not 'mptt' in django_settings.INSTALLED_APPS:
if not 'sekizai' in django_settings.INSTALLED_APPS: if not 'sekizai' in django_settings.INSTALLED_APPS:
raise ImproperlyConfigured('django-wiki: needs sekizai in INSTALLED_APPS') raise ImproperlyConfigured('django-wiki: needs sekizai in INSTALLED_APPS')
if not 'django_notify' in django_settings.INSTALLED_APPS: #if not 'django_nyt' in django_settings.INSTALLED_APPS:
raise ImproperlyConfigured('django-wiki: needs django_notify in INSTALLED_APPS') # raise ImproperlyConfigured('django-wiki: needs django_nyt in INSTALLED_APPS')
if not 'django.contrib.humanize' in django_settings.INSTALLED_APPS: if not 'django.contrib.humanize' in django_settings.INSTALLED_APPS:
raise ImproperlyConfigured('django-wiki: needs django.contrib.humanize in INSTALLED_APPS') raise ImproperlyConfigured('django-wiki: needs django.contrib.humanize in INSTALLED_APPS')
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import datetime from south.utils import datetime_utils as datetime
from south.db import db from south.db import db
from south.v2 import SchemaMigration from south.v2 import SchemaMigration
from django.db import models from django.db import models
try:
from django.contrib.auth import get_user_model
except ImportError: # django < 1.5
from django.contrib.auth.models import User
else:
User = get_user_model()
user_orm_label = '%s.%s' % (User._meta.app_label, User._meta.object_name)
user_model_label = '%s.%s' % (User._meta.app_label, User._meta.module_name)
class Migration(SchemaMigration): class Migration(SchemaMigration):
def forwards(self, orm): def forwards(self, orm):
# Adding model 'Image' pass
db.create_table('images_image', (
('revisionplugin_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['wiki.RevisionPlugin'], unique=True, primary_key=True)),
('image', self.gf('django.db.models.fields.files.ImageField')(max_length=100)),
('caption', self.gf('django.db.models.fields.CharField')(max_length=2056, null=True, blank=True)),
))
db.send_create_signal('images', ['Image'])
def backwards(self, orm): def backwards(self, orm):
# Deleting model 'Image' pass
db.delete_table('images_image')
models = { 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'})
},
user_model_label: {
'Meta': {'object_name': User.__name__, 'db_table': "'%s'" % User._meta.db_table},
'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'})
},
'images.image': {
'Meta': {'object_name': 'Image', '_ormbases': ['wiki.RevisionPlugin']},
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
'revisionplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['wiki.RevisionPlugin']", 'unique': 'True', 'primary_key': 'True'})
},
'wiki.article': {
'Meta': {'object_name': 'Article'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'current_revision': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'current_set'", 'unique': 'True', 'null': 'True', 'to': "orm['wiki.ArticleRevision']"}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']", 'null': 'True', 'blank': 'True'}),
'group_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'group_write': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'other_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'other_write': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_orm_label, 'null': 'True', 'blank': 'True'})
},
'wiki.articleplugin': {
'Meta': {'object_name': 'ArticlePlugin'},
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['wiki.Article']"}),
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'wiki.articlerevision': {
'Meta': {'ordering': "('created',)", 'unique_together': "(('article', 'revision_number'),)", 'object_name': 'ArticleRevision'},
'article': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['wiki.Article']"}),
'automatic_log': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'content': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'previous_revision': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['wiki.ArticleRevision']", 'null': 'True', 'blank': 'True'}),
'redirect': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'redirect_set'", 'null': 'True', 'to': "orm['wiki.Article']"}),
'revision_number': ('django.db.models.fields.IntegerField', [], {}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_orm_label, 'null': 'True', 'blank': 'True'}),
'user_message': ('django.db.models.fields.TextField', [], {'blank': 'True'})
},
'wiki.revisionplugin': {
'Meta': {'object_name': 'RevisionPlugin', '_ormbases': ['wiki.ArticlePlugin']},
'articleplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['wiki.ArticlePlugin']", 'unique': 'True', 'primary_key': 'True'}),
'revision': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['wiki.ArticleRevision']"})
}
} }
complete_apps = ['images'] complete_apps = ['images']
\ No newline at end of file
...@@ -3,8 +3,8 @@ from django import forms ...@@ -3,8 +3,8 @@ from django import forms
from django.forms.models import modelformset_factory, BaseModelFormSet from django.forms.models import modelformset_factory, BaseModelFormSet
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django_notify.models import Settings, NotificationType from django_nyt.models import Settings, NotificationType
from django_notify import settings as notify_settings from django_nyt import settings as notify_settings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
......
...@@ -4,8 +4,8 @@ from django.core.urlresolvers import reverse ...@@ -4,8 +4,8 @@ from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.db.models import signals from django.db.models import signals
from django_notify import notify from django_nyt.utils import notify
from django_notify.models import Subscription from django_nyt.models import Subscription
from wiki import models as wiki_models from wiki import models as wiki_models
from wiki.models.pluginbase import ArticlePlugin from wiki.models.pluginbase import ArticlePlugin
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
APP_LABEL = 'wiki' APP_LABEL = 'wiki'
# Key for django_notify - changing it will break any existing notifications. # Key for django_nyt - changing it will break any existing notifications.
ARTICLE_EDIT = "article_edit" ARTICLE_EDIT = "article_edit"
SLUG = 'notifications' SLUG = 'notifications'
\ No newline at end of file
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
</li> </li>
{% addtoblock "js" %} {% addtoblock "js" %}
<script type="text/javascript"> <script type="text/javascript">
URL_NOTIFY_GET_NEW = "{% url "notify:json_get" %}"; URL_NOTIFY_GET_NEW = "{% url "nyt:json_get" %}";
URL_NOTIFY_MARK_READ = "{% url "notify:json_mark_read_base" %}"; URL_NOTIFY_MARK_READ = "{% url "nyt:json_mark_read_base" %}";
URL_NOTIFY_GOTO = "{% url "notify:goto_base" %}"; URL_NOTIFY_GOTO = "{% url "nyt:goto_base" %}";
</script> </script>
{% endaddtoblock %} {% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{{ STATIC_URL }}wiki/plugins/notifications/js/ui.js"></script>{% endaddtoblock %} {% addtoblock "js" %}<script type="text/javascript" src="{{ STATIC_URL }}wiki/plugins/notifications/js/ui.js"></script>{% endaddtoblock %}
...@@ -4,23 +4,30 @@ ...@@ -4,23 +4,30 @@
{% block wiki_pagetitle %}wiki_pagetitle{% trans "Log in" %}{% endblock %} {% block wiki_pagetitle %}wiki_pagetitle{% trans "Log in" %}{% endblock %}
{% block wiki_contents %} {% block wiki_contents %}
<h1 class="page-header">{% trans "Please log in" %}</h1> <div class="row">
<form method="POST" class="form-horizontal"> <div class="col-lg-3"></div>
{% wiki_form form %} <div class="col-lg-6">
<div class="form-group form-actions"> <h1 class="page-header">{% trans "Please log in" %}</h1>
<div class="col-lg-2"></div> <form method="POST" class="form-horizontal">
<div class="col-lg-10"> {% wiki_form form %}
<button type="submit" name="save_changes" class="btn btn-primary btn-large"> <div class="form-group form-actions">
<span class="icon-lock"></span> <div class="col-lg-2"></div>
{% trans "Log me in..." %} <div class="col-lg-10">
</button> <button type="submit" name="save_changes" class="btn btn-primary btn-large">
<span class="icon-lock"></span>
{% trans "Log me in..." %}
</button>
</div>
</div>
</form>
<p>
{% trans "Don't have an account?" %} <a href="{% url 'wiki:signup' %}">{% trans "Sign up" %} &raquo;</a>
</p>
</div> </div>
<div class="col-lg-3"></div>
</div> </div>
</form>
<p>
{% trans "Don't have an account?" %} <a href="{% url 'wiki:signup' %}">{% trans "Sign up" %} &raquo;</a>
</p>
{% addtoblock "js" %} {% addtoblock "js" %}
<script type="text/javascript"> <script type="text/javascript">
......
{% extends "wiki/create_root.html" %} {% extends "wiki/create_root.html" %}
{% load i18n %} {% load i18n wiki_tags %}
{% block wiki_contents %} {% block wiki_contents %}
<h1>{% trans "Congratulations!" %}</h1> <div class="row">
<p class="lead"> <div class="col-lg-2"></div>
{% trans "You have django-wiki installed... but there are no articles. So it's time to create the first one, the root article." %} <div class="col-lg-8">
</p>
<p class="lead"> <h1>{% trans "Congratulations!" %}</h1>
{% trans "It can be created and/or edited only by administrators, but you can define permissions after." %} <p class="lead">
</p> {% trans "You have django-wiki installed and it seems to be working. But there are no articles yet." %}
</p>
{% if not user.is_superuser %}
<p class="lead">
{% trans "Not to worry! You simply have to login with a superuser account and create the first article in the root of the URL hierarchy." %}
</p>
{% login_url as wiki_login_url %}
{% if wiki_login_url %}
<a href="{{ wiki_login_url }}" class="btn btn-primary btn-large">{% trans "Click here to login" %}</a>
{% endif %}
{% else %}
<p class="lead">
{% trans "But since you're logged in as a superuser, we should really get started..." %}
</p>
<a href="{% url 'wiki:root_create' %}" class="btn btn-primary btn-large">{% trans "Yes, I'll go and create the first article" %}</a>
<a href="http://django-wiki.readthedocs.org/" class="btn btn-default">{% trans "No thanks, I'd rather read the documentation" %}</a>
{% endif %}
</div>
<div class="col-lg-2"></div>
</div>
{% endblock %} {% endblock %}
...@@ -19,7 +19,7 @@ if settings.DEBUG: ...@@ -19,7 +19,7 @@ if settings.DEBUG:
) )
from wiki.urls import get_pattern as get_wiki_pattern from wiki.urls import get_pattern as get_wiki_pattern
from django_notify.urls import get_pattern as get_notify_pattern from django_nyt.urls import get_pattern as get_notify_pattern
urlpatterns += patterns('', urlpatterns += patterns('',
(r'^notify/', get_notify_pattern()), (r'^notify/', get_notify_pattern()),
(r'', get_wiki_pattern()) (r'', get_wiki_pattern())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment