Hi,
just a patch to incorporate the CPSSchemas layout mechanism into the
post and reply forms of a Forum.
Michael
P.s. I had problems getting the patch command to work with the
isAllowedToPost.py file. If it fails add the parent_id=None to the list
of parameters.
Index: CPSForum/Forum.py
===================================================================
--- CPSForum/Forum.py (revision 24668)
+++ CPSForum/Forum.py (working copy)
@@ -215,7 +215,7 @@
#retrieve all root posts
result = [self.getPostInfo(post)
for post in proxy.objectValues(['CPS Proxy Document']) #[x for x in proxy.objectValues() if x.meta_type == 'CPS Proxy Document']
- if post.getContent().parent_id is None]
+ if not post.getContent().parent_id]
else:
discussion = self.portal_discussion.getDiscussionFor(self)
result = [ self.getPostInfo(post, discussion=1)
@@ -269,7 +269,7 @@
post_proxy = getattr(proxy, post_id)
post_doc = post_proxy.getContent()
- while post_doc.parent_id is not None:
+ while post_doc.parent_id:
post_proxy = getattr(proxy, post_doc.parent_id)
post_doc = post_proxy.getContent()
return post_doc
Index: CPSForum/skins/forum_default/isAllowedToPost.py
===================================================================
--- CPSForum/skins/forum_default/isAllowedToPost.py (revision 24668)
+++ CPSForum/skins/forum_default/isAllowedToPost.py (working copy)
@@ -1,4 +1,4 @@
-##parameters=is_poster=0,is_anon=1,forum=None
+##parameters=is_poster=0,is_anon=1,forum=None,parent_id=None
# $Id$
"""Determine whether the current user has posting rights on a forum"""
@@ -7,5 +7,9 @@
if ((is_anon and forum.anonymousPostsAllowed()) or
(not is_anon and is_poster)):
ret = 1
+ if parent_id is not None:
+ post = getattr(context, parent_id, None)
+ if forum.belongsToLockedThread(post, context):
+ ret = 0
return ret
Index: CPSForum/skins/forum_default/getCPSForumSchemas.py
===================================================================
--- CPSForum/skins/forum_default/getCPSForumSchemas.py (revision 24668)
+++ CPSForum/skins/forum_default/getCPSForumSchemas.py (working copy)
@@ -53,6 +53,7 @@
'author': {
'type': 'CPS String Field',
'data': {
+ 'default_expr': 'python:portal.getForumPostAuthor()',
'is_searchabletext': 1,
},
},
Index: CPSForum/skins/forum_default/forum_post_form.pt
===================================================================
--- CPSForum/skins/forum_default/forum_post_form.pt (revision 24668)
+++ CPSForum/skins/forum_default/forum_post_form.pt (working copy)
@@ -1,114 +1,49 @@
-<metal:block metal:use-macro="here/content_lib_master/macros/master">
-
-<metal:block fill-slot="header">
- <h1 tal:content="here/title_or_id">Title</h1>
- <div class="description" tal:content="doc/Description"
- tal:condition="doc/Description">
- Document Description goes here.
- </div>
-</metal:block>
-
-<metal:block fill-slot="css_slot">
- <link rel="Stylesheet" type="text/css" href=""
- tal:attributes="href string:${base_url}document.css" />
-</metal:block>
-
-<metal:block fill-slot="main"
- tal:define="parent_id options/parent_id|nothing;
- frm_start options/frm_start|nothing;
- forum here/getContent;
- member python:here.portal_membership.getAuthenticatedMember();
- dtool python:here.portal_directories.members;
- errormsg options/error_message|nothing;">
-
- <tal:block tal:condition="python:not forum.isFrozen()"
- tal:define="is_poster python:here.portal_membership.checkPermission('Forum Post',
+<metal:block tal:define="parent_id options/parent_id|nothing;
+ frm_start options/frm_start|nothing;
+ forum here/getContent;
+ member python:here.portal_membership.getAuthenticatedMember();
+ dtool python:here.portal_directories.members;
+ errormsg options/error_message|nothing;
+ isAnon here/portal_membership/isAnonymousUser;
+ is_frozen python: forum.isFrozen();
+ is_poster python:here.portal_membership.checkPermission('Forum Post',
forum);
- can_post python:here.isAllowedToPost(is_poster=is_poster,
- is_anon=isAnon,forum=forum)">
- <tal:block tal:condition="not:can_post">
- <p i18n:translate="forum_post_unauthorize">
- You are not authorized to post on this forum
- </p>
+ can_post python:here.isAllowedToPost(is_poster = is_poster,
+ is_anon = isAnon, forum = forum,
+ parent_id = parent_id);">
+ <metal:block tal:condition="can_post">
+ <tal:block define="res python: here.forum_post_create(REQUEST = request);
+ rendered_main python: res[0];
+ portal_status_message python: res[1];
+ edition python: 1;">
+ <metal:block use-macro="here/cpsdocument_edit_form/macros/edit_form"/>
</tal:block>
- <tal:block tal:condition="can_post">
- <form method="post" action="." enctype="multipart/form-data">
- <div class="group">
- <div class="row">
- <div class="label" i18n:translate="forum_author">Author</div>
- <div class="field">
- <tal:block condition="not:here/portal_membership/isAnonymousUser">
- <tal:block define="user_id member/getUserName;
- user_props python:dtool.getEntry(user_id);
- fullname python:user_props and
- user_props.get(dtool.title_field, user_id) or
- user_id;">
- <input type="hidden" name="author:string"
- tal:attributes="value user_id" />
- <span tal:replace="fullname" />
- </tal:block>
- </tal:block>
- <tal:block condition="here/portal_membership/isAnonymousUser">
- <input type="text" name="author:string" value="" />
- <span tal:condition="python:errormsg == 'error_author'"
- i18n:translate="forum_psm_name_required"
- class="forumError">Author field must be filled</span>
- </tal:block>
- </div>
+ </metal:block>
+ <metal:block tal:condition="not: can_post">
+ <metal:block metal:use-macro="here/content_lib_master/macros/master">
+ <metal:block fill-slot="header">
+ <h1 tal:content="here/title_or_id">Title</h1>
+ <div class="description" tal:content="doc/Description"
+ tal:condition="doc/Description">
+ Document Description goes here.
</div>
- <div class="row"
- tal:define="parent_info python:parent_id and getattr(here, parent_id);
- parent_subject python:parent_info and parent_info.Title()">
- <div class="label required"
- i18n:translate="forum_subject">Subject</div>
- <div class="field">
- <tal:block condition="parent_subject">
- <input type="text" name="subject:string" size="60"
- tal:attributes="value python:test(parent_subject.lower().startswith('re:'),
- parent_subject,
- 'Re: ' + parent_subject)" />
- </tal:block>
- <tal:block condition="not:parent_subject">
- <input type="text" name="subject:string" size="60" />
- </tal:block>
- </div>
- </div>
- <div class="row error"
- tal:condition="python:errormsg == 'error_subject'"
- i18n:translate="forum_psm_subject_required">
- Subject field must be filled
- </div>
- <div class="row">
- <div class="label"
- i18n:translate="forum_message">Message</div>
- <div class="field">
- <div style="width:550px; height:300px"
- tal:define="locale here/translation_service/getSelectedLanguage|string:en"
- tal:content="structure python:here.Epoz(name='message', data='', lang=locale, style='width:550px; height:220px; border:1px solid #A0A0A0; border-style:solid;')"></div>
- </div>
- </div>
- <div class="row">
- <div class="field">
- <input type="hidden" name="parent_id:string"
- tal:attributes="value parent_id" />
- <input type="hidden" name="frm_start"
- tal:attributes="value frm_start" />
- <input type="submit" name="forum_post:method"
- class="standalone" value="forum_post"
- i18n:attributes="value" />
- <input type="button" class="context" onClick="history.back()"
- value="button_cancel" i18n:attributes="value" />
- </div>
- </div>
- </div>
- </form>
- </tal:block>
- </tal:block>
+ </metal:block>
- <tal:block tal:condition="python:forum.isFrozen()">
- <p i18n:translate="forum_msg_forum_frozen">This forum is locked. You cannot post new messages to it.</p>
- </tal:block>
+ <metal:block fill-slot="css_slot">
+ <link rel="Stylesheet" type="text/css" href=""
+ tal:attributes="href string:${base_url}document.css" />
+ </metal:block>
+ <metal:block fill-slot="main">
+ <tal:block tal:condition="is_frozen">
+ <p i18n:translate="forum_msg_forum_frozen">This forum is locked. You cannot post new messages to it.</p>
+ </tal:block>
+ <tal:block tal:condition="not: can_post">
+ <p i18n:translate="forum_post_unauthorize">
+ You are not authorized to post on this forum
+ </p>
+ </tal:block>
+ </metal:block>
+ </metal:block>
+ </metal:block>
</metal:block>
-
-</metal:block>
Index: CPSForum/skins/forum_default/forum_post_create.py
===================================================================
--- CPSForum/skins/forum_default/forum_post_create.py (revision 0)
+++ CPSForum/skins/forum_default/forum_post_create.py (revision 0)
@@ -0,0 +1,34 @@
+##parameters=REQUEST
+"""
+Create a CPS ForumPost object.
+
+return html renderer + psm
+"""
+
+type_name = 'ForumPost'
+REQUEST.form.update({'type_name': type_name})
+ti = context.portal_types[type_name]
+validate = REQUEST.has_key('cpsdocument_create_button')
+
+parent_id = REQUEST.form.get('parent_id', None)
+parent_info = parent_id and getattr(context, parent_id)
+parent_subject = parent_info and parent_info.Title()
+## XXX - is there a nicer why of setting these values.
+## e.g. in the keyword arguements to renderCreateObjectDetailed
+if parent_id:
+ REQUEST.form.update({'widget__parent_id': parent_id})
+if parent_subject:
+ REQUEST.form.update({'widget__Title': 'Re: %s' % parent_subject})
+
+res = ti.renderCreateObjectDetailed(container=context, request=REQUEST,
+ validate=validate, layout_mode='create',
+ create_callback='forum_post_create_cb',
+ created_callback='forum_post_created')
+
+psm = ''
+if not res[1]:
+ psm = 'psm_content_error'
+elif validate:
+ psm = 'psm_content_created'
+
+return res[0], psm
Index: CPSForum/skins/forum_default/getCPSForumTypes.py
===================================================================
--- CPSForum/skins/forum_default/getCPSForumTypes.py (revision 24668)
+++ CPSForum/skins/forum_default/getCPSForumTypes.py (working copy)
@@ -70,6 +70,12 @@
'cps_workspace_wf': 'forum_post_wf',
'cps_section_wf': 'forum_post_wf',
'use_content_status_history': 1,
+ 'actions': ({'id': 'create',
+ 'name': 'action_create',
+ 'action': 'string:forum_post_form',
+ 'permissions': ('Change permissions',),
+ },
+ )
}
return {'CPSForum': forum_type,
Index: CPSForum/skins/forum_default/forum_post_created.py
===================================================================
--- CPSForum/skins/forum_default/forum_post_created.py (revision 0)
+++ CPSForum/skins/forum_default/forum_post_created.py (revision 0)
@@ -0,0 +1,20 @@
+##parameters=
+"""
+Do the necessary rendering or redirection after an object has been
+successfully created and filled with the initial values by the user.
+
+In CPS, context is a proxy.
+
+May return a rendered document, or do a redirect.
+"""
+
+psm = 'psm_content_created'
+parent = context.aq_parent # the forum
+if context.portal_membership.isAnonymousUser():
+ url = "%s?post_id=%s" % (parent.absolute_url(),
+ context.getId())
+else:
+ url = "%s?post_id=%s&portal_status_message=%s" % (parent.absolute_url(),
+ context.getId(),
+ 'forum_psm_message_posted')
+context.REQUEST.RESPONSE.redirect(url)
Index: CPSForum/skins/forum_default/forum_post.py
===================================================================
--- CPSForum/skins/forum_default/forum_post.py (revision 24668)
+++ CPSForum/skins/forum_default/forum_post.py (working copy)
@@ -1,53 +0,0 @@
-##parameters=subject,author,message,parent_id=None,frm_start=None,REQUEST=None
-
-# $Id$
-
-if not author:
- msg = 'error_author'
- return context.forum_post_form(error_message=msg)
-
-if not subject:
- msg = 'error_subject'
- return context.forum_post_form(error_message=msg)
-
-if not parent_id or parent_id.isspace():
- parent_id = None
-
-post_id = context.computeId(compute_from=subject)
-
-isAnon = context.portal_membership.isAnonymousUser()
-
-if isAnon:
- context.portal_discussion.createAnonymousForumPost(context, post_id,
- subject,
- author,
- message,
- parent_id)
-else:
- context.portal_workflow.invokeFactoryFor(context, 'ForumPost', post_id,
- subject=subject,
- author=author,
- message=message,
- parent_id=parent_id)
- forum = context.getContent()
- forum.newPostCreated(post_id, proxy=context)
-
-if REQUEST is not None:
- if not isAnon:
- if frm_start:
- url = "%s?post_id=%s&frm_start=%s" % (context.absolute_url(),
- post_id, frm_start)
- else:
- url = "%s?post_id=%s" % (context.absolute_url(),
- post_id)
- else:
- if frm_start:
- url = "%s?frm_start=%s?portal_status_message=%s" % (context.absolute_url(),
- frm_start,
- 'forum_psm_message_posted')
- else:
- url = "%s?portal_status_message=%s" % (context.absolute_url(),
- 'forum_psm_message_posted')
- REQUEST.RESPONSE.redirect(url)
-else:
- return post_id
Index: CPSForum/skins/forum_default/parentIdWidget.pt
===================================================================
--- CPSForum/skins/forum_default/parentIdWidget.pt (revision 0)
+++ CPSForum/skins/forum_default/parentIdWidget.pt (revision 0)
@@ -0,0 +1,12 @@
+<!--
+ Hide values within a form.
+ -->
+<tal:block define="name here/getWidgetId;
+ ds options/datastructure;
+ value python: ds.get('parent_id', '')">
+
+ <input type="hidden" name="" value=""
+ tal:attributes="value value;
+ name name;"/>
+
+</tal:block>
Index: CPSForum/skins/forum_default/getCPSForumLayouts.py
===================================================================
--- CPSForum/skins/forum_default/getCPSForumLayouts.py (revision 24668)
+++ CPSForum/skins/forum_default/getCPSForumLayouts.py (working copy)
@@ -129,13 +129,38 @@
'hidden_empty': 1,
},
},
+ 'parent_id': {
+ 'type': 'Method Widget',
+ 'data': {
+ 'title': '',
+ 'fields': ('parent_id',),
+ 'is_required': False,
+ 'label': '',
+ 'label_edit': '',
+ 'description': '',
+ 'help': '',
+ 'is_i18n': False,
+ 'readonly_layout_modes': (),
+ 'hidden_layout_modes': (),
+ 'hidden_readonly_layout_modes': (),
+ 'hidden_empty': False,
+ 'hidden_if_expr': '',
+ 'widget_mode_expr': '',
+ 'css_class': '',
+ 'css_class_expr': '',
+ 'javascript_expr': '',
+ 'render_method': 'parentIdWidget',
+ 'field_types': ('CPS String Field',),
+ },
},
+ },
'layout': {
'style_prefix': 'layout_default_',
'rows': [[{'widget_id': 'Title'}, ],
[{'widget_id': 'author'}, ],
[{'widget_id': 'Description'}, ],
[{'widget_id': 'links'}, ],
+ [{'widget_id': 'parent_id'}, ],
],
}
}
Index: CPSForum/skins/forum_default/getForumPostAuthor.py
===================================================================
--- CPSForum/skins/forum_default/getForumPostAuthor.py (revision 0)
+++ CPSForum/skins/forum_default/getForumPostAuthor.py (revision 0)
@@ -0,0 +1,8 @@
+##parameters=
+pm = context.portal_membership
+
+if pm.isAnonymousUser():
+ return ''
+
+member = pm.getAuthenticatedMember()
+return member.getUserName()
Index: CPSForum/skins/forum_default/forum_post_create_cb.py
===================================================================
--- CPSForum/skins/forum_default/forum_post_create_cb.py (revision 0)
+++ CPSForum/skins/forum_default/forum_post_create_cb.py (revision 0)
@@ -0,0 +1,53 @@
+##parameters=type_name, datamodel
+"""
+Callback to create an empty object with the context as a container.
+
+Datamodel may be examined to create a suitable id.
+
+Call notifyCPSDocumentCreation script
+
+Returns the created object. In CPS, returns the proxy (which is
+the only thing the user sees).
+"""
+
+folder = context
+
+author = datamodel.get('author')
+subject = datamodel.get('Title')
+message = datamodel.get('Description')
+
+parent_id = datamodel.get('parent_id')
+if not parent_id or parent_id.isspace():
+ parent_id = None
+
+post_id = context.computeId(compute_from = subject)
+
+isAnon = context.portal_membership.isAnonymousUser()
+
+language = datamodel.get('Language')
+if not language:
+ language = context.translation_service.getSelectedLanguage()
+
+if isAnon:
+ ## XXX - what does this do.
+ context.portal_discussion.createAnonymousForumPost(context, post_id,
+ subject,
+ author,
+ message,
+ parent_id)
+else:
+ context.invokeFactory('ForumPost', post_id,
+ subject = subject,
+ author = author,
+ message = message,
+ parent_id = parent_id,
+ datamodel = datamodel, language = language)
+ forum = context.getContent()
+ forum.newPostCreated(post_id, proxy=context)
+
+ob = getattr(context, post_id)
+
+## XXX - possible two events notified here.
+context.notifyCPSDocumentCreation(ob = ob)
+
+return ob
Index: CPSForum/tests/testForum.py
===================================================================
--- CPSForum/tests/testForum.py (revision 24668)
+++ CPSForum/tests/testForum.py (working copy)
@@ -65,14 +65,18 @@
forum = self.forum
proxy_forum = self.proxy_forum
self.assertEquals(forum.moderation_mode, 1)
- post_id = proxy_forum.forum_post(subject='subject', message='message',
- author='root')
+ post_id = self.proxy_forum.computeId(compute_from = 'subject')
+ proxy_forum.invokeFactory('ForumPost', post_id,
+ subject='subject', message='message',
+ author='root')
self.assertEquals(len(forum.getThreads(proxy=proxy_forum)), 1)
forum.forum_view()
forum.forum_view(post_id)
- proxy_forum.forum_post_reply(parent_id=post_id)
+ post_proxy = getattr(proxy_forum, post_id)
+ post_info = forum.getPostInfo(post_proxy)
+ proxy_forum.forum_post_reply(parent_id = post_id)
post_proxy = getattr(proxy_forum, post_id)
post_info = forum.getPostInfo(post_proxy)
@@ -80,7 +84,7 @@
self.assertEquals(post_info['subject'], "subject")
self.assertEquals(post_info['author'], "root")
self.assertEquals(post_info['message'], "message")
- self.assertEquals(post_info['parent_id'], None)
+ self.failIf(post_info['parent_id'])
self.assertEquals(post_info['published'], 1)
self.assertEquals(post_info['locked'], 0)
self.assert_(post_info['creation'])
@@ -102,8 +106,10 @@
proxy_forum = self.proxy_forum
forum.edit(moderation_mode=0)
self.assertEquals(forum.moderation_mode, 0)
- post_id = proxy_forum.forum_post(subject='subject', message='message',
- author='root')
+ post_id = self.proxy_forum.computeId(compute_from = 'subject')
+ proxy_forum.invokeFactory('ForumPost', post_id,
+ subject='subject', message='message',
+ author='root')
self.assertEquals(len(forum.getThreads(proxy=proxy_forum)), 1)
@@ -116,7 +122,7 @@
self.assertEquals(post_info['subject'], "subject")
self.assertEquals(post_info['author'], "root")
self.assertEquals(post_info['message'], "message")
- self.assertEquals(post_info['parent_id'], None)
+ self.failIf(post_info['parent_id'])
self.assertEquals(post_info['published'], 1)
self.assertEquals(post_info['locked'], 0)
self.assert_(post_info['creation'])
@@ -132,20 +138,25 @@
forum.edit(moderation_mode=0)
self.assertEquals(forum.moderation_mode, 0)
- post1_id = proxy_forum.forum_post(subject='subject1',
- message='message1',
- author='root')
+ post1_id = self.proxy_forum.computeId(compute_from = 'subject1')
+ proxy_forum.invokeFactory('ForumPost', post1_id,
+ subject='subject', message='message1',
+ author='root')
self.assertEquals(len(forum.getThreads(proxy=proxy_forum)), 1)
- post2_id = proxy_forum.forum_post(subject='subject1 reply',
- message='message1 reply',
- author='root',
- parent_id=post1_id)
+ post2_id = self.proxy_forum.computeId(compute_from = 'subject1 reply')
+ proxy_forum.invokeFactory('ForumPost', post2_id,
+ subject='subject', message='message',
+ author='root', parent_id = post1_id)
self.assertEquals(len(forum.getThreads(proxy=proxy_forum)), 1)
+ post2_proxy = getattr(proxy_forum, post2_id)
+ post2_info = forum.getPostInfo(post2_proxy)
+ self.assertEqual(post2_info['parent_id'], post1_id)
- post3_id = proxy_forum.forum_post(subject='subject2',
- message='message2',
- author='root')
+ post3_id = self.proxy_forum.computeId(compute_from = 'subject2')
+ proxy_forum.invokeFactory('ForumPost', post3_id,
+ subject='subject2', message='message2',
+ author='root')
self.assertEquals(len(forum.getThreads(proxy=proxy_forum)), 2)
self.assertEquals(len(forum.getDescendants(post1_id, proxy=proxy_forum)), 1)
_______________________________________________
cps-devel mailing list
http://lists.nuxeo.com/mailman/listinfo/cps-devel