Esempio n. 1
0
 def test_restapi_add_item_with_annexes_children(self):
     """When creating an item, we may add annexes as __children__,
        we may add several annexes at once."""
     cfg = self.meetingConfig
     self.changeUser("pmManager")
     endpoint_url = "{0}/@item".format(self.portal_url)
     json = {
         "config_id":
         cfg.getId(),
         "proposingGroup":
         self.developers.getId(),
         "title":
         "My item",
         "__children__": [
             {
                 "@type": "annex",
                 "title": "My annex 1",
                 "content_category": "item-annex",
                 "file": {
                     "data": "123456",
                     "encoding": "ascii",
                     "filename": "file.txt",
                 },
             },
             {
                 "@type": "annex",
                 "title": "My annex 2",
                 "content_category": "item-annex",
                 "file": {
                     "data": base64_pdf_data,
                     "filename": "file.pdf"
                 },
             },
         ],
     }
     response = self.api_session.post(endpoint_url, json=json)
     transaction.commit()
     # this tries to manage randomly failing test
     try:
         self.assertEqual(response.status_code, 201, response.content)
     except Exception:
         response = self.api_session.post(endpoint_url, json=json)
         transaction.commit()
         self.assertEqual(response.status_code, 201, response.content)
     pmFolder = self.getMeetingFolder()
     item = pmFolder.objectValues()[-1]
     annex1 = get_annexes(item)[0]
     annex2 = get_annexes(item)[1]
     self.assertEqual(annex1.file.filename,
                      json["__children__"][0]["file"]["filename"])
     self.assertEqual(annex1.file.size, 6)
     self.assertEqual(annex1.file.contentType, "text/plain")
     self.assertEqual(annex2.file.filename,
                      json["__children__"][1]["file"]["filename"])
     self.assertEqual(annex2.file.size, 6475)
     self.assertEqual(annex2.file.contentType, "application/pdf")
 def test_ws_createItemWithAnnexNotRecognizedByLibmagicRequest(self):
     """
       Test SOAP service behaviour when creating items with one annex that is not recognized
       by libmagic.  The annex used here is a MS Word .doc file that fails to be recognized when
       using libmagic/file 5.09
     """
     self.changeUser('pmCreator1')
     req = self._prepareCreationData()
     data = {
         'title': 'My crashing created annex',
         'filename': 'file_crash_libmagic.doc',
         'file': 'file_crash_libmagic.doc'
     }
     req._creationData._annexes = [self._prepareAnnexInfo(**data)]
     annex = req._creationData._annexes[0]
     # first make sure this file crash libmagic
     self.assertRaises(MagicException,
                       magic.Magic(mime=True).from_buffer, annex._file)
     newItem, response = self._createItem(req)
     # the annex is nevertheless created and correctly recognized because it had a correct file extension
     annexes = get_annexes(newItem)
     self.failUnless(len(annexes) == 1)
     # the annex mimetype is correct
     annex = annexes[0]
     self.failUnless(annex.file.contentType == 'application/msword')
     # the annex metadata are ok
     self.failUnless(
         annex.Title() == 'My crashing created annex'
         and annex.getMeetingFileType().getId() == 'financial-analysis')
     # if libmagic crash and no valid filename provided, the annex is not created
     data = {
         'title': 'My crashing NOT created annex',
         'filename': 'file_crash_libmagic_without_extension',
         'file': 'file_crash_libmagic.doc'
     }
     req._creationData._annexes = [self._prepareAnnexInfo(**data)]
     newItem2, response = self._createItem(req)
     self.failUnless(len(get_annexes(newItem2)) == 0)
     # a warning specifying that annex was not added because mimetype could
     # not reliabily be found is added in the response
     self.assertEqual(response._warnings, [
         translate(MIMETYPE_NOT_FOUND_OF_ANNEX_WARNING,
                   domain='imio.pm.ws',
                   mapping={
                       'annex_path': (data['filename']),
                       'item_path': newItem2.absolute_url_path()
                   },
                   context=self.portal.REQUEST)
     ])
Esempio n. 3
0
 def test_restapi_add_item_with_annexes_and_check_encoding(self):
     """When creating an item, we may add annexes as __children__,
        if encoding not given, we assume it is 'base64'."""
     cfg = self.meetingConfig
     self.changeUser("pmManager")
     endpoint_url = "{0}/@item".format(self.portal_url)
     json = {
         "config_id":
         cfg.getId(),
         "proposingGroup":
         self.developers.getId(),
         "title":
         "My item",
         "__children__": [
             {
                 "@type": "annex",
                 "title": "My annex",
                 "content_category": "item-annex",
                 "file": {
                     "data": base64_pdf_data,
                     "filename": "file.pdf"
                 },
             },
         ],
     }
     response = self.api_session.post(endpoint_url, json=json)
     transaction.begin()
     self.assertEqual(response.status_code, 201, response.content)
     pmFolder = self.getMeetingFolder()
     item = pmFolder.objectValues()[-1]
     annex = get_annexes(item)[0]
     self.assertEqual(annex.file.filename,
                      json["__children__"][0]["file"]["filename"])
     self.assertEqual(annex.file.size, 6475)
     self.assertEqual(annex.file.contentType, "application/pdf")
Esempio n. 4
0
 def showDecisionAnnexesSection(self):
     """Check if context contains decisionAnnexes or if there
        are some decisionAnnex annex types available in the configuration."""
     if self.context.__class__.__name__ == 'MeetingItem' and \
         (get_annexes(self.context, portal_types=['annexDecision']) or
          self._showAddAnnexDecision):
         return True
     return False
Esempio n. 5
0
 def test_restapi_add_a_meeting_with_annexes(self):
     """When creating a meeting, we may add annexes as __children__,
        we may add several annexes at once."""
     cfg = self.meetingConfig
     self.changeUser("pmManager")
     endpoint_url = "{0}/@item".format(self.portal_url)
     json = {
         "config_id":
         cfg.getId(),
         "date":
         "2022-02-02 12:00",
         "__children__": [
             {
                 "@type": "annex",
                 "title": "My annex 1",
                 "file": {
                     "data": "123456",
                     "encoding": "ascii",
                     "filename": "file.txt",
                 },
             },
             {
                 "@type": "annex",
                 "title": "My annex 2",
                 "file": {
                     "data": base64_pdf_data,
                     "filename": "file.pdf"
                 },
             },
         ],
     }
     response = self.api_session.post(endpoint_url, json=json)
     transaction.begin()
     self.assertEqual(response.status_code, 201, response.content)
     pmFolder = self.getMeetingFolder()
     meeting = pmFolder.objectValues()[-1]
     annex1 = get_annexes(meeting)[0]
     annex2 = get_annexes(meeting)[1]
     self.assertEqual(annex1.file.filename,
                      json["__children__"][0]["file"]["filename"])
     self.assertEqual(annex1.file.size, 6)
     self.assertEqual(annex1.file.contentType, "text/plain")
     self.assertEqual(annex2.file.filename,
                      json["__children__"][1]["file"]["filename"])
     self.assertEqual(annex2.file.size, 6475)
     self.assertEqual(annex2.file.contentType, "application/pdf")
    def test_ws_createItemWithOneAnnexRequest(self):
        """
          Test SOAP service behaviour when creating items with one annex
        """
        # by default no item exists
        self.changeUser('pmCreator1')
        req = self._prepareCreationData()
        data = {
            'title': 'My annex 1',
            'filename': 'smallTestFile.pdf',
            'file': 'smallTestFile.pdf'
        }
        req._creationData._annexes = [self._prepareAnnexInfo(**data)]
        annex = req._creationData._annexes[0]
        # Serialize the request so it can be easily tested
        request = serializeRequest(req)
        # This is what the sent enveloppe should looks like
        expected = """POST /plone/createItemRequest HTTP/1.0
Authorization: Basic %s:%s
Content-Length: 102
Content-Type: text/xml
SOAPAction: /
<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" """ \
"""xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" """ \
"""xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">""" \
"""<SOAP-ENV:Header></SOAP-ENV:Header><SOAP-ENV:Body xmlns:ns1="http://ws4pm.imio.be">""" \
"""<ns1:createItemRequest><meetingConfigId>plonegov-assembly</meetingConfigId>""" \
"""<proposingGroupId>developers</proposingGroupId><creationData xsi:type="ns1:CreationData">""" \
"""<title>My new item title</title><category>development</category>""" \
"""<description>&lt;p&gt;Description&lt;/p&gt;</description>""" \
"""<detailedDescription>&lt;p&gt;Detailed description&lt;/p&gt;</detailedDescription>""" \
"""<decision>&lt;p&gt;Décision&lt;/p&gt;</decision>""" \
"""<annexes xsi:type="ns1:AnnexInfo"><title>%s</title><annexTypeId>%s</annexTypeId><filename>%s</filename><file>
%s</file></annexes></creationData><cleanHtml>true</cleanHtml></ns1:createItemRequest>""" \
"""</SOAP-ENV:Body></SOAP-ENV:Envelope>""" % ('pmCreator1', 'meeting', annex._title, annex._annexTypeId,
                                              annex._filename, base64.encodestring(annex._file))
        result = """POST /plone/createItemRequest HTTP/1.0
Authorization: Basic %s:%s
Content-Length: 102
Content-Type: text/xml
SOAPAction: /
%s""" % ('pmCreator1', 'meeting', request)
        self.assertEqual(expected, result)
        newItem, response = self._createItem(req)
        # now check the created item have the annex
        annexes = get_annexes(newItem)
        # the annex is actually created
        self.failUnless(len(annexes) == 1)
        # the annex mimetype is correct
        annex = annexes[0]
        self.failUnless(annex.file.contentType == 'application/pdf')
        # the annex metadata are ok
        self.assertEqual(annex.Title(), 'My annex 1')
        self.assertEqual(
            annex.content_category,
            'plonegov-assembly-annexes_types_-_item_annexes_-_financial-analysis'
        )
Esempio n. 7
0
    def print_all_annexes(self,
                          portal_types=['annex'],
                          filters={},
                          with_icon=False,
                          with_filename=False):
        """
        Printing Method use in templates :
        return all viewable annexes for item
        @param: filters is a dict of {"attribute" : value}.
        It excludes all non matching annex from the result.
        Example : {'confidential': True, 'publishable': False}
        possible keys are : 'confidential', 'to_print', 'to_sign' and 'publishable' (all are bool or None)
        """
        res = []
        annexes = get_annexes(self.context, portal_types=portal_types)
        mimetypes_registry = self.portal.mimetypes_registry
        if filters:
            effective_annexes = []
            for annex in annexes:
                use_this_annex = True
                for attribute, value in filters.items():
                    if getattr(annex, attribute) != value:
                        use_this_annex = False
                        break
                if use_this_annex:
                    effective_annexes.append(annex)
            annexes = effective_annexes

        for annex in annexes:
            url = annex.absolute_url()
            title = safe_unicode(cgi.escape(annex.Title()))
            file_type_icon = u''
            if with_icon:
                mime_type = mimetypes_registry.lookup(
                    annex.file.contentType)[0]
                file_type_icon = u'&nbsp;<img src="{0}/{1}"/>'.format(
                    self.portal.absolute_url(), mime_type.icon_path)
            annex_type_icon = u'<img src="{0}/{1}"/>'.format(
                self.portal.absolute_url(),
                self.real_context.categorized_elements[
                    annex.UID()]['icon_url'])
            # sometimes filename may be None
            if annex.file.filename:
                extension = annex.file.filename.split(u'.')[-1]
                # escape just in case there is no file extension
                file_info = u'&nbsp;({0})'.format(
                    safe_unicode(cgi.escape(extension)))
            else:
                file_info = u'&nbsp;(???)'

            res.append(u'<p>{0}&nbsp;<a href="{1}">{2}</a>{3}{4}</p>'.format(
                annex_type_icon, url, title, file_type_icon, file_info))
            if with_filename:
                file_name = safe_unicode(cgi.escape(annex.file.filename))
                res.append(u'<p><i>{0}</i></p>'.format(file_name))
        return u'\n'.join(res)
Esempio n. 8
0
 def printAllAnnexes(self, portal_types=['annex']):
     ''' Printing Method use in templates :
         return all viewable annexes for item '''
     res = []
     annexes = get_annexes(self.context, portal_types=portal_types)
     for annex in annexes:
         url = annex.absolute_url()
         title = annex.Title().replace('&', '&amp;')
         res.append(u'<p><a href="{0}">{1}</a></p>'.format(
             url, safe_unicode(title)))
     return (u'\n'.join(res))
