class FilteredCollectionIndex(CollectionIndex): inclusions = schema.ListField(schema.SchemaField(CollectionFilter), blank=True) exclusions = schema.ListField(schema.SchemaField(CollectionFilter), blank=True) parameters = schema.ListField(schema.SchemaField(CollectionParam), blank=True) def get_index(self): document = self.get_document() index = document.objects.all() inclusions = list() exclusions = list() params = list() for collection_filter in self.inclusions: inclusions.append(collection_filter.get_query_filter_operation()) for collection_filter in self.exclusions: exclusions.append(collection_filter.get_query_filter_operation()) for param in self.parameters: params.append(param.get_query_filter_operation()) index = index._add_filter_parts(inclusions=inclusions, exclusions=exclusions, indexes=params) return index def save(self, *args, **kwargs): ret = super(FilteredCollectionIndex, self).save(*args, **kwargs) self.get_index().commit() return ret class Meta: typed_key = 'dockitcms.filteredcollection'
class ListingViewPoint(BaseViewPoint): list_view = schema.SchemaField(ListViewPoint) detail_view = schema.SchemaField(DetailViewPoint) class Meta: typed_key = 'dockitcms.listing' def register_view_endpoints(self, site): self.list_view.register_view_endpoints(site) self.detail_view.register_view_endpoints(site)
class ModelWidgets(schema.Document): ''' Associates a model with a set of defined widgets ''' content_type = schema.ModelReferenceField(ContentType) object_id = schema.CharField() widgets = schema.ListField(schema.SchemaField(BlockWidget))
class SchemaEntry(FieldEntry, DesignMixin): #inherit_from = SchemaDesignChoiceField(blank=True) fields = schema.ListField(schema.SchemaField(FieldEntry)) object_label = schema.CharField(blank=True) class Meta: proxy = True
class ThumbnailField(BaseFieldEntry): thumbnails = schema.ListField( schema.SchemaField(ThumbnailFieldEntrySchema)) field_class = properties.ThumbnailField def get_field_kwargs(self): kwargs = super(ThumbnailField, self).get_field_kwargs() if kwargs.get('verbose_name', None) == '': del kwargs['verbose_name'] thumbnails = kwargs.pop('thumbnails', list()) config = {'thumbnails': dict()} for thumb in thumbnails: key = thumb.pop('key') for key, value in thumb.items(): if value is None: thumb.pop(key) resize = {} for key in ['width', 'height', 'crop', 'upscale']: if key in thumb: resize[key] = thumb.pop(key) if resize: thumb['resize'] = resize config['thumbnails'][key] = thumb kwargs['config'] = config return kwargs class Meta: typed_key = 'ThumbnailField'
class ThumbnailsSchema(GeneratedThumbnailSchema): thumbnails = schema.DictField( value_subfield=schema.SchemaField(GeneratedThumbnailSchema)) def pil_image(self): file_obj = self.image file_obj.open() file_obj.seek(0) try: return Image.open(file_obj) except IOError: file_obj.seek(0) cf = ContentFile(file_obj.read()) return Image.open(cf) def reprocess_info(self, config): source_image = self.pil_image() self.info = process_image_info(source_image) self.config = config def reprocess_thumbnail_info(self, config): source_image = self.pil_image() for key, thumbnail in self.thumbnails.iteritems(): if key in config['thumbnails']: cfg = config['thumbnails'][key] info = process_image_info(source_image, cfg) thumbnail.info = info def reprocess_thumbnails(self, config, force_reprocess=False): base_name, base_ext = os.path.splitext( os.path.basename(self.image.name)) source_image = self.pil_image() for key, cfg in config['thumbnails'].iteritems(): if not force_reprocess and key in self.thumbnails and self.thumbnails[ key].config == cfg: continue thumb_name = '%s-%s%s' % (base_name, key, base_ext) self.thumbnails[key] = self._process_thumbnail( source_image, thumb_name, cfg) def reprocess(self, config, force_reprocess=False): self.reprocess_info(config) self.reprocess_thumbnails(config, force_reprocess=force_reprocess) def _process_thumbnail(self, source_image, thumb_name, config): img, info = process_image(source_image, config) image_field = self._meta.fields['image'] storage = image_field.storage thumb_name = storage.get_available_name(thumb_name) #not efficient, requires image to be loaded into memory thumb_fobj = ContentFile(img_to_fobj(img, info).read()) thumb_name = storage.save(thumb_name, thumb_fobj) return GeneratedThumbnailSchema(**{ 'image': thumb_name, 'config': config, 'info': info })
class FlatMenuWidget(BaseTemplateWidget): entries = schema.ListField(schema.SchemaField(FlatMenuEntry)) class Meta: typed_key = 'widgetblock.flatmenuwidget' def get_context(self, context): context = BaseTemplateWidget.get_context(self, context) #TODO find the active menu entry return context
class PageDefinition(SchemaEntry): unique_id = schema.CharField(default=uuid.uuid4, editable=False) templates = schema.ListField(schema.SchemaField(TemplateEntry)) def get_template(self, name): for candidate in self.templates: if candidate.path == name: return candidate.get_template_object() #CONSIDER: perhaps a page definition should have a default template return None
class ChoiceField(BaseFieldEntry): choices = schema.ListField(schema.SchemaField(ChoiceOptionSchema)) field_class = schema.CharField def get_field_kwargs(self): kwargs = super(ChoiceField, self).get_field_kwargs() kwargs['choices'] = [(entry['value'], entry['label']) for entry in kwargs['choices']] return kwargs class Meta: typed_key = 'ChoiceField'
class CTAWidget(BaseTemplateWidget): template_name = schema.CharField(blank=True, default='widgetblock/cta_widget.html') default_url = schema.CharField() width = schema.CharField() height = schema.CharField() delay = schema.DecimalField(help_text=_("Display interval of each item"), max_digits=5, decimal_places=2, default=5) images = schema.ListField(schema.SchemaField(CTAImage)) class Meta: typed_key = 'widgetblock.ctawidget'
class FlatMenuWidget(BaseTemplateWidget): template_name = schema.CharField(blank=True, default='widgetblock/menu_widget.html') entries = schema.ListField(schema.SchemaField(FlatMenuEntry)) class Meta: typed_key = 'widgetblock.flatmenuwidget' def get_context(self, context): context = BaseTemplateWidget.get_context(self, context) #TODO find the active menu entry return context
class TemporaryDocument(schema.Document): _tempinfo = schema.SchemaField(TemporaryDocumentInfo) @classmethod def generate_document(cls, document): class GeneratedTempDocument(cls): class Meta: proxy = True fields = deepcopy(document._meta.fields) #handle dynamic typing if document._meta.typed_field: GeneratedTempDocument._meta.typed_field = document._meta.typed_field GeneratedTempDocument._meta.typed_key = document._meta.typed_key t_field = fields[document._meta.typed_field] orignal_schemas = t_field.schemas t_field.schemas = SchemaProxyDict(orignal_schemas) GeneratedTempDocument._meta.fields.update(fields) GeneratedTempDocument._meta.original_document = document for name, value in GeneratedTempDocument._meta.fields.iteritems(): if hasattr(value, 'contribute_to_class'): value.contribute_to_class(GeneratedTempDocument, name) else: setattr(GeneratedTempDocument, name, value) return GeneratedTempDocument def commit_changes(self, doc_id=None): document_cls = self._meta.original_document backend = get_document_backend() id_field = backend.get_id_field_name() data = self.to_primitive(self) data[id_field] = doc_id data.pop('_tempinfo', None) instance = document_cls(_primitive_data=data) instance.save() return instance @classmethod def create_from_instance(cls, instance): backend = get_document_backend() data = instance.to_primitive(instance) instance_id = data.pop(backend.get_id_field_name(), None) obj = cls.to_python(data) obj._original_id = instance_id return obj
class FilteredModelIndex(ModelIndex): inclusions = schema.ListField(schema.SchemaField(ModelFilter), blank=True) exclusions = schema.ListField(schema.SchemaField(ModelFilter), blank=True) parameters = schema.ListField(schema.SchemaField(ModelParam), blank=True) def get_index(self): model = self.get_model() index = model.objects.all() inclusions = list() exclusions = list() params = list() for collection_filter in self.inclusions: inclusions.append(collection_filter.get_query_filter_operation()) for collection_filter in self.exclusions: exclusions.append(collection_filter.get_query_filter_operation()) if inclusions: index = index.filter(*inclusions) if exclusions: index = index.exclude(*exclusions) return index class Meta: typed_key = 'dockitcms.filteredmodel'
class PublicCollectionResource(PublicResource): collection = schema.ReferenceField(Collection) view_points = schema.ListField(schema.SchemaField(BaseViewPoint)) @property def cms_resource(self): return self.collection.get_collection_resource() def get_public_resource_kwargs(self, **kwargs): kwargs.setdefault('view_points', self.view_points) return super(PublicCollectionResource, self).get_public_resource_kwargs(**kwargs) class Meta: typed_key = 'collection'
class BaseCollection(schema.Document): application = schema.ReferenceField(Application) admin_options = schema.SchemaField(AdminOptions) title = None @permalink def get_admin_manage_url(self): return ('admin:dockitcms_basecollection_manage', [self.pk], {}) def admin_manage_link(self): url = self.get_admin_manage_url() return u'<a href="%s">%s</a>' % (url, _('Manage')) admin_manage_link.short_description = _('Manage') admin_manage_link.allow_tags = True class Meta: typed_field = 'collection_type' verbose_name = 'collection'
class CTAWidget(BaseTemplateWidget): default_url = schema.CharField() width = schema.CharField() height = schema.CharField() delay = schema.DecimalField(help_text=_("Display interval of each item"), max_digits=5, decimal_places=2, default=5) images = schema.ListField(schema.SchemaField( CTAImage)) #TODO the following will be an inline when supported class Meta: typed_key = 'widgetblock.ctawidget' @classmethod def get_admin_form_class(cls): from forms import CTAWidgetForm return CTAWidgetForm
class DocumentDesign(schema.Document, DesignMixin): title = schema.CharField() inherit_from = SchemaDesignChoiceField(blank=True) fields = schema.ListField(schema.SchemaField(FieldEntry), blank=True) object_label = schema.CharField(blank=True) def __unicode__(self): return self.title or '' def get_schema_name(self): return str(''.join([capfirst(part) for part in self.title.split()])) def get_document_kwargs(self, **kwargs): kwargs = DesignMixin.get_document_kwargs(self, **kwargs) if self.inherit_from: parent = self._meta.fields['inherit_from'].get_schema( self.inherit_from) if parent: if issubclass(parent, schema.Document): kwargs['parents'] = (parent, ) else: kwargs['parents'] = (parent, schema.Document) return kwargs
class ModelWidgets(schema.Document): content_type = schema.ModelReferenceField(ContentType) object_id = schema.CharField() widgets = schema.ListField(schema.SchemaField(BlockWidget))
class PageCollection(Collection): title = schema.CharField() page_definitions = schema.ListField(schema.SchemaField(PageDefinition)) def get_collection_name(self): return 'dockitcms.virtual.%s' % self.key def get_schema_name(self): return str(''.join([part for part in self.title.split()])) def register_collection(self): #create a base page document params = { 'module': 'dockitcms.models.virtual', 'virtual': False, 'verbose_name': self.title, 'collection': self.get_collection_name(), 'parents': (BasePage, schema.Document), 'name': self.get_schema_name(), 'attrs': SortedDict(), 'fields': SortedDict(), 'typed_field': '_page_type', } if self.application: params['app_label'] = self.application.name params['attrs']['_collection_document'] = self base_doc = create_document(**params) force_register_documents(base_doc._meta.app_label, base_doc) base_doc.objects.index('path').commit() #loop through page_definitions and register them for page_def in self.page_definitions: params = { 'parents': (base_doc,), 'virtual': False, 'typed_key': page_def.unique_id, 'attrs': SortedDict([ ('_page_def', page_def), ]) } page_def.get_document(**params) #CONSIDER: provide page defs defined in code for unique_id, page_schema in dict().items(): #REGISTERED_PAGE_DEFS.items() params = { 'virtual': False, 'typed_key': unique_id, 'parents': (page_schema, base_doc), 'name': '', #page_schema._meta.name, 'fields': SortedDict(), } create_document(**params) return base_doc def get_document(self): key = self.get_collection_name() #TODO how do we know if we should recreate the document? ie what if the design was modified on another node try: return get_base_document(key) except KeyError: doc = self.register_collection() return doc def get_object_class(self): return self.get_document() def get_resource_class(self): from dockitcms.pagecollection.resources import PageCollectionResource return PageCollectionResource def get_collection_resource(self): admin_client = self.get_collection_admin_client() cls = self.get_object_class() try: return admin_client.registry[cls] except Exception as error: for key, resource in admin_client.registry.iteritems(): if isinstance(key, type) and issubclass(cls, key): return resource #TODO why do we need this? if issubclass(key, schema.Document) and key._meta.collection == cls._meta.collection: return resource def __unicode__(self): if self.title: return self.title else: return self.__repr__() class Meta: typed_key = 'dockitcms.page'
class AuthMixinSchema(schema.Schema): _auth = schema.SchemaField(AuthConfiguration)
def get_field_kwargs(self): field_schema = self.get_schema() field_schema._meta.verbose_name = self.name field_schema._meta.verbose_name_plural = self.name + 's' kwargs = {'subfield': schema.SchemaField(field_schema)} return kwargs
class WidgetMixinSchema(schema.Schema): widgets = schema.ListField(schema.SchemaField(BlockWidget)) class Meta: verbose_name = 'widget'
class InlineSchema(schema.Schema): a_list = schema.ListField(schema.SchemaField(SimpleSchema), blank=True)
class Collection(ManageUrlsMixin, schema.Document, EventMixin): key = schema.SlugField(unique=True) application = schema.ReferenceField(Application) admin_options = schema.SchemaField(AdminOptions) title = None mixins = schema.SetField(schema.CharField(), choices=COLLECTION_MIXINS.choices, blank=True) mixin_function_events = { 'get_document_kwargs': { 'post': PostEventFunction(event='document_kwargs', keyword='document_kwargs'), }, #'get_view_endpoints': { #'collect': CollectEventFunction(event='view_endpoints', extend_function='extends'), #'post': PostEventFunction(event='view_endpoints', keyword='view_endpoints'), #}, } @classmethod def register_mixin(self, key, mixin_class): self.get_available_mixins()[key] = mixin_class @classmethod def get_available_mixins(self): return COLLECTION_MIXINS def __getattribute__(self, name): function_events = object.__getattribute__(self, 'mixin_function_events') if name in function_events: ret = object.__getattribute__(self, name) return self._mixin_function(ret, function_events[name]) return schema.Document.__getattribute__(self, name) def get_active_mixins(self): mixins = list() available_mixins = self.get_available_mixins() for mixin_key in self.mixins: if mixin_key in available_mixins: mixin_cls = available_mixins[mixin_key] mixins.append(mixin_cls(self)) return mixins @permalink def get_admin_manage_url(self): return self.get_resource_item().get_absolute_url() def admin_manage_link(self): url = self.get_admin_manage_url() return '<a href="%s">%s</a>' % (url, _('Manage')) admin_manage_link.short_description = _('Manage') admin_manage_link.allow_tags = True def get_object_class(self): raise NotImplementedError def get_resource_class(self): raise NotImplementedError @classmethod def get_collection_admin_client(cls): #TODO this should be configurable from dockitcms.urls import admin_client return admin_client.api_endpoint def get_collection_resource(self): admin_client = self.get_collection_admin_client() cls = self.get_object_class() try: return admin_client.registry[cls] except Exception as error: seen = list() for key, resource in admin_client.registry.iteritems(): seen.append((resource.collection.collection_type, key, resource.collection)) #if resource.collection.collection_type != 'dockitcms.virtualdocument': # assert False, str("%s, %s, %s, %s" % (resource.collection, self, resource.collection==self, resource.collection.collection_type)) if hasattr(resource, 'collection') and resource.collection == self: return resource assert False, str(seen) def register_collection(self): pass def save(self, *args, **kwargs): ret = super(Collection, self).save(*args, **kwargs) self.register_collection() return ret class Meta: typed_field = 'collection_type' verbose_name = 'collection'