Beispiel #1
0
 def render(self, context):
     settings = get_cms_settings()
     if settings and settings.image_placeholder_id:
         shape = value_or_literal(self.shape, context)
         return self.render_image(settings.image_placeholder, shape, noscript=False)
     else:
         return ''
Beispiel #2
0
    def configure(self, request, instance=None, edit=True):
        super(PageForm, self).configure(request, instance, edit)

        # generate list of entity type choices based on all django models
        # that subclass from PageBase (but not Page itself).
        choices = [('', '-------')]
        for model in get_models():
            if issubclass(model, ChildPage):
                choices.append((model.__name__, model._meta.verbose_name))
        self.fields['entity_type'].choices = choices

        # navigation
        if edit or self.is_duplicate:
            self.fields['nav'].initial = instance.nav

        # parent page only available if hierarchical pages is enabled
        if not settings.PAGE_HIERARCHY:
            self.remove_field('parent')
            self.update_sections()

        # 404 page cannot be disabled!
        cms_settings = get_cms_settings()
        if instance and cms_settings.default_404 and instance.pk == cms_settings.default_404.pk:
            self.fields['disabled'].widget.attrs['disabled'] = True
            self.fields[
                'disabled'].help_text = 'This page is configured as the default 404 (Page Not Found) page and can therefore not be disabled.'
            self.fields['sitemap'].widget.attrs['disabled'] = True
            self.fields[
                'sitemap'].help_text = 'This page is configured as the default 404 (Page Not Found) page and can therefore not be excluded from the sitemap.'
Beispiel #3
0
def verify_barcode(barcode_system, barcode_digits):
    """
    Raises BarcodeError if the given barcode of the given system is invalid.
    Returns the full barcode as a sequence of digits (string) without any
    formatting characters.
    """
    # pick default barcode system from settings, if no barcode system
    # has been defined...
    if barcode_system is None:
        if 'cubane.cms' in settings.INSTALLED_APPS:
            from cubane.cms.views import get_cms_settings
            cms_settings = get_cms_settings()
            barcode_system = cms_settings.barcode_system

    # remove invalid digits from barcode to begin with
    if barcode_digits is not None:
        barcode_digits = re.sub(r'[^\d]', '', barcode_digits)

    # get decoder based on system
    try:
        system = barcode.get_barcode_class(barcode_system)
    except barcode.errors.BarcodeNotFoundError, e:
        raise BarcodeError(
            'The barcode system \'%s\' is not known or invalid.' % barcode_system
        )
Beispiel #4
0
def site_notification():
    """
    Render notification message if configured in settings.
    """
    if settings.CUBANE_SITE_NOTIFICATION:
        cms_settings = get_cms_settings()
        if cms_settings.notification_enabled and cms_settings.notification_text:
            return mark_safe('<div class="cubane-notification-container" style="background-color: #b94a48; color: white; font-family: Arial, Helvetica, sans-serif; padding: 15px 0; margin: 0; line-height: 1.25em; font-size: 16px;"><div class="cubane-notification" style="max-width: 1200px; margin: 0 auto; padding: 0;">%s</div></div>' % cms_settings.notification_text)

    return ''
Beispiel #5
0
def background_image_placeholder(context, shape):
    """
    Renders the missing image placeholder image if configured in settings as
    a background image.
    """
    settings = get_cms_settings()
    if settings and settings.image_placeholder_id:
        return render_background_image_attr(settings.image_placeholder, shape)
    else:
        return ''
Beispiel #6
0
    def inventory_export(self, request):
        """
        Shop Inventory Export (CSV).
        """
        # create exporter and export inventory data
        exporter = ShopInventoryExporter()
        f = exporter.export_to_temp_file(encoding=request.GET.get('encoding'))

        # generate filename based on today's date
        cms_settings = get_cms_settings()
        today = datetime.date.today()
        filename = '{0}__{1:02d}_{2:02d}_{3:04d}.csv'.format(
            slugify(cms_settings.name).replace('-', '_'), today.day,
            today.month, today.year)

        # serve file
        response = FileResponse(f)
        response['Content-Type'] = 'text/csv'
        response[
            'Content-Disposition'] = 'attachment; filename="%s"' % filename
        return response