Esempio n. 9
0
    def test_pm_SendItemToOtherMCWithoutDefinedAnnexType(self):
        """When cloning an item to another meetingConfig or to the same meetingConfig,
           if we have annexes on the original item and destination meetingConfig (that could be same
           as original item or another) does not have annex types defined,
           it does not fail but annexes are not kept and a portal message is displayed."""
        cfg = self.meetingConfig
        cfg2 = self.meetingConfig2
        # first test when sending to another meetingConfig
        # remove every annexTypes from meetingConfig2
        self.changeUser('admin')
        self._removeConfigObjectsFor(cfg2,
                                     folders=[
                                         'annexes_types/item_annexes',
                                     ])
        self.assertTrue(not cfg2.annexes_types.item_annexes.objectValues())
        # a portal message will be added, for now there is no message
        messages = IStatusMessage(self.request).show()
        self.assertTrue(not messages)
        # now create an item, add an annex and clone it to the other meetingConfig
        data = self._setupSendItemToOtherMC(with_annexes=True)
        originalItem = data['originalItem']
        newItem = data['newItem']
        # original item had annexes
        self.assertEqual(
            len(get_annexes(originalItem, portal_types=['annex'])), 2)
        self.assertEqual(
            len(get_annexes(originalItem, portal_types=['annexDecision'])), 2)
        # but new item is missing the normal annexes because
        # no annexType for normal annexes are defined in the cfg2
        self.assertEqual(len(get_annexes(newItem, portal_types=['annex'])), 0)
        # XXX Seraing, decision's annexe are keep (but in their config, these annexes was send in simply annexes
        self.assertEqual(
            len(get_annexes(newItem, portal_types=['annexDecision'])), 2)
        # moreover a message was added
        messages = IStatusMessage(self.request).show()
        expectedMessage = translate(
            "annex_not_kept_because_no_available_annex_type_warning",
            mapping={'annexTitle': data['annex2'].Title()},
            domain='PloneMeeting',
            context=self.request)
        self.assertEqual(messages[-2].message, expectedMessage)

        # now test when cloning locally, even if annexes types are not enabled
        # it works, this is the expected behavior, backward compatibility when an annex type
        # is no more enabled but no more able to create new annexes with this annex type
        self.changeUser('admin')
        for at in (cfg.annexes_types.item_annexes.objectValues() +
                   cfg.annexes_types.item_decision_annexes.objectValues()):
            at.enabled = False
        # no available annex types, try to clone newItem now
        self.changeUser('pmManager')
        # clean status message so we check that a new one is added
        del IAnnotations(self.request)['statusmessages']
        clonedItem = originalItem.clone(copyAnnexes=True)
        # annexes were kept
        self.assertEqual(len(get_annexes(clonedItem, portal_types=['annex'])),
                         2)
        # for Seraing, item had not annexes decisions
        self.assertEqual(
            len(get_annexes(clonedItem, portal_types=['annexDecision'])), 0)
Esempio n. 10
0
def SearchableText(obj):
    """
      Contained annex title and scan_id are indexed in the SearchableText.
    """
    res = []
    res.append(obj.SearchableText())
    for annex in get_annexes(obj):
        res.append(annex.Title())
        scan_id = getattr(annex, "scan_id", None)
        if scan_id:
            # we need utf-8, when edited thru the UI, scan_id is stored as unicode
            res.append(safe_encode(scan_id))
    res = ' '.join(res)
    return res or _marker
Esempio n. 11
0
def annexes_index(obj):
    """
      Unique index with data relative to stored annexes :
      - to_print :
        - 'not_to_print' if contains annexes not to print;
        - 'to_print' otherwise;
      - confidential :
        - 'not_confidential' if contains not confidential annexes;
        - 'confidential' otherwise;
      - publishable :
        - 'not_publishable' if contains not publishable annexes;
        - 'publishable' otherwise;
      - to_sign/signed :
        - 'not_to_sign' if contains not to sign annexes;
        - 'to_sign' if contains to_sign but not signed annexes;
        - 'signed' if contains signed annexes.
    """
    res = []
    # use objectValues because with events order, an annex
    # could be added but still not registered in the categorized_elements dict
    for annex in get_annexes(obj):
        # to_print
        if annex.to_print:
            res.append('to_print')
        else:
            res.append('not_to_print')
        # confidential
        if annex.confidential:
            res.append('confidential')
        else:
            res.append('not_confidential')
        # publishable
        if annex.publishable:
            res.append('publishable')
        else:
            res.append('not_publishable')
        # to_sign/signed
        if annex.to_sign:
            if annex.signed:
                res.append('signed')
            else:
                res.append('to_sign')
        else:
            res.append('not_to_sign')
    # remove duplicates
    return list(set(res))
Esempio n. 12
0
 def test_restapi_annexes_endpoint_filters(self):
     """@annexes, it is possible to filter on existing boolean values
        to_print, publishable, ..."""
     cfg = self.meetingConfig
     config = cfg.annexes_types.item_annexes
     config.publishable_activated = True
     # create item with annexes
     self.changeUser("pmManager")
     item = self.create("MeetingItem")
     annex = self.addAnnex(item, publishable=True)
     self.addAnnex(item, publishable=False)
     transaction.commit()
     item_url = item.absolute_url()
     endpoint_url = "{0}/@annexes?publishable=true".format(item_url)
     response = self.api_session.get(endpoint_url)
     self.assertEqual(len(response.json()), 1)
     self.assertEqual(len(get_annexes(item)), 2)
     annex_infos = response.json()[0]
     self.assertEqual(annex_infos['UID'], annex.UID())
Esempio n. 13
0
 def test_restapi_add_item_with_annexes(self):
     """When creating an item, we may add annexes as __children__."""
     cfg = self.meetingConfig
     self.changeUser("pmManager")
     endpoint_url = "{0}/@item".format(self.portal_url)
     json = {
         "config_id":
         cfg.getId(),
         "proposingGroup":
         self.developers.getId(),
         "title":
         "My item",
         "__children__": [
             {
                 "@type": "annex",
                 "title": "My annex",
                 "content_category": "item-annex",
                 "file": {
                     "data": "123456",
                     "encoding": "ascii",
                     "filename": "file.txt",
                 },
             },
         ],
     }
     response = self.api_session.post(endpoint_url, json=json)
     transaction.begin()
     self.assertEqual(response.status_code, 201, response.content)
     pmFolder = self.getMeetingFolder()
     item = pmFolder.objectValues()[-1]
     self.assertEqual(item.Title(), json["title"])
     annex = get_annexes(item)[0]
     self.assertEqual(annex.title, json["__children__"][0]["title"])
     self.assertEqual(
         annex.content_category,
         calculate_category_id(
             cfg.annexes_types.item_annexes.get("item-annex")),
     )
     self.assertEqual(annex.file.filename,
                      json["__children__"][0]["file"]["filename"])
     self.assertEqual(annex.file.size, 6)
     self.assertEqual(annex.file.contentType, "text/plain")
