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: E-Commerce.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.shop), shop=request.shop, view_name=view_name, draft=is_edit_mode(request), global_type=global_type, ) context.vars[config_key] = config return config
def inject_global_snippet(context, content): if not valid_view(context): return from E-Commerce.xtheme import get_current_theme from E-Commerce.xtheme.models import Snippet, SnippetType shop = get_shop(context["request"]) cache_key = GLOBAL_SNIPPETS_CACHE_KEY.format(shop_id=shop.id) snippets = cache.get(cache_key) if snippets is None: snippets = Snippet.objects.filter(shop=shop) cache.set(cache_key, snippets) for snippet in snippets: if snippet.themes: current_theme = get_current_theme(shop) if current_theme and current_theme.identifier not in snippet.themes: continue content = snippet.snippet if snippet.snippet_type == SnippetType.InlineJS: content = InlineScriptResource(content) elif snippet.snippet_type == SnippetType.InlineCSS: content = InlineStyleResource(content) elif snippet.snippet_type == SnippetType.InlineHTMLMarkup: content = InlineMarkupResource(content) add_resource(context, snippet.location, content)
def process_request(self, request): shop = getattr(request, "shop", Shop.objects.first()) theme = get_current_theme(shop) if theme: theme.set_current() else: log.error((_("Shop '{}' has no active theme")).format(shop))
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 test_xtheme_snippet_injection(browser, admin_user, live_server, settings): shop = factories.get_default_shop() initialize_admin_browser_test(browser, live_server, settings) url = reverse("E-Commerce_admin:xtheme_snippet.new") browser.visit("%s%s" % (live_server, url)) wait_until_condition(browser, lambda x: x.is_text_present("New Snippet")) browser.execute_script("$(\"[name='location']\").val('body_end').trigger('change')") browser.execute_script("$(\"[name='snippet_type']\").val('inline_js').trigger('change')") browser.execute_script("window.CodeMirror.editors['id_snippet-snippet'].setValue('alert(\"works\")');") click_element(browser, "button[type='submit']") wait_until_appeared(browser, "div[class='message success']") url = reverse("E-Commerce:index") browser.visit("%s%s" % (live_server, url)) def has_alert(browser): try: return browser.get_alert().text == "works" except: return False wait_until_condition(browser, has_alert) browser.get_alert().accept() theme = get_current_theme(shop) snippet = Snippet.objects.filter(shop=shop).first() snippet.themes = [theme.identifier] snippet.save() cache.clear() browser.visit("%s%s" % (live_server, url)) wait_until_condition(browser, has_alert) browser.get_alert().accept() snippet.themes = ["doesnt-exist"] snippet.save() cache.clear() browser.visit("%s%s" % (live_server, url)) wait_until_condition(browser, lambda x: x.is_text_present("Welcome to Default!")) with pytest.raises(Exception): browser.get_alert() # delete the snippet url = reverse("E-Commerce_admin:xtheme_snippet.edit", kwargs=dict(pk=snippet.pk)) browser.visit("%s%s" % (live_server, url)) assert Snippet.objects.filter(shop=shop).exists() click_element(browser, ".E-Commerce-toolbar button.btn.btn-danger") browser.get_alert().accept() wait_until_condition(browser, lambda x: not Snippet.objects.filter(shop=shop).exists())
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("E-Commerce_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( E-Commerce_SETUP_WIZARD_PANE_SPEC = [ "E-Commerce.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", ["E-Commerce_tests.xtheme.utils:FauxTheme"]): from E-Commerce_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="E-Commerce_admin:xtheme.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 'E-Commerce.xtheme' in settings.INSTALLED_APPS: from E-Commerce.front.apps.carousel.plugins import CarouselPlugin from E-Commerce.xtheme.plugins.products import ProductHighlightPlugin from E-Commerce.xtheme.models import SavedViewConfig, SavedViewConfigStatus from E-Commerce.xtheme.layout import Layout from E-Commerce.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.shop) 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.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_page_layout(): if "E-Commerce.xtheme" not in settings.INSTALLED_APPS: pytest.skip("Need E-Commerce.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("E-Commerce: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("E-Commerce: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_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 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 _get_basic_view_config(view_name="pow"): shop = factories.get_default_shop() theme = get_current_theme(shop) return ViewConfig(theme=theme, shop=shop, view_name=view_name, draft=True)