def afterSetUp(self):
     self.setRoles(['Manager'])
     self.article = self.addPloneArticle(self.portal, 'article')
     name = 'proxies'
     self.proxies = InnerContentContainer(name)
     self.proxies = self.proxies.__of__(self.portal)
     self.portal._setObject(name, self.proxies)
     for name, portal_type in test_proxies:
         self.proxies.invokeFactory(type_name=portal_type, id=name)
 def afterSetUp(self):
     self.setRoles(['Manager'])
     self.article = self.addPloneArticle(self.portal, 'article')
     name = 'proxies'
     self.proxies = InnerContentContainer(name)
     self.proxies = self.proxies.__of__(self.portal)
     self.portal._setObject(name, self.proxies)
     for name, portal_type in test_proxies:
         self.proxies.invokeFactory(type_name=portal_type, id=name)
    def set(self, instance, value, **kwargs):
        """
            Set inner fields of this field.

            self is an instance of BaseInnerContentField instance is the
            instance of the article we are working on.

            value can be:
                InnerContentContainer
                A list of InnerContentProxy objects:
                A list of dictionaries: Each item of the dictionary will be handled

            kwargs are optionnals arguments changing the way this field is
            updated :
                "update": If True, update inner content proxies present in the value's dict list.
                          If False, update inner content proxies present in the value's dict list,
                          but delete all inner content proxies that are missing from the list but
                          have been created before.
                "_initializing_": creates a new inner container

            This method calls the mutator of each inner field of this field, by
            sending to it only what has been returned by the associated widget.

            Example of the value when the image already existed and hasn't changed:

            ({'description': ('Existing image', {}),
              'id': ('imageinnercontentproxy.2007-01-30.0017453092', {}),
              'title': ('Existing image', {})},)

            Example of value when there is a new image:

            ({'description': ('New image', {}),
              'id': ('imageinnercontentproxy.2007-02-04.7516632708', {}),
              'attachedImage': (<BaseUnit at fss.JPG>, {}),
              'title': ('New image', {})})

            ({'description': ('Referenced image', {}),
              'referencedContent': ('817b168ec61fbfcb080de02629431631', {}),
              'id': ('imageinnercontentproxy.2007-02-04.1880613482', {}),
              'title': ('Referenced image', {})})

        """

        if kwargs.get('_initializing_', False):
            return

        if isinstance(value, InnerContentContainer):
            return self.set(instance, value.objectValues(), **kwargs)

        # value must be a list of dictionnary
        # Each dictionnary defines values of inner content fields
        # Values can be wrapped into a tuple if for example you want to
        # define some extra args on the field mutator
        if type(value) not in (ListType, TupleType,):
            raise ValueError, \
                  "Value must be a list or a tuple, get: %s" % type(value)

        # Value can be a list of dictionnary or a list of InnerContent proxy
        # objects. In this case, wrap object into a dictionnary
        for index in range(0, len(value)):
            item = value[index]

            if IBaseInnerContentProxy.providedBy(item):
                schema = item.Schema()
                data = {}

                # Loop on fields and extract data using accessor
                for field in schema.fields():
                    if 'w' not in field.mode:
                        continue

                    field_id = field.getName()
                    accessor = field.getAccessor(item)

                    if accessor is None:
                        continue

                    data[field_id] = accessor()

                value[index] = data

        # Get inner container
        container_name = self.getContainerName()
        if shasattr(instance, container_name):
            container = getattr(instance, container_name, None)
        else:
            container = None

        # Do nothing if value is empty and container doesn't already exist
        if not isinstance(container, InnerContentContainer) and not value:
            return

        # Create a new container if it doesn't already exist
        if not isinstance(container, InnerContentContainer):
            container = InnerContentContainer(container_name)
            instance._setObject(container_name, container)
            container = instance._getOb(container_name)
            container.initializeArchetype()
            #instance._p_changed = 1

        # 'update' argument is a switch for innercontent deletion:
        # - if True, ids that are not present in the request WON'T be destroyed
        # - if False or doesn't exist, all ids that are not in request WILL be deleted.
        update = kwargs.get('update', False)

        # Format all field values to be a tuple. If no extra args defined,
        # replace by an empty dictionnary
        for item in value:
            for item_key in item.keys():
                item_value = item[item_key]

                if type(item_value) not in (TupleType, ListType,):
                    item[item_key] = (item_value, {})

        # Build a list containing all inner content ids to be replaced or updated
        inner_content_ids = [x['id'][0] for x in value]

        # If update not in kwargs, delete objects in container
        if not update and container is not None:
            inner_content_ids_to_remove = [x for x in container.objectIds()
                                           if x not in inner_content_ids]
            container.manage_delObjects(ids=inner_content_ids_to_remove)

        # Check for new inner contents
        for item, item_index in izip(value, count()):
            inner_content_field_values = item.copy()
            inner_content_id = inner_content_field_values['id'][0]
            # no need to reindex until a new inner content is really added
            to_reindex = False
            # Create a new inner content if it doesn't exist
            if not shasattr(container, inner_content_id):
                container.invokeFactory(type_name=self.inner_portal_type,
                                        id=inner_content_id)
                to_reindex = True

            # reorder content only if update not in kwargs
            if not update:
                content_position = container.getObjectPosition(inner_content_id)
                if content_position != item_index:
                    container.moveObjectToPosition(inner_content_id, item_index)

            inner_content = getattr(container, inner_content_id)
            # removing id from field_values since id shouldn't be updated
            # (it's the key)
            del inner_content_field_values['id']

            # Update inner content fields (new and already existing)
            for field_name, field_args in inner_content_field_values.items():
                field = inner_content.getField(field_name)
                mutator = field.getMutator(inner_content)
                mutator(field_args[0], **field_args[1])
                to_reindex = True

            # Then reindex object
            if to_reindex:
                inner_content.reindexObject()