Beispiel #7
0
    def sku(self, request):
        # get product
        product_id = request.GET.get('pk')
        product = get_object_or_404(get_product_model(), pk=product_id)

        # get varieties
        _varieties = Variety.objects.prefetch_related(
            Prefetch('options',
                     queryset=VarietyOption.objects.order_by('title'))
        ).filter(sku=True).exclude(options=None).exclude(
            style=Variety.STYLE_ATTRIBUTE).order_by('title').distinct()
        skus = ProductSKU.objects.filter(product=product)
        assigned_option_ids = [
            a.variety_option.id
            for a in VarietyAssignment.objects.select_related('variety_option')
            .filter(product=product, variety_option__variety__sku=True)
        ]

        # initial dataset currently present
        initial = {}
        for sku in skus:
            initial[sku.pk] = sku
            initial[sku.pk].errors = []

        # determine barcode system
        cms_settings = get_cms_settings()
        barcode_system = cms_settings.get_barcode_system(product)

        # create template form
        form_template = ProductSKUForm()
        form_template.configure(request, barcode_system)

        def has_var(prefix, name):
            return 'f-%s-%s' % (prefix, name) in request.POST

        def get_var(prefix, name, default=None):
            return request.POST.get('f-%s-%s' % (prefix, name), default)

        def get_int_var(prefix, name, default=None):
            return parse_int(get_var(prefix, name), default)

        # construct list of variety option names
        varieties = []
        variety_index = {}
        for variety in _varieties:
            variety_index[variety.id] = {
                'id': variety.id,
                'title': variety.title,
                'sku': variety.sku,
                'options': {}
            }

            item = {
                'id': variety.id,
                'title': variety.title,
                'sku': variety.sku,
                'options': [],
                'n_assigned_options': 0
            }
            for option in variety.options.all():
                variety_index[variety.id].get('options')[option.id] = {
                    'id': option.id,
                    'title': option.title,
                    'fullTitle':
                    '%s: <em>%s</em>' % (variety.title, option.title)
                }
                item.get('options').append({
                    'id':
                    option.id,
                    'title':
                    option.title,
                    'assigned':
                    option.id in assigned_option_ids
                })
                if option.pk in assigned_option_ids:
                    item['n_assigned_options'] += 1
            varieties.append(item)

        # sort varieties by number of assigned options, so that varieties that
        # have been assigned are at the top of the list. The rest remains sorted
        # alphabetically...
        varieties.sort(key=lambda x: -x.get('n_assigned_options', 0))

        # validation
        is_valid = True
        if request.method == 'POST':
            # process sku records
            prefixes = request.POST.getlist('skus')
            assigned_option_ids = []
            skus_to_save = []
            sku_code_processed = []
            barcodes_processed = []
            for index, prefix in enumerate(prefixes):
                # extract relevant informatioin from post for
                # individual combination
                _id = get_var(prefix, '_id')
                d = {
                    'enabled': get_var(prefix, 'enabled') == 'on',
                    'sku': get_var(prefix, 'sku'),
                    'barcode': get_var(prefix, 'barcode'),
                    'price': get_var(prefix, 'price'),
                    'stocklevel': get_int_var(prefix, 'stocklevel', 0)
                }

                # parse assigned variety options from request data
                n_variety_option = 1
                d['variety_options'] = []
                while len(d['variety_options']) <= 16:
                    _name = 'vo_%d' % n_variety_option
                    if has_var(prefix, _name):
                        d['variety_options'].append(get_int_var(prefix, _name))
                        n_variety_option += 1
                    else:
                        break

                # make sure that sku, barcode and price are None
                # instead of empty
                if _id == '': _id = None
                if d.get('sku') == '': d['sku'] = None
                if d.get('barcode') == '': d['barcode'] = None
                if d.get('price') == '': d['price'] = None

                # construct form based on this data and validate
                form = ProductSKUForm(d)
                form.configure(request, barcode_system)

                # get variety options
                variety_options = VarietyOption.objects.filter(
                    pk__in=d.get('variety_options'))

                # create or edit?
                sku = initial.get(_id, None)
                if sku is None:
                    sku = ProductSKU.objects.get_by_variety_options(
                        product, variety_options)

                    # still not found? -> create new item
                    if sku is None:
                        sku = ProductSKU()
                        sku.product = product

                # remember the sku record to be saved once we processed
                # everything. We will not save anything until everything
                # is considered to be valid.
                skus_to_save.append(sku)

                # mark any assigned variety options as selected, so that they
                # indeed remain selected, even if they have actually not been
                # properly assigned yet because if from errors for example
                for _variety in varieties:
                    _options = _variety.get('options')
                    for _option in _options:
                        for _assigned_option in variety_options:
                            if _option.get('id') == _assigned_option.pk:
                                _option['assigned'] = True
                                break

                # inject error information and keep track of error states
                sku.errors = []
                if form.is_valid():
                    # update data from from
                    d = form.cleaned_data
                else:
                    for field, error in form.errors.items():
                        sku.errors.append({'field': field, 'error': error[0]})
                    is_valid = False

                # copy original data or cleaned data
                sku.enabled = d.get('enabled', False)
                sku.sku = d.get('sku')
                sku.barcode = d.get('barcode')
                sku.price = d.get('price')
                sku.stocklevel = d.get('stocklevel', 0)

                # keep track of variety options that should be assigned due to
                # SKU's that are enabled
                if sku.enabled:
                    assigned_option_ids.extend(
                        [option.pk for option in variety_options])

                # set variety options (saved later)
                sku._variety_options = variety_options

                # verify uniqueness of the SKU code
                if not self._verify_sku(product, sku, sku_code_processed,
                                        initial):
                    is_valid = False

                # verify uniqueness of barcode
                if not self._verify_barcode(product, sku, barcodes_processed,
                                            initial):
                    is_valid = False

                # maintain changed data in initial data set, so that all
                # changes make theire way back into the view, even through
                # we might not have saved changes due to errors
                _id = ('idx_%d' % index) if sku.pk is None else sku.pk
                initial[_id] = sku

        # process if everything is valid
        if request.method == 'POST' and is_valid:
            # create missing option assignments
            assigned_option_ids = list(
                set(filter(lambda x: x is not None, assigned_option_ids)))
            for option_id in assigned_option_ids:
                try:
                    assignment = VarietyAssignment.objects.get(
                        product=product, variety_option__pk=option_id)
                except VarietyAssignment.DoesNotExist:
                    VarietyAssignment.objects.create(
                        product=product, variety_option_id=option_id)

            # remove deprecated option assignments
            deprecated_assignments = VarietyAssignment.objects.select_related(
                'variety_option').filter(
                    product=product,
                    variety_option__variety__sku=True).exclude(
                        variety_option__pk__in=assigned_option_ids)
            for deprecated_assignment in deprecated_assignments:
                deprecated_assignment.delete()

            # save changes to sku records. Null sku, so that we would not
            # collide when making updates
            sku_ids_saved = []
            for sku in skus_to_save:
                # save product sku itself
                sku._sku = sku.sku
                sku.sku = None
                sku.save()
                sku_ids_saved.append(sku.id)

                # assign and save variety options
                sku.variety_options = sku._variety_options

            # remove all previous SKU
            deprecated_skus = ProductSKU.objects.filter(
                product=product).exclude(pk__in=sku_ids_saved)
            for deprecated_sku in deprecated_skus:
                deprecated_sku.delete()

            # apply new sku names, which is now safe to do
            for sku in skus_to_save:
                if request.settings.sku_is_barcode:
                    sku.sku = sku.barcode
                else:
                    sku.sku = sku._sku
                sku.save()

        # redirect and message
        if request.method == 'POST' and is_valid:
            messages.add_message(
                request, messages.SUCCESS,
                'Product Varieties and SKUs saved for <em>%s</em>.' %
                product.title)

            if request.POST.get('cubane_save_and_continue') is None:
                return self._redirect(request, 'index')
            else:
                return self._redirect(request, 'sku', product)

        # materialise current initial data
        _initial = {}
        for _id, _sku in initial.items():
            _initial[_id] = model_to_dict(_sku)
            if _sku.pk is None:
                _initial[_id]['variety_options'] = [
                    option.pk for option in _sku._variety_options
                ]
            else:
                _initial[_id]['variety_options'] = [
                    option.pk for option in _sku.variety_options.all()
                ]
            _initial[_id]['errors'] = _sku.errors if hasattr(_sku,
                                                             'errors') else []

        # template context
        return {
            'product': product,
            'varieties': varieties,
            'initial': to_json(_initial),
            'variety_index_json': to_json(variety_index),
            'form_template': form_template
        }
