306 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			306 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 | 
						|
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 | 
						|
 | 
						|
<html xmlns="http://www.w3.org/1999/xhtml">
 | 
						|
  <head>
 | 
						|
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 | 
						|
    
 | 
						|
    <title>Design Notes — plone.app.discussion v1.0b4 documentation</title>
 | 
						|
    <link rel="stylesheet" href="_static/default.css" type="text/css" />
 | 
						|
    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
 | 
						|
    <script type="text/javascript">
 | 
						|
      var DOCUMENTATION_OPTIONS = {
 | 
						|
        URL_ROOT:    '#',
 | 
						|
        VERSION:     '1.0b4',
 | 
						|
        COLLAPSE_MODINDEX: false,
 | 
						|
        FILE_SUFFIX: '.html',
 | 
						|
        HAS_SOURCE:  true
 | 
						|
      };
 | 
						|
    </script>
 | 
						|
    <script type="text/javascript" src="_static/jquery.js"></script>
 | 
						|
    <script type="text/javascript" src="_static/doctools.js"></script>
 | 
						|
    <link rel="top" title="plone.app.discussion v1.0b4 documentation" href="index.html" />
 | 
						|
    <link rel="next" title="API/Interfaces" href="api.html" />
 | 
						|
    <link rel="prev" title="Architectural Principles" href="architecture.html" /> 
 | 
						|
  </head>
 | 
						|
  <body>
 | 
						|
    <div class="related">
 | 
						|
      <h3>Navigation</h3>
 | 
						|
      <ul>
 | 
						|
        <li class="right" style="margin-right: 10px">
 | 
						|
          <a href="genindex.html" title="General Index"
 | 
						|
             accesskey="I">index</a></li>
 | 
						|
        <li class="right" >
 | 
						|
          <a href="api.html" title="API/Interfaces"
 | 
						|
             accesskey="N">next</a> |</li>
 | 
						|
        <li class="right" >
 | 
						|
          <a href="architecture.html" title="Architectural Principles"
 | 
						|
             accesskey="P">previous</a> |</li>
 | 
						|
        <li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> »</li> 
 | 
						|
      </ul>
 | 
						|
    </div>  
 | 
						|
 | 
						|
    <div class="document">
 | 
						|
      <div class="documentwrapper">
 | 
						|
        <div class="bodywrapper">
 | 
						|
          <div class="body">
 | 
						|
            
 | 
						|
  <div class="section" id="design-notes">
 | 
						|
<h1>Design Notes<a class="headerlink" href="#design-notes" title="Permalink to this headline">¶</a></h1>
 | 
						|
<p>This document contains design notes for plone.app.discussion.</p>
 | 
						|
<div class="section" id="storage-and-traversal">
 | 
						|
<h2>Storage and traversal<a class="headerlink" href="#storage-and-traversal" title="Permalink to this headline">¶</a></h2>
 | 
						|
<p>For each content item, there is a Conversation object stored in annotations.
 | 
						|
This can be traversed to via the ++conversation++ namespace, but also fetched
 | 
						|
via an adapter lookup to IConversation.</p>
 | 
						|
<p>The conversation stores all comments related to a content object. Each
 | 
						|
comment has an integer id (also representable as a string, to act as an OFS
 | 
						|
id and allow traversal). Hence, traversing to obj/++conversation++/123 retrieves
 | 
						|
the comment with id 123.</p>
 | 
						|
<p>Comments ids are assigned in order, so a comment with id N was posted before
 | 
						|
a comment with id N + 1. However, it is not guaranteed that ids will be
 | 
						|
incremental. Ids must be positive integers - 0 or negative numbers are not
 | 
						|
allowed.</p>
 | 
						|
<p>Threading information is stored in the conversation: we keep track of the
 | 
						|
set of children and the parent if any comment. Top-level comments have a
 | 
						|
parent id of 0. This information is managed by the conversation class when
 | 
						|
comments are manipulated using a dict-like API.</p>
 | 
						|
<p>Note that the __parent__/acquisition parent of an IComment is the
 | 
						|
IConversation, and the __parent__/acquisition parent of an IConversation is
 | 
						|
the content object.</p>
 | 
						|
</div>
 | 
						|
<div class="section" id="events">
 | 
						|
<h2>Events<a class="headerlink" href="#events" title="Permalink to this headline">¶</a></h2>
 | 
						|
<p>Manipulating the IConversation object should fire the usual IObjectAddedEvent
 | 
						|
