2010-03-18 15:06:04 +01:00
|
|
|
<!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" />
|
2010-06-01 17:11:33 +02:00
|
|
|
<link rel="next" title="API/Interfaces" href="api.html" />
|
2010-03-18 15:06:04 +01:00
|
|
|
<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" >
|
2010-06-01 17:11:33 +02:00
|
|
|
<a href="api.html" title="API/Interfaces"
|
|
|
|
accesskey="N">next</a> |</li>
|
2010-03-18 15:06:04 +01:00
|
|
|
<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>
|
2010-06-01 17:11:33 +02:00
|
|
|
<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>
|
2010-03-18 15:06:04 +01:00
|
|
|
</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>
|
2010-06-01 17:11:33 +02:00
|
|
|
<h4>Next topic</h4>
|
|
|
|
<p class="topless"><a href="api.html"
|
|
|
|
title="next chapter">API/Interfaces</a></p>
|
2010-03-18 15:06:04 +01:00
|
|
|
<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" >
|
2010-06-01 17:11:33 +02:00
|
|
|
<a href="api.html" title="API/Interfaces"
|
|
|
|
>next</a> |</li>
|
2010-03-18 15:06:04 +01:00
|
|
|
<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>
|