Beispiel #8
0
 def settings(self):
     """
     Return the CMS/Shop settings object (cached).
     """
     return get_cms_settings()
Beispiel #9
0
    def download(self, request):
        """
        Download individual or multiple media assets. Multiple media assets are
        zipped.
        """
        # get pks
        pks = get_pks(request.GET)

        # get list of media
        media = Media.objects.filter(pk__in=pks).order_by('caption')
        n_media = media.count()

        # no media?
        if n_media == 0:
            raise Http404(
                'Unable to export media assets for empty list of media objects.'
            )

        # single media item?
        if n_media == 1:
            item = media.first()
            response = FileResponse(open(item.original_path, 'rb'))
            response[
                'Content-Disposition'] = 'attachment; filename="%s"' % item.filename
            return response

        # multiple assets -> create zip file
        f = NamedTemporaryFile()
        zf = zipfile.ZipFile(f, 'w')

        # attach original files to zip, handle duplicated filenames
        filenames = {}
        for item in media:
            # determine unique filename
            filename = item.filename
            if filename not in filenames:
                filenames[filename] = 1
            else:
                fn = filename
                base, ext = os.path.splitext(filename)
                while fn in filenames:
                    filenames[fn] += 1
                    fn = '%s-%d%s' % (base, filenames[fn], ext)
                filename = fn
                filenames[filename] = 1

            # attach file to zip...
            zf.write(item.original_path, filename)
        zf.close()
        f.seek(0)

        # determine site name from settings (CMS)
        if 'cubane.cms' in settings.INSTALLED_APPS:
            from cubane.cms.views import get_cms_settings
            site_name = get_cms_settings().name
            if site_name is None: site_name = ''
            site_name = slugify(site_name)
            if site_name != '': site_name += '_'
        else:
            site_name = ''

        # generate download filename for zip file
        today = datetime.date.today()
        filename = '{0}media_{1:02d}_{2:02d}_{3:04d}.zip'.format(
            site_name, today.day, today.month, today.year)

        # serve file
        response = FileResponse(f)
        response[
            'Content-Disposition'] = 'attachment; filename="%s"' % filename
        return response