and IObjectRemovedEvent events. The UI may further fire IObjectCreatedEvent
 | 
						|
and IObjectModifiedEvent for comments.</p>
 | 
						|
</div>
 | 
						|
<div class="section" id="factories">
 | 
						|
<h2>Factories<a class="headerlink" href="#factories" title="Permalink to this headline">¶</a></h2>
 | 
						|
<p>Comments should always be created via the ‘Discussion Item’ IFactory utility.
 | 
						|
Conversations should always be obtained via the IConversation adapter (even
 | 
						|
the ++conversation++ namespace should use this). This makes it possible to
 | 
						|
replace conversations and comments transparently.</p>
 | 
						|
</div>
 | 
						|
<div class="section" id="the-comment-class">
 | 
						|
<h2>The Comment class<a class="headerlink" href="#the-comment-class" title="Permalink to this headline">¶</a></h2>
 | 
						|
<p>The inheritance tree for DiscussionItem is shown below. Classes we want to
 | 
						|
mix in and interface we want to implement in the Comment class are marked
 | 
						|
with [x].</p>
 | 
						|
<blockquote>
 | 
						|
<dl class="docutils">
 | 
						|
<dt>[ ] DiscussionItem</dt>
 | 
						|
<dd><dl class="first last docutils">
 | 
						|
<dt>[ ] Document</dt>
 | 
						|
<dd><dl class="first last docutils">
 | 
						|
<dt>[ ] PortalContent                       = [ ] IContentish</dt>
 | 
						|
<dd><p class="first">[ ] DynamicType                     = [ ] IDynamicType
 | 
						|
[ ] CMFCatalogAware                 = [ ] <no interface>
 | 
						|
[ ] SimpleItem                      = [ ] ISimpleItem</p>
 | 
						|
<blockquote class="last">
 | 
						|
<dl class="docutils">
 | 
						|
<dt>[ ] Item                          [ ]</dt>
 | 
						|
<dd>[?] Base                    = [ ] <no interface>
 | 
						|
[ ] Resource                = [ ] <no interface>
 | 
						|
[ ] CopySource              = [ ] ICopySource
 | 
						|
[ ] Tabs                    = [ ] <no interface>
 | 
						|
[x] Traversable             = [ ] ITraversable
 | 
						|
[ ] Element                 = [ ] <no interface>
 | 
						|
[x] Owned                   = [ ] IOwned
 | 
						|
[ ] UndoSupport             = [ ] IUndoSupport</dd>
 | 
						|
</dl>
 | 
						|
<p>[ ] Persistent                    [ ]
 | 
						|
[ ] Implicit                      [ ]
 | 
						|
[x] RoleManager                 = [ ] IRoleManager</p>
 | 
						|
<blockquote>
 | 
						|
[ ] RoleManager             = [ ] IPermissionMappingSupport</blockquote>
 | 
						|
</blockquote>
 | 
						|
</dd>
 | 
						|
<dt>[ ] DefaultDublinCoreImpl               = [ ] IDublinCore</dt>
 | 
						|
<dd><blockquote class="first">
 | 
						|
[ ] ICatalogableDublinCore
 | 
						|
[ ] IMutableDublinCore</blockquote>
 | 
						|
<p class="last">[ ] PropertyManager                 = [ ] IPropertyManager</p>
 | 
						|
</dd>
 | 
						|
</dl>
 | 
						|
</dd>
 | 
						|
</dl>
 | 
						|
</dd>
 | 
						|
</dl>
 | 
						|
</blockquote>
 | 
						|
<p>Thus, we want:</p>
 | 
						|
<blockquote>
 | 
						|
<ul>
 | 
						|
<li><dl class="first docutils">
 | 
						|
<dt>Traversable, to get absolute_url() and friends</dt>
 | 
						|
<dd><ul class="first last simple">
 | 
						|
<li>this requires a good acquisition chain at all times</li>
 | 
						|
</ul>
 | 
						|
</dd>
 | 
						|
</dl>
 | 
						|
</li>
 | 
						|
<li><dl class="first docutils">
 | 
						|
<dt>Acquisition.Explicit, to support acquisition</dt>
 | 
						|
<dd><ul class="first last simple">
 | 
						|
<li>we do not want implicit acquisition</li>
 | 
						|
</ul>
 | 
						|
</dd>
 | 
						|
</dl>
 | 
						|
</li>
 | 
						|
<li><p class="first">Owned, to be able to track ownership</p>
 | 
						|
