class DetailViewPoint(BaseViewPoint, TemplateMixin, CanonicalMixin): slug_field = schema.SlugField(blank=True) view_class = PointDetailView def get_object_class(self): object_class = super(DetailViewPoint, self).get_object_class() view_point = self def get_absolute_url_for_instance(instance): if view_point.slug_field: return view_point.reverse('detail', instance[view_point.slug_field]) return view_point.reverse('detail', instance.pk) if self.canonical: object_class.get_absolute_url = get_absolute_url_for_instance return object_class def get_urls(self): params = self.to_primitive(self) object_class = self.get_object_class() index = self.get_index() if self.slug_field: return patterns( '', url( r'^(?P<slug>.+)/$', self.view_class.as_view( document=object_class, queryset=index, view_point=self, configuration=params, slug_field=self.slug_field, ), name='index', ), ) else: return patterns( '', url( r'^(?P<pk>.+)/$', self.view_class.as_view( document=object_class, queryset=index, view_point=self, configuration=params, ), name='index', ), ) class Meta: typed_key = 'dockitcms.detailview' @classmethod def get_admin_form_class(cls): return DetailViewPointForm
class FieldEntry(schema.Schema): ''' This schema is extended by others to define a field entry ''' name = schema.SlugField() field_class = None def __unicode__(self): return u'%s (%s)' % (self.name, self.field_type) def get_field_kwargs(self): params = self.to_primitive(self) params.pop('field_type', None) params.pop('name', None) if params.get('verbose_name', None) == '': del params['verbose_name'] kwargs = dict() for key, value in params.items(): if key in self._meta.fields: kwargs[str(key)] = value return kwargs def create_field(self): kwargs = self.get_field_kwargs() return self.field_class(**kwargs) def get_scaffold_example(self, context, varname): raise NotImplementedError class Meta: typed_field = 'field_type'
class Subsite(schema.Document, ManageUrlsMixin, create_document_mixin(SUBSITE_MIXINS)): url = schema.CharField() name = schema.CharField() slug = schema.SlugField() sites = schema.ModelSetField(Site, blank=True) def __unicode__(self): return '%s - %s' % (self.name, self.url) def get_logger(self): from dockitcms.sites import logger return logger @property def resource_definitions(self): return PublicResource.objects.filter(subsite=self) def get_site_client(self): """ Returns a hyperadmin client for public consumption """ from dockitcms.resources.virtual import site from dockitcms.resources.public import PublicSubsite subsite_api = PublicSubsite(api_endpoint=site, name=self.name, subsite=self) for resource_def in self.resource_definitions: try: resource_def.register_public_resource(subsite_api) except Exception as error: self.get_logger().exception( 'Could not register public resource') return subsite_api def get_urls(self): if not hasattr(self, '_client'): self._client = self.get_site_client() client = self._client return client.get_urls() @property def urls(self): #urls, app_name, namespace try: self.urlpatterns except Exception as error: logger = self.get_logger() logger.exception('Error while constructing urls') raise return self, None, self.name @property def urlpatterns(self): return self.get_urls()
class Application(schema.Document): name = schema.CharField() slug = schema.SlugField(unique=True) def create_natural_key(self): return {'slug':self.slug} def __unicode__(self): return self.name
class BaseField(schema.Schema): name = schema.SlugField() required = schema.BooleanField(default=True) label = schema.CharField(blank=True) initial = schema.CharField(blank=True) help_text = schema.CharField(blank=True) class Meta: typed_field = 'field_type'
class BasePage(schema.Schema): parent = schema.ReferenceField('self', blank=True, null=True) url = schema.CharField(blank=True) url_name = schema.SlugField(blank=True, help_text='registers the page with the url tag with this name') path = schema.CharField(editable=False) title = schema.CharField() slug = schema.SlugField() published = schema.BooleanField() template = schema.CharField() inline_css = schema.TextField(blank=True) inline_js = schema.TextField(blank=True) def clean_path(self): if self.url: return self.url if self.parent: return self.parent.path + self.slug + '/' return self.slug + '/'
class ThumbnailFieldEntrySchema(schema.Schema): key = schema.SlugField() format = schema.CharField(blank=True, null=True, choices=IMAGE_FORMATS) quality = schema.IntegerField(blank=True, null=True) width = schema.IntegerField(blank=True, null=True) height = schema.IntegerField(blank=True, null=True) upscale = schema.BooleanField( default=False, help_text='Upsize the image if it doesn\'t match the width and height') crop = schema.CharField(blank=True, null=True, choices=CROP_CHOICES) autocrop = schema.BooleanField( default=False, help_text='Remove white space from around the image') def __unicode__(self): return self.key or repr(self)
class ListingViewPoint(ViewPoint, CanonicalMixin, IndexMixin): slug_field = schema.SlugField(blank=True) list_template_source = schema.CharField(choices=TEMPLATE_SOURCE_CHOICES, default='name') list_template_name = schema.CharField(default='dockitcms/list.html', blank=True) list_template_html = schema.TextField(blank=True) list_content = schema.TextField(blank=True, help_text=LIST_CONTEXT_DESCRIPTION) detail_template_source = schema.CharField(choices=TEMPLATE_SOURCE_CHOICES, default='name') detail_template_name = schema.CharField(default='dockitcms/detail.html', blank=True) detail_template_html = schema.TextField(blank=True) detail_content = schema.TextField(blank=True, help_text=DETAIL_CONTEXT_DESCRIPTION) paginate_by = schema.IntegerField(blank=True, null=True) list_view_class = PointListView detail_view_class = PointDetailView def get_object_class(self): doc_cls = self.index.get_object_class() view_point = self def get_absolute_url_for_instance(instance): if view_point.slug_field: return view_point.reverse('detail', instance[view_point.slug_field]) return view_point.reverse('detail', instance.pk) if self.canonical: #TODO this does not work setattr(doc_cls, 'get_absolute_url', get_absolute_url_for_instance) assert hasattr(doc_cls, 'get_absolute_url') #TODO support model or do this gently class WrappedDoc(doc_cls): get_absolute_url = get_absolute_url_for_instance class Meta: proxy = True return WrappedDoc def _configuration_from_prefix(self, params, prefix): config = dict() for key in ('template_source', 'template_name', 'template_html', 'content'): config[key] = params.get('%s_%s' % (prefix, key), None) return config def get_urls(self): document = self.get_object_class() params = self.to_primitive(self) index = self.get_index() urlpatterns = patterns( '', url( r'^$', self.list_view_class.as_view( document=document, queryset=index, view_point=self, configuration=self._configuration_from_prefix( params, 'list'), paginate_by=params.get('paginate_by', None)), name='index', ), ) if params.get('slug_field', None): urlpatterns += patterns( '', url( r'^(?P<slug>.+)/$', self.detail_view_class.as_view( document=document, queryset=index, slug_field=params['slug_field'], view_point=self, configuration=self._configuration_from_prefix( params, 'detail'), ), name='detail', ), ) else: urlpatterns += patterns( '', url( r'^(?P<pk>.+)/$', self.detail_view_class.as_view( document=document, queryset=index, view_point=self, configuration=self._configuration_from_prefix( params, 'detail'), ), name='detail', ), ) return urlpatterns class Meta: typed_key = 'dockitcms.listing' @classmethod def get_admin_form_class(cls): return ListingViewPointForm
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'
class Collection(BaseCollection, DocumentDesign, EventMixin): key = schema.SlugField(unique=True) mixins = schema.SetField(schema.CharField(), choices=mixin_choices, blank=True) mixin_function_events = { 'get_document_kwargs': { 'post': PostEventFunction(event='document_kwargs', keyword='document_kwargs') }, } @classmethod def register_mixin(self, key, mixin_class): COLLECTION_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 BaseCollection.__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 def save(self, *args, **kwargs): ret = super(Collection, self).save(*args, **kwargs) self.register_collection() return ret def get_collection_name(self): return 'dockitcms.virtual.%s' % self.key def get_document_kwargs(self, **kwargs): kwargs = super(Collection, self).get_document_kwargs(**kwargs) kwargs.setdefault('attrs', dict()) parents = list(kwargs.get('parents', list())) if parents and not any( [issubclass(parent, schema.Document) for parent in parents]): parents.append(schema.Document) if parents: kwargs['parents'] = tuple(parents) if self.application: kwargs['app_label'] = self.application.name def get_manage_urls(instance): base_url = self.get_admin_manage_url() urls = { 'add': base_url + 'add/', 'list': base_url, } if instance.pk: urls['edit'] = base_url + instance.pk + '/' return urls kwargs['attrs']['get_manage_urls'] = get_manage_urls kwargs['attrs']['_collection_document'] = self return kwargs def register_collection(self): doc = DocumentDesign.get_document( self, virtual=False, verbose_name=self.title, collection=self.get_collection_name()) force_register_documents(doc._meta.app_label, doc) return 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 __unicode__(self): if self.title: return self.title else: return self.__repr__() class Meta: typed_key = 'document'
def test_force_register_documents(self): doc = create_document('testDocument', fields={'title':schema.CharField()}) doc = create_document('testDocument', fields={'title':schema.CharField(), 'slug':schema.SlugField()}) force_register_documents(doc._meta.app_label, doc) doc = get_base_document(doc._meta.collection) self.assertTrue('slug' in doc._meta.fields)