Esempio n. 14
0
 def doClose(self, stateChange):
     ''' '''
     # Set the firstItemNumber
     self.context.update_first_item_number()
     # remove annex previews of every items if relevant
     if self.cfg.getRemoveAnnexesPreviewsOnMeetingClosure():
         # add logging message to fingerpointing log
         for item in self.context.get_items(ordered=True):
             annexes = get_annexes(item)
             if annexes:
                 for annex in annexes:
                     self.tool._removeAnnexPreviewFor(item, annex)
             extras = 'item={0} number_of_annexes={1}'.format(
                 repr(item), len(annexes))
             fplog('remove_annex_previews', extras=extras)
         msg = translate(
             u"Preview of annexes were deleted upon meeting closure.",
             domain='PloneMeeting',
             context=self.context.REQUEST)
         api.portal.show_message(msg, request=self.context.REQUEST)
Esempio n. 15
0
def onItemDuplicated(original, event):
    """After item's cloning, we removed decision annexe.
    """
    newItem = event.newItem
    annexes = get_annexes(newItem)
    for annex in annexes:
        if getattr(annex, 'scan_id', None):
            unrestrictedRemoveGivenObject(annex)
            msg = translate(
                'annex_not_kept_because_using_scan_id',
                mapping={'annexTitle': safe_unicode(annex.Title())},
                domain='PloneMeeting',
                context=newItem.REQUEST)
            api.portal.show_message(msg,
                                    request=newItem.REQUEST,
                                    type='warning')
    # xxx Seraing clear some fields linked to meeting
    newRawDescri = _removeTypistNote(newItem.getRawDescription())
    newItem.setDescription(newRawDescri)
    # Make sure we have 'text/html' for every Rich fields
    forceHTMLContentTypeForEmptyRichFields(newItem)
Esempio n. 16
0
    def test_pm_UpdateLocalRolesOn50ItemsWith0AnnexesAnd10Advices(self):
        '''Call.update_local_roles on items with 0 annexes and 10 advices.'''
        items = self._setupItemsForUpdateLocalRoles(add_advices=True,
                                                    add_annexes=False)
        number_of_advices = 10
        for item in items:
            self.assertEqual(len(item.adviceIndex), number_of_advices)

        # call update local roles 2 times
        uids = listify_uids([item.UID() for item in items])
        number_of_annexes = 0
        for item in items:
            self.assertEqual(len(get_annexes(item)), number_of_annexes)
        pm_logger.info(
            'Call 1 to.update_local_roles on 50 items holding '
            '{0} annexes and {1} auto asked advices.'.format(number_of_annexes, number_of_advices))
        self._updateItemLocalRoles(uids)
        pm_logger.info(
            'Call 2 to.update_local_roles on 50 items holding '
            '{0} annexes and {1} auto asked advices.'.format(number_of_annexes, number_of_advices))
        self._updateItemLocalRoles(uids)
Esempio n. 17
0
 def test_pm_DuplicatedItemDoesNotKeepDecisionAnnexes(self):
     """When an item is duplicated using the 'duplicate and keep link',
        decision annexes are not kept."""
     self.changeUser('pmCreator1')
     item = self.create('MeetingItem')
     self.addAnnex(item)
     # xxx Namur, creator can't create "Annexe decision"
     self.changeUser('admin')
     self.addAnnex(item, relatedTo='item_decision')
     self.changeUser('pmCreator1')
     self.assertTrue(get_annexes(item, portal_types=['annex']))
     self.assertTrue(get_annexes(item, portal_types=['annexDecision']))
     # cloned and link not kept, decison annexes are removed
     clonedItem = item.clone()
     self.assertTrue(get_annexes(clonedItem, portal_types=['annex']))
     self.assertFalse(
         get_annexes(clonedItem, portal_types=['annexDecision']))
     # cloned but link kept, decison annexes are also removed
     clonedItemWithLink = item.clone(setCurrentAsPredecessor=True)
     self.assertTrue(get_annexes(clonedItemWithLink,
                                 portal_types=['annex']))
     self.assertFalse(
         get_annexes(clonedItemWithLink, portal_types=['annexDecision']))
Esempio n. 18
0
    def test_restapi_add_annex_to_existing_element(self):
        """Use the @annex POST endpoint to create an annex."""
        cfg = self.meetingConfig
        self._removeConfigObjectsFor(cfg)
        self.changeUser("pmManager")
        item = self.create('MeetingItem')
        item_uid = item.UID()
        date = None
        if not HAS_MEETING_DX:
            date = DateTime()
        meeting = self.create('Meeting', date=date)
        meeting_uid = meeting.UID()
        transaction.commit()

        # add annex to item
        json = {
            "title": "My annex",
            "content_category": "wrong-annex",
            "file": {
                "data": "123456",
                "encoding": "ascii",
                "filename": "file.txt"
            }
        }
        endpoint_url = "{0}/@annex/{1}".format(self.portal_url, item_uid)
        # wrong content_category
        response = self.api_session.post(endpoint_url, json=json)
        self.assertEqual(response.status_code, 400, response.content)
        self.assertEqual(
            response.json(), {
                u"message": ANNEX_CONTENT_CATEGORY_ERROR % "wrong-annex",
                u"type": u"BadRequest"
            })
        # add annex to item correctly
        json["content_category"] = "item-annex"
        response = self.api_session.post(endpoint_url, json=json)
        transaction.begin()
        self.assertEqual(response.status_code, 201, response.content)
        # adding an annex without "content_category" will use default one
        # the default annex type is "financial-analysis"
        json.pop("content_category")
        response = self.api_session.post(endpoint_url, json=json)
        self.assertEqual(response.status_code, 201, response.content)
        self.assertEqual(response.json()["content_category"]["title"],
                         u'Financial analysis')
        # add annexDecision to item correctly
        json["content_category"] = "decision-annex"
        json["decision_related"] = True
        response = self.api_session.post(endpoint_url, json=json)
        self.assertEqual(response.status_code, 201, response.content)
        # add annex to meeting
        # can not use parameter "decision_related" on a meeting
        json["content_category"] = "meeting-annex"
        endpoint_url = endpoint_url.replace(item_uid, meeting_uid)
        response = self.api_session.post(endpoint_url, json=json)
        self.assertEqual(response.status_code, 400, response.content)
        self.assertEqual(
            response.json(), {
                u"message": ANNEX_DECISION_RELATED_NOT_ITEM_ERROR,
                u"type": u"BadRequest"
            })
        # add annex to meeting correctly
        json["decision_related"] = False
        response = self.api_session.post(endpoint_url, json=json)
        self.assertEqual(response.status_code, 201, response.content)
        transaction.begin()

        # annexes were added to item and meeting
        item_annexes = get_annexes(item, ["annex"])
        self.assertEqual(len(item_annexes), 2)
        decision_annexes = get_annexes(item, ["annexDecision"])
        self.assertEqual(len(decision_annexes), 1)
        meeting_annexes = get_annexes(meeting)
        self.assertEqual(len(meeting_annexes), 1)