</li>
 | 
						|
<li><p class="first">RoleManager, to support permissions and local roles</p>
 | 
						|
</li>
 | 
						|
</ul>
 | 
						|
</blockquote>
 | 
						|
<p>We also want to use a number of custom indexers for most of the standard
 | 
						|
metadata such as creator, effective date etc.</p>
 | 
						|
<p>Finally, we’ll need event handlers to perform the actual indexing.</p>
 | 
						|
</div>
 | 
						|
<div class="section" id="discussion-settings">
 | 
						|
<h2>Discussion settings<a class="headerlink" href="#discussion-settings" title="Permalink to this headline">¶</a></h2>
 | 
						|
<p>Discussion can be enabled per-type and per-instance, via values in the FTI
 | 
						|
(allow_discussion) and on the object. These will remain unchanged. The
 | 
						|
IConversation object’s ‘enabled’ property should consult these.</p>
 | 
						|
<p>Global settings should be managed using plone.registry. A control panel
 | 
						|
can be generated from this as well, using the helper class in
 | 
						|
plone.app.registry.</p>
 | 
						|
<p>Note that some settings, notably those to do with permissions and workflow,
 | 
						|
will need to be wired up as custom form fields with custom data mangers
 | 
						|
or similar.</p>
 | 
						|
</div>
 | 
						|
<div class="section" id="workflow-and-permissions">
 | 
						|
<h2>Workflow and permissions<a class="headerlink" href="#workflow-and-permissions" title="Permalink to this headline">¶</a></h2>
 | 
						|
<p>Where possible, we should use existing permissions:</p>
 | 
						|
<blockquote>
 | 
						|
<ul class="simple">
 | 
						|
<li>View</li>
 | 
						|
<li>Reply to Item</li>
 | 
						|
<li>Modify Portal Content</li>
 | 
						|
<li>Request Review</li>
 | 
						|
</ul>
 | 
						|
</blockquote>
 | 
						|
<p>In addition, we’ll need a ‘Moderator’ role and a moderation permission,</p>
 | 
						|
<blockquote>
 | 
						|
<ul class="simple">
 | 
						|
<li>Moderate comment</li>
 | 
						|
<li>Bypass moderation</li>
 | 
						|
</ul>
 | 
						|
</blockquote>
 | 
						|
<p>To control whether Anonymous can post comments, we manage the ‘Reply to Item’
 | 
						|
permission. To control whether moderation is required for various roles, we
 | 
						|
could manage the ‘Bypass moderation’ permission.</p>
 | 
						|
<p>These could work in a workflow like this:</p>
 | 
						|
<blockquote>
 | 
						|
<ul>
 | 
						|
<li><dl class="first docutils">
 | 
						|
<dt>–> [posted] – {publish} –> [published]–> *</dt>
 | 
						|
<dd><div class="first line-block">
 | 
						|
<div class="line">^</div>
 | 
						|
<div class="line"><a href="#id1"><span class="problematic" id="id2">|</span></a></div>
 | 
						|
</div>
 | 
						|
<p class="last">+—– {auto-publish} —–+
 | 
						|
|                          |
 | 
						|
+—– {auto-moderate} —-+</p>
 | 
						|
</dd>
 | 
						|
</dl>
 | 
						|
</li>
 | 
						|
</ul>
 | 
						|
</blockquote>
 | 
						|
<p>The ‘posted’ state is the initial state. ‘published’ is the state where the
 | 
						|
comment is visible to non-reviewers.</p>
 | 
						|
<p>The ‘publish’ transition would be protected by the ‘Moderate comment’
 | 
						|
permission. We could have states and transition for ‘rejected’, etc, but it
 | 
						|
is probably just as good to delete comments that are rejected.</p>
 | 
						|
<p>The ‘auto-publish’ transition would be an automatic transition protected by
 | 
						|
the ‘Bypass moderation’ permission.</p>
 | 
						|
<p>The ‘auto-moderate’ transition would be another automatic transition protected
 | 
						|
by an expression (e.g. calling a view) that returns True if the user is on
 | 
						|
an auto-moderation ‘white-list’, e.g. by email address or username.</p>
 | 
						|
</div>
 | 
						|
<div class="section" id="forms-and-ui">
 | 
						|
<h2>Forms and UI<a class="headerlink" href="#forms-and-ui" title="Permalink to this headline">¶</a></h2>
 | 
						|
<p>The basic commenting display/reply form is placed in a viewlet.</p>
 | 
						|
