Author: douglas
Date: 2008-01-02 12:03:48 -0500 (Wed, 02 Jan 2008)
New Revision: 12227

Added:
   opencore/trunk/opencore/listen/browser/create.pt
   opencore/trunk/opencore/listen/browser/edit.pt
Modified:
   opencore/trunk/opencore/browser/octopus.py
   opencore/trunk/opencore/listen/browser/configure.zcml
   opencore/trunk/opencore/listen/browser/listen_formlib.pt
   opencore/trunk/opencore/listen/browser/mailing_lists.pt
   opencore/trunk/opencore/listen/browser/moderation.pt
   opencore/trunk/opencore/listen/browser/view.py
   opencore/trunk/opencore/listen/utils.py
Log:
Merge from listen-without-formlib branch, tests passing :-D


Modified: opencore/trunk/opencore/browser/octopus.py
===================================================================
--- opencore/trunk/opencore/browser/octopus.py  2008-01-02 17:02:19 UTC (rev 
12226)
+++ opencore/trunk/opencore/browser/octopus.py  2008-01-02 17:03:48 UTC (rev 
12227)
@@ -125,9 +125,22 @@
 
     def __delegate(self, action, objects, fields, raise_=False):
         """ delegate to the appropriate action method, if it exists."""
-        if action in self.actions:
-            return self.actions[action](self, objects, fields)
-        elif raise_:
+        
+        #check self and superclasses for appropriate action methods
+        bases = [self.__class__]
+        while bases:
+            base = bases[0]
+            if hasattr(base, 'actions'):
+                try:
+                    if action in base.actions:
+                        return base.actions[action](self, objects, fields)
+                except TypeError: #actions isn't a list
+                    pass
+
+            bases = bases[1:]
+            bases += list(base.__bases__)
+
+        if raise_:
             raise KeyError("No actions in request")
         elif self.actions.default is not None:
             return self.actions.default(self, objects, fields)

Modified: opencore/trunk/opencore/listen/browser/configure.zcml
===================================================================
--- opencore/trunk/opencore/listen/browser/configure.zcml       2008-01-02 
17:02:19 UTC (rev 12226)
+++ opencore/trunk/opencore/listen/browser/configure.zcml       2008-01-02 
17:03:48 UTC (rev 12227)
@@ -17,19 +17,19 @@
   <include package="plone.app.form" />
 
   <browser:page
-     name="opencore.add_mailinglist"
+     name="create"
      for="opencore.featurelets.interfaces.IListenContainer"
      permission="listen.AddMailingList"
-     class=".view.NuiMailingListAddView"
-     template="listen_formlib.pt"
+     class=".view.ListAddView"
+     template="create.pt"
      />
 
   <browser:page
      name="edit"
      for="opencore.listen.interfaces.IOpenMailingList"
      permission="listen.EditMailingList"
-     class=".view.NuiMailingListEditView"
-     template="listen_formlib.pt"
+     class=".view.ListEditView"
+     template="edit.pt"
      />
 
   <browser:page
@@ -40,13 +40,6 @@
      template="listen_macros.pt"
      />
 
-  <adapter
-     for=".view.NuiMailingListAddView"
-     factory=".view.default_named_template_adapter"
-     name="default"
-     provides="zope.formlib.namedtemplate.INamedTemplate"
-     />
-
    <browser:page
      for="opencore.listen.interfaces.IOpenMailingList"
      name="summary"

Copied: opencore/trunk/opencore/listen/browser/create.pt (from rev 12156, 
opencore/branches/listen-without-formlib/opencore/listen/browser/create.pt)
===================================================================
--- opencore/trunk/opencore/listen/browser/create.pt                            
(rev 0)
+++ opencore/trunk/opencore/listen/browser/create.pt    2008-01-02 17:03:48 UTC 
(rev 12227)
@@ -0,0 +1,167 @@
+<html metal:use-macro="context/@@standard_macros/master">
+       <head>
+               <title metal:fill-slot="title" 
tal:content="string:${view/context/Title} - ${view/area/Title}" />
+       </head>
+       <body>
+               <div metal:fill-slot="content">
+                       <div class="oc-headingBlock">
+                               <h1 i18n:translate="create_list_heading">Create 
new mailing list</h1>
+                               <p i18n:translate="create_list_desc" 
class="oc-headingContext">Email based mailing lists are used to have 
discussions and distribute information about the project.</p>
+                       </div>
+
+                       <div id="oc-content-main" 
class="oc-content-main-fullWidth">
+                               <form name="edit-form" id="oc-list-create" 
method="post" enctype="multipart/form-data"
+                                     class="enableUnloadProtection" 
tal:attributes="action view/name">
+
+<!-- basics -->
+                                       <fieldset class="oc-boxy">
+                                               <legend 
i18n:translate="create_list_step_1" class="oc-legend-heading 
oc-biggerText">Step 1: Basics</legend>
+                                               <table class="oc-form">
+                                                       <tbody>
+                                                               <tr 
class="oc-form-row">
+                                                                       <th 
class="oc-form-label" scope="row">
+                                                                               
<label i18n:translate="list_title_name" for="title">Title</label>
+                                                                       </th>
+                                                                       <td 
class="oc-form-value">
+                                                                               
<input type="text" id="title" class="oc-autoFocus" name="title"
+                                                                               
       tal:attributes="value request/title | nothing" />
+                                                                       </td>
+                                                                       <td 
class="oc-form-help">
+                                                                               
<span class="oc-form-context"></span>
+                                                                               
<span id="oc-title-validator" class="oc-form-validator"></span>
+                                                                               
<span id="oc-title-error" class="oc-form-error" tal:content="view/errors/title 
| nothing" />
+                                                                       </td>
+                                                               </tr>
+                                                               <tr 
class="oc-form-row">
+                                                                       <th 
class="oc-form-label" scope="row">
+                                                                               
<label i18n:translate="list_description_name" 
for="description">Description</label>
+                                                                       </th>
+                                                                       <td 
class="oc-form-value">
+                                                                               
<textarea name="description" id="description" rows="3" cols="40" 
tal:content="request/description | nothing"/>
+                                                                       </td>
+                                                                       <td 
class="oc-form-help">
+                                                                               
<span class="oc-form-context"></span>
+                                                                               
<span id="oc-description-validator" class="oc-form-validator"></span>
+                                                                               
<span id="oc-description-error" class="oc-form-error" 
tal:content="view/errors/description | nothing" />
+                                                                       </td>
+                                                               </tr>
+                                                               <tr 
class="oc-form-row">
+                                                                       <th 
class="oc-form-label" scope="row">
+                                                                               
<label i18n:translate="list_mailto_name" for="mailto">List Address 
Prefix</label>
+                                                                       </th>
+                                                                       <td 
class="oc-form-value oc-form-fieldBlock">
+                                                                               
<input type="text" name="mailto" id="mailto"
+                                                                               
       class="oc-js-liveValidate"
