John,

Nice. Thanks for this.

Rob
On Thursday 15 March 2007 10:35:47 pm john habermann wrote:
> I thought I would follow up my own post explaining how I come up with
> the solution to get the comment workflow to work as I wanted, so at
> least if other run into the same problem and come looking on the list
> they won't find an unanswered question something I personally find
> very frustrating :) It is a bit of a detailed post so apologies to
> peoples inboxes.
>
> The problems I had and things that I wanted to do with commenting in
> COREBlog2 where:
>
> 1. Creating an easy to use workflow to allow my bloggers to process
> comments that are submitted to their blog entries. Requirements where to
> allow a simple "Publish" or "Reject" from the state drop down and that this
> process be as
> simple as possible, Ideally blogger would have a specific role and not
> have to be made a manager in order to make the interface as simple as
> possible.
>
> 2. Email notifications for comments where easy to understand and worked
> in mozilla-thunderbird as by default they where unreadable in
> thunderbird due to every character being spaced apart.
>
> 3. Spam via comments and trackbacks should be reduced to an absolute
> minimum as to not turn off our bloggers from the process. Having them
> being barraged by spam and spending all their time time rejecting
> these would really reduce the appeal of a blog.
>
> 4. Commentors would be notified by email when their comment was approved.
> This was something requested by our bloggers as a courteous thing to do.
>
>
> 1. SETTING UP A SMOOTH WORKFLOW FOR COMMENT APPROVAL
>
> I created an editor role that had the following permissions to my
> editor role in the root plone site permissions tab:
>
>
> ATContentTypes: Add Document
> ATContentTypes: Add Event
> ATContentTypes: Add File
> ATContentTypes: Add Image
> ATContentTypes: Add Link
> ATContentTypes: Add News Item
>
> Access contents information
> Add portal content
> List folder contents
> Modify portal content
> Request review
> View
>
> I initially had real problems understanding what was happening in the
> permissions as they didn't seem to work, but the problems was due to
> me falsely assuming that all the folder objects and the articles would
> by default just be aquiring their permissions from the root folder but
> that was not the case. The article folder was not aquiring from the
> root in case of the "modify portal content" permission nor where the
> articles themselves set to aquire for that permission.
>
> You need to look at the workflow that applies to objects as that
> determines what permissions they are created with or at least the
> settings of those permissions that are managed by the workflow.
>
> There where 4 permissions managed by the cb_comments_workflow, which
> was just a copy of the plone_default_workflow I had made:
>
> Access contents information
> Change portal events
> Modify portal content
> View
>
> Each state has its own specific security settings which you can
> control by clicking on the "Permissions" tab for that state. For
> example when an object is in the "Pending" state the Reviewer role is
> given all the 4 permissions while when and object is in "Published"
> state only the Manager role has permission to edit the object.
>
> For the cb_comment_workflow I just needed 3 states:
>
> Pending (set this to the default state)
> Published
> Rejected ( a new state I created)
>
> and 3 transitions:
>
> Publish
> Reject
> Submit
>
> I deleted all other states and transitions. My bloggers are added to
> an Editors group which has been given the editor role. All bloggers
> are also placed in the Reviewers Group.
>
> REJECTING COMMENTS
>
> After thinking initially that I would have the reject transition just
> delete the rejected comments I thought it might be better to have a
> system they are kept available for historical purposes so switching
> them to a state where they are not visible to my bloggers or anonymous
> users would be a better option.
>
> One way I have thought that I could do it was to have reject be set to
> make the state of the comment private and private to be only viewable by
> the manager. This might have the added benefit of keeping the comments
> for historical puposes. The manger could easily go in and chose the
> delete option to clean out all obvious spam ones now and then but to a
> person who doesn't have the manager role they would effectively deleted.
>
> I changed the state that the reject transition changes to from visible
> to private. That works the comment disappears from the review list as it
> is not in the pending state but it doesn't appear to anonymous users as
> the private state has the view permission only allowed in Manager and
> Owner.
>
> The manager will see the comments as still showing in recent comments
> portlet but others won't. To delete the comments the manager just needs
> to go to
> http://simpson.wilderness.org.au:8081/test/blog/comments/folder_contents
> to see the full list of comments. The ones that have been set to private
> can be reviewed and cleaned out if they are spam but it might be that
> ones that are rejected from legitimate people who have made
> inappropriate comments could be kept, perhaps moved to another folder.
> However when I tested trying to move the comments to another folder I
> found that I wasn't allowed, I guess because they are strongly
> associated with their parent entry.
>
> What I found though was that if I rejected a comment as a user with the
> "Editor" role they would be shown a login page as they didn't have
> permission to see private comments and the default behaviour is to show
> the comment in its new state. I thought that the easiest way to deal
> with this would simply be to add a script to the reject transition that
> redirects the user to the blog root so they can just continue on with
> their review process.
>
> This turned out to be a long exercise in frustration though as even
> though I eventually figured out how to get a redirect to occur using the
> ObjectMoved method which the state_change object has it would still only
> work if you had permission to view objects in the private state.
>
> This is the way you can easily do redirects on a page that you have
> permissions:
>
> return
> context.REQUEST.RESPONSE.redirect(context.portal_url.getPortalPath() +
> '/blog')
>
> and you see it being used in various products. However this wouldn't do
> anything when called from a script running off a transition even when
> running the script logged in as manager.
>
> The following script would perform a redirect when called from a
> transition but only if you had rights to view the new object:
>
> ------------------------------
> obj = state_change.object
> obj.plone_log('Beginning redirect_to script')
>
> url = obj.portal_url.getPortalObject()
> obj.plone_log(url)
>
> rootobj = context.portal_url.getPortalObject()
>
> id = obj.id
> obj.plone_log(id)
>
> newobj = state_change.new_state
> newid = newobj.id
> newobj.plone_log(newid)
>
> conid = context.id
> context.plone_log(conid)
>
> raise state_change.ObjectMoved(newobj, url)
> ------------------------------------
>
> I also tried altering the comment view template to perform a redirect
> but once again the permission are such that the redirect is not called
> because permissions block the page before it loads the redirect.
>
> CREATING A NEW STATE AND MODIFYING COREBLOG2
>
> Ok I had given up on the idea of making use of the private state and
> decided to see what happened if I created a state. I added a rejected
> state to the cb_commments workflow and made it the state that the reject
> transition moves an object to. Changing it to this state removes it from
> the Review list but they still display in the comment listing and the
> recent comment entries portlet.
>
> I then had to look at changing the COREBLog2 code to not display
> comments in the rejected state.
>
> There is a portlet_global_recent_comment.pt file which is not
> displayed in the portlets but offered a way to restrict the search of
> comments that are displayed.
>
> I copied this file to portlet_tws_recent_comment.pt and then added
> "review_state='published'" to the portal_catalog.searchResuls keywords.
>
> I also changed the style and the title to match the default Recent
> Comments. This recent comments portlet will now only display comments
> that have a state of published. Just need to swap that with the other
> recent comment portlet in the left slots of the properties tab for the
> blog.
>
> The next step was to try and stop the comments from displaying in the
> entry listing. It looked like the object method to do that came from the
> COREBlog2/content/coreblogentry.py file and was based around a catalog
> search again.
>
> CUSTOMISING COREBLOG2 TO ONLY SHOW PUBLISHED COMMENTS
>
> I made the following changes to 2 files to show only published comments
> in the list of comments displayed with an entry.
>
> I added the following to the COREBlog2/config.py file:
>
> coreblogcomment_state = 'published
>
> I then made the following changes to the
> COREBlog2/content/coreblogentry.py file:
>
> changed:
>
> from Products.COREBlog2.config import PROJECTNAME,\
> comemnt_rel_id,trackback_rel_id,\
> coreblogentry_meta_type,coreblogcomment_meta_type,\
> coreblogtrackback_meta_type
>
> to
>
> from Products.COREBlog2.config import PROJECTNAME,\
> comemnt_rel_id,trackback_rel_id,\
> coreblogentry_meta_type,coreblogcomment_meta_type,\
> coreblogtrackback_meta_type,coreblogcomment_state
>
> and changed this line in the getComment method:
>
> contentFilter = {'path':path,'portal_type':coreblogcomment_meta_type}
>
> to
>
> contentFilter =
> {'path':path,'portal_type':coreblogcomment_meta_type,'review_state':coreblo
>gcomment_state}
>
> the contentFilter variable is passed into a call to the searchResults
> which is called via the queryCatalog in this script.
>
> Ok that caused only published comments to be shown in the comments
> listing for an entry but the count was still displaying all comments. To
> fix that I just had to change the contentFilter in the countComment
> method in the coreblogentry.py file to be the same as the one I had in
> the getComment method.
>
> I had to restart Zope after these changes to get them to load.
>
> RESTRICTING ACCESS TO COMMENTS IN THE REJECTED STATE
>
> Ok the remaining problem I have now with the comments is that I need to
> restrict access to the comments folder because an anonymous user can
> still go to .....t/blog/comments folder and see all comments except those
> that are private or pending. What I need to do is make it so that anonymous
> users don't have the right to see comments that are in an rejected state.
> This will also stop them being able to access these comments by search.
>
> Setting the permissions that you want on a particular state is quite
> easy. To do it go to the workflow that is managing the content type that
> you are interesting in and then click on the states tab, select the
> state that you want to change permissions for and then click on the
> Permissions tab.
>
> By default it appears that when you create a new state it is set to
> aquire all the permissions. I set the permissions for the rejected state
> so that they wheren't aquired and the manager had rights for all
> permissions and the Editor role had "View" and "Access Content
> Information" permissions. The other roles had no permissions for
> objects in the rejected state.
>
> You need to click on the "Update Security Settings" button in the
> portal_workflow page to apply any changes to permissions you make. Ok
> that has fixed that if anonymous goes to the comments folder now they
> will only see comments that are in the published state.
>
> Ok that appears to be it as far as workflowing comments goes. Bloggers now
> have a nice simple workflow and the anonymous user only sees content if
> they are published.
>
>
> 2. FIXING CONFIRMATION EMAIL ON COMMENT SUBMISSION
>
> The email notification that coreblog sends to people when someone
> submitts a comment or trackback has a number of problems:
>
> 1. There is no subject
> 2. The from address is not the one specified in the blog settings but
> the same as the to address.
> 3. The format of the email in thunderbird is unreadable with large
> spaces between every character.
>
> COREBlog doesn't use the normal mailhost that you see used in other
> scripts. The author has written his own method "send_mail" in order to
> bypass Zopes security and allow anonymous users the ability to send
> email by submitting a comment.
>
> What I ended up doing was changing the send_mail() method in the
> COREBlogTool.py.
>
> I changed the send_mail() from:
>
> def send_mail(self, body,to_addr,from_addr,subject):
> #
> # Method to bypass Zope's security.
> # For case of comment/trackback post by anonymous user
> #
> try:
> self.MailHost.send(body,to_addr, from_addr, subject)
>
> to:
>
> def send_mail(self, msg):
> #
> # Method to bypass Zope's security.
> # For case of comment/trackback post by anonymous user
> #
> try:
> self.MailHost.send(msg)
>
> I then worked on trying to get the message created properly.
>
> Ok after some stuffing around to get date field right for mozilla
> thunderbird people monitoring the blog now get an email that provides
> the comment and the comment details with a subject in the format of
> "[blog comment] comment title". I couldn't figure out exactly what was
> causing the wierd formatting in mozilla but thought it could possibly be
> the translate functions as they where used in the script.
>
> Here is a diff from fcomp of the original cbaddComment.cpy and my changes:
> -------------------------------------------------
>
> FILE A: cbaddComment.cpy-original
> FILE B: cbaddComment.cpy
> TOTALS: 43 inserted 7 deleted 67 matched
>
> ******************** INSERT [A 15, B 15]:
> from DateTime import DateTime
>
> ******************** REPLACE [A 40-41, B 41-46]:
> from_addr = context.getNotify_to()
> msgbody = context.translate('comment_notify_body')
> ******************** WITH:
> from_addr = context.getNotify_from()
> Date = DateTime()
> commondate = DateTime.aCommon(Date)
> context.plone_log(commondate)
>
> #Get elements from the form setting them to empty strings if they don't
> exist
>
> ******************** REPLACE [A 50-52, B 55-66]:
> msgbody = msgbody % (elements)
> msgsubject = context.translate('comment_notify_title')
> mgsheader = """To: %s
> ******************** WITH:
>
> #Set variables to be inserted in message
> title = elements['title']
> author = elements['author']
> url = elements['url']
> ip = elements['post_ip']
> entryurl = elements['entry_url']
> msgbody = elements['body']
> msgsubject = '[blog comment] ' + title
>
> message = """
> To: %s
>
> ******************** INSERT [A 56, B 70-71]:
> Date: %s
> Subject: %s
>
> ******************** REPLACE [A 57-58, B 73-94]:
> """ % (to_addr,from_addr)
> cbtool.send_mail(mgsheader+msgbody, to_addr, from_addr, msgsubject)
> ******************** WITH:
> Comment Title: %s
> Author: %s
> Url: %s
> Client IP: %s
> Entry URL: %s
>
> %s
>
> """
> msg = message % (
> to_addr,
> from_addr,
> commondate,
> msgsubject,
> title,
> author,
> url,
> ip,
> entryurl,
> msgbody
> )
> cbtool.send_mail(msg)
> ------------------------------------------
>
> 3. INSTALL ANTI-COMMENT SPAM TOOL CAPTCHA'S
>
> - First I registered an account at http://captchas.net/registration/
>
> - They emailed me a key to use with the username I had created.
>
> - I then installed the plonecatpcha product using the latest version
> which you can get from
> http://sourceforge.net/project/showfiles.php?group_id=177298, be aware
> that it unpacks just the files and not the folder so you need to create
> the PloneCaptcha folder in your products directory and then unpack into
> that.
>
> - This latest version allows you to add the username and password you
> got from captchas.net via the properties tab in the ZMI. To do that go
> the root of your plone site and then click on plone_captcha. It will
> default to displaying the properties so just enter your username and
> password there.
>
> - - I had added the following to my "cbcomment_form.pt" file above the
> <div class="formControls"> line:
>
> <div class="field"
> tal:define="error errors/captcha| nothing;"
> tal:attributes="class python:test(error, 'field error',
> 'field')">
>
> <label i18n:translate="label_captcha_help">Verification
> Code</label>
> <div class="formHelp"
> i18n:translate="help_plone_captcha">
> This helps us prevent automated spamming.
> </div>
>
> <div tal:content="error">Validation error output</div>
> <div metal:use-macro="here/captcha/macros/edit" />
> </div>
>
> as suggested in this post
> http://postaria.com/pipermail/coreblog-en/2006-June/000428.html
>
> - I had also added the validate_captcha to via the ZMI to the
> portal_skins/COREBlog2/cbcomment_preview.pt file anborder="0" d cbentry_view 
file.
> To save having to do this for every plone site that used the COREBlog2
> product I added "validate_captcha" on to the list of validators in the
> metadata files for these 2 forms cbcomment_preview.cpt.metadata and
> cbentry_view.cpt.metadata.
>
> ** Note the .cpt stands for controller page template which gives you an
> associated metadata file as it lets you set up validators and actions
> for your page template.
>
> validators=validateComment,validate_captcha
>
> Trackback spam just poured in as soon as the blog got linked to an
> google. I was uncertain how useful it was myself and thought that it
> could just be too confusing for our bloggers so I disabled it. Setting
> the permissions so that anonymous users couldn't create trackback
> entries didn't appear to stop it. In the blog settings -> Edit Entries
> tab I set trackbacks to "None/Hidden" and then applied the suggested
> patch at http://coreblog.org/trac/coreblog2/ticket/50 now when I
> create a new entry trackbacks are not shown.
>
> 4. SETUP EMAIL NOTIFICATIONS FOR COMMENTERS WHEN THEIR COMMENT IS APPROVED
>
> It turned out to be quite a bit of stuffing around to get this to work
> as i got caught up on a couple of things that wheren't documented in any
> of the documentation I saw about writing scripts to send emails. This
> was the fact that not all methods return strings that are in a format
> that will be accepted by mailhost.send. With these you need to transform
> them using the encode() method. If you get the following error when
> passing a msg to mailhost.send:
>
> Error Value
> No message recipients designated
>
> then look for some of your variables not being encoded correctly for
> email and you need to use the encode method prior to passing them to
> mailhost.send. If you add .encode() for email = obj.email.encode() for
> example you can then get it accepted by mailhost.send.
>
> This is what my comment_approved script that is called after the
> "publish" transition:
>
> ---------------------------------------------
> #This script lets people know that their comment has been published
> from DateTime import DateTime
>
> obj = state_change.object
>
> mhost = context.MailHost
> from_addr = '[EMAIL PROTECTED]'
>
> #Get the email to send to make sure you encode it otherwise mailhost
> choke on message
> to_addr = obj.email.encode()
>
> #Set the date for the date header need to use commondate format for
> thunderbirds sake.
> date = DateTime()
> commondate = DateTime.aCommon(date)
>
> #Get the author's name
> name = obj.author.encode()
>
> #Get the url of the blog entry
> parent = obj.getParentEntry()
> parenturl = parent.absolute_url()
>
> #Get the title of the blog entry
> parentTitle = parent.Title()
>
> # the message format, %s will be filled in from data
> message = """
> From: %s
> To: %s
> Date: %s
> Subject: comment on nuclear dump blog published
>
> Hi %s
>
> Your comment on my blog entry "%s" has been published see
> %s#comments
>
> Thank you for your input
> """
>
> msg = message % (
> from_addr,
> to_addr,
> commondate,
> name,
> parentTitle,
> parenturl
> )
>
> #Log message for referece purposes
> context.plone_log(msg)
>
> mhost.send(msg)
> --------------------------------------
>
> Ok thats was it the comment process in COREBlog2 is now nice and
> simple for my bloggers.
>
> cheers
> John



-- 
Robert B. Hawkins
http://www.neohawk.org
440-210-1621 (home)
440-829-4993 (cell)
[EMAIL PROTECTED]
_______________________________________________
COREblog-en mailing list
[email protected]
http://postaria.com/mailman/listinfo/coreblog-en
Unsubscription writing to [EMAIL PROTECTED]

Reply via email to