def test_render_store_layout_configuration_in_state(self, browser):
        config = IPageConfiguration(self.content)
        state = {
            "default": [
                {"cols": [{"blocks": []}]},
                {"cols": [{"blocks": []}]}
            ]
        }
        config.store(state)

        configdata = {'somekey': 'somevalue'}
        payload = json.dumps({'name': 'default',
                              'layoutindex': '1',
                              'config': configdata})
        self.portal.REQUEST.set('data', payload)
        response = json.loads(self.content.restrictedTraverse(
            '@@sl-ajax-reload-layout-view')())

        browser.open_html(response['content'])

        self.assertDictEqual(
            configdata,
            json.loads(
                browser.css('.sl-layout-content').first.attrib['data-config']))
        self.assertTrue(browser.css('.sl-layout-content.somevalue'),
                        'Expect one item')
Beispiel #2
0
def update_page_state_on_block_remove(block, event):

    if event.newParent is None:
        # Be sure it's not cut/paste
        block_uid = IUUID(block)
        parent = aq_parent(aq_inner(block))

        # Do nothing if the event wasn't fired by the block's parent.
        # This happens when an ancestor is deleted, e.g. the Plone site itself.
        if parent is not event.oldParent:
            return

        config = IPageConfiguration(parent)
        page_state = config.load()

        for container in page_state.values():
            for layout in container:
                for column in layout['cols']:
                    cache_amound_blocks = len(column['blocks'])
                    column['blocks'] = [item for item in column['blocks']
                                        if item['uid'] != block_uid]
                    if cache_amound_blocks != len(column['blocks']):
                        # Block has been removed
                        break
        config.store(page_state)
Beispiel #3
0
    def migrate_prepare_page_state(self):
        config = IPageConfiguration(self.new)

        page_config = {
            "default": [{
                "cols": [
                    {
                        "blocks": []
                    },
                    {
                        "blocks": []
                    },
                    {
                        "blocks": []
                    },
                    {
                        "blocks": []
                    },
                ]
            }, {
                "cols": [{
                    "blocks": []
                }, {
                    "blocks": []
                }]
            }]
        }
        config.store(page_config)
Beispiel #4
0
def update_page_state_on_copy_paste_block(block, event):
    """Update the uid of the new created block in the page state.
    block: new block
    event.original: origin of the copy event - usually the simplelayout page"""

    # Only update page state, if the original object is a Simplelayout page.
    if not ISimplelayout.providedBy(event.original):
        return

    # The event is triggered recursively - we need to check if the block is
    # actually part of the original page
    if event.original.get(block.id) is None:
        return

    origin_block_uid = IUUID(event.original.get(block.id))
    page_config = IPageConfiguration(block.aq_parent)
    page_state = unwrap_persistence(page_config.load())

    new_block_uid = IUUID(block)
    new_page_state = json.loads(
        json.dumps(page_state).replace(origin_block_uid,
                                       new_block_uid))

    # We should not update object positions here, because:
    # 1. "Ordered folder" makes sure that the order is the same as before
    #    when copy / pasting.
    # 2. Updating positions does not work here, because our objects are not
    #    acquisition wrappable yet (since not yet pasted) and the updating
    #    mechanism will trigger events (such as plone.app.referenceablebehavior),
    #    which require acquisition.
    page_config.store(new_page_state, update_positions=False)
 def _get_uids(self):
     page_conf = IPageConfiguration(self.context)
     # look for blocks in default slot first ...
     state_string = json.dumps(unwrap_persistence(
         page_conf.load().get('default', {})))
     # ... then look in all slots.
     state_string += json.dumps(unwrap_persistence(
         page_conf.load()))
     return re.findall(r'\"uid\"\: \"(.+?)\"', state_string)