Beispiel #10
0
 def set_settings_vars(self, settings_dict):
     settings = get_cms_settings()
     for item in settings_dict:
         setattr(settings, item, settings_dict[item])
     settings.save()
     return settings
Beispiel #11
0
    def inventory_import(self, request):
        """
        Shop Inventory Import (CSV).
        """
        # default encoding
        initial = {'encoding': get_cms_settings().default_encoding}

        if request.method == 'POST':
            form = ShopInventoryImportForm(request.POST, request.FILES)
        else:
            form = ShopInventoryImportForm(initial=initial)
            form.configure(request)

            export_form = ShopInventoryExportForm(initial=initial)
            export_form.configure(request)

        if request.method == 'POST' and form.is_valid():
            d = form.cleaned_data

            # create importer and import date
            importer = ShopInventoryImporter()
            importer.import_from_stream(request,
                                        request.FILES['csvfile'],
                                        encoding=d.get('encoding'))

            # present information what happend during import
            if importer.has_errors:
                transaction.rollback()

                errors = importer.get_formatted_errors()
                messages.add_message(
                    request, messages.ERROR,
                    ('Import failed due to %s. No data ' +
                     'has been imported. Please correct all issues ' +
                     'and try again.') %
                    pluralize(len(errors), 'error', tag='em'))

                for message in errors:
                    messages.add_message(request, messages.ERROR, message)

                # redirect to itself if we have errors
                return HttpResponseRedirect(
                    get_absolute_url(
                        'cubane.ishop.inventory.inventory_import'))
            else:
                # success message, render image processing page
                messages.add_message(
                    request, messages.SUCCESS,
                    pluralize(importer.num_records_processed,
                              'record',
                              'processed successfully',
                              tag='em'))

                # redirect to itself if we have errors
                return HttpResponseRedirect(
                    get_absolute_url(
                        'cubane.ishop.inventory.inventory_import'))

        return {
            'form':
            form,
            'export_form':
            export_form,
            'export_form_action':
            reverse('cubane.ishop.inventory.inventory_export')
        }