class Queue(BaseModel): job_type = CharField(null=False, max_length=16, index=True) is_control = BooleanField(null=False, default=False, index=True) priority = IntegerField(default=9, index=True) data_string = TextField(null=True) data_integer = IntegerField(null=True, index=True) date_touched = DateTimeField(default=datetime.datetime.now) blog = ForeignKeyField(Blog, index=True, null=False) site = ForeignKeyField(Site, index=True, null=False)
class Plugin(BaseModel): name = TextField(null=False) friendly_name = TextField(null=False) path = TextField(null=False) priority = IntegerField(null=True, default=0) enabled = BooleanField(null=False, default=False) @property def _plugin_list(self): from core.plugins import plugin_list return plugin_list def _get_plugin_property(self, plugin_property, deactivated_message): if self.enabled is True: return self._plugin_list[self.name].__dict__[plugin_property] else: return deactivated_message @property def loaded_plugins(self): return self.plugin_list @property def description(self): return self._get_plugin_property('__plugin_description__', '[Not activated]') @property def version(self): return self._get_plugin_property('__version__', '') @property def _friendly_name(self): return self._get_plugin_property('__plugin_name__', '')
class KeyValue(BaseModel): object = CharField(max_length=64, null=False, index=True) # table name objectid = IntegerField(null=True, index=True) key = EnforcedCharField(null=False, default="Key", index=True) value = TextField(null=True) parent = ForeignKeyField('self', null=True, index=True) is_schema = BooleanField(default=False) is_unique = BooleanField(default=False) value_type = CharField(max_length=64) def children(self, field=None, value=None): if self.is_schema is False: return None else: children = self.select().where(KeyValue.parent == self) if field is not None: children = children.select().where( getattr(KeyValue, field) == value) return children def siblings(self, field=None, value=None): if self.parent is None: return None else: siblings = self.select().where(KeyValue.parent == self.parent) if field is not None: siblings = siblings.select().where( getattr(KeyValue, field) == value) return siblings
class User(BaseModel): name = EnforcedCharField(index=True, null=False, unique=True) email = EnforcedCharField(index=True, null=False, unique=True) password = CharField(null=False) avatar = IntegerField(null=True) # refers to an asset ID last_login = DateTimeField(null=True) path_prefix = "/system" site = None blog = None logout_nonce = CharField(max_length=64, null=True, default=None) def from_site(self, site): self.site = site self.path_prefix = "/site/{}".format(str(site.id)) return self def from_blog(self, blog): self.blog = blog self.path_prefix = "/blog/{}".format(str(blog.id)) return self # for creating new post from main menu, among other things def blogs(self): from core.auth import role, bitmask, get_permissions permissions = get_permissions(self, level=bitmask.contribute_to_blog) if permissions[0].permission & role.SYS_ADMIN: all_blogs = Blog.select() return all_blogs ''' permissions = Permission.select( Permission.blog).where( Permission.user == self, Permission.blog >0, Permission.permission.bin_and(bitmask)) ''' # for n in permissions: # print (n.permission, n.blog.id, n.site.id) blogs = Blog.select().where( Blog.id << permissions.select(Permission.blog).tuples()) return blogs def sites(self, bitmask=1): sites = Permission.select().where( Permission.user == self, Permission.site > 0, Permission.permission.bin_and(bitmask)) return sites @property def link_format(self): return "{}{}/user/{}".format(BASE_URL, self.path_prefix, self.id)
class Category(BaseModel): blog = ForeignKeyField(Blog, null=False, index=True) title = TextField() parent_category = IntegerField(default=None, null=True, index=True) default = BooleanField(default=False) @property def next_category(self): pass @property def previous_category(self): pass
class PageRevision(Page, RevisionMixin): page_id = IntegerField(null=False) is_backup = BooleanField(default=False) change_note = TextField(null=True) saved_by = IntegerField(null=True) @property def saved_by_user(self): saved_by_user = get_user(user_id=self.saved_by) if saved_by_user is None: dead_user = User(name='Deleted user (ID #' + str(self.saved_by) + ')', id=saved_by_user) return dead_user else: return saved_by_user def save(self, user, current_revision, is_backup=False, change_note=None): from core.log import logger from core.error import PageNotChanged max_revisions = self.blog.max_revisions previous_revisions = (self.select().where( PageRevision.page_id == self.page_id).order_by( PageRevision.modified_date.desc()).limit(max_revisions)) if previous_revisions.count() > 0: last_revision = previous_revisions[0] page_changed = False for name in last_revision._meta.fields: if name not in ("modified_date", "id", "page_id", "is_backup", "change_note", "saved_by"): value = getattr(current_revision, name) new_value = getattr(last_revision, name) if value != new_value: page_changed = True break if page_changed is False: raise PageNotChanged( 'Page {} was saved but without changes.'.format( current_revision.for_log)) if previous_revisions.count() >= max_revisions: older_revisions = DeleteQuery(PageRevision).where( PageRevision.page_id == self.page_id, PageRevision.modified_date < previous_revisions[max_revisions - 1].modified_date) older_revisions.execute() self.is_backup = is_backup self.change_note = change_note self.saved_by = user.id results = Model.save(self) logger.info("Revision {} for page {} created.".format( date_format(self.modified_date), self.for_log)) return results
class Page(BaseModel): title = TextField() type = IntegerField( default=0, index=True) # 0 = regular blog post; 1 = standalone page path = EnforcedCharField( unique=True, null=True) # only used if this is a standalone page external_path = EnforcedCharField( null=True, index=True) # used for linking in an external file basename = TextField() user = ForeignKeyField(User, null=False, index=True) text = TextField() excerpt = TextField(null=True) blog = ForeignKeyField(Blog, null=False, index=True) created_date = DateTimeField(default=datetime.datetime.now) modified_date = DateTimeField(null=True) publication_date = DateTimeField(null=True, index=True) status = CharField(max_length=32, index=True, default=page_status.unpublished) tag_text = TextField(null=True) currently_edited_by = IntegerField(null=True) author = user @property def status_id(self): return page_status.id[self.status] @property def link_format(self): return '{}/page/{}/edit'.format(BASE_URL, self.id) @property def listing_id(self): return 'page_title_{}'.format(self.id) @property def paginated_text(self): paginated_text = self.text.split('<!-- pagebreak -->') return paginated_text @property def tags(self): tag_list = Tag.select().where(Tag.id << TagAssociation.select( TagAssociation.tag).where(TagAssociation.page == self)).order_by( Tag.tag) return tag_list @property def author(self): return self.user @property def revisions(self): revisions = PageRevision.select().where( PageRevision.page_id == self.id).order_by( PageRevision.modified_date.desc()) return revisions @property def templates(self): ''' Returns all page templates for this page. ''' page_templates = Template.select().where( Template.blog == self.blog.id, Template.template_type == template_type.page) return page_templates @property def default_template(self): ''' Returns the default page template used by this blog. ''' default_template = self.templates.select().where( Template.default_type == archive_type.page).get() return default_template @property def archives(self): ''' Returns all date-based archives for this page. ''' page_templates = Template.select().where( Template.blog == self.blog.id, Template.template_type == template_type.archive) return page_templates @property def archive_mappings(self): ''' Returns mappings for all date-based archives for this page. ''' archive_mappings = TemplateMapping.select().where( TemplateMapping.template << self.archives.select( Template.id).tuples()) return archive_mappings @property def template_mappings(self): ''' Returns all template mappings associated with page for this blog. ''' template_mappings = TemplateMapping.select().where( TemplateMapping.template << self.templates.select( Template.id).tuples()) return template_mappings @property def default_template_mapping(self): ''' Returns the default template mapping associated with this page. ''' t = TemplateMapping.get( TemplateMapping.is_default == True, TemplateMapping.template << self.templates.select( Template.id).where(Template.default_type == "P").tuples()) default_template_mapping = self.publication_date.date().strftime( t.path_string) return default_template_mapping @property def fileinfos(self): ''' Returns any fileinfo objects associated with this page. ''' fileinfos = FileInfo.select().where(FileInfo.page == self) return fileinfos @property def default_fileinfo(self): ''' Returns the default fileinfo associated with the page. Useful if you have pages that have multiple mappings. ''' default_fileinfo = FileInfo.get( FileInfo.page == self, FileInfo.template_mapping == self.default_template.default_mapping) return default_fileinfo @property def permalink(self): if self.id is not None: f_info = self.default_fileinfo permalink = self.blog.url + "/" + f_info.file_path else: permalink = "" return permalink @property def preview_permalink(self): ''' TODO: the behavior of this function is wrong in both local and remote mode, it should specify a link to a temporary file generated from the current draft for the sake of a preview. ''' if self.status_id == page_status.published: if DESKTOP_MODE is True: tags = template_tags(page_id=self.id) preview_permalink = tpl( BASE_URL_ROOT + '/' + self.default_template_mapping + "." + self.blog.base_extension + "?_=" + str(self.blog.id), **tags.__dict__) else: preview_permalink = self.permalink else: preview_permalink = BASE_URL + "/page/" + str(self.id) + "/preview" return preview_permalink @property def categories(self): categories = PageCategory.select().where(PageCategory.page == self) return categories @property def primary_category(self): primary = self.categories.select().where( PageCategory.primary == True).get() return primary.category @property def media(self): ''' Returns iterable of all Media types associated with an entry. ''' media_association = MediaAssociation.select(MediaAssociation.id).where( MediaAssociation.page == self.id).tuples() media = Media.select().where(Media.id << media_association) return media @property def next_page(self): ''' Returns the next published page in the blog, in ascending chronological order. ''' try: next_page = self.blog.published_pages().select().where( Page.blog == self.blog, Page.publication_date > self.publication_date).order_by( Page.publication_date.asc(), Page.id.asc()).get() except Page.DoesNotExist: next_page = None return next_page @property def previous_page(self): ''' Returns the previous published page in the blog, in descending chronological order. ''' try: previous_page = self.blog.published_pages().select().where( Page.blog == self.blog, Page.publication_date < self.publication_date).order_by( Page.publication_date.desc(), Page.id.desc()).get() except Page.DoesNotExist: previous_page = None return previous_page @property def next_in_category(self): ''' This returns a dictionary of categories associated with the current entry along with the next entry in that category This way we can say self.next_in_category[category_id], etc. ''' pass @property def previous_in_category(self): pass def save(self, user, no_revision=False, backup_only=False, change_note=None): ''' Wrapper for the model's .save() action, which also updates the PageRevision table to include a copy of the current revision of the page BEFORE the save is committed. ''' from core.log import logger revision_save_result = None if no_revision == False and self.id is not None: page_revision = PageRevision.copy(self) revision_save_result = page_revision.save(user, self, False, change_note) page_save_result = Model.save(self) if backup_only is False else None if revision_save_result is not None: logger.info("Page {} edited by user {}.".format( self.for_log, user.for_log)) else: logger.info( "Page {} edited by user {} but without changes.".format( self.for_log, user.for_log)) return (page_save_result, revision_save_result) revision_fields = {'id': 'page_id'}
class Log(BaseModel): date = DateTimeField(default=datetime.datetime.now, index=True) level = IntegerField() message = TextField()
class Permission(BaseModel): user = ForeignKeyField(User, index=True) permission = IntegerField(null=False) blog = ForeignKeyField(Blog, index=True, null=True) site = ForeignKeyField(Site, index=True, null=True)
class FileInfoContext(BaseModel): fileinfo = ForeignKeyField(FileInfo, null=False, index=True) object = CharField(max_length=1) ref = IntegerField(null=True)