Re: [mezzanine-users] Moderation support

291 views
Skip to first unread message

Stephen McDonald

unread,
Oct 7, 2012, 3:53:30 PM10/7/12
to mezzani...@googlegroups.com
There's nothing like this at the moment.

There's an open issue for working on scheduled publishing:


Everything else you described would be a welcome addition.

On Mon, Oct 8, 2012 at 4:14 AM, Robin Parmar <robi...@gmail.com> wrote:
I have tried searching for this to no avail. What support does Mezzanine provide for post moderation? My simple use case is a team of writers who need their posts edited and approved before they go live. The workflow is typically:

1. Writer creates a new post in DRAFT mode. May come back to it for several edits.
2. Writer finishes and submits the post. It is now PENDING.
3. Editor gets a notice (email or site message) of a new submission. They can easily browse all PENDING posts.
4. Editor corrects post and PUBLISHES, possibly with a future date. Or they put it aside into an ARCHIVE.
5. When the datestamp occurs, post automatically goes LIVE.

This is basic, so I assume there is a plugin somewhere! TIA.



--
Stephen McDonald
http://jupo.org

Christian Bahls (Gmail)

unread,
Oct 7, 2012, 4:06:19 PM10/7/12
to mezzani...@googlegroups.com
The same would be useful for us :)

On Sun, Oct 7, 2012 at 7:14 PM, Robin Parmar <robi...@gmail.com> wrote:
I have tried searching for this to no avail. What support does Mezzanine provide for post moderation? My simple use case is a team of writers who need their posts edited and approved before they go live. The workflow is typically:

1. Writer creates a new post in DRAFT mode. May come back to it for several edits.
2. Writer finishes and submits the post. It is now PENDING.
3. Editor gets a notice (email or site message) of a new submission. They can easily browse all PENDING posts.
4. Editor corrects post and PUBLISHES, possibly with a future date. Or they put it aside into an ARCHIVE.
5. When the datestamp occurs, post automatically goes LIVE.

This is basic, so I assume there is a plugin somewhere! TIA.



--
I moved away from Google Mail - please use my qb352.de email address

Sean Voss

unread,
Oct 7, 2012, 5:29:03 PM10/7/12
to mezzani...@googlegroups.com
I think I would like to start on this, there seems to be a lot of interest.

Stephen do have time to get a rough set of requirements or ideas on how you'd like it implemented?

My first thought was to have some sort of a model for "publishable_page" which can be of any of the page type with a foreign key to the pages model with an id on the pages model to the primary key publishable_pages.

We could have any number of workflow stages. On that publishable pages.

What do you think of using a state machine plugin?


On the actual scheduling, do you currently have any mechanism for scheduling?

Just throwing out ideas, lemme know.

Stephen McDonald

unread,
Oct 7, 2012, 8:55:04 PM10/7/12
to mezzani...@googlegroups.com
Here's how I see it working. Just thinking out loud at this stage to trigger discussion.

Keep in mind the below is a *very* simple implementation. This fits the overall philosophy that Mezzanine has always taken, which is to require as few dependencies as possible by implementing features in as simple as possible a way, that cover a large use case, but not all (eg thumbnailing, page tree, single blog, content model).

Here's the model for publishing state. It only contains three states, with "pending approval" being the third on top of the two current states "draft" and "published", but it solves the current shortcoming of not being able to have published content that is also in draft mode:

- Each DB record (page, blog post, etc) can exist twice in the DB. If it does, the second copy is in either the "draft" or "pending approval" state, while the first copy is always in the "published" state.
- We implement model managers to query for either state - public records for displaying on the site (eg only things in a published state), and admin records for the admin (eg anything in draft or pending approval state, or anything that is published without a draft state).
- Once the draft/pending copy is published, it overrides the first copy, and the second (draft/pending) record is deleted.
- Each DB record now contains a "published_id" field, which is the ID of the published record, for draft records.
- A new Workflow model exists, which contains two ID fields (for each of the records described above), a user ID (the person who put the record into draft state), and some pointer to the type of content (page, blog post, etc). This is used for generating a task list described later below.

Then for workflow:

- We set up two user groups by default (using standard django.contrib.auth), publishers (can save things as published or draft) and authors (can only save things as draft). We'll call these system groups.
- When an author saves a record, it can only be put into draft state. They see two buttons: "Save as draft", and "Save for approval". If the latter is hit, publishers are emailed with an admin link to the change view for the record.
- When a publisher saves a record, it can be put into either draft or published state. They might see two save buttons which reflect either state, similar to the above buttons.
- We can also implement logic around who gets sent emails for larger groups of people - for example if the author is in a custom user group (eg "Sales", not a system group), and there are publishers in that same group, then we only email those publishers. This gives admins the ability to restrict the workflow (which is simply emails being sent) to smaller groups of users.
- The Workflow model mentioned above is used solely for generating a task list in the admin dashboard. Whenever a record goes into "draft/pending approval" state, a workflow record gets created, with the user ID who made the change. When a record is published (the draft/pending record gets copied then deleted), the workflow record is removed. For editors, their workflow list is all the workflow records with their user ID. For authors, its all the records with "pending approval" state. Extra granularity should be represented here in the same way described above for emailing publishers, if extra non-system groups are defined.

I worked on an unnamed proprietary CMS for several years prior to working on Mezzanine, and many of the lessons learnt from it have shaped Mezzanine. All the above is the workflow model that was used, and for small to medium sized businesses, it was perfect.

I may have left some points out, so please pull this apart.


Sean Voss

unread,
Oct 9, 2012, 1:58:05 AM10/9/12
to mezzani...@googlegroups.com, st...@jupo.org
I think most of your post looks great there.

One thing I am opposed to, is the thought having 2 and only 2 copies of a DB Record. The part about deleting records makes me a bit nervous as well. 

I think you should most definitely have N number of versions of a document, potentially as another record type, and publish any version at any time if you have the rights. This would simply set the "published" id of the page record. 

I've seen this implemented as tables "pages" which has many "page_contents". "page_contents" contains "unique_id", "page_id", "content", "version", and timestamps.

The 2 copies version doesn't seem to gain anything and I think actually makes it more difficult to maintain and therefore more brittle. 

Following with this versions track you would want to be able to load any version into the administration editor and edit it. The dicey parts there is if you edit it then technically it becomes a new version and if you are adding sequentially it's a higher numbered version, since you want to save all versions but there might be changes you want in the middle and so forth. 

The moderation queue works for me more or less as you describe it, I don't think I have much to add there, the pending approval in the versions version could easily contain both the page_contents id, and the page_id. 

So a description to the publishing admin might flash the message like "Sean" wants to publish version 12 of Page "Django Ponies".

Thanks for taking the time to write out your thoughts.

Stephen McDonald

unread,
Oct 10, 2012, 3:40:36 PM10/10/12
to C Heathcott, mezzani...@googlegroups.com
Yes I immediately thought of the reversion app when reading Sean's idea, as he's described exactly what reversion does.

