def test_draft_reversion(): view_name = printable_gibberish() theme = ATestTheme() placeholder_name = "test_ph" vc = ViewConfig(theme=theme, view_name=view_name, draft=True) def get_layout_data(draft): # shorthand -- we're going to be doing this a lot in this test case return ViewConfig(theme=theme, view_name=view_name, draft=draft).saved_view_config.get_layout_data(placeholder_name) data1 = {printable_gibberish(): True} data2 = {printable_gibberish(): True} vc.save_placeholder_layout(placeholder_name, data1) vc.publish() assert get_layout_data(draft=False) == data1 assert get_layout_data(draft=True) == data1 vc = ViewConfig(theme=theme, view_name=view_name, draft=True) svc = vc.saved_view_config assert svc.draft assert svc.get_layout_data(placeholder_name) == data1 # Make changes over the last published version svc.set_layout_data(placeholder_name, data2) svc.save() # Still all good in public? assert get_layout_data(draft=False) == data1 # Still got it in draft? assert get_layout_data(draft=True) == data2 # Actually revert those draft changes now! vc.revert() # So in draft we're back to the published version, right? assert get_layout_data(draft=True) == data1
def test_draft_reversion(): view_name = printable_gibberish() shop = get_default_shop() theme = ATestTheme(shop=shop) placeholder_name = "test_ph" vc = ViewConfig(theme=theme, shop=shop, view_name=view_name, draft=True) def get_layout_data(draft): # shorthand -- we're going to be doing this a lot in this test case return ViewConfig(theme=theme, shop=shop, view_name=view_name, draft=draft).saved_view_config.get_layout_data(placeholder_name) data1 = {printable_gibberish(): True} data2 = {printable_gibberish(): True} vc.save_placeholder_layout(placeholder_name, data1) vc.publish() assert get_layout_data(draft=False) == data1 assert get_layout_data(draft=True) == data1 vc = ViewConfig(theme=theme, shop=shop, view_name=view_name, draft=True) svc = vc.saved_view_config assert svc.draft assert svc.get_layout_data(placeholder_name) == data1 # Make changes over the last published version svc.set_layout_data(placeholder_name, data2) svc.save() # Still all good in public? assert get_layout_data(draft=False) == data1 # Still got it in draft? assert get_layout_data(draft=True) == data2 # Actually revert those draft changes now! vc.revert() # So in draft we're back to the published version, right? assert get_layout_data(draft=True) == data1
def test_unthemebound_view_config_cant_do_much(): vc = ViewConfig(theme=None, shop=get_default_shop(), view_name="durr", draft=True) with pytest.raises(ValueError): vc.publish() with pytest.raises(ValueError): vc.revert() with pytest.raises(ValueError): vc.save_placeholder_layout("hurr", {"foo": True}) l = vc.get_placeholder_layout(Layout, "hurr") # loading should work, but . . . assert not len(l.rows) # . . . there shouldn't be much in there
def test_unthemebound_view_config_cant_do_much(): vc = ViewConfig(theme=None, view_name="durr", draft=True) with pytest.raises(ValueError): vc.publish() with pytest.raises(ValueError): vc.revert() with pytest.raises(ValueError): vc.save_placeholder_layout("hurr", {"foo": True}) l = vc.get_placeholder_layout("hurr") # loading should work, but . . . assert not len(l.rows) # . . . there shouldn't be much in there
def test_page_layout(): if "shuup.xtheme" not in settings.INSTALLED_APPS: pytest.skip("Need shuup.xtheme in INSTALLED_APPS") shop = factories.get_default_shop() theme = get_current_theme(shop) view_config = ViewConfig(theme=theme, shop=shop, view_name="PageView", draft=True) page1_content = printable_gibberish() page1 = create_page(available_from=datetime.date(1917, 12, 6), content=page1_content, shop=shop, url="test1") page2_content = printable_gibberish() page2 = create_page(available_from=datetime.date(1917, 12, 6), content=page2_content, shop=shop, url="test2") placeholder_name = "cms_page" context = {"page": page1} layout = view_config.get_placeholder_layout(PageLayout, placeholder_name, context=context) assert isinstance(layout, PageLayout) assert layout.get_help_text({}) == "" # Invalid context for help text assert page1.title in layout.get_help_text(context) # Make sure layout is empty serialized = layout.serialize() assert len(serialized["rows"]) == 0 assert serialized["name"] == placeholder_name # Add custom plugin to page layout.begin_column({"md": 8}) plugin_text = printable_gibberish() layout.add_plugin("text", {"text": plugin_text}) view_config.save_placeholder_layout( get_layout_data_key(placeholder_name, layout, context), layout) view_config.publish() c = SmartClient() soup = c.soup(reverse("shuup:cms_page", kwargs={"url": page1.url})) page_content = soup.find("div", {"class": "page-content"}) assert page1_content in page_content.text assert plugin_text in page_content.text c = SmartClient() soup = c.soup(reverse("shuup:cms_page", kwargs={"url": page2.url})) page_content = soup.find("div", {"class": "page-content"}) assert page2_content in page_content.text assert plugin_text not in page_content.text
def test_load_save_publish(): view_name = printable_gibberish() theme = ATestTheme() vc = ViewConfig(theme=theme, view_name=view_name, draft=True) placeholder_name = "test_ph" data = {"dummy": True} vc.save_placeholder_layout(placeholder_name, data) assert not ViewConfig(theme=theme, view_name=view_name, draft=False).saved_view_config.get_layout_data(placeholder_name) vc.publish() with pytest.raises(ValueError): # Republishment is bad vc.publish() with pytest.raises(ValueError): # Editing directly in public is bad vc.save_placeholder_layout(placeholder_name, "break all the things") with pytest.raises(ValueError): # Can't quite revert public changes either vc.revert() assert ViewConfig(theme=theme, view_name=view_name, draft=False).saved_view_config.get_layout_data(placeholder_name)
def test_load_save_publish(): view_name = printable_gibberish() shop = get_default_shop() theme = ATestTheme(shop=shop) vc = ViewConfig(theme=theme, shop=shop, view_name=view_name, draft=True) placeholder_name = "test_ph" data = {"dummy": True} vc.save_placeholder_layout(placeholder_name, data) assert not ViewConfig(theme=theme, shop=shop, view_name=view_name, draft=False).saved_view_config.get_layout_data(placeholder_name) vc.publish() with pytest.raises(ValueError): # Republishment is bad vc.publish() with pytest.raises(ValueError): # Editing directly in public is bad vc.save_placeholder_layout(placeholder_name, "break all the things") with pytest.raises(ValueError): # Can't quite revert public changes either vc.revert() assert ViewConfig(theme=theme, shop=shop, view_name=view_name, draft=False).saved_view_config.get_layout_data(placeholder_name)
def test_page_layout(): if "shuup.xtheme" not in settings.INSTALLED_APPS: pytest.skip("Need shuup.xtheme in INSTALLED_APPS") shop = factories.get_default_shop() theme = get_current_theme(shop) view_config = ViewConfig(theme=theme, shop=shop, view_name="PageView", draft=True) page1_content = printable_gibberish() page1 = create_page(available_from=datetime.date(1917, 12, 6), content=page1_content, shop=shop, url="test1") page2_content = printable_gibberish() page2 = create_page(available_from=datetime.date(1917, 12, 6), content=page2_content, shop=shop, url="test2") placeholder_name = "cms_page" context = {"page": page1} layout = view_config.get_placeholder_layout(PageLayout, placeholder_name, context=context) assert isinstance(layout, PageLayout) assert layout.get_help_text({}) == "" # Invalid context for help text assert page1.title in layout.get_help_text(context) # Make sure layout is empty serialized = layout.serialize() assert len(serialized["rows"]) == 0 assert serialized["name"] == placeholder_name # Add custom plugin to page layout.begin_column({"md": 8}) plugin_text = printable_gibberish() layout.add_plugin("text", {"text": plugin_text}) view_config.save_placeholder_layout(get_layout_data_key(placeholder_name, layout, context), layout) view_config.publish() c = SmartClient() soup = c.soup(reverse("shuup:cms_page", kwargs={"url": page1.url})) page_content = soup.find("div", {"class": "page-content"}) assert page1_content in page_content.text assert plugin_text in page_content.text c = SmartClient() soup = c.soup(reverse("shuup:cms_page", kwargs={"url": page2.url})) page_content = soup.find("div", {"class": "page-content"}) assert page2_content in page_content.text assert plugin_text not in page_content.text
def test_plugin(): shop = factories.get_default_shop() set_current_theme(ClassicGrayTheme.identifier, shop) blog_one_page = Page.objects.create( shop=shop, title="Blog One", url="blog_one", available_from=(now() - timedelta(days=10)), available_to=(now() + timedelta(days=10)), content="") blog_two_page = Page.objects.create( shop=shop, title="Blog Two", url="blog_two", available_from=(now() - timedelta(days=10)), available_to=(now() + timedelta(days=10)), content="") # create 10 blog pages for page in [blog_one_page, blog_two_page]: for i in range(10): article = Page.objects.create( shop=shop, title="Article %d %s" % (i, page.title), url="blog-%d-%s" % (i, page.url), available_from=(now() - timedelta(days=10)), available_to=(now() + timedelta(days=10)), content="Content %d" % i, template_name="shuup_cms_blog/blog_page.jinja", parent=page) BlogArticle.objects.create( page=article, is_blog_article=True, image=factories.get_random_filer_image(), small_description="description %d" % i) # create 3 non blog post pages for i in range(3): article = Page.objects.create( shop=shop, title="Nothing %d" % i, url="non-%d" % i, available_from=(now() - timedelta(days=10)), available_to=(now() + timedelta(days=10)), content="content %i" % i) theme = get_current_theme(shop) view_config = ViewConfig(theme=theme, shop=shop, view_name="PageView", draft=True) placeholder_name = "cms_page" context_one = {"page": blog_one_page} context_two = {"page": blog_two_page} layout_one = view_config.get_placeholder_layout(PageLayout, placeholder_name, context=context_one) layout_two = view_config.get_placeholder_layout(PageLayout, placeholder_name, context=context_two) assert isinstance(layout_one, PageLayout) assert isinstance(layout_two, PageLayout) assert layout_one.get_help_text({}) == "" assert layout_two.get_help_text({}) == "" assert blog_one_page.title in layout_two.get_help_text(context_one) assert blog_two_page.title in layout_two.get_help_text(context_two) serialized_one = layout_one.serialize() serialized_two = layout_two.serialize() assert len(serialized_one["rows"]) == 0 assert len(serialized_two["rows"]) == 0 assert serialized_one["name"] == placeholder_name assert serialized_two["name"] == placeholder_name layout_one.begin_column({"sm": 12}) layout_two.begin_column({"sm": 12}) layout_one.add_plugin(ShuupCMSBlogArticleListPlugin.identifier, {"blog_page": blog_one_page.pk}) layout_two.add_plugin(ShuupCMSBlogArticleListPlugin.identifier, {"blog_page": blog_two_page.pk}) view_config.save_placeholder_layout( get_layout_data_key(placeholder_name, layout_one, context_one), layout_one) view_config.save_placeholder_layout( get_layout_data_key(placeholder_name, layout_two, context_two), layout_two) view_config.publish() client = SmartClient() response, soup = client.response_and_soup( reverse("shuup:cms_page", kwargs={"url": blog_one_page.url})) assert response.status_code == 200 assert len(soup.find_all("a", {"class": "article-card"})) == 10 response, soup = client.response_and_soup( reverse("shuup:cms_page", kwargs={"url": blog_two_page.url})) assert response.status_code == 200 assert len(soup.find_all("a", {"class": "article-card"})) == 10 article_one = Page.objects.create( shop=shop, title="Article test", url="blog-test", available_from=(now() - timedelta(days=10)), available_to=(now() + timedelta(days=10)), content="Content test", template_name= "shuup_cms_blog/blog_page.jinja", # Add an article without a parent ) BlogArticle.objects.create(page=article_one, is_blog_article=True, image=factories.get_random_filer_image(), small_description="description test") article_two = Page.objects.create( shop=shop, title="Article test 2", url="blog-test-2", available_from=(now() - timedelta(days=10)), available_to=(now() + timedelta(days=10)), content="Content test 2", template_name= "shuup_cms_blog/blog_page.jinja", # Add an article without a parent ) BlogArticle.objects.create(page=article_two, is_blog_article=True, image=factories.get_random_filer_image(), small_description="description test 2") view_config = ViewConfig(theme=theme, shop=shop, view_name="PageView", draft=True) # No blog page set means that only articles with no parent will be shown layout_two.add_plugin(ShuupCMSBlogArticleListPlugin.identifier, {}) view_config.save_placeholder_layout( get_layout_data_key(placeholder_name, layout_two, context_two), layout_two) view_config.publish() response, soup = client.response_and_soup( reverse("shuup:cms_page", kwargs={"url": blog_two_page.url})) assert response.status_code == 200 assert len(soup.find_all("a", {"class": "article-card"})) == 2 response, soup = client.response_and_soup( reverse("shuup:cms_page", kwargs={"url": article_one.url})) assert response.status_code == 200 assert len(soup.find_all("a", {"class": "article-card"})) == 1 assert soup.find("div", { "class": "article-title" }).text == article_two.title article_one.soft_delete() # Delete the article that has no parent article_two.soft_delete() # Delete the article that has no parent response, soup = client.response_and_soup( reverse("shuup:cms_page", kwargs={"url": blog_two_page.url})) assert response.status_code == 200 assert len(soup.find_all("a", {"class": "article-card"})) == 0 article_with_parent = Page.objects.filter(parent=blog_one_page).first() response, soup = client.response_and_soup( reverse("shuup:cms_page", kwargs={"url": article_with_parent.url})) assert response.status_code == 200 assert len(soup.find_all( "a", {"class": "article-card"})) == 9 # Assert there are 9 articles shown article_card_titles = soup.find_all("div", {"class": "article-title"}) article_card_titles = [title.text for title in article_card_titles] # Assert that the current visited article (article_with_parent) is not visible in Related articles assert article_with_parent.title not in article_card_titles
class EditorView(TemplateView): template_name = "shuup/xtheme/editor.jinja" xtheme_injection = False # We don't need the editing injection here, so opt-out changed = False # Overridden in `save_layout` def _get_default_layout(self): try: return json.loads(self.request.GET["default_config"]) except (ValueError, KeyError): return None def get_context_data(self, **kwargs): # doccov: ignore ctx = super(EditorView, self).get_context_data(**kwargs) ctx["layout"] = self.layout ctx["csrf_token_str"] = get_token(self.request) # ctx["layout_debug"] = pformat(ctx["layout"].serialize()) ctx["current_cell_coords"] = self.current_cell_coords ctx["current_cell"] = self.current_cell ctx["form"] = self.form ctx["changed"] = self.changed ctx["cell_limit"] = ROW_CELL_LIMIT return ctx def dispatch(self, request, *args, **kwargs): # doccov: ignore if not could_edit(request): raise Problem(_("No access to editing.")) self._populate_vars() if self.default_layout: self.view_config.save_default_placeholder_layout(self.placeholder_name, self.default_layout) # We saved the default layout, so get rid of the humongous GET arg and try again get_args = dict(self.request.GET.items()) get_args.pop("default_config", None) global_type = get_args.pop("global_type", None) if global_type: get_args["view"] = XTHEME_GLOBAL_VIEW_NAME # We are overriding the view with XTHEME_GLOBAL_VIEW_NAME if this is a global placeholder return HttpResponseRedirect("%s?%s" % (self.request.path, urlencode(get_args))) return super(EditorView, self).dispatch(request, *args, **kwargs) def post(self, request, *args, **kwargs): # doccov: ignore command = request.POST.get("command") if command: dispatcher = getattr(self, "dispatch_%s" % command, None) if not callable(dispatcher): raise Problem(_("Unknown command: `%s`.") % command) dispatch_kwargs = dict(request.POST.items()) rv = dispatcher(**dispatch_kwargs) if rv: return rv self.request.method = "GET" # At this point, we won't want to cause form validation self.build_form() # and it's not a bad idea to rebuild the form return super(EditorView, self).get(request, *args, **kwargs) if request.POST.get("save") and self.form and self.form.is_valid(): self.form.save() self.save_layout() # after we save the new layout configs, make sure to reload the saved data in forms # so the returned get() response contains updated data self.build_form() if request.POST.get("publish") == "1": return self.dispatch_publish() return self.get(request, *args, **kwargs) def _populate_vars(self): theme = get_theme_by_identifier(self.request.GET["theme"], self.request.shop) if not theme: raise Problem(_("Unable to determine the current theme.")) view_name = self.request.GET["view"] global_type = self.request.GET.get("global_type", None) self.view_config = ViewConfig( theme=theme, shop=self.request.shop, view_name=view_name, draft=True, global_type=global_type, ) # Let's store the layout data key for save here self.layout_data_key = self.request.GET.get("layout_data_key", None) # Let's use the layout identifier passed by the view to # fetch correct layout layout_identifier = self.request.GET.get("layout_identifier", None) layout_cls = Layout for provided_layout in get_provided_layouts(): if provided_layout.identifier == layout_identifier: layout_cls = provided_layout self.placeholder_name = self.request.GET["ph"] self.default_layout = self._get_default_layout() self.layout = self.view_config.get_placeholder_layout( layout_cls=layout_cls, placeholder_name=self.placeholder_name, default_layout=self.default_layout, layout_data_key=self.layout_data_key ) (x, y) = self.current_cell_coords = ( int(self.request.GET.get("x", -1)), int(self.request.GET.get("y", -1)), ) self.current_cell = self.layout.get_cell(x=x, y=y) self.build_form() def build_form(self): if not self.current_cell: self.form = None return kwargs = { "layout_cell": self.current_cell, "theme": self.view_config.theme, "request": self.request } if self.request.method == "POST": kwargs["data"] = self.request.POST kwargs["files"] = self.request.FILES self.form = LayoutCellFormGroup(**kwargs) def save_layout(self, layout=None): self.view_config.save_placeholder_layout( layout_data_key=self.layout_data_key, layout=(layout or self.layout) ) self.changed = True def dispatch_add_cell(self, y, **kwargs): y = int(y) if len(self.layout.rows[y].cells) >= ROW_CELL_LIMIT: raise ValueError(_("Can't add more than %d cells in one row.") % ROW_CELL_LIMIT) if not (0 <= y < len(self.layout.rows)): # No need to raise an exception, really. # It must have been a honest mistake. return self.layout.rows[y].add_cell() self.save_layout() def dispatch_add_row(self, y=None, **kwargs): row = self.layout.insert_row(y) row.add_cell() # For convenience, add a cell to the row. self.save_layout() def dispatch_del_row(self, y, **kwargs): self.layout.delete_row(y) self.save_layout() def dispatch_move_row_to_index(self, from_y, to_y, **kwargs): self.layout.move_row_to_index(from_y, to_y) self.save_layout() def dispatch_move_cell_to_position(self, from_x, from_y, to_x, to_y, **kwargs): self.layout.move_cell_to_position(from_x, from_y, to_x, to_y) self.save_layout() def dispatch_del_cell(self, x, y, **kwargs): self.layout.delete_cell(x, y) self.save_layout() def dispatch_change_plugin(self, plugin="", **kwargs): if self.current_cell: if not plugin: plugin = None self.current_cell.plugin_identifier = plugin self.save_layout() def dispatch_publish(self, **kwargs): self.view_config.publish() return HttpResponse("<html><script>parent.location.reload()</script>%s.</html>" % _("Published")) def dispatch_revert(self, **kwargs): self.view_config.revert() return HttpResponse("<html><script>parent.location.reload()</script>%s.</html>" % _("Reverted"))
def test_page_anonymous_layout(): if "shuup.simple_cms" not in settings.INSTALLED_APPS: pytest.skip("Need shuup.simple_cms in INSTALLED_APPS") if "shuup.xtheme" not in settings.INSTALLED_APPS: pytest.skip("Need shuup.xtheme in INSTALLED_APPS") shop = factories.get_default_shop() theme = set_current_theme("shuup.themes.classic_gray", shop) view_config = ViewConfig(theme=theme, shop=shop, view_name="PageView", draft=True) page1_content = printable_gibberish() page1 = create_page(available_from=datetime.date(1917, 12, 6), content=page1_content, shop=shop, url="test1") page2_content = printable_gibberish() page2 = create_page(available_from=datetime.date(1917, 12, 6), content=page2_content, shop=shop, url="test2") person = factories.create_random_person(shop=shop) person.user = factories.create_random_user() password = "******" person.user.set_password(password) person.user.save() person.save() placeholder_name = "cms_page" request = get_request() context = {"page": page1, "request": request} layout = view_config.get_placeholder_layout(PageAnonymousLayout, placeholder_name, context=context) assert isinstance(layout, PageAnonymousLayout) assert layout.get_help_text({}) == "" # Invalid context for help text assert page1.title in layout.get_help_text(context) # Make sure layout is empty serialized = layout.serialize() assert len(serialized["rows"]) == 0 assert serialized["name"] == placeholder_name # Add custom plugin to page layout.begin_column({"md": 8}) plugin_text = printable_gibberish() layout.add_plugin("text", {"text": plugin_text}) view_config.save_placeholder_layout( get_layout_data_key(placeholder_name, layout, context), layout) view_config.publish() c = SmartClient() soup = c.soup(reverse("shuup:cms_page", kwargs={"url": page1.url})) page_content = soup.find("div", {"class": "page-content"}) assert page1_content in page_content.text assert plugin_text in page_content.text # Make sure content not available for page2 c = SmartClient() soup = c.soup(reverse("shuup:cms_page", kwargs={"url": page2.url})) page_content = soup.find("div", {"class": "page-content"}) assert page2_content in page_content.text assert plugin_text not in page_content.text # Make sure content not available for logged in users c = SmartClient() c.login(username=person.user.username, password=password) soup = c.soup(reverse("shuup:cms_page", kwargs={"url": page1.url})) page_content = soup.find("div", {"class": "page-content"}) assert page1_content in page_content.text assert plugin_text not in page_content.text
class EditorView(TemplateView): template_name = "shuup/xtheme/editor.jinja" xtheme_injection = False # We don't need the editing injection here, so opt-out changed = False # Overridden in `save_layout` def _get_default_layout(self): try: return json.loads(self.request.GET["default_config"]) except (ValueError, KeyError): return None def get_context_data(self, **kwargs): # doccov: ignore ctx = super(EditorView, self).get_context_data(**kwargs) ctx["layout"] = self.layout ctx["csrf_token_str"] = get_token(self.request) # ctx["layout_debug"] = pformat(ctx["layout"].serialize()) ctx["current_cell_coords"] = self.current_cell_coords ctx["current_cell"] = self.current_cell ctx["form"] = self.form ctx["changed"] = self.changed ctx["cell_limit"] = ROW_CELL_LIMIT return ctx def dispatch(self, request, *args, **kwargs): # doccov: ignore if not could_edit(request): raise Problem(_("No access to editing")) self._populate_vars() if self.default_layout: self.view_config.save_default_placeholder_layout(self.placeholder_name, self.default_layout) # We saved the default layout, so get rid of the humongous GET arg and try again get_args = dict(self.request.GET.items()) get_args.pop("default_config", None) global_type = get_args.pop("global_type", None) if global_type: get_args["view"] = XTHEME_GLOBAL_VIEW_NAME # We are overriding the view with XTHEME_GLOBAL_VIEW_NAME if this is a global placeholder return HttpResponseRedirect("%s?%s" % (self.request.path, urlencode(get_args))) return super(EditorView, self).dispatch(request, *args, **kwargs) def post(self, request, *args, **kwargs): # doccov: ignore command = request.POST.get("command") if command: dispatcher = getattr(self, "dispatch_%s" % command, None) if not callable(dispatcher): raise Problem(_("Unknown command %s") % command) dispatch_kwargs = dict(request.POST.items()) rv = dispatcher(**dispatch_kwargs) if rv: return rv self.request.method = "GET" # At this point, we won't want to cause form validation self.build_form() # and it's not a bad idea to rebuild the form return super(EditorView, self).get(request, *args, **kwargs) if request.POST.get("save") and self.form and self.form.is_valid(): self.form.save() self.save_layout() return super(EditorView, self).get(request, *args, **kwargs) def _populate_vars(self): theme = get_theme_by_identifier(self.request.GET["theme"]) if not theme: raise Problem(_("Unable to determine current theme.")) view_name = self.request.GET["view"] global_type = self.request.GET.get("global_type", None) self.view_config = ViewConfig( theme=theme, view_name=view_name, draft=True, global_type=global_type, ) self.placeholder_name = self.request.GET["ph"] self.default_layout = self._get_default_layout() self.layout = self.view_config.get_placeholder_layout( placeholder_name=self.placeholder_name, default_layout=self.default_layout ) (x, y) = self.current_cell_coords = ( int(self.request.GET.get("x", -1)), int(self.request.GET.get("y", -1)), ) self.current_cell = self.layout.get_cell(x=x, y=y) self.build_form() def build_form(self): if not self.current_cell: self.form = None return kwargs = { "layout_cell": self.current_cell } if self.request.method == "POST": kwargs["data"] = self.request.POST kwargs["files"] = self.request.FILES self.form = LayoutCellFormGroup(**kwargs) def save_layout(self, layout=None): self.view_config.save_placeholder_layout( placeholder_name=self.placeholder_name, layout=(layout or self.layout) ) self.changed = True def dispatch_add_cell(self, y, **kwargs): y = int(y) if len(self.layout.rows[y].cells) >= ROW_CELL_LIMIT: raise ValueError(_("Cannot add more than %d cells in one row.") % ROW_CELL_LIMIT) if not (0 <= y < len(self.layout.rows)): # No need to raise an exception, really. # It must have been a honest mistake. return self.layout.rows[y].add_cell() self.save_layout() def dispatch_add_row(self, y=None, **kwargs): row = self.layout.insert_row(y) row.add_cell() # For convenience, add a cell to the row. self.save_layout() def dispatch_del_row(self, y, **kwargs): self.layout.delete_row(y) self.save_layout() def dispatch_del_cell(self, x, y, **kwargs): self.layout.delete_cell(x, y) self.save_layout() def dispatch_change_plugin(self, plugin="", **kwargs): if self.current_cell: if not plugin: plugin = None self.current_cell.plugin_identifier = plugin self.save_layout() def dispatch_publish(self, **kwargs): self.view_config.publish() return HttpResponse("<html><script>parent.location.reload()</script>%s.</html>" % _("Published")) def dispatch_revert(self, **kwargs): self.view_config.revert() return HttpResponse("<html><script>parent.location.reload()</script>%s.</html>" % _("Reverted"))
def test_plugin(): shop = factories.get_default_shop() set_current_theme(ClassicGrayTheme.identifier, shop) blog_page = Page.objects.create(shop=shop, title="Blog", url="blog", available_from=(now() - timedelta(days=10)), available_to=(now() + timedelta(days=10)), content="") # create 10 blog pages for i in range(10): article = Page.objects.create( shop=shop, title="Article %d" % i, url="blog-%d" % i, available_from=(now() - timedelta(days=10)), available_to=(now() + timedelta(days=10)), content="Content %d" % i, template_name="shuup_cms_blog/blog_page.jinja") BlogArticle.objects.create(page=article, is_blog_article=True, image=factories.get_random_filer_image(), small_description="description %d" % i) # create 3 non blog post pages for i in range(3): article = Page.objects.create( shop=shop, title="Nothing %d" % i, url="non-%d" % i, available_from=(now() - timedelta(days=10)), available_to=(now() + timedelta(days=10)), content="content %i" % i) theme = get_current_theme(shop) view_config = ViewConfig(theme=theme, shop=shop, view_name="PageView", draft=True) placeholder_name = "cms_page" context = {"page": blog_page} layout = view_config.get_placeholder_layout(PageLayout, placeholder_name, context=context) assert isinstance(layout, PageLayout) assert layout.get_help_text({}) == "" assert blog_page.title in layout.get_help_text(context) serialized = layout.serialize() assert len(serialized["rows"]) == 0 assert serialized["name"] == placeholder_name layout.begin_column({"sm": 12}) layout.add_plugin(ShuupCMSBlogArticleListPlugin.identifier, {}) view_config.save_placeholder_layout( get_layout_data_key(placeholder_name, layout, context), layout) view_config.publish() client = SmartClient() response, soup = client.response_and_soup( reverse("shuup:cms_page", kwargs={"url": blog_page.url})) assert response.status_code == 200 assert len(soup.find_all("a", {"class": "article-card"})) == 10