Commit 74fc68a7 authored by Jérome Perrin's avatar Jérome Perrin

support_request_ui: Ingest post into Web Message

Also:
 * post are now HTML and not plain text
 * all event types are returned by
SupportRequest_getCommentPostListAsJson (so that the app can also
display support request used in "traditional" erp5 interface)
 * instead of immediate reindex, we store the "just posted" data in
portal_session.
 * events are created using resource defined as a web site "layout"
property (that's not yet editable)
 * posts do not receive a message-id yet (because ui part is not yet
updated for that), so generate a message-id server side (by just using
id)
parent b5153d8b
from Products.ERP5Type.ImmediateReindexContextManager import ImmediateReindexContextManager
follow_up_value = context.getPortalObject().restrictedTraverse(follow_up)
from Products.ERP5Type.Message import translateString
portal = context.getPortalObject()
follow_up_value = portal.restrictedTraverse(follow_up)
assert follow_up_value.getPortalType() == "Support Request"
follow_up_value.edit() # update modification date
with ImmediateReindexContextManager() as immediate_reindex_context_manager:
post = context.PostModule_createHTMLPostFromText(
follow_up=follow_up,
data=data,
immediate_reindex_context_manager=immediate_reindex_context_manager,
)
if file not in ("undefined", None): # XXX "undefined" ? should also be fixed in javascript side
document_kw = {'batch_mode': True,
'redirect_to_document': False,
'file': file}
document = context.Base_contribute(**document_kw)
# set relation between post and document
# XXX successor is used as a way to put a relation between the attachment and the post,
# the actual way should be to use a proper container like an Event that will have
# one or several posts and one or several attachments.
post.setSuccessorValueList([document])
# XXX depending on security model this should be changed accordingly
document.publish()
post.publish()
# update modification date
portal.portal_workflow.doActionFor(
follow_up_value,
'edit_action',
comment=translateString('New message posted.'))
post = context.PostModule_createHTMLPostFromText(
follow_up=follow_up,
data=data,
source_reference=source_reference,
)
if file not in ("undefined", None): # XXX "undefined" ? should also be fixed in javascript side
document_kw = {'batch_mode': True,
'redirect_to_document': False,
'file': file}
# XXX this Base_contribute might update in place another document with same reference
# and leave the post with a "dead link" for successor value.
document = context.Base_contribute(**document_kw)
# set relation between post and document
# XXX successor is used as a way to put a relation between the attachment and the post,
# the actual way should be to use a proper container like an Event that will have
# one or several posts and one or several attachments.
post.setSuccessorValueList([document])
# XXX depending on security model this should be changed accordingly
document.publish() # XXX isn't it share a better default ?
# XXX the UI of support request app should be responsible for generating a unique
# "message id" for each posted message.
if not post.getSourceReference():
post.setSourceReference(post.getId())
if not web_site_relative_url:
web_site_relative_url = context.getWebSiteValue().getRelativeUrl()
post.publish() # XXX
post.activate().Post_ingestMailMessageForSupportRequest(# XXX This API is not agreed
web_site_relative_url=web_site_relative_url
)
# to be able to display the just posted data in SupportRequest_getCommentPostListAsJson,
# we store it in a session variable.
successor_list = post.getSuccessorValueList()
successor_name = successor_link = None
if successor_list:
successor_link, successor_name = successor_list[0].getRelativeUrl(), successor_list[0].getFilename()
portal.portal_sessions[
'%s.latest_comment' % follow_up_value.getRelativeUrl()]['comment_post_list'] = (
post.Base_getOwnerTitle(),
post.getStartDate().rfc822(),
post.asStrippedHTML(),
successor_link,
successor_name,
post.getSourceReference(),
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>follow_up, predecessor, data, file</string> </value>
<value> <string>follow_up, predecessor, data, file, source_reference=None, web_site_relative_url=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
portal = context.getPortalObject()
support_request = context.getFollowUpValue()
web_site_value = portal.restrictedTraverse(web_site_relative_url)
# XXX what to do with PData ?
# As a first step just use a string.
data = str(context.getData())
is_html = context.getPortalType() == 'HTML Post'
if is_html:
# sanitize HTML
data = portal.portal_transforms.convertToData(
'text/x-html-safe',
data,
context=context,
mimetype=context.getContentType())
# lookup a resource and a source.
# It's critical for support request app that we can create movement with source and resouce
# because movements without source & resource does not get indexed in stock table. As this
# app uses Inventory API to list the history of movements, movements needs to be indexed.
resource = web_site_value.getLayoutProperty('preferred_event_resource', None)
if not resource:
resource = portal.portal_preferences.getPreferredEventResource()
assert resource, "No resource configured for event"
source_value = portal.portal_membership.getAuthenticatedMember().getUserValue()
if source_value is None:
# try harder to get a source for non-person users.
source_value = support_request.getSourceSectionValue()
web_message = portal.event_module.newContent(
portal_type='Web Message',
title=context.getTitle() if context.hasTitle() else None,
content_type='text/html' if is_html else 'text/plain',
text_content=data,
follow_up_value=support_request,
aggregate_value_list=[context] + context.getSuccessorValueList(
portal_type=portal.getPortalDocumentTypeList()),
resource=resource,
source_value=source_value,
start_date=context.getCreationDate(),
source_reference=context.getSourceReference())
web_message.stop()
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>web_site_relative_url</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Post_ingestMailMessageForSupportRequest</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -25,6 +25,8 @@ if description is not None or file is not None:
predecessor=None,
data="" if description is None else description,
file=file,
web_site_relative_url=context.getWebSiteValue().getRelativeUrl(),
source_reference=source_reference,
)
return support_request.Base_redirect('officejs_support_request_view',
......
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>description, file, resource, title, project, **kwargs</string> </value>
<value> <string>description, file, resource, title, project, source_reference=None, **kwargs</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
from json import dumps
portal = context.getPortalObject()
document_type_list = portal.getPortalDocumentTypeList()
preferred_date_order = portal.portal_preferences.getPreferredDateOrder() or "ymd"
preferred_date_order = "/".join(preferred_date_order)
def formatDate(date):
# XXX modification date & creation date are still in server timezone.
# See merge request !17
#
# if default_time_zone:
# date = date.toZone(default_time_zone)
return date.strftime("%s %%H:%%M" %(
preferred_date_order.
replace("y", "%Y").
replace("m", "%m").
replace("d", "%d"),
))
post_list = portal.portal_catalog(
portal_type="HTML Post",
strict_follow_up_uid=context.getUid(),
sort_on=(('modification_date', 'ascending'),),
validation_state="published",
event_list = portal.portal_simulation.getMovementHistoryList(
portal_type=portal.getPortalEventTypeList(),
strict_follow_up_uid=context.getUid(),
simulation_state=('started', 'stopped', 'delivered', ),
only_accountable=False,
omit_input=True,
sort_on=(('date', 'asc'), ('uid', 'asc',),)
)
comment_list = []
for post in post_list:
owner = post.Base_getOwnerTitle()
time_stamp = formatDate(post.getStartDate())
content = post.asStrippedHTML()
successor_list = post.getSuccessorValueList()
successor_name = successor_link = None
if successor_list:
successor_link, successor_name = successor_list[0].getRelativeUrl(), successor_list[0].getFilename()
comment_list.append((owner, time_stamp, content, successor_link, successor_name))
for event in event_list:
event = event.getObject()
attachment_link = attachment_name = None
attachment = event.getDefaultAggregateValue(portal_type=document_type_list)
if attachment is not None:
attachment_link, attachment_name = attachment.getRelativeUrl(), attachment.getFilename()
comment_list.append((
event.getSourceTitle(),
event.getStartDate().rfc822(),
event.asStrippedHTML(),
attachment_link,
attachment_name,
event.getSourceReference(),
))
just_posted_comment = portal.portal_sessions[
'%s.latest_comment' % context.getRelativeUrl()].pop(
'comment_post_list', None)
if just_posted_comment is not None:
# make sure not to display twice if it was already ingested in the meantime.
if just_posted_comment[-1] not in [comment[-1] for comment in comment_list]:
comment_list.append(just_posted_comment)
return dumps(comment_list)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment