class Config(HasCustomValue, db.DynamicDocument): group = db.StringField(max_length=255) description = db.StringField() @classmethod def get(cls, group, name=None, default=None): try: instance = cls.objects.get(group=group) except: return None if not name: ret = instance.values if group == 'settings': ret = {} ret.update(current_app.config) ret.update({item.name: item.value for item in instance.values}) else: try: ret = instance.values.get(name=name).value except (MultipleObjectsReturned, AttributeError): ret = None if not ret and group == 'settings' and name is not None: ret = current_app.config.store.get(name) return ret or default def __unicode__(self): return self.group
class ProductType(db.Document): name = db.StringField() base_class = db.StringField( default='quokka.modules.cart.models.BaseProduct') @classmethod def _get_class_from_db(cls, _id): pass def get_class_from_db(self): base_class_module, base_class_name = self.base_class.rsplit('.', 1) print base_class_module, base_class_name base_class = getattr( __import__(base_class_module, [], [], fromlist=[base_class_name]), base_class_name) return type(str(self.name), (base_class, ), {}) def __str__(self): return str(unicode(self)) def __unicode__(self): return "<ProductType: [{}]>".format(self.name) def __repr__(self): return str(unicode(self))
class Reply(Publishable, BaseComment, db.EmbeddedDocument): uid = db.StringField(verbose_name=_l('UID')) parent = db.StringField(verbose_name=_l('Parent')) def clean(self): if not self.uid: self.uid = str(uuid.uuid4())
class Media(MediaController, Content): DEFAULT_CHANNEL = "media" path = db.StringField() embed = db.StringField() link = db.StringField() meta = { 'allow_inheritance': True } @property def full_path(self): return Markup( "<a target='_blank' href='{full}'>{path}</a>".format( full=url_for('quokka.core.media', filename=self.path), path=self.path ) ) @classmethod def get_default_channel(cls): default_channel = cls.DEFAULT_CHANNEL try: return Channel.objects.get(long_slug=default_channel) except Exception as e: logger.warning(str(e)) return Channel.get_homepage()
class Content(HasCustomValue, Imaged, Publishable, Slugged, Commentable, Channeling, Tagged, db.DynamicDocument): title = db.StringField(max_length=255, required=True) summary = db.StringField(required=False) meta = { 'allow_inheritance': True, 'indexes': ['-created_at', 'slug'], 'ordering': ['-created_at'] } def get_absolute_url(self, endpoint='detail'): if self.channel.is_homepage: long_slug = self.slug else: long_slug = self.long_slug try: return url_for(self.URL_NAMESPACE, long_slug=long_slug) except: return url_for(endpoint, long_slug=long_slug) def __unicode__(self): return self.title @property def content_type(self): return self.__class__.__name__ def save(self, *args, **kwargs): self.validate_slug() self.validate_long_slug() super(Content, self).save(*args, **kwargs)
class Reply(Publishable, BaseComment, db.EmbeddedDocument): uid = db.StringField() parent = db.StringField() def clean(self): if not self.uid: self.uid = str(uuid.uuid4())
class LongSlugged(Slugged): long_slug = db.StringField(unique=True, required=True) mpath = db.StringField() def _create_mpath_long_slug(self): if isinstance(self, Channel): if self.parent and self.parent != self: self.long_slug = "/".join([self.parent.long_slug, self.slug]) self.mpath = "".join([self.parent.mpath, self.slug, ',']) else: self.long_slug = self.slug self.mpath = ",%s," % self.slug elif isinstance(self, Content): self.long_slug = "/".join([self.channel.long_slug, self.slug]) self.mpath = "".join([self.channel.mpath, self.slug, ',']) def validate_long_slug(self): self._create_mpath_long_slug() filters = dict(long_slug=self.long_slug) if self.id: filters['id__ne'] = self.id exist = self.__class__.objects(**filters) if exist.count(): if current_app.config.get('SMART_SLUG_ENABLED', False): self.slug = "{0}-{1}".format(self.slug, random.getrandbits(32)) self._create_mpath_long_slug() else: raise db.ValidationError( _l("%(slug)s slug already exists", slug=self.long_slug))
class ClassRoom(Slugged, Publishable, db.EmbeddedDocument): WEEKDAYS = ( ("sun", _l("Sunday")), ("mon", _l("Monday")), ("tue", _l("Tuesday")), ("wed", _l("Wednesday")), ("thu", _l("Thursday")), ("fri", _l("Friday")), ("sat", _l("Saturday")), ) title = db.StringField(required=True, max_length=100) description = db.StringField() weekdays = db.ListField(db.StringField(choices=WEEKDAYS), default=[]) start_date = db.DateTimeField() end_date = db.DateTimeField() status = db.StringField() def get_description(self): return "<br>".join([ self.title, self.description, ",".join(self.weekdays), self.start_date.strftime("%Y-%m-%d") if self.start_date else '' ]) def get_weekdays_display(self, **kwargs): data = dict(self.WEEKDAYS) data.update(kwargs) return [data.get(k) for k in self.weekdays] def clean(self): self.validate_slug() def __unicode__(self): return self.title
class SubContent(Publishable, Ordered, db.EmbeddedDocument): """Content can have inner contents Its useful for any kind of relation with Content childs Images, ImageGalleries, RelatedContent, Attachments, Media """ content = db.ReferenceField('Content', required=True) caption = db.StringField() purpose = db.ReferenceField(SubContentPurpose, required=True) identifier = db.StringField() @property def thumb(self): try: return url_for('media', filename=self.content.thumb) # return self.content.thumb except Exception as e: logger.warning(str(e)) return self.content.get_main_image_url(thumb=True) meta = { 'ordering': ['order'], 'indexes': ['order'] } def clean(self): self.identifier = self.purpose.identifier def __unicode__(self): return self.content and self.content.title or self.caption
class Config(HasCustomValue, Publishable, db.DynamicDocument): group = db.StringField(max_length=255) description = db.StringField() @classmethod def get(cls, group, name=None, default=None): instance = cls.objects.get(group=group) if not name: ret = instance.values else: try: ret = instance.values.get(name=name).value except MultipleObjectsReturned: ret = None return ret or default def save(self, *args, **kwargs): super(Config, self).save(*args, **kwargs) # Try to update the config for the running app # AFAIK Flask apps are not thread safe # TODO: do it in a signal try: if self.group == 'settings': _settings = {i.name: i.value for i in self.values} current_app.config.update(_settings) except: logger.warning("Cant update app settings") def __unicode__(self): return self.group
class CourseSubscription(BaseProductReference, Publishable, db.DynamicDocument): subscriber = db.ReferenceField(Subscriber, reverse_delete_rule=db.NULLIFY) student = db.ReferenceField(Subscriber, reverse_delete_rule=db.NULLIFY) course = db.ReferenceField(Course, required=True, reverse_delete_rule=db.DENY) classroom = db.StringField() variant = db.EmbeddedDocumentField(CourseVariant) status = db.StringField(default="pending") unity_value = db.FloatField() total_value = db.FloatField() cart = db.ReferenceField(Cart, reverse_delete_rule=db.NULLIFY) confirmed_date = db.DateTimeField() def clean(self): self.unity_value = self.get_unity_value() def __unicode__(self): if self.variant: return u"{s.course.title} {s.classroom} {s.variant}".format(s=self) else: return self.course.title def get_title(self): return self.course.get_title() def get_description(self): return "<br>".join([ self.course.get_summary(classroom=self.classroom), self.variant.get_description() if self.variant else '', self.student.name if self.student else '' ]) def get_unity_value(self): if self.unity_value: return self.unity_value if self.variant and self.variant.unity_value: return self.variant.unity_value return self.course.get_unity_value() def get_weight(self): return getattr(self, 'weight', None) def get_dimensions(self): return getattr(self, 'dimensions', None) def get_extra_value(self): return getattr(self, 'extra_value', None) def get_uid(self): return str(self.id) def set_status(self, status, *args, **kwargs): self.status = status if status == "confirmed": now = datetime.datetime.now() self.confirmed_date = kwargs.get('date', now) self.save()
class BaseProduct(BaseProductReference, Content): description = db.StringField(required=True) unity_value = db.FloatField() weight = db.FloatField() dimensions = db.StringField() extra_value = db.FloatField() meta = {'allow_inheritance': True}
class TemplateType(HasCustomValue): title = db.StringField(max_length=255, required=True) identifier = db.StringField(max_length=255, required=True, unique=True) template_suffix = db.StringField(max_length=255, required=True) theme_name = db.StringField(max_length=255, required=False) def __unicode__(self): return self.title
class CustomValue(db.EmbeddedDocument): FORMATS = { ('json', 'json'), ('text', 'text'), ('int', 'int'), ('float', 'float'), } DEFAULT_FORMATTER = default_formatter FORMATTERS = { 'json': json.loads, 'text': DEFAULT_FORMATTER, 'int': int, 'float': float, } REVERSE_FORMATTERS = { 'json': lambda val: val if isinstance(val, str) else json.dumps(val), 'text': DEFAULT_FORMATTER, 'int': DEFAULT_FORMATTER, 'float': DEFAULT_FORMATTER, } name = db.StringField(max_length=50, required=True) raw_value = db.StringField( verbose_name=_l('Value'), required=True ) formatter = db.StringField( choice=FORMATS, default='text', required=True ) @property def value(self): return self.FORMATTERS.get( self.formatter, self.DEFAULT_FORMATTER )(self.raw_value) @value.setter def value(self, value): self.raw_value = self.REVERSE_FORMATTERS.get( self.formatter, self.STR_FORMATTER )(value) def clean(self): try: self.value except Exception as e: raise Exception(e.message) super(CustomValue, self).clean() def __unicode__(self): return '{s.name} -> {s.value}'.format(s=self)
class Payment(db.EmbeddedDocument): uid = db.StringField() payment_system = db.StringField() method = db.StringField() value = db.FloatField() extra_value = db.FloatField() date = db.DateTimeField() confirmed_at = db.DateTimeField() status = db.StringField()
class UserLink(db.EmbeddedDocument): title = db.StringField(max_length=50, required=True) link = db.StringField(max_length=255, required=True) icon = db.StringField(max_length=255) css_class = db.StringField(max_length=50) order = db.IntField(default=0) def __unicode__(self): return '{0} -> {1}'.format(self.title, self.link)
class Role(db.Document, RoleMixin): name = db.StringField(max_length=80, unique=True) description = db.StringField(max_length=255) @classmethod def create_role(cls, name, description=None): return cls.objects.create(name=name, description=description) def __unicode__(self): return '{0} ({1})'.format(self.name, self.description or 'Role')
class CustomValue(db.EmbeddedDocument): FORMATS = ( ('json', "json"), ('text', "text"), ('int', "int"), ('float', "float"), ) DEFAULT_FORMATTER = lambda value: value FORMATTERS = { 'json': lambda value: json.loads(value), 'text': DEFAULT_FORMATTER, 'int': lambda value: int(value), 'float': lambda value: float(value) } REVERSE_FORMATTERS = { 'json': lambda value: value if isinstance(value, str) else json.dumps(value), 'text': DEFAULT_FORMATTER, 'int': DEFAULT_FORMATTER, 'float': DEFAULT_FORMATTER } name = db.StringField(max_length=50, required=True) rawvalue = db.StringField(verbose_name=lazy_gettext("Value"), required=True) formatter = db.StringField(choices=FORMATS, default="text", required=True) @property def value(self): return self.FORMATTERS.get(self.formatter, self.DEFAULT_FORMATTER)(self.rawvalue) @value.setter def value(self, value): self.rawvalue = self.REVERSE_FORMATTERS.get(self.formatter, self.STR_FORMATTER)(value) def clean(self): try: self.value except Exception as e: # raise base exception because Flask-Admin can't handle the output # for some specific Exceptions of Mongoengine raise Exception(e.message) super(CustomValue, self).clean() def __unicode__(self): return u"{s.name} -> {s.value}".format(s=self)
class Content(HasCustomValue, Publishable, LongSlugged, Commentable, Channeling, Tagged, db.DynamicDocument): title = db.StringField(max_length=255, required=True) summary = db.StringField(required=False) template_type = db.ReferenceField(ContentTemplateType, required=False, reverse_delete_rule=db.NULLIFY) contents = db.ListField(db.EmbeddedDocumentField(SubContent)) model = db.StringField() meta = { 'allow_inheritance': True, 'indexes': ['-created_at', 'slug'], 'ordering': ['-created_at'] } def get_themes(self): themes = self.channel.get_themes() theme = self.template_type and self.template_type.theme_name if theme: themes.insert(0, theme) return list(set(themes)) def get_absolute_url(self, endpoint='detail'): if self.channel.is_homepage: long_slug = self.slug else: long_slug = self.long_slug try: return url_for(self.URL_NAMESPACE, long_slug=long_slug) except: return url_for(endpoint, long_slug=long_slug) def __unicode__(self): return self.title @property def model_name(self): return self.__class__.__name__.lower() @property def module_name(self): module = self.__module__ module_name = module.replace('quokka.modules.', '').split('.')[0] return module_name def heritage(self): self.model = "{0}.{1}".format(self.module_name, self.model_name) def save(self, *args, **kwargs): self.validate_slug() self.validate_long_slug() self.heritage() super(Content, self).save(*args, **kwargs)
class SubContentPurpose(db.Document): title = db.StringField(max_length=255, required=True) identifier = db.StringField(max_length=255, required=True, unique=True) module = db.StringField() def save(self, *args, **kwargs): self.identifier = slugify(self.identifier or self.title) super(SubContentPurpose, self).save(*args, **kwargs) def __unicode__(self): return self.title
class Role(db.Document, RoleMixin): name = db.StringField(max_length=80, unique=True, verbose_name=_l('Name')) description = db.StringField(max_length=255, verbose_name=_l('Description')) @classmethod def createrole(cls, name, description=None): return cls.objects.create(name=name, description=description) def __unicode__(self): return u"{0} ({1})".format(self.name, self.description or 'Role')
class Archive(HasCustomValue, Publishable, ChannelingNotRequired, Tagged, Slugged, db.DynamicDocument): title = db.StringField(max_length=255, required=True) summary = db.StringField(required=False) path = db.StringField() meta = { 'allow_inheritance': True, 'indexes': ['-created_at', 'slug'], 'ordering': ['-created_at'] }
class Subscriber(db.DynamicDocument): name = db.StringField() email = db.EmailField() document = db.StringField() phone = db.StringField() address = db.StringField() user = db.ReferenceField('User', default=get_current_user, reverse_delete_rule=db.NULLIFY) def __unicode__(self): return self.name
class PostImage(db.Document): image = db.ImageField() name = db.StringField(default='', max_length=255) filetype = db.StringField(choices=['jpg','png','bmp'], default='jpg') def __init__(self, *args, **kwargs): super(PostImage, self).__init__(*args, **kwargs) if not self.name: self.name, self.filetype = os.path.splitext(self.image.filename) def __unicode__(self): return self.image.filename
class ExternalBlogs(db.Document): """ Blogs that should be aggregated """ name = db.StringField(max_length=255, required=True) root_url = db.StringField(default='') feeds_url = db.StringField(required=True) channel = db.ReferenceField('Channel', required=True, reverse_delete_rule=db.CASCADE) def __str__(self): return self.name
class CourseVariant(Slugged, db.EmbeddedDocument): title = db.StringField(required=True, max_length=100) description = db.StringField() unity_value = db.FloatField() def clean(self): self.validate_slug() def get_description(self): return "<br>".join([self.title, self.description]) def __unicode__(self): return self.title
class BaseComment(object): author_name = db.StringField(max_length=255, required=True) author_email = db.StringField(max_length=255) body = db.StringField(required=True) spam = db.BooleanField() deleted = db.BooleanField() content_format = db.StringField(choices=('markdown', ), default="markdown") @property def gravatar_email(self): if self.created_by: return self.created_by.email return self.author_email
class User(db.DynamicDocument, UserMixin): name = db.StringField(max_length=255) email = db.EmailField(max_length=255, unique=True) password = db.StringField(max_length=255) active = db.BooleanField(default=True) confirmed_at = db.DateTimeField() roles = db.ListField( db.ReferenceField(Role, reverse_delete_rule=db.DENY), default=[] ) last_login_at = db.DateTimeField() current_login_at = db.DateTimeField() last_login_ip = db.StringField(max_length=255) current_login_ip = db.StringField(max_length=255) login_count = db.IntField() username = db.StringField(max_length=50, required=False, unique=True) def clean(self, *args, **kwargs): if not self.username: self.username = User.generate_username(self.email) try: super(User, self).clean(*args, **kwargs) except: pass @classmethod def generate_username(cls, email): username = email.lower() for item in ['@', '.', '-', '+']: username = username.replace(item, '_') return username @classmethod def createuser(cls, name, email, password, active=True, roles=None, username=None): username = username or cls.generate_username(email) return cls.objects.create( name=name, email=email, password=encrypt_password(password), active=active, roles=roles, username=username ) def __unicode__(self): return "{0} <{1}>".format(self.name or '', self.email)
class Slugged(object): slug = db.StringField(max_length=255) long_slug = db.StringField() mpath = db.StringField() def _create_mpath_long_slug(self): try: if self.parent and self.parent != self: self.long_slug = "/".join( [self.parent.long_slug, self.slug] ) self.mpath = "".join( [self.parent.mpath, self.slug, ','] ) else: self.long_slug = self.slug self.mpath = ",%s," % self.slug except: logger.info("excepting to content validate_long_slug") self.long_slug = "/".join( [self.channel.long_slug, self.slug] ) self.mpath = "".join([self.channel.mpath, self.slug, ',']) def validate_long_slug(self): self._create_mpath_long_slug() filters = dict(long_slug=self.long_slug) if self.id: filters['id__ne'] = self.id exist = self.__class__.objects(**filters) if exist.count(): if current_app.config.get('SMART_SLUG_ENABLED', False): self.slug = "{}-{}".format(self.slug, random.getrandbits(32)) self._create_mpath_long_slug() else: raise db.ValidationError( lazy_gettext("%(slug)s slug already exists", slug=self.long_slug) ) def validate_slug(self, title=None): if self.slug: self.slug = slugify(self.slug) else: self.slug = slugify(title or self.title)
class Comment(db.EmbeddedDocument): body = db.StringField(verbose_name="Comment", required=True) author = db.StringField(verbose_name="Name", max_length=255, required=True) published = db.BooleanField(default=True) created_at = db.DateTimeField(default=datetime.datetime.now) created_by = db.ReferenceField(User) def __unicode__(self): return "{}-{}...".format(self.author, self.body[:10]) meta = { 'indexes': ['-created_at', '-available_at'], 'ordering': ['-created_at'] }