def move_sl_block_into_slot(old_page, new_page, block, slot_name):
    page_configuration = IPageConfiguration(new_page)
    page_state = page_configuration.load()

    # initiate layout if it is in its initial state
    if slot_name == 'default' and page_state == page_configuration._default_page_config():

        # setup different layouts
        if ISimplelayoutTwoColumnView.providedBy(old_page):
            # two columns
            page_state[slot_name] = [
                {'cols': [ {'blocks': []}, {'blocks': []} ]}
            ]

        elif ISimplelayoutTwoColumnOneOnTopView.providedBy(old_page):
            # two columns and a top row
            page_state[slot_name] = [
                {'cols': [{'blocks': []}]},
                {'cols': [ {'blocks': []}, {'blocks': []} ]}
            ]

    if slot_name not in page_state:
        # normal single column layout
        page_state[slot_name] = [{'cols': [{'blocks': []}]}]

    if slot_name == 'default':
        slot = page_state['default']

        # two column layout
        if ISimplelayoutTwoColumnView.providedBy(old_page):
            if ISlotA.providedBy(block):  # left column
                slot[0]['cols'][0]['blocks'].append({'uid': IUUID(block)})
            elif ISlotB.providedBy(block):  # right column
                slot[0]['cols'][1]['blocks'].append({'uid': IUUID(block)})
            else:
                raise ValueError('Block has unused slot in layout.')

        # two columns and a top row layout
        elif ISimplelayoutTwoColumnOneOnTopView.providedBy(old_page):
            if ISlotA.providedBy(block):  # top row
                slot[0]['cols'][0]['blocks'].append({'uid': IUUID(block)})
            elif ISlotB.providedBy(block):  # bottom row, left column
                slot[1]['cols'][0]['blocks'].append({'uid': IUUID(block)})
            elif ISlotC.providedBy(block):  # bottom row, right column
                slot[1]['cols'][1]['blocks'].append({'uid': IUUID(block)})
            else:
                raise ValueError('Block has unused slot in layout.')

        else:
            slot[0]['cols'][0]['blocks'].append({'uid': IUUID(block)})

    else:
        page_state[slot_name][0]['cols'][0]['blocks'].append({
            'uid': IUUID(block)})

    page_configuration.store(page_state)
    def create_block(self, portlet, manager, type_):

        config = IPageConfiguration(self.new)
        normalizer = getUtility(IFileNameNormalizer).normalize
        if type_ == 'teaser':
            block = create(Builder('sl textblock')
                           .within(self.new)
                           .titled(portlet.teasertitle)
                           .having(text=RichTextValue(portlet.teaserdesc),
                                   image=NamedBlobImage(
                                       filename=normalizer(
                                           portlet.image.filename).decode('utf-8'),
                                       data=portlet.image.data)))

            blockconfig = IBlockConfiguration(block)
            blockconfigdata = blockconfig.load()
            blockconfigdata['scale'] = 'large'
            blockconfigdata['imagefloat'] = 'no-float'
            blockconfig.store(blockconfigdata)

            if portlet.internal_target:
                teaser = ITeaser(block)
                target = uuidToObject(portlet.internal_target)
                if target:
                    intids = getUtility(IIntIds)
                    teaser.internal_link = RelationValue(intids.getId(target))

        elif type_ == 'static':
            block = create(Builder('sl textblock')
                           .within(self.new)
                           .titled(portlet.header)
                           .having(text=RichTextValue(portlet.text)))
        else:
            return

        uid = IUUID(block)

        page_state = config.load()
        if manager == 'ftw.subsite.front1':
            page_state['default'][0]['cols'][0]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front2':
            page_state['default'][0]['cols'][1]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front3':
            page_state['default'][0]['cols'][2]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front4':
            page_state['default'][0]['cols'][3]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front5':
            page_state['default'][1]['cols'][0]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front6':
            page_state['default'][1]['cols'][1]['blocks'].append({'uid': uid})
        # Don't know where manager 7 belongs
        elif manager == 'ftw.subsite.front7':
            page_state['default'][1]['cols'][0]['blocks'].append({'uid': uid})

        config.store(page_state)
    def save_state(self):
        data = self.request.form.get('data')
        if data:
            json_conf = json.loads(data)
            page_conf = IPageConfiguration(self.context)
            page_conf.store(json_conf)
        else:
            raise BadRequest('No data given.')

        self.request.response.setHeader("Content-type", "application/json")
        return ''
Beispiel #9
0
    def test_syncs_pagestate_before_publishing(self):
        page = create(Builder('sl content page'))
        create(Builder('sl textblock').within(page))
        self.assertEquals([],
                          flattened_block_uids(
                              IPageConfiguration(page).load()))

        page.restrictedTraverse('@@publisher.publish')()
        self.assertEquals(['staticuid00000000000000000000002'],
                          flattened_block_uids(
                              IPageConfiguration(page).load()))
Beispiel #10
0
    def create_block(self, portlet, manager, type_):

        config = IPageConfiguration(self.new)
        normalizer = getUtility(IFileNameNormalizer).normalize
        if type_ == 'teaser':
            block = create(
                Builder('sl textblock').within(self.new).titled(
                    portlet.teasertitle).having(
                        text=RichTextValue(portlet.teaserdesc),
                        image=NamedBlobImage(filename=normalizer(
                            portlet.image.filename).decode('utf-8'),
                                             data=portlet.image.data)))

            blockconfig = IBlockConfiguration(block)
            blockconfigdata = blockconfig.load()
            blockconfigdata['scale'] = 'large'
            blockconfigdata['imagefloat'] = 'no-float'
            blockconfig.store(blockconfigdata)

            if portlet.internal_target:
                teaser = ITeaser(block)
                target = uuidToObject(portlet.internal_target)
                if target:
                    intids = getUtility(IIntIds)
                    teaser.internal_link = RelationValue(intids.getId(target))

        elif type_ == 'static':
            block = create(
                Builder('sl textblock').within(self.new).titled(
                    portlet.header).having(text=RichTextValue(portlet.text)))
        else:
            return

        uid = IUUID(block)

        page_state = config.load()
        if manager == 'ftw.subsite.front1':
            page_state['default'][0]['cols'][0]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front2':
            page_state['default'][0]['cols'][1]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front3':
            page_state['default'][0]['cols'][2]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front4':
            page_state['default'][0]['cols'][3]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front5':
            page_state['default'][1]['cols'][0]['blocks'].append({'uid': uid})
        elif manager == 'ftw.subsite.front6':
            page_state['default'][1]['cols'][1]['blocks'].append({'uid': uid})
        # Don't know where manager 7 belongs
        elif manager == 'ftw.subsite.front7':
            page_state['default'][1]['cols'][0]['blocks'].append({'uid': uid})

        config.store(page_state)
