Init Django-SHOP

This commit is contained in:
2021-02-23 22:57:30 +00:00
parent 8842939839
commit b4a79a6890
109 changed files with 5734 additions and 160 deletions

View 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()

View 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)

View 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.')

View 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)

View 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)

View File

@@ -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.")

View 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)

View 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