class InnerContentProxyTestCase(BaseTestCase):
    """
    Test all our inner content proxies
    """
    def afterSetUp(self):
        self.setRoles(['Manager'])
        self.article = self.addPloneArticle(self.portal, 'article')
        name = 'proxies'
        self.proxies = InnerContentContainer(name)
        self.proxies = self.proxies.__of__(self.portal)
        self.portal._setObject(name, self.proxies)
        for name, portal_type in test_proxies:
            self.proxies.invokeFactory(type_name=portal_type, id=name)

    def testGetPrimaryValue(self):
        self.loginAsPortalOwner()

        #for name, attached_name, attached_value, ref_type, ref_value, default in test_primary_fields:
        for data in test_primary_fields:

            proxy = self.proxies[data.proxy_name]
            primary_field = proxy.getField(data.primary_field_name)
            primary_accessor = primary_field.getAccessor(proxy)

            # Create referenced content
            kwargs = {}
            kwargs[data.primary_field_name] = data.ref_value
            ref_content = self.addContent(data.ref_type, self.portal,
                                          data.proxy_name)
            ref_content.edit(**kwargs)

            # No referenced content, no attached file
            value = primary_accessor()
            self.assertEquals(getattr(value, 'data', value), data.default)

            # Referenced content, no attached file
            kwargs = {}
            kwargs['referencedContent'] = (ref_content.UID(), )
            proxy.edit(**kwargs)
            value = primary_accessor()
            self.assertEquals(getattr(value, 'data', value), data.ref_expected)

            # referenced content, attached file
            kwargs = {}
            kwargs[data.attached_name] = data.attached_value
            proxy.edit(**kwargs)
            value = primary_accessor()
            self.assertEquals(getattr(value, 'data', value),
                              data.attached_expected)

            # No Referenced content, attached file
            kwargs = {}
            kwargs['referencedContent'] = ()
            value = primary_accessor()
            self.assertEquals(getattr(value, 'data', value),
                              data.attached_expected)

        self.logout()

    def testReferenceableInterfaces(self):

        for class_name in test_types_names:
            klass = getattr(pa_proxies, class_name)
            rf_present = hasattr(klass, 'referenceable_interfaces')
            if class_name == 'BaseInnerContentProxy':
                self.failIf(
                    rf_present,
                    "BaseInnerContentProxy must not define 'referenceable_interfaces'"
                )
            else:
                self.failIf(
                    not rf_present,
                    "%s must define 'referenceable_interfaces'" % class_name)
                attr = getattr(klass, 'referenceable_interfaces')
                is_tuple = type(attr) == TupleType
                self.failUnless(
                    is_tuple,
                    "%s.referenceable_interfaces is not a tuple" % class_name)

                if is_tuple:
                    for i in attr:
                        self.failUnless(
                            issubclass(i, Interface),
                            "%s.referenceable_interfaces: %s is not an interface"
                            % (class_name, i.__name__))

    def testgetReferenceablePortalTypes(self):
        article = self.article
        article.setFiles(file_proxy_values)
        fp = article.getFiles()[0]
        rpt = fp.getReferenceablePortalTypes(article.getField('files'))
        self.assertEquals(rpt, ['File'])

    def testRenameAfterCreation(self):
        fields_data = (
            (
                'LinkInnerContentProxy',
                {
                    'title': 'My nice title',
                },
                'my-nice-title',
            ),
            ('ImageInnerContentProxy', {
                'title': 'Test renamed after file name',
                'attachedImage_file': openTestFile('test.jpg'),
            }, 'test.jpg'),
            ('ImageInnerContentProxy', {
                'title': 'Test twice the same file name',
                'attachedImage_file': openTestFile('test.jpg'),
            }, 'test-1.jpg'),
            ('FileInnerContentProxy', {
                'title': 'Test file renamed after file name',
                'attachedFile_file': openTestFile('test.jpg'),
            }, 'test-2.jpg'),
        )

        self.loginAsPortalOwner()

        # from http://www.zope.org/Members/shh/ZopeTestCaseWiki/FrequentlyAskedQuestions
        # ensure we have _p_jar to avoid problems with CopySupport (cb_isMoveable)
        import transaction
        transaction.savepoint(optimistic=True)

        for ptype, data, expected_id in fields_data:
            initial_id = self.portal.generateUniqueId(ptype)
            proxy_id = self.proxies.invokeFactory(ptype, initial_id)
            proxy = self.proxies[proxy_id]
            proxy.processForm(values=data)

            self.assertEquals(proxy.getId(), expected_id)

    def test_searcheableText(self):
        """ test circular reference in linkinnerproxy """
        self.loginAsPortalOwner()

        ## article1 reference article2
        article1 = self.article
        article2 = self.addPloneArticle(self.portal, 'article2')
        _createObjectByType('InnerContentContainer', article1, 'links')
        _createObjectByType('LinkInnerContentProxy', article1.links, 'link')
        article1.links.link.update(title='Reference to article 2',
                                   description='description2',
                                   referencedContent=article2)
        ## article2 reference artilce1
        _createObjectByType('InnerContentContainer', article2, 'links')
        _createObjectByType('LinkInnerContentProxy', article2.links, 'link')
        article2.links.link.update(title='Reference to article 1',
                                   description='description1',
                                   referencedContent=article1)
        self.failUnless('Reference to article 2' in article1.SearchableText())
        self.failUnless('Reference to article 1' in article2.SearchableText())