Beispiel #11
0
    def structure(self):
        """ Render a simplelayout slot by name.
        Name is given by the simplelayout expression.
        """
        page_conf = IPageConfiguration(self.context)
        storage = page_conf.load()
        sl_renderer = SimplelayoutRenderer(self.context,
                                           storage,
                                           self.name,
                                           view=self.view)

        return sl_renderer.render_slot()
Beispiel #12
0
    def _blocks_without_state(self):
        page_conf = IPageConfiguration(self.context)
        saved_blocks = []

        for container in page_conf.load().values():
            for row in container:
                for col in row['cols']:
                    for block in col['blocks']:
                        if 'uid' in block:
                            saved_blocks.append(block['uid'])

        return filter(lambda x: x[0] not in saved_blocks,
                      self._blocks().items())
 def setup_block(self, container='portletright'):
     page_config = IPageConfiguration(self.container)
     page_config.store({container: [
         {
             "cols": [
                 {
                     "blocks": [
                         {
                             "uid": IUUID(self.block)
                         }
                     ]
                 }
             ]
         }]})
     transaction.commit()
    def test_support_images_in_gallery_blocks(self, browser):
        page = create(Builder('sl content page'))
        gallery = create(Builder('sl galleryblock').within(page))
        image = create(Builder('image').with_dummy_content().within(gallery))
        page_config = IPageConfiguration(page)
        page_config.store(
            {"default": [{"cols": [{"blocks": [
                {"uid": IUUID(gallery)},
            ]}]}]})
        transaction.commit()

        browser.login().visit(page, view='@@leadimage')
        src_url = browser.css('img').first.attrib['src']
        self.assertRegexpMatches(src_url, r'^{}'.format(
            re.escape(image.absolute_url())))
    def setUp(self):
        super(TestSimplelayoutView, self).setUp()
        self.setup_sample_ftis(self.layer['portal'])
        self.setup_block_views()
        self.container = create(Builder('sample container'))
        self.page_config = IPageConfiguration(self.container)
        self.url = self.container.absolute_url() + '/@@simplelayout-view'

        self.payload = {
            "default": [
                {
                    "cols": [
                        {
                            "blocks": [
                                {
                                    "uid": "c774b0ca2a5544bf9bb46d865b11bff9"
                                }
                            ]
                        }
                    ]
                },
                {
                    "cols": [
                        {
                            "blocks": [
                                {
                                    "uid": "413fb945952d4403a58ab1958c38f1d2"
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    def migrate_prepare_page_state(self):
        config = IPageConfiguration(self.new)

        page_config = {
            "default": [
                {"cols": [
                    {"blocks": []},
                    {"blocks": []},
                    {"blocks": []},
                    {"blocks": []},
                ]},
                {"cols": [
                    {"blocks": []},
                    {"blocks": []}]
                 }]}
        config.store(page_config)
    def test_data_setter(self):
        page = create(Builder('sl content page').titled(u'The Page'))
        block = create(
            Builder('sl textblock').titled(u'The Block').within(page))
        component = getAdapter(
            page,
            IDataCollector,
            name='ftw.simplelayout:SimplelayoutPageAnnotations')
        component.setData(
            {"default": [
                {
                    "cols": [
                        {
                            "blocks": [{
                                "uid": IUUID(block)
                            }]
                        },
                    ]
                },
            ]}, {})

        self.assertEquals(
            {"default": [
                {
                    "cols": [
                        {
                            "blocks": [{
                                "uid": IUUID(block)
                            }]
                        },
                    ]
                },
            ]},
            IPageConfiguration(page).load())
Beispiel #18
0
    def has_blocks(self):
        config = IPageConfiguration(self.context)
        data = config.load()

        if self.manager.__name__ == 'plone.rightcolumn':
            portlet_container = data.get('portletright', [])
        elif self.manager.__name__ == 'plone.leftcolumn':
            portlet_container = data.get('portletleft', [])

        for layout in portlet_container:
            for columns in layout.values():
                for column in columns:
                    if len(column['blocks']):
                        return True
                    else:
                        continue
        return False
    def test_unauthorized_when_not_allowed_to_change_layouts(self):
        page = create(Builder("sample container"))
        config = IPageConfiguration(page)
        config.store(
            {
                "default": [
                    {"cols": [{"blocks": [{"uid": "foo"}, {"uid": "bar"}]}]},
                    {"cols": [{"blocks": []}, {"blocks": []}]},
                ]
            }
        )

        # The user should not change layouts
        page.manage_permission("ftw.simplelayout: Change Layouts", roles=[], acquire=0)

        # When he changes layouts, Unauthorized is raised
        with self.assertRaises(Unauthorized):
            config.store({"default": [{"cols": [{"blocks": [{"uid": "foo"}, {"uid": "bar"}]}]}]})

        # But he is allowed to move blocks
        config.store(
            {
                "default": [
                    {"cols": [{"blocks": [{"uid": "foo"}]}]},
                    {"cols": [{"blocks": [{"uid": "bar"}]}, {"blocks": []}]},
                ]
            }
        )
    def test_unauthorized_when_not_allowed_to_change_layouts(self):
        page = create(Builder('sample container'))
        config = IPageConfiguration(page)
        config.store(
            {'default': [{'cols': [{'blocks': [{'uid': 'foo'},
                                               {'uid': 'bar'}]}]},
                         {'cols': [{'blocks': []},
                                   {'blocks': []}]}]}
        )

        # The user should not change layouts
        page.manage_permission('ftw.simplelayout: Change Layouts',
                               roles=[],
                               acquire=0)

        # When he changes layouts, Unauthorized is raised
        with self.assertRaises(Unauthorized):
            config.store(
                {'default': [{'cols': [{'blocks': [{'uid': 'foo'},
                                                   {'uid': 'bar'}]}]}]}
            )

        # But he is allowed to move blocks
        config.store(
            {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]},
                         {'cols': [{'blocks': [{'uid': 'bar'}]},
                                   {'blocks': []}]}]}
        )
    def test_setting_and_loading_config(self):
        config = IPageConfiguration(create(Builder("sample container")))
        config.store({"default": [{"cols": [{"blocks": [{"uid": "foo"}]}]}]})
        self.assertEquals({"default": [{"cols": [{"blocks": [{"uid": "foo"}]}]}]}, config.load())

        config.store({"default": [{"cols": [{"blocks": [{"uid": "bar"}]}]}]})
        self.assertEquals({"default": [{"cols": [{"blocks": [{"uid": "bar"}]}]}]}, config.load())
Beispiel #22
0
    def rows(self):
        """ Return datastructure for rendering blocks.
        """
        page_conf = IPageConfiguration(self.context)
        blocks = self._blocks()

        rows = page_conf.load().get(self.name, self.one_layout_one_column)

        user_can_edit = self.user_can_edit()

        for row in rows:
            row['class'] = 'sl-layout'
            for col in row['cols']:
                col['class'] = 'sl-column sl-col-{}'.format(len(row['cols']))
                col['blocks'] = filter(
                    lambda block: block.get('uid', '') in blocks,
                    col['blocks'])

                for block in col['blocks']:
                    obj = blocks[block['uid']]
                    self.create_or_update_block(obj, block)

                # Remove hidden blocks for users not having the permission
                # to edit content.
                col['blocks'] = [
                    block for block in col['blocks']
                    if not block['is_hidden'] or block['is_hidden'] and user_can_edit
                ]

        # Append blocks, which are not in the simplelayout configuration into
        # the last column.

        if self.name == 'default':
            for uid, obj in self._blocks_without_state():
                block = self.create_or_update_block(obj, uid=uid)

                # Skip hidden blocks for users not having the permission
                # to edit content.
                if block['is_hidden'] and not user_can_edit:
                    continue

                rows[-1]['cols'][-1]['blocks'].append(block)

        return rows
Beispiel #23
0
def create_page_state(obj, block):
    page_state = {
        "default": [
            {
                "cols": [
                    {
                        "blocks": [
                            {
                                "uid": IUUID(block)
                            }
                        ]
                    }
                ]
            },
        ]
    }
    page_config = IPageConfiguration(obj)
    page_config.store(page_state)
    transaction.commit()
Beispiel #24
0
 def save_state(self, page, block):
     self.page_state = {
         "default": [
             {
                 "cols": [
                     {
                         "blocks": [
                             {
                                 "uid": IUUID(block)
                             }
                         ]
                     }
                 ]
             }
         ]
     }
     page_config = IPageConfiguration(page)
     page_config.store(self.page_state)
     transaction.commit()
    def test_store_partial_updates(self):
        page = create(Builder("sample container"))
        config = IPageConfiguration(page)

        state = {
            "default": [
                {"cols": [{"blocks": [{"uid": "foo"}]}]},
                {"cols": [{"blocks": [{"uid": "bar"}]}, {"blocks": []}]},
            ],
            "sidebar": [{"cols": [{"blocks": [{"uid": "baz"}, {"uid": "foobar"}]}]}],
        }
        config.store(state)

        partial_state = {"sidebar": [{"cols": [{"blocks": [{"uid": "baz"}]}]}]}
        config.store(partial_state)

        # Remove block "foobar" from "sidebar" slot
        new_state = {
            "default": [
                {"cols": [{"blocks": [{"uid": "foo"}]}]},
                {"cols": [{"blocks": [{"uid": "bar"}]}, {"blocks": []}]},
            ],
            "sidebar": [{"cols": [{"blocks": [{"uid": "baz"}]}]}],
        }

        self.assertEquals(new_state, config.load())
    def test_loaded_config_mutations_are_not_stored(self):
        config = IPageConfiguration(create(Builder("sample container")))
        config.store({"default": [{"cols": [{"blocks": [{"uid": "foo"}]}]}]})

        config.load()["default"][0]["cols"][0]["blocks"].append({"uid": "bar"})

        self.assertEquals({"default": [{"cols": [{"blocks": [{"uid": "foo"}]}]}]}, config.load())
Beispiel #27
0
def update_page_state_on_copy_paste_block(block, event):
    """Update the uid of the new created block in the page state.
    block: new block
    event.original: origin of the copy event - usually the simplelayout page"""

    # Only update page state, if the original object is a Simplelayout page.
    if not ISimplelayout.providedBy(event.original):
        return

    # The event is triggered recursively - we need to check if the block is
    # actually part of the original page
    if event.original.get(block.id) is None:
        return

    origin_block_uid = IUUID(event.original.get(block.id))
    page_config = IPageConfiguration(block.aq_parent)
    page_state = unwrap_persistence(page_config.load())

    new_block_uid = IUUID(block)
    new_page_state = json.loads(
        json.dumps(page_state).replace(origin_block_uid,
                                       new_block_uid))

    page_config.store(new_page_state)
    def test_setting_and_loading_config(self):
        config = IPageConfiguration(create(Builder('sample container')))
        config.store(
            {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]}
        )
        self.assertEquals(
            {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]},
            config.load())

        config.store(
            {'default': [{'cols': [{'blocks': [{'uid': 'bar'}]}]}]}
        )
        self.assertEquals(
            {'default': [{'cols': [{'blocks': [{'uid': 'bar'}]}]}]},
            config.load())
    def test_loaded_config_mutations_are_not_stored(self):
        config = IPageConfiguration(create(Builder('sample container')))
        config.store(
            {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]}
        )

        config.load()['default'][0]['cols'][0]['blocks'].append(
            {'uid': 'bar'})

        self.assertEquals(
            {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]},
            config.load())
    def setUp(self):
        self.page = create(Builder('sl content page'))
        self.block_without_image = create(Builder('sl textblock')
                                          .within(self.page))

        self.block_with_image = create(Builder('sl textblock')
                                       .within(self.page)
                                       .with_dummy_image())

        self.page_state = {
            "default": [
                {
                    "cols": [
                        {
                            "blocks": [
                                {
                                    "uid": IUUID(self.block_with_image)
                                }
                            ]
                        }
                    ]
                },
                {
                    "cols": [
                        {
                            "blocks": [
                                {
                                    "uid": IUUID(self.block_without_image)
                                }
                            ]
                        }
                    ]
                }
            ]
        }
        self.page_config = IPageConfiguration(self.page)
        self.page_config.store(self.page_state)
        transaction.commit()
    def test_store_partial_updates(self):
        page = create(Builder('sample container'))
        config = IPageConfiguration(page)

        state = {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]},
                             {'cols': [{'blocks': [{'uid': 'bar'}]},
                                       {'blocks': []}]}],
                 'sidebar': [{'cols': [{'blocks': [{'uid': 'baz'},
                                                   {'uid': 'foobar'}]}]}]}
        config.store(state)

        partial_state = {'sidebar': [{'cols': [
            {'blocks': [{'uid': 'baz'}]}]}]}
        config.store(partial_state)

        # Remove block "foobar" from "sidebar" slot
        new_state = {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]},
                                 {'cols': [{'blocks': [{'uid': 'bar'}]},
                                           {'blocks': []}]}],
                     'sidebar': [{'cols': [{'blocks': [{'uid': 'baz'}]}]}]}

        self.assertEquals(new_state, config.load())
