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 ''
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.'
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 )
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 ''
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 ''
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
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 }
def settings(self): """ Return the CMS/Shop settings object (cached). """ return get_cms_settings()
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
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
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') }