class InnerContentProxyTestCase(BaseTestCase):
    """
    Test all our inner content proxies
    """

    def afterSetUp(self):
        self.setRoles(['Manager'])
        self.article = self.addPloneArticle(self.portal, 'article')
        name = 'proxies'
        self.proxies = InnerContentContainer(name)
        self.proxies = self.proxies.__of__(self.portal)
        self.portal._setObject(name, self.proxies)
        for name, portal_type in test_proxies:
            self.proxies.invokeFactory(type_name=portal_type, id=name)

    def testGetPrimaryValue(self):
        self.loginAsPortalOwner()

        #for name, attached_name, attached_value, ref_type, ref_value, default in test_primary_fields:
        for data in test_primary_fields:

            proxy = self.proxies[data.proxy_name]
            primary_field = proxy.getField(data.primary_field_name)
            primary_accessor = primary_field.getAccessor(proxy)

            # Create referenced content
            kwargs = {}
            kwargs[data.primary_field_name] = data.ref_value
            ref_content = self.addContent(data.ref_type, self.portal,
                                          data.proxy_name)
            ref_content.edit(**kwargs)

            # No referenced content, no attached file
            value = primary_accessor()
            self.assertEquals(getattr(value, 'data', value), data.default)

            # Referenced content, no attached file
            kwargs = {}
            kwargs['referencedContent'] = (ref_content.UID(),)
            proxy.edit(**kwargs)
            value = primary_accessor()
            self.assertEquals(getattr(value, 'data', value), data.ref_expected)

            # referenced content, attached file
            kwargs = {}
            kwargs[data.attached_name] = data.attached_value
            proxy.edit(**kwargs)
            value = primary_accessor()
            self.assertEquals(getattr(value, 'data', value),
                              data.attached_expected)

            # No Referenced content, attached file
            kwargs = {}
            kwargs['referencedContent'] = ()
            value = primary_accessor()
            self.assertEquals(getattr(value, 'data', value), data.attached_expected)

        self.logout()

    def testReferenceableInterfaces(self):

        for class_name in test_types_names:
            klass = getattr(pa_proxies, class_name)
            rf_present = hasattr(klass, 'referenceable_interfaces')
            if class_name == 'BaseInnerContentProxy':
                self.failIf(rf_present,
                            "BaseInnerContentProxy must not define 'referenceable_interfaces'")
            else:
                self.failIf(not rf_present, "%s must define 'referenceable_interfaces'" % class_name)
                attr = getattr(klass, 'referenceable_interfaces')
                is_tuple = type(attr) == TupleType
                self.failUnless(is_tuple, "%s.referenceable_interfaces is not a tuple" % class_name)

                if is_tuple:
                    for i in attr:
                        self.failUnless(issubclass(i, Interface),
                            "%s.referenceable_interfaces: %s is not an interface" % (class_name, i.__name__))

    def testgetReferenceablePortalTypes(self):
        article = self.article
        article.setFiles(file_proxy_values)
        fp = article.getFiles()[0]
        rpt = fp.getReferenceablePortalTypes(article.getField('files'))
        self.assertEquals(rpt, ['File'])

    def testRenameAfterCreation(self):
        fields_data = (
            ('LinkInnerContentProxy',
             {'title': 'My nice title',}, 'my-nice-title',
             ),
            ('ImageInnerContentProxy',
             {'title': 'Test renamed after file name',
              'attachedImage_file': openTestFile('test.jpg'),
              },
             'test.jpg'),
            ('ImageInnerContentProxy',
             {'title': 'Test twice the same file name',
              'attachedImage_file': openTestFile('test.jpg'),
              },
             'test-1.jpg'),
            ('FileInnerContentProxy',
             {'title': 'Test file renamed after file name',
              'attachedFile_file': openTestFile('test.jpg'),
              },
             'test-2.jpg'),
            )

        self.loginAsPortalOwner()

        # from http://www.zope.org/Members/shh/ZopeTestCaseWiki/FrequentlyAskedQuestions
        # ensure we have _p_jar to avoid problems with CopySupport (cb_isMoveable)
        import transaction
        transaction.savepoint(optimistic=True)

        for ptype, data, expected_id in fields_data:
            initial_id = self.portal.generateUniqueId(ptype)
            proxy_id = self.proxies.invokeFactory(ptype, initial_id)
            proxy = self.proxies[proxy_id]
            proxy.processForm(values=data)

            self.assertEquals(proxy.getId(), expected_id)

    def test_searcheableText(self):
        """ test circular reference in linkinnerproxy """
        self.loginAsPortalOwner()

        ## article1 reference article2
        article1 = self.article
        article2 = self.addPloneArticle(self.portal, 'article2')
        _createObjectByType('InnerContentContainer',article1,'links')
        _createObjectByType('LinkInnerContentProxy',article1.links, 'link')
        article1.links.link.update(title='Reference to article 2',
                                            description='description2',
                                            referencedContent=article2)
        ## article2 reference artilce1
        _createObjectByType('InnerContentContainer',article2,'links')
        _createObjectByType('LinkInnerContentProxy',article2.links, 'link')
        article2.links.link.update(title='Reference to article 1',
                                    description='description1',
                                    referencedContent=article1)
        self.failUnless('Reference to article 2' in article1.SearchableText() )
        self.failUnless('Reference to article 1' in article2.SearchableText() )