class TestLeadImage(SimplelayoutTestCase):

    layer = FTW_SIMPLELAYOUT_CONTENT_TESTING

    def setUp(self):
        self.page = create(Builder('sl content page'))
        self.block_without_image = create(Builder('sl textblock')
                                          .within(self.page))

        self.block_with_image = create(Builder('sl textblock')
                                       .within(self.page)
                                       .with_dummy_image())

        self.page_state = {
            "default": [
                {
                    "cols": [
                        {
                            "blocks": [
                                {
                                    "uid": IUUID(self.block_with_image)
                                }
                            ]
                        }
                    ]
                },
                {
                    "cols": [
                        {
                            "blocks": [
                                {
                                    "uid": IUUID(self.block_without_image)
                                }
                            ]
                        }
                    ]
                }
            ]
        }
        self.page_config = IPageConfiguration(self.page)
        self.page_config.store(self.page_state)
        transaction.commit()

    @browsing
    def test_use_first_image_in_page_state(self, browser):
        browser.login().visit(self.page, view='@@leadimage')
        self.assertTrue(
            browser.css('img').first.attrib['src'].startswith(
                self.block_with_image.absolute_url()))

    @browsing
    def test_default_scale_is_preview(self, browser):
        browser.login().visit(self.page, view='@@leadimage')
        self.assertEquals(
            '400',
            browser.css('img').first.attrib['width'])

    @browsing
    def test_render_image_with_other_scale(self, browser):
        browser.login().visit(self.page,
                              view='@@leadimage',
                              data={'scale': 'mini'})
        self.assertEquals(
            '200',
            browser.css('img').first.attrib['width'])

    @browsing
    def test_get_image_from_block_in_any_container(self, browser):
        page = create(Builder('sl content page'))
        block = create(Builder('sl textblock').with_dummy_image().within(page))
        IPageConfiguration(page).store(
            {"portletright": [{"cols": [{"blocks": [
                {"uid": IUUID(block)},
            ]}]}]})
        transaction.commit()

        browser.login().visit(page, view='@@leadimage')
        src_url = browser.css('img').first.attrib['src']
        self.assertRegexpMatches(src_url, r'^{}'.format(
            re.escape(block.absolute_url())))

    @browsing
    def test_support_images_in_gallery_blocks(self, browser):
        page = create(Builder('sl content page'))
        gallery = create(Builder('sl galleryblock').within(page))
        image = create(Builder('image').with_dummy_content().within(gallery))
        page_config = IPageConfiguration(page)
        page_config.store(
            {"default": [{"cols": [{"blocks": [
                {"uid": IUUID(gallery)},
            ]}]}]})
        transaction.commit()

        browser.login().visit(page, view='@@leadimage')
        src_url = browser.css('img').first.attrib['src']
        self.assertRegexpMatches(src_url, r'^{}'.format(
            re.escape(image.absolute_url())))
 def getData(self):
     return unwrap_persistence(IPageConfiguration(self.context).load())
class TestSimplelayoutView(SimplelayoutTestCase):

    layer = FTW_SIMPLELAYOUT_FUNCTIONAL_TESTING

    def setUp(self):
        super(TestSimplelayoutView, self).setUp()
        self.setup_sample_ftis(self.layer['portal'])
        self.setup_block_views()
        self.container = create(Builder('sample container'))
        self.page_config = IPageConfiguration(self.container)
        self.url = self.container.absolute_url() + '/@@simplelayout-view'

        self.payload = {
            "default": [
                {
                    "cols": [
                        {
                            "blocks": [
                                {
                                    "uid": "c774b0ca2a5544bf9bb46d865b11bff9"
                                }
                            ]
                        }
                    ]
                },
                {
                    "cols": [
                        {
                            "blocks": [
                                {
                                    "uid": "413fb945952d4403a58ab1958c38f1d2"
                                }
                            ]
                        }
                    ]
                }
            ]
        }

    @browsing
    def test_render_blocks_not_in_page_configuration(self, browser):
        # Fallback for not saved blocks thru the simplelayout JS lib.
        create(Builder('sample block')
               .titled('TextBlock title')
               .within(self.container)
               .having(text=RichTextValue('The text'))
               )

        browser.login().visit(self.container, view='@@simplelayout-view')

        self.assertEqual(browser.url, self.url)
        self.assertEquals('OK',
                          browser.css('.sl-block').first.text)

    @browsing
    def test_invalid_simplelayout_save_state_request(self, browser):
        with browser.expect_http_error(reason='Bad Request'):
            browser.login().visit(self.container,
                                  view='sl-ajax-save-state-view',
                                  data={})

    @browsing
    def test_store_save_simplelayout_state_thru_view(self, browser):
        payload = {"data": json.dumps(self.payload)}

        if IS_PLONE_5:
            from plone.protect.authenticator import createToken
            payload["_authenticator"] = createToken()

        browser.login().visit(self.container,
                              view='sl-ajax-save-state-view',
                              data=payload)

        browser.visit(self.container)
        self.assertEquals(self.payload, self.page_config.load())

    @browsing
    def test_render_blocks_in_different_layouts(self, browser):
        block1 = create(Builder('sample block')
                        .titled('Block 1')
                        .within(self.container))
        block2 = create(Builder('sample block')
                        .titled('Block 1')
                        .within(self.container))

        self.payload['default'][0]['cols'][0][
            'blocks'][0]['uid'] = IUUID(block1)
        self.payload['default'][1]['cols'][0][
            'blocks'][0]['uid'] = IUUID(block2)
        self.page_config.store(self.payload)
        transaction.commit()

        browser.login().visit(self.container)
        self.assertEquals(2,
                          len(browser.css('.sl-layout')),
                          'Expect 2 layouts')

        self.assertEquals(2,
                          len(browser.css('.sl-column.sl-col-1')),
                          'Expect two, one column layouts')

    @browsing
    def test_render_blocks_in_different_columns(self, browser):
        block1 = create(Builder('sample block')
                        .titled('Block 1')
                        .within(self.container))
        block2 = create(Builder('sample block')
                        .titled('Block 1')
                        .within(self.container))

        self.payload['default'][0]['cols'][0][
            'blocks'][0]['uid'] = IUUID(block1)
        self.payload['default'][1]['cols'][0][
            'blocks'][0]['uid'] = IUUID(block2)

        # Move Block into layout 1, column 2
        data_colmn = self.payload['default'][1]['cols'][0]
        self.payload['default'].pop()

        self.payload['default'][0]['cols'].append(data_colmn)
        self.page_config.store(self.payload)
        transaction.commit()

        browser.login().visit(self.container)
        self.assertEquals(2,
                          len(browser.css('.sl-column.sl-col-2')),
                          'Expect 2 columns')

    @browsing
    def test_skips_unavailable_blocks(self, browser):
        # The block may no longer exist or may not be visible for
        # the current user.

        block1 = create(Builder('sample block')
                        .titled('Block 1')
                        .within(self.container))

        self.payload['default'][0]['cols'][0][
            'blocks'][0]['uid'] = IUUID(block1)
        self.payload['default'][1]['cols'][0][
            'blocks'][0]['uid'] = '123xNONxEXISTINGxUIDx123'
        self.page_config.store(self.payload)
        transaction.commit()

        browser.login().visit(self.container)
        self.assertEquals(
            ['http://nohost/plone/samplecontainer/block-1'],
            map(lambda node: node.attrib.get('data-url'),
                browser.css('.sl-block')))

    @browsing
    def test_empty_block_state_does_not_break_the_view(self, browser):
        self.payload['default'][0]['cols'][0]['blocks'].append({})
        self.page_config.store(self.payload)
        transaction.commit()

        browser.login().visit(self.container)
        self.assertTrue(
            browser.css('body.template-simplelayout-view'),
            'Expect to be on the simplelayout template, not the error page.')

    @browsing
    def test_simplelayout_default_config_from_control_panel(self, browser):
        browser.login().visit(self.container, view='@@simplelayout-view')

        registry = getUtility(IRegistry)
        settings = registry.forInterface(ISimplelayoutDefaultSettings)
        settings.slconfig = u'{"layouts": [1, 2]}'
        transaction.commit()

        browser.login().visit(self.container, view='@@simplelayout-view')
        data_attr_value = json.loads(browser.css(
            '[data-sl-settings]').first.attrib['data-sl-settings'])

        self.assertEquals([1, 2],
                          data_attr_value['layouts'],
                          'Expect the layout setting in default config.')

    @browsing
    def test_simplelayout_config_updated_by_permissions(self, browser):

        browser.login().visit(self.container, view='@@simplelayout-view')
        data_attr_value = json.loads(browser.css(
            '[data-sl-settings]').first.attrib['data-sl-settings'])

        self.assertTrue(data_attr_value['canChangeLayout'],
                        'Should have the Change layouts permission.')

        self.container.manage_permission('ftw.simplelayout: Change Layouts',
                                         roles=[],
                                         acquire=0)
        transaction.commit()

        browser.visit(self.container, view='@@simplelayout-view')
        data_attr_value = json.loads(browser.css(
            '[data-sl-settings]').first.attrib['data-sl-settings'])

        self.assertFalse(data_attr_value['canChangeLayout'],
                         'Should NOT have the Change layouts permission.')

    @browsing
    def test_prevent_layout_changes_if_not_allowed(self, browser):

        self.container.manage_permission('ftw.simplelayout: Change Layouts',
                                         roles=[],
                                         acquire=0)
        transaction.commit()

        self.payload['default'].append({'cols': [{}]})
        payload = {"data": json.dumps(self.payload)}
        with browser.expect_unauthorized():
            browser.login().visit(self.container,
                                  view='sl-ajax-save-state-view',
                                  data=payload)

    @browsing
    def test_simplelayout_config_updated_by_adapter(self, browser):

        class ContainerConfigAdapter(object):
            implements(ISimplelayoutContainerConfig)

            def __init__(self, context, request):
                pass

            def __call__(self, settings):
                settings['layouts'] = [1]

            def default_page_layout(self):
                return None

        provideAdapter(ContainerConfigAdapter,
                       adapts=(ISampleSimplelayoutContainer, Interface))
        transaction.commit()

        try:
            browser.login().visit(self.container, view='@@simplelayout-view')
            data_attr_value = json.loads(browser.css(
                '[data-sl-settings]').first.attrib['data-sl-settings'])
            self.assertEquals([1], data_attr_value['layouts'])

        finally:
            # Unregister adapter - since the component registry is not isolatet
            # per test
            sm = getGlobalSiteManager()
            sm.unregisterAdapter(ContainerConfigAdapter,
                                 required=(
                                     ISampleSimplelayoutContainer, Interface),
                                 provided=ISimplelayoutContainerConfig)

    @browsing
    def test_simplelayout_default_page_layouts_by_adapter(self, browser):

        class ContainerConfigAdapter(object):
            implements(ISimplelayoutContainerConfig)

            def __init__(self, context, request):
                pass

            def __call__(self, settings):
                pass

            def default_page_layout(self):
                return {
                    "default": [
                        {"cols": [{"blocks": []},
                                  {"blocks": []}]}
                    ]
                }

        provideAdapter(ContainerConfigAdapter,
                       adapts=(ISampleSimplelayoutContainer, Interface))
        transaction.commit()

        try:
            browser.login().visit(self.container, view='@@simplelayout-view')
            # This should result in one layout with two columns
            self.assertEquals(1, len(browser.css('.sl-layout')))
            self.assertEquals(2, len(browser.css('.sl-column.sl-col-2')))

        finally:
            # Unregister adapter - since the component registry is not isolatet
            # per test
            sm = getGlobalSiteManager()
            sm.unregisterAdapter(ContainerConfigAdapter,
                                 required=(
                                     ISampleSimplelayoutContainer, Interface),
                                 provided=ISimplelayoutContainerConfig)

    @browsing
    def test_simplelayout_config_updated_view(self, browser):

        class CustomSimplelayoutView(SimplelayoutView):
            def update_simplelayout_settings(self, settings):
                settings['layouts'] = [1, 4]

        provideAdapter(CustomSimplelayoutView,
                       adapts=(Interface, Interface),
                       provides=IBrowserView,
                       name='customview')

        browser.login().visit(self.container, view='@@customview')
        data_attr_value = json.loads(browser.css(
            '[data-sl-settings]').first.attrib['data-sl-settings'])
        self.assertEquals([1, 4], data_attr_value['layouts'])

    @browsing
    def test_show_fallback_view_on_block_render_problems(self, browser):
        block = create(Builder('sample block')
                       .titled('TextBlock title')
                       .within(self.container))

        properties = getMultiAdapter((block, block.REQUEST),
                                     IBlockProperties)
        properties.set_view('block_view_broken')

        transaction.commit()

        browser.login().visit(self.container)
        self.assertEquals(
            'The block could not be rendered. Please check the log for '
            'details.',
            browser.css('.sl-block').first.text)

    @browsing
    def test_empty_sl_page_renders_at_least_one_layout(self, browser):
        browser.login().visit(self.container)

        # By default it's a one column layout.
        self.assertEquals(1,
                          len(browser.css('.sl-column.sl-col-1')),
                          'There should be at least a empty one column layout')

    @browsing
    def test_normalized_portal_type_as_css_klass_on_block(self, browser):
        create(Builder('sample block')
               .titled('TextBlock title')
               .within(self.container))
        browser.login().visit(self.container)
        self.assertEquals('sl-block sampleblock',
                          browser.css('.sl-block').first.attrib['class'],
                          'Expect "sample" as css klass on block structure.')

    @browsing
    def test_block_has_anchor(self, browser):
        create(Builder('sample block')
               .titled('Block 1')
               .within(self.container))

        browser.login().open(self.container)
        self.assertEqual(
            'block-1',
            browser.css('.sl-layout a').first.attrib['name']
        )

    @browsing
    def test_canEdit_is_false_if_border_disabled(self, browser):
        browser.login().visit(self.container, data={'disable_border': 1})
        data_attr_value = json.loads(browser.css(
            '[data-sl-settings]').first.attrib['data-sl-settings'])

        self.assertFalse(data_attr_value['canEdit'],
                         'Edit should be disabled if disable_border is there.')

    @browsing
    def test_sl_container_has_sl_edit_css_class(self, browser):
        browser.login().visit(self.container)
        self.assertTrue(len(browser.css('.sl-can-edit')),
                        'Expect the sl-can-edit class on sl-simplelayout.')

    @browsing
    def test_sl_container_no_sl_edi_css_class(self, browser):
        browser.login().visit(self.container, data={'disable_border': 1})
        self.assertFalse(len(browser.css('.sl-can-edit')),
                         'no sl-can-edit class expected.')

    @browsing
    def test_simplelayout_renderer_only_one_layout_of_storage(self, browser):
        storage = self.payload.copy()
        sl_renderer = SimplelayoutRenderer(self.container, storage, 'default')

        browser.parse(sl_renderer.render_layout(index=1))
        self.assertEquals(1, len(browser.css('.sl-layout')),
                          'Expect only one layout')

        browser.parse(sl_renderer.render_layout(index=0))
        self.assertEquals(1, len(browser.css('.sl-layout')),
                          'Expect only one layout')

        browser.parse(sl_renderer.render_layout())
        self.assertEquals(2, len(browser.css('.sl-layout')),
                          'Expect both layouts')

    @browsing
    def test_simplelayout_renderer_raises_ValueError(self, browser):
        storage = self.payload.copy()
        sl_renderer = SimplelayoutRenderer(self.container, storage, 'default')

        with self.assertRaises(ValueError):
            sl_renderer.render_layout(index=4)

    @browsing
    def test_simplelayout_renderer_can_omit_sl_layout_class(self, browser):
        storage = self.payload.copy()
        sl_renderer = SimplelayoutRenderer(self.container, storage, 'default')

        browser.open_html(sl_renderer.render_layout(index=0, is_update=True))
        self.assertEquals(0, len(browser.css('.sl-layout')),
                          'Expect no sl-layout wrapper')
 def setData(self, data, metadata):
     IPageConfiguration(self.context).store(data)
    def test_restore_slot_default_when_removing_last_layout(self):
        """If the last layout was removed from a state, the slot default
        should be restored.
        """

        class ConfigAdapter(object):
            def __init__(self, context, request):
                pass

            def __call__(self, settings):
                pass

            def default_page_layout(self):
                return {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]}

        adapter_registration_kwargs = {
            'factory': ConfigAdapter,
            'required': (ISampleSimplelayoutContainer, Interface),
            'provided': ISimplelayoutContainerConfig}

        container = create(Builder('sample container'))

        gsm = getGlobalSiteManager()
        gsm.registerAdapter(**adapter_registration_kwargs)
        try:
            config = IPageConfiguration(container)
            config.store(config.load())
            self.assertEquals(
                {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}]},
                config.load())

            config.store({'default': [{'cols': [{'blocks': []}]}],
                          'portlet': [{'cols': [{'blocks': [{'uid': 'bar'}]}]}]})
            self.assertEquals(
                {'default': [{'cols': [{'blocks': []}]}],
                 'portlet': [{'cols': [{'blocks': [{'uid': 'bar'}]}]}]},
                config.load())

            config.store({'default': []})
            self.assertEquals(
                {'default': [{'cols': [{'blocks': [{'uid': 'foo'}]}]}],
                 'portlet': [{'cols': [{'blocks': [{'uid': 'bar'}]}]}]},
                config.load())

        finally:
            gsm.unregisterAdapter(**adapter_registration_kwargs)