This includes a number of new features:
* Move some moderation functionality into shared places, so we don't
keep re-inventing the wheel.
* Implement three-state moderation, where the submitter can edit their
item and then explicitly say "i'm done, please moderate this now".
This is currently only implemented for News, but done in a reusable
way.
* Move moderation workflow to it's own set of URLs instead of
overloading it on the general admin interface. Admin interface remains
for editing things, but these are now separated out into separate
things.
* Do proper stylesheet clearing for moderation of markdown fields, using
a dynamic sandboxed iframe, so it's not ruined by the /admin/ css.
* Move moderation email notification into dedicated moderation code,
thereby simplifying the admin subclassing we did which was in some
places quite fragile.
* Reset date of news postings to the date of their approval, when
approved. This avoids some annoying ordering issues.
The way signals are sent for many2many apparently changed completely
between the python2 and python3 versions of the same Django version,
which broke the way we did this before. And it was always a bit of a
hack...
Instead, reimplement notifications in the simple_form handler. This now
also consolidates regular field notificationss and many2many
notifications in a much cleaner way.
This will, however, *only* have an effect on changes made through
simple_form. Luckily that's the most common way we handle forms, with
the exception being /admin/. So leave the old code in place to handle
the changes through /admin/, as well as the deletion of objects.
In the end the only thing lost is the ability to get m2m differences
when an admin makes changes, and that's the least important of all
notification. And as a bonus, the regular change notifications and in
particular "new item" notifications look a lot nicer.
Django 1.11 fires the save signals in more cases than 1.8 did it seems,
so we can generate extra notifications for example when the twitter
script posts a news item to twitter.
To avoid this, just don't send notification if the user is unknown
(=None).
Per discussion with Jonathan
If the m2m field is optional, there will be no "pre" data available, not
even an empty one. Don't crash in this case, just assume it's empty
(which it is).
This could happen when adding a new Organisation, which currently is the
only model we have with optional m2m fields
Unfortunately, we'll send one email for each m2m field, instead of
collecting them to a single one. That's because there is no signal
delivered at the end of them all, there will be one sent for each field.
Luckily we don't have a lot of m2m fields at this point, and no model
has more than one, so at this point that part is not a problem.
It also means that if a regular field *and* an m2m field is changed,
then we will get two notifications.
Finally, enable these notifications for the Organisation fields, meaning
we will get a notification when an Organisation changes managers, which
was not working before.
Instead of reporting the integer value of the foreign key, we should
report the text value from the related object. This makes the new
submissions more readable, and also makes the system not throw an
exception when trying to diff (as integers cannot be diffed).
THis seems to have broken around the time of the 1.8 upgrade, just went
unnoticed for a long time probably because changing things like which
organization owns a news item doesn't happen very often.
Previous code triggered a conversion from unicode to ascii inside the
django framework, which would throw an exception when the object itself
returned unicode in the name.
The new version will work around that by actually checking the primary
key first.
This still doesn't work insofar that any changes to a many2many fields
are now lost. This did not work properly before either, but this
probably made it a bit work. We definitely need to fix this properly at
some point, probably by using the m2m_changed signal handler (but it's
not straight forward as this is now a separate signal and we'll somehow
want to track this indepdendently)
We were already using signals for everything except delete, and even
in our old version of django the delete signal exists (it didn't exist
when this code was first written).
Django doesn't really like models to be OOP like this, so keeping PgModel
would cause issues with upcoming changes in django 1.8. Using simple functions
is easier, and the actual functionality is replicated straight off.