+                                                                               
       tal:attributes="value request/mailto | nothing" />
+                                                                               
<span tal:replace="view/getSuffix" />
+                                                                       </td>
+                                                                       <td 
class="oc-form-help">
+                                                                               
<span class="oc-form-context"></span>
+                                                                               
<span id="oc-mailto-validator" class="oc-form-validator"></span>
+                                                                               
<span id="oc-mailto-error" class="oc-form-error" 
tal:content="view/errors/mailto | nothing" />
+                                                                       </td>
+                                                               </tr>
+                                                       </tbody>
+                                               </table>
+                                       </fieldset>
+
+<!-- security -->
+                                       <fieldset class="oc-boxy">
+                                               <legend 
i18n:translate="create_list_step_2" class="oc-legend-heading 
oc-biggerText">Step 2: Security</legend>
+                                               <table class="oc-form">
+                                                       <tbody>
+                                                               <tr 
class="oc-form-row">
+                                                                       <th 
class="oc-form-label" scope="row">
+                                                                               
<p i18n:translate="list_workflow_policy_name">Workflow</p>
+                                                                       </th>
+                                                                       <td 
class="oc-form-value">
+                                                                               
<p i18n:translate="list_workflow_desc" class="oc-headingContext 
oc-smallText">The policy that defines the behavior of the list.</p>
+                                                                               
<fieldset tal:define="policy request/workflow_policy | string:policy_open">
+                                                                               
        <ul class="oc-plainList oc-form-fieldBlock">
+                                                                               
                <li>
+                                                                               
                        <input type="radio" class="oc-input-typeRadio" 
id="workflow_policy_open" name="workflow_policy"
+                                                                               
                               value="policy_open" tal:attributes="checked 
python:policy == 'policy_open' and 'checked' or ''" />
+                                                                               
                        <label i18n:translate="list_workflow_open" 
for="workflow_policy_open">
+                                                                               
                        Anyone who confirms their email address is valid can 
post and receive messages.</label>
+                                                                               
                </li>
+                                                                               
                <li>
+                                                                               
                        <input type="radio" class="oc-input-typeRadio" 
id="workflow_policy_moderated" name="workflow_policy"
+                                                                               
                               value="policy_moderated" tal:attributes="checked 
python:policy == 'policy_moderated' and 'checked' or ''" />
+                                                                               
                        <label i18n:translate="list_workflow_moderated" 
for="workflow_policy_moderated">Anyone can receive messages, but each posted 
message has to be approved by the list managers first.</label>
+                                                                               
                </li>
+                                                                               
                <li>
+                                                                               
                        <input type="radio" class="oc-input-typeRadio" 
id="workflow_policy_closed" name="workflow_policy"
+                                                                               
                               value="policy_closed" tal:attributes="checked 
python:policy == 'policy_closed' and 'checked' or ''" />
+                                                                               
                        <label i18n:translate="list_workflow_closed" 
for="workflow_policy_closed">Only those approved by the list managers can post 
and receive messages.</label>
+                                                                               
                </li>
+                                                                               
        </ul>
+                                                                               
</fieldset>
+                                                                       </td>
+                                                                       <td 
class="oc-form-help">
+                                                                               
<span class="oc-form-context"></span>
+                                                                       </td>
+                                                               </tr>
+<!-- managers -->
+                                                               <tr 
class="oc-form-row">
+                                                                       <th 
class="oc-form-label" scope="row">
+                                                                               
<label i18n:translate="list_managers_name" for="managers">Managers</label>
+                                                                       </th>
+                                                                       <td 
class="oc-form-value">
+                                                                               
<p i18n:translate="list_managers_desc" class="oc-headingContext oc-smallText 
oc-js-memberList_description">A comma separated list of users with permissions 
to modify the list.</p>
+                                                                               
<input type="text" id="managers" class="oc-autoFocus oc-js-memberList" 
name="managers"
+                                                                               
       tal:attributes="value request/managers | view/loggedinmember | nothing" 
/>
+                                                                       </td>
+                                                                       <td 
class="oc-form-help">
+                                                                               
<span class="oc-form-context"></span>
+                                                                               
<span id="oc-managers-validator" class="oc-form-validator"></span>
+                                                                               
<span id="oc-managers-error" class="oc-form-error" 
tal:content="view/errors/managers | nothing" />
+                                                                       </td>
+                                                               </tr>
+                                                       </tbody>
+                                               </table>
+                                       </fieldset>
+<!-- archival -->
+                                       <fieldset class="oc-boxy">
+                                               <legend 
i18n:translate="create_list_step_3" class="oc-legend-heading 
oc-biggerText">Step 3: Archival</legend>
+                                               <p 
i18n:translate="create_list_step_3_desc" class="oc-headingContext 
oc-smallText">When archiving is enabled, all messages sent to the list will be 
saved on the server. You may choose whether to archive just the message text, 
or include attachments.</p>
+                                               <fieldset 
tal:define="policy_str request/archival_policy | python:0;
+                                                                     policy 
python: int(policy_str)">
+                                                       <ul 
class="oc-form-radiolist oc-form-fieldBlock">
+                                                               <li>
+                                                                       <input 
type="radio" class="oc-input-typeRadio" id="archival_policy_all" 
name="archival_policy"
+                                                                              
value="0" tal:attributes="checked python:policy == 0 and 'checked' or ''" />
+                                                                       <label 
i18n:translate="list_archive_all" for="archival_policy_all">The entire message, 
including attachments</label>
+                                                               </li>
+                                                               <li>
+                                                                       <input 
type="radio" class="oc-input-typeRadio" id="archival_policy_text" 
name="archival_policy"
+                                                                              
value="1" tal:attributes="checked python:policy == 1 and 'checked' or ''" />
+                                                                       <label 
i18n:translate="list_archive_text" for="archival_policy_text">The message text 
only</label>
+                                                               </li>
+                                                               <li>
+                                                                       <input 
type="radio" class="oc-input-typeRadio" id="archival_policy_none" 
name="archival_policy"
+                                                                              
value="2" tal:attributes="checked python:policy == 2 and 'checked' or ''" />
+                                                                       <label 
i18n:translate="list_archive_none" for="archival_policy_none">Do not archive 
messages</label>
+                                                               </li>
+                                                       </ul>
+                                               </fieldset>
+                                       </fieldset>
+
+<!-- submit -->
+                                       <fieldset>
+                                               <ul class="oc-actions">
+                                                       <li>
+                                                               <input 
type="submit" 
+                                                                      
name="task|add" 
+                                                                      
value="Create" 
+                                                                      
i18n:attributes="value create_create_button"
+                                                                      
class="oc-button oc-chooseThis" />
+                                                       </li>
+                                                       <li>or <a 
i18n:translate="list_cancel" href="">Cancel</a></li>
+                                               </ul>
+                                       </fieldset>
+                               </form>
+                       </div>
+               </div>
+       </body>
+</html>
+