Esempio n. 19
0
 def _testWholeDecisionProcessCouncil(self):
     """
         This test covers the whole decision workflow. It begins with the
         creation of some items, and ends by closing a meeting.
     """
     # meeting-config-college is tested in test_pm_WholeDecisionProcessCollege
     # we do the test for the council config
     self.meetingConfig = getattr(self.tool, self.cfg2_id)
     # pmCreator1 creates an item with 1 annex and proposes it
     self.changeUser('pmCreator1')
     item1 = self.create('MeetingItem', title='The first item')
     self.addAnnex(item1)
     # The creator can add a decision annex on created item
     self.addAnnex(item1, relatedTo='item_decision')
     self.do(item1, 'propose')
     # can add decision annex but not normal annex
     self.assertRaises(Unauthorized, self.addAnnex, item1)
     self.addAnnex(item1, relatedTo='item_decision')
     self.failIf(self.transitions(item1))  # He may trigger no more action
     # pmManager creates a meeting
     self.changeUser('pmManager')
     meeting = self.create('Meeting')
     # The meetingManager can add a decision annex
     self.addAnnex(item1, relatedTo='item_decision')
     # pmCreator2 creates and proposes an item
     self.changeUser('pmCreator2')
     item2 = self.create('MeetingItem',
                         title='The second item',
                         preferredMeeting=meeting.UID())
     self.do(item2, 'propose')
     # pmReviewer1 validates item1 and adds an annex to it
     self.changeUser('pmReviewer1')
     # The reviewer can add a decision annex on proposed item
     self.addAnnex(item1, relatedTo='item_decision')
     self.do(item1, 'validate')
     # can not add decision annex or normal annex
     self.assertRaises(Unauthorized, self.addAnnex, item1)
     self.assertRaises(Unauthorized,
                       self.addAnnex,
                       item1,
                       relatedTo='item_decision')
     # pmManager inserts item1 into the meeting and freezes it
     self.changeUser('pmManager')
     managerAnnex = self.addAnnex(item1)
     self.portal.restrictedTraverse('@@delete_givenuid')(managerAnnex.UID())
     self.do(item1, 'present')
     self.changeUser('pmCreator1')
     # can not add decision annex or normal annex
     self.assertRaises(Unauthorized, self.addAnnex, item1)
     self.assertRaises(Unauthorized,
                       self.addAnnex,
                       item1,
                       relatedTo='item_decision')
     self.changeUser('pmManager')
     self.do(meeting, 'freeze')
     # pmReviewer2 validates item2
     self.changeUser('pmReviewer2')
     self.do(item2, 'validate')
     # pmManager inserts item2 into the meeting, as late item, and adds an
     # annex to it
     self.changeUser('pmManager')
     self.do(item2, 'present')
     self.addAnnex(item2)
     # So now I should have 1 normal item left and one late item in the meeting
     self.failIf(len(meeting.get_items()) != 2)
     self.failUnless(len(meeting.get_items(list_types=['late'])) == 1)
     self.changeUser('pmReviewer1')
     # can not add decision annex or normal annex
     self.assertRaises(Unauthorized, self.addAnnex, item1)
     self.assertRaises(Unauthorized,
                       self.addAnnex,
                       item1,
                       relatedTo='item_decision')
     # pmManager adds a decision to item1 and publishes the meeting
     self.changeUser('pmManager')
     item1.setDecision(self.decisionText)
     self.do(meeting, 'publish')
     self.changeUser('pmReviewer2')
     # can not add decision annex or normal annex
     self.assertRaises(Unauthorized, self.addAnnex, item2)
     self.assertRaises(Unauthorized,
                       self.addAnnex,
                       item2,
                       relatedTo='item_decision')
     self.changeUser('pmReviewer1')
     self.assertRaises(Unauthorized, self.addAnnex, item2)
     self.assertRaises(Unauthorized,
                       self.addAnnex,
                       item2,
                       relatedTo='item_decision')
     # pmManager adds a decision for item2, decides and closes the meeting
     self.changeUser('pmManager')
     item2.setDecision(self.decisionText)
     self.do(meeting, 'decide')
     # check that a delayed item is duplicated
     self.assertEqual(len(item1.getBRefs('ItemPredecessor')), 0)
     self.do(item1, 'delay')
     # the duplicated item has item1 as predecessor
     duplicatedItem = item1.get_successors()[0]
     self.assertEqual(duplicatedItem.get_predecessor().UID(), item1.UID())
     # when duplicated on delay, only normal annexes are kept, decision annexes are not
     self.assertEqual(
         len(get_annexes(duplicatedItem, portal_types=('annex', ))), 1)
     self.assertEqual(
         len(get_annexes(duplicatedItem, portal_types=('annexDecision', ))),
         0)
     self.addAnnex(item2, relatedTo='item_decision')
     self.failIf(len(self.transitions(meeting)) != 2)
     # When a meeting is closed, items without a decision are automatically 'accepted'
     self.do(meeting, 'close')
     self.assertEqual(item2.query_state(), 'accepted')
     # An already decided item keep his given decision
     self.assertEqual(item1.query_state(), 'delayed')
     # XXX added tests regarding ticket #5887
     # test back transitions
     self.changeUser('admin')
     self.do(meeting, 'backToDecided')
     self.changeUser('pmManager')
     self.do(meeting, 'backToPublished')
     # set an item back to published to test the 'freeze' meeting here under
     self.do(item1, 'backToItemPublished')
     self.do(meeting, 'backToFrozen')
     # this also test the 'doBackToCreated' action on the meeting
     self.do(meeting, 'backToCreated')
     self.do(meeting, 'freeze')
     self.do(meeting, 'publish')
     self.do(meeting, 'decide')
     self.do(meeting, 'close')
