diff --git a/product/ERP5/Document/Acknowledgement.py b/product/ERP5/Document/Acknowledgement.py new file mode 100644 index 0000000000000000000000000000000000000000..6cb9729f534f689b45a3d0054a6b1646d20fc396 --- /dev/null +++ b/product/ERP5/Document/Acknowledgement.py @@ -0,0 +1,80 @@ +############################################################################## +# +# Copyright (c) 2009 Nexedi SARL and Contributors. All Rights Reserved. +# Ben Mayhew <maybewhen@gmx.net> +# Sebastien Robin <seb@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +############################################################################## +from AccessControl import ClassSecurityInfo +from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface + +from Products.ERP5.Document.EmailDocument import EmailDocumentProxyMixin +from Products.ERP5.Document.Event import Event + +class Acknowledgement(EmailDocumentProxyMixin, Event): + """ + goal : + + Acts as a proxy to the message in the case of + - private email + - message displayed to the user ? + + We need this proxy because the user might not have the right to access + to the original message, and we don't wish to duplicate the content of + the original message (which can use attachements). + + Use Case: + + - A Site Notification is created in order to notify to all people of a + company. Then every time an user will acknowledge the notification, + a new Acknowledgement is created. + """ + + meta_type = 'ERP5 Acknowledgement' + portal_type = 'Acknowledgement' + add_permission = Permissions.AddPortalContent + isPortalContent = 1 + isRADContent = 1 + isDelivery = 1 + + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + + # Declarative properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.Document + , PropertySheet.DublinCore + , PropertySheet.Snapshot + , PropertySheet.Task + , PropertySheet.Url + , PropertySheet.Arrow + , PropertySheet.Event + , PropertySheet.Delivery + , PropertySheet.DocumentProxy + ) + + diff --git a/product/ERP5/Document/Document.py b/product/ERP5/Document/Document.py index f3376720dc33ece17c33d65b0a5d6a6f15382232..ab8dc8bb2058d9d39e6623d6a57960851feed75d 100644 --- a/product/ERP5/Document/Document.py +++ b/product/ERP5/Document/Document.py @@ -375,6 +375,31 @@ class PermanentURLMixIn(ExtensibleTraversableMixIn): document = document.__of__(self) return document +class DocumentProxyMixin: + """ + Provides access to documents referenced by the follow_up field + """ + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + + security.declareProtected(Permissions.AccessContentsInformation, + 'index_html' ) + def index_html(self, REQUEST, RESPONSE, format=None, **kw): + """ Only a proxy method """ + self.getProxiedDocument().index_html(REQUEST, RESPONSE, format, **kw) + + security.declareProtected(Permissions.AccessContentsInformation, + 'getProxiedDocument' ) + def getProxiedDocument(self): + """ + Try to retrieve the original document + """ + proxied_document = self.getDocumentProxyValue() + if proxied_document is None: + raise ValueError("Unable to find a proxied document") + return proxied_document + class UpdateMixIn: """ Provides an API to compute a date index based on the update @@ -1550,4 +1575,4 @@ class Document(PermanentURLMixIn, XMLObject, UrlMixIn, ConversionCacheMixin, Sna # Cut the trailing part in http://www.some.site/at/trailing.html # but not in http://www.some.site/at base_url = '/'.join(base_url_list[:-1]) - return base_url \ No newline at end of file + return base_url diff --git a/product/ERP5/Document/EmailDocument.py b/product/ERP5/Document/EmailDocument.py index 50588d960f49e5d7ac140bae5138cd60e67bc533..2a1426f4e3d2882404ab35c6e2b6d53653588592 100644 --- a/product/ERP5/Document/EmailDocument.py +++ b/product/ERP5/Document/EmailDocument.py @@ -38,8 +38,9 @@ from Products.CMFDefault.utils import isHTMLSafe from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface from Products.ERP5.Document.TextDocument import TextDocument from Products.ERP5.Document.File import File -from Products.ERP5.Document.Document import ConversionError +from Products.ERP5.Document.Document import ConversionError, DocumentProxyMixin from Products.ERP5.Tool.NotificationTool import buildEmailMessage +from MethodObject import Method from zLOG import LOG, INFO @@ -62,6 +63,39 @@ _MARKER = [] file_name_regexp = 'name="([^"]*)"' + +class EmailDocumentProxyMixin(DocumentProxyMixin): + """ + Provides access to documents referenced by the causality field + """ + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + + +class ProxiedMethod(Method): + """ + Accessort that retrieve methods directly on the proxy + """ + + def __init__(self, proxied_method_id): + self.proxied_method_id = proxied_method_id + + def __call__(self, instance, *args, **kw): + proxied_document = instance.getProxiedDocument() + method = getattr(proxied_document, self.proxied_method_id) + return method(*args, **kw) + +# generate all proxy method on EmailDocumentProxyMixin +for method_id in ('getTextContent', 'getTextFormat', 'hasFile', + 'getContentInformation', 'getAttachmentData', + 'getAttachmentInformationList'): + EmailDocumentProxyMixin.security.declareProtected( + Permissions.AccessContentsInformation, + method_id) + setattr(EmailDocumentProxyMixin, method_id, + ProxiedMethod(method_id)) + class EmailDocument(File, TextDocument): """ EmailDocument is a File which stores its metadata in a form which diff --git a/product/ERP5/Document/Event.py b/product/ERP5/Document/Event.py index 1d1a2b421c9ee7a00b42f1609080f361845a2ac8..5ac30b3612bd8394c43e13505db44cefc9f28577 100644 --- a/product/ERP5/Document/Event.py +++ b/product/ERP5/Document/Event.py @@ -32,7 +32,62 @@ from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5.Document.Movement import Movement from Products.ERP5.Document.EmailDocument import EmailDocument -class Event(EmailDocument, Movement): +class AcknowledgeableMixin: + """ + Mixin class for all documents that we can acknowledge + """ + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + + security.declareProtected(Permissions.AccessContentsInformation, 'acknowledge') + def acknowledge(self, **kw): + """ + Define what we want to do with acknowledgment. + + Possibilities : + - do nothing + - add an Acknowledge document every time someone read + an event corresponding to this ticket + - we could even think to move the workflow forward + when all event have been acknowledge + + Is the name buildAcknowledgement better ??? + """ + method = self._getTypeBasedMethod('acknowledge') + if method is not None: + return method(**kw) + return None + + def hasAcknowledgementActivity(self, user_name=None): + """ + We will check if there is some current activities running or not + """ + tag = "%s_%s" % (user_name, self.getRelativeUrl()) + result = False + # First look at activities, we check if an acknowledgement document + # is under reindexing + if self.portal_activities.countMessageWithTag(tag): + result = True + return result + + security.declareProtected(Permissions.AccessContentsInformation, 'isAcknowledged') + def isAcknowledged(self, user_name=None): + """ + Say if this ticket is already acknowledged or not by this user. + """ + result = self.hasAcknowledgementActivity(user_name=user_name) + if not result: + # Check in the catalog if we can find an acknowledgement + person_value = self.ERP5Site_getAuthenticatedMemberPersonValue( + user_name=user_name) + if len(self.portal_catalog(portal_type='Acknowledgement', + causality_relative_url=self.getRelativeUrl(), + destination_relative_url=person_value.getRelativeUrl())) > 0: + result = True + return result + +class Event(EmailDocument, Movement, AcknowledgeableMixin): """ Event is the base class for all events in ERP5. diff --git a/product/ERP5/ERP5Site.py b/product/ERP5/ERP5Site.py index cbc8f08e58533de636b4b2c00b1f0285e8dec6aa..7ac091edb3b8d91ef836f3b46809ac23fcff08b1 100644 --- a/product/ERP5/ERP5Site.py +++ b/product/ERP5/ERP5Site.py @@ -1338,6 +1338,8 @@ class ERP5Generator(PortalGenerator): addTool('ERP5 Test Tool', None) if not p.hasObject('portal_password'): addTool('ERP5 Password Tool', None) + if not p.hasObject('portal_acknowledgements'): + addTool('ERP5 Acknowledgement Tool', None) # Add ERP5Type Tool addTool = p.manage_addProduct['ERP5Type'].manage_addTool diff --git a/product/ERP5/PropertySheet/DocumentProxy.py b/product/ERP5/PropertySheet/DocumentProxy.py new file mode 100755 index 0000000000000000000000000000000000000000..cf49d3df83e18ac276d91053a704d0d75a1b8143 --- /dev/null +++ b/product/ERP5/PropertySheet/DocumentProxy.py @@ -0,0 +1,34 @@ +############################################################################## +# +# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved. +# Sebastien Robin <seb@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +class DocumentProxy: + """ + Document Proxy properties + """ + + _categories = ( 'document_proxy', ) diff --git a/product/ERP5/Tool/AcknowledgementTool.py b/product/ERP5/Tool/AcknowledgementTool.py new file mode 100644 index 0000000000000000000000000000000000000000..b00cc3902576938aa471515f82097eef60b6fd32 --- /dev/null +++ b/product/ERP5/Tool/AcknowledgementTool.py @@ -0,0 +1,173 @@ +############################################################################## +# +# Copyright (c) 2009 Nexedi SARL and Contributors. All Rights Reserved. +# Ben Mayhew <maybewhen@gmx.net> +# Sebastien Robin <seb@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +############################################################################## +from AccessControl import ClassSecurityInfo +from Globals import InitializeClass, DTMLFile +from Products.ERP5Type.Tool.BaseTool import BaseTool +from Products.ERP5Type import Permissions +from Products.ERP5 import _dtmldir +from Products.ERP5.Document.Acknowledgement import Acknowledgement +from zLOG import LOG +from DateTime import DateTime +from Products.ZSQLCatalog.SQLCatalog import Query, NegatedQuery + + +class AcknowledgementTool(BaseTool): + """ + Provide an entry point to track reception of events + + someone who can not view the ticket or the event + must be able to acknowledge reception of email + or of site message sent by CRM. + + This tools take into account that for some kind of document, + acknowledgements are not created in advance. For Site Message, + acknowledgements will be created every time the user confirm that he has + read the information. + + In the case of internal emails, acknowledgements are created in advance. + + Use Case: who read the emails I sent ? + Use Case: who said OK to Site Message ? + """ + id = 'portal_acknowledgements' + meta_type = 'ERP5 Acknowledgement Tool' + portal_type = 'Acknowledgement Tool' + allowed_types = ('ERP5 Acknowledgement',) + # Declarative Security + security = ClassSecurityInfo() + + + security.declarePublic('getUnreadAcknowledgementList') + def countUnread(self, *args, **kw): + """ + counts number of acknowledgements pending + """ + return len(self.getUnreadAcknowledgementList(*args, **kw)) + + security.declarePublic('getUnreadAcknowledgementList') + def getUnreadAcknowledgementList(self, portal_type=None, user_name=None, + url_list=None): + """ + returns acknowledgements pending + in the form of + - TempAcknowledgement (for Site Message) + - Acknowledgement (internal email) + """ + portal = self.getPortalObject() + return_list = [] + if url_list is None: + url_list = self.getUnreadDocumentUrlList(portal_type=portal_type, + user_name=user_name) + for url in url_list: + document = portal.restrictedTraverse(url) + if not document.isAcknowledged(user_name=user_name): + # If the document to acknowledge is a ticket, we should return + # a temp acknowledgement + if document.getPortalType() in portal.getPortalEventTypeList(): + module = portal.getDefaultModule('Acknowledgement') + temp_acknowledgement = module.newContent( + portal_type='Acknowledgement', + temp_object=1, + document_proxy=document.getRelativeUrl(), + causality=document.getRelativeUrl()) + return_list.append(temp_acknowledgement) + else: + # If not an event, this means that we have directly the document + # that we must acknowledge + return_list.append(document) + return return_list + + security.declarePublic('getUnreadDocumentUrlList') + def getUnreadDocumentUrlList(self, portal_type=None, user_name=None, **kw): + """ + returns document that needs to be acknowledged : + - Acknowledgement (internal email) + - Site Message + + This method will mainly be used by getUnreadAcknowledgementList. Also, + because url are used, the result will be easy to cache. + """ + document_list = [] + if user_name is not None: + portal = self.getPortalObject() + now = DateTime() + # First look at all event that define the current user as destination + all_document_list = [x for x in \ + self.portal_catalog(portal_type = portal_type, + simulation_state = self.getPortalTransitInventoryStateList(), + # start_date = {'query':now,'range':'max'}, + # stop_date = {'query':now,'range':'min'}, + default_destination_reference=user_name)] + # Now we can look directly at acknowledgement document not approved yet + # so not in a final state + final_state_list = self.getPortalCurrentInventoryStateList() + query = NegatedQuery(Query(simulation_state=final_state_list)) + all_document_list.extend([x for x in \ + self.portal_catalog(portal_type = portal_type, + query=query, + # start_date = {'query':now,'range':'max'}, + # stop_date = {'query':now,'range':'min'}, + destination_reference=user_name)]) + for document in all_document_list: + # We filter manually on dates until a good solution is found for + # searching by dates on the catalog + if (document.getStartDate() < now < (document.getStopDate()+1)): + acknowledged = document.isAcknowledged(user_name=user_name) + if not acknowledged: + document_list.append(document.getRelativeUrl()) + else: + raise ValueError('No user name given') + return document_list + + security.declareProtected(Permissions.AccessContentsInformation, + 'acknowledge') + def acknowledge(self, uid=None, path=None, user_name=None, **kw): + """ + Create an acknowledgement document for : + - a ticket + - an event + - an acknowledgement + + This methods needs to check if there is already ongoing ackowledgement + for the document of for this user. We will have to use activities with + tag and probably a serialization. + """ + document = None + if uid is not None: + document = self.portal_catalog.getObject(uid) + elif path is not None: + document = self.restrictedTraverse(path) + else: + raise ValueError("No path or uid given") + if document is None: + raise ValueError("Ticket does not exist or you don't have access to it") + return document.acknowledge(user_name=user_name, **kw) + + +InitializeClass(AcknowledgementTool) diff --git a/product/ERP5/__init__.py b/product/ERP5/__init__.py index 5cca0263e5ec7c7472b51df9846981ba2982e0cb..5499b6695e088c5f60420cb8e64625d273693fd2 100644 --- a/product/ERP5/__init__.py +++ b/product/ERP5/__init__.py @@ -47,7 +47,8 @@ product_path = package_home( globals() ) from Tool import CategoryTool, SimulationTool, RuleTool, IdTool, TemplateTool,\ TestTool, DomainTool, AlarmTool, OrderTool, DeliveryTool,\ TrashTool, ContributionTool, NotificationTool, PasswordTool,\ - GadgetTool, ContributionRegistryTool, IntrospectionTool + GadgetTool, ContributionRegistryTool, IntrospectionTool,\ + AcknowledgementTool import ERP5Site object_classes = ( ERP5Site.ERP5Site, ) @@ -68,6 +69,7 @@ portal_tools = ( CategoryTool.CategoryTool, GadgetTool.GadgetTool, ContributionRegistryTool.ContributionRegistryTool, IntrospectionTool.IntrospectionTool, + AcknowledgementTool.AcknowledgementTool, ) content_classes = () content_constructors = () diff --git a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/bulletin_board.xml b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/bulletin_board.xml new file mode 100644 index 0000000000000000000000000000000000000000..24b67a02b51adea9386d1224294372dc9b5d8eb5 --- /dev/null +++ b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/bulletin_board.xml @@ -0,0 +1,79 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <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_subpath</string> </key> + <value> <string>traverse_subpath</string> </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </state> + </object> + </value> + </item> + <item> + <key> <string>_text</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +<tal:block xmlns:tal="http://xml.zope.org/namespaces/tal"\n + xmlns:metal="http://xml.zope.org/namespaces/metal"\n + xmlns:i18n="http://xml.zope.org/namespaces/i18n">\n + <tal:block metal:define-macro="master">\n + <tal:block tal:repeat="item here/AcknowledgementTool_getUserUnreadAcknowledgementList | nothing">\n + <div class="dialog_box">\n + <div class="list_dialog">\n + <tal:div content="structure item/text_content" />\n + </div>\n + <a tal:attributes="href item/acknowledge_url"><button>DISMISS</button></a>\n + </div>\n + </tal:block>\n + </tal:block>\n +</tal:block>\n + + +]]></string> </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>text/html</string> </value> + </item> + <item> + <key> <string>expand</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>bulletin_board</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/template_erp5_xhtml_style.xml b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/template_erp5_xhtml_style.xml index 8c323e2878145bdea0fff836b3a70b67fe75860e..3a9b291f1c8ef00d162bba71c3d0da44b20ab942 100644 --- a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/template_erp5_xhtml_style.xml +++ b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/template_erp5_xhtml_style.xml @@ -129,6 +129,9 @@ IDEAS:\n </tal:block>\n </div>\n <p class="clear"></p>\n + <div id="bulletin_board">\n + <div tal:content="structure here/bulletin_board"/>\n + </div>\n <div tal:content="request/portal_status_message | nothing" id="transition_message" />\n <div id="information_area" tal:condition="request/field_errors | nothing"\n i18n:translate="" i18n:domain="ui">\n diff --git a/product/ERP5/bootstrap/erp5_xhtml_style/bt/revision b/product/ERP5/bootstrap/erp5_xhtml_style/bt/revision index cbb5735d831582b9cb1038377ec1114c6c947561..72c2a20c91294863bcd1770213c774d1565c6164 100644 --- a/product/ERP5/bootstrap/erp5_xhtml_style/bt/revision +++ b/product/ERP5/bootstrap/erp5_xhtml_style/bt/revision @@ -1 +1 @@ -760 \ No newline at end of file +761 diff --git a/product/ERP5/tests/testAcknowledgementTool.py b/product/ERP5/tests/testAcknowledgementTool.py new file mode 100644 index 0000000000000000000000000000000000000000..00d3383612799436b481af988b2761e71547a16a --- /dev/null +++ b/product/ERP5/tests/testAcknowledgementTool.py @@ -0,0 +1,118 @@ +############################################################################## +# -*- coding: utf8 -*- +# Copyright (c) 2007 Nexedi SA and Contributors. All Rights Reserved. +# Sebastien Robin <seb@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +import unittest +from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase +import transaction +from DateTime import DateTime + +class TestAcknowledgementTool(ERP5TypeTestCase): + + def getTitle(self): + return "AcknowledgementTool" + + def getBusinessTemplateList(self): + return ('erp5_base', + 'erp5_crm',) + + def test_01_checkAcknowledgementToolWithOneEvent(self): + """ + Create an event of type site message, post it and check that the + acknowledgement tool is able to see it + """ + event_type = "Site Message" + portal = self.getPortalObject() + module = portal.getDefaultModule(event_type) + event = module.newContent(portal_type=event_type) + person_module = portal.getDefaultModule('Person') + person = person_module.newContent(portal_type='Person', title='Seb', + reference='seb') + now = DateTime() + event.edit(destination_value=person, + text_content="A Nice Message", + text_format="text/plain", + title="foo", + start_date = now-2, + stop_date = now+2) + portal.portal_workflow.doActionFor(event, 'start_action') + self.assertEqual(event.getSimulationState(), 'started') + transaction.commit() + self.tic() + + acknowledgement_tool_kw = {} + acknowledgement_tool_kw['user_name'] = 'seb' + acknowledgement_tool_kw['portal_type'] = event_type + document_url_list = portal.portal_acknowledgements\ + .getUnreadDocumentUrlList(**acknowledgement_tool_kw) + self.assertTrue(event.getRelativeUrl() in document_url_list) + + # function in order to retrieve many times the list of acknowledgements + def getEventAcknowlegementList(): + acknowledgement_list = portal.portal_acknowledgements\ + .getUnreadAcknowledgementList( + **acknowledgement_tool_kw) + event_acknowledgement_list = [x for x in acknowledgement_list + if x.getCausality() == event.getRelativeUrl()] + return event_acknowledgement_list + + # We should have unread acknowledgement + event_acknowledgement_list = getEventAcknowlegementList() + self.assertEqual(1, len(event_acknowledgement_list)) + + # Check that the content is retrieved on the original event + event_acknowledgement = event_acknowledgement_list[0] + self.assertEqual(event_acknowledgement.getTextContent(), "A Nice Message") + + # We know acknowledge the event + acknowledgement = portal.portal_acknowledgements.acknowledge( + path=event.getRelativeUrl(), + user_name='seb') + # Make sure that we have a new acknowledge document wich is a proxy of + # the event + self.assertEqual(acknowledgement.getPortalType(), 'Acknowledgement') + self.assertEqual(acknowledgement.getTextContent(), "A Nice Message") + transaction.commit() + + # We should not have any acknowledgements, we just commited previous + # transaction, this means that we look if the mechanism that looks at + # activity tags is working or not + event_acknowledgement_list = getEventAcknowlegementList() + # We should not have any acknowledgements, tic is finished + # the code should look directly for acnowledgement documents + self.tic() + event_acknowledgement_list = getEventAcknowlegementList() + self.assertEqual(0, len(event_acknowledgement_list)) + + # We should have one acknowledgement in the event module + + + +def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestAcknowledgementTool)) + return suite