Copied: opencore/trunk/opencore/listen/browser/edit.pt (from rev 12156, 
opencore/branches/listen-without-formlib/opencore/listen/browser/edit.pt)
===================================================================
--- opencore/trunk/opencore/listen/browser/edit.pt                              
(rev 0)
+++ opencore/trunk/opencore/listen/browser/edit.pt      2008-01-02 17:03:48 UTC 
(rev 12227)
@@ -0,0 +1,162 @@
+<html metal:use-macro="context/@@standard_macros/master">
+       <head>
+               <title metal:fill-slot="title" 
tal:content="string:${view/context/Title} - ${view/area/Title}" />
+       </head>
+       <body>
+
+               <div metal:fill-slot="content">
+                       <div metal:use-macro="here/@@listen_macros/bcrumb"/>
+                       <div metal:use-macro="here/@@listen_macros/tabs"/>
+
+                       <div id="oc-content-main" 
class="oc-content-main-fullWidth">
+                               <form name="edit-form" id="oc-list-edit" 
method="post" enctype="multipart/form-data"
+                                     class="enableUnloadProtection" 
tal:attributes="action view/name">
+<!-- basics -->
+                                       <fieldset class="oc-boxy">
+                                               <legend 
i18n:translate="edit_list_basics" class="oc-legend-heading 
oc-biggerText">Basics</legend>
+                                               <table class="oc-form">
+                                                       <tbody>
+                                                               <tr 
class="oc-form-row">
+                                                                       <th 
class="oc-form-label" scope="row">
+                                                                               
<label i18n:translate="list_title_name" for="title">Title</label>
+                                                                       </th>
+                                                                       <td 
class="oc-form-value">
+                                                                               
<input type="text" id="title" class="oc-autoFocus" name="title"
+                                                                               
       tal:attributes="value request/title | context/title | nothing" />
+                                                                       </td>
+                                                                       <td 
class="oc-form-help">
+                                                                               
<span class="oc-form-context"></span>
+                                                                               
<span id="oc-title-validator" class="oc-form-validator"></span>
+                                                                               
<span id="oc-title-error" class="oc-form-error" tal:content="view/errors/title 
| nothing" />
+                                                                       </td>
+                                                               </tr>
+                                                               <tr 
class="oc-form-row">
+                                                                       <th 
class="oc-form-label" scope="row">
+                                                                               
<label i18n:translate="list_description_name" 
for="description">Description</label>
+                                                                       </th>
+                                                                       <td 
class="oc-form-value">
+                                                                               
<textarea name="description" id="description" rows="3" cols="40" 
tal:content="request/description | context/description | nothing"/>
+                                                                       </td>
+                                                                       <td 
class="oc-form-help">
+                                                                               
<span class="oc-form-context"></span>
+                                                                               
<span id="oc-description-validator" class="oc-form-validator"></span>
+                                                                               
<span id="oc-description-error" class="oc-form-error" 
tal:content="view/errors/description | nothing" />
+                                                                       </td>
+                                                               </tr>
+                                                               <tr 
class="oc-form-row">
+                                                                       <th 
class="oc-form-label" scope="row">
+                                                                               
<label i18n:translate="list_mailto_name" for="mailto">List Address 
Prefix</label>
+                                                                       </th>
+                                                                       <td 
class="oc-form-value oc-form-fieldBlock">
+                                                                               
<span tal:replace="context/mailto" />
+
+                                                                       </td>
+                                                                       <td 
class="oc-form-help">
+                                                                               
<span class="oc-form-context"></span>
+                                                                               
<span id="oc-mailto-validator" class="oc-form-validator"></span>
+                                                                       </td>
+                                                               </tr>
+                                                       </tbody>
+                                               </table>
+                                       </fieldset>
+
+<!-- security -->
+                                       <fieldset class="oc-boxy">
+                                               <legend 
i18n:translate="edit_list_security" class="oc-legend-heading 
oc-biggerText">Security</legend>
+                                               <table class="oc-form">
+                                                       <tbody>
+                                                               <tr 
class="oc-form-row">
+                                                                       <th 
class="oc-form-label" scope="row">
+                                                                               
<p i18n:translate="list_workflow_policy_name">Workflow</p>
+                                                                       </th>
+                                                                       <td 
class="oc-form-value">
+                                                                               
<p i18n:translate="list_workflow_desc" class="oc-headingContext 
oc-smallText">The policy that defines the behavior of the list.</p>
+                                                                               
<fieldset tal:define="policy request/workflow_policy | view/workflow_policy | 
string:policy_open">
+                                                                               
        <ul class="oc-plainList oc-form-fieldBlock">
+                                                                               
                <li>
+                                                                               
                        <input type="radio" class="oc-input-typeRadio" 
id="workflow_policy_open" name="workflow_policy"
+                                                                               
                               value="policy_open" tal:attributes="checked 
python:policy == 'policy_open' and 'checked' or ''" />
+                                                                               
                        <label i18n:translate="list_workflow_open" 
for="workflow_policy_open">
+                                                                               
                        Anyone who confirms their email address is valid can 
post and receive messages.</label>
+                                                                               
                </li>
+                                                                               
                <li>
+                                                                               
                        <input type="radio" class="oc-input-typeRadio" 
id="workflow_policy_moderated" name="workflow_policy"
+                                                                               
                               value="policy_moderated" tal:attributes="checked 
python:policy == 'policy_moderated' and 'checked' or ''" />
+                                                                               
                        <label i18n:translate="list_workflow_moderated" 
for="workflow_policy_moderated">Anyone can receive messages, but each posted 
message has to be approved by the list managers first.</label>
+                                                                               
                </li>
+                                                                               
                <li>
+                                                                               
                        <input type="radio" class="oc-input-typeRadio" 
id="workflow_policy_closed" name="workflow_policy"
+                                                                               
                               value="policy_closed" tal:attributes="checked 
python:policy == 'policy_closed' and 'checked' or ''" />
+                                                                               
                        <label i18n:translate="list_workflow_closed" 
for="workflow_policy_closed">Only those approved by the list managers can post 
and receive messages.</label>
+                                                                               
                </li>
+                                                                               
        </ul>
+                                                                               
</fieldset>
+                                                                       </td>
+                                                                       <td 
class="oc-form-help">
+                                                                               
<span class="oc-form-context"></span>
+                                                                       </td>
+                                                               </tr>
+<!-- managers -->
+                                                               <tr 
class="oc-form-row">
+                                                                       <th 
class="oc-form-label" scope="row">
+                                                                               
<label i18n:translate="list_managers_name" for="managers">Managers</label>
+                                                                       </th>
+                                                                       <td 
class="oc-form-value">
+                                                                               
<p i18n:translate="list_managers_desc" class="oc-headingContext oc-smallText 
oc-js-memberList_description">A comma separated list of users with permissions 
to modify the list.</p>
+                                                                               
<input type="text" id="managers" class="oc-autoFocus oc-js-memberList" 
name="managers"
+                                                                               
       tal:attributes="value request/managers | 
python:','.join(context.managers); | nothing" />
+                                                                       </td>
+                                                                       <td 
class="oc-form-help">
+                                                                               
<span class="oc-form-context"></span>
+                                                                               
<span id="oc-managers-validator" class="oc-form-validator"></span>
+                                                                               
<span id="oc-managers-error" class="oc-form-error" 
tal:content="view/errors/managers | nothing" />
+                                                                       </td>
+                                                               </tr>
+                                                       </tbody>
+                                               </table>
+                                       </fieldset>
+<!-- archival -->
+
+                                       <fieldset class="oc-boxy">
+                                               <legend 
i18n:translate="list_archival" class="oc-legend-heading 
oc-biggerText">Archival</legend>
+                                               <p 
i18n:translate="list_archival_desc" class="oc-headingContext oc-smallText">When 
archiving is enabled, all messages sent to the list will be saved on the 
server. You may choose whether to archive just the message text, or include 
attachments.</p>
+                                               <fieldset 
tal:define="policy_str request/archival_policy | context/archived | python: 0; 
+                                                                     policy 
python:int(policy_str)">
+                                                       <ul 
class="oc-form-radiolist oc-form-fieldBlock">
+                                                               <li>
+                                                                       <input 
type="radio" class="oc-input-typeRadio" id="archival_policy_all" 
name="archival_policy"
+                                                                              
value="0" tal:attributes="checked python:policy == 0 and 'checked' or ''" />
+                                                                       <label 
i18n:translate="list_archive_all" for="archival_policy_all">The entire message, 
including attachments</label>
+                                                               </li>
+                                                               <li>
+                                                                       <input 
type="radio" class="oc-input-typeRadio" id="archival_policy_text" 
name="archival_policy"
+                                                                              
value="1" tal:attributes="checked python:policy == 1 and 'checked' or ''" />
+                                                                       <label 
i18n:translate="list_archive_text" for="archival_policy_text">The message text 
only</label>
+                                                               </li>
+                                                               <li>
+                                                                       <input 
type="radio" class="oc-input-typeRadio" id="archival_policy_none" 
name="archival_policy"
+                                                                              
value="2" tal:attributes="checked python:policy == 2 and 'checked' or ''" />
+                                                                       <label 
i18n:translate="list_archive_none" for="archival_policy_none">Do not archive 
messages</label>
+                                                               </li>
+                                                       </ul>
+                                               </fieldset>
+                                       </fieldset>
+
+<!-- submit -->
+                                       <fieldset>
+                                               <ul class="oc-actions">
+                                                       <li>
+                                                               <input 
type="submit" 
+                                                                      
name="task|edit" 
+                                                                      
value="Save" 
+                                                                      
i18n:attributes="value edit_edit_button"
+                                                                      
class="oc-button oc-chooseThis" />
+                                                       </li>
+                                                       <li>or <a 
i18n:translate="edit_list_cancel" href="">Cancel</a></li>
+                                               </ul>
+                                       </fieldset>
+                               </form>
+                       </div>
+               </div>
+       </body>
+</html>

Modified: opencore/trunk/opencore/listen/browser/listen_formlib.pt
===================================================================
--- opencore/trunk/opencore/listen/browser/listen_formlib.pt    2008-01-02 
17:02:19 UTC (rev 12226)
+++ opencore/trunk/opencore/listen/browser/listen_formlib.pt    2008-01-02 
17:03:48 UTC (rev 12227)
@@ -26,7 +26,7 @@
               tal:content="structure widget/error"
               class="oc-form-error" />
             <div class="oc-form-fieldBlock">
-              <input tal:replace="structure widget" />
+              <input tal:attributes="value python:widget.hasValidInput() and 
widget.getInputValue() or None" tal:replace="structure widget" />
             </div>
           </fieldset>
           <span class="oc-actions"

