Init Django-SHOP
This commit is contained in:
2
weirdlittleempire/__init__.py
Normal file
2
weirdlittleempire/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
__version__ = '0.0.1'
|
||||
default_app_config = 'weirdlittleempire.apps.WeirdLittleEmpire'
|
||||
130
weirdlittleempire/admin.py
Normal file
130
weirdlittleempire/admin.py
Normal file
@@ -0,0 +1,130 @@
|
||||
from django.contrib import admin
|
||||
from django.template.context import Context
|
||||
from django.template.loader import get_template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from filer.models import ThumbnailOption
|
||||
from cms.admin.placeholderadmin import PlaceholderAdminMixin, FrontendEditableAdminMixin
|
||||
from shop.admin.defaults import customer
|
||||
from shop.admin.defaults.order import OrderAdmin
|
||||
from shop.models.defaults.order import Order
|
||||
from shop.admin.order import PrintInvoiceAdminMixin
|
||||
from shop.admin.delivery import DeliveryOrderAdminMixin
|
||||
from adminsortable2.admin import SortableAdminMixin, PolymorphicSortableAdminMixin
|
||||
from shop.admin.product import CMSPageAsCategoryMixin, UnitPriceMixin, ProductImageInline, InvalidateProductCacheMixin, SearchProductIndexMixin, CMSPageFilter
|
||||
from polymorphic.admin import (PolymorphicParentModelAdmin, PolymorphicChildModelAdmin,
|
||||
PolymorphicChildModelFilter)
|
||||
from weirdlittleempire.models import Product, Commodity, SmartPhoneVariant, SmartPhoneModel, OperatingSystem
|
||||
from weirdlittleempire.models import Manufacturer, SmartCard
|
||||
|
||||
|
||||
admin.site.site_header = "Weird Little Empire Administration"
|
||||
admin.site.unregister(ThumbnailOption)
|
||||
|
||||
|
||||
@admin.register(Order)
|
||||
class OrderAdmin(PrintInvoiceAdminMixin, DeliveryOrderAdminMixin, OrderAdmin):
|
||||
pass
|
||||
|
||||
|
||||
admin.site.register(Manufacturer, admin.ModelAdmin)
|
||||
|
||||
__all__ = ['customer']
|
||||
|
||||
|
||||
@admin.register(Commodity)
|
||||
class CommodityAdmin(InvalidateProductCacheMixin, SearchProductIndexMixin, SortableAdminMixin, FrontendEditableAdminMixin,
|
||||
PlaceholderAdminMixin, CMSPageAsCategoryMixin, PolymorphicChildModelAdmin):
|
||||
"""
|
||||
Since our Commodity model inherits from polymorphic Product, we have to redefine its admin class.
|
||||
"""
|
||||
base_model = Product
|
||||
fields = [
|
||||
('product_name', 'slug'),
|
||||
('product_code', 'unit_price'),
|
||||
'quantity',
|
||||
'active',
|
||||
'caption',
|
||||
'manufacturer',
|
||||
]
|
||||
filter_horizontal = ['cms_pages']
|
||||
inlines = [ProductImageInline]
|
||||
prepopulated_fields = {'slug': ['product_name']}
|
||||
|
||||
|
||||
@admin.register(SmartCard)
|
||||
class SmartCardAdmin(InvalidateProductCacheMixin, SearchProductIndexMixin, SortableAdminMixin, FrontendEditableAdminMixin,
|
||||
CMSPageAsCategoryMixin, PlaceholderAdminMixin, PolymorphicChildModelAdmin):
|
||||
base_model = Product
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': [
|
||||
('product_name', 'slug'),
|
||||
('product_code', 'unit_price'),
|
||||
'quantity',
|
||||
'active',
|
||||
'caption',
|
||||
'description',
|
||||
],
|
||||
}),
|
||||
(_("Properties"), {
|
||||
'fields': ['manufacturer', 'storage', 'card_type', 'speed'],
|
||||
}),
|
||||
)
|
||||
filter_horizontal = ['cms_pages']
|
||||
inlines = [ProductImageInline]
|
||||
prepopulated_fields = {'slug': ['product_name']}
|
||||
|
||||
|
||||
admin.site.register(OperatingSystem, admin.ModelAdmin)
|
||||
|
||||
|
||||
class SmartPhoneInline(admin.TabularInline):
|
||||
model = SmartPhoneVariant
|
||||
extra = 0
|
||||
|
||||
|
||||
@admin.register(SmartPhoneModel)
|
||||
class SmartPhoneAdmin(InvalidateProductCacheMixin, SearchProductIndexMixin, SortableAdminMixin, FrontendEditableAdminMixin,
|
||||
CMSPageAsCategoryMixin, PlaceholderAdminMixin, PolymorphicChildModelAdmin):
|
||||
base_model = Product
|
||||
fieldsets = [
|
||||
(None, {
|
||||
'fields': [
|
||||
('product_name', 'slug'),
|
||||
'active',
|
||||
'caption',
|
||||
'description',
|
||||
],
|
||||
}),
|
||||
(_("Properties"), {
|
||||
'fields': ['manufacturer', 'battery_type', 'battery_capacity', 'ram_storage',
|
||||
'wifi_connectivity', 'bluetooth', 'gps', 'operating_system',
|
||||
('width', 'height', 'weight',), 'screen_size'],
|
||||
}),
|
||||
]
|
||||
filter_horizontal = ['cms_pages']
|
||||
inlines = [ProductImageInline, SmartPhoneInline]
|
||||
prepopulated_fields = {'slug': ['product_name']}
|
||||
|
||||
def render_text_index(self, instance):
|
||||
template = get_template(
|
||||
'search/indexes/weirdlittleempire/commodity_text.txt')
|
||||
return template.render(Context({'object': instance}))
|
||||
render_text_index.short_description = _("Text Index")
|
||||
|
||||
|
||||
@admin.register(Product)
|
||||
class ProductAdmin(PolymorphicSortableAdminMixin, PolymorphicParentModelAdmin):
|
||||
base_model = Product
|
||||
child_models = [SmartPhoneModel, SmartCard, Commodity]
|
||||
list_display = ['product_name', 'get_price', 'product_type', 'active']
|
||||
list_display_links = ['product_name']
|
||||
search_fields = ['product_name']
|
||||
list_filter = [PolymorphicChildModelFilter, CMSPageFilter]
|
||||
list_per_page = 250
|
||||
list_max_show_all = 1000
|
||||
|
||||
def get_price(self, obj):
|
||||
return str(obj.get_real_instance().get_price(None))
|
||||
|
||||
get_price.short_description = _("Price starting at")
|
||||
24
weirdlittleempire/apps.py
Normal file
24
weirdlittleempire/apps.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
import logging
|
||||
from django.apps import AppConfig
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class WeirdLittleEmpire(AppConfig):
|
||||
name = 'weirdlittleempire'
|
||||
verbose_name = _("My Shop")
|
||||
logger = logging.getLogger('weirdlittleempire')
|
||||
|
||||
def ready(self):
|
||||
if not os.path.isdir(settings.STATIC_ROOT):
|
||||
os.makedirs(settings.STATIC_ROOT)
|
||||
if not os.path.isdir(settings.MEDIA_ROOT):
|
||||
os.makedirs(settings.MEDIA_ROOT)
|
||||
if hasattr(settings, 'COMPRESS_ROOT') and not os.path.isdir(settings.COMPRESS_ROOT):
|
||||
os.makedirs(settings.COMPRESS_ROOT)
|
||||
as_i18n = ""
|
||||
self.logger.info("Running as polymorphic{}".format(as_i18n))
|
||||
|
||||
from weirdlittleempire import search_indexes
|
||||
__all__ = ['search_indexes']
|
||||
60
weirdlittleempire/cms_apps.py
Normal file
60
weirdlittleempire/cms_apps.py
Normal file
@@ -0,0 +1,60 @@
|
||||
from shop.cms_apphooks import CatalogSearchApp
|
||||
from django.conf.urls import url
|
||||
from rest_framework.settings import api_settings
|
||||
|
||||
from cms.apphook_pool import apphook_pool
|
||||
from cms.cms_menus import SoftRootCutter
|
||||
from menus.menu_pool import menu_pool
|
||||
|
||||
from shop.cms_apphooks import CatalogListCMSApp, CatalogSearchApp, OrderApp, PasswordResetApp
|
||||
from shop.rest.filters import CMSPagesFilterBackend
|
||||
|
||||
|
||||
class CatalogListApp(CatalogListCMSApp):
|
||||
def get_urls(self, page=None, language=None, **kwargs):
|
||||
from shop.search.mixins import ProductSearchViewMixin
|
||||
from shop.views.catalog import AddToCartView, ProductListView, ProductRetrieveView
|
||||
from shop.views.catalog import AddFilterContextMixin
|
||||
from weirdlittleempire.filters import ManufacturerFilterSet
|
||||
from weirdlittleempire.serializers import AddSmartPhoneToCartSerializer
|
||||
|
||||
ProductListView = type(
|
||||
'ProductSearchListView', (AddFilterContextMixin, ProductSearchViewMixin, ProductListView), {})
|
||||
filter_backends = [CMSPagesFilterBackend]
|
||||
filter_backends.extend(api_settings.DEFAULT_FILTER_BACKENDS)
|
||||
return [
|
||||
url(r'^(?P<slug>[\w-]+)/add-to-cart', AddToCartView.as_view()),
|
||||
url(r'^(?P<slug>[\w-]+)/add-smartphone-to-cart', AddToCartView.as_view(
|
||||
serializer_class=AddSmartPhoneToCartSerializer,
|
||||
)),
|
||||
url(r'^(?P<slug>[\w-]+)', ProductRetrieveView.as_view(
|
||||
use_modal_dialog=False,
|
||||
)),
|
||||
url(r'^', ProductListView.as_view(
|
||||
filter_backends=filter_backends,
|
||||
filter_class=ManufacturerFilterSet,
|
||||
)),
|
||||
]
|
||||
|
||||
|
||||
apphook_pool.register(CatalogListApp)
|
||||
|
||||
|
||||
apphook_pool.register(CatalogSearchApp)
|
||||
|
||||
apphook_pool.register(OrderApp)
|
||||
|
||||
apphook_pool.register(PasswordResetApp)
|
||||
|
||||
|
||||
def _deregister_menu_pool_modifier(Modifier):
|
||||
index = None
|
||||
for k, modifier_class in enumerate(menu_pool.modifiers):
|
||||
if issubclass(modifier_class, Modifier):
|
||||
index = k
|
||||
if index is not None:
|
||||
# intentionally only modifying the list
|
||||
menu_pool.modifiers.pop(index)
|
||||
|
||||
|
||||
_deregister_menu_pool_modifier(SoftRootCutter)
|
||||
3
weirdlittleempire/cms_wizards.py
Normal file
3
weirdlittleempire/cms_wizards.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from cms.wizards.wizard_base import Wizard
|
||||
from cms.wizards.wizard_pool import wizard_pool
|
||||
39
weirdlittleempire/filters.py
Normal file
39
weirdlittleempire/filters.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from django.forms.widgets import Select
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django_filters import FilterSet
|
||||
|
||||
from djng.forms import NgModelFormMixin
|
||||
from djng.styling.bootstrap3.forms import Bootstrap3Form
|
||||
|
||||
from shop.filters import ModelChoiceFilter
|
||||
|
||||
from weirdlittleempire.models import Manufacturer, Product
|
||||
|
||||
|
||||
class FilterForm(NgModelFormMixin, Bootstrap3Form):
|
||||
scope_prefix = 'filters'
|
||||
|
||||
|
||||
class ManufacturerFilterSet(FilterSet):
|
||||
manufacturer = ModelChoiceFilter(
|
||||
queryset=Manufacturer.objects.all(),
|
||||
widget=Select(attrs={'ng-change': 'filterChanged()'}),
|
||||
empty_label=_("Any Manufacturer"),
|
||||
help_text=_("Restrict product on this manufacturer only"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Product
|
||||
form = FilterForm
|
||||
fields = ['manufacturer']
|
||||
|
||||
@classmethod
|
||||
def get_render_context(cls, request, queryset):
|
||||
# create filter set with bound form, to enable the selected option
|
||||
filter_set = cls(data=request.GET)
|
||||
|
||||
# we only want to show manufacturers for products available in the current list view
|
||||
filter_field = filter_set.filters['manufacturer'].field
|
||||
filter_field.queryset = filter_field.queryset.filter(
|
||||
id__in=queryset.values_list('manufacturer_id'))
|
||||
return dict(filter_set=filter_set)
|
||||
43
weirdlittleempire/finders.py
Normal file
43
weirdlittleempire/finders.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import os
|
||||
from django.conf import settings
|
||||
from django.contrib.staticfiles.finders import (FileSystemFinder as FileSystemFinderBase,
|
||||
AppDirectoriesFinder as AppDirectoriesFinderBase)
|
||||
|
||||
|
||||
class FileSystemFinder(FileSystemFinderBase):
|
||||
"""
|
||||
In debug mode, serve /static/any/asset.min.ext as /static/any/asset.ext
|
||||
"""
|
||||
locations = []
|
||||
serve_unminimized = getattr(settings, 'DEBUG', False)
|
||||
|
||||
def find_location(self, root, path, prefix=None):
|
||||
if self.serve_unminimized:
|
||||
# search for the unminimized version, and if it exists, return it
|
||||
base, ext = os.path.splitext(path)
|
||||
base, minext = os.path.splitext(base)
|
||||
if minext == '.min':
|
||||
unminimized_path = super().find_location(root, base + ext, prefix)
|
||||
if unminimized_path:
|
||||
return unminimized_path
|
||||
# otherwise proceed with the given one
|
||||
path = super().find_location(root, path, prefix)
|
||||
return path
|
||||
|
||||
|
||||
class AppDirectoriesFinder(AppDirectoriesFinderBase):
|
||||
serve_unminimized = getattr(settings, 'DEBUG', False)
|
||||
|
||||
def find_in_app(self, app, path):
|
||||
matched_path = super().find_in_app(app, path)
|
||||
if matched_path and self.serve_unminimized:
|
||||
base, ext = os.path.splitext(matched_path)
|
||||
base, minext = os.path.splitext(base)
|
||||
if minext == '.min':
|
||||
storage = self.storages.get(app, None)
|
||||
path = '{}{}'.format(base, ext)
|
||||
if storage.exists(path):
|
||||
path = storage.path(path)
|
||||
if path:
|
||||
return path
|
||||
return matched_path
|
||||
5
weirdlittleempire/forms.py
Normal file
5
weirdlittleempire/forms.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from shop.forms.checkout import CustomerForm as CustomerFormBase
|
||||
|
||||
|
||||
class CustomerForm(CustomerFormBase):
|
||||
field_order = ['salutation', 'first_name', 'last_name', 'email']
|
||||
0
weirdlittleempire/management/__init__.py
Normal file
0
weirdlittleempire/management/__init__.py
Normal file
0
weirdlittleempire/management/commands/__init__.py
Normal file
0
weirdlittleempire/management/commands/__init__.py
Normal file
37
weirdlittleempire/management/commands/assign_iconfonts.py
Normal file
37
weirdlittleempire/management/commands/assign_iconfonts.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from cmsplugin_cascade.icon.utils import zipfile, unzip_archive
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Iterates over all files in Filer and creates an IconFont for all eligibles."
|
||||
|
||||
def handle(self, verbosity, *args, **options):
|
||||
self.verbosity = verbosity
|
||||
self.assign_files_to_iconfonts()
|
||||
|
||||
def assign_files_to_iconfonts(self):
|
||||
from filer.models.filemodels import File
|
||||
from cmsplugin_cascade.models import IconFont
|
||||
|
||||
for file in File.objects.all():
|
||||
if file.label != 'Font Awesome':
|
||||
continue
|
||||
if self.verbosity >= 2:
|
||||
self.stdout.write(
|
||||
"Creating Icon Font from: {}".format(file.label))
|
||||
try:
|
||||
zip_ref = zipfile.ZipFile(file.file, 'r')
|
||||
except zipfile.BadZipFile as exc:
|
||||
self.stderr.write(
|
||||
"Unable to unpack {}: {}".format(file.label, exc))
|
||||
else:
|
||||
if not IconFont.objects.filter(zip_file=file).exists():
|
||||
font_folder, config_data = unzip_archive(
|
||||
file.label, zip_ref)
|
||||
IconFont.objects.create(
|
||||
identifier=config_data['name'],
|
||||
config_data=config_data,
|
||||
zip_file=file,
|
||||
font_folder=font_folder,
|
||||
)
|
||||
zip_ref.close()
|
||||
41
weirdlittleempire/management/commands/create_social_icons.py
Normal file
41
weirdlittleempire/management/commands/create_social_icons.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from cms.models.static_placeholder import StaticPlaceholder
|
||||
from django.core.management.base import BaseCommand
|
||||
from cmsplugin_cascade.models import CascadeClipboard
|
||||
from shop.management.utils import deserialize_to_placeholder
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Iterates over all files in Filer and creates an IconFont for all eligibles."
|
||||
|
||||
def handle(self, verbosity, *args, **options):
|
||||
self.verbosity = verbosity
|
||||
self.create_social_icons()
|
||||
|
||||
def create_social_icons(self):
|
||||
from cms.utils.i18n import get_public_languages
|
||||
|
||||
default_language = get_public_languages()[0]
|
||||
|
||||
try:
|
||||
clipboard = CascadeClipboard.objects.get(identifier='social-icons')
|
||||
except CascadeClipboard.DoesNotExist:
|
||||
self.stderr.write(
|
||||
"No Persisted Clipboard named 'social-icons' found.")
|
||||
else:
|
||||
static_placeholder = StaticPlaceholder.objects.create(
|
||||
code='Social Icons')
|
||||
deserialize_to_placeholder(
|
||||
static_placeholder.public, clipboard.data, default_language)
|
||||
deserialize_to_placeholder(
|
||||
static_placeholder.draft, clipboard.data, default_language)
|
||||
self.stdout.write("Added Social Icons to Static Placeholder")
|
||||
|
||||
def publish_in_all_languages(self, page):
|
||||
from cms.api import copy_plugins_to_language
|
||||
from cms.utils.i18n import get_public_languages
|
||||
|
||||
languages = get_public_languages()
|
||||
for language in languages[1:]:
|
||||
copy_plugins_to_language(page, languages[0], language)
|
||||
for language in languages:
|
||||
page.publish(language)
|
||||
64
weirdlittleempire/management/commands/download_workdir.py
Normal file
64
weirdlittleempire/management/commands/download_workdir.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import os
|
||||
import requests
|
||||
from io import BytesIO as StringIO
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
try:
|
||||
import czipfile as zipfile
|
||||
except ImportError:
|
||||
import zipfile
|
||||
from .spinner import Spinner
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
version = 18
|
||||
help = "Download workdir to run a demo of django-SHOP."
|
||||
download_url = 'https://downloads.django-shop.org/django-shop-workdir-{version}.zip'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--noinput',
|
||||
'--no-input',
|
||||
action='store_false',
|
||||
dest='interactive',
|
||||
default=True,
|
||||
help="Do NOT prompt the user for input of any kind.",
|
||||
)
|
||||
|
||||
def set_options(self, **options):
|
||||
self.interactive = options['interactive']
|
||||
|
||||
def handle(self, verbosity, *args, **options):
|
||||
self.set_options(**options)
|
||||
fixture1 = '{workdir}/fixtures/products-media.json'.format(
|
||||
workdir=settings.WORK_DIR)
|
||||
fixture2 = '{workdir}/fixtures/products-meta.json'.format(
|
||||
workdir=settings.WORK_DIR)
|
||||
if os.path.isfile(fixture1) or os.path.isfile(fixture2):
|
||||
if self.interactive:
|
||||
mesg = """
|
||||
This will overwrite your workdir for your django-SHOP demo.
|
||||
Are you sure you want to do this?
|
||||
|
||||
Type 'yes' to continue, or 'no' to cancel:
|
||||
"""
|
||||
if input(mesg) != 'yes':
|
||||
raise CommandError(
|
||||
"Downloading workdir has been cancelled.")
|
||||
else:
|
||||
self.stdout.write(self.style.WARNING(
|
||||
"Can not override downloaded data in input-less mode."))
|
||||
return
|
||||
|
||||
extract_to = os.path.join(settings.WORK_DIR, os.pardir)
|
||||
msg = "Downloading workdir and extracting to {}. Please wait"
|
||||
self.stdout.write(msg.format(extract_to), ending=' ')
|
||||
with Spinner():
|
||||
download_url = self.download_url.format(version=self.version)
|
||||
response = requests.get(download_url, stream=True)
|
||||
zip_ref = zipfile.ZipFile(StringIO(response.content))
|
||||
try:
|
||||
zip_ref.extractall(extract_to)
|
||||
finally:
|
||||
zip_ref.close()
|
||||
self.stdout.write('- done.')
|
||||
35
weirdlittleempire/management/commands/export_products.py
Normal file
35
weirdlittleempire/management/commands/export_products.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import json
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.translation import activate
|
||||
from weirdlittleempire.models import Product
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'-o',
|
||||
'--output',
|
||||
type=str,
|
||||
dest='filename',
|
||||
)
|
||||
|
||||
def handle(self, verbosity, filename, *args, **options):
|
||||
activate(settings.LANGUAGE_CODE)
|
||||
data = []
|
||||
for product in Product.objects.all():
|
||||
ProductModel = ContentType.objects.get(
|
||||
app_label='weirdlittleempire', model=product.product_model)
|
||||
class_name = 'weirdlittleempire.management.serializers.' + \
|
||||
ProductModel.model_class().__name__ + 'Serializer'
|
||||
serializer_class = import_string(class_name)
|
||||
serializer = serializer_class(product, context={'request': None})
|
||||
data.append(serializer.data)
|
||||
dump = json.dumps(data, indent=2)
|
||||
if filename:
|
||||
with open(filename, 'w') as fh:
|
||||
fh.write(dump)
|
||||
else:
|
||||
self.stdout.write(dump)
|
||||
84
weirdlittleempire/management/commands/import_products.py
Normal file
84
weirdlittleempire/management/commands/import_products.py
Normal file
@@ -0,0 +1,84 @@
|
||||
import json
|
||||
import os
|
||||
from cms.utils.copy_plugins import copy_plugins_to
|
||||
from cms.utils.i18n import get_public_languages
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.translation import activate
|
||||
from cmsplugin_cascade.models import CascadeClipboard
|
||||
from shop.management.utils import deserialize_to_placeholder
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'filename',
|
||||
nargs='?',
|
||||
default='products-meta.json',
|
||||
)
|
||||
|
||||
def handle(self, verbosity, filename, *args, **options):
|
||||
activate(settings.LANGUAGE_CODE)
|
||||
path = self.find_fixture(filename)
|
||||
if verbosity >= 2:
|
||||
self.stdout.write("Importing products from: {}".format(path))
|
||||
with open(path, 'r') as fh:
|
||||
data = json.load(fh)
|
||||
|
||||
for number, product in enumerate(data, 1):
|
||||
product_model = product.pop('product_model')
|
||||
if product.get('product_code') == "parklake-springfield":
|
||||
continue
|
||||
ProductModel = ContentType.objects.get(
|
||||
app_label='weirdlittleempire', model=product_model)
|
||||
class_name = 'weirdlittleempire.management.serializers.' + \
|
||||
ProductModel.model_class().__name__ + 'Serializer'
|
||||
serializer_class = import_string(class_name)
|
||||
serializer = serializer_class(data=product)
|
||||
assert serializer.is_valid(), serializer.errors
|
||||
instance = serializer.save()
|
||||
self.assign_product_to_catalog(instance)
|
||||
self.stdout.write("{}. {}".format(number, instance))
|
||||
if product_model == 'commodity':
|
||||
languages = get_public_languages()
|
||||
try:
|
||||
clipboard = CascadeClipboard.objects.get(
|
||||
identifier=instance.slug)
|
||||
except CascadeClipboard.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
deserialize_to_placeholder(
|
||||
instance.placeholder, clipboard.data, languages[0])
|
||||
plugins = list(instance.placeholder.get_plugins(
|
||||
language=languages[0]).order_by('path'))
|
||||
for language in languages[1:]:
|
||||
copy_plugins_to(
|
||||
plugins, instance.placeholder, language)
|
||||
|
||||
def find_fixture(self, filename):
|
||||
if os.path.isabs(filename):
|
||||
fixture_dirs = [os.path.dirname(filename)]
|
||||
fixture_name = os.path.basename(filename)
|
||||
else:
|
||||
fixture_dirs = settings.FIXTURE_DIRS
|
||||
if os.path.sep in os.path.normpath(filename):
|
||||
fixture_dirs = [os.path.join(dir_, os.path.dirname(filename))
|
||||
for dir_ in fixture_dirs]
|
||||
fixture_name = os.path.basename(filename)
|
||||
else:
|
||||
fixture_name = filename
|
||||
for fixture_dir in fixture_dirs:
|
||||
path = os.path.join(fixture_dir, fixture_name)
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
raise CommandError(
|
||||
"No such file in any fixture dir: {}".format(filename))
|
||||
|
||||
def assign_product_to_catalog(self, product):
|
||||
from cms.models.pagemodel import Page
|
||||
from shop.models.related import ProductPageModel
|
||||
|
||||
for page in Page.objects.published().filter(application_urls='CatalogListApp'):
|
||||
ProductPageModel.objects.get_or_create(page=page, product=product)
|
||||
@@ -0,0 +1,26 @@
|
||||
import random
|
||||
from django.core.management.base import BaseCommand
|
||||
from weirdlittleempire.models import Commodity, CommodityInventory, SmartCard, SmartCardInventory, SmartPhoneVariant, SmartPhoneInventory
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Create Inventories for all products using random values."
|
||||
|
||||
def handle(self, verbosity, *args, **options):
|
||||
self.verbosity = verbosity
|
||||
for commodity in Commodity.objects.all():
|
||||
CommodityInventory.objects.create(
|
||||
product=commodity,
|
||||
quantity=random.randint(0, 15)
|
||||
)
|
||||
for smart_card in SmartCard.objects.all():
|
||||
SmartCardInventory.objects.create(
|
||||
product=smart_card,
|
||||
quantity=random.randint(0, 55)
|
||||
)
|
||||
for smart_phone in SmartPhoneVariant.objects.all():
|
||||
SmartPhoneInventory.objects.create(
|
||||
product=smart_phone,
|
||||
quantity=random.randint(0, 8)
|
||||
)
|
||||
self.stdout.write("Created inventories with random quantities.")
|
||||
104
weirdlittleempire/management/commands/initialize_shop_demo.py
Normal file
104
weirdlittleempire/management/commands/initialize_shop_demo.py
Normal file
@@ -0,0 +1,104 @@
|
||||
import os
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management import call_command
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
try:
|
||||
import czipfile as zipfile
|
||||
except ImportError:
|
||||
import zipfile
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = _("Initialize the workdir to run the demo of weirdlittleempire.")
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--noinput', '--no-input',
|
||||
action='store_false',
|
||||
dest='interactive',
|
||||
default=True,
|
||||
help="Do NOT prompt the user for input of any kind.",
|
||||
)
|
||||
|
||||
def set_options(self, **options):
|
||||
self.interactive = options['interactive']
|
||||
|
||||
def clear_compressor_cache(self):
|
||||
from django.core.cache import caches
|
||||
from django.core.cache.backends.base import InvalidCacheBackendError
|
||||
from compressor.conf import settings
|
||||
|
||||
cache_dir = os.path.join(settings.STATIC_ROOT,
|
||||
settings.COMPRESS_OUTPUT_DIR)
|
||||
if settings.COMPRESS_ENABLED is False or not os.path.isdir(cache_dir) or os.listdir(cache_dir) != []:
|
||||
return
|
||||
try:
|
||||
caches['compressor'].clear()
|
||||
except InvalidCacheBackendError:
|
||||
pass
|
||||
|
||||
def handle(self, verbosity, *args, **options):
|
||||
self.set_options(**options)
|
||||
self.clear_compressor_cache()
|
||||
call_command('migrate')
|
||||
initialize_file = os.path.join(settings.WORK_DIR, '.initialize')
|
||||
if os.path.isfile(initialize_file):
|
||||
self.stdout.write("Initializing project weirdlittleempire")
|
||||
call_command('makemigrations', 'weirdlittleempire')
|
||||
call_command('migrate')
|
||||
os.remove(initialize_file)
|
||||
call_command('loaddata', 'skeleton')
|
||||
call_command('shop', 'check-pages', add_recommended=True)
|
||||
call_command('assign_iconfonts')
|
||||
call_command('create_social_icons')
|
||||
call_command('download_workdir', interactive=self.interactive)
|
||||
call_command('loaddata', 'products-media')
|
||||
call_command('import_products')
|
||||
self.create_polymorphic_subcategories()
|
||||
try:
|
||||
call_command('search_index', action='rebuild', force=True)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
self.stdout.write("Project weirdlittleempire already initialized")
|
||||
call_command('migrate')
|
||||
|
||||
def create_polymorphic_subcategories(self):
|
||||
from cms.models.pagemodel import Page
|
||||
from shop.management.commands.shop import Command as ShopCommand
|
||||
from weirdlittleempire.models import Commodity, SmartCard, SmartPhoneModel
|
||||
|
||||
apphook = ShopCommand.get_installed_apphook('CatalogListCMSApp')
|
||||
catalog_pages = Page.objects.drafts().filter(
|
||||
application_urls=apphook.__class__.__name__)
|
||||
assert catalog_pages.count() == 1, "There should be only one catalog page"
|
||||
self.create_subcategory(
|
||||
apphook, catalog_pages.first(), "Earphones", Commodity)
|
||||
self.create_subcategory(
|
||||
apphook, catalog_pages.first(), "Smart Cards", SmartCard)
|
||||
self.create_subcategory(
|
||||
apphook, catalog_pages.first(), "Smart Phones", SmartPhoneModel)
|
||||
|
||||
def create_subcategory(self, apphook, parent_page, title, product_type):
|
||||
from cms.api import create_page
|
||||
from cms.constants import TEMPLATE_INHERITANCE_MAGIC
|
||||
from cms.utils.i18n import get_public_languages
|
||||
from shop.management.commands.shop import Command as ShopCommand
|
||||
from shop.models.product import ProductModel
|
||||
from shop.models.related import ProductPageModel
|
||||
|
||||
language = get_public_languages()[0]
|
||||
page = create_page(
|
||||
title,
|
||||
TEMPLATE_INHERITANCE_MAGIC,
|
||||
language,
|
||||
apphook=apphook,
|
||||
created_by="manage.py initialize_shop_demo",
|
||||
in_navigation=True,
|
||||
parent=parent_page,
|
||||
)
|
||||
ShopCommand.publish_in_all_languages(page)
|
||||
page = page.get_public_object()
|
||||
for product in ProductModel.objects.instance_of(product_type):
|
||||
ProductPageModel.objects.create(page=page, product=product)
|
||||
37
weirdlittleempire/management/commands/spinner.py
Normal file
37
weirdlittleempire/management/commands/spinner.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import sys
|
||||
import time
|
||||
import threading
|
||||
|
||||
|
||||
class Spinner:
|
||||
busy = False
|
||||
delay = 0.1
|
||||
|
||||
@staticmethod
|
||||
def spinning_cursor():
|
||||
while 1:
|
||||
for cursor in '|/-\\':
|
||||
yield cursor
|
||||
|
||||
def __init__(self, delay=None):
|
||||
self.spinner_generator = self.spinning_cursor()
|
||||
if delay and float(delay):
|
||||
self.delay = delay
|
||||
|
||||
def spinner_task(self):
|
||||
while self.busy:
|
||||
sys.stdout.write(next(self.spinner_generator))
|
||||
sys.stdout.flush()
|
||||
time.sleep(self.delay)
|
||||
sys.stdout.write('\b')
|
||||
sys.stdout.flush()
|
||||
|
||||
def __enter__(self):
|
||||
self.busy = True
|
||||
threading.Thread(target=self.spinner_task).start()
|
||||
|
||||
def __exit__(self, exception, value, tb):
|
||||
self.busy = False
|
||||
time.sleep(self.delay)
|
||||
if exception is not None:
|
||||
return False
|
||||
68
weirdlittleempire/management/serializers.py
Normal file
68
weirdlittleempire/management/serializers.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""
|
||||
These serializers are used exclusively to import the file ``workdir/fixtures/products-meta.json``.
|
||||
They are not intended for general purpose and can be deleted thereafter.
|
||||
"""
|
||||
from rest_framework import serializers
|
||||
from shop.serializers.catalog import CMSPagesField, ImagesField, ValueRelatedField
|
||||
from weirdlittleempire.models import (Commodity, SmartCard, SmartPhoneModel, SmartPhoneVariant,
|
||||
Manufacturer, OperatingSystem, ProductPage, ProductImage)
|
||||
from .translation import TranslatedFieldsField, TranslatedField, TranslatableModelSerializerMixin
|
||||
|
||||
|
||||
class ProductSerializer(serializers.ModelSerializer):
|
||||
product_model = serializers.CharField(read_only=True)
|
||||
manufacturer = ValueRelatedField(model=Manufacturer)
|
||||
images = ImagesField()
|
||||
caption = TranslatedField()
|
||||
cms_pages = CMSPagesField()
|
||||
|
||||
class Meta:
|
||||
exclude = ['id', 'polymorphic_ctype', 'updated_at']
|
||||
|
||||
def create(self, validated_data):
|
||||
cms_pages = validated_data.pop('cms_pages')
|
||||
images = validated_data.pop('images')
|
||||
product = super().create(validated_data)
|
||||
for page in cms_pages:
|
||||
ProductPage.objects.create(product=product, page=page)
|
||||
for image in images:
|
||||
ProductImage.objects.create(product=product, image=image)
|
||||
return product
|
||||
|
||||
|
||||
class CommoditySerializer(TranslatableModelSerializerMixin, ProductSerializer):
|
||||
|
||||
class Meta(ProductSerializer.Meta):
|
||||
model = Commodity
|
||||
exclude = ['id', 'placeholder', 'polymorphic_ctype', 'updated_at']
|
||||
|
||||
|
||||
class SmartCardSerializer(TranslatableModelSerializerMixin, ProductSerializer):
|
||||
multilingual = TranslatedFieldsField(
|
||||
help_text="Helper to convert multilingual data into single field.",
|
||||
)
|
||||
|
||||
class Meta(ProductSerializer.Meta):
|
||||
model = SmartCard
|
||||
|
||||
|
||||
class SmartphoneVariantSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SmartPhoneVariant
|
||||
fields = ['product_code', 'unit_price', 'storage', 'quantity']
|
||||
|
||||
|
||||
class SmartPhoneModelSerializer(TranslatableModelSerializerMixin, ProductSerializer):
|
||||
multilingual = TranslatedFieldsField()
|
||||
operating_system = ValueRelatedField(model=OperatingSystem)
|
||||
variants = SmartphoneVariantSerializer(many=True)
|
||||
|
||||
class Meta(ProductSerializer.Meta):
|
||||
model = SmartPhoneModel
|
||||
|
||||
def create(self, validated_data):
|
||||
variants = validated_data.pop('variants')
|
||||
product = super().create(validated_data)
|
||||
for variant in variants:
|
||||
SmartPhoneVariant.objects.create(product=product, **variant)
|
||||
return product
|
||||
73
weirdlittleempire/management/translation.py
Normal file
73
weirdlittleempire/management/translation.py
Normal file
@@ -0,0 +1,73 @@
|
||||
"""
|
||||
These serializer mixinins and fields are used exclusively to import the file
|
||||
``workdir/fixtures/products-meta.json``. They are not intended for general
|
||||
purpose and can be deleted thereafter.
|
||||
"""
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class TranslatableModelSerializerMixin:
|
||||
"""
|
||||
Pseudo class mimicking the behaviour of :class:`parler_rest.TranslatableModelSerializerMixin`.
|
||||
It converts the content for fields of type TranslatedFieldsField to simple serializer
|
||||
fields.
|
||||
"""
|
||||
|
||||
def to_internal_value(self, data):
|
||||
data = self._unify_translated_data(data)
|
||||
result = super().to_internal_value(data)
|
||||
return result
|
||||
|
||||
def _unify_translated_data(self, data):
|
||||
"""
|
||||
Unify translated data to be used by simple serializer fields.
|
||||
"""
|
||||
for field_name, field in self.get_fields().items():
|
||||
if isinstance(field, TranslatedFieldsField):
|
||||
key = field.source or field_name
|
||||
translations = data.pop(key, None)
|
||||
if isinstance(translations, dict):
|
||||
data.update(translations.get('en', {}))
|
||||
return data
|
||||
|
||||
|
||||
class TranslatedFieldsField(serializers.Field):
|
||||
"""
|
||||
Pseudo class mimicking the behaviour of :class:`parler_rest.TranslatedFieldsField`, where only
|
||||
the English translation is used.
|
||||
"""
|
||||
|
||||
def to_representation(self, value):
|
||||
raise NotImplementedError(
|
||||
"If USE_I18N is False, do not use {cls}.to_representation() for field '{field_name}'. "
|
||||
"It thwarts the possibility to reuse that string in a multi language environment.".format(
|
||||
cls=self.__class__.__name__,
|
||||
field_name=self.field_name,
|
||||
)
|
||||
)
|
||||
|
||||
def validate_empty_values(self, data):
|
||||
raise serializers.SkipField()
|
||||
|
||||
|
||||
class TranslatedField(serializers.Field):
|
||||
"""
|
||||
Pseudo class mimicking the behaviour of :class:`parler_rest.TranslatedField`, where only
|
||||
the English translation is used.
|
||||
"""
|
||||
|
||||
def to_representation(self, value):
|
||||
raise NotImplementedError(
|
||||
"If USE_I18N is False, do not use {cls}.to_representation() for field '{field_name}'. "
|
||||
"It thwarts the possibility to reuse that string in a multi language environment.".format(
|
||||
cls=self.__class__.__name__,
|
||||
field_name=self.field_name,
|
||||
)
|
||||
)
|
||||
|
||||
def to_internal_value(self, data):
|
||||
return data.get('en')
|
||||
|
||||
|
||||
__all__ = ['TranslatedFieldsField', 'TranslatedField',
|
||||
'TranslatableModelSerializerMixin']
|
||||
0
weirdlittleempire/migrations/__init__.py
Normal file
0
weirdlittleempire/migrations/__init__.py
Normal file
405
weirdlittleempire/models.py
Normal file
405
weirdlittleempire/models.py
Normal file
@@ -0,0 +1,405 @@
|
||||
|
||||
from decimal import Decimal
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.validators import MinValueValidator
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from djangocms_text_ckeditor.fields import HTMLField
|
||||
from cms.models.fields import PlaceholderField
|
||||
from shop.money import Money, MoneyMaker
|
||||
from shop.money.fields import MoneyField
|
||||
from shop.models.product import BaseProduct, BaseProductManager, AvailableProductMixin, CMSPageReferenceMixin
|
||||
from shop.models.defaults.cart import Cart
|
||||
from shop.models.defaults.cart_item import CartItem
|
||||
from shop.models.order import BaseOrderItem
|
||||
from shop.models.defaults.delivery import Delivery
|
||||
from shop.models.defaults.delivery_item import DeliveryItem
|
||||
from shop.models.defaults.order import Order
|
||||
from shop.models.defaults.mapping import ProductPage, ProductImage
|
||||
from shop.models.defaults.address import BillingAddress, ShippingAddress
|
||||
from shop.models.defaults.customer import Customer
|
||||
|
||||
|
||||
__all__ = ['Cart', 'CartItem', 'Order', 'Delivery', 'DeliveryItem',
|
||||
'BillingAddress', 'ShippingAddress', 'Customer', ]
|
||||
|
||||
|
||||
class OrderItem(BaseOrderItem):
|
||||
quantity = models.PositiveIntegerField(_("Ordered quantity"))
|
||||
canceled = models.BooleanField(_("Item canceled "), default=False)
|
||||
|
||||
def populate_from_cart_item(self, cart_item, request):
|
||||
super().populate_from_cart_item(cart_item, request)
|
||||
# the product's unit_price must be fetched from the product's variant
|
||||
try:
|
||||
variant = cart_item.product.get_product_variant(
|
||||
product_code=cart_item.product_code)
|
||||
self._unit_price = Decimal(variant.unit_price)
|
||||
except (KeyError, ObjectDoesNotExist) as e:
|
||||
raise CartItem.DoesNotExist(e)
|
||||
|
||||
|
||||
class Manufacturer(models.Model):
|
||||
name = models.CharField(
|
||||
_("Name"),
|
||||
max_length=50,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class ProductManager(BaseProductManager):
|
||||
pass
|
||||
|
||||
|
||||
class Product(CMSPageReferenceMixin, BaseProduct):
|
||||
"""
|
||||
Base class to describe a polymorphic product. Here we declare common fields available in all of
|
||||
our different product types. These common fields are also used to build up the view displaying
|
||||
a list of all products.
|
||||
"""
|
||||
product_name = models.CharField(
|
||||
_("Product Name"),
|
||||
max_length=255,
|
||||
)
|
||||
|
||||
slug = models.SlugField(
|
||||
_("Slug"),
|
||||
unique=True,
|
||||
)
|
||||
|
||||
caption = HTMLField(
|
||||
verbose_name=_("Caption"),
|
||||
blank=True,
|
||||
null=True,
|
||||
configuration='CKEDITOR_SETTINGS_CAPTION',
|
||||
help_text=_(
|
||||
"Short description used in the catalog's list view of products."),
|
||||
)
|
||||
|
||||
# common product properties
|
||||
manufacturer = models.ForeignKey(
|
||||
Manufacturer,
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name=_("Manufacturer"),
|
||||
)
|
||||
|
||||
# controlling the catalog
|
||||
order = models.PositiveIntegerField(
|
||||
_("Sort by"),
|
||||
db_index=True,
|
||||
)
|
||||
|
||||
cms_pages = models.ManyToManyField(
|
||||
'cms.Page',
|
||||
through=ProductPage,
|
||||
help_text=_("Choose list view this product shall appear on."),
|
||||
)
|
||||
|
||||
images = models.ManyToManyField(
|
||||
'filer.Image',
|
||||
through=ProductImage,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ('order',)
|
||||
verbose_name = _("Product")
|
||||
verbose_name_plural = _("Products")
|
||||
|
||||
objects = ProductManager()
|
||||
|
||||
# filter expression used to lookup for a product item using the Select2 widget
|
||||
lookup_fields = ['product_name__icontains']
|
||||
|
||||
def __str__(self):
|
||||
return self.product_name
|
||||
|
||||
@property
|
||||
def sample_image(self):
|
||||
return self.images.first()
|
||||
|
||||
|
||||
class Commodity(AvailableProductMixin, Product):
|
||||
"""
|
||||
This Commodity model inherits from polymorphic Product, and therefore has to be redefined.
|
||||
"""
|
||||
unit_price = MoneyField(
|
||||
_("Unit price"),
|
||||
decimal_places=3,
|
||||
help_text=_("Net price for this product"),
|
||||
)
|
||||
|
||||
product_code = models.CharField(
|
||||
_("Product code"),
|
||||
max_length=255,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
quantity = models.PositiveIntegerField(
|
||||
_("Quantity"),
|
||||
default=0,
|
||||
validators=[MinValueValidator(0)],
|
||||
help_text=_("Available quantity in stock")
|
||||
)
|
||||
|
||||
# controlling the catalog
|
||||
placeholder = PlaceholderField("Commodity Details")
|
||||
show_breadcrumb = True # hard coded to always show the product's breadcrumb
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Commodity")
|
||||
verbose_name_plural = _("Commodities")
|
||||
|
||||
default_manager = ProductManager()
|
||||
|
||||
def get_price(self, request):
|
||||
return self.unit_price
|
||||
|
||||
|
||||
class SmartCard(AvailableProductMixin, Product):
|
||||
unit_price = MoneyField(
|
||||
_("Unit price"),
|
||||
decimal_places=3,
|
||||
help_text=_("Net price for this product"),
|
||||
)
|
||||
|
||||
card_type = models.CharField(
|
||||
_("Card Type"),
|
||||
choices=[2 * ('{}{}'.format(s, t),)
|
||||
for t in ['SD', 'SDXC', 'SDHC', 'SDHC II'] for s in ['', 'micro ']],
|
||||
max_length=15,
|
||||
)
|
||||
|
||||
speed = models.CharField(
|
||||
_("Transfer Speed"),
|
||||
choices=[(str(s), "{} MB/s".format(s))
|
||||
for s in [4, 20, 30, 40, 48, 80, 95, 280]],
|
||||
max_length=8,
|
||||
)
|
||||
|
||||
product_code = models.CharField(
|
||||
_("Product code"),
|
||||
max_length=255,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
storage = models.PositiveIntegerField(
|
||||
_("Storage Capacity"),
|
||||
help_text=_("Storage capacity in GB"),
|
||||
)
|
||||
|
||||
description = HTMLField(
|
||||
_("Description"),
|
||||
configuration='CKEDITOR_SETTINGS_DESCRIPTION',
|
||||
help_text=_("Long description for the detail view of this product."),
|
||||
)
|
||||
|
||||
quantity = models.PositiveIntegerField(
|
||||
_("Quantity"),
|
||||
default=0,
|
||||
validators=[MinValueValidator(0)],
|
||||
help_text=_("Available quantity in stock")
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Smart Card")
|
||||
verbose_name_plural = _("Smart Cards")
|
||||
ordering = ['order']
|
||||
|
||||
# filter expression used to lookup for a product item using the Select2 widget
|
||||
lookup_fields = ['product_code__startswith', 'product_name__icontains']
|
||||
|
||||
def get_price(self, request):
|
||||
return self.unit_price
|
||||
|
||||
default_manager = ProductManager()
|
||||
|
||||
|
||||
class OperatingSystem(models.Model):
|
||||
name = models.CharField(
|
||||
_("Name"),
|
||||
max_length=50,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class SmartPhoneModel(Product):
|
||||
"""
|
||||
A generic smart phone model, which must be concretized by a `SmartPhoneVariant` - see below.
|
||||
"""
|
||||
BATTERY_TYPES = [
|
||||
(1, "Lithium Polymer (Li-Poly)"),
|
||||
(2, "Lithium Ion (Li-Ion)"),
|
||||
]
|
||||
WIFI_CONNECTIVITY = [
|
||||
(1, "802.11 b/g/n"),
|
||||
]
|
||||
BLUETOOTH_CONNECTIVITY = [
|
||||
(1, "Bluetooth 4.0"),
|
||||
(2, "Bluetooth 3.0"),
|
||||
(3, "Bluetooth 2.1"),
|
||||
]
|
||||
battery_type = models.PositiveSmallIntegerField(
|
||||
_("Battery type"),
|
||||
choices=BATTERY_TYPES,
|
||||
)
|
||||
|
||||
battery_capacity = models.PositiveIntegerField(
|
||||
_("Capacity"),
|
||||
help_text=_("Battery capacity in mAh"),
|
||||
)
|
||||
|
||||
ram_storage = models.PositiveIntegerField(
|
||||
_("RAM"),
|
||||
help_text=_("RAM storage in MB"),
|
||||
)
|
||||
|
||||
wifi_connectivity = models.PositiveIntegerField(
|
||||
_("WiFi"),
|
||||
choices=WIFI_CONNECTIVITY,
|
||||
help_text=_("WiFi Connectivity"),
|
||||
)
|
||||
|
||||
bluetooth = models.PositiveIntegerField(
|
||||
_("Bluetooth"),
|
||||
choices=BLUETOOTH_CONNECTIVITY,
|
||||
help_text=_("Bluetooth Connectivity"),
|
||||
)
|
||||
|
||||
gps = models.BooleanField(
|
||||
_("GPS"),
|
||||
default=False,
|
||||
help_text=_("GPS integrated"),
|
||||
)
|
||||
|
||||
operating_system = models.ForeignKey(
|
||||
OperatingSystem,
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name=_("Operating System"),
|
||||
)
|
||||
|
||||
width = models.DecimalField(
|
||||
_("Width"),
|
||||
max_digits=4,
|
||||
decimal_places=1,
|
||||
help_text=_("Width in mm"),
|
||||
)
|
||||
|
||||
height = models.DecimalField(
|
||||
_("Height"),
|
||||
max_digits=4,
|
||||
decimal_places=1,
|
||||
help_text=_("Height in mm"),
|
||||
)
|
||||
|
||||
weight = models.DecimalField(
|
||||
_("Weight"),
|
||||
max_digits=5,
|
||||
decimal_places=1,
|
||||
help_text=_("Weight in gram"),
|
||||
)
|
||||
|
||||
screen_size = models.DecimalField(
|
||||
_("Screen size"),
|
||||
max_digits=4,
|
||||
decimal_places=2,
|
||||
help_text=_("Diagonal screen size in inch"),
|
||||
)
|
||||
|
||||
description = HTMLField(
|
||||
verbose_name=_("Description"),
|
||||
configuration='CKEDITOR_SETTINGS_DESCRIPTION',
|
||||
help_text=_(
|
||||
"Full description used in the catalog's detail view of Smart Phones."),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Smart Phone")
|
||||
verbose_name_plural = _("Smart Phones")
|
||||
|
||||
default_manager = ProductManager()
|
||||
|
||||
def get_price(self, request):
|
||||
"""
|
||||
Return the starting price for instances of this smart phone model.
|
||||
"""
|
||||
if not hasattr(self, '_price'):
|
||||
if self.variants.exists():
|
||||
currency = self.variants.first().unit_price.currency
|
||||
aggr = self.variants.aggregate(models.Min('unit_price'))
|
||||
self._price = MoneyMaker(currency)(aggr['unit_price__min'])
|
||||
else:
|
||||
self._price = Money()
|
||||
return self._price
|
||||
|
||||
def get_availability(self, request, **kwargs):
|
||||
variant = self.get_product_variant(**kwargs)
|
||||
return variant.get_availability(request)
|
||||
|
||||
def deduct_from_stock(self, quantity, **kwargs):
|
||||
variant = self.get_product_variant(**kwargs)
|
||||
variant.deduct_from_stock(quantity)
|
||||
|
||||
def is_in_cart(self, cart, watched=False, **kwargs):
|
||||
try:
|
||||
product_code = kwargs['product_code']
|
||||
except KeyError:
|
||||
return
|
||||
cart_item_qs = CartItem.objects.filter(cart=cart, product=self)
|
||||
for cart_item in cart_item_qs:
|
||||
if cart_item.product_code == product_code:
|
||||
return cart_item
|
||||
|
||||
def get_product_variant(self, **kwargs):
|
||||
try:
|
||||
product_code = kwargs.get('product_code')
|
||||
return self.variants.get(product_code=product_code)
|
||||
except SmartPhoneVariant.DoesNotExist as e:
|
||||
raise SmartPhoneModel.DoesNotExist(e)
|
||||
|
||||
def get_product_variants(self):
|
||||
return self.variants.all()
|
||||
|
||||
|
||||
class SmartPhoneVariant(AvailableProductMixin, models.Model):
|
||||
product = models.ForeignKey(
|
||||
SmartPhoneModel,
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name=_("Smartphone Model"),
|
||||
related_name='variants',
|
||||
)
|
||||
|
||||
product_code = models.CharField(
|
||||
_("Product code"),
|
||||
max_length=255,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
unit_price = MoneyField(
|
||||
_("Unit price"),
|
||||
decimal_places=3,
|
||||
help_text=_("Net price for this product"),
|
||||
)
|
||||
|
||||
storage = models.PositiveIntegerField(
|
||||
_("Internal Storage"),
|
||||
help_text=_("Internal storage in GB"),
|
||||
)
|
||||
|
||||
quantity = models.PositiveIntegerField(
|
||||
_("Quantity"),
|
||||
default=0,
|
||||
validators=[MinValueValidator(0)],
|
||||
help_text=_("Available quantity in stock")
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return _("{product} with {storage} GB").format(product=self.product, storage=self.storage)
|
||||
|
||||
def get_price(self, request):
|
||||
return self.unit_price
|
||||
52
weirdlittleempire/modifiers.py
Normal file
52
weirdlittleempire/modifiers.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from shop.modifiers.pool import cart_modifiers_pool
|
||||
from shop.modifiers.defaults import DefaultCartModifier
|
||||
from shop.serializers.cart import ExtraCartRow
|
||||
from shop.money import Money
|
||||
from shop.shipping.modifiers import ShippingModifier
|
||||
from shop_stripe import modifiers
|
||||
|
||||
|
||||
class PrimaryCartModifier(DefaultCartModifier):
|
||||
"""
|
||||
Extended default cart modifier which handles the price for product variations
|
||||
"""
|
||||
|
||||
def process_cart_item(self, cart_item, request):
|
||||
variant = cart_item.product.get_product_variant(
|
||||
product_code=cart_item.product_code)
|
||||
cart_item.unit_price = variant.unit_price
|
||||
cart_item.line_total = cart_item.unit_price * cart_item.quantity
|
||||
# grandparent super
|
||||
return super(DefaultCartModifier, self).process_cart_item(cart_item, request)
|
||||
|
||||
|
||||
class PostalShippingModifier(ShippingModifier):
|
||||
"""
|
||||
This is just a demo on how to implement a shipping modifier, which when selected
|
||||
by the customer, adds an additional charge to the cart.
|
||||
"""
|
||||
identifier = 'postal-shipping'
|
||||
|
||||
def get_choice(self):
|
||||
return (self.identifier, _("Postal shipping"))
|
||||
|
||||
def add_extra_cart_row(self, cart, request):
|
||||
shipping_modifiers = cart_modifiers_pool.get_shipping_modifiers()
|
||||
if not self.is_active(cart.extra.get('shipping_modifier')) and len(shipping_modifiers) > 1:
|
||||
return
|
||||
# add a shipping flat fee
|
||||
amount = Money('5')
|
||||
instance = {'label': _("Shipping costs"), 'amount': amount}
|
||||
cart.extra_rows[self.identifier] = ExtraCartRow(instance)
|
||||
cart.total += amount
|
||||
|
||||
def ship_the_goods(self, delivery):
|
||||
if not delivery.shipping_id:
|
||||
raise ValidationError("Please provide a valid Shipping ID")
|
||||
super().ship_the_goods(delivery)
|
||||
|
||||
|
||||
class StripePaymentModifier(modifiers.StripePaymentModifier):
|
||||
commision_percentage = 3
|
||||
8
weirdlittleempire/search_indexes.py
Normal file
8
weirdlittleempire/search_indexes.py
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
from shop.search.documents import ProductDocument
|
||||
|
||||
settings = {
|
||||
'number_of_shards': 1,
|
||||
'number_of_replicas': 0,
|
||||
}
|
||||
ProductDocument(settings=settings)
|
||||
31
weirdlittleempire/serializers.py
Normal file
31
weirdlittleempire/serializers.py
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
from shop.models.cart import CartModel
|
||||
from shop.serializers.defaults.catalog import AddToCartSerializer
|
||||
|
||||
|
||||
class AddSmartPhoneToCartSerializer(AddToCartSerializer):
|
||||
"""
|
||||
Modified AddToCartSerializer which handles SmartPhones
|
||||
"""
|
||||
|
||||
def get_instance(self, context, data, extra_args):
|
||||
product = context['product']
|
||||
request = context['request']
|
||||
try:
|
||||
cart = CartModel.objects.get_from_request(request)
|
||||
except CartModel.DoesNotExist:
|
||||
cart = None
|
||||
try:
|
||||
variant = product.get_product_variant(
|
||||
product_code=data['product_code'])
|
||||
except (TypeError, KeyError, product.DoesNotExist):
|
||||
variant = product.variants.first()
|
||||
instance = {
|
||||
'product': product.id,
|
||||
'product_code': variant.product_code,
|
||||
'unit_price': variant.unit_price,
|
||||
'is_in_cart': bool(product.is_in_cart(cart, product_code=variant.product_code)),
|
||||
'extra': {'storage': variant.storage},
|
||||
'availability': variant.get_availability(request),
|
||||
}
|
||||
return instance
|
||||
598
weirdlittleempire/settings.py
Normal file
598
weirdlittleempire/settings.py
Normal file
@@ -0,0 +1,598 @@
|
||||
"""
|
||||
Django settings for weirdlittleempire project.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/stable/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/stable/ref/settings/
|
||||
"""
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
from decimal import Decimal
|
||||
import os
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.text import format_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from cmsplugin_cascade.bootstrap4.mixins import BootstrapUtilities
|
||||
from cmsplugin_cascade.extra_fields.config import PluginExtraFieldsConfig
|
||||
|
||||
SHOP_APP_LABEL = 'weirdlittleempire'
|
||||
BASE_DIR = os.path.dirname(__file__)
|
||||
|
||||
# Root directory for this django project
|
||||
PROJECT_ROOT = os.path.abspath(os.path.join(BASE_DIR, os.path.pardir))
|
||||
|
||||
# Directory where working files, such as media and databases are kept
|
||||
WORK_DIR = os.environ.get('DJANGO_WORKDIR', os.path.abspath(
|
||||
os.path.join(PROJECT_ROOT, 'workdir')))
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
|
||||
|
||||
ADMINS = [("A Jones", 'biz@aronajones.com')]
|
||||
|
||||
# SECURITY WARNING: in production, inject the secret key through the environment
|
||||
SECRET_KEY = os.environ.get(
|
||||
'DJANGO_SECRET_KEY', 'Q1ayyKMNv4figvm1DDseLjWlOHn4OI7lW2hxNn0BztgWkXJLBTFDkYJCmY2OshPt')
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# Local time zone for this installation. Choices can be found here:
|
||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||
# although not all choices may be available on all operating systems.
|
||||
# On Unix systems, a value of None will cause Django to use the same
|
||||
# timezone as the operating system.
|
||||
# If running in a Windows environment this must be set to the same as your
|
||||
# system time zone.
|
||||
TIME_ZONE = 'GMT'
|
||||
|
||||
USE_THOUSAND_SEPARATOR = True
|
||||
|
||||
# Application definition
|
||||
|
||||
# replace django.contrib.auth.models.User by implementation
|
||||
# allowing to login via email address
|
||||
AUTH_USER_MODEL = 'email_auth.User'
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
'OPTIONS': {
|
||||
'min_length': 6,
|
||||
}
|
||||
}]
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
'allauth.account.auth_backends.AuthenticationBackend',
|
||||
]
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.auth',
|
||||
'email_auth',
|
||||
'polymorphic',
|
||||
# deprecated: 'djangocms_admin_style',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.sitemaps',
|
||||
'djangocms_text_ckeditor',
|
||||
'django_select2',
|
||||
'cmsplugin_cascade',
|
||||
'cmsplugin_cascade.clipboard',
|
||||
'cmsplugin_cascade.sharable',
|
||||
'cmsplugin_cascade.extra_fields',
|
||||
'cmsplugin_cascade.icon',
|
||||
'cmsplugin_cascade.segmentation',
|
||||
'cms_bootstrap',
|
||||
'adminsortable2',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
'rest_auth',
|
||||
'django_elasticsearch_dsl',
|
||||
'django_fsm',
|
||||
'fsm_admin',
|
||||
'djng',
|
||||
'cms',
|
||||
'menus',
|
||||
'treebeard',
|
||||
'compressor',
|
||||
'sass_processor',
|
||||
'sekizai',
|
||||
'django_filters',
|
||||
'filer',
|
||||
'easy_thumbnails',
|
||||
'easy_thumbnails.optimize',
|
||||
'post_office',
|
||||
'shop_stripe',
|
||||
'shop',
|
||||
'weirdlittleempire',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
# 'django.middleware.cache.UpdateCacheMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'shop.middleware.CustomerMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.gzip.GZipMiddleware',
|
||||
'cms.middleware.language.LanguageCookieMiddleware',
|
||||
'cms.middleware.user.CurrentUserMiddleware',
|
||||
'cms.middleware.page.CurrentPageMiddleware',
|
||||
'cms.middleware.utils.ApphookReloadMiddleware',
|
||||
'cms.middleware.toolbar.ToolbarMiddleware',
|
||||
# 'django.middleware.cache.FetchFromCacheMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'weirdlittleempire.urls'
|
||||
|
||||
WSGI_APPLICATION = 'wsgi.application'
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(WORK_DIR, 'db.sqlite3'),
|
||||
}
|
||||
}
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/stable/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en'
|
||||
|
||||
USE_I18N = False
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
USE_X_FORWARDED_HOST = True
|
||||
|
||||
X_FRAME_OPTIONS = 'SAMEORIGIN'
|
||||
|
||||
# Absolute path to the directory that holds media.
|
||||
# Example: "/home/media/media.lawrence.com/"
|
||||
MEDIA_ROOT = os.path.join(WORK_DIR, 'media')
|
||||
|
||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||
# trailing slash.
|
||||
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
# Absolute path to the directory that holds static files.
|
||||
# Example: "/home/media/media.lawrence.com/static/"
|
||||
STATIC_ROOT = os.getenv('DJANGO_STATIC_ROOT', os.path.join(WORK_DIR, 'static'))
|
||||
|
||||
# URL that handles the static files served from STATIC_ROOT.
|
||||
# Example: "http://media.lawrence.com/static/"
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
STATICFILES_FINDERS = [
|
||||
# or 'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'weirdlittleempire.finders.FileSystemFinder',
|
||||
# or 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'weirdlittleempire.finders.AppDirectoriesFinder',
|
||||
'sass_processor.finders.CssFinder',
|
||||
'compressor.finders.CompressorFinder',
|
||||
]
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
('node_modules', os.path.join(PROJECT_ROOT, 'node_modules')),
|
||||
]
|
||||
|
||||
TEMPLATES = [{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'APP_DIRS': True,
|
||||
'DIRS': [],
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.i18n',
|
||||
'django.template.context_processors.media',
|
||||
'django.template.context_processors.static',
|
||||
'django.template.context_processors.tz',
|
||||
'django.template.context_processors.csrf',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'sekizai.context_processors.sekizai',
|
||||
'cms.context_processors.cms_settings',
|
||||
'shop.context_processors.customer',
|
||||
'shop.context_processors.shop_settings',
|
||||
'shop_stripe.context_processors.public_keys',
|
||||
]
|
||||
}
|
||||
}, {
|
||||
'BACKEND': 'post_office.template.backends.post_office.PostOfficeTemplates',
|
||||
'APP_DIRS': True,
|
||||
'DIRS': [],
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.i18n',
|
||||
'django.template.context_processors.media',
|
||||
'django.template.context_processors.static',
|
||||
'django.template.context_processors.tz',
|
||||
'django.template.context_processors.request',
|
||||
]
|
||||
}
|
||||
}]
|
||||
|
||||
POST_OFFICE = {
|
||||
'TEMPLATE_ENGINE': 'post_office',
|
||||
}
|
||||
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||||
},
|
||||
'select2': {
|
||||
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
|
||||
}
|
||||
}
|
||||
|
||||
############################################
|
||||
# settings for caching and storing session data
|
||||
REDIS_HOST = os.getenv('REDIS_HOST')
|
||||
if REDIS_HOST:
|
||||
SESSION_ENGINE = 'redis_sessions.session'
|
||||
|
||||
SESSION_REDIS = {
|
||||
'host': REDIS_HOST,
|
||||
'port': 6379,
|
||||
'db': 0,
|
||||
'prefix': 'session-',
|
||||
'socket_timeout': 1
|
||||
}
|
||||
|
||||
CACHES['default'] = {
|
||||
'BACKEND': 'redis_cache.RedisCache',
|
||||
'LOCATION': 'redis://{}:6379/1'.format(REDIS_HOST),
|
||||
}
|
||||
|
||||
COMPRESS_CACHE_BACKEND = 'compressor'
|
||||
CACHES[COMPRESS_CACHE_BACKEND] = {
|
||||
'BACKEND': 'redis_cache.RedisCache',
|
||||
'LOCATION': 'redis://{}:6379/2'.format(REDIS_HOST),
|
||||
}
|
||||
|
||||
CACHE_MIDDLEWARE_ALIAS = 'default'
|
||||
CACHE_MIDDLEWARE_SECONDS = 3600
|
||||
else:
|
||||
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
|
||||
|
||||
SESSION_SAVE_EVERY_REQUEST = True
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
'filters': {'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}},
|
||||
'formatters': {
|
||||
'simple': {
|
||||
'format': '[%(asctime)s %(module)s] %(levelname)s: %(message)s'
|
||||
},
|
||||
},
|
||||
'handlers': {
|
||||
'console': {
|
||||
'level': 'INFO',
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'simple',
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django': {
|
||||
'handlers': ['console'],
|
||||
'level': 'INFO',
|
||||
'propagate': True,
|
||||
},
|
||||
'post_office': {
|
||||
'handlers': ['console'],
|
||||
'level': 'WARNING',
|
||||
'propagate': True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
SILENCED_SYSTEM_CHECKS = ['auth.W004']
|
||||
|
||||
FIXTURE_DIRS = [
|
||||
os.path.join(WORK_DIR, 'fixtures'),
|
||||
]
|
||||
|
||||
############################################
|
||||
# settings for sending mail
|
||||
|
||||
EMAIL_HOST = os.getenv('DJANGO_EMAIL_HOST', 'localhost')
|
||||
EMAIL_PORT = os.getenv('DJANGO_EMAIL_PORT', 25)
|
||||
EMAIL_HOST_USER = os.getenv('DJANGO_EMAIL_USER', 'no-reply@localhost')
|
||||
EMAIL_HOST_PASSWORD = os.getenv('DJANGO_EMAIL_PASSWORD', 'smtp-secret')
|
||||
EMAIL_USE_TLS = bool(os.getenv('DJANGO_EMAIL_USE_TLS', '1'))
|
||||
DEFAULT_FROM_EMAIL = os.getenv('DJANGO_EMAIL_FROM', 'no-reply@localhost')
|
||||
EMAIL_REPLY_TO = os.getenv('DJANGO_EMAIL_REPLY_TO', 'info@localhost')
|
||||
EMAIL_BACKEND = 'post_office.EmailBackend'
|
||||
|
||||
|
||||
############################################
|
||||
# settings for third party Django apps
|
||||
|
||||
NODE_MODULES_URL = STATIC_URL + 'node_modules/'
|
||||
|
||||
SASS_PROCESSOR_INCLUDE_DIRS = [
|
||||
os.path.join(PROJECT_ROOT, 'node_modules'),
|
||||
]
|
||||
|
||||
COERCE_DECIMAL_TO_STRING = True
|
||||
|
||||
FSM_ADMIN_FORCE_PERMIT = True
|
||||
|
||||
ROBOTS_META_TAGS = ('noindex', 'nofollow')
|
||||
|
||||
SERIALIZATION_MODULES = {'json': str('shop.money.serializers')}
|
||||
|
||||
############################################
|
||||
# settings for django-restframework and plugins
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_RENDERER_CLASSES': [
|
||||
'shop.rest.money.JSONRenderer',
|
||||
# can be disabled for production environments
|
||||
'rest_framework.renderers.BrowsableAPIRenderer',
|
||||
],
|
||||
'DEFAULT_FILTER_BACKENDS': [
|
||||
'django_filters.rest_framework.DjangoFilterBackend',
|
||||
],
|
||||
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
|
||||
# 'PAGE_SIZE': 16,
|
||||
}
|
||||
|
||||
REST_AUTH_SERIALIZERS = {
|
||||
'LOGIN_SERIALIZER': 'shop.serializers.auth.LoginSerializer',
|
||||
}
|
||||
|
||||
############################################
|
||||
# settings for storing files and images
|
||||
|
||||
FILER_ADMIN_ICON_SIZES = ('16', '32', '48', '80', '128')
|
||||
|
||||
FILER_ALLOW_REGULAR_USERS_TO_ADD_ROOT_FOLDERS = True
|
||||
|
||||
FILER_DUMP_PAYLOAD = False
|
||||
|
||||
FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880
|
||||
|
||||
THUMBNAIL_HIGH_RESOLUTION = False
|
||||
|
||||
THUMBNAIL_PRESERVE_EXTENSIONS = True
|
||||
|
||||
THUMBNAIL_PROCESSORS = (
|
||||
'easy_thumbnails.processors.colorspace',
|
||||
'easy_thumbnails.processors.autocrop',
|
||||
'filer.thumbnail_processors.scale_and_crop_with_subject_location',
|
||||
'easy_thumbnails.processors.filters',
|
||||
)
|
||||
|
||||
|
||||
############################################
|
||||
# settings for django-cms and its plugins
|
||||
|
||||
CMS_TEMPLATES = [
|
||||
('weirdlittleempire/pages/default.html', "Default Page"),
|
||||
]
|
||||
|
||||
CMS_CACHE_DURATIONS = {
|
||||
'content': 600,
|
||||
'menus': 3600,
|
||||
'permissions': 86400,
|
||||
}
|
||||
|
||||
CMS_PERMISSION = True
|
||||
|
||||
CMS_PLACEHOLDER_CONF = {
|
||||
'Breadcrumb': {
|
||||
'plugins': ['BreadcrumbPlugin'],
|
||||
'parent_classes': {'BreadcrumbPlugin': None},
|
||||
},
|
||||
'Commodity Details': {
|
||||
'plugins': ['BootstrapContainerPlugin', 'BootstrapJumbotronPlugin'],
|
||||
'parent_classes': {
|
||||
'BootstrapContainerPlugin': None,
|
||||
'BootstrapJumbotronPlugin': None,
|
||||
},
|
||||
},
|
||||
'Main Content': {
|
||||
'plugins': ['BootstrapContainerPlugin', 'BootstrapJumbotronPlugin'],
|
||||
'parent_classes': {
|
||||
'BootstrapContainerPlugin': None,
|
||||
'BootstrapJumbotronPlugin': None,
|
||||
'TextLinkPlugin': ['TextPlugin', 'AcceptConditionPlugin'],
|
||||
},
|
||||
},
|
||||
'Static Footer': {
|
||||
'plugins': ['BootstrapContainerPlugin', 'BootstrapJumbotronPlugin'],
|
||||
'parent_classes': {
|
||||
'BootstrapContainerPlugin': None,
|
||||
'BootstrapJumbotronPlugin': None,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
CMSPLUGIN_CASCADE_PLUGINS = [
|
||||
'cmsplugin_cascade.bootstrap4',
|
||||
'cmsplugin_cascade.segmentation',
|
||||
'cmsplugin_cascade.generic',
|
||||
'cmsplugin_cascade.icon',
|
||||
'cmsplugin_cascade.leaflet',
|
||||
'cmsplugin_cascade.link',
|
||||
'shop.cascade',
|
||||
]
|
||||
|
||||
CMSPLUGIN_CASCADE = {
|
||||
'link_plugin_classes': [
|
||||
'shop.cascade.plugin_base.CatalogLinkPluginBase',
|
||||
'shop.cascade.plugin_base.CatalogLinkForm',
|
||||
],
|
||||
'alien_plugins': ['TextPlugin', 'TextLinkPlugin', 'AcceptConditionPlugin'],
|
||||
'bootstrap4': {
|
||||
'template_basedir': 'angular-ui/',
|
||||
},
|
||||
'plugins_with_extra_render_templates': {
|
||||
'CustomSnippetPlugin': [
|
||||
('shop/catalog/product-heading.html', _("Product Heading")),
|
||||
('weirdlittleempire/catalog/manufacturer-filter.html',
|
||||
_("Manufacturer Filter")),
|
||||
],
|
||||
# required to purchase real estate
|
||||
'ShopAddToCartPlugin': [
|
||||
(None, _("Default")),
|
||||
('weirdlittleempire/catalog/commodity-add2cart.html',
|
||||
_("Add Commodity to Cart")),
|
||||
],
|
||||
},
|
||||
'plugins_with_sharables': {
|
||||
'BootstrapImagePlugin': ['image_shapes', 'image_width_responsive', 'image_width_fixed',
|
||||
'image_height', 'resize_options'],
|
||||
'BootstrapPicturePlugin': ['image_shapes', 'responsive_heights', 'responsive_zoom', 'resize_options'],
|
||||
},
|
||||
'plugins_with_extra_fields': {
|
||||
'BootstrapCardPlugin': PluginExtraFieldsConfig(),
|
||||
'BootstrapCardHeaderPlugin': PluginExtraFieldsConfig(),
|
||||
'BootstrapCardBodyPlugin': PluginExtraFieldsConfig(),
|
||||
'BootstrapCardFooterPlugin': PluginExtraFieldsConfig(),
|
||||
'SimpleIconPlugin': PluginExtraFieldsConfig(),
|
||||
},
|
||||
'plugins_with_extra_mixins': {
|
||||
'BootstrapContainerPlugin': BootstrapUtilities(),
|
||||
'BootstrapRowPlugin': BootstrapUtilities(BootstrapUtilities.paddings),
|
||||
'BootstrapYoutubePlugin': BootstrapUtilities(BootstrapUtilities.margins),
|
||||
'BootstrapButtonPlugin': BootstrapUtilities(BootstrapUtilities.floats),
|
||||
},
|
||||
'leaflet': {
|
||||
'tilesURL': 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}',
|
||||
'accessToken': 'pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw',
|
||||
'apiKey': 'AIzaSyD71sHrtkZMnLqTbgRmY_NsO0A9l9BQmv4',
|
||||
},
|
||||
'bookmark_prefix': '/',
|
||||
'segmentation_mixins': [
|
||||
('shop.cascade.segmentation.EmulateCustomerModelMixin',
|
||||
'shop.cascade.segmentation.EmulateCustomerAdminMixin'),
|
||||
],
|
||||
'allow_plugin_hiding': True,
|
||||
'register_page_editor': True,
|
||||
}
|
||||
|
||||
CKEDITOR_SETTINGS = {
|
||||
'language': '{{ language }}',
|
||||
'skin': 'moono-lisa',
|
||||
'toolbar_CMS': [
|
||||
['Undo', 'Redo'],
|
||||
['cmsplugins', '-', 'ShowBlocks'],
|
||||
['Format'],
|
||||
['TextColor', 'BGColor', '-', 'PasteText', 'PasteFromWord'],
|
||||
'/',
|
||||
['Bold', 'Italic', 'Underline', 'Strike', '-',
|
||||
'Subscript', 'Superscript', '-', 'RemoveFormat'],
|
||||
['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
|
||||
['HorizontalRule'],
|
||||
['NumberedList', 'BulletedList', 'Outdent', 'Indent'],
|
||||
['Table', 'Source']
|
||||
],
|
||||
'stylesSet': format_lazy('default:{}', reverse_lazy('admin:cascade_texteditor_config')),
|
||||
}
|
||||
|
||||
CKEDITOR_SETTINGS_CAPTION = {
|
||||
'language': '{{ language }}',
|
||||
'skin': 'moono-lisa',
|
||||
'height': 70,
|
||||
'toolbar_HTMLField': [
|
||||
['Undo', 'Redo'],
|
||||
['Format', 'Styles'],
|
||||
['Bold', 'Italic', 'Underline', '-', 'Subscript',
|
||||
'Superscript', '-', 'RemoveFormat'],
|
||||
['Source']
|
||||
],
|
||||
}
|
||||
|
||||
CKEDITOR_SETTINGS_DESCRIPTION = {
|
||||
'language': '{{ language }}',
|
||||
'skin': 'moono-lisa',
|
||||
'height': 250,
|
||||
'toolbar_HTMLField': [
|
||||
['Undo', 'Redo'],
|
||||
['cmsplugins', '-', 'ShowBlocks'],
|
||||
['Format', 'Styles'],
|
||||
['TextColor', 'BGColor', '-', 'PasteText', 'PasteFromWord'],
|
||||
['Maximize', ''],
|
||||
'/',
|
||||
['Bold', 'Italic', 'Underline', '-', 'Subscript',
|
||||
'Superscript', '-', 'RemoveFormat'],
|
||||
['JustifyLeft', 'JustifyCenter', 'JustifyRight'],
|
||||
['HorizontalRule'],
|
||||
['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent'],
|
||||
['Source']
|
||||
],
|
||||
}
|
||||
|
||||
SELECT2_CSS = 'node_modules/select2/dist/css/select2.min.css'
|
||||
SELECT2_JS = 'node_modules/select2/dist/js/select2.min.js'
|
||||
SELECT2_I18N_PATH = 'node_modules/select2/dist/js/i18n'
|
||||
|
||||
|
||||
#############################################
|
||||
# settings for full index text search
|
||||
|
||||
ELASTICSEARCH_HOST = os.getenv('ELASTICSEARCH_HOST', 'localhost')
|
||||
|
||||
ELASTICSEARCH_DSL = {
|
||||
'default': {
|
||||
'hosts': '{}:9200'.format(ELASTICSEARCH_HOST)
|
||||
},
|
||||
}
|
||||
|
||||
############################################
|
||||
# settings for django-shop and its plugins
|
||||
|
||||
SHOP_VALUE_ADDED_TAX = Decimal(19)
|
||||
SHOP_DEFAULT_CURRENCY = 'EUR'
|
||||
SHOP_EDITCART_NG_MODEL_OPTIONS = "{updateOn: 'default blur', debounce: {'default': 2500, 'blur': 0}}"
|
||||
|
||||
SHOP_CART_MODIFIERS = [
|
||||
'weirdlittleempire.modifiers.PrimaryCartModifier',
|
||||
'shop.modifiers.taxes.CartExcludedTaxModifier',
|
||||
'weirdlittleempire.modifiers.PostalShippingModifier',
|
||||
'weirdlittleempire.modifiers.StripePaymentModifier',
|
||||
'shop.payment.modifiers.PayInAdvanceModifier',
|
||||
'shop.shipping.modifiers.SelfCollectionModifier',
|
||||
]
|
||||
|
||||
SHOP_ORDER_WORKFLOWS = [
|
||||
'shop.payment.workflows.ManualPaymentWorkflowMixin',
|
||||
'shop.payment.workflows.CancelOrderWorkflowMixin',
|
||||
'shop.shipping.workflows.PartialDeliveryWorkflowMixin',
|
||||
'shop_stripe.workflows.OrderWorkflowMixin',
|
||||
]
|
||||
|
||||
|
||||
SHOP_STRIPE = {
|
||||
'PUBKEY': os.getenv('STRIPE_PUBKEY', 'pk_test_HlEp5oZyPonE21svenqowhXp'),
|
||||
'APIKEY': os.getenv('STRIPE_APIKEY', 'sk_test_xUdHLeFasmOUDvmke4DHGRDP'),
|
||||
'PURCHASE_DESCRIPTION': _("Thanks for purchasing at Weird Little Empire"),
|
||||
}
|
||||
SHOP_STRIPE_PREFILL = True
|
||||
|
||||
|
||||
SHOP_CASCADE_FORMS = {
|
||||
'CustomerForm': 'weirdlittleempire.forms.CustomerForm',
|
||||
}
|
||||
12
weirdlittleempire/sitemap.py
Normal file
12
weirdlittleempire/sitemap.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from django.contrib.sitemaps import Sitemap
|
||||
from django.conf import settings
|
||||
from weirdlittleempire.models import Product
|
||||
|
||||
|
||||
class ProductSitemap(Sitemap):
|
||||
changefreq = 'monthly'
|
||||
priority = 0.5
|
||||
i18n = settings.USE_I18N
|
||||
|
||||
def items(self):
|
||||
return Product.objects.filter(active=True)
|
||||
35
weirdlittleempire/static/weirdlittleempire/css/_footer.scss
Normal file
35
weirdlittleempire/static/weirdlittleempire/css/_footer.scss
Normal file
@@ -0,0 +1,35 @@
|
||||
@import "variables";
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
&.cms-toolbar-expanded {
|
||||
// prevents pushing a sticky footer outside the vertical viewport if CMS toolbar is active
|
||||
height: calc(100% - 46px);
|
||||
}
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
main {
|
||||
flex: 1 0 auto;
|
||||
padding-bottom: $body-footer-margin;
|
||||
}
|
||||
footer {
|
||||
flex-shrink: 0;
|
||||
color: $body-footer-color;
|
||||
background: $body-footer-bg;
|
||||
padding-top: $body-footer-margin;
|
||||
padding-bottom: $body-footer-margin;
|
||||
a {
|
||||
color: $body-footer-link-color;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
color: $body-footer-link-hover-color;
|
||||
}
|
||||
&:active {
|
||||
color: $body-footer-link-active-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
103
weirdlittleempire/static/weirdlittleempire/css/_navbar.scss
Normal file
103
weirdlittleempire/static/weirdlittleempire/css/_navbar.scss
Normal file
@@ -0,0 +1,103 @@
|
||||
@import "variables";
|
||||
@import "shop/css/navbar";
|
||||
|
||||
body {
|
||||
padding-top: $body-header-height;
|
||||
@include media-breakpoint-up(lg) {
|
||||
padding-top: $body-header-lg-height;
|
||||
}
|
||||
.navbar {
|
||||
$navbar: &;
|
||||
@include media-breakpoint-up(lg) {
|
||||
height: $body-header-lg-height;
|
||||
transition: height 500ms ease, box-shadow 250ms ease;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
.navbar-nav, .navbar-collapse, >.container {
|
||||
height: 100% !important;
|
||||
}
|
||||
&.scrolled {
|
||||
height: 75px;
|
||||
box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.075);
|
||||
.shop-brand-icon {
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
.nav-link {
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
}
|
||||
.shop-brand-icon {
|
||||
height: 48px;
|
||||
transition: height 500ms ease;
|
||||
position: absolute;
|
||||
padding-top: 0.5rem;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
pointer-events: none;
|
||||
a {
|
||||
width: min-content;
|
||||
}
|
||||
img {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
margin: auto;
|
||||
display: block;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
.shop-social-icons {
|
||||
.nav-link {
|
||||
display: inline-block;
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
@include media-breakpoint-down(md) {
|
||||
order: 4;
|
||||
.nav-link {
|
||||
margin-left: 0.25rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
align-self: flex-end;
|
||||
}
|
||||
.cms-placeholder {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.shop-primary-menu {
|
||||
font-size: 125%;
|
||||
font-weight: 300;
|
||||
@include media-breakpoint-down(md) {
|
||||
order: 1;
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
font-size: 150%;
|
||||
.dropdown-toggle::after {
|
||||
font-size: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
.shop-secondary-menu {
|
||||
@include media-breakpoint-down(md) {
|
||||
order: 2;
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
.shop-search-form {
|
||||
@include media-breakpoint-down(md) {
|
||||
order: 3;
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
@import "shop/css/variables";
|
||||
|
||||
// header
|
||||
$body-header-height: 50px;
|
||||
$body-header-lg-height: 90px;
|
||||
|
||||
// footer
|
||||
$body-footer-margin: 1rem;
|
||||
$body-footer-color: $white;
|
||||
$body-footer-bg: $gray-900;
|
||||
$body-footer-border: $gray-900;
|
||||
$body-footer-link-color: darken($body-footer-color, 15%);
|
||||
$body-footer-link-hover-color: $body-footer-color;
|
||||
$body-footer-link-active-color: $body-footer-color;
|
||||
@@ -0,0 +1,5 @@
|
||||
@import "variables";
|
||||
@import "font-awesome/scss/font-awesome";
|
||||
@import "shop/css/django-shop";
|
||||
@import "navbar";
|
||||
@import "footer";
|
||||
BIN
weirdlittleempire/static/weirdlittleempire/django-shop-logo.png
Normal file
BIN
weirdlittleempire/static/weirdlittleempire/django-shop-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="453.54px"
|
||||
height="85.04px"
|
||||
viewBox="0 0 453.54 85.04"
|
||||
enable-background="new 0 0 453.54 85.04"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="django-shop-logo.svg"><metadata
|
||||
id="metadata31"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs29" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2091"
|
||||
inkscape:window-height="1115"
|
||||
id="namedview27"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.79816553"
|
||||
inkscape:cx="152.22406"
|
||||
inkscape:cy="42.52"
|
||||
inkscape:window-x="1440"
|
||||
inkscape:window-y="1"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Layer_1" /><g
|
||||
id="g4195"
|
||||
inkscape:export-xdpi="44.479092"
|
||||
inkscape:export-ydpi="44.479092"><g
|
||||
id="g4189"><path
|
||||
id="path5"
|
||||
d="m 245.27,46.11 c 6.24,4.24 10.48,5.681 16.24,5.681 5.6,0 8.801,-2 8.801,-5.44 0,-3.2 -1.439,-4.56 -9.6,-8.64 -6.641,-3.28 -9.121,-4.96 -11.441,-7.521 -2.32,-2.48 -3.52,-5.92 -3.52,-9.76 0,-10.4 8.24,-16.96 21.439,-16.96 5.762,0 11.041,1.2 15.762,3.6 l 0,12.24 c -4.961,-3.52 -9.281,-4.96 -14.801,-4.96 -5.84,0 -9.201,1.92 -9.201,5.28 0,2.24 1.602,3.92 5.201,5.6 l 4.801,2.32 c 5.76,2.64 8.479,4.4 10.959,6.88 2.881,2.88 4.4,6.8 4.4,11.281 0,10.72 -8.48,17.359 -22,17.359 -6.08,0 -11.761,-1.279 -17.041,-3.84 l 0,-13.12 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#43b68b" /><path
|
||||
id="path7"
|
||||
d="m 289.59,4.51 13.359,0 0,22.32 22.801,0 0,-22.32 13.361,0 0,57.121 -13.361,0 0,-23.521 -22.801,0 0,23.521 -13.359,0 0,-57.121 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#43b68b" /><path
|
||||
id="path9"
|
||||
d="m 373.67,3.39 c 17.279,0 28.16,11.44 28.16,29.44 0,18.48 -11.201,30.081 -29.041,30.081 -17.52,0 -28.4,-11.2 -28.4,-29.121 0,-18.56 11.359,-30.4 29.281,-30.4 z m -0.561,48.241 c 9.201,0 14.721,-6.961 14.721,-18.721 0,-11.68 -5.361,-18.641 -14.48,-18.641 -9.361,0 -14.961,7.041 -14.961,18.721 0,11.76 5.441,18.641 14.72,18.641 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#43b68b" /><path
|
||||
id="path11"
|
||||
d="m 407.428,4.91 1.279,-0.08 c 6.08,-0.4 10.961,-0.64 15.441,-0.64 8.799,0 14.08,1.2 18.32,4.24 4.48,3.2 7.039,8.48 7.039,14.72 0,6.4 -2.879,11.92 -8,14.88 -4.24,2.48 -9.359,3.6 -16.561,3.6 -1.119,0 -2.24,-0.08 -4.16,-0.16 l 0,20.161 -13.359,0 0,-56.721 z m 13.359,26 c 1.361,0.24 2.24,0.24 3.281,0.24 8.721,0 12.24,-2.4 12.24,-8.161 0,-5.6 -3.52,-8.32 -10.561,-8.32 -1.359,0 -2.561,0 -4.961,0.4 l 0,15.841 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#43b68b" /></g><g
|
||||
id="g13"><path
|
||||
id="path15"
|
||||
d="m 31.092,3.071 12.401,0 0,57.404 c -6.361,1.207 -11.033,1.69 -16.107,1.69 -15.138,0 -23.032,-6.847 -23.032,-19.973 0,-12.643 8.378,-20.857 21.342,-20.857 2.013,0 3.543,0.16 5.396,0.646 l 0,-18.91 z m 0,28.895 c -1.45,-0.481 -2.657,-0.642 -4.188,-0.642 -6.282,0 -9.906,3.865 -9.906,10.63 0,6.604 3.463,10.226 9.826,10.226 1.369,0 2.495,-0.08 4.268,-0.32 l 0,-19.894 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#082e20" /><path
|
||||
id="path17"
|
||||
d="m 63.223,22.225 0,28.749 c 0,9.904 -0.725,14.656 -2.9,18.762 -2.012,3.946 -4.67,6.443 -10.146,9.181 L 38.661,73.44 c 5.477,-2.576 8.134,-4.831 9.824,-8.293 1.772,-3.543 2.335,-7.65 2.335,-18.443 l 0,-24.479 12.403,0 z M 50.82,3.137 l 12.403,0 0,12.726 -12.403,0 0,-12.726 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#082e20" /><path
|
||||
id="path19"
|
||||
d="m 70.712,25.042 c 5.478,-2.576 10.711,-3.706 16.431,-3.706 6.36,0 10.548,1.692 12.4,4.994 1.047,1.852 1.369,4.268 1.369,9.422 l 0,25.206 c -5.558,0.806 -12.562,1.37 -17.715,1.37 -10.389,0 -15.061,-3.625 -15.061,-11.678 0,-8.696 6.2,-12.723 21.421,-14.012 l 0,-2.737 c 0,-2.255 -1.126,-3.062 -4.268,-3.062 -4.59,0 -9.744,1.29 -14.578,3.785 l 0,-9.582 z m 19.409,19.729 c -8.212,0.806 -10.872,2.096 -10.872,5.313 0,2.419 1.53,3.546 4.913,3.546 1.853,0 3.543,-0.16 5.959,-0.564 l 0,-8.295 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#082e20" /><path
|
||||
id="path21"
|
||||
d="m 106.952,24.155 c 7.329,-1.931 13.368,-2.819 19.489,-2.819 6.362,0 10.951,1.45 13.69,4.269 2.576,2.657 3.382,5.557 3.382,11.758 l 0,24.319 -12.402,0 0,-23.835 c 0,-4.751 -1.611,-6.523 -6.038,-6.523 -1.692,0 -3.221,0.161 -5.719,0.884 l 0,29.475 -12.402,0 0,-37.528 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#082e20" /><path
|
||||
id="path23"
|
||||
d="m 148.334,68.446 c 4.351,2.256 8.698,3.303 13.288,3.303 8.135,0 11.597,-3.303 11.597,-11.194 0,-0.079 0,-0.159 0,-0.241 -2.415,1.209 -4.83,1.69 -8.052,1.69 -10.872,0 -17.798,-7.166 -17.798,-18.521 0,-14.095 10.227,-22.066 28.347,-22.066 5.314,0 10.226,0.565 16.187,1.774 l -4.246,8.945 c -3.303,-0.646 -0.264,-0.088 -2.759,-0.33 l 0,1.291 0.16,5.233 0.081,6.765 c 0.081,1.692 0.081,3.385 0.162,5.073 0,1.531 0,2.256 0,3.385 0,10.63 -0.886,15.623 -3.545,19.729 -3.865,6.04 -10.549,9.02 -20.05,9.02 -4.833,0 -9.02,-0.727 -13.371,-2.416 l 0,-11.44 z m 24.644,-37.04 c -0.163,0 -0.322,0 -0.404,0 l -0.885,0 c -2.417,-0.082 -5.234,0.56 -7.166,1.769 -2.982,1.692 -4.51,4.753 -4.51,9.099 0,6.204 3.059,9.746 8.536,9.746 1.689,0 3.06,-0.322 4.67,-0.805 l 0,-0.888 0,-3.38 c 0,-1.45 -0.08,-3.062 -0.08,-4.754 l -0.08,-5.715 -0.081,-4.107 0,-0.965 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#082e20" /><path
|
||||
id="path25"
|
||||
d="m 211.155,21.177 c 12.399,0 19.971,7.812 19.971,20.455 0,12.966 -7.892,21.099 -20.456,21.099 -12.401,0 -20.052,-7.811 -20.052,-20.376 0,-13.047 7.893,-21.178 20.537,-21.178 z m -0.243,31.565 c 4.751,0 7.569,-3.945 7.569,-10.788 0,-6.766 -2.737,-10.792 -7.487,-10.792 -4.911,0 -7.732,3.947 -7.732,10.792 0,6.843 2.821,10.788 7.65,10.788 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#082e20" /></g></g></svg>
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
695
weirdlittleempire/static/weirdlittleempire/strides/checkout.json
Normal file
695
weirdlittleempire/static/weirdlittleempire/strides/checkout.json
Normal file
@@ -0,0 +1,695 @@
|
||||
{
|
||||
"plugins":[
|
||||
[
|
||||
"BootstrapContainerPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"media_queries":{
|
||||
"xs":[
|
||||
"(max-width: 768px)"
|
||||
],
|
||||
"lg":[
|
||||
"(min-width: 1200px)"
|
||||
],
|
||||
"sm":[
|
||||
"(min-width: 768px)",
|
||||
"(max-width: 992px)"
|
||||
],
|
||||
"md":[
|
||||
"(min-width: 992px)",
|
||||
"(max-width: 1200px)"
|
||||
]
|
||||
},
|
||||
"container_max_widths":{
|
||||
"xs":750,
|
||||
"lg":1170,
|
||||
"sm":750,
|
||||
"md":970
|
||||
},
|
||||
"extra_inline_styles:Paddings":{
|
||||
"padding-top":"",
|
||||
"padding-bottom":"30px"
|
||||
},
|
||||
"fluid":"",
|
||||
"breakpoints":[
|
||||
"xs",
|
||||
"sm",
|
||||
"md",
|
||||
"lg"
|
||||
]
|
||||
},
|
||||
"pk":14488
|
||||
},
|
||||
[
|
||||
[
|
||||
"SegmentPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"open_tag":"if",
|
||||
"condition":"customer.is_recognized"
|
||||
},
|
||||
"pk":14489
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapRowPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"extra_css_classes":[
|
||||
"foo",
|
||||
"bar",
|
||||
"cap"
|
||||
],
|
||||
"hide_plugin":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-top":"",
|
||||
"margin-bottom":"20px"
|
||||
}
|
||||
},
|
||||
"pk":14490
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"sm-responsive-utils":"",
|
||||
"xs-responsive-utils":"",
|
||||
"md-column-offset":"",
|
||||
"sm-column-width":"col-sm-10",
|
||||
"md-responsive-utils":"",
|
||||
"xs-column-offset":"",
|
||||
"sm-column-offset":"col-sm-offset-1",
|
||||
"sm-column-ordering":"",
|
||||
"md-column-ordering":"",
|
||||
"lg-column-ordering":"",
|
||||
"lg-column-offset":"col-lg-offset-2",
|
||||
"md-column-width":"",
|
||||
"xs-column-width":"col-xs-12",
|
||||
"lg-responsive-utils":"",
|
||||
"container_max_widths":{
|
||||
"xs":720.0,
|
||||
"lg":750.0,
|
||||
"sm":595.0,
|
||||
"md":778.33
|
||||
},
|
||||
"lg-column-width":"col-lg-8",
|
||||
"xs-column-ordering":""
|
||||
},
|
||||
"pk":14491
|
||||
},
|
||||
[
|
||||
[
|
||||
"ProcessBarPlugin",
|
||||
{
|
||||
"glossary":{},
|
||||
"pk":14492
|
||||
},
|
||||
[
|
||||
[
|
||||
"ProcessStepPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"hide_plugin":"",
|
||||
"step_title":"Addresses"
|
||||
},
|
||||
"pk":14500
|
||||
},
|
||||
[
|
||||
[
|
||||
"CheckoutAddressPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"allow_use_primary":"",
|
||||
"allow_multiple":"on",
|
||||
"address_form":"shipping",
|
||||
"render_type":"form",
|
||||
"hide_plugin":"",
|
||||
"headline_legend":"on"
|
||||
},
|
||||
"pk":14503
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"CheckoutAddressPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"allow_use_primary":"on",
|
||||
"allow_multiple":"on",
|
||||
"address_form":"billing",
|
||||
"render_type":"form",
|
||||
"hide_plugin":"",
|
||||
"headline_legend":"on"
|
||||
},
|
||||
"pk":14504
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"RequiredFormFieldsPlugin",
|
||||
{
|
||||
"glossary":{},
|
||||
"pk":14502
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"ProcessNextStepPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"icon_align":"icon-right",
|
||||
"symbol":"right-open",
|
||||
"button_size":"",
|
||||
"quick_float":"pull-right",
|
||||
"button_options":[],
|
||||
"icon_font":"4",
|
||||
"link_content":"Next",
|
||||
"button_type":"btn-success",
|
||||
"hide_plugin":""
|
||||
},
|
||||
"pk":14501
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"ProcessStepPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"step_title":"Customer"
|
||||
},
|
||||
"pk":14493
|
||||
},
|
||||
[
|
||||
[
|
||||
"SegmentPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"open_tag":"if",
|
||||
"condition":"customer.is_registered"
|
||||
},
|
||||
"pk":14494
|
||||
},
|
||||
[
|
||||
[
|
||||
"CustomerFormPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"form"
|
||||
},
|
||||
"pk":14495
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"SegmentPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"open_tag":"else",
|
||||
"condition":""
|
||||
},
|
||||
"pk":14496
|
||||
},
|
||||
[
|
||||
[
|
||||
"GuestFormPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"form"
|
||||
},
|
||||
"pk":14497
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"RequiredFormFieldsPlugin",
|
||||
{
|
||||
"glossary":{},
|
||||
"pk":14499
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"ProcessNextStepPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"icon_align":"icon-right",
|
||||
"symbol":"right-open",
|
||||
"button_size":"",
|
||||
"quick_float":"pull-right",
|
||||
"button_options":[],
|
||||
"icon_font":"4",
|
||||
"link_content":"Next",
|
||||
"button_type":"btn-success",
|
||||
"hide_plugin":""
|
||||
},
|
||||
"pk":14498
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"ProcessStepPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"hide_plugin":"",
|
||||
"step_title":"Payment"
|
||||
},
|
||||
"pk":14505
|
||||
},
|
||||
[
|
||||
[
|
||||
"HeadingPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"content":"Bezahlen und Versenden",
|
||||
"element_id":"",
|
||||
"tag_type":"h3"
|
||||
},
|
||||
"pk":14512
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"ShopCartPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"summary"
|
||||
},
|
||||
"pk":14511
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"PaymentMethodFormPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"form"
|
||||
},
|
||||
"pk":14506
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"ShippingMethodFormPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"form"
|
||||
},
|
||||
"pk":14507
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"ExtraAnnotationFormPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"form"
|
||||
},
|
||||
"pk":14508
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"RequiredFormFieldsPlugin",
|
||||
{
|
||||
"glossary":{},
|
||||
"pk":14509
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"ProcessNextStepPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"icon_align":"icon-right",
|
||||
"symbol":"right-open",
|
||||
"button_size":"",
|
||||
"quick_float":"pull-right",
|
||||
"button_options":[],
|
||||
"icon_font":"4",
|
||||
"link_content":"Next",
|
||||
"button_type":"btn-success",
|
||||
"hide_plugin":""
|
||||
},
|
||||
"pk":14510
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"ProcessStepPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"hide_plugin":"",
|
||||
"step_title":"Summary"
|
||||
},
|
||||
"pk":14513
|
||||
},
|
||||
[
|
||||
[
|
||||
"HeadingPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"content":"Summary of your Order",
|
||||
"element_id":"",
|
||||
"tag_type":"h3",
|
||||
"hide_plugin":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-right":"",
|
||||
"margin-top":"",
|
||||
"margin-left":"",
|
||||
"margin-bottom":""
|
||||
}
|
||||
},
|
||||
"pk":14518
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"ShopCartPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"static"
|
||||
},
|
||||
"pk":14514
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"SegmentPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"open_tag":"if",
|
||||
"condition":"customer.is_registered"
|
||||
},
|
||||
"pk":14519
|
||||
},
|
||||
[
|
||||
[
|
||||
"CustomerFormPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"summary"
|
||||
},
|
||||
"pk":14520
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"SegmentPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"open_tag":"else",
|
||||
"condition":""
|
||||
},
|
||||
"pk":14521
|
||||
},
|
||||
[
|
||||
[
|
||||
"GuestFormPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"summary"
|
||||
},
|
||||
"pk":14522
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"PaymentMethodFormPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"summary"
|
||||
},
|
||||
"pk":14515
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"ShippingMethodFormPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"summary"
|
||||
},
|
||||
"pk":14516
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"ExtraAnnotationFormPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"render_type":"summary"
|
||||
},
|
||||
"pk":14517
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"AcceptConditionPlugin",
|
||||
{
|
||||
"body":"<p>I have read the <cms-plugin id=\"14526\" alt=\"Link - terms and conditions \" title=\"Link - terms and conditions\"></cms-plugin> and agree with them.</p>",
|
||||
"pk":14525
|
||||
},
|
||||
[
|
||||
[
|
||||
"TextLinkPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"link_content":"terms and conditions",
|
||||
"link":{
|
||||
"pk":15,
|
||||
"model":"cms.Page",
|
||||
"type":"cmspage",
|
||||
"section":""
|
||||
},
|
||||
"target":"",
|
||||
"title":""
|
||||
},
|
||||
"pk":14526
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"RequiredFormFieldsPlugin",
|
||||
{
|
||||
"glossary":{},
|
||||
"pk":14523
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"ShopProceedButton",
|
||||
{
|
||||
"glossary":{
|
||||
"icon_align":"icon-right",
|
||||
"symbol":"right-hand",
|
||||
"button_size":"btn-lg",
|
||||
"quick_float":"",
|
||||
"button_options":[],
|
||||
"icon_font":"4",
|
||||
"link_content":"Purchase Now",
|
||||
"link":{
|
||||
"type":"PURCHASE_NOW"
|
||||
},
|
||||
"button_type":"btn-success",
|
||||
"hide_plugin":""
|
||||
},
|
||||
"pk":14524
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"SegmentPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"open_tag":"else",
|
||||
"condition":""
|
||||
},
|
||||
"pk":14527
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapRowPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"extra_inline_styles:Paddings":{
|
||||
"padding-right":"",
|
||||
"padding-left":""
|
||||
},
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-top":"",
|
||||
"margin-bottom":"20px"
|
||||
}
|
||||
},
|
||||
"pk":14528
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"sm-responsive-utils":"",
|
||||
"xs-responsive-utils":"",
|
||||
"lg-column-offset":"",
|
||||
"sm-column-width":"col-sm-4",
|
||||
"md-responsive-utils":"",
|
||||
"xs-column-offset":"",
|
||||
"md-column-offset":"",
|
||||
"sm-column-ordering":"",
|
||||
"sm-column-offset":"",
|
||||
"lg-column-ordering":"",
|
||||
"lg-column-width":"",
|
||||
"xs-column-ordering":"",
|
||||
"xs-column-width":"col-xs-12",
|
||||
"lg-responsive-utils":"",
|
||||
"container_max_widths":{
|
||||
"xs":720.0,
|
||||
"lg":360.0,
|
||||
"sm":220.0,
|
||||
"md":293.33
|
||||
},
|
||||
"md-column-width":"",
|
||||
"md-column-ordering":""
|
||||
},
|
||||
"pk":14529
|
||||
},
|
||||
[
|
||||
[
|
||||
"ShopAuthenticationPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"form_type":"login-reset",
|
||||
"link":{
|
||||
"type":"RELOAD_PAGE"
|
||||
}
|
||||
},
|
||||
"pk":14530
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"sm-responsive-utils":"",
|
||||
"xs-responsive-utils":"",
|
||||
"md-column-offset":"",
|
||||
"sm-column-width":"col-sm-4",
|
||||
"md-responsive-utils":"",
|
||||
"xs-column-offset":"",
|
||||
"sm-column-offset":"",
|
||||
"sm-column-ordering":"",
|
||||
"md-column-ordering":"",
|
||||
"lg-column-ordering":"",
|
||||
"lg-column-offset":"",
|
||||
"md-column-width":"",
|
||||
"xs-column-width":"col-xs-12",
|
||||
"lg-responsive-utils":"",
|
||||
"container_max_widths":{
|
||||
"xs":720.0,
|
||||
"lg":360.0,
|
||||
"sm":220.0,
|
||||
"md":293.33
|
||||
},
|
||||
"lg-column-width":"",
|
||||
"xs-column-ordering":""
|
||||
},
|
||||
"pk":14531
|
||||
},
|
||||
[
|
||||
[
|
||||
"ShopAuthenticationPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"form_type":"register-user",
|
||||
"link":{
|
||||
"type":"RELOAD_PAGE"
|
||||
}
|
||||
},
|
||||
"pk":14532
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"sm-responsive-utils":"",
|
||||
"xs-responsive-utils":"",
|
||||
"md-column-offset":"",
|
||||
"sm-column-width":"col-sm-4",
|
||||
"md-responsive-utils":"",
|
||||
"xs-column-offset":"",
|
||||
"sm-column-offset":"",
|
||||
"sm-column-ordering":"",
|
||||
"md-column-ordering":"",
|
||||
"lg-column-ordering":"",
|
||||
"lg-column-offset":"",
|
||||
"md-column-width":"",
|
||||
"xs-column-width":"col-xs-12",
|
||||
"lg-responsive-utils":"",
|
||||
"container_max_widths":{
|
||||
"xs":720.0,
|
||||
"lg":360.0,
|
||||
"sm":220.0,
|
||||
"md":293.33
|
||||
},
|
||||
"lg-column-width":"",
|
||||
"xs-column-ordering":""
|
||||
},
|
||||
"pk":14533
|
||||
},
|
||||
[
|
||||
[
|
||||
"ShopAuthenticationPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"form_type":"continue-as-guest",
|
||||
"link":{
|
||||
"type":"RELOAD_PAGE"
|
||||
}
|
||||
},
|
||||
"pk":14534
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
317
weirdlittleempire/static/weirdlittleempire/strides/footer.json
Normal file
317
weirdlittleempire/static/weirdlittleempire/strides/footer.json
Normal file
@@ -0,0 +1,317 @@
|
||||
{
|
||||
"plugins":[
|
||||
[
|
||||
"BootstrapContainerPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"media_queries":{
|
||||
"xs":[
|
||||
"(max-width: 768px)"
|
||||
],
|
||||
"lg":[
|
||||
"(min-width: 1200px)"
|
||||
],
|
||||
"sm":[
|
||||
"(min-width: 768px)",
|
||||
"(max-width: 992px)"
|
||||
],
|
||||
"md":[
|
||||
"(min-width: 992px)",
|
||||
"(max-width: 1200px)"
|
||||
]
|
||||
},
|
||||
"container_max_widths":{
|
||||
"xs":750,
|
||||
"lg":1170,
|
||||
"sm":750,
|
||||
"md":970
|
||||
},
|
||||
"hide_plugin":"",
|
||||
"fluid":"",
|
||||
"breakpoints":[
|
||||
"xs",
|
||||
"sm",
|
||||
"md",
|
||||
"lg"
|
||||
]
|
||||
},
|
||||
"pk":9086
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapRowPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"extra_css_classes":[],
|
||||
"hide_plugin":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-top":"",
|
||||
"margin-bottom":""
|
||||
}
|
||||
},
|
||||
"pk":9087
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"container_max_widths":{
|
||||
"xs":157.5,
|
||||
"lg":262.5,
|
||||
"sm":157.5,
|
||||
"md":212.5
|
||||
},
|
||||
"xs-column-width":"col-xs-3"
|
||||
},
|
||||
"pk":9088
|
||||
},
|
||||
[
|
||||
[
|
||||
"HeadingPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"content":"ABOUT US",
|
||||
"element_id":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-top":"",
|
||||
"margin-bottom":"",
|
||||
"margin-left":"",
|
||||
"margin-right":""
|
||||
},
|
||||
"hide_plugin":"",
|
||||
"tag_type":"h4"
|
||||
},
|
||||
"pk":9089
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"BootstrapSecondaryMenuPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"limit":"3",
|
||||
"page_id":"shop-about",
|
||||
"hide_plugin":"",
|
||||
"render_template":"cascade/bootstrap3/secmenu-unstyled-list.html",
|
||||
"offset":"0"
|
||||
},
|
||||
"pk":9090
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"container_max_widths":{
|
||||
"xs":157.5,
|
||||
"lg":262.5,
|
||||
"sm":157.5,
|
||||
"md":212.5
|
||||
},
|
||||
"xs-column-width":"col-xs-3"
|
||||
},
|
||||
"pk":9091
|
||||
},
|
||||
[
|
||||
[
|
||||
"HeadingPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"content":"HELP & CONTACT",
|
||||
"element_id":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-top":"",
|
||||
"margin-bottom":"",
|
||||
"margin-left":"",
|
||||
"margin-right":""
|
||||
},
|
||||
"hide_plugin":"",
|
||||
"tag_type":"h4"
|
||||
},
|
||||
"pk":9092
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"BootstrapSecondaryMenuPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"limit":"100",
|
||||
"page_id":"shop-contact",
|
||||
"hide_plugin":"",
|
||||
"render_template":"cascade/bootstrap3/secmenu-unstyled-list.html",
|
||||
"offset":"0"
|
||||
},
|
||||
"pk":9093
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"container_max_widths":{
|
||||
"xs":157.5,
|
||||
"lg":262.5,
|
||||
"sm":157.5,
|
||||
"md":212.5
|
||||
},
|
||||
"xs-column-width":"col-xs-3"
|
||||
},
|
||||
"pk":9094
|
||||
},
|
||||
[
|
||||
[
|
||||
"HeadingPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"content":"MORE FROM US",
|
||||
"element_id":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-top":"",
|
||||
"margin-bottom":"",
|
||||
"margin-left":"",
|
||||
"margin-right":""
|
||||
},
|
||||
"hide_plugin":"",
|
||||
"tag_type":"h4"
|
||||
},
|
||||
"pk":9095
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"BootstrapSecondaryMenuPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"limit":"3",
|
||||
"page_id":"shop-more",
|
||||
"hide_plugin":"",
|
||||
"render_template":"cascade/bootstrap3/secmenu-unstyled-list.html",
|
||||
"offset":"0"
|
||||
},
|
||||
"pk":9096
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"container_max_widths":{
|
||||
"xs":157.5,
|
||||
"lg":262.5,
|
||||
"sm":157.5,
|
||||
"md":212.5
|
||||
},
|
||||
"xs-column-width":"col-xs-3"
|
||||
},
|
||||
"pk":9097
|
||||
},
|
||||
[
|
||||
[
|
||||
"SegmentPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"open_tag":"if",
|
||||
"condition":"user.is_anonymous"
|
||||
},
|
||||
"pk":9098
|
||||
},
|
||||
[
|
||||
[
|
||||
"HeadingPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"content":"Join Us",
|
||||
"element_id":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-top":"",
|
||||
"margin-bottom":"",
|
||||
"margin-left":"",
|
||||
"margin-right":""
|
||||
},
|
||||
"hide_plugin":"",
|
||||
"tag_type":"h4"
|
||||
},
|
||||
"pk":9099
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"BootstrapSecondaryMenuPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"page_id":"shop-membership",
|
||||
"limit":"100",
|
||||
"hide_plugin":"",
|
||||
"render_template":"cascade/bootstrap3/secmenu-unstyled-list.html",
|
||||
"offset":"0"
|
||||
},
|
||||
"pk":9100
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"SegmentPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"open_tag":"else",
|
||||
"condition":""
|
||||
},
|
||||
"pk":9101
|
||||
},
|
||||
[
|
||||
[
|
||||
"HeadingPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"content":"YOUR ACCOUNT",
|
||||
"element_id":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-top":"",
|
||||
"margin-bottom":"",
|
||||
"margin-left":"",
|
||||
"margin-right":""
|
||||
},
|
||||
"hide_plugin":"",
|
||||
"tag_type":"h4"
|
||||
},
|
||||
"pk":9102
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"BootstrapSecondaryMenuPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"page_id":"shop-personal",
|
||||
"limit":"3",
|
||||
"hide_plugin":"",
|
||||
"render_template":"cascade/bootstrap3/secmenu-unstyled-list.html",
|
||||
"offset":"0"
|
||||
},
|
||||
"pk":9103
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
859
weirdlittleempire/static/weirdlittleempire/strides/home.json
Normal file
859
weirdlittleempire/static/weirdlittleempire/strides/home.json
Normal file
@@ -0,0 +1,859 @@
|
||||
{
|
||||
"plugins":[
|
||||
[
|
||||
"BootstrapJumbotronPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"background_width_height":{
|
||||
"width":"",
|
||||
"height":""
|
||||
},
|
||||
"background_vertical_position":"center",
|
||||
"media_queries":{
|
||||
"xs":[
|
||||
"(max-width: 768px)"
|
||||
],
|
||||
"lg":[
|
||||
"(min-width: 1200px)"
|
||||
],
|
||||
"sm":[
|
||||
"(min-width: 768px)",
|
||||
"(max-width: 992px)"
|
||||
],
|
||||
"md":[
|
||||
"(min-width: 992px)",
|
||||
"(max-width: 1200px)"
|
||||
]
|
||||
},
|
||||
"background_attachment":"fixed",
|
||||
"image":{
|
||||
"pk":184,
|
||||
"model":"filer.Image"
|
||||
},
|
||||
"background_repeat":"no-repeat",
|
||||
"hide_plugin":"",
|
||||
"fluid":true,
|
||||
"container_max_heights":{
|
||||
"xs":"100%",
|
||||
"md":"100%",
|
||||
"sm":"100%",
|
||||
"lg":"100%"
|
||||
},
|
||||
"extra_inline_styles:Paddings":{
|
||||
"padding-top":"500px",
|
||||
"padding-bottom":""
|
||||
},
|
||||
"background_size":"cover",
|
||||
"resize_options":[
|
||||
"crop",
|
||||
"subject_location",
|
||||
"high_resolution"
|
||||
],
|
||||
"container_max_widths":{
|
||||
"xs":768,
|
||||
"lg":1980,
|
||||
"sm":992,
|
||||
"md":1200
|
||||
},
|
||||
"breakpoints":[
|
||||
"xs",
|
||||
"sm",
|
||||
"md",
|
||||
"lg"
|
||||
],
|
||||
"background_color":[
|
||||
"",
|
||||
"#12308b"
|
||||
],
|
||||
"background_horizontal_position":"center"
|
||||
},
|
||||
"pk":15056
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"BootstrapContainerPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"media_queries":{
|
||||
"xs":[
|
||||
"(max-width: 768px)"
|
||||
],
|
||||
"lg":[
|
||||
"(min-width: 1200px)"
|
||||
],
|
||||
"sm":[
|
||||
"(min-width: 768px)",
|
||||
"(max-width: 992px)"
|
||||
],
|
||||
"md":[
|
||||
"(min-width: 992px)",
|
||||
"(max-width: 1200px)"
|
||||
]
|
||||
},
|
||||
"container_max_widths":{
|
||||
"xs":750,
|
||||
"lg":1170,
|
||||
"sm":750,
|
||||
"md":970
|
||||
},
|
||||
"fluid":"",
|
||||
"breakpoints":[
|
||||
"xs",
|
||||
"sm",
|
||||
"md",
|
||||
"lg"
|
||||
]
|
||||
},
|
||||
"pk":15057
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapRowPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"extra_css_classes":[],
|
||||
"hide_plugin":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-top":"",
|
||||
"margin-bottom":""
|
||||
}
|
||||
},
|
||||
"pk":15058
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"container_max_widths":{
|
||||
"xs":720.0,
|
||||
"lg":1140.0,
|
||||
"sm":720.0,
|
||||
"md":940.0
|
||||
},
|
||||
"xs-column-width":"col-xs-12"
|
||||
},
|
||||
"pk":15059
|
||||
},
|
||||
[
|
||||
[
|
||||
"CarouselPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"resize_options":[
|
||||
"upscale",
|
||||
"crop",
|
||||
"subject_location",
|
||||
"high_resolution"
|
||||
],
|
||||
"container_max_heights":{
|
||||
"xs":"100px",
|
||||
"md":"200px",
|
||||
"sm":"150px",
|
||||
"lg":"250px"
|
||||
},
|
||||
"interval":"5",
|
||||
"options":[
|
||||
"slide",
|
||||
"pause",
|
||||
"wrap"
|
||||
]
|
||||
},
|
||||
"pk":15060
|
||||
},
|
||||
[
|
||||
[
|
||||
"CarouselSlidePlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"resize_options":[
|
||||
"upscale",
|
||||
"crop",
|
||||
"subject_location",
|
||||
"high_resolution"
|
||||
],
|
||||
"image":{
|
||||
"pk":170,
|
||||
"model":"filer.Image"
|
||||
},
|
||||
"image_title":"",
|
||||
"alt_tag":""
|
||||
},
|
||||
"pk":15061
|
||||
},
|
||||
[
|
||||
[
|
||||
"TextPlugin",
|
||||
{
|
||||
"body":"<h3>Django under the Hood</h3>\n\n<p>Conference ending</p>",
|
||||
"pk":15062
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"CarouselSlidePlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"resize_options":[
|
||||
"upscale",
|
||||
"crop",
|
||||
"subject_location",
|
||||
"high_resolution"
|
||||
],
|
||||
"image":{
|
||||
"pk":171,
|
||||
"model":"filer.Image"
|
||||
},
|
||||
"image_title":"",
|
||||
"alt_tag":""
|
||||
},
|
||||
"pk":15063
|
||||
},
|
||||
[
|
||||
[
|
||||
"TextPlugin",
|
||||
{
|
||||
"body":"<h1>Social Event</h1>\n\n<p>at <cms-plugin id=\"15065\" alt=\"Link - Pllek \" title=\"Link - Pllek\"></cms-plugin>, Amsterdam</p>",
|
||||
"pk":15064
|
||||
},
|
||||
[
|
||||
[
|
||||
"TextLinkPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"link_content":"Pllek",
|
||||
"link":{
|
||||
"url":"http://www.pllek.nl/",
|
||||
"type":"exturl"
|
||||
},
|
||||
"target":"",
|
||||
"title":""
|
||||
},
|
||||
"pk":15065
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"CarouselSlidePlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"resize_options":[
|
||||
"upscale",
|
||||
"crop",
|
||||
"subject_location",
|
||||
"high_resolution"
|
||||
],
|
||||
"image":{
|
||||
"pk":172,
|
||||
"model":"filer.Image"
|
||||
},
|
||||
"image_title":"",
|
||||
"alt_tag":""
|
||||
},
|
||||
"pk":15066
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"ShopProductGallery",
|
||||
{
|
||||
"glossary":{
|
||||
"hide_plugin":""
|
||||
},
|
||||
"pk":15067,
|
||||
"inlines":[
|
||||
{
|
||||
"product":{
|
||||
"pk":50
|
||||
}
|
||||
},
|
||||
{
|
||||
"product":{
|
||||
"pk":25
|
||||
}
|
||||
},
|
||||
{
|
||||
"product":{
|
||||
"pk":48
|
||||
}
|
||||
},
|
||||
{
|
||||
"product":{
|
||||
"pk":22
|
||||
}
|
||||
},
|
||||
{
|
||||
"product":{
|
||||
"pk":54
|
||||
}
|
||||
},
|
||||
{
|
||||
"product":{
|
||||
"pk":51
|
||||
}
|
||||
},
|
||||
{
|
||||
"product":{
|
||||
"pk":49
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapRowPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"extra_css_classes":[],
|
||||
"hide_plugin":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-top":"10px",
|
||||
"margin-bottom":"20px"
|
||||
}
|
||||
},
|
||||
"pk":15068
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"container_max_widths":{
|
||||
"xs":220.0,
|
||||
"lg":360.0,
|
||||
"sm":220.0,
|
||||
"md":293.33
|
||||
},
|
||||
"xs-column-width":"col-xs-4"
|
||||
},
|
||||
"pk":15069
|
||||
},
|
||||
[
|
||||
[
|
||||
"FramedIconPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"font_size":"10em",
|
||||
"color":"#470a31",
|
||||
"background_color":[
|
||||
"",
|
||||
"#c8ffcd"
|
||||
],
|
||||
"symbol":"heart-empty-2",
|
||||
"hide_plugin":"",
|
||||
"text_align":"text-center",
|
||||
"icon_font":"4",
|
||||
"border_radius":"50%",
|
||||
"border":[
|
||||
"3px",
|
||||
"dotted",
|
||||
"#000000"
|
||||
]
|
||||
},
|
||||
"pk":15070
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"container_max_widths":{
|
||||
"xs":220.0,
|
||||
"lg":360.0,
|
||||
"sm":220.0,
|
||||
"md":293.33
|
||||
},
|
||||
"xs-column-width":"col-xs-4"
|
||||
},
|
||||
"pk":15071
|
||||
},
|
||||
[
|
||||
[
|
||||
"FramedIconPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"font_size":"10em",
|
||||
"color":"#470a31",
|
||||
"background_color":[
|
||||
"",
|
||||
"#c8ffcd"
|
||||
],
|
||||
"symbol":"linux",
|
||||
"hide_plugin":"",
|
||||
"text_align":"text-center",
|
||||
"icon_font":"4",
|
||||
"border_radius":"50%",
|
||||
"border":[
|
||||
"3px",
|
||||
"solid",
|
||||
"#000000"
|
||||
]
|
||||
},
|
||||
"pk":15072,
|
||||
"shared_glossary":"HeadIcon"
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"container_max_widths":{
|
||||
"xs":220.0,
|
||||
"lg":360.0,
|
||||
"sm":220.0,
|
||||
"md":293.33
|
||||
},
|
||||
"xs-column-width":"col-xs-4"
|
||||
},
|
||||
"pk":15073
|
||||
},
|
||||
[
|
||||
[
|
||||
"FramedIconPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"font_size":"10em",
|
||||
"color":"#470a31",
|
||||
"background_color":[
|
||||
"",
|
||||
"#c8ffcd"
|
||||
],
|
||||
"symbol":"windows",
|
||||
"hide_plugin":"",
|
||||
"text_align":"text-center",
|
||||
"icon_font":"4",
|
||||
"border_radius":"50%",
|
||||
"border":[
|
||||
"3px",
|
||||
"solid",
|
||||
"#000000"
|
||||
]
|
||||
},
|
||||
"pk":15074,
|
||||
"shared_glossary":"HeadIcon"
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapRowPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"extra_css_classes":[],
|
||||
"hide_plugin":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-top":"",
|
||||
"margin-bottom":"30px"
|
||||
}
|
||||
},
|
||||
"pk":15075
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"sm-responsive-utils":"",
|
||||
"xs-responsive-utils":"",
|
||||
"md-column-offset":"",
|
||||
"sm-column-width":"col-sm-6",
|
||||
"md-responsive-utils":"",
|
||||
"xs-column-offset":"",
|
||||
"sm-column-offset":"",
|
||||
"sm-column-ordering":"",
|
||||
"md-column-ordering":"",
|
||||
"lg-column-ordering":"",
|
||||
"lg-column-offset":"",
|
||||
"lg-column-width":"",
|
||||
"xs-column-width":"col-xs-12",
|
||||
"lg-responsive-utils":"",
|
||||
"container_max_widths":{
|
||||
"xs":720.0,
|
||||
"lg":555.0,
|
||||
"sm":345.0,
|
||||
"md":455.0
|
||||
},
|
||||
"md-column-width":"",
|
||||
"xs-column-ordering":""
|
||||
},
|
||||
"pk":15076
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapPanelPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"heading_size":"",
|
||||
"panel_type":"panel-warning",
|
||||
"heading":"Panel Heading",
|
||||
"hide_plugin":"",
|
||||
"footer":"Panel Footer"
|
||||
},
|
||||
"pk":15077
|
||||
},
|
||||
[
|
||||
[
|
||||
"LeafletPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"hide_plugin":"",
|
||||
"map_position":{
|
||||
"lat":47.944636605532914,
|
||||
"lng":12.570934295654299,
|
||||
"zoom":12
|
||||
},
|
||||
"render_template":"cascade/plugins/googlemap.html",
|
||||
"map_height":"400px",
|
||||
"map_width":"100%"
|
||||
},
|
||||
"pk":15078,
|
||||
"inlines":[
|
||||
{
|
||||
"position":{
|
||||
"lat":47.92554522341879,
|
||||
"lng":12.618141174316406
|
||||
},
|
||||
"popup_text":null,
|
||||
"title":"Marker",
|
||||
"marker_width":"",
|
||||
"marker_anchor":{
|
||||
"top":"",
|
||||
"left":""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapColumnPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"sm-responsive-utils":"",
|
||||
"xs-responsive-utils":"",
|
||||
"md-column-offset":"",
|
||||
"sm-column-width":"col-sm-6",
|
||||
"md-responsive-utils":"",
|
||||
"xs-column-offset":"",
|
||||
"sm-column-offset":"",
|
||||
"sm-column-ordering":"",
|
||||
"md-column-ordering":"",
|
||||
"lg-column-ordering":"",
|
||||
"lg-column-offset":"",
|
||||
"md-column-width":"",
|
||||
"xs-column-width":"col-xs-12",
|
||||
"lg-responsive-utils":"",
|
||||
"container_max_widths":{
|
||||
"xs":720.0,
|
||||
"lg":555.0,
|
||||
"sm":345.0,
|
||||
"md":455.0
|
||||
},
|
||||
"lg-column-width":"",
|
||||
"xs-column-ordering":""
|
||||
},
|
||||
"pk":15079
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapAccordionPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"hide_plugin":"",
|
||||
"close_others":"on",
|
||||
"first_is_open":"on"
|
||||
},
|
||||
"pk":15080
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapAccordionPanelPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"heading_size":"",
|
||||
"panel_type":"panel-success",
|
||||
"panel_title":"First"
|
||||
},
|
||||
"pk":15081
|
||||
},
|
||||
[
|
||||
[
|
||||
"TextPlugin",
|
||||
{
|
||||
"body":"<p>Nullam id dolor id nibh ultricies vehicula ut id elit. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. <cms-plugin id=\"15083\" alt=\"Link - Donec \" title=\"Link - Donec\"></cms-plugin> id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit sit amet non magna.</p>",
|
||||
"pk":15082
|
||||
},
|
||||
[
|
||||
[
|
||||
"TextLinkPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"link_content":"Donec",
|
||||
"link":{
|
||||
"pk":25,
|
||||
"model":"cms.Page",
|
||||
"type":"cmspage",
|
||||
"section":""
|
||||
},
|
||||
"target":"",
|
||||
"title":""
|
||||
},
|
||||
"pk":15083
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapAccordionPanelPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"heading_size":"",
|
||||
"panel_type":"panel-success",
|
||||
"panel_title":"Second"
|
||||
},
|
||||
"pk":15084
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapImagePlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"image_width_responsive":"",
|
||||
"target":"",
|
||||
"title":"",
|
||||
"image":{
|
||||
"pk":1,
|
||||
"model":"filer.Image"
|
||||
},
|
||||
"alt_tag":"",
|
||||
"image_width_fixed":"",
|
||||
"image_height":"",
|
||||
"link":{
|
||||
"type":"none"
|
||||
},
|
||||
"resize_options":[
|
||||
"upscale",
|
||||
"crop",
|
||||
"subject_location",
|
||||
"high_resolution"
|
||||
],
|
||||
"image_title":"Django Pony",
|
||||
"image_shapes":[
|
||||
"img-responsive"
|
||||
]
|
||||
},
|
||||
"pk":15085
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapTabSetPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"justified":"on"
|
||||
},
|
||||
"pk":15086
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapTabPanePlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"tab_title":"Left"
|
||||
},
|
||||
"pk":15087
|
||||
},
|
||||
[
|
||||
[
|
||||
"TextPlugin",
|
||||
{
|
||||
"body":"<h3>Vestibulum id ligula porta felis euismod semper</h3>\n\n<p><cms-plugin id=\"15091\" alt='Icon - fontawesome: <i class=\"icon-retweet\"></i> ' title='Icon - fontawesome: <i class=\"icon-retweet\"></i>'></cms-plugin>\u00a0Vestibulum <cms-plugin id=\"15092\" alt='Icon - fontawesome: <i class=\"icon-camera-alt\"></i> ' title='Icon - fontawesome: <i class=\"icon-camera-alt\"></i>'></cms-plugin>\u00a0id ligula porta felis euismod semper. <cms-plugin id=\"15089\" alt=\"Link - Nullam \" title=\"Link - Nullam\"></cms-plugin> id dolor id nibh ultricies vehicula ut id elit. <cms-plugin id=\"15090\" alt=\"Link - Cras \" title=\"Link - Cras\"></cms-plugin> mattis consectetur purus sit amet fermentum. <cms-plugin id=\"15093\" alt=\"Link - Donec \" title=\"Link - Donec\"></cms-plugin> sed odio dui. Integer posuere erat a ante venenatis dapibus posuere velit aliquet.</p>",
|
||||
"pk":15088
|
||||
},
|
||||
[
|
||||
[
|
||||
"TextLinkPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"link_content":"Nullam",
|
||||
"link":{
|
||||
"pk":56,
|
||||
"model":"myshop.Product",
|
||||
"type":"product"
|
||||
},
|
||||
"target":"",
|
||||
"title":""
|
||||
},
|
||||
"pk":15089
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"TextLinkPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"link_content":"Cras",
|
||||
"link":{
|
||||
"pk":55,
|
||||
"model":"myshop.Product",
|
||||
"type":"product"
|
||||
},
|
||||
"target":"",
|
||||
"title":""
|
||||
},
|
||||
"pk":15090
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"TextIconPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"icon_font":"4",
|
||||
"symbol":"retweet"
|
||||
},
|
||||
"pk":15091
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"TextIconPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"icon_font":"4",
|
||||
"symbol":"camera-alt"
|
||||
},
|
||||
"pk":15092
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"TextLinkPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"link_content":"Donec",
|
||||
"link":{
|
||||
"pk":50,
|
||||
"model":"myshop.Product",
|
||||
"type":"product"
|
||||
},
|
||||
"target":"",
|
||||
"title":""
|
||||
},
|
||||
"pk":15093
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapButtonPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"icon_align":"icon-right",
|
||||
"symbol":"angle-circled-right",
|
||||
"button_size":"btn-lg",
|
||||
"quick_float":"",
|
||||
"button_options":[],
|
||||
"icon_font":"4",
|
||||
"link_content":"Proceed",
|
||||
"link":{
|
||||
"pk":54,
|
||||
"model":"myshop.Product",
|
||||
"type":"product"
|
||||
},
|
||||
"button_type":"btn-info",
|
||||
"hide_plugin":""
|
||||
},
|
||||
"pk":15094
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
"BootstrapTabPanePlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"tab_title":"Right"
|
||||
},
|
||||
"pk":15095
|
||||
},
|
||||
[
|
||||
[
|
||||
"BootstrapSecondaryMenuPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"page_id":"shop-order",
|
||||
"hide_plugin":"",
|
||||
"render_template":"cascade/bootstrap3/secmenu-list-group.html"
|
||||
},
|
||||
"pk":15096
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
"HeadingPlugin",
|
||||
{
|
||||
"glossary":{
|
||||
"content":"Heading with Anchor",
|
||||
"element_id":"anchor1",
|
||||
"tag_type":"h1",
|
||||
"hide_plugin":"",
|
||||
"extra_inline_styles:Margins":{
|
||||
"margin-right":"",
|
||||
"margin-top":"10px",
|
||||
"margin-bottom":"10px",
|
||||
"margin-left":""
|
||||
}
|
||||
},
|
||||
"pk":15097
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
1
weirdlittleempire/templates/400.html
Normal file
1
weirdlittleempire/templates/400.html
Normal file
@@ -0,0 +1 @@
|
||||
{% extends "weirdlittleempire/pages/error.html" %}
|
||||
1
weirdlittleempire/templates/403.html
Normal file
1
weirdlittleempire/templates/403.html
Normal file
@@ -0,0 +1 @@
|
||||
{% extends "weirdlittleempire/pages/error.html" %}
|
||||
1
weirdlittleempire/templates/404.html
Normal file
1
weirdlittleempire/templates/404.html
Normal file
@@ -0,0 +1 @@
|
||||
{% extends "weirdlittleempire/pages/error.html" %}
|
||||
@@ -0,0 +1 @@
|
||||
{% extends "shop/cart/editable.html" %}
|
||||
@@ -0,0 +1,12 @@
|
||||
{% extends "shop/catalog/available-product-add2cart.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block available-quantity-in-stock %}{# intentionally empty #}{% endblock %}
|
||||
|
||||
{% block change-purchasing-quantity %}
|
||||
<div class="d-flex flex-column w-25" ng-hide="context.availability.quantity">
|
||||
<div class="lead mt-1">
|
||||
{% trans "This item has already been sold" %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,23 @@
|
||||
{% extends "weirdlittleempire/pages/default.html" %}
|
||||
{% load cms_tags sekizai_tags sass_tags %}
|
||||
|
||||
{% block title %}{{ product.product_name }}{% endblock %}
|
||||
|
||||
{% block breadcrumb %}{% with extra_ance=product.product_name %}
|
||||
{% if product.show_breadcrumb %}{% include "shop/breadcrumb/default.html" %}{% endif %}
|
||||
{% endwith %}{% endblock %}
|
||||
|
||||
{% block main-content %}
|
||||
{# the first `render_placeholder` is only required for editing the page #}
|
||||
{% render_placeholder product.placeholder %}{% render_placeholder product.placeholder as product_details %}
|
||||
{% if not product_details %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1>{% render_model product "product_name" %}</h1>
|
||||
<p class="lead">Edit this page, then switch into <em>Structure</em> mode and add plugins to placeholder <code> {{ product.placeholder.slot }} </code>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock main-content %}
|
||||
@@ -0,0 +1,9 @@
|
||||
{% load static sekizai_tags %}
|
||||
|
||||
{% addtoblock "js" %}<script src="{% static 'shop/js/filter-form.js' %}" type="text/javascript"></script>{% endaddtoblock %}
|
||||
{% add_data "ng-requires" "django.shop.filter" %}
|
||||
|
||||
<form shop-product-filter="manufacturer" style="margin-bottom: 10px;">
|
||||
{{ filter.filter_set.form.as_div }}
|
||||
</form>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{% extends "weirdlittleempire/pages/default.html" %}
|
||||
{% load cms_tags sekizai_tags sass_tags %}
|
||||
|
||||
{% block title %}{{ product.product_name }}{% endblock %}
|
||||
|
||||
{% block breadcrumb %}{% with extra_ance=product.product_name %}
|
||||
{% include "shop/breadcrumb/default.html" %}
|
||||
{% endwith %}{% endblock %}
|
||||
|
||||
{% block main-content %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1>{% render_model product "product_name" %}</h1>
|
||||
{# the first `render_placeholder` is only required for editing the page #}
|
||||
{% render_placeholder product.placeholder %}{% render_placeholder product.placeholder as product_details %}
|
||||
{% if not product_details %}
|
||||
<p class="lead">Edit this page, then switch into <em>Structure</em> mode and add plugins to placeholder <code> {{ product.placeholder.slot }} </code>.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock main-content %}
|
||||
@@ -0,0 +1,36 @@
|
||||
{% extends "weirdlittleempire/catalog/product-detail.html" %}
|
||||
{% load i18n cms_tags thumbnail %}
|
||||
|
||||
{% block main-content %}
|
||||
{% thumbnail product.images.first 250x250 crop as thumb %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col col-md-10 offset-md-1">
|
||||
<h1>{% render_model product "product_name" %}</h1>
|
||||
<div class="media mb-3 flex-column flex-md-row">
|
||||
<img class="mr-3 mb-3" src="{{ thumb.url }}" width="{{ thumb.width }}" height="{{ thumb.height }}" alt="{{ product.product_name }}">
|
||||
<div class="media-body">
|
||||
{{ product.description|safe }}
|
||||
</div>
|
||||
</div>
|
||||
<h4>{% trans "Details" %}</h4>
|
||||
<ul class="list-group mb-3">
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">{% trans "Card Type" %}:</div>
|
||||
<strong>{{ product.get_card_type_display }}</strong>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">{% trans "Storage capacity" %}:</div>
|
||||
<strong>{{ product.storage }} GB</strong>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">{% trans "Manufacturer" %}:</div>
|
||||
<strong>{{ product.manufacturer }}</strong>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- include "Add to Cart" dialog box -->
|
||||
{% include "shop/catalog/available-product-add2cart.html" with card_css_classes="mb-3" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock main-content %}
|
||||
@@ -0,0 +1,18 @@
|
||||
{% extends "shop/catalog/available-product-add2cart.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block add-to-cart-url %}{{ product.get_absolute_url }}/add-smartphone-to-cart{% endblock %}
|
||||
|
||||
{% block available-quantity-in-stock %}
|
||||
<div class="d-flex flex-column">
|
||||
<label for="product_code">{% trans "Internal Storage" %}</label>
|
||||
<select class="form-control" name="product_code" ng-model="context.product_code" ng-change="updateContext()" >
|
||||
{% for smartphone in product.variants.all %}
|
||||
<option value="{{ smartphone.product_code }}">
|
||||
{% if smartphone.storage == 0 %}{% trans "Pluggable" %}{% else %}{{ smartphone.storage }} GB{% endif %}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,71 @@
|
||||
{% extends "weirdlittleempire/catalog/product-detail.html" %}
|
||||
{% load i18n static cms_tags sekizai_tags sass_tags %}
|
||||
|
||||
{% block main-content %}
|
||||
|
||||
{% addtoblock "css" %}<link href="{% sass_src 'shop/css/bsp-scrollpanel.scss' %}" rel="stylesheet" type="text/css" />{% endaddtoblock %}
|
||||
|
||||
{% addtoblock "js" %}<script src="{% static 'node_modules/angular-bootstrap-plus/src/scrollpanel/scrollpanel.js' %}" type="text/javascript"></script>{% endaddtoblock %}
|
||||
{% add_data "ng-requires" "bs-plus.scrollpanel" %}
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col col-md-10 offset-md-1">
|
||||
<h1>{% render_model product "product_name" %}</h1>
|
||||
<bsp-scrollpanel class="shop-product-detail">
|
||||
<ul>{% for img in product.images.all %}
|
||||
<li><img src="{{ img.url }}" alt="{{ product.product_name }}" /></li>
|
||||
{% endfor %}</ul>
|
||||
</bsp-scrollpanel>
|
||||
</div>
|
||||
<div class="col col-md-10 offset-md-1">
|
||||
<h4>{% trans "Details" %}</h4>
|
||||
{{ product.description|safe }}
|
||||
<ul class="list-group mb-3">
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">{% trans "Manufacturer" %}:</div>
|
||||
<strong>{{ product.manufacturer }}</strong>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">{% trans "Battery" %}:</div>
|
||||
<strong>{{ product.get_battery_type_display }} ({{ product.battery_capacity }} mAh)</strong>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">{% trans "RAM Storage" %}:</div>
|
||||
<strong>{{ product.ram_storage }} MB</strong>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">{% trans "WiFi Connectivity" %}:</div>
|
||||
<strong>{{ product.wifi_connectivity }}</strong>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">Bluetooth:</div>
|
||||
<strong>{{ product.get_bluetooth_display }}</strong>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">GPS:</div>
|
||||
<strong><i class="fa {{ product.gps|yesno:'fa-check,fa-times' }}"></i></strong>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">{% trans "Dimensions" %}:</div>
|
||||
<strong>{{ product.width }} mm (w) × {{ product.height }} mm (h)</strong>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">{% trans "Weight" %}:</div>
|
||||
<strong>{{ product.weight }} g</strong>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div class="w-50">{% trans "Screen size" %}:</div>
|
||||
<strong>{{ product.screen_size }} ({% trans "inch" %})</strong>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- include "Add to Cart" dialog box -->
|
||||
{% include "weirdlittleempire/catalog/smartphone-add2cart.html" with use_modal_dialog=True card_css_classes="mb-3" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "shop/catalog/bsp-scrollpanel.tmpl.html" %}
|
||||
|
||||
{% endblock main-content %}
|
||||
@@ -0,0 +1,6 @@
|
||||
{% extends "shop/email/base.html" %}
|
||||
{% load post_office %}
|
||||
|
||||
{% block email-logo %}
|
||||
<img src="{% inline_image 'weirdlittleempire/django-shop-logo.png' %}" width="200" style="margin: 20px auto; display: block;" />
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,6 @@
|
||||
{% extends "shop/email/password-reset-body.html" %}
|
||||
{% load post_office %}
|
||||
|
||||
{% block email-logo %}
|
||||
<img src="{% inline_image 'weirdlittleempire/django-shop-logo.png' %}" width="200" style="margin: 20px auto; display: block;" />
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,6 @@
|
||||
{% extends "shop/email/register-user-body.html" %}
|
||||
{% load post_office %}
|
||||
|
||||
{% block email-logo %}
|
||||
<img src="{% inline_image 'weirdlittleempire/django-shop-logo.png' %}" width="200" style="margin: 20px auto; display: block;" />
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,67 @@
|
||||
{% load static cms_tags sekizai_tags djng_tags i18n %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ LANGUAGE_CODE }}" ng-app="myShop">
|
||||
<head>
|
||||
<title>{% block title %}django SHOP demo{% endblock %}</title>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="robots" content="{{ ROBOTS_META_TAGS }}" />
|
||||
<meta name="description" content="{% block meta-description %}{% endblock %}" />
|
||||
{% block head %}{% endblock head %}
|
||||
{% render_block "css" postprocessor "compressor.contrib.sekizai.compress" %}
|
||||
</head>
|
||||
|
||||
{% addtoblock "js" %}<script src="{% static 'node_modules/angular/angular.min.js' %}" type="text/javascript"></script>{% endaddtoblock %}
|
||||
{% addtoblock "js" %}<script src="{% static 'node_modules/angular-sanitize/angular-sanitize.min.js' %}" type="text/javascript"></script>{% endaddtoblock %}
|
||||
{% addtoblock "js" %}<script src="{% static 'node_modules/angular-i18n/' %}{% djng_locale_script 'de' %}" type="text/javascript"></script>{% endaddtoblock %}
|
||||
{% addtoblock "js" %}<script src="{% static 'node_modules/angular-animate/angular-animate.min.js' %}" type="text/javascript"></script>{% endaddtoblock %}
|
||||
|
||||
<body>
|
||||
{% cms_toolbar %}
|
||||
<header>
|
||||
{% block header %}{% endblock %}
|
||||
</header>
|
||||
|
||||
{% block toast-messages %}{% include "shop/messages.html" %}{% endblock %}
|
||||
|
||||
<main>
|
||||
{% block breadcrumb %}{% endblock %}
|
||||
|
||||
{% block main-content %}
|
||||
<div class="container">
|
||||
<div class="row shop-starter-template">
|
||||
<div class="col">
|
||||
<h1>Base Template</h1>
|
||||
<p class="lead">This document does not contain any content yet.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock main-content %}
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
{% block footer %}{% endblock footer %}
|
||||
</footer>
|
||||
|
||||
{% render_block "js" postprocessor "compressor.contrib.sekizai.compress" %}
|
||||
<script type="text/javascript">
|
||||
angular.module('myShop', ['ngAnimate', 'ngSanitize', {% with_data "ng-requires" as ng_requires %}
|
||||
{% for module in ng_requires %}'{{ module }}'{% if not forloop.last %}, {% endif %}{% endfor %}{% end_with_data %}
|
||||
]).config(['$httpProvider', '$locationProvider', '$sanitizeProvider', function($httpProvider, $locationProvider, $sanitizeProvider) {
|
||||
$httpProvider.defaults.headers.common['X-CSRFToken'] = '{{ csrf_token }}';
|
||||
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
$locationProvider.html5Mode({
|
||||
enabled: true,
|
||||
requireBase: false,
|
||||
rewriteLinks: false
|
||||
});
|
||||
$sanitizeProvider.addValidAttrs(['srcset']);
|
||||
}]){% with_data "ng-config" as configs %}
|
||||
{% for config in configs %}.config({{ config }}){% endfor %};
|
||||
{% end_with_data %}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
{% extends "weirdlittleempire/pages/base.html" %}
|
||||
{% load static cms_tags i18n sekizai_tags sass_tags %}
|
||||
|
||||
{% block title %}{% page_attribute "page_title" %}{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{{ block.super }}
|
||||
{% addtoblock "css" %}<link href="{% sass_src 'weirdlittleempire/css/default.scss' %}" rel="stylesheet" type="text/css" />{% endaddtoblock %}
|
||||
{% endblock head %}
|
||||
|
||||
{% block header %}
|
||||
{% include "weirdlittleempire/pages/navbar.html" with navbar_classes="navbar-expand-lg navbar-light bg-light fixed-top" %}
|
||||
{% endblock header %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{% placeholder "Breadcrumb" %}
|
||||
{% endblock breadcrumb %}
|
||||
|
||||
{% block main-content %}{% placeholder "Main Content" inherit or %}
|
||||
<div class="container">
|
||||
<div class="row shop-starter-template">
|
||||
<div class="col">
|
||||
<h1>Default Template</h1>
|
||||
<p class="lead">Use this placeholder as a quick way to start editing a new CMS page.<br/>
|
||||
All you have to do is to append <code>?edit</code> to the URL and switch to “Structure” mode.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endplaceholder %}{% endblock main-content %}
|
||||
|
||||
{% block footer %}{% static_placeholder "Static Footer" or %}
|
||||
<div class="container">
|
||||
<p class="text-muted">Place sticky footer content here.</p>
|
||||
</div>
|
||||
{% endstatic_placeholder %}{% endblock footer %}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{% extends "weirdlittleempire/pages/default.html" %}%}
|
||||
{% load i18n cms_tags %}
|
||||
|
||||
{% block breadcrumb %}{% endblock %}
|
||||
|
||||
{% page_url 'shop-login' as login_url %}
|
||||
|
||||
{% block main-content %}
|
||||
<div class="container mt-5">
|
||||
<div class="row">
|
||||
<div class="col col-sm-10 col-md-8 offset-sm-1 offset-md-2">
|
||||
<h3>{{ detail|default:"Forbidden" }}</h3>
|
||||
{% if status_code == 403 and login_url %}
|
||||
<p>{% blocktrans %}In case you have ordered anything on this site before, please <a href="{{ login_url }}">sign in</a> and try again.{% endblocktrans %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,49 @@
|
||||
{% extends "bootstrap4/includes/ng-nav-navbar.html" %}
|
||||
{% load static i18n cms_tags menu_tags sekizai_tags sass_tags shop_tags %}
|
||||
{% spaceless %}
|
||||
|
||||
{% page_url 'shop-watch-list' as shop_watch_list_url %}{% if not shop_watch_list_url %}{% url "shop-watch-list" as shop_watch_list_url %}{% endif %}
|
||||
|
||||
{% block navbar %}
|
||||
<div class="container">
|
||||
{% block navbar-brand %}
|
||||
<div class="shop-brand-icon">
|
||||
<a href="/">
|
||||
<img src="{% static 'weirdlittleempire/django-shop-logo.svg' %}" alt="django-SHOP" aria-hidden="true">
|
||||
</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block navbar-toggler %}{{ block.super }}{% endblock %}
|
||||
|
||||
<div class="collapse navbar-collapse" uib-collapse="isNavCollapsed">
|
||||
<ul class="navbar-nav flex-wrap align-content-between w-100">
|
||||
<li class="nav-item shop-social-icons">{% static_placeholder "Social Icons" %}</li>
|
||||
<li class="mx-auto"></li>
|
||||
{% include "shop/navbar/login-logout.html" with item_class="shop-secondary-menu" %}
|
||||
{% with item_class="shop-secondary-menu" %}{% language_chooser "shop/navbar/language-chooser.html" %}{% endwith %}
|
||||
{% include "shop/navbar/watch-icon.html" with item_class="shop-secondary-menu" %}
|
||||
{% with item_class="shop-secondary-menu" %}
|
||||
{% if current_page.reverse_id == 'shop-cart' or current_page.reverse_id == 'shop-watch-list' %}
|
||||
{% cart_icon without %}
|
||||
{% else %}
|
||||
{% cart_icon unsorted %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<li class="w-100"></li>
|
||||
{% with item_class="nav-item shop-primary-menu" %}{% block navbar-nav %}{{ block.super }}{% endblock %}{% endwith %}
|
||||
<li class="nav-item shop-search-form">{% include "shop/navbar/search-form.html" with search_form_classes="form-inline" %}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% addtoblock "js" %}<script src="{% static 'node_modules/ui-bootstrap4/dist/ui-bootstrap-tpls.js' %}" type="text/javascript"></script>{% endaddtoblock %}
|
||||
{% add_data "ng-requires" "ui.bootstrap" %}
|
||||
|
||||
{% addtoblock "js" %}<script src="{% static 'cms_bootstrap/js/ng-nav-navbar.js' %}" type="text/javascript"></script>{% endaddtoblock %}
|
||||
{% addtoblock "js" %}<script src="{% static 'shop/js/navbar.js' %}" type="text/javascript"></script>{% endaddtoblock %}
|
||||
{% add_data "ng-requires" "django.shop.navbar" %}
|
||||
|
||||
{% endblock navbar %}
|
||||
|
||||
{% endspaceless %}
|
||||
@@ -0,0 +1,54 @@
|
||||
{% load static i18n cascade_tags djng_tags sekizai_tags sass_tags %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ LANGUAGE_CODE }}" ng-app="myShop">
|
||||
<head>
|
||||
<title>Test page</title>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="{{ ROBOTS_META_TAGS }}" />
|
||||
<meta name="description" content="{% block meta-description %}{% endblock %}" />
|
||||
{% block head %}{% endblock head %}
|
||||
{% render_block "css" postprocessor "shop.sekizai_processors.compress" %}
|
||||
</head>
|
||||
|
||||
{% addtoblock "css" %}<link href="{% sass_src 'weirdlittleempire/css/default.scss' %}" rel="stylesheet" type="text/css" />{% endaddtoblock %}
|
||||
|
||||
{% addtoblock "js" %}<script src="{% static 'node_modules/angular/angular.min.js' %}" type="text/javascript"></script>{% endaddtoblock %}
|
||||
{% addtoblock "js" %}<script src="{% static 'node_modules/angular-sanitize/angular-sanitize.min.js' %}"></script>{% endaddtoblock %}
|
||||
{% addtoblock "js" %}<script src="{% static 'node_modules/angular-i18n/' %}{% djng_locale_script 'de' %}"></script>{% endaddtoblock %}
|
||||
{% addtoblock "js" %}<script src="{% static 'node_modules/angular-animate/angular-animate.min.js' %}"></script>{% endaddtoblock %}
|
||||
|
||||
<body>
|
||||
<header>
|
||||
{% include "weirdlittleempire/pages/navbar.html" with navbar_classes="navbar-default navbar-fixed-top" %}
|
||||
</header>
|
||||
|
||||
<main>
|
||||
{% render_cascade "weirdlittleempire/strides/home.json" %}
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
{% block footer %}{% endblock footer %}
|
||||
</footer>
|
||||
|
||||
{% render_block "js" postprocessor "shop.sekizai_processors.compress" %}
|
||||
<script type="text/javascript">
|
||||
angular.module('myShop', ['ngAnimate', 'ngSanitize', {% with_data "ng-requires" as ng_requires %}
|
||||
{% for module in ng_requires %}'{{ module }}'{% if not forloop.last %}, {% endif %}{% endfor %}{% end_with_data %}
|
||||
]).config(['$httpProvider', '$locationProvider', function($httpProvider, $locationProvider) {
|
||||
$httpProvider.defaults.headers.common['X-CSRFToken'] = '{{ csrf_token }}';
|
||||
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
$locationProvider.html5Mode({
|
||||
enabled: true,
|
||||
requireBase: false,
|
||||
rewriteLinks: false
|
||||
});
|
||||
}]){% with_data "ng-config" as configs %}
|
||||
{% for config in configs %}.config({{ config }}){% endfor %};
|
||||
{% end_with_data %}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{% extends "shop/print/delivery-note.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block header %}
|
||||
<img src="{% static 'weirdlittleempire/django-shop-logo.svg' %}" class="shop-logo" alt="django-SHOP" height="45">
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,6 @@
|
||||
{% extends "shop/print/invoice.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block header %}
|
||||
<img src="{% static 'weirdlittleempire/django-shop-logo.svg' %}" class="shop-logo" alt="django-SHOP" height="45">
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,2 @@
|
||||
{% extends "shop/products/cart-product-media.html" %}
|
||||
{% block sample-image %}{% include "shop/products/sample-image.html" %}{% endblock %}
|
||||
@@ -0,0 +1,4 @@
|
||||
{% load thumbnail %}
|
||||
{% thumbnail product.sample_image 244x244 crop as thumb %}
|
||||
{% thumbnail product.sample_image 488x488 crop as thumb2 %}
|
||||
<img class="img-fluid" src="{{ thumb.url }}" width="{{ thumb.width }}" height="{{ thumb.height }}" srcset="{{ thumb.url }} 1x, {{ thumb2.url }} 2x" />
|
||||
@@ -0,0 +1,7 @@
|
||||
{% extends "shop/products/dropdown-product-media.html" %}
|
||||
{% load thumbnail %}
|
||||
{% block sample-image %}
|
||||
{% thumbnail product.sample_image 50x50 crop as thumb %}
|
||||
{% thumbnail product.sample_image 100x100 crop as thumb2 %}
|
||||
<img class="mr-1" width="{{ thumb.width }}" height="{{ thumb.height }}" src="{{ thumb.url }}" srcset="{{ thumb.url }} 1x, {{ thumb2.url }} 2x" />
|
||||
{% endblock %}
|
||||
@@ -0,0 +1 @@
|
||||
{% extends "shop/products/sample-image.path" %}
|
||||
@@ -0,0 +1,2 @@
|
||||
{% extends "shop/products/order-product-media.html" %}
|
||||
{% block sample-image %}{% include "shop/products/sample-image.html" %}{% endblock %}
|
||||
@@ -0,0 +1,2 @@
|
||||
{% extends "shop/products/print-product-media.html" %}
|
||||
{% block print-image %}{% include "shop/products/print-image.html" %}{% endblock %}
|
||||
@@ -0,0 +1,2 @@
|
||||
{% extends "shop/products/search-product-media.html" %}
|
||||
{% block sample-image %}{% include "shop/products/sample-image.html" %}{% endblock %}
|
||||
@@ -0,0 +1,5 @@
|
||||
{% extends "weirdlittleempire/products/search-product-media.html" %}
|
||||
{% block media-body %}
|
||||
<h4 class="media-heading"><a href="{{ product.get_absolute_url }}">{{ product.product_name }}</a></h4>
|
||||
{{ product.description|truncatewords_html:50 }}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,5 @@
|
||||
{% extends "weirdlittleempire/products/search-product-media.html" %}
|
||||
{% block media-body %}
|
||||
<h4 class="media-heading"><a href="{{ product.get_absolute_url }}">{{ product.product_name }}</a></h4>
|
||||
{{ product.caption|truncatewords_html:50 }}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1 @@
|
||||
{% extends "weirdlittleempire/products/cart-product-media.html" %}
|
||||
@@ -0,0 +1,3 @@
|
||||
{% load shop_search_tags %}
|
||||
{% include "weirdlittleempire/search/indexes/product.txt" %}
|
||||
{% render_placeholder product.placeholder %}
|
||||
@@ -0,0 +1,3 @@
|
||||
{{ product.caption }}
|
||||
{{ product.manufacturer }}{% for page in product.cms_pages.public %}
|
||||
{{ page.get_title }}{% endfor %}
|
||||
@@ -0,0 +1,3 @@
|
||||
{% include "weirdlittleempire/search/indexes/product.txt" %}
|
||||
{{ product.description }}
|
||||
{{ product.get_card_type_display }} {{ product.storage }}GB
|
||||
@@ -0,0 +1,4 @@
|
||||
{% include "myshop/search/indexes/product.txt" %}
|
||||
{{ product.description }}
|
||||
{{ product.operating_system }}{% for variant in product.get_product_variants %}
|
||||
{{ variant.storage}}GB{% endfor %}
|
||||
34
weirdlittleempire/urls.py
Normal file
34
weirdlittleempire/urls.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
from django.conf.urls import url, include
|
||||
from django.conf.urls.i18n import i18n_patterns
|
||||
from django.contrib import admin
|
||||
from django.contrib.sitemaps.views import sitemap
|
||||
from django.http import HttpResponse
|
||||
from cms.sitemaps import CMSSitemap
|
||||
from weirdlittleempire.sitemap import ProductSitemap
|
||||
|
||||
sitemaps = {'cmspages': CMSSitemap,
|
||||
'products': ProductSitemap}
|
||||
|
||||
|
||||
def render_robots(request):
|
||||
permission = 'noindex' in settings.ROBOTS_META_TAGS and 'Disallow' or 'Allow'
|
||||
return HttpResponse('User-Agent: *\n%s: /\n' % permission, content_type='text/plain')
|
||||
|
||||
|
||||
i18n_urls = (
|
||||
url(r'^admin/', admin.site.urls),
|
||||
url(r'^', include('cms.urls')),
|
||||
)
|
||||
urlpatterns = [
|
||||
url(r'^robots\.txt$', render_robots),
|
||||
url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, name='sitemap'),
|
||||
url(r'^shop/', include('shop.urls')),
|
||||
]
|
||||
if settings.USE_I18N:
|
||||
urlpatterns.extend(i18n_patterns(*i18n_urls))
|
||||
else:
|
||||
urlpatterns.extend(i18n_urls)
|
||||
urlpatterns.extend(
|
||||
static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT))
|
||||
Reference in New Issue
Block a user