Esempio n. 20
0
    def test_ws_createItemWithSeveralAnnexesRequest(self):
        """
          Test SOAP service behaviour when creating items with several annexes of different types
        """
        # by default no item exists
        self.changeUser('pmCreator1')
        req = self._prepareCreationData()
        # add 4 extra annexes
        # no data give, some default values are used (smallTestFile.pdf)
        data1 = {'title': 'My annex 1',
                 'filename': 'smallTestFile.pdf',
                 'file': 'smallTestFile.pdf'}
        # other annexTypeId than the default one
        data2 = {'title': 'My annex 2',
                 'filename': 'arbitraryFilename.odt',
                 'file': 'mediumTestFile.odt',
                 'annexTypeId': 'budget-analysis'}
        # a wrong annexTypeId and a test with a large msword document
        data3 = {'title': 'My annex 3',
                 'filename': 'largeTestFile.doc',
                 'file': 'largeTestFile.doc',
                 'annexTypeId': 'wrong-annexTypeId'}
        # empty file data provided, at the end, the annex is not created but the item is correctly created
        data4 = {'title': 'My annex 4',
                 'filename': 'emptyTestFile.txt',
                 'file': 'emptyTestFile.txt',
                 'annexTypeId': 'budget-analysis'}
        # a file that will have several extensions found in mimetypes_registry
        # is not handled if no valid filename is provided
        data5 = {'title': 'My annex 5',
                 'filename': 'notValidFileNameNoExtension',
                 'file': 'octetStreamTestFile.bin',
                 'annexTypeId': 'budget-analysis'}
        # but if the filename is valid, then the annex is handled
        data6 = {'title': 'My annex 6',
                 'filename': 'validExtension.bin',
                 'file': 'octetStreamTestFile.bin',
                 'annexTypeId': 'budget-analysis'}
        req._creationData._annexes = [self._prepareAnnexInfo(**data1), self._prepareAnnexInfo(**data2),
                                      self._prepareAnnexInfo(**data3), self._prepareAnnexInfo(**data4),
                                      self._prepareAnnexInfo(**data5), self._prepareAnnexInfo(**data6)]
        # serialize the request so it can be easily tested
        request = serializeRequest(req)
        # build annexes part of the envelope
        annexesEnveloppePart = ""
        for annex in req._creationData._annexes:
            annexesEnveloppePart = annexesEnveloppePart + """<annexes xsi:type="ns1:AnnexInfo"><title>%s</title>""" \
                """<annexTypeId>%s</annexTypeId><filename>%s</filename><file>
%s</file></annexes>""" % (annex._title, annex._annexTypeId, annex._filename, base64.encodestring(annex._file))
        # This is what the sent enveloppe should looks like
        expected = """POST /plone/createItemRequest HTTP/1.0
Authorization: Basic %s:%s
Content-Length: 102
Content-Type: text/xml
SOAPAction: /
<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" """ \
"""xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" """ \
"""xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">""" \
"""<SOAP-ENV:Header></SOAP-ENV:Header><SOAP-ENV:Body xmlns:ns1="http://ws4pm.imio.be"><ns1:createItemRequest>""" \
"""<meetingConfigId>plonegov-assembly</meetingConfigId><proposingGroupId>developers</proposingGroupId>""" \
"""<creationData xsi:type="ns1:CreationData"><title>My new item title</title><category>development</category>""" \
"""<description>&lt;p&gt;Description&lt;/p&gt;</description>""" \
"""<detailedDescription>&lt;p&gt;Detailed description&lt;/p&gt;</detailedDescription>""" \
"""<decision>&lt;p&gt;Décision&lt;/p&gt;</decision>""" \
"""%s</creationData><cleanHtml>true</cleanHtml></ns1:createItemRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>""" \
% ('pmCreator1', 'meeting', annexesEnveloppePart)
        result = """POST /plone/createItemRequest HTTP/1.0
Authorization: Basic %s:%s
Content-Length: 102
Content-Type: text/xml
SOAPAction: /
%s""" % ('pmCreator1', 'meeting', request)
        self.assertEqual(expected, result)
        newItem, response = self._createItem(req)
        annexes = get_annexes(newItem)
        # 4 annexes are actually created
        self.failUnless(len(annexes) == 4)
        # the annexes mimetype are corrects
        self.failUnless(annexes[0].file.contentType == 'application/pdf')
        self.failUnless(annexes[1].file.contentType == 'application/vnd.oasis.opendocument.text')
        self.failUnless(annexes[2].file.contentType == 'application/msword')
        self.failUnless(annexes[3].file.contentType == 'application/octet-stream')
        # the annexes metadata are ok
        self.failUnless(
            annexes[0].Title() == 'My annex 1' and
            annexes[0].content_category == 'plonegov-assembly-annexes_types_-_item_annexes_-_financial-analysis')
        self.failUnless(
            annexes[1].Title() == 'My annex 2' and
            annexes[1].content_category == 'plonegov-assembly-annexes_types_-_item_annexes_-_budget-analysis')
        # meetingFileType is back to default one when a wrong file type is given in the annexInfo
        self.failUnless(
            annexes[2].Title() == 'My annex 3' and
            annexes[2].content_category == 'plonegov-assembly-annexes_types_-_item_annexes_-_financial-analysis')
        self.failUnless(
            annexes[3].Title() == 'My annex 6' and
            annexes[3].content_category == 'plonegov-assembly-annexes_types_-_item_annexes_-_budget-analysis')
        # annexes filename are the ones defined in the 'filename', either it is generated
        self.failUnless(annexes[0].file.filename == u'smallTestFile.pdf')
        self.failUnless(annexes[1].file.filename == u'arbitraryFilename.odt')
        self.failUnless(annexes[2].file.filename == u'largeTestFile.doc')
        self.failUnless(annexes[3].file.filename == u'validExtension.bin')
        # now try to create an item with an annex that has no file
        # when file attribute is not provided, the annex is not created
        data = {'title': 'My annex 7',
                'filename': 'validExtension.bin',
                'annexTypeId': 'budget-analysis'}
        req._creationData._annexes = [self._prepareAnnexInfo(**data), ]
        self.assertEqual(req._creationData._annexes[0]._file, None)
        newItem, response = self._createItem(req)
        annexes = get_annexes(newItem)
        # no annexes have been added
        self.assertEqual(len(annexes), 0)