Modified: opencore/trunk/opencore/listen/browser/mailing_lists.pt
===================================================================
--- opencore/trunk/opencore/listen/browser/mailing_lists.pt     2008-01-02 
17:02:19 UTC (rev 12226)
+++ opencore/trunk/opencore/listen/browser/mailing_lists.pt     2008-01-02 
17:03:48 UTC (rev 12227)
@@ -15,7 +15,7 @@
         <div class="oc-headingBlock">
           <h1 i18n:translate="mailing_lists_heading">Mailing lists</h1>
           <p i18n:translate="mailing_lists_description" 
class="oc-headingContent">
-            View<span tal:condition="can_add_lists"> or manage 
exisiting</span> mailing lists<span tal:condition="can_add_lists"> or <a 
tal:attributes="href 
string:${context/absolute_url}/opencore.add_mailinglist">add a new mailing 
list</a></span>.
+            View<span tal:condition="can_add_lists"> or manage 
exisiting</span> mailing lists<span tal:condition="can_add_lists"> or <a 
tal:attributes="href string:${context/absolute_url}/create">add a new mailing 
list</a></span>.
           </p>
         </div>
   
@@ -104,7 +104,7 @@
       
       <div id="oc-content-sidebar">
         <div class="oc-getstarted">
-          <a class="oc-banana" tal:attributes="href 
string:${context/absolute_url}/opencore.add_mailinglist">Add a mailing list</a>
+          <a class="oc-banana" tal:attributes="href 
string:${context/absolute_url}/create">Add a mailing list</a>
        </div>
       </div>
     </div>

Modified: opencore/trunk/opencore/listen/browser/moderation.pt
===================================================================
--- opencore/trunk/opencore/listen/browser/moderation.pt        2008-01-02 
17:02:19 UTC (rev 12226)
+++ opencore/trunk/opencore/listen/browser/moderation.pt        2008-01-02 
17:03:48 UTC (rev 12227)
@@ -26,7 +26,7 @@
               </tr>
               </thead>
               <tbody>
-                <tr tal:repeat="post pending_list">
+                <tr tal:repeat="post pending_list" tal:attributes="id 
string:post_${post/postid}">
                   <td style="width: 25%;" tal:content="post/user_name" /> 
                   <td style="width: 49%;">
                     <dl class="oc-plainList">
@@ -43,22 +43,23 @@
                       <input type="hidden" name="email" tal:attributes="value 
python: str(post['user'])" />
                       <ul class="oc-actions oc-dataTable-row-actions 
oc-js-liveEdit-value">
                         <li>
-                          <input class="oc-actionLink" type="submit" 
name="post_approve" i18n:attributes="value moderation_approve_button" 
value="Approve" title="Allow this message to be posted" />
+                          <input type="submit" name="post_approve" 
class="oc-actionLink oc-actionButton oc-js-actionButton" tal:attributes="href 
string:moderation?post_approve=Approve&postid=${post/postid}&email=${post/user}"
 title="Allow this message to be posted" i18n:attributes="value 
moderation_approve_button" value="Approve" />
                         </li>
                         <li>
-                          <input class="oc-actionLink" type="submit" 
name="post_discard" i18n:attributes="value moderation_discard_button" 
value="Discard (Spam)" title="Deny this message without notifying the sender" />
+                          <input type="submit" name="post_discard" 
class="oc-actionLink oc-actionButton oc-js-actionButton" tal:attributes="href 
string: 
moderation?post_discard=moderation_discard_button&postid=${post/postid}&email=${post/user}"
 title="Deny this message without notifying the sender" i18n:attributes="value 
moderation_discard_button" value="Discard" />
                         </li>
-                        <li class="oc-js-liveEdit_showForm" 
tal:condition="python:is_post_moderated or is_membership_moderated">
-                          <a class="oc-actionLink" href="moderation#" 
title="Deny this message and notify the sender, message optional" 
i18n:attributes="value moderation_reject_button">Reject</a>
+                        <li class="" tal:condition="python:is_post_moderated 
or is_membership_moderated">
+                          <input type="submit" name="post_reject" 
class="oc-actionLink oc-actionButton oc-js-actionButton 
oc-js-liveEdit_showForm" tal:attributes="href string: 
moderation?post_deny=moderation_deny_button&postid=${post/postid}&email=${post/user}"
 title="Deny this message and notify the sender, message optional" 
i18n:attributes="value moderation_reject_confirm_button" value="Reject" />
                         </li>
                       </ul>
-                      <div class="oc-js-liveEdit-editForm oc-liveEdit-editForm 
oc-form-fieldBlock" style="display: none;" 
tal:condition="python:is_post_moderated or is_membership_moderated">
+                      <div class="oc-js-liveEdit-editForm oc-liveEdit-editForm 
oc-form-fieldBlock" tal:condition="python:is_post_moderated or 
is_membership_moderated">
                           <label class="oc-smallText" 
for="message_reject_reason" i18n:translate="moderation_reason">
                             <strong>Reason:</strong> <span 
class="oc-discreetText">(optional)</span>
                           </label>
                           <input id="message_reject_reason" 
name="reject_reason" type="text" />
-                          <input class="oc-actionLink" type="submit" 
name="post_reject" i18n:attributes="value moderation_reject_confirm_button" 
value="Reject" title="Deny this message and notify the sender, message 
optional"/> or <a href="#" class="oc-js-liveEdit_hideForm">Cancel</a>
 
+                          <input class="oc-actionLink oc-js-actionButton" 
name="post_reject" i18n:attributes="value moderation_reject_confirm_button"  
type="submit" value="Reject"  title="Deny this message and notify the sender, 
message optional"/> or <a href="#" class="oc-js-liveEdit_hideForm">Cancel</a>
+
                       </div>
                     </form>
                   </td>
@@ -88,19 +89,20 @@
                 <tr tal:repeat="pending_member pending_members">
                   <td tal:content="pending_member/user_name" />
                   <td>
-                    <form name="moderate-member-form" id="moderate-member-form"
+                    <form name="moderate-member-form" 
id="moderate-member-form" method="POST"
+                          class="oc-listen-moderate-form"
                           tal:attributes="action request/ACTUAL_URL">
                       <input type="hidden" name="email" tal:attributes="value 
pending_member/user" />
                       <ul class="oc-actions oc-dataTable-row-actions">
                         <li>