It then raises the question as to whether it's worthwhile trying to reimplement something that's mature and already works (I don't think it is in this case), or whether a better approach would be to try and work out what changes need to be made to Mezzanine to ensure it works smoothly with something like reversion.


On Thu, Oct 11, 2012 at 6:35 AM, C Heathcott <c.hea...@efficientek.com> wrote:
Regarding the versioning, I suggest that you consider using django-reversion, which the 2.4 branch of Grappelli already supports.

Sean Voss

unread,
Oct 10, 2012, 3:53:14 PM10/10/12
to mezzani...@googlegroups.com, C Heathcott, st...@jupo.org
Looking at the GitHub for the django-revisions project, this looks absolutely perfect for what i was talking about.

C Heathcott

unread,
Oct 10, 2012, 4:16:04 PM10/10/12
to mezzani...@googlegroups.com, C Heathcott, st...@jupo.org
There is django-revisions and django-reversion.  The former has been dormant for about two years, whereas the latter is still active and supported by Grappelli 2.4.x.  One immediate obstacle with running Grappelli and Reversion basically "out of the box," is that the 2.4 branch of Grappelli requires the 1.4 branch of Django, and Mezzanine only requires the 1.3 branch of Django.  A second obstacle is that Mezzanine already uses a fork of Grappelli. 

Sean Voss

unread,
Oct 10, 2012, 4:40:49 PM10/10/12
to mezzani...@googlegroups.com, C Heathcott, st...@jupo.org
Sorry yea django-reversion is the one i looked at. 

None of the version problems seem insurmountable, we'd just need to go in and see what the actual changes between 1.3 and 1.4 that are being used by Reversion. Hopefully they aren't too great. 

Do you know the context of why the Grappelli for originally forked, how diverged are the source trees?

C Heathcott

unread,
Oct 11, 2012, 12:46:31 PM10/11/12
to mezzani...@googlegroups.com, st...@jupo.org
I'm admittedly just getting started with Mezzanine, so I'm unable to offer any insight into the motivation behind the Grappelli fork aside from what Stephen wrote in the fork's overview:

"grappelli_safe was created to provide a snapshot of the Grappelli admin skin for Django, to be referenced as a dependency for the Mezzanine CMS for Django.

At the time of grappelli_safe's creation, Grappelli was incorrectly packaged on PyPI, and had also dropped compatibility with Django 1.1 - grappelli_safe was therefore created to address these specific issues.

This repository exists for bug fixes and minor enhancements, and should some day become redundant, once the original Grappelli becomes a feasibly stable dependency target."
 
Regarding that last sentence, it appears to me that significant development has been undertaken on Grappelli, especially in the 2.4 branch with Django-reversion support, since the creation of the Grappelli_safe fork that Mezzanine uses.  Perhaps Stephen can offer more insight into the current state of Grappelli_safe and the future prospects of transitioning back to vanilla Grappelli.

Anyhow, integrating django-reversion into Mezzanine in some form or fashion is definitely a task with which I'd like to help.

C Heathcott

unread,
Oct 11, 2012, 1:18:15 PM10/11/12
to mezzani...@googlegroups.com, st...@jupo.org
I just did a quick test of django-reversion with a model that simply extends Mezzanine Page and RichText, and I am able to see and edit among versions in the change history, so perhaps django-reversion integration is actually rather trivial.  I'm going to explore what features the Grappelli 2.4 branch has added beyond what I get "out of the box" from django-reversion, and I'll report back to this tread later today.

Ken Bolton

unread,
Oct 11, 2012, 1:21:48 PM10/11/12
to mezzani...@googlegroups.com
Unless the philosophy of Django and Mezzanine both change abruptly,
support for the canonical version of Grappelli is unlikely. The reason
is that Mezzanine supports both the current stable release of Django –
1.4 at this moment – and one prior release – 1.3. This is modeled on
Django's support of Python's current stable, 2.7, and *two* prior
releases. Grappelli's current releases, 2.3.9 and 2.4.0, require
Django 1.3 and 1.4 respectively.

I think we are far more likely to see Grappelli dropped from Mezzanine
rather than the new versions integrated.

ken

C Heathcott

unread,
Oct 11, 2012, 4:47:48 PM10/11/12
to mezzani...@googlegroups.com
I noticed a feature request in Mezzanine's issue tracker for replacing Grappelli with django-admintools-bootstrap, but that topic has been quiet for about 7 months.  From my limited exposure to both admin wrappers, the former seems much more polished than the latter, but in the long run it also seems desirable for Mezzanine to use the same HTML/CSS/JavaScript framework in the admin as on the user facing content.

Concerning the narrower scope of this thread, after some quick testing of the 2.4 branch of Grappelli, the only extra feature I've noticed with respect to django-reversion is functionality for recovering deleted objects.  Otherwise, the versioned change history seems the same in Grappelli 2.4.x as it does in Grappelli_safe included in Mezzanine.

Shaurya Chaudhuri

unread,
Aug 24, 2016, 11:39:28 AM8/24/16
to Mezzanine Users, st...@jupo.org

Hi,

I was thinking to start working on this. I have looked at what everyone suggests. I believe that the user should be able to post multiple updates to a post. I made a flowchart depicting the flow of data after a post has been saved. 



I have recently started using mezzanine , and not sure if about the existing django user groups in mezzanine. If someone could give me some insight about them, would be good.


Regards,

Shaurya


Reply all
Reply to author
Forward
0 new messages