Esempio n. 21
0
    def test_pm_AnnexToPrintBehaviourWhenCloned(self):
        """When cloning an item with annexes, to the same or another MeetingConfig, the 'toPrint' field
           is kept depending on MeetingConfig.keepOriginalToPrintOfClonedItems.
           If it is True, the original value is kept, if it is False, it will use the
           MeetingConfig.annexToPrintDefault value."""
        cfg = self.meetingConfig
        cfg2 = self.meetingConfig2
        cfg2Id = cfg2.getId()
        cfg.setKeepOriginalToPrintOfClonedItems(False)
        cfg2.setKeepOriginalToPrintOfClonedItems(False)
        self.changeUser('pmManager')
        meeting = self.create('Meeting', date=DateTime('2016/02/02'))
        item = self.create('MeetingItem')
        annex = self.addAnnex(item)
        annex_config = get_config_root(annex)
        annex_group = get_group(annex_config, annex)
        self.assertFalse(annex_group.to_be_printed_activated)
        self.assertFalse(annex.to_print)
        annex.to_print = True
        self.assertTrue(annex.to_print)
        # decide the item so we may add decision annex
        item.setDecision(self.decisionText)
        self.presentItem(item)
        self.decideMeeting(meeting)
        self.do(item, 'accept')
        self.assertEquals(item.queryState(), 'accepted')
        annexDec = self.addAnnex(item, relatedTo='item_decision')
        annexDec_config = get_config_root(annexDec)
        annexDec_group = get_group(annexDec_config, annexDec)
        self.assertFalse(annexDec_group.to_be_printed_activated)
        self.assertFalse(annexDec.to_print)
        annexDec.to_print = True
        self.assertTrue(annexDec.to_print)

        # clone item locally, as keepOriginalToPrintOfClonedItems is False
        # default values defined in the config will be used
        self.assertFalse(cfg.getKeepOriginalToPrintOfClonedItems())
        clonedItem = item.clone()
        annexes = get_annexes(clonedItem, portal_types=['annex'])
        if not annexes:
            pm_logger.info('No annexes found on duplicated item clonedItem')
        cloneItemAnnex = annexes and annexes[0]
        annexesDec = get_annexes(clonedItem, portal_types=['annexDecision'])
        if not annexesDec:
            pm_logger.info(
                'No decision annexes found on duplicated item clonedItem')
        cloneItemAnnexDec = annexesDec and annexesDec[0]
        self.assertFalse(cloneItemAnnex and cloneItemAnnex.to_print)
        self.assertFalse(cloneItemAnnexDec and cloneItemAnnexDec.to_print)

        # enable keepOriginalToPrintOfClonedItems
        # some plugins remove annexes/decision annexes on duplication
        # so make sure we test if an annex is there...
        self.changeUser('siteadmin')
        cfg.setKeepOriginalToPrintOfClonedItems(True)
        self.changeUser('pmManager')
        clonedItem2 = item.clone()
        annexes = get_annexes(clonedItem2, portal_types=['annex'])
        if not annexes:
            pm_logger.info('No annexes found on duplicated item clonedItem2')
        cloneItem2Annex = annexes and annexes[0]
        annexesDec = get_annexes(clonedItem2, portal_types=['annexDecision'])
        if not annexesDec:
            pm_logger.info(
                'No decision annexes found on duplicated item clonedItem2')
        cloneItem2AnnexDec = annexesDec and annexesDec[0]
        self.assertTrue(cloneItem2Annex and cloneItem2Annex.to_print or True)
        self.assertTrue(cloneItem2AnnexDec and cloneItem2AnnexDec.to_print
                        or True)

        # clone item to another MC and test again
        # cfg2.keepOriginalToPrintOfClonedItems is True
        self.assertFalse(cfg2.getKeepOriginalToPrintOfClonedItems())
        item.setOtherMeetingConfigsClonableTo((cfg2Id, ))
        clonedToCfg2 = item.cloneToOtherMeetingConfig(cfg2Id)
        annexes = get_annexes(clonedToCfg2, portal_types=['annex'])
        if not annexes:
            pm_logger.info('No annexes found on duplicated item clonedToCfg2')
        clonedToCfg2Annex = annexes and annexes[0]
        annexesDec = get_annexes(clonedToCfg2, portal_types=['annexDecision'])
        if not annexesDec:
            pm_logger.info(
                'No decision annexes found on duplicated item clonedToCfg2')
        self.assertFalse(clonedToCfg2Annex and clonedToCfg2Annex.to_print)

        # enable keepOriginalToPrintOfClonedItems
        self.changeUser('siteadmin')
        cfg2.setKeepOriginalToPrintOfClonedItems(True)
        self.deleteAsManager(clonedToCfg2.UID())
        # send to cfg2 again
        self.changeUser('pmManager')
        clonedToCfg2Again = item.cloneToOtherMeetingConfig(cfg2Id)
        annexes = get_annexes(clonedToCfg2Again, portal_types=['annex'])
        if not annexes:
            pm_logger.info(
                'No annexes found on duplicated item clonedToCfg2Again')
        clonedToCfg2AgainAnnex = annexes and annexes[0]
        annexesDec = get_annexes(clonedToCfg2Again,
                                 portal_types=['annexDecision'])
        if not annexesDec:
            pm_logger.info(
                'No decision annexes found on duplicated item clonedToCfg2Again'
            )
        self.assertTrue(
            clonedToCfg2AgainAnnex and clonedToCfg2AgainAnnex.to_print or True)
    def test_ws_getItemInfosWithAnnexesRequest(self):
        """
          Test that getting an item with a given UID returns valuable informations and linked annexes
        """
        cfg = self.meetingConfig
        self.changeUser('pmCreator1')
        self.failUnless(
            len(self.portal.portal_catalog(portal_type='MeetingItemPga')) == 0)
        # prepare data for a default item
        req = self._prepareCreationData()
        # add one annex
        data = {
            'title': 'My annex 1',
            'filename': 'smallTestFile.pdf',
            'file': 'smallTestFile.pdf'
        }
        req._creationData._annexes = [self._prepareAnnexInfo(**data)]
        # create the item
        newItem, reponse = self._createItem(req)
        newItemUID = newItem.UID()
        # get informations about the item, by default 'showAnnexes' is False
        resp = self._getItemInfos(newItemUID)
        expected = """<ns1:getItemInfosResponse xmlns:ns1="http://ws4pm.imio.be" """ \
            """xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" """ \
            """xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" """ \
            """xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" """ \
            """xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <itemInfo xsi:type="ns1:ItemInfo">
    <UID>{0}</UID>
    <id>{1}</id>
    <title>My new item title</title>
    <creator>pmCreator1</creator>
    <creation_date>{2}</creation_date>
    <modification_date>{3}</modification_date>
    <category>development</category>
    <description>&lt;p&gt;Description&lt;/p&gt;</description>
    <detailedDescription>&lt;p&gt;Detailed description&lt;/p&gt;</detailedDescription>
    <decision>&lt;p&gt;Décision&lt;/p&gt;</decision>
    <preferredMeeting/>
    <preferred_meeting_date>1950-01-01T00:00:00.006Z</preferred_meeting_date>
    <review_state>itemcreated</review_state>
    <meeting_date>1950-01-01T00:00:00.006Z</meeting_date>
    <absolute_url>http://nohost/plone/Members/pmCreator1/mymeetings/plonegov-assembly/{4}</absolute_url>
    <externalIdentifier/>
    <extraInfos/>
  </itemInfo>
</ns1:getItemInfosResponse>
""".format(newItemUID,
                newItem.getId(),
                gDateTime.get_formatted_content(gDateTime(), localtime(newItem.created())),
                gDateTime.get_formatted_content(gDateTime(), localtime(newItem.modified())),
                newItem.getId())
        # annexes are not shown by default
        self.assertEqual(expected, resp)
        # now with 'showAnnexes=True'
        financial_annex_type_id = calculate_category_id(
            cfg.annexes_types.item_annexes.get('financial-analysis'))
        item_annex_type_id = calculate_category_id(
            cfg.annexes_types.item_annexes.get('item-annex'))
        resp = self._getItemInfos(newItemUID, showAnnexes=True)
        expected = """<ns1:getItemInfosResponse xmlns:ns1="http://ws4pm.imio.be" """ \
            """xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" """ \
            """xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" """ \
            """xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" """ \
            """xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <itemInfo xsi:type="ns1:ItemInfo">
    <UID>{0}</UID>
    <id>{1}</id>
    <title>My new item title</title>
    <creator>pmCreator1</creator>
    <creation_date>{2}</creation_date>
    <modification_date>{3}</modification_date>
    <category>development</category>
    <description>&lt;p&gt;Description&lt;/p&gt;</description>
    <detailedDescription>&lt;p&gt;Detailed description&lt;/p&gt;</detailedDescription>
    <decision>&lt;p&gt;Décision&lt;/p&gt;</decision>
    <preferredMeeting/>
    <preferred_meeting_date>1950-01-01T00:00:00.006Z</preferred_meeting_date>
    <review_state>itemcreated</review_state>
    <meeting_date>1950-01-01T00:00:00.006Z</meeting_date>
    <absolute_url>http://nohost/plone/Members/pmCreator1/mymeetings/plonegov-assembly/{4}</absolute_url>
    <externalIdentifier/>
    <extraInfos/>
    <annexes xsi:type="ns1:AnnexInfo">
      <id>smalltestfile.pdf</id>
      <title>My annex 1</title>
      <annexTypeId>{5}</annexTypeId>
      <filename>smallTestFile.pdf</filename>
      <file>
{6}</file>
    </annexes>
  </itemInfo>
</ns1:getItemInfosResponse>
""".format(newItemUID,
                newItem.getId(),
                gDateTime.get_formatted_content(gDateTime(), localtime(newItem.created())),
                gDateTime.get_formatted_content(gDateTime(), localtime(newItem.modified())),
                newItem.getId(),
                financial_annex_type_id,
                base64.encodestring(get_annexes(newItem)[0].file.data))
        # one annex is shown
        self.assertEqual(expected, resp)
        # now check with several (2) annexes...
        afile = open(
            os.path.join(os.path.dirname(__file__), 'mediumTestFile.odt'))
        annex_file = afile.read()
        afile.close()
        api.content.create(
            title='My BeautifulTestFile title',
            type='annex',
            file=namedfile.NamedBlobFile(
                annex_file, filename=safe_unicode(u'myBeautifulTestFile.odt')),
            container=newItem,
            content_category=item_annex_type_id,
            to_print=False,
            confidential=False)

        resp = self._getItemInfos(newItemUID, showAnnexes=True)
        expected = """<ns1:getItemInfosResponse xmlns:ns1="http://ws4pm.imio.be" """ \
            """xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" """ \
            """xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" """ \
            """xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" """ \
            """xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <itemInfo xsi:type="ns1:ItemInfo">
    <UID>{0}</UID>
    <id>{1}</id>
    <title>My new item title</title>
    <creator>pmCreator1</creator>
    <creation_date>{2}</creation_date>
    <modification_date>{3}</modification_date>
    <category>development</category>
    <description>&lt;p&gt;Description&lt;/p&gt;</description>
    <detailedDescription>&lt;p&gt;Detailed description&lt;/p&gt;</detailedDescription>
    <decision>&lt;p&gt;Décision&lt;/p&gt;</decision>
    <preferredMeeting/>
    <preferred_meeting_date>1950-01-01T00:00:00.006Z</preferred_meeting_date>
    <review_state>itemcreated</review_state>
    <meeting_date>1950-01-01T00:00:00.006Z</meeting_date>
    <absolute_url>http://nohost/plone/Members/pmCreator1/mymeetings/plonegov-assembly/{4}</absolute_url>
    <externalIdentifier/>
    <extraInfos/>
    <annexes xsi:type="ns1:AnnexInfo">
      <id>{5}</id>
      <title>My annex 1</title>
      <annexTypeId>{6}</annexTypeId>
      <filename>smallTestFile.pdf</filename>
      <file>
{7}</file>
    </annexes>
    <annexes xsi:type="ns1:AnnexInfo">
      <id>{8}</id>
      <title>My BeautifulTestFile title</title>
      <annexTypeId>{9}</annexTypeId>
      <filename>myBeautifulTestFile.odt</filename>
      <file>
{10}</file>
    </annexes>
  </itemInfo>
</ns1:getItemInfosResponse>
""".format(newItemUID,
                newItem.getId(),
                gDateTime.get_formatted_content(gDateTime(), localtime(newItem.created())),
                gDateTime.get_formatted_content(gDateTime(), localtime(newItem.modified())),
                newItem.getId(),
                get_annexes(newItem)[0].id,
                financial_annex_type_id,
                base64.encodestring(get_annexes(newItem)[0].file.data),
                get_annexes(newItem)[1].id,
                item_annex_type_id,
                base64.encodestring(get_annexes(newItem)[1].file.data))
        # 2 annexes are shown
        self.assertEqual(expected, resp)