-                          <input i18n:attributes="value 
moderation_user_approve" type="submit" name="member_approve" value="Approve" />
+                          <input class="oc-actionLink" i18n:attributes="value 
moderation_user_approve" type="submit" name="member_approve" value="Approve" />
                         </li>
                         <li>
-                          <input i18n:attributes="value 
moderation_user_discard" type="submit" name="member_discard" value="Discard" />
+                          <input class="oc-actionLink" i18n:attributes="value 
moderation_user_discard" type="submit" name="member_discard" value="Discard" />
                         </li>
                         <li oc-form-fieldBlock>
                           <label for="user_reject_reason">
-                            <input i18n:attributes="value 
moderation_user_reject" type="submit" name="member_reject" value="Reject" />
+                            <input class="oc-actionLink" 
i18n:attributes="value moderation_user_reject" type="submit" 
name="member_reject" value="Reject" />
                           </label>
                           <input type="text" id="user_reject_reason" 
name="reject_reason" />
                         </li>

Modified: opencore/trunk/opencore/listen/browser/view.py
===================================================================
--- opencore/trunk/opencore/listen/browser/view.py      2008-01-02 17:02:19 UTC 
(rev 12226)
+++ opencore/trunk/opencore/listen/browser/view.py      2008-01-02 17:03:48 UTC 
(rev 12227)
@@ -1,28 +1,59 @@
-from Products.Five.browser import metaconfigure
-from Products.Five.browser import pagetemplatefile
 from Acquisition import aq_inner
-from zope.app.annotation.interfaces import IAnnotations
+from Products.CMFCore.utils import getToolByName
+from Products.Five.browser import metaconfigure, pagetemplatefile
+from Products.Five.browser.pagetemplatefile import ZopeTwoPageTemplateFile
 from Products.PageTemplates.PageTemplate import PageTemplate
-from Products.listen.browser.mail_archive_views import ArchiveForumView, 
ArchiveDateView
-from Products.listen.browser.mail_archive_views import ArchiveNewTopicView, 
SubFolderDateView
-from Products.listen.browser.mail_archive_views import ArchiveSearchView
-from Products.listen.browser.mail_message_views import ForumMailMessageView, 
ThreadedMailMessageView
-from Products.listen.browser.mail_message_views import MessageReplyView, 
SearchDebugView
+from Products.listen.browser.mail_archive_views import ArchiveForumView, 
ArchiveDateView, \
+                                                       ArchiveNewTopicView, 
SubFolderDateView, \
+                                                       ArchiveSearchView
+from Products.listen.browser.mail_message_views import ForumMailMessageView, 
ThreadedMailMessageView, \
+                                                       MessageReplyView, 
SearchDebugView
 from Products.listen.browser.manage_membership import ManageMembersView
-from Products.listen.browser.moderation import ModerationView
-from Products.listen.interfaces import IMailingList
+from Products.listen.browser.moderation import ModerationView as 
BaseModerationView
+from Products.listen.config import PROJECTNAME
+from Products.listen.config import MODERATION_FAILED
+from Products.listen.content import ListTypeChanged
+from Products.listen.interfaces.list_types import PublicListTypeDefinition, \
+                                                  
PostModeratedListTypeDefinition, \
+                                                  
MembershipModeratedListTypeDefinition
+from Products.listen.interfaces import IMailingList, IMembershipModeratedList, 
\
+                                       IPostModeratedList, IPublicList, \
+                                       IWriteMembershipList, IEmailPostPolicy, 
\
+                                       IUserEmailMembershipPolicy
+
 from Products.listen.utilities.list_lookup import ListLookupView
 from lxml.html.clean import Cleaner
-from opencore.browser.base import BaseView
+from opencore.browser.formhandler import OctopoLite, action
+from opencore.browser.base import BaseView, _
+from opencore.listen.mailinglist import OpenMailingList
 from opencore.listen.mailinglist_views import MailingListAddForm, 
MailingListEditForm, MailingListView
+from opencore.listen.utils import isValidPrefix
 from plone.app.form import _named
 from plone.memoize.view import memoize as req_memoize
+from zope.app.annotation.interfaces import IAnnotations
+from zope.app.component.hooks import getSite
+from zope.event import notify
 from zope.formlib.namedtemplate import INamedTemplate
-from zope.interface import implements
+from zope.interface import implements, directlyProvides
+from zExceptions import BadRequest
 import cgi
+import re
 import new
 import os.path
 
+_ml_type_to_workflow = {
+    PublicListTypeDefinition : 'policy_open',
+    PostModeratedListTypeDefinition : 'policy_moderated',
+    MembershipModeratedListTypeDefinition : 'policy_closed',
+    }
+
+_workflow_to_ml_type = dict((y, x) for x, y in _ml_type_to_workflow.items())
+
+_list_error_fields = ['title', 'mailto']
+def oc_json_error(v):
+    return {'html': v,
+            'action': 'copy',
+            }
 class ListenBaseView(BaseView):
     @req_memoize
     def list_url(self):
@@ -65,6 +96,235 @@
 
         return msgs
 
+    def getSuffix(self):
+        """
+        Retrieves the FQDN that is the list address suffix for a site from
+        the opencore_properties PropertySheet.  Requires a context object
+        from inside the site so the properties tool can be retrieved.
+        """
+        # use threadlocal site to hook into acquisition context
+        site = getSite()
+        ptool = getToolByName(site, 'portal_properties')
+        ocprops = ptool._getOb('opencore_properties')
+        return '@' + str(ocprops.getProperty('mailing_list_fqdn').strip())
+
+
+class ListenEditBaseView(ListenBaseView, OctopoLite):
+
+    def validate_form(self, justValidate=False, creation=False):
+        putils = getToolByName(self.context, 'plone_utils')
+        # Create an empty dictionary to hold any eventual errors.
+        self.errors = {}
+
+        # Let's do some form validation
+        # Get and clean up title from request
+        title = self.request.form.get('title', '')
+        title = re.compile('\s+').sub(' ', title).strip()
+        # The form title variable must be unicode or listen blows up
+        if not isinstance(title, unicode):
+            title = unicode(title, 'utf-8')
+
+        if title:
+            self.request.form['title'] = title
+        else:
+            self.errors['title'] = _(u'list_invalid_title', u'The mailing list 
must have a title.')
+
+        # Check the list of managers
+        form_managers = self.request.form.get('managers','')
+        if not isinstance(form_managers, unicode):
+            form_managers = unicode(form_managers, 'utf-8')
+        self.request.form['managers'] = form_managers
+
+        managers = []
+        bad_managers = []
+        if not form_managers:
+            self.errors['managers'] = _(u'list_no_managers_error', u'The 
mailing list must have at least one manager.')
+        else:
+            for manager in form_managers.split(','):
+                manager = manager.strip()
+                if not self.is_member(manager):
+                    bad_managers.append(manager)
+                else:
+                    managers.append(manager)
+
+        if bad_managers:
+            s_message_mapping = {'managers': ", ".join(bad_managers)}
+            self.errors['managers'] = _(u'list_invalid_managers_error',
+                                        u'The following managers are not 
members of this site: ${managers}',
+                                        mapping=s_message_mapping)
+
+        # Get and check the list policies
+        workflow = self.request.form.get('workflow_policy')
+        if workflow not in ('policy_open', 'policy_moderated', 
'policy_closed'):
+            self.errors['workflow_policy'] = _(u'list_invalid_workflow_error', 
u'The mailing list security must be set to open, moderated, or closed.')
+
+        archive = None
+        try:
+            archive = int(self.request.form.get('archival_policy'))
+        except TypeError:
+            pass 
+            
+        if archive not in (0, 1, 2):
+            self.errors['archive'] = _(u'list_invalid_archive_error', u'The 
mailing list archival method must be set to all, text-only, or none.')
+
+        mailto = None
+        if creation:
+            mailto = self.request.form.get('mailto')
+            if not mailto:
+                self.errors['mailto'] = _(u'list_missing_prefix_error', u'The 
mailing list must have a list prefix.')
+            elif not isValidPrefix(mailto):
+                self.errors['mailto'] = _(u'list_invalid_prefix_error', u'Only 
the following characters are allowed in list address prefixes: alpha-numerics, 
underscores, hyphens, and periods (i.e. A-Z, a-z, 0-9, and _-. symbols)')
+            else:
+                mailto = putils.normalizeString(mailto)
+                if hasattr(self.context, mailto):
+                    self.errors['mailto'] = _(u'list_create_duplicate_error', 
u'The requested list prefix is already taken.')
+
+        # If we don't pass sanity checks by this point, abort and let the user 
correct their errors.
+        if self.errors and not justValidate:
+            self.add_status_message(_(u'psm_correct_errors_below', u'Please 
correct the errors indicated below.'))
+            return False
+        return title, workflow, archive, mailto, managers
+
+
+    @action('validate')
+    def validate(self, target=None, fields=None):
+        putils = getToolByName(self.context, 'plone_utils')
+        result = self.validate_form(justValidate=True)
+
+        errors = dict (("oc-%s-error" % k, oc_json_error('')) for k in 
_list_error_fields)
+        #fixme: should not be default, should be translated.        
+        errors.update(dict (("oc-%s-error" % k, oc_json_error(v.default)) for 
k, v in self.errors.items()))
+        
+        mailto = self.request.form.get('mailto')
+        mailto = putils.normalizeString(mailto)
+
+        return errors
+
+
+    @action('validate-members')
+    def validate_members(self, target=None, fields=None):
+        # Check the list of members
+        form_members = self.request.form.get('members','')
+
+        members = []
+        bad_members = []
+        if not form_members:
+            return {
+                'rejects':'',
+                'valid':''
+            }
+        else:
+            for manager in form_members.split(','):
+                manager = manager.strip()
+                if not self.is_member(manager):
+                    bad_members.append(manager)
+                else:
+                    members.append(manager)
+        return {
+            'rejects':bad_members,
+            'valid':members
+        }
+
+class ListAddView(ListenEditBaseView):
+
+    template = ZopeTwoPageTemplateFile('create.pt')
+
+    @action('add')
+    def handle_request(self, target=None, fields=None):
+        # Get the tool used to normalize strings
+        putils = getToolByName(self.context, 'plone_utils')
+
+        result = self.validate_form(creation=True)
+        if not result:
+            return
+
+        title, workflow, archive, mailto, managers = result
+
+        # Try to create a mailing list using the mailto address to see if it's 
going to be valid
+        lists_folder = self.context
+        try:
+            lists_folder.invokeFactory(OpenMailingList.portal_type, mailto)
+        except BadRequest:
+            self.errors['mailto'] = _(u'list_create_duplicate_error', u'The 
requested list prefix is already taken.')
+            self.add_status_message(_(u'psm_correct_errors_below', u'Please 
correct the errors indicated below.'))
+            return
+
+        list = lists_folder._getOb(mailto)
+
+        list.managers = tuple(managers)
+        list.setDescription(unicode(self.request.form.get('description','')))
+
+        old_workflow_type = list.list_type
+        new_workflow_type = _workflow_to_ml_type[workflow]
+            
+        notify(ListTypeChanged(list,
+                               old_workflow_type.list_marker,
+                               new_workflow_type.list_marker))
+
+        list.archived = archive
+
+        self.template = None
+
+        #subscribe user to list
+        sub_list = IWriteMembershipList(list)
+        current_user = unicode(self.loggedinmember.getId())        
+        sub_list.subscribe(current_user)
+
+        s_message_mapping = {'title': title}
+        s_message = _(u'list_created',
+                      u'"${title}" has been created.',
+                      mapping=s_message_mapping)
+        
+        self.add_status_message(s_message)
+
+        self.redirect(list.absolute_url())
+
+
+class ListEditView(ListenEditBaseView):
+    template = ZopeTwoPageTemplateFile('edit.pt')
+
+    @action('edit')
+    def handle_request(self, target=None, fields=None):
+        result = self.validate_form()
+
+        if not result:
+            return
+
+        title, workflow, archive, mailto, managers = result
+
+        list = self.context
+
+        list.setTitle(title)        
+        list.setDescription(unicode(self.request.form.get('description','')))
+
+        old_workflow_type = list.list_type
+        new_workflow_type = _workflow_to_ml_type[workflow]
+            
+        notify(ListTypeChanged(list,
+                               old_workflow_type.list_marker,
+                               new_workflow_type.list_marker))
+
+        list.archived = archive
+
+        list.managers = tuple(managers)
+
+        self.template = None
+
+        s_message = _(u'list_preferences_updated',
+                      u'Your changes have been saved.')
+        
+        self.add_status_message(s_message)
+
+        self.redirect(list.absolute_url())
+
+    def workflow_policy(self):
+        return _ml_type_to_workflow[self.context.list_type]
+
+    def mailto(self):
+        return self.context.mailto.split("@")[0]
+
+
+
 # uh.. if you are going write meta factories you should write tests too
 # isn't this what super and mixins are is suppose to solve?
 def make_nui_listen_view_class(ListenClass, set_errors=False, 
add_update=False):
@@ -98,10 +358,77 @@
     
     return NuiListenView
 
+
+class ModerationView(BaseModerationView):
+    """A view for moderating things """
+
+    def __call__(self):
+        #figure out request method
+        method = self.request.environ['REQUEST_METHOD']
+        if method == "GET":
+            return self.index()
+
+        d = self.request.form
+        self.errors = ''
+        post = email = None
+        action = ''
+        postid = None
+        reject_reason = ''
+
+        # first check if mass moderating all posts
+        if d.get('discard_all_posts', False):
+            action = 'discard'
+            policy = getAdapter(self.context, IEmailPostPolicy)
+            for post in self.get_pending_lists():
+                postid = post['postid']
+                email = post['user']
+                req = dict(action=action, email=email, postid=postid)
+                policy_result = policy.enforce(req)
+                if policy_result == MODERATION_FAILED:
+                    self.errors = _(u'Could not moderate!')
+                    break
+            return self.index()
+
+        for name, value in d.items():
+            if name.endswith('_approve') or \
+               name.endswith('_discard') or \
+               name.endswith('_reject'):
+                action = value.split('_')[-1]
+            elif name == 'postid':
+                postid = int(value)
+            elif name == 'email':
+                email = value
+            elif name == 'reject_reason':
+                reject_reason = value            
+
+        json = {}
+        # having a post id specified means that we need to moderate posts
+        if postid is not None:
+            # using email post policy
+            # may have to try enforcing the ITTWPostPolicy as well on failure
+            policy = getAdapter(self.context, IEmailPostPolicy)
+            req = dict(action=action, email=email, postid=postid, 
reject_reason=reject_reason)
+            policy_result = policy.enforce(req)
+            if policy_result == MODERATION_FAILED:
+                self.errors = _(u'Could not moderate!')
+            json = {'post_%s' % postid : {'action': 'delete'}}
+        else:
+            # same idea between membership policy
+            # may have to try the IUserTTWMembershipPolicy if the email policy 
fails
+            policy = getAdapter(self.context, IUserEmailMembershipPolicy)
+            req = dict(action=action, email=email, reject_reason=reject_reason)
+            policy_result = policy.enforce(req)
+            if policy_result == MODERATION_FAILED:
+                self.errors = _(u'Could not moderate!')
+            json = {'member_%s' % postid : {'action': 'delete'}}
+        if 'mode' in self.request.keys() and self.request.mode == 'async':
+            return json
+        else:
+            self.redirect(self.request.ACTUAL_URL)
+
+
 # prefixing everything is unnecessary
 NuiMailingListView = make_nui_listen_view_class(MailingListView)
-NuiMailingListAddView = make_nui_listen_view_class(MailingListAddForm, 
set_errors=True, add_update=True)
-NuiMailingListEditView = make_nui_listen_view_class(MailingListEditForm, 
set_errors=True, add_update=True)
 
 
 from Products.listen.interfaces import IMembershipPendingList

Modified: opencore/trunk/opencore/listen/utils.py
===================================================================
--- opencore/trunk/opencore/listen/utils.py     2008-01-02 17:02:19 UTC (rev 
12226)
+++ opencore/trunk/opencore/listen/utils.py     2008-01-02 17:03:48 UTC (rev 
12227)
@@ -5,30 +5,29 @@
 from zope.app.component.hooks import getSite
 
 from Products.CMFCore.utils import getToolByName
-from Products.listen.interfaces.mailinglist import check_mailto
+from Products.listen.interfaces.mailinglist import check_mailto, 
ManagerMailTo, InvalidMailTo
 
 _ = MessageFactory("opencore")
 
-regex = re.compile(r'[^A-Za-z0-9_\-\.+]')
+invalid_list_prefix_re = re.compile(r'[^\w.-]')
 
-class InvalidPrefix(ValidationError):
-    __doc__ = _(u'listen_prefix_validation_error', u"Only the following 
characters are allowed in "
-                "list address prefixes: alpha-numerics, underscores, "
-                "hyphens, periods, and plus signs (i.e. A-Z, a-z, 0-9, "
-                "and _-.+ symbols).")
-
+#XXX: I'm not sure how this is supposed to work. - novalis
 def isValidPrefix(prefix):
     """
     Returns True if the prefix only contains valid email prefix chars,
-    raises an InvalidPrefix exception otherwise.
+    returns False otherwise
     """
-    # use getSite since we've got no other acq hook
     suffix = getSuffix()
-    check_mailto(prefix + suffix)
+    try:
+        check_mailto(prefix + suffix)
+    except InvalidMailTo:
+        return False
+    except ManagerMailTo:
+        return False
 
-    match = regex.search(prefix)
+    match = invalid_list_prefix_re.search(prefix)
     if match is not None:
-        raise InvalidPrefix
+        return False
     return True
     
 def getSuffix():
@@ -37,7 +36,7 @@
     the opencore_properties PropertySheet.  Requires a context object
     from inside the site so the properties tool can be retrieved.
     """
-    # use threadlocal site to hook into acquisition context
+    # use getSite since we've got no other acq hook    
     site = getSite()
     ptool = getToolByName(site, 'portal_properties')
     ocprops = ptool._getOb('opencore_properties')



--
Archive: 
http://www.openplans.org/projects/opencore/lists/openplans-svn/archive/2008/01/1199293429365
To unsubscribe send an email with subject unsubscribe to [EMAIL PROTECTED]  
Please contact [EMAIL PROTECTED] for questions.

Reply via email to