def test_lcfg(rf): two_thirds = int(LayoutCellGeneralInfoForm.CELL_FULL_WIDTH * 2 / 3) with plugin_override(): with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, "text", sizes={"md": two_thirds, "sm": two_thirds}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/"))) assert "general" in lcfg.forms assert "plugin" in lcfg.forms assert not lcfg.is_valid() # Oh, we must've forgotten the text... lcfg = LayoutCellFormGroup( data={ "general-cell_width": "%d" % two_thirds, "general-cell_align": " ", "general-cell_extra_classes" : "newClass", "plugin-text_*": "Hello, world!" }, layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/")) ) assert lcfg.is_valid() # Let's see now! lcfg.save() assert cell.sizes["md"] == two_thirds assert cell.extra_classes == "newClass" assert cell.config["text"] == {FALLBACK_LANGUAGE_CODE: "Hello, world!"}
def get_view_config(context, global_type=False): """ Get a view configuration object for a Jinja2 rendering context. :param context: Rendering context :type context: jinja2.runtime.Context :param global_type: Boolean indicating whether this is a global type :type global_type: bool|False :return: View config :rtype: shuup.xtheme.view_config.ViewConfig """ # This uses the Jinja context's technically-immutable vars dict # to cache the view configuration. This is fine in our case, I'd say. request = context.get("request") config_key = "_xtheme_global_view_config" if global_type else "_xtheme_view_config" config = context.vars.get(config_key) if (config is None): view_object = context.get("view") if view_object: view_class = view_object.__class__ view_name = view_class.__name__ else: view_name = "UnknownView" config = ViewConfig( theme=get_current_theme(request), view_name=view_name, draft=is_edit_mode(request), global_type=global_type, ) context.vars[config_key] = config return config
def test_xtheme_wizard_pane(rf, admin_user, settings): settings.SHUUP_SETUP_WIZARD_PANE_SPEC = [ "shuup.xtheme.admin_module.views.ThemeWizardPane" ] with override_current_theme_class(): with override_provides("xtheme", [ "shuup_tests.xtheme.utils:FauxTheme" ]): get_default_shop() assert get_current_theme() == None fields = _extract_fields(rf, admin_user) fields["theme-activate"] = FauxTheme.identifier request = rf.post("/", data=fields) response = WizardView.as_view()(request) assert isinstance(get_current_theme(), FauxTheme) assert_redirect_to_dashboard(rf)
def get_context_data(self, **kwargs): context = super(ThemeConfigView, self).get_context_data(**kwargs) context["theme_classes"] = sorted( [t for t in get_provide_objects("xtheme") if t.identifier], key=lambda t: (t.name or t.identifier) ) context["current_theme"] = get_current_theme() return context
def _handle_xtheme_save(self): svc_pk = config.get(self.shop, CONTENT_FOOTER_KEY) svc = SavedViewConfig.objects.filter(pk=svc_pk).first() theme = get_current_theme(self.shop) if not svc and theme: context = {"shop": self.shop} rendered_content = template_loader.render_to_string(content_data.FOOTER_TEMPLATE, context).strip() layout = Layout(theme, "footer-bottom") # adds the footer template layout.begin_row() layout.begin_column({"md": 12}) layout.add_plugin(SnippetsPlugin.identifier, {"in_place": rendered_content}) svc = SavedViewConfig( theme_identifier=theme.identifier, shop=self.shop, view_name=XTHEME_GLOBAL_VIEW_NAME, status=SavedViewConfigStatus.CURRENT_DRAFT ) svc.set_layout_data(layout.placeholder_name, layout) svc.save() svc.publish() config.set(self.shop, CONTENT_FOOTER_KEY, svc.pk)
def test_pluginless_lcfg(rf): with plugin_override(): with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, None) assert not cell.instantiate_plugin() lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/"))) assert "plugin" not in lcfg.forms
def get_theme_context(): return { "theme_classes": sorted( [t for t in get_provide_objects("xtheme") if t.identifier], key=lambda t: (t.name or t.identifier) ), "current_theme": get_current_theme() }
def test_pluginless_lcfg(): with plugin_override(): with override_current_theme_class(None): request = get_request(edit=False) theme = get_current_theme(request) cell = LayoutCell(theme, None) assert not cell.instantiate_plugin() lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme) assert "plugin" not in lcfg.forms
def get_help_blocks(self, request, kind): theme = get_current_theme(request.shop) if kind == "quicklink" and theme: yield SimpleHelpBlock( text=_("Customize the look and feel of your shop"), actions=[{ "text": _("Customize theme"), "url": reverse("shuup_admin:xtheme.config_detail", kwargs={"theme_identifier": theme.identifier}) }], priority=200, category=HelpBlockCategory.STOREFRONT, icon_url="xtheme/theme.png" )
def test_xtheme_wizard_pane(rf, admin_user): with override_settings( SHUUP_SETUP_WIZARD_PANE_SPEC = [ "shuup.xtheme.admin_module.views.ThemeWizardPane" ], CACHES={ 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'test_simple_set_and_get_with_shop', } } ): cache.init_cache() shop = get_default_shop() with override_provides("xtheme", ["shuup_tests.xtheme.utils:FauxTheme"]): from shuup_tests.xtheme.utils import FauxTheme assert get_current_theme(shop) is None fields = _extract_fields(rf, admin_user) fields["theme-activate"] = FauxTheme.identifier request = apply_request_middleware(rf.post("/", data=fields), user=admin_user) response = WizardView.as_view()(request) assert isinstance(get_current_theme(shop), FauxTheme) assert_redirect_to_dashboard(rf, admin_user, shop)
def test_product_from_category_plugin(rf): shop = get_default_shop() category1 = get_default_category() category2 = CategoryFactory(status=CategoryStatus.VISIBLE) category1.shops.add(shop) category2.shops.add(shop) p1 = create_product("p1", shop, get_default_supplier(), "10") p2 = create_product("p2", shop, get_default_supplier(), "20") p3 = create_product("p3", shop, get_default_supplier(), "30") sp1 = p1.get_shop_instance(shop) sp2 = p2.get_shop_instance(shop) sp3 = p3.get_shop_instance(shop) sp1.categories.add(category1) sp2.categories.add(category1) sp3.categories.add(category2) context = get_context(rf) plugin = ProductsFromCategoryPlugin({ "category": category1.pk }) context_products = plugin.get_context_data(context)["products"] assert p1 in context_products assert p2 in context_products assert p3 not in context_products # test the plugin form with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, ProductsFromCategoryPlugin.identifier, sizes={"md": 8}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/"))) assert not lcfg.is_valid() lcfg = LayoutCellFormGroup( data={ "general-cell_width": "8", "general-cell_align": "pull-right", "plugin-count": 4, "plugin-category": category2.pk }, layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/")) ) assert lcfg.is_valid() lcfg.save() assert cell.config["category"] == str(category2.pk)
def get_notifications(self, request): try: engine = engines["jinja2"] except KeyError: engine = None if engine and isinstance(engine, Jinja2): # The engine is what we expect... if isinstance(engine.env, XthemeEnvironment): # ... and it's capable of loading themes... if not get_current_theme(request.shop): # ... but there's no theme active?! # Panic! yield Notification( text=_("No theme is active. Click here to activate one."), title=_("Theming"), url="shuup_admin:xtheme.config" )
def test_formless_plugin_in_lcfg(): two_thirds = int(LayoutCellGeneralInfoForm.CELL_FULL_WIDTH * 2 / 3) with plugin_override(): with override_current_theme_class(None): request = get_request(edit=False) theme = get_current_theme(request) cell = LayoutCell(theme, "inject") assert cell.instantiate_plugin() lcfg = LayoutCellFormGroup(data={"general-cell_width": "%d" % two_thirds, "general-cell_align": "pull-right"}, layout_cell=cell, theme=theme) assert "plugin" not in lcfg.forms assert lcfg.is_valid() lcfg.save() assert cell.sizes["md"] == two_thirds # Something got saved even if the plugin doesn't need config
def _create_sample_carousel(cls, shop, business_segment): """ Create the sample carousel for the given business_segment and also injects it to the default theme currently being used in front """ if business_segment not in BUSINESS_SEGMENTS: return None carousel_data = BUSINESS_SEGMENTS[business_segment]["carousel"] carousel = create_sample_carousel(carousel_data, business_segment, shop) # injects the carousel plugin with in the front_content placeholder # this will only works if the theme have this placeholder, we expect so if 'shuup.xtheme' in settings.INSTALLED_APPS: from shuup.front.apps.carousel.plugins import CarouselPlugin from shuup.xtheme.plugins.products import ProductHighlightPlugin from shuup.xtheme.models import SavedViewConfig, SavedViewConfigStatus from shuup.xtheme.layout import Layout from shuup.xtheme._theme import get_current_theme theme = get_current_theme(shop) if theme: layout = Layout(theme, "front_content") # adds the carousel layout.begin_row() layout.begin_column({"md": 12}) layout.add_plugin(CarouselPlugin.identifier, {"carousel": carousel.pk}) # adds some products layout.begin_row() layout.begin_column({"md": 12}) layout.add_plugin(ProductHighlightPlugin.identifier, {}) svc = SavedViewConfig( theme_identifier=theme.identifier, shop=shop, view_name="IndexView", status=SavedViewConfigStatus.CURRENT_DRAFT ) svc.set_layout_data(layout.placeholder_name, layout) svc.save() svc.publish() return carousel
def extra_view_dispatch(request, view): """ Dispatch to an Xtheme extra view. :param request: A request :type request: django.http.HttpRequest :param view: View name :type view: str :return: A response of some ilk :rtype: django.http.HttpResponse """ theme = get_current_theme(request) view_func = get_view_by_name(theme, view) if not view_func: msg = "%s/%s: Not found" % (getattr(theme, "identifier", None), view) return HttpResponseNotFound(msg) return view_func(request)
def get(self, context, name, default=None): """ Get a theme setting value. :param context: Implicit Jinja2 context :type context: jinja2.runtime.Context :param name: Setting name :type name: str :param default: Default value if setting is not found :type default: object :return: Value :rtype: object """ request = context["request"] theme = get_current_theme(request) if theme: return theme.get_setting(name, default=default) return default
def extra_view_dispatch(request, view): """ Dispatch to an Xtheme extra view. :param request: A request. :type request: django.http.HttpRequest :param view: View name. :type view: str :return: A response of some kind. :rtype: django.http.HttpResponse """ theme = get_current_theme(request.shop) view_func = get_view_by_name(theme, view) if not view_func: msg = "Error! %s/%s: Not found." % (getattr(theme, "identifier", None), view) return HttpResponseNotFound(msg) return view_func(request)
def __getitem__(self, item): """ Look for additional helper callables in the active theme. Callables marked with the Django standard `alters_data` attribute will not be honored. :param item: Template helper name :type item: str :return: Template helper, maybe :rtype: object|None """ theme = get_current_theme() if theme: helper = getattr(theme, item, None) if helper and callable(helper) and not getattr( helper, "alters_data", False): return helper raise KeyError("No such template helper: %s" % item)
def get(self, context, name, default=None): """ Get a theme setting value. :param context: Implicit Jinja2 context :type context: jinja2.runtime.Context :param name: Setting name :type name: str :param default: Default value if setting is not found :type default: object :return: Value :rtype: object """ request = context["request"] theme = get_current_theme(request.shop) if theme: return theme.get_setting(name, default=default) return default
def test_product_selection_plugin(rf): shop = get_default_shop() p1 = create_product("p1", shop, get_default_supplier(), "10") p2 = create_product("p2", shop, get_default_supplier(), "20") p3 = create_product("p3", shop, get_default_supplier(), "30") p4 = create_product("p4", shop, get_default_supplier(), "40") sp1 = p1.get_shop_instance(shop) sp2 = p2.get_shop_instance(shop) sp3 = p3.get_shop_instance(shop) context = get_context(rf) plugin = ProductSelectionPlugin({"products": [sp1.pk, sp2.pk, sp3.pk]}) context_products = plugin.get_context_data(context)["products"] assert p1 in context_products assert p2 in context_products assert p3 in context_products assert p4 not in context_products # test the plugin form with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, ProductSelectionPlugin.identifier, sizes={"md": 8}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme, request=apply_request_middleware( rf.get("/"))) # not valid, products are required assert not lcfg.is_valid() lcfg = LayoutCellFormGroup(data={ "general-cell_width": "8", "general-cell_align": "pull-right", "plugin-products": [p1.pk, p2.pk] }, layout_cell=cell, theme=theme, request=apply_request_middleware( rf.get("/"))) assert lcfg.is_valid() lcfg.save() assert cell.config["products"] == [str(p1.pk), str(p2.pk)]
def test_formless_plugin_in_lcfg(): two_thirds = int(LayoutCellGeneralInfoForm.CELL_FULL_WIDTH * 2 / 3) with plugin_override(): with override_current_theme_class(None): request = get_request(edit=False) theme = get_current_theme(request) cell = LayoutCell(theme, "inject") assert cell.instantiate_plugin() lcfg = LayoutCellFormGroup( data={"general-cell_width": "%d" % two_thirds}, layout_cell=cell, theme=theme) assert "plugin" not in lcfg.forms assert lcfg.is_valid() lcfg.save() assert cell.sizes[ "md"] == two_thirds # Something got saved even if the plugin doesn't need config
def test_product_selection_plugin(rf): shop = get_default_shop() p1 = create_product("p1", shop, get_default_supplier(), "10") p2 = create_product("p2", shop, get_default_supplier(), "20") p3 = create_product("p3", shop, get_default_supplier(), "30") p4 = create_product("p4", shop, get_default_supplier(), "40") sp1 = p1.get_shop_instance(shop) sp2 = p2.get_shop_instance(shop) sp3 = p3.get_shop_instance(shop) context = get_context(rf) plugin = ProductSelectionPlugin({ "products": [sp1.pk, sp2.pk, sp3.pk] }) context_products = plugin.get_context_data(context)["products"] assert p1 in context_products assert p2 in context_products assert p3 in context_products assert p4 not in context_products # test the plugin form with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, ProductSelectionPlugin.identifier, sizes={"md": 8}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/"))) # not valid, products are required assert not lcfg.is_valid() lcfg = LayoutCellFormGroup( data={ "general-cell_width": "8", "general-cell_align": "pull-right", "plugin-products": [p1.pk, p2.pk] }, layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/")) ) assert lcfg.is_valid() lcfg.save() assert cell.config["products"] == [str(p1.pk), str(p2.pk)]
def test_lcfg(): two_thirds = int(LayoutCellGeneralInfoForm.CELL_FULL_WIDTH * 2 / 3) with plugin_override(): with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, "text", sizes={"md": two_thirds, "sm": two_thirds}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme) assert "general" in lcfg.forms assert "plugin" in lcfg.forms assert not lcfg.is_valid() # Oh, we must've forgotten the text... lcfg = LayoutCellFormGroup(data={ "general-cell_width": "%d" % two_thirds, "general-cell_align": " ", "plugin-text_*": "Hello, world!" }, layout_cell=cell, theme=theme) assert lcfg.is_valid() # Let's see now! lcfg.save() assert cell.sizes["md"] == two_thirds assert cell.config["text"] == {FALLBACK_LANGUAGE_CODE: "Hello, world!"}
def get_notifications(self, request): try: engine = engines["jinja2"] except KeyError: engine = None if engine and isinstance(engine, Jinja2): # The engine is what we expect... if isinstance(engine.env, XthemeEnvironment ): # ... and it's capable of loading themes... if not (getattr(request, "theme", None) or get_current_theme(request.shop)): # ... but there's no theme active?! # Panic! yield Notification( text=_( "No theme is active. Click here to activate one."), title=_("Theming"), url="shuup_admin:xtheme.config", )
def test_lcfg(): two_thirds = int(LayoutCellGeneralInfoForm.CELL_FULL_WIDTH * 2 / 3) with plugin_override(): with override_current_theme_class(None): request = get_request(edit=False) theme = get_current_theme(request) cell = LayoutCell(theme, "text", sizes={"md": two_thirds, "sm": two_thirds}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme) assert "general" in lcfg.forms assert "plugin" in lcfg.forms assert not lcfg.is_valid() # Oh, we must've forgotten the text... lcfg = LayoutCellFormGroup(data={ "general-cell_width": "%d" % two_thirds, "plugin-text": "Hello, world!" }, layout_cell=cell, theme=theme) assert lcfg.is_valid() # Let's see now! lcfg.save() assert cell.sizes["md"] == two_thirds assert cell.config["text"] == {FALLBACK_LANGUAGE_CODE: "Hello, world!"}
def _get_themed_template_names(self, name): """ Get theme-prefixed paths for the given template name. For instance, if the template_dir or identifier of the current theme is `mystery` and we're looking up `shuup/front/bar.jinja`, we'll look at `mystery/shuup/front/bar.jinja`, then at `shuup/front/bar.jinja`. :param name: Template name :type name: str :return: A template name or a list thereof :rtype: str|list[str] """ if name.startswith("shuup/admin"): # Ignore the admin. return name theme = get_current_theme() if not theme: return name return [ "%s/%s" % ((theme.template_dir or theme.identifier), name), name ]
def test_formless_plugin_in_lcfg(rf): two_thirds = int(LayoutCellGeneralInfoForm.CELL_FULL_WIDTH * 2 / 3) with plugin_override(): with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, "inject") assert cell.instantiate_plugin() lcfg = LayoutCellFormGroup(data={ "general-cell_width": "%d" % two_thirds, "general-cell_align": "pull-right" }, layout_cell=cell, theme=theme, request=apply_request_middleware( rf.get("/"))) assert "plugin" not in lcfg.forms assert lcfg.is_valid() lcfg.save() assert cell.sizes[ "md"] == two_thirds # Something got saved even if the plugin doesn't need config
def test_custom_cell_size(rf): with plugin_override(): with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, "text", sizes={"md": None, "sm": None}) lcfg = LayoutCellFormGroup( data={ "general-cell_width": None, "general-cell_align": " ", "general-cell_extra_classes": "newClass", "plugin-text_*": "Hello, world!", }, layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/")), ) assert lcfg.is_valid() lcfg.save() assert cell.sizes["md"] is None assert cell.sizes["sm"] is None assert cell.extra_classes == "newClass" assert cell.config["text"] == {FALLBACK_LANGUAGE_CODE: "Hello, world!"}
def test_ratings_plugin(show_recommenders, title): shop = factories.get_default_shop() product = factories.create_product( "product", shop=shop, supplier=factories.get_default_supplier()) # create 15 reviews for the product [create_random_review_for_product(shop, product) for _ in range(15)] set_current_theme(ClassicGrayTheme.identifier, shop) svc = SavedViewConfig(theme_identifier=ClassicGrayTheme.identifier, shop=shop, view_name="ProductDetailView", status=SavedViewConfigStatus.CURRENT_DRAFT) layout = Layout(get_current_theme(shop), "product_extra_2") layout.add_plugin( ProductReviewStarRatingsPlugin.identifier, { "customer_ratings_title": { "en": title }, "show_recommenders": show_recommenders }) svc.set_layout_data(layout.placeholder_name, layout) svc.save() svc.publish() client = Client() response = client.get( reverse("shuup:product", kwargs=dict(pk=product.pk, slug=product.slug))) assert response.status_code == 200 response.render() content = response.content.decode("utf-8") assert "product-reviews-rating-star" in content assert 'class="rating"' in content assert ('class="recommend"' in content) == show_recommenders assert title in content
def _handle_xtheme_save(self): svc_pk = config.get(self.shop, CONTENT_FOOTER_KEY) svc = SavedViewConfig.objects.filter(pk=svc_pk).first() theme = get_current_theme() if not svc and theme: context = {"shop": self.shop} rendered_content = template_loader.render_to_string(content_data.FOOTER_TEMPLATE, context).strip() layout = Layout(theme, "footer-bottom") # adds the footer template layout.begin_row() layout.begin_column({"md": 12}) layout.add_plugin(SnippetsPlugin.identifier, {"in_place": rendered_content}) svc = SavedViewConfig( theme_identifier=theme.identifier, view_name=XTHEME_GLOBAL_VIEW_NAME, status=SavedViewConfigStatus.CURRENT_DRAFT ) svc.set_layout_data(layout.placeholder_name, layout) svc.save() svc.publish() config.set(self.shop, CONTENT_FOOTER_KEY, svc.pk)
def test_formless_plugin_in_lcfg(rf): two_thirds = int(LayoutCellGeneralInfoForm.CELL_FULL_WIDTH * 2 / 3) with plugin_override(): with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, "inject") assert cell.instantiate_plugin() lcfg = LayoutCellFormGroup( data={ "general-cell_width": "%d" % two_thirds, "general-cell_align": "pull-right", "general-cell_extra_classes" : "newClass", }, layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/")) ) assert "plugin" not in lcfg.forms assert lcfg.is_valid() lcfg.save() assert cell.extra_classes == "newClass" assert cell.sizes["md"] == two_thirds # Something got saved even if the plugin doesn't need config
def _get_themed_template_names(self, name): """ Get theme-prefixed paths for the given template name. For instance, if the template_dir or identifier of the current theme is `mystery` and we're looking up `shuup/front/bar.jinja`, we'll look at `mystery/shuup/front/bar.jinja`, finally at `shuup/front/bar.jinja`. Mystery theme also can define default template dir let's say `pony`. In this scenario we're looking up `shuup/front/bar.jinja` from `mystery/shuup/front/bar.jinja` then at `pony/shuup/front/bar.jinja` and finally at the default `shuup/front/bar.jinja`. :param name: Template name :type name: str :return: A template name or a list thereof :rtype: str|list[str] """ if name.startswith("shuup/admin"): # Ignore the admin. return name theme = get_current_theme() if not theme: return name theme_template = "%s/%s" % ((theme.template_dir or theme.identifier), name) default_template = (("%s/%s" % (theme.default_template_dir, name)) if theme.default_template_dir else None) return [theme_template, default_template, name] if default_template else [theme_template, name]
def test_carousel_custom_colors(rf): from shuup.front.apps.carousel.plugins import CarouselPlugin from shuup.utils.django_compat import reverse from shuup.xtheme._theme import get_current_theme from shuup.xtheme.layout import Layout from shuup.xtheme.models import SavedViewConfig, SavedViewConfigStatus shop = get_default_shop() shop.maintenance_mode = False shop.save() carousel = Carousel.objects.create(name="test") carousel.shops.add(shop) test_image = Image.objects.create(original_filename="slide.jpg") test_slide = Slide.objects.create( carousel=carousel, name="test", available_from=(datetime.now() - timedelta(days=1)), image=test_image, target=LinkTargetType.CURRENT, ) theme = get_current_theme(shop) # adds the carousel to the front page layout = Layout(theme, "front_content") layout.begin_row() layout.begin_column({"md": 12}) layout.add_plugin(CarouselPlugin.identifier, {"carousel": carousel.pk}) svc = SavedViewConfig( theme_identifier=theme.identifier, shop=shop, view_name="IndexView", status=SavedViewConfigStatus.CURRENT_DRAFT ) svc.set_layout_data(layout.placeholder_name, layout) svc.save() svc.publish() client = Client() # no customized color response = client.get(reverse("shuup:index")) content = response.content.decode("utf-8") assert "owl-carousel" in content assert ".owl-nav .owl-prev" not in content assert ".owl-nav .owl-next" not in content assert ".owl-dot:nth-child(" not in content # put colors in arrows carousel.arrows_color = "#ffaabb" carousel.save() response = client.get(reverse("shuup:index")) content = response.content.decode("utf-8") assert ".owl-nav .owl-prev" in content assert ".owl-nav .owl-next" in content assert "color: #ffaabb !important;" in content # put custom color in dots test_slide.inactive_dot_color = "#a1b2c3" test_slide.active_dot_color = "#d4e4f6" test_slide.save() response = client.get(reverse("shuup:index")) content = response.content.decode("utf-8") assert ".owl-dot:nth-child(1)" in content assert "border-color: #a1b2c3 !important" in content assert "background-color: #d4e4f6 !important;" in content
def visible(self): return not get_current_theme()
def test_product_from_category_plugin(rf): shop = get_default_shop() category1 = get_default_category() category2 = CategoryFactory(status=CategoryStatus.VISIBLE) category1.shops.add(shop) category2.shops.add(shop) p1 = create_product("p1", shop, get_default_supplier(), "10") p2 = create_product("p2", shop, get_default_supplier(), "20") p3 = create_product("p3", shop, get_default_supplier(), "30") sp1 = p1.get_shop_instance(shop) sp2 = p2.get_shop_instance(shop) sp3 = p3.get_shop_instance(shop) sp1.categories.add(category1) sp2.categories.add(category1) sp3.categories.add(category2) plugin = ProductsFromCategoryPlugin({ "category": category1.pk, "cache_timeout": 120 }) plugin_context = plugin.get_context_data(get_context(rf, is_ajax=False)) context_products = plugin_context["products"] assert len(context_products) == 0 plugin_context = plugin.get_context_data(get_context(rf)) context_data_url = plugin_context["data_url"] context_products = plugin_context["products"] assert p1 in context_products assert p2 in context_products assert p3 not in context_products check_expected_product_count(context_data_url, 2) check_expected_product_count(context_data_url, 2) # one for checking it is cached # test the plugin form with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, ProductsFromCategoryPlugin.identifier, sizes={"md": 8}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/"))) assert not lcfg.is_valid() lcfg = LayoutCellFormGroup( data={ "general-cell_width": "8", "general-cell_align": "pull-right", "plugin-count": 4, "plugin-category": category2.pk, "plugin-cache_timeout": 3600 }, layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/")) ) assert lcfg.is_valid() lcfg.save() assert cell.config["category"] == str(category2.pk)
def test_product_selection_plugin(rf): shop = factories.get_default_shop() category1 = factories.CategoryFactory(status=CategoryStatus.VISIBLE) category2 = factories.CategoryFactory(status=CategoryStatus.VISIBLE) p1 = factories.create_product("p1", shop, factories.get_default_supplier(), "10") p2 = factories.create_product("p2", shop, factories.get_default_supplier(), "20") p3 = factories.create_product("p3", shop, factories.get_default_supplier(), "30") p4 = factories.create_product("p4", shop, factories.get_default_supplier(), "40") p5 = factories.create_product("p5", shop, factories.get_default_supplier(), "50") sp1 = p1.get_shop_instance(shop) sp2 = p2.get_shop_instance(shop) sp3 = p3.get_shop_instance(shop) sp4 = p4.get_shop_instance(shop) sp1.categories.add(category1, category2) sp2.categories.add(category1) sp3.categories.add(category2) sp4.categories.add(category2) # this discount should show products: p1, p2 and p5 discount1 = Discount.objects.create( name="discount1", active=True, start_datetime=now() - timedelta(days=10), end_datetime=now() + timedelta(days=1), product=p5, category=category1 ) discount1.shops = [shop] # this discount should show products: p1, p3 and p4 discount2 = Discount.objects.create( name="discount2", active=True, start_datetime=now() - timedelta(days=10), end_datetime=now() + timedelta(days=1), category=category2 ) discount2.shops = [shop] # this discount shouldn't be available for this shop discount3 = Discount.objects.create( name="discount3", active=True, start_datetime=now() - timedelta(days=10), end_datetime=now() + timedelta(days=1), category=category2 ) context = get_context(rf) # test only discount1 plugin = DiscountedProductsPlugin({"discounts": [discount1.pk], "count": 10}) context_products = plugin.get_context_data(context)["products"] assert p1 in context_products assert p2 in context_products assert p3 not in context_products assert p4 not in context_products assert p5 in context_products for status in range(2): if status == 1: discount2.active = False discount2.save() # test only discount2 plugin = DiscountedProductsPlugin({"discounts": [discount2.pk], "count": 10}) context_products = plugin.get_context_data(context)["products"] if status == 1: assert context_products == [] else: assert p1 in context_products assert p2 not in context_products assert p3 in context_products assert p4 in context_products assert p5 not in context_products # test discount3 plugin = DiscountedProductsPlugin({"discounts": [discount3.pk], "count": 10}) assert plugin.get_context_data(context)["products"] == [] discount2.active = True discount2.save() # test both discount1 and discount2 plugin = DiscountedProductsPlugin({"discounts": [discount1.pk, discount2.pk], "count": 10}) context_products = plugin.get_context_data(context)["products"] assert p1 in context_products assert p2 in context_products assert p3 in context_products assert p4 in context_products assert p5 in context_products # test the plugin form with override_current_theme_class(None): theme = get_current_theme(shop) cell = LayoutCell(theme, DiscountedProductsPlugin.identifier, sizes={"md": 8}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/"))) # not valid, products are required assert not lcfg.is_valid() lcfg = LayoutCellFormGroup( data={ "general-cell_width": "8", "general-cell_align": "pull-right", "plugin-discounts": [discount1.pk, discount2.pk], "plugin-count": 6 }, layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/")) ) assert lcfg.is_valid() lcfg.save() assert cell.config["discounts"] == [discount1.pk, discount2.pk]
def test_theme_selection(): cache.clear() shop = factories.get_default_shop() theme = get_current_theme(shop) test_js_script = 'console.log("this is JS snippet");' js_snippet = Snippet.objects.create(shop=shop, location="body_end", snippet_type=SnippetType.InlineJS, snippet=test_js_script, themes=theme.identifier) test_css_style = 'h1 { font-size: 3px; }' css_snippet = Snippet.objects.create(shop=shop, location="head_end", snippet_type=SnippetType.InlineCSS, snippet=test_css_style, themes=theme.identifier) test_html_code = '<p class="test-snippet">Test HTML snippet</p>' html_snippet = Snippet.objects.create( shop=shop, location="body_end", snippet_type=SnippetType.InlineHTMLMarkup, snippet=test_html_code, themes=theme.identifier) test_jinja_code = '<p class="test-snippet">Test Jinja snippet %s</p>' jinja_snippet = Snippet.objects.create( shop=shop, location="body_end", snippet_type=SnippetType.InlineJinjaHTMLMarkup, snippet=test_jinja_code % ('{{ request.shop.public_name}}')) html_that_should_not_exist = "<h1>-Hello world</h1>" snippet_for_other_theme = Snippet.objects.create( shop=shop, location="body_end", snippet_type=SnippetType.InlineHTMLMarkup, snippet=html_that_should_not_exist, themes="random.theme") with override_provides("xtheme_resource_injection", ["shuup.xtheme.resources:inject_global_snippet"]): client = SmartClient() response, soup = client.response_and_soup("/") assert response.status_code == 200 assert html_that_should_not_exist not in str(soup) body = str(soup.find("body")) assert "<script>%s</script>" % test_js_script in body assert test_html_code in body assert (test_jinja_code % shop.public_name) in body head = str(soup.find("head")) assert '<style type="text/css">%s</style>' % test_css_style in head # Admin views are not allowed to inject into client = SmartClient() response, soup = client.response_and_soup("/sa/login/") assert response.status_code == 200 soup_str = str(soup) assert html_that_should_not_exist not in soup_str assert ('<style type="text/css">%s</style>' % test_css_style) not in soup_str
def test_product_selection_plugin(rf, reindex_catalog): shop = factories.get_default_shop() shop2 = factories.get_shop(identifier="shop2") category1 = factories.CategoryFactory(status=CategoryStatus.VISIBLE) category2 = factories.CategoryFactory(status=CategoryStatus.VISIBLE) p1 = factories.create_product("p1", shop, factories.get_default_supplier(), "10") p2 = factories.create_product("p2", shop, factories.get_default_supplier(), "20") p3 = factories.create_product("p3", shop, factories.get_default_supplier(), "30") p4 = factories.create_product("p4", shop, factories.get_default_supplier(), "40") p5 = factories.create_product("p5", shop, factories.get_default_supplier(), "50") sp1 = p1.get_shop_instance(shop) sp2 = p2.get_shop_instance(shop) sp3 = p3.get_shop_instance(shop) sp4 = p4.get_shop_instance(shop) sp1.categories.add(category1, category2) sp2.categories.add(category1) sp3.categories.add(category2) sp4.categories.add(category2) # this discount should show products: p1, p2 and p5 discount1 = Discount.objects.create( shop=shop, name="discount1", active=True, start_datetime=now() - timedelta(days=10), end_datetime=now() + timedelta(days=1), product=p5, category=category1, ) # this discount should show products: p1, p3 and p4 discount2 = Discount.objects.create( shop=shop, name="discount2", active=True, start_datetime=now() - timedelta(days=10), end_datetime=now() + timedelta(days=1), category=category2, ) # this discount shouldn't be available for this shop discount3 = Discount.objects.create( shop=shop2, name="discount3", active=True, start_datetime=now() - timedelta(days=10), end_datetime=now() + timedelta(days=1), category=category2, ) reindex_catalog() context = get_context(rf) # test only discount1 plugin = DiscountedProductsPlugin({ "discounts": [discount1.pk], "count": 10 }) context_products = plugin.get_context_data(context)["products"] assert p1 in context_products assert p2 in context_products assert p3 not in context_products assert p4 not in context_products assert p5 in context_products for status in range(2): if status == 1: discount2.active = False discount2.save() reindex_catalog() # test only discount2 plugin = DiscountedProductsPlugin({ "discounts": [discount2.pk], "count": 10 }) context_products = plugin.get_context_data(context)["products"] if status == 1: assert list(context_products) == [] else: assert p1 in context_products assert p2 not in context_products assert p3 in context_products assert p4 in context_products assert p5 not in context_products # test discount3 plugin = DiscountedProductsPlugin({ "discounts": [discount3.pk], "count": 10 }) assert list(plugin.get_context_data(context)["products"]) == [] discount2.active = True discount2.save() reindex_catalog() # test both discount1 and discount2 plugin = DiscountedProductsPlugin({ "discounts": [discount1.pk, discount2.pk], "count": 10 }) context_products = plugin.get_context_data(context)["products"] assert p1 in context_products assert p2 in context_products assert p3 in context_products assert p4 in context_products assert p5 in context_products # test the plugin form with override_current_theme_class(None): theme = get_current_theme(shop) cell = LayoutCell(theme, DiscountedProductsPlugin.identifier, sizes={"md": 8}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme, request=apply_request_middleware( rf.get("/"))) # not valid, products are required assert not lcfg.is_valid() lcfg = LayoutCellFormGroup( data={ "general-cell_width": "8", "general-cell_align": "pull-right", "plugin-discounts": [discount1.pk, discount2.pk], "plugin-count": 6, }, layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/")), ) assert lcfg.is_valid() lcfg.save() assert cell.config["discounts"] == [discount1.pk, discount2.pk]
def test_product_selection_plugin(rf, reindex_catalog): shop = get_default_shop() supplier = get_default_supplier() p1 = create_product("p1", shop, supplier, "10") p2 = create_product("p2", shop, supplier, "20") p3 = create_product("p3", shop, supplier, "30") p4 = create_product("p4", shop, supplier, "40") sp1 = p1.get_shop_instance(shop) sp2 = p2.get_shop_instance(shop) sp3 = p3.get_shop_instance(shop) reindex_catalog() plugin = ProductSelectionPlugin({ "products": [sp1.product.pk, sp2.product.pk, sp3.product.pk], "cache_timeout": 120 }) plugin_context = plugin.get_context_data(get_context(rf, is_ajax=False)) context_products = plugin_context["products"] assert len(context_products) == 0 plugin_context = plugin.get_context_data(get_context(rf)) context_data_url = plugin_context["data_url"] context_products = plugin_context["products"] assert p1 in context_products assert p2 in context_products assert p3 in context_products assert p4 not in context_products check_expected_product_count(context_data_url, 3) check_expected_product_count(context_data_url, 3) # one for checking it is cached # test the plugin form with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, ProductSelectionPlugin.identifier, sizes={"md": 8}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme, request=apply_request_middleware( rf.get("/"))) # not valid, products are required assert not lcfg.is_valid() lcfg = LayoutCellFormGroup( data={ "general-cell_width": "8", "general-cell_align": "pull-right", "plugin-products": [p1.pk, p2.pk], "plugin-cache_timeout": 120, }, layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/")), ) assert lcfg.is_valid() lcfg.save() assert cell.config["products"] == [str(p1.pk), str(p2.pk)]
def test_carousel_custom_colors(rf): from shuup.front.apps.carousel.plugins import CarouselPlugin from shuup.xtheme.models import SavedViewConfig, SavedViewConfigStatus from shuup.xtheme.layout import Layout from shuup.xtheme._theme import get_current_theme from django.core.urlresolvers import reverse shop = get_default_shop() shop.maintenance_mode = False shop.save() carousel = Carousel.objects.create(name="test") carousel.shops.add(shop) test_image = Image.objects.create(original_filename="slide.jpg") test_slide = Slide.objects.create( carousel=carousel, name="test", available_from=(datetime.now() - timedelta(days=1)), image=test_image, target=LinkTargetType.CURRENT ) theme = get_current_theme(shop) # adds the carousel to the front page layout = Layout(theme, "front_content") layout.begin_row() layout.begin_column({"md": 12}) layout.add_plugin(CarouselPlugin.identifier, {"carousel": carousel.pk}) svc = SavedViewConfig( theme_identifier=theme.identifier, shop=shop, view_name="IndexView", status=SavedViewConfigStatus.CURRENT_DRAFT ) svc.set_layout_data(layout.placeholder_name, layout) svc.save() svc.publish() client = Client() # no customized color response = client.get(reverse("shuup:index")) content = response.content.decode("utf-8") assert "owl-carousel" in content assert ".owl-nav .owl-prev" not in content assert ".owl-nav .owl-next" not in content assert ".owl-dot:nth-child(" not in content # put colors in arrows carousel.arrows_color = "#ffaabb" carousel.save() response = client.get(reverse("shuup:index")) content = response.content.decode("utf-8") assert ".owl-nav .owl-prev" in content assert ".owl-nav .owl-next" in content assert "color: #ffaabb !important;" in content # put custom color in dots test_slide.inactive_dot_color = "#a1b2c3" test_slide.active_dot_color = "#d4e4f6" test_slide.save() response = client.get(reverse("shuup:index")) content = response.content.decode("utf-8") assert ".owl-dot:nth-child(1)" in content assert "border-color: #a1b2c3 !important" in content assert "background-color: #d4e4f6 !important;" in content