Commits

Artur Barseghyan  committed 9ddb796 Draft

rename the project to werewolf

  • Participants
  • Parent commits d8d390d

Comments (0)

Files changed (53)

File docs/Makefile

 	@echo
 	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
 	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
-	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-warewolf.qhcp"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-werewolf.qhcp"
 	@echo "To view the help file:"
-	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-warewolf.qhc"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-werewolf.qhc"
 
 devhelp:
 	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
 	@echo
 	@echo "Build finished."
 	@echo "To view the help file:"
-	@echo "# mkdir -p $$HOME/.local/share/devhelp/django-warewolf"
-	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-warewolf"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/django-werewolf"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-werewolf"
 	@echo "# devhelp"
 
 epub:

File docs/conf.py

 # -*- coding: utf-8 -*-
 #
-# django-warewolf documentation build configuration file, created by
+# django-werewolf documentation build configuration file, created by
 # sphinx-quickstart on Sat Jun 15 22:37:33 2013.
 #
 # This file is execfile()d with the current directory set to its containing dir.
 master_doc = 'index'
 
 # General information about the project.
-project = u'django-warewolf'
+project = u'django-werewolf'
 copyright = u'2013, Artur Barseghyan <artur.barseghyan@gmail.com>'
 
 # The version info for the project you're documenting, acts as replacement for
 #html_file_suffix = None
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = 'django-warewolfdoc'
+htmlhelp_basename = 'django-werewolfdoc'
 
 
 # -- Options for LaTeX output --------------------------------------------------
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title, author, documentclass [howto/manual]).
 latex_documents = [
-  ('index', 'django-warewolf.tex', u'django-warewolf Documentation',
+  ('index', 'django-werewolf.tex', u'django-werewolf Documentation',
    u'Artur Barseghyan \\textless{}artur.barseghyan@gmail.com\\textgreater{}', 'manual'),
 ]
 
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    ('index', 'django-warewolf', u'django-warewolf Documentation',
+    ('index', 'django-werewolf', u'django-werewolf Documentation',
      [u'Artur Barseghyan <artur.barseghyan@gmail.com>'], 1)
 ]
 
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
 texinfo_documents = [
-  ('index', 'django-warewolf', u'django-warewolf Documentation',
-   u'Artur Barseghyan <artur.barseghyan@gmail.com>', 'django-warewolf', 'One line description of project.',
+  ('index', 'django-werewolf', u'django-werewolf Documentation',
+   u'Artur Barseghyan <artur.barseghyan@gmail.com>', 'django-werewolf', 'One line description of project.',
    'Miscellaneous'),
 ]
 
 # -- Options for Epub output ---------------------------------------------------
 
 # Bibliographic Dublin Core info.
-epub_title = u'django-warewolf'
+epub_title = u'django-werewolf'
 epub_author = u'Artur Barseghyan <artur.barseghyan@gmail.com>'
 epub_publisher = u'Artur Barseghyan <artur.barseghyan@gmail.com>'
 epub_copyright = u'2013, Artur Barseghyan <artur.barseghyan@gmail.com>'

File docs/index.rst

 Package
 ==================================
-django-warewolf
+django-werewolf
 
 Description
 ==================================
 
 Installation
 ==================================
-1. Install django-warewolf into your virtual environment:
+1. Install django-werewolf into your virtual environment:
 
-    $ pip install django-warewolf
+    $ pip install django-werewolf
 
-2. Add `warewolf` to your ``INSTALLED_APPS``.
+2. Add `werewolf` to your ``INSTALLED_APPS``.
 
 That's all. See the `Usage and examples` section for more.
 
 to `published`, some others not. This app allows you (and gives you a good working example with pre-configured django
 environment) to write a custom workflow for publishing your items with minimal efforts.
 
-For a complete example of a working django-warewolf app see the https://bitbucket.org/barseghyanartur/django-warewolf
+For a complete example of a working django-werewolf app see the https://bitbucket.org/barseghyanartur/django-werewolf
 (example directory) and read the `readme.rst` of the `news` app.
 
 settings.py
 
 >>> from django.contrib.auth.models import User
 >>>
->>> from warewolf.models import WarewolfBaseModel, WarewolfBaseMeta
+>>> from werewolf.models import WerewolfBaseModel, WerewolfBaseMeta
 >>>
 >>> _chief_editors = {'groups__name__iexact': 'Chief editors'}
 >>> _editors = {'groups__name__iexact': 'Editors'}
 >>> _writers = {'groups__name__iexact': 'Writers'}
 >>>
->>> class NewsItem(WarewolfBaseModel): # Important!
+>>> class NewsItem(WerewolfBaseModel): # Important!
 >>>     title = models.CharField(_("Title"), max_length=100)
 >>>     body = models.TextField(_("Body"))
 >>>     date_published = models.DateTimeField(_("Date published"), default=datetime.datetime.now())
 >>>     chief_editor = models.ForeignKey(User, verbose_name=_("Chief editor"), related_name='chief_editors', \
 >>>                                      limit_choices_to=_chief_editors)
 >>>
->>>     class Meta(WarewolfBaseMeta): # Important!
+>>>     class Meta(WerewolfBaseMeta): # Important!
 >>>         verbose_name = "News item"
 >>>         verbose_name_plural = "News items"
 
-Or if you want to define custom permissions for your model as well, do extend the warewolf permissions as follows:
+Or if you want to define custom permissions for your model as well, do extend the werewolf permissions as follows:
 
->>> from warewolf.models import WarewolfBaseModel
->>> from warewolf.utils import extend_warewolf_permissions
+>>> from werewolf.models import WerewolfBaseModel
+>>> from werewolf.utils import extend_werewolf_permissions
 >>>
->>> class NewsItem(WarewolfBaseModel):
+>>> class NewsItem(WerewolfBaseModel):
 >>>     # Your fields here
 >>>     class Meta:
 >>>         verbose_name = "News item"
 >>>         verbose_name_plural = "News items"
 >>>
 >>>         # Important!
->>>         permissions = extend_warewolf_permissions(
+>>>         permissions = extend_werewolf_permissions(
 >>>             ('can_change_author', _("Can change author")),
 >>>             ('can_change_editor', _("Can change editor")),
 >>>             ('can_change_chief_editor', _("Can change chief editor"))
 
 NOTE: See the `Permission tuning` section.
 
->>> from warewolf.admin import WarewolfBaseAdmin
+>>> from werewolf.admin import WerewolfBaseAdmin
 >>>
 >>> from news.models import NewsItem
 >>>
->>> class NewsItemAdmin(WarewolfBaseAdmin):
+>>> class NewsItemAdmin(WerewolfBaseAdmin):
 >>>     # Your code comes here
 >>>
 >>> admin.site.register(NewsItem, NewsItemAdmin)
 
 NOTE: If you override the ``queryset`` method of your model's admin class, make sure to see the source code of
-`warewolf.admin.WarewolfBaseAdmin.queryset` and copy the approach from there. Otherwise, your users with no permission
+`werewolf.admin.WerewolfBaseAdmin.queryset` and copy the approach from there. Otherwise, your users with no permission
 to change the `published` status will be able to chgange the status of already published items to non-published
 statuses.
 
 >>>     news_items = NewsItem._default_manager.published()
 >>>     # Other code
 
-news/warewolf_triggers.py
+news/werewolf_triggers.py
 ----------------------------------
 In order to perform extra tasks on status change, triggers are used. You simply make a new file in your app called
-`warewolf_triggers.py` and define custom classes that should be called when a ``status`` field of your model changes
-to a certain value. Each trigger should subclass the ``warewolf.triggers.WarewolfBaseTrigger`` class.
+`werewolf_triggers.py` and define custom classes that should be called when a ``status`` field of your model changes
+to a certain value. Each trigger should subclass the ``werewolf.triggers.WerewolfBaseTrigger`` class.
 
->>> from warewolf.triggers import WarewolfBaseTrigger, registry
+>>> from werewolf.triggers import WerewolfBaseTrigger, registry
 >>>
->>> class StatusNewTrigger(WarewolfBaseTrigger):
+>>> class StatusNewTrigger(WerewolfBaseTrigger):
 >>>     """
 >>>     News item status changed to `new`.
 >>>     """
 >>>     def process(self):
 >>>         # Your code
 >>>
->>> class StatusReadyTrigger(WarewolfBaseTrigger):
+>>> class StatusReadyTrigger(WerewolfBaseTrigger):
 >>>     """
 >>>     News item status changed to `ready` (ready for review).
 >>>     """
 ----------------------------------
 In order to have triggers autodiscovered, place the following code into your main `urls` module.
 
->>> from warewolf import autodiscover as warewolf_autodiscover
->>> warewolf_autodiscover()
+>>> from werewolf import autodiscover as werewolf_autodiscover
+>>> werewolf_autodiscover()
 
 Permission tuning
 ----------------------------------
 
 Running the example project
 ==================================
-A working example of a django-warewolf app is available here: https://bitbucket.org/barseghyanartur/django-warewolf
+A working example of a django-werewolf app is available here: https://bitbucket.org/barseghyanartur/django-werewolf
 (see the `example` directory).
 
 1. Go to example/example directory
 .. toctree::
    :maxdepth: 20
 
-   warewolf
+   werewolf
 
 Indices and tables
 ==================================

File docs/warewolf.management.commands.rst

-commands Package
-================
-
-:mod:`syncww` Module
---------------------
-
-.. automodule:: warewolf.management.commands.syncww
-    :members:
-    :undoc-members:
-    :show-inheritance:
-

File docs/warewolf.management.rst

-management Package
-==================
-
-Subpackages
------------
-
-.. toctree::
-
-    warewolf.management.commands
-

File docs/warewolf.models.rst

-models Package
-==============
-
-:mod:`models` Package
----------------------
-
-.. automodule:: warewolf.models
-    :members:
-    :show-inheritance:
-
-:mod:`managers` Module
-----------------------
-
-.. automodule:: warewolf.models.managers
-    :members:
-    :show-inheritance:
-

File docs/warewolf.rst

-warewolf Package
-================
-
-:mod:`warewolf` Package
------------------------
-
-.. automodule:: warewolf.__init__
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`admin` Module
--------------------
-
-.. automodule:: warewolf.admin
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`helpers` Module
----------------------
-
-.. automodule:: warewolf.helpers
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`triggers` Module
-----------------------
-
-.. automodule:: warewolf.triggers
-    :members:
-    :show-inheritance:
-
-:mod:`utils` Module
--------------------
-
-.. automodule:: warewolf.utils
-    :members:
-    :show-inheritance:
-
-Subpackages
------------
-
-.. toctree::
-
-    warewolf.management
-    warewolf.models
-

File docs/werewolf.management.commands.rst

+commands Package
+================
+
+:mod:`syncww` Module
+--------------------
+
+.. automodule:: werewolf.management.commands.syncww
+    :members:
+    :undoc-members:
+    :show-inheritance:
+

File docs/werewolf.management.rst

+management Package
+==================
+
+Subpackages
+-----------
+
+.. toctree::
+
+    werewolf.management.commands
+

File docs/werewolf.models.rst

+models Package
+==============
+
+:mod:`models` Package
+---------------------
+
+.. automodule:: werewolf.models
+    :members:
+    :show-inheritance:
+
+:mod:`managers` Module
+----------------------
+
+.. automodule:: werewolf.models.managers
+    :members:
+    :show-inheritance:
+

File docs/werewolf.rst

+werewolf Package
+================
+
+:mod:`werewolf` Package
+-----------------------
+
+.. automodule:: werewolf.__init__
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`admin` Module
+-------------------
+
+.. automodule:: werewolf.admin
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`helpers` Module
+---------------------
+
+.. automodule:: werewolf.helpers
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`triggers` Module
+----------------------
+
+.. automodule:: werewolf.triggers
+    :members:
+    :show-inheritance:
+
+:mod:`utils` Module
+-------------------
+
+.. automodule:: werewolf.utils
+    :members:
+    :show-inheritance:
+
+Subpackages
+-----------
+
+.. toctree::
+
+    werewolf.management
+    werewolf.models
+

File example-docs/conf.py

 # -*- coding: utf-8 -*-
 #
-# django-warewolf-example documentation build configuration file, created by
+# django-werewolf-example documentation build configuration file, created by
 # sphinx-quickstart on Sat Jun 15 22:31:07 2013.
 #
 # This file is execfile()d with the current directory set to its containing dir.
 master_doc = 'index'
 
 # General information about the project.
-project = u'django-warewolf-example'
+project = u'django-werewolf-example'
 copyright = u'2013, Artur Barseghyan <artur.barseghyan@gmail.com>'
 
 # The version info for the project you're documenting, acts as replacement for
 #html_file_suffix = None
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = 'django-warewolf-exampledoc'
+htmlhelp_basename = 'django-werewolf-exampledoc'
 
 
 # -- Options for LaTeX output --------------------------------------------------
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title, author, documentclass [howto/manual]).
 latex_documents = [
-  ('index', 'django-warewolf-example.tex', u'django-warewolf-example Documentation',
+  ('index', 'django-werewolf-example.tex', u'django-werewolf-example Documentation',
    u'Artur Barseghyan \\textless{}artur.barseghyan@gmail.com\\textgreater{}', 'manual'),
 ]
 
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    ('index', 'django-warewolf-example', u'django-warewolf-example Documentation',
+    ('index', 'django-werewolf-example', u'django-werewolf-example Documentation',
      [u'Artur Barseghyan <artur.barseghyan@gmail.com>'], 1)
 ]
 
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
 texinfo_documents = [
-  ('index', 'django-warewolf-example', u'django-warewolf-example Documentation',
-   u'Artur Barseghyan <artur.barseghyan@gmail.com>', 'django-warewolf-example', 'One line description of project.',
+  ('index', 'django-werewolf-example', u'django-werewolf-example Documentation',
+   u'Artur Barseghyan <artur.barseghyan@gmail.com>', 'django-werewolf-example', 'One line description of project.',
    'Miscellaneous'),
 ]
 
 # -- Options for Epub output ---------------------------------------------------
 
 # Bibliographic Dublin Core info.
-epub_title = u'django-warewolf-example'
+epub_title = u'django-werewolf-example'
 epub_author = u'Artur Barseghyan <artur.barseghyan@gmail.com>'
 epub_publisher = u'Artur Barseghyan <artur.barseghyan@gmail.com>'
 epub_copyright = u'2013, Artur Barseghyan <artur.barseghyan@gmail.com>'

File example/example/local_settings.example

 
 DEFAULT_FROM_EMAIL = '<no-reply@example.com>'
 
-WAREWOLF_USE_DJANGO_REVERSION = True
+WEREWOLF_USE_DJANGO_REVERSION = True

File example/example/news/admin.py

 from django.forms.models import modelform_factory
 from django.contrib.admin.util import flatten_fieldsets
 
-from warewolf.admin import WarewolfBaseAdmin
+from werewolf.admin import WerewolfBaseAdmin
 
 from news.models import NewsItem
 from news.constants import PERMISSION_CAN_CHANGE_AUTHOR, PERMISSION_CAN_CHANGE_EDITOR
 from news.constants import PERMISSION_CAN_CHANGE_CHIEF_EDITOR
 
-class NewsItemAdmin(WarewolfBaseAdmin):
+class NewsItemAdmin(WerewolfBaseAdmin):
     """
     News item admin.
     """

File example/example/news/models.py

 from django.contrib.auth.models import User
 from django.core.exceptions import ValidationError
 
-from warewolf.models import WarewolfBaseModel
-from warewolf.utils import extend_warewolf_permissions
+from werewolf.models import WerewolfBaseModel
+from werewolf.utils import extend_werewolf_permissions
 
 from news.constants import PERMISSION_CAN_CHANGE_AUTHOR, PERMISSION_CAN_CHANGE_EDITOR
 from news.constants import PERMISSION_CAN_CHANGE_CHIEF_EDITOR
 _writers = {'groups__name__iexact': 'Writers'}
 
 
-class NewsItem(WarewolfBaseModel):
+class NewsItem(WerewolfBaseModel):
     """
     News item.
 
         verbose_name = _("News item")
         verbose_name_plural = _("News items")
 
-        permissions = extend_warewolf_permissions(
+        permissions = extend_werewolf_permissions(
             (PERMISSION_CAN_CHANGE_AUTHOR, _("Can change author")),
             (PERMISSION_CAN_CHANGE_EDITOR, _("Can change editor")),
             (PERMISSION_CAN_CHANGE_CHIEF_EDITOR, _("Can change chief editor"))

File example/example/news/warewolf_triggers.py

-import datetime
-
-from django.utils.translation import ugettext_lazy as _
-from django.contrib.auth.models import User
-
-from warewolf.triggers import WarewolfBaseTrigger, registry
-from warewolf.helpers import admin_edit_url_for_object
-
-from lime import send_email
-
-from news.settings import CHIEF_EDITORS_GROUP_NAME
-
-
-class StatusNewTrigger(WarewolfBaseTrigger):
-    """
-    News item status changed to `new`.
-    """
-    def process(self):
-        author = self.obj.author
-        editor = self.obj.editor
-        edit_url = admin_edit_url_for_object(self.obj)
-        send_email(
-            _('A new News Item has been assigned to you'),
-            editor.email,
-            author.email,
-            {
-                'date_submitted': datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
-                'url': edit_url,
-                'full_name': author.get_full_name(),
-                'from_name': editor.get_full_name(),
-            },
-            'news/emails/new_newsitem.txt',
-            'news/emails/new_newsitem.html'
-        )
-
-
-class StatusDraftTrigger(WarewolfBaseTrigger):
-    """
-    News item status changed to `draft`.
-    """
-    def process(self):
-        # do things here as in previous examples if needed
-        pass
-
-
-class StatusReadyTrigger(WarewolfBaseTrigger):
-    """
-    News item status changed to `ready` (ready for review).
-    """
-    def process(self):
-        author = self.obj.author
-        editor = self.obj.editor
-        edit_url = admin_edit_url_for_object(self.obj)
-        send_email(
-            _('A News Item is ready for review!'),
-            author.email,
-            editor.email,
-            {
-                'date_submitted': datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
-                'url': edit_url,
-                'full_name': editor.get_full_name(),
-                'from_name': author.get_full_name(),
-            },
-            'news/emails/ready_newsitem.txt',
-            'news/emails/ready_newsitem.html'
-        )
-
-
-class StatusReviewedTrigger(WarewolfBaseTrigger):
-    """
-    News item status changed to `reviewed`.
-    """
-    def process(self):
-        author = self.obj.author
-        editor = self.obj.editor
-        edit_url = admin_edit_url_for_object(self.obj)
-        send_email(
-            _('A News Item has been reviewed!'),
-            author.email,
-            editor.email,
-            {
-                'date_submitted': datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
-                'url': edit_url,
-                'full_name': editor.get_full_name(),
-                'from_name': author.get_full_name(),
-            },
-            'news/emails/reviewed_newsitem.txt',
-            'news/emails/reviewed_newsitem.html'
-        )
-
-
-class StatusPublishedTrigger(WarewolfBaseTrigger):
-    """
-    News item status changed to `published`.
-    """
-    def process(self):
-        editor = self.obj.editor
-        edit_url = admin_edit_url_for_object(self.obj)
-        send_email(
-            _('A News Item has been published!'),
-            [u.email for u in User._default_manager.filter(groups__name=CHIEF_EDITORS_GROUP_NAME).only('email')],
-            editor.email,
-            {
-                'date_submitted': datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
-                'url': edit_url,
-                'front_url': self.obj.get_absolute_url(),
-                'full_name': _("Chief editor"),
-                'from_name': editor.get_full_name(),
-            },
-            'news/emails/published_newsitem.txt',
-            'news/emails/published_newsitem.html'
-        )
-
-
-registry.register('news', 'newsitem', 'new', StatusNewTrigger)
-registry.register('news', 'newsitem', 'ready', StatusReadyTrigger)
-registry.register('news', 'newsitem', 'reviewed', StatusReviewedTrigger)
-registry.register('news', 'newsitem', 'published', StatusPublishedTrigger)
-registry.register('news', 'newsitem', 'draft', StatusDraftTrigger)

File example/example/news/werewolf_triggers.py

+import datetime
+
+from django.utils.translation import ugettext_lazy as _
+from django.contrib.auth.models import User
+
+from werewolf.triggers import WerewolfBaseTrigger, registry
+from werewolf.helpers import admin_edit_url_for_object
+
+from lime import send_email
+
+from news.settings import CHIEF_EDITORS_GROUP_NAME
+
+
+class StatusNewTrigger(WerewolfBaseTrigger):
+    """
+    News item status changed to `new`.
+    """
+    def process(self):
+        author = self.obj.author
+        editor = self.obj.editor
+        edit_url = admin_edit_url_for_object(self.obj)
+        send_email(
+            _('A new News Item has been assigned to you'),
+            editor.email,
+            author.email,
+            {
+                'date_submitted': datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
+                'url': edit_url,
+                'full_name': author.get_full_name(),
+                'from_name': editor.get_full_name(),
+            },
+            'news/emails/new_newsitem.txt',
+            'news/emails/new_newsitem.html'
+        )
+
+
+class StatusDraftTrigger(WerewolfBaseTrigger):
+    """
+    News item status changed to `draft`.
+    """
+    def process(self):
+        # do things here as in previous examples if needed
+        pass
+
+
+class StatusReadyTrigger(WerewolfBaseTrigger):
+    """
+    News item status changed to `ready` (ready for review).
+    """
+    def process(self):
+        author = self.obj.author
+        editor = self.obj.editor
+        edit_url = admin_edit_url_for_object(self.obj)
+        send_email(
+            _('A News Item is ready for review!'),
+            author.email,
+            editor.email,
+            {
+                'date_submitted': datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
+                'url': edit_url,
+                'full_name': editor.get_full_name(),
+                'from_name': author.get_full_name(),
+            },
+            'news/emails/ready_newsitem.txt',
+            'news/emails/ready_newsitem.html'
+        )
+
+
+class StatusReviewedTrigger(WerewolfBaseTrigger):
+    """
+    News item status changed to `reviewed`.
+    """
+    def process(self):
+        author = self.obj.author
+        editor = self.obj.editor
+        edit_url = admin_edit_url_for_object(self.obj)
+        send_email(
+            _('A News Item has been reviewed!'),
+            author.email,
+            editor.email,
+            {
+                'date_submitted': datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
+                'url': edit_url,
+                'full_name': editor.get_full_name(),
+                'from_name': author.get_full_name(),
+            },
+            'news/emails/reviewed_newsitem.txt',
+            'news/emails/reviewed_newsitem.html'
+        )
+
+
+class StatusPublishedTrigger(WerewolfBaseTrigger):
+    """
+    News item status changed to `published`.
+    """
+    def process(self):
+        editor = self.obj.editor
+        edit_url = admin_edit_url_for_object(self.obj)
+        send_email(
+            _('A News Item has been published!'),
+            [u.email for u in User._default_manager.filter(groups__name=CHIEF_EDITORS_GROUP_NAME).only('email')],
+            editor.email,
+            {
+                'date_submitted': datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
+                'url': edit_url,
+                'front_url': self.obj.get_absolute_url(),
+                'full_name': _("Chief editor"),
+                'from_name': editor.get_full_name(),
+            },
+            'news/emails/published_newsitem.txt',
+            'news/emails/published_newsitem.html'
+        )
+
+
+registry.register('news', 'newsitem', 'new', StatusNewTrigger)
+registry.register('news', 'newsitem', 'ready', StatusReadyTrigger)
+registry.register('news', 'newsitem', 'reviewed', StatusReviewedTrigger)
+registry.register('news', 'newsitem', 'published', StatusPublishedTrigger)
+registry.register('news', 'newsitem', 'draft', StatusDraftTrigger)

File example/example/settings.py

     # 'django.contrib.admindocs',
 
     'reversion', # Content versioning
-    'warewolf', # Yet another workflow app
+    'werewolf', # Yet another workflow app
     'lime', # Mixed content e-mails
 
     'news', # Our news example

File example/example/urls.py

 
 # Uncomment the next two lines to enable the admin:
 from django.contrib import admin
-from warewolf import autodiscover as warewolf_autodiscover
+from werewolf import autodiscover as werewolf_autodiscover
 
 admin.autodiscover()
-warewolf_autodiscover()
+werewolf_autodiscover()
 
 urlpatterns = patterns('',
     # Examples:

File example/requirements.txt

 django-lime==0.2
 django-reversion==1.6.5
 django-tinymce==1.5.1
-django-warewolf==0.1
+django-werewolf
 ipdb==0.7
 ipython==0.13.2
 python-dateutil==2.1
 Package
 ==================================
-django-warewolf
+django-werewolf
 
 Description
 ==================================
 
 Installation
 ==================================
-1. Install django-warewolf into your virtual environment:
+1. Install django-werewolf into your virtual environment:
 
-    $ pip install django-warewolf
+    $ pip install django-werewolf
 
-2. Add `warewolf` to your ``INSTALLED_APPS``.
+2. Add `werewolf` to your ``INSTALLED_APPS``.
 
 That's all. See the `Usage and examples` section for more.
 
 to `published`, some others not. This app allows you (and gives you a good working example with pre-configured django
 environment) to write a custom workflow for publishing your items with minimal efforts.
 
-For a complete example of a working django-warewolf app see the https://bitbucket.org/barseghyanartur/django-warewolf
+For a complete example of a working django-werewolf app see the https://bitbucket.org/barseghyanartur/django-werewolf
 (example directory) and read the `readme.rst` of the `news` app.
 
 settings.py
 
 >>> from django.contrib.auth.models import User
 >>>
->>> from warewolf.models import WarewolfBaseModel, WarewolfBaseMeta
+>>> from werewolf.models import WerewolfBaseModel, WerewolfBaseMeta
 >>>
 >>> _chief_editors = {'groups__name__iexact': 'Chief editors'}
 >>> _editors = {'groups__name__iexact': 'Editors'}
 >>> _writers = {'groups__name__iexact': 'Writers'}
 >>>
->>> class NewsItem(WarewolfBaseModel): # Important!
+>>> class NewsItem(WerewolfBaseModel): # Important!
 >>>     title = models.CharField(_("Title"), max_length=100)
 >>>     body = models.TextField(_("Body"))
 >>>     date_published = models.DateTimeField(_("Date published"), default=datetime.datetime.now())
 >>>     chief_editor = models.ForeignKey(User, verbose_name=_("Chief editor"), related_name='chief_editors', \
 >>>                                      limit_choices_to=_chief_editors)
 >>>
->>>     class Meta(WarewolfBaseMeta): # Important!
+>>>     class Meta(WerewolfBaseMeta): # Important!
 >>>         verbose_name = "News item"
 >>>         verbose_name_plural = "News items"
 
-Or if you want to define custom permissions for your model as well, do extend the warewolf permissions as follows:
+Or if you want to define custom permissions for your model as well, do extend the werewolf permissions as follows:
 
->>> from warewolf.models import WarewolfBaseModel
->>> from warewolf.utils import extend_warewolf_permissions
+>>> from werewolf.models import WerewolfBaseModel
+>>> from werewolf.utils import extend_werewolf_permissions
 >>>
->>> class NewsItem(WarewolfBaseModel):
+>>> class NewsItem(WerewolfBaseModel):
 >>>     # Your fields here
 >>>     class Meta:
 >>>         verbose_name = "News item"
 >>>         verbose_name_plural = "News items"
 >>>
 >>>         # Important!
->>>         permissions = extend_warewolf_permissions(
+>>>         permissions = extend_werewolf_permissions(
 >>>             ('can_change_author', _("Can change author")),
 >>>             ('can_change_editor', _("Can change editor")),
 >>>             ('can_change_chief_editor', _("Can change chief editor"))
 
 NOTE: See the `Permission tuning` section.
 
->>> from warewolf.admin import WarewolfBaseAdmin
+>>> from werewolf.admin import WerewolfBaseAdmin
 >>>
 >>> from news.models import NewsItem
 >>>
->>> class NewsItemAdmin(WarewolfBaseAdmin):
+>>> class NewsItemAdmin(WerewolfBaseAdmin):
 >>>     # Your code comes here
 >>>
 >>> admin.site.register(NewsItem, NewsItemAdmin)
 
 NOTE: If you override the ``queryset`` method of your model's admin class, make sure to see the source code of
-`warewolf.admin.WarewolfBaseAdmin.queryset` and copy the approach from there. Otherwise, your users with no permission
+`werewolf.admin.WerewolfBaseAdmin.queryset` and copy the approach from there. Otherwise, your users with no permission
 to change the `published` status will be able to chgange the status of already published items to non-published
 statuses.
 
 >>>     news_items = NewsItem._default_manager.published()
 >>>     # Other code
 
-news/warewolf_triggers.py
+news/werewolf_triggers.py
 ----------------------------------
 In order to perform extra tasks on status change, triggers are used. You simply make a new file in your app called
-`warewolf_triggers.py` and define custom classes that should be called when a ``status`` field of your model changes
-to a certain value. Each trigger should subclass the ``warewolf.triggers.WarewolfBaseTrigger`` class.
+`werewolf_triggers.py` and define custom classes that should be called when a ``status`` field of your model changes
+to a certain value. Each trigger should subclass the ``werewolf.triggers.WerewolfBaseTrigger`` class.
 
->>> from warewolf.triggers import WarewolfBaseTrigger, registry
+>>> from werewolf.triggers import WerewolfBaseTrigger, registry
 >>>
->>> class StatusNewTrigger(WarewolfBaseTrigger):
+>>> class StatusNewTrigger(WerewolfBaseTrigger):
 >>>     """
 >>>     News item status changed to `new`.
 >>>     """
 >>>     def process(self):
 >>>         # Your code
 >>>
->>> class StatusReadyTrigger(WarewolfBaseTrigger):
+>>> class StatusReadyTrigger(WerewolfBaseTrigger):
 >>>     """
 >>>     News item status changed to `ready` (ready for review).
 >>>     """
 ----------------------------------
 In order to have triggers autodiscovered, place the following code into your main `urls` module.
 
->>> from warewolf import autodiscover as warewolf_autodiscover
->>> warewolf_autodiscover()
+>>> from werewolf import autodiscover as werewolf_autodiscover
+>>> werewolf_autodiscover()
 
 Permission tuning
 ----------------------------------
 
 Running the example project
 ==================================
-A working example of a django-warewolf app is available here: https://bitbucket.org/barseghyanartur/django-warewolf
+A working example of a django-werewolf app is available here: https://bitbucket.org/barseghyanartur/django-werewolf
 (see the `example` directory).
 
 1. Go to example/example directory
 version = '0.1'
 
 setup(
-    name='django-warewolf',
+    name='django-werewolf',
     version=version,
     description=("Item publishing workflow for Django."),
     long_description=readme,
     keywords='workflow, publishing',
     author='Artur Barseghyan',
     author_email='artur.barseghyan@gmail.com',
-    url='https://bitbucket.org/barseghyanartur/django-warewolf',
+    url='https://bitbucket.org/barseghyanartur/django-werewolf',
     package_dir={'':'src'},
     packages=find_packages(where='./src'),
     license='GPL 2.0/LGPL 2.1',

File src/warewolf/__init__.py

-import imp
-
-from django.conf import settings
-
-def autodiscover():
-    """
-    Autodiscovers the warewolf in project apps. Each report file which should be found by warewolf, should be
-    named "warewolf_triggers.py".
-    """
-    from django.conf import settings
-
-    WAREWOLF_TRIGGERS_MODULE_NAME = 'warewolf_triggers'
-
-    for app in settings.INSTALLED_APPS:
-        try:
-            app_path = __import__(app, {}, {}, [app.split('.')[-1]]).__path__
-        except AttributeError:
-            continue
-
-        try:
-            imp.find_module(WAREWOLF_TRIGGERS_MODULE_NAME, app_path)
-        except ImportError:
-            continue
-        __import__('%s.%s' % (app, WAREWOLF_TRIGGERS_MODULE_NAME))

File src/warewolf/admin.py

-__all__ = ('WarewolfBaseAdmin',)
-
-from django.contrib import admin
-from django import forms
-
-from warewolf.utils import status_choices_for_user
-from warewolf.triggers import registry
-from warewolf.settings import USE_DJANGO_REVERSION, DEFAULT_STATUS
-
-if USE_DJANGO_REVERSION:
-    import reversion
-    from reversion.admin import VersionAdmin
-    AdminParentClass = VersionAdmin
-    create_on_success = reversion.revision.create_on_success
-else:
-    AdminParentClass = admin.ModelAdmin
-    def create_on_success(func):
-        """
-        A do-nothing replacement if we're not using django-reversion.
-        """
-        return func
-
-
-class WarewolfBaseAdmin(AdminParentClass):
-    """
-    Base warewolf admin model.
-    """
-    def formfield_for_dbfield(self, db_field, **kwargs):
-        """
-        Here we replace the choices based on the user permissions.
-        """
-        if 'status' == db_field.name:
-            status_choices = status_choices_for_user(kwargs['request'].user, self.model._meta.app_label)
-            field = forms.ChoiceField(choices=status_choices, required=True, initial=DEFAULT_STATUS)
-            return field
-
-        return super(WarewolfBaseAdmin, self).formfield_for_dbfield(db_field, **kwargs)
-
-    def queryset(self, request):
-        """
-        Make sure users with no rights to edit an object with status, don't even see it.
-        """
-        status_choices = dict(status_choices_for_user(request.user, self.model._meta.app_label)).keys()
-        return super(WarewolfBaseAdmin, self).queryset(request).filter(status__in=status_choices)
-
-    def status_change_trigger(self, request, obj, form, change):
-        """
-        Status change trigger. Executes appropriate registered trigger if applicable.
-
-        :param django.http.HttpRequest request:
-        :param django.db.models.Model obj: Subclass of ``django.db.models.Model``.
-        :param form:
-        :param bool change:
-        """
-        # It's important to perform the checks after the
-        if 'status' in form.changed_data:
-            Trigger = registry.get_for_model(obj, obj.status)
-            if Trigger:
-                trigger = Trigger(obj=obj, request=request)
-                trigger.process()
-
-    def save_model(self, request, obj, form, change):
-        super(WarewolfBaseAdmin, self).save_model(request, obj, form, change)
-
-        self.status_change_trigger(request, obj, form, change)

File src/warewolf/conf.py

-from django.conf import settings
-
-from warewolf import defaults
-
-def get_setting(setting, override=None):
-    """
-    Get a setting from `warewolf` conf module, falling back to the default.
-
-    If override is not None, it will be used instead of the setting.
-    """
-    if override is not None:
-        return override
-    if hasattr(settings, 'WAREWOLF_%s' % setting):
-        return getattr(settings, 'WAREWOLF_%s' % setting)
-    else:
-        return getattr(defaults, setting)

File src/warewolf/constants.py

-# Don't touch this!
-CHANGE_STATUS_TO = 'change_status_to'
-CAN_VIEW_STATUS = 'can_view_status'

File src/warewolf/defaults.py

-gettext = lambda s: s
-
-# Status choices for the workflow. When customizing pay extra attention to `STATUS_PUBLISHED` and `DEFAULT_STATUS`
-# as they should match those set in `STATUS_CHOICES`. Order is preserved.
-STATUS_CHOICES = (
-    ('new', gettext('New')), # New - this is how it's assigned to a writer.
-    ('draft', gettext('Draft')), # Draft - this is how the writer works on it.
-    ('ready', gettext('Ready')), # Ready to be reviewed by editor.
-    ('reviewed', gettext('Reviewed')), # Reviewed by editor (means positive and ready to be published).
-    ('published', gettext('Published')), # Published.
-)
-
-# Published status.
-STATUS_PUBLISHED = 'published'
-
-# Default status. Be careful with this. All users must have permissions to this status. Otherwise, set to None.
-DEFAULT_STATUS = None
-
-# It's unlikely that you're going to exceed the 50 chars limit for the status. Still, possible to customise.
-STATUS_MAX_LENGTH = 50
-
-# When set to True, django-reversion is used.
-USE_DJANGO_REVERSION = True

File src/warewolf/helpers.py

-__all__ = ('admin_edit_url', 'admin_edit_url_for_object')
-
-from django.core.urlresolvers import reverse
-
-def admin_edit_url(app_label, module_name, object_id, url_title=None):
-    """
-    Gets an admin edit URL for the object given.
-
-    :param str app_label:
-    :param str module_name:
-    :param int object_id:
-    :param str url_title: If given, an HTML a tag is returned with `url_title` as the tag title. If left to None
-        just the URL string is returned.
-    :return str:
-    """
-    try:
-        url = reverse('admin:%s_%s_change' %(app_label, module_name), args=[object_id])
-        if url_title:
-            return u'<a href="%s">%s</a>' %(url, url_title)
-        else:
-            return url
-    except:
-        return None
-
-def admin_edit_url_for_object(obj, url_title=None):
-    """
-    Gets an admin edit URL for the object given.
-
-    :param django.db.models.Model obj: Django model subclass.
-    :param str url_title: If given, an HTML a tag is returned with `url_title` as the tag title. If left to None
-        just the URL string is returned.
-    :return str:
-    """
-    return admin_edit_url(obj._meta.app_label, obj._meta.module_name, obj.id, url_title)

File src/warewolf/management/__init__.py

Empty file removed.

File src/warewolf/management/commands/__init__.py

Empty file removed.

File src/warewolf/management/commands/syncww.py

-from django.core.management.base import BaseCommand
-from django.db.models import get_models, get_app
-from django.contrib.auth.management import create_permissions
-
-class Command(BaseCommand):
-    args = '<app app ...>'
-    help = 'reloads permissions for specified apps, or all apps if no args are specified'
-
-    def handle(self, *args, **options):
-        if not args:
-            apps = []
-            for model in get_models():
-                apps.append(get_app(model._meta.app_label))
-        else:
-            apps = []
-            for arg in args:
-                apps.append(get_app(arg))
-
-        for app in apps:
-            create_permissions(app, get_models(), options.get('verbosity', 0))

File src/warewolf/models/__init__.py

-__all__ = ('WarewolfBaseMeta', 'WarewolfBaseModel')
-
-from django.db import models
-from django.utils.translation import ugettext_lazy as _
-
-from warewolf.models.managers import WarewolfBaseManager
-from warewolf.utils import extend_warewolf_permissions
-from warewolf.conf import get_setting
-
-STATUS_CHOICES = get_setting('STATUS_CHOICES')
-DEFAULT_STATUS = get_setting('DEFAULT_STATUS')
-STATUS_MAX_LENGTH = get_setting('STATUS_MAX_LENGTH')
-
-
-class WarewolfBaseMeta(object):
-    """
-    Base Meta class of the ``WarewolfBaseModel``. Every subclass of the ``WarewolfBaseModel`` shall extend it:
-    
-    >>> from warewolf.models import WarewolfBaseModel, WarewolfBaseMeta
-    >>> class NewsItem(WarewolfBaseModel): # Important!
-    >>>     # Your fields here
-    >>>     class Meta(WarewolfBaseMeta): # Important!
-    >>>         verbose_name = "News item"
-    >>>         verbose_name_plural = "News items"
-
-    Alternatively you can add the ``permissions`` attribute:
-
-    >>> from warewolf.utils import extend_warewolf_permissions
-    >>> class NewsItem(WarewolfBaseModel):
-    >>>     # Your fields here
-    >>>     class Meta:
-    >>>         verbose_name = "News item"
-    >>>         verbose_name_plural = "News items"
-    >>>         permissions = extend_warewolf_permissions(
-    >>>             ('can_change_author', _("Can change author")),
-    >>>             ('can_change_editor', _("Can change editor")),
-    >>>         )
-    """
-    permissions = extend_warewolf_permissions()
-
-
-class WarewolfBaseModel(models.Model):
-    """
-    Base Warewolf model. If you want to have a workflow in your model (for statuses like new, draft, published, etc)
-    you should extend this model.
-    """
-    status = models.CharField(_("Status"), max_length=STATUS_MAX_LENGTH, choices=STATUS_CHOICES, default=DEFAULT_STATUS)
-
-    objects = WarewolfBaseManager()
-
-    class Meta(WarewolfBaseMeta):
-        abstract = True

File src/warewolf/models/managers.py

-__all__ = ('WarewolfBaseManager',)
-
-from django.db import models
-
-from warewolf.settings import STATUS_PUBLISHED
-
-
-class WarewolfBaseManager(models.Manager):
-    """
-    Warewolf base manager.
-    """
-    def published(self):
-        return self.filter(status__exact=STATUS_PUBLISHED)

File src/warewolf/requirements.txt

-Django==1.5.1
-django-reversion==1.6.5

File src/warewolf/settings.py

-__all__ = ('STATUS_CHOICES', 'STATUS_PUBLISHED', 'DEFAULT_STATUS', 'STATUS_MAX_LENGTH', 'USE_DJANGO_REVERSION')
-
-from warewolf.conf import get_setting
-
-STATUS_CHOICES = get_setting('STATUS_CHOICES')
-
-STATUS_PUBLISHED = get_setting('STATUS_PUBLISHED')
-
-DEFAULT_STATUS = get_setting('DEFAULT_STATUS')
-
-STATUS_MAX_LENGTH = get_setting('STATUS_MAX_LENGTH')
-
-USE_DJANGO_REVERSION = get_setting('USE_DJANGO_REVERSION')

File src/warewolf/triggers.py

-__all__ = ('WarewolfBaseTrigger', 'registry')
-
-class WarewolfBaseTrigger(object):
-    """
-    Warewolf base trigger.
-    """
-    def __init__(self, obj, request):
-        self.obj = obj
-        self.requeset = request
-
-    def process(self):
-        raise NotImplementedError("You should define a ``process`` method in your trigger class!")
-
-class WarewolfRegistry(object):
-    """
-    Trigger registry.
-
-    Register all your warewolf triggers subclassed from ``warewolf.triggers.WarewolfBaseTrigger`` as follows:
-    >>> from warewolf.triggers import WarewolfBaseTrigger, registry
-    >>> 
-    >>> # Our trigger
-    >>> class StatusExampleTrigger(WarewolfBaseTrigger):
-    >>>     def process(self):
-    >>>         print 'status triggered'
-    >>> 
-    >>> registry.register('your-app-label', 'your-module-name', 'status-to-catch', StatusExampleTrigger)
-    """
-    def __init__(self):
-        self._registry = {}
-
-    def __make_key(self, app_label, module_name, status):
-        return '%s.%s:%status' % (app_label, module_name, status)
-
-    def register(self, app_label, module_name, status, trigger_class):
-        """
-        Registers the trigger into the global registry.
-
-        :param str app_label:
-        :param str module_name:
-        :param str status:
-        :param str warewolf.triggers.WarewolfBaseTrigger: Subclass of ``warewolf.triggers.WarewolfBaseTrigger``.
-        """
-        self._registry[self.__make_key(app_label, module_name, status)] = trigger_class
-
-    def register_for_model(self, model, status, trigger_class):
-        self._registry[self.__make_key(model._metal.app_label, model._meta.module_name, status)] = trigger_class
-
-    def get(self, app_label, module_name, status):
-        """
-        Gets the trigger from global trigger registry.
-
-        :param str app_label:
-        :param str module_name:
-        :param str status:
-        :return warewolf.triggers.WarewolfBaseTrigger: Subclass of ``warewolf.triggers.WarewolfBaseTrigger``.
-        """
-        key = self.__make_key(app_label, module_name, status)
-        if self._registry.has_key(key):
-            return self._registry[key]
-
-    def get_for_model(self, model, status):
-        return self.get(model._meta.app_label, model._meta.module_name, status)
-
-# Register triggers by calling registry.register()
-registry = WarewolfRegistry()

File src/warewolf/utils.py

-__all__ = ('permission_key', 'permissions_for_base_model', 'status_choices_for_user', 'extend_warewolf_permissions')
-
-from django.utils.translation import ugettext_lazy as _
-
-from warewolf.settings import STATUS_CHOICES
-from warewolf.constants import CHANGE_STATUS_TO #, CAN_VIEW_STATUS
-
-CHOICES = dict(STATUS_CHOICES)
-
-CHOICES_KEYS = [choice[0] for choice in STATUS_CHOICES]
-
-
-def permission_key(status, choice_key):
-    """
-    Gets the permission key from ``choice_key`` given.
-
-    :param str status:
-    :param str choice_key:
-    :return str:
-    """
-    return '%s_%s' % (status, choice_key)
-
-
-def permissions_for_base_model(permissions=[]):
-    """
-    Gets/extends permissions for the base model based on the ``STATUS_CHOICES`` defined.
-
-    :param list|tuple permissions: Permissions you want to have in your model. Those permissions would be extended
-        by warewolf permissions.
-    :return list:
-    """
-    warewolf_permissions = []
-    for choice_key in CHOICES_KEYS:
-        warewolf_permissions.append((permission_key(CHANGE_STATUS_TO, choice_key), _("Can change status to %s") % choice_key))
-        # Not sure if this shall be taken out. This allows viewsing the status. Leave out for now.
-        #permissions.append((permission_key(CAN_VIEW_STATUS, choice_key), _("Can view status %s") % choice_key))
-
-    if isinstance(permissions, list):
-        warewolf_permissions.extend(permissions)
-    elif isinstance(permissions, tuple):
-        permissions = list(permissions)
-        warewolf_permissions.extend(permissions)
-
-    return warewolf_permissions
-
-
-def extend_warewolf_permissions(*args):
-    """
-    Extends model permissions with warewolf permissions.
-
-    :example:
-    >>> from warewolf.models import WarewolfBaseModel
-    >>> from warewolf.utils import extend_warewolf_permissions
-    >>> class NewsItem(WarewolfBaseModel):
-    >>>     # Some fields here
-    >>>
-    >>>     class Meta:
-    >>>         verbose_name = _("News item")
-    >>>         verbose_name_plural = _("News items")
-    >>>
-    >>>         permissions = extend_warewolf_permissions(
-    >>>             ('can_change_author', _("Can change author")),
-    >>>             ('can_change_editor', _("Can change editor")),
-    >>>             ('can_change_chief_editor', _("Can change chief editor"))
-    >>>         )
-    """
-    return permissions_for_base_model(args)
-
-
-def status_choices_for_user(user, app_label):
-    """
-    Gets available status choices for the user given.
-
-    :param django.contrib.auth.models.User user: User for who the permissions are checked.
-    :param str module_name: `app_label` of the model to check permissions to.
-    :return list: List of choices in a same form as ``warewolf.defaults.STATUS_CHOICES`` but then limited to actual
-        choices that user has permissions to.
-    """
-    statuses = []
-    for choice_key in CHOICES_KEYS:
-        if user.has_perm('%s.%s' % (app_label, permission_key(CHANGE_STATUS_TO, choice_key))):
-            statuses.append((choice_key, CHOICES[choice_key]))
-
-    return statuses
-
-
-def trigger_import(app_label, module_name, status):
-    """
-    Dynamically imports the trigger class for the status change.
-
-    :deprecated: Use ``warewolf.triggers.registry.register`` instead.
-
-    :param str app_label:
-    :param str module_name:
-    :param str status:
-    :return warewolf.triggers.WarewolfBaseTrigger: Subclass of ``warewolf.triggers.WarewolfBaseTrigger``.
-    """
-    try:
-        exec "from %s.warewolf_triggers import Status%s%sTrigger as Trigger" % (app_label, module_name, status.title())
-        return Trigger
-    except:
-        pass

File src/werewolf/__init__.py

+import imp
+
+from django.conf import settings
+
+def autodiscover():
+    """
+    Autodiscovers the werewolf in project apps. Each report file which should be found by werewolf, should be
+    named "werewolf_triggers.py".
+    """
+    from django.conf import settings
+
+    WEREWOLF_TRIGGERS_MODULE_NAME = 'werewolf_triggers'
+
+    for app in settings.INSTALLED_APPS:
+        try:
+            app_path = __import__(app, {}, {}, [app.split('.')[-1]]).__path__
+        except AttributeError:
+            continue
+
+        try:
+            imp.find_module(WEREWOLF_TRIGGERS_MODULE_NAME, app_path)
+        except ImportError:
+            continue
+        __import__('%s.%s' % (app, WEREWOLF_TRIGGERS_MODULE_NAME))

File src/werewolf/admin.py

+__all__ = ('WerewolfBaseAdmin',)
+
+from django.contrib import admin
+from django import forms
+
+from werewolf.utils import status_choices_for_user
+from werewolf.triggers import registry
+from werewolf.settings import USE_DJANGO_REVERSION, DEFAULT_STATUS
+
+if USE_DJANGO_REVERSION:
+    import reversion
+    from reversion.admin import VersionAdmin
+    AdminParentClass = VersionAdmin
+    create_on_success = reversion.revision.create_on_success
+else:
+    AdminParentClass = admin.ModelAdmin
+    def create_on_success(func):
+        """
+        A do-nothing replacement if we're not using django-reversion.
+        """
+        return func
+
+
+class WerewolfBaseAdmin(AdminParentClass):
+    """
+    Base werewolf admin model.
+    """
+    def formfield_for_dbfield(self, db_field, **kwargs):
+        """
+        Here we replace the choices based on the user permissions.
+        """
+        if 'status' == db_field.name:
+            status_choices = status_choices_for_user(kwargs['request'].user, self.model._meta.app_label)
+            field = forms.ChoiceField(choices=status_choices, required=True, initial=DEFAULT_STATUS)
+            return field
+
+        return super(WerewolfBaseAdmin, self).formfield_for_dbfield(db_field, **kwargs)
+
+    def queryset(self, request):
+        """
+        Make sure users with no rights to edit an object with status, don't even see it.
+        """
+        status_choices = dict(status_choices_for_user(request.user, self.model._meta.app_label)).keys()
+        return super(WerewolfBaseAdmin, self).queryset(request).filter(status__in=status_choices)
+
+    def status_change_trigger(self, request, obj, form, change):
+        """
+        Status change trigger. Executes appropriate registered trigger if applicable.
+
+        :param django.http.HttpRequest request:
+        :param django.db.models.Model obj: Subclass of ``django.db.models.Model``.
+        :param form:
+        :param bool change:
+        """
+        # It's important to perform the checks after the
+        if 'status' in form.changed_data:
+            Trigger = registry.get_for_model(obj, obj.status)
+            if Trigger:
+                trigger = Trigger(obj=obj, request=request)
+                trigger.process()
+
+    def save_model(self, request, obj, form, change):
+        super(WerewolfBaseAdmin, self).save_model(request, obj, form, change)
+
+        self.status_change_trigger(request, obj, form, change)

File src/werewolf/conf.py

+from django.conf import settings
+
+from werewolf import defaults
+
+def get_setting(setting, override=None):
+    """
+    Get a setting from `werewolf` conf module, falling back to the default.
+
+    If override is not None, it will be used instead of the setting.
+    """
+    if override is not None:
+        return override
+    if hasattr(settings, 'WEREWOLF_%s' % setting):
+        return getattr(settings, 'WEREWOLF_%s' % setting)
+    else:
+        return getattr(defaults, setting)

File src/werewolf/constants.py

+# Don't touch this!
+CHANGE_STATUS_TO = 'change_status_to'
+CAN_VIEW_STATUS = 'can_view_status'

File src/werewolf/defaults.py

+gettext = lambda s: s
+
+# Status choices for the workflow. When customizing pay extra attention to `STATUS_PUBLISHED` and `DEFAULT_STATUS`
+# as they should match those set in `STATUS_CHOICES`. Order is preserved.
+STATUS_CHOICES = (
+    ('new', gettext('New')), # New - this is how it's assigned to a writer.
+    ('draft', gettext('Draft')), # Draft - this is how the writer works on it.
+    ('ready', gettext('Ready')), # Ready to be reviewed by editor.
+    ('reviewed', gettext('Reviewed')), # Reviewed by editor (means positive and ready to be published).
+    ('published', gettext('Published')), # Published.
+)
+
+# Published status.
+STATUS_PUBLISHED = 'published'
+
+# Default status. Be careful with this. All users must have permissions to this status. Otherwise, set to None.
+DEFAULT_STATUS = None
+
+# It's unlikely that you're going to exceed the 50 chars limit for the status. Still, possible to customise.
+STATUS_MAX_LENGTH = 50
+
+# When set to True, django-reversion is used.
+USE_DJANGO_REVERSION = True

File src/werewolf/helpers.py

+__all__ = ('admin_edit_url', 'admin_edit_url_for_object')
+
+from django.core.urlresolvers import reverse
+
+def admin_edit_url(app_label, module_name, object_id, url_title=None):
+    """
+    Gets an admin edit URL for the object given.
+
+    :param str app_label:
+    :param str module_name:
+    :param int object_id:
+    :param str url_title: If given, an HTML a tag is returned with `url_title` as the tag title. If left to None
+        just the URL string is returned.
+    :return str:
+    """
+    try:
+        url = reverse('admin:%s_%s_change' %(app_label, module_name), args=[object_id])
+        if url_title:
+            return u'<a href="%s">%s</a>' %(url, url_title)
+        else:
+            return url
+    except:
+        return None
+
+def admin_edit_url_for_object(obj, url_title=None):
+    """
+    Gets an admin edit URL for the object given.
+
+    :param django.db.models.Model obj: Django model subclass.
+    :param str url_title: If given, an HTML a tag is returned with `url_title` as the tag title. If left to None
+        just the URL string is returned.
+    :return str:
+    """
+    return admin_edit_url(obj._meta.app_label, obj._meta.module_name, obj.id, url_title)

File src/werewolf/management/__init__.py

Empty file added.

File src/werewolf/management/commands/__init__.py

Empty file added.

File src/werewolf/management/commands/syncww.py

+from django.core.management.base import BaseCommand
+from django.db.models import get_models, get_app
+from django.contrib.auth.management import create_permissions
+
+class Command(BaseCommand):
+    args = '<app app ...>'
+    help = 'reloads permissions for specified apps, or all apps if no args are specified'
+
+    def handle(self, *args, **options):
+        if not args:
+            apps = []
+            for model in get_models():
+                apps.append(get_app(model._meta.app_label))
+        else:
+            apps = []
+            for arg in args:
+                apps.append(get_app(arg))
+
+        for app in apps:
+            create_permissions(app, get_models(), options.get('verbosity', 0))

File src/werewolf/models/__init__.py

+__all__ = ('WerewolfBaseMeta', 'WerewolfBaseModel')
+
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+from werewolf.models.managers import WerewolfBaseManager
+from werewolf.utils import extend_werewolf_permissions
+from werewolf.conf import get_setting
+
+STATUS_CHOICES = get_setting('STATUS_CHOICES')
+DEFAULT_STATUS = get_setting('DEFAULT_STATUS')
+STATUS_MAX_LENGTH = get_setting('STATUS_MAX_LENGTH')
+
+
+class WerewolfBaseMeta(object):
+    """
+    Base Meta class of the ``WerewolfBaseModel``. Every subclass of the ``WerewolfBaseModel`` shall extend it:
+    
+    >>> from werewolf.models import WerewolfBaseModel, WerewolfBaseMeta
+    >>> class NewsItem(WerewolfBaseModel): # Important!
+    >>>     # Your fields here
+    >>>     class Meta(WerewolfBaseMeta): # Important!
+    >>>         verbose_name = "News item"
+    >>>         verbose_name_plural = "News items"
+
+    Alternatively you can add the ``permissions`` attribute:
+
+    >>> from werewolf.utils import extend_werewolf_permissions
+    >>> class NewsItem(WerewolfBaseModel):
+    >>>     # Your fields here
+    >>>     class Meta:
+    >>>         verbose_name = "News item"
+    >>>         verbose_name_plural = "News items"
+    >>>         permissions = extend_werewolf_permissions(
+    >>>             ('can_change_author', _("Can change author")),
+    >>>             ('can_change_editor', _("Can change editor")),
+    >>>         )
+    """
+    permissions = extend_werewolf_permissions()
+
+
+class WerewolfBaseModel(models.Model):
+    """
+    Base Werewolf model. If you want to have a workflow in your model (for statuses like new, draft, published, etc)
+    you should extend this model.
+    """
+    status = models.CharField(_("Status"), max_length=STATUS_MAX_LENGTH, choices=STATUS_CHOICES, default=DEFAULT_STATUS)
+
+    objects = WerewolfBaseManager()
+
+    class Meta(WerewolfBaseMeta):
+        abstract = True

File src/werewolf/models/fields.py

+__all__ = ('StatusField',)
+
+from django.db import models
+
+from werewolf.settings import STATUS_CHOICES
+
+
+class StatusField(models.CharField):
+    def __init__(self, *args, **kwargs):
+        super(StatusField, self).__init__(*args, **kwargs)
+
+    def formfield(self, **kwargs):
+        defaults = {'max_length': self.max_length}
+        defaults.update(kwargs)
+        defaults.update(choices=STATUS_CHOICES)
+        return super(StatusField, self).formfield(**defaults)
+
+# Add schema's for South
+try:
+    from south.modelsinspector import add_introspection_rules
+    add_introspection_rules(
+        rules=[((StatusField,), [], {})], \
+        patterns=['werewolf.models\.fields\.StatusField',]
+        )
+except ImportError:
+    pass

File src/werewolf/models/managers.py

+__all__ = ('WerewolfBaseManager',)
+
+from django.db import models
+
+from werewolf.settings import STATUS_PUBLISHED
+
+
+class WerewolfBaseManager(models.Manager):
+    """
+    Werewolf base manager.
+    """
+    def published(self):
+        return self.filter(status__exact=STATUS_PUBLISHED)

File src/werewolf/requirements.txt

+Django==1.5.1
+django-reversion==1.6.5

File src/werewolf/settings.py

+__all__ = ('STATUS_CHOICES', 'STATUS_PUBLISHED', 'DEFAULT_STATUS', 'STATUS_MAX_LENGTH', 'USE_DJANGO_REVERSION')
+
+from werewolf.conf import get_setting
+
+STATUS_CHOICES = get_setting('STATUS_CHOICES')
+
+STATUS_PUBLISHED = get_setting('STATUS_PUBLISHED')
+
+DEFAULT_STATUS = get_setting('DEFAULT_STATUS')
+
+STATUS_MAX_LENGTH = get_setting('STATUS_MAX_LENGTH')
+
+USE_DJANGO_REVERSION = get_setting('USE_DJANGO_REVERSION')

File src/werewolf/triggers.py

+__all__ = ('WerewolfBaseTrigger', 'registry')
+
+class WerewolfBaseTrigger(object):
+    """
+    Werewolf base trigger.
+    """
+    def __init__(self, obj, request):
+        self.obj = obj
+        self.requeset = request
+
+    def process(self):
+        raise NotImplementedError("You should define a ``process`` method in your trigger class!")
+
+class WerewolfRegistry(object):
+    """
+    Trigger registry.
+
+    Register all your werewolf triggers subclassed from ``werewolf.triggers.WerewolfBaseTrigger`` as follows:
+    >>> from werewolf.triggers import WerewolfBaseTrigger, registry
+    >>> 
+    >>> # Our trigger
+    >>> class StatusExampleTrigger(WerewolfBaseTrigger):
+    >>>     def process(self):
+    >>>         print 'status triggered'
+    >>> 
+    >>> registry.register('your-app-label', 'your-module-name', 'status-to-catch', StatusExampleTrigger)
+    """
+    def __init__(self):
+        self._registry = {}
+
+    def __make_key(self, app_label, module_name, status):
+        return '%s.%s:%status' % (app_label, module_name, status)
+
+    def register(self, app_label, module_name, status, trigger_class):
+        """
+        Registers the trigger into the global registry.
+
+        :param str app_label:
+        :param str module_name:
+        :param str status:
+        :param str werewolf.triggers.WerewolfBaseTrigger: Subclass of ``werewolf.triggers.WerewolfBaseTrigger``.
+        """
+        self._registry[self.__make_key(app_label, module_name, status)] = trigger_class
+
+    def register_for_model(self, model, status, trigger_class):
+        self._registry[self.__make_key(model._metal.app_label, model._meta.module_name, status)] = trigger_class
+
+    def get(self, app_label, module_name, status):
+        """
+        Gets the trigger from global trigger registry.
+
+        :param str app_label:
+        :param str module_name:
+        :param str status:
+        :return werewolf.triggers.WerewolfBaseTrigger: Subclass of ``werewolf.triggers.WerewolfBaseTrigger``.
+        """
+        key = self.__make_key(app_label, module_name, status)
+        if self._registry.has_key(key):
+            return self._registry[key]
+
+    def get_for_model(self, model, status):
+        return self.get(model._meta.app_label, model._meta.module_name, status)
+
+# Register triggers by calling registry.register()
+registry = WerewolfRegistry()

File src/werewolf/utils.py

+__all__ = ('permission_key', 'permissions_for_base_model', 'status_choices_for_user', 'extend_werewolf_permissions')
+
+from django.utils.translation import ugettext_lazy as _
+
+from werewolf.settings import STATUS_CHOICES
+from werewolf.constants import CHANGE_STATUS_TO #, CAN_VIEW_STATUS
+
+CHOICES = dict(STATUS_CHOICES)
+
+CHOICES_KEYS = [choice[0] for choice in STATUS_CHOICES]
+
+
+def permission_key(status, choice_key):
+    """
+    Gets the permission key from ``choice_key`` given.
+
+    :param str status:
+    :param str choice_key:
+    :return str:
+    """
+    return '%s_%s' % (status, choice_key)
+
+
+def permissions_for_base_model(permissions=[]):
+    """
+    Gets/extends permissions for the base model based on the ``STATUS_CHOICES`` defined.
+
+    :param list|tuple permissions: Permissions you want to have in your model. Those permissions would be extended
+        by werewolf permissions.
+    :return list:
+    """
+    werewolf_permissions = []
+    for choice_key in CHOICES_KEYS:
+        werewolf_permissions.append((permission_key(CHANGE_STATUS_TO, choice_key), _("Can change status to %s") % choice_key))
+        # Not sure if this shall be taken out. This allows viewsing the status. Leave out for now.
+        #permissions.append((permission_key(CAN_VIEW_STATUS, choice_key), _("Can view status %s") % choice_key))
+
+    if isinstance(permissions, list):
+        werewolf_permissions.extend(permissions)
+    elif isinstance(permissions, tuple):
+        permissions = list(permissions)
+        werewolf_permissions.extend(permissions)
+
+    return werewolf_permissions
+
+
+def extend_werewolf_permissions(*args):
+    """
+    Extends model permissions with werewolf permissions.
+
+    :example:
+    >>> from werewolf.models import WerewolfBaseModel
+    >>> from werewolf.utils import extend_werewolf_permissions
+    >>> class NewsItem(WerewolfBaseModel):
+    >>>     # Some fields here
+    >>>
+    >>>     class Meta:
+    >>>         verbose_name = _("News item")
+    >>>         verbose_name_plural = _("News items")
+    >>>
+    >>>         permissions = extend_werewolf_permissions(
+    >>>             ('can_change_author', _("Can change author")),
+    >>>             ('can_change_editor', _("Can change editor")),
+    >>>             ('can_change_chief_editor', _("Can change chief editor"))
+    >>>         )
+    """
+    return permissions_for_base_model(args)
+
+
+def status_choices_for_user(user, app_label):
+    """
+    Gets available status choices for the user given.
+
+    :param django.contrib.auth.models.User user: User for who the permissions are checked.
+    :param str module_name: `app_label` of the model to check permissions to.
+    :return list: List of choices in a same form as ``werewolf.defaults.STATUS_CHOICES`` but then limited to actual
+        choices that user has permissions to.
+    """
+    statuses = []
+    for choice_key in CHOICES_KEYS:
+        if user.has_perm('%s.%s' % (app_label, permission_key(CHANGE_STATUS_TO, choice_key))):
+            statuses.append((choice_key, CHOICES[choice_key]))
+
+    return statuses
+
+
+def trigger_import(app_label, module_name, status):
+    """