<p>The reply form is dynamically created right under the comment when the user hits
 | 
						|
the reply button. To do so, we copy the standard comment form with a jQuery
 | 
						|
function. This function sets the form’s hidden in_reply_to field to the id of
 | 
						|
the comment the user wants to reply to. This also makes is possible to use
 | 
						|
z3c.form validation for the reply forms, because we can uniquely identify the
 | 
						|
a reply form request and return the reply form with validation errors.</p>
 | 
						|
<p>Since we rely on JavaScript for the reply form creation, the reply button is
 | 
						|
removed for nonJavaScript enabled browsers.</p>
 | 
						|
<p>The comment form uses z3c.form and plone.z3cform’s ExtensibleForm support. This
 | 
						|
makes it possible to plug in additional fields declaratively, e.g. to include
 | 
						|
SPAM protection.</p>
 | 
						|
</div>
 | 
						|
</div>
 | 
						|
 | 
						|
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
      <div class="sphinxsidebar">
 | 
						|
        <div class="sphinxsidebarwrapper">
 | 
						|
            <h3><a href="index.html">Table Of Contents</a></h3>
 | 
						|
            <ul>
 | 
						|
<li><a class="reference external" href="#">Design Notes</a><ul>
 | 
						|
<li><a class="reference external" href="#storage-and-traversal">Storage and traversal</a></li>
 | 
						|
<li><a class="reference external" href="#events">Events</a></li>
 | 
						|
<li><a class="reference external" href="#factories">Factories</a></li>
 | 
						|
<li><a class="reference external" href="#the-comment-class">The Comment class</a></li>
 | 
						|
<li><a class="reference external" href="#discussion-settings">Discussion settings</a></li>
 | 
						|
<li><a class="reference external" href="#workflow-and-permissions">Workflow and permissions</a></li>
 | 
						|
<li><a class="reference external" href="#forms-and-ui">Forms and UI</a></li>
 | 
						|
</ul>
 | 
						|
</li>
 | 
						|
</ul>
 | 
						|
 | 
						|
            <h4>Previous topic</h4>
 | 
						|
            <p class="topless"><a href="architecture.html"
 | 
						|
                                  title="previous chapter">Architectural Principles</a></p>
 | 
						|
            <h4>Next topic</h4>
 | 
						|
            <p class="topless"><a href="api.html"
 | 
						|
                                  title="next chapter">API/Interfaces</a></p>
 | 
						|
            <h3>This Page</h3>
 | 
						|
            <ul class="this-page-menu">
 | 
						|
              <li><a href="_sources/design.txt"
 | 
						|
                     rel="nofollow">Show Source</a></li>
 | 
						|
            </ul>
 | 
						|
          <div id="searchbox" style="display: none">
 | 
						|
            <h3>Quick search</h3>
 | 
						|
              <form class="search" action="search.html" method="get">
 | 
						|
                <input type="text" name="q" size="18" />
 | 
						|
                <input type="submit" value="Go" />
 | 
						|
                <input type="hidden" name="check_keywords" value="yes" />
 | 
						|
                <input type="hidden" name="area" value="default" />
 | 
						|
              </form>
 | 
						|
              <p class="searchtip" style="font-size: 90%">
 | 
						|
              Enter search terms or a module, class or function name.
 | 
						|
              </p>
 | 
						|
          </div>
 | 
						|
          <script type="text/javascript">$('#searchbox').show(0);</script>
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
      <div class="clearer"></div>
 | 
						|
    </div>
 | 
						|
    <div class="related">
 | 
						|
      <h3>Navigation</h3>
 | 
						|
      <ul>
 | 
						|
        <li class="right" style="margin-right: 10px">
 | 
						|
          <a href="genindex.html" title="General Index"
 | 
						|
             >index</a></li>
 | 
						|
        <li class="right" >
 | 
						|
          <a href="api.html" title="API/Interfaces"
 | 
						|
             >next</a> |</li>
 | 
						|
        <li class="right" >
 | 
						|
          <a href="architecture.html" title="Architectural Principles"
 | 
						|
             >previous</a> |</li>
 | 
						|
        <li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> »</li> 
 | 
						|
      </ul>
 | 
						|
    </div>
 | 
						|
    <div class="footer">
 | 
						|
      © Copyright 2010, Timo Stollenwerk.
 | 
						|
      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
 | 
						|
    </div>
 | 
						|
  </body>
 | 
						|
</html> |