class ContentType(db.Model): """This table holds metadata necessary to save and render content types""" name = db.Column(db.String(200), index=True) content_class = db.Column(db.String(200)) editable_fields = db.Column(db.UnicodeText()) viewable_fields = db.Column(db.UnicodeText()) edit_url = db.Column(db.String(100)) view_url = db.Column(db.String(100))
class ContentTypeRevision(db.Model): """This table holds metadata necessary to save and render content types""" _version = db.Column(db.Integer, primary_key=True, index=True) # Revision override name = db.Column(db.String(200), index=True) content_class = db.Column(db.String(200)) editable_fields = db.Column(db.UnicodeText()) viewable_fields = db.Column(db.UnicodeText()) edit_url = db.Column(db.String(100)) view_url = db.Column(db.String(100))
class Site(db.Model): """A delivery endpoint to publish content to""" site_name = db.Column(db.String(200)) environment_name = db.Column(db.String(200)) last_published = db.Column(db.DateTime) local_build_dir = db.Column(db.String(200)) static_files_dir = db.Column(db.String(200)) hosting_type = db.Column(db.String(100)) content_hash = db.Column(db.String(200)) index_content = db.Column(db.String(200)) menu_content = db.Column(db.UnicodeText()) groups_content = db.Column(db.UnicodeText())
class SiteRevision(db.Model): """A delivery endpoint to publish content to""" _version = db.Column(db.Integer, primary_key=True, index=True) # Revision override site_name = db.Column(db.String(200)) environment_name = db.Column(db.String(200)) last_published = db.Column(db.DateTime) local_build_dir = db.Column(db.String(200)) static_files_dir = db.Column(db.String(200)) hosting_type = db.Column(db.String(100)) content_hash = db.Column(db.String(200)) index_content = db.Column(db.String(200)) menu_content = db.Column(db.UnicodeText()) groups_content = db.Column(db.UnicodeText())
class NodeRevision(db.Model): """All content tables have related revision tables, all changes are saved as revisions.""" """Content updates first save the existing content to it's appropriate revision table including nodes themselves. In this way the base tables are always the latest revision. """ # content_type = db.Column(db.Integer) # After we build the type system user_id = db.Column(db.Integer, db.ForeignKey("user._id")) labels = db.Column(db.UnicodeText(), index=True) first_child = db.Column(db.String(200), index=True) _version = db.Column(db.Integer, primary_key=True, index=True) # Revision override layer_parents = db.Column(db.UnicodeText()) layer_children = db.Column(db.UnicodeText()) layer_next_node = db.Column(db.Integer) layer_previous_node = db.Column(db.Integer)
class ArticleRevision(db.Model): """The article revisions table""" # content_type = db.Column(db.Integer) # After we build the type system # Common fields _version = db.Column(db.Integer, primary_key=True, index=True) # Revision override title = db.Column(db.String(200)) body = db.Column(db.UnicodeText())
class Article(db.Model): """The most basic content type, a title field and a body field.""" """The body field whitelists a small subset of HTML and filters out all other special characters not required to support the HTML. """ # content_type = db.Column(db.Integer) # After we build the type system title = db.Column(db.String(200)) body = db.Column(db.UnicodeText())
class Node(db.Model): """The node model is the central organizing unit of the content model.""" """This is pervasive, to the extent that almost everything a user interacts with in the site is content organized by at least one node, including the users themselves. Nodes do not hold content themselves, but they reference content and the relationships of the content. Nodes may hold multiple content references, and content may even reference multiple other nodes, given the base constraint that nodes have only one immutable "first_child" and content rows can only ever have one immutable "node_id" (these constraints are within the content system). Potentially recursively nested fields are denoted with a leading "layer" prefix. This is to attempt to make cleared when fields require recursion crontrols in views and controllers. """ user_id = db.Column(db.Integer, db.ForeignKey("user._id")) labels = db.Column(db.UnicodeText(), index=True) first_child = db.Column(db.String(200), index=True) layer_parents = db.Column(db.UnicodeText()) layer_children = db.Column(db.UnicodeText()) layer_next_node = db.Column(db.Integer) layer_previous_node = db.Column(db.Integer)
class Message(db.Model): __tablename__ = 'messages' # nonvolatile data stored in the db id = db.Column(db.Integer, primary_key=True) recipient_email = db.Column(db.String, db.ForeignKey('users.email')) recipient = db.relationship("User", backref=db.backref("messages", uselist=True)) sender_name = db.Column(db.String(120), default="") subject = db.Column(db.String(120), default="") message_html = db.Column(db.UnicodeText(), default="") message_send_date = db.Column(ArrowType, default=arrow.utcnow) message_read = db.Column(db.Boolean, default=False) def __repr__(self): return '<Message from {} to {} with subject "{}" [{}] >'.format( self.sender_name, self.recipient_name, self.subject, self.message_send_date)
class User(UserMixin, db.Model): """User content type""" # content_type = db.Column(db.Integer) # After we build the type system username = db.Column(db.String(64), index=True, unique=True) email = db.Column(db.String(120), index=True, unique=True) password_hash = db.Column(db.String(128)) last_login = db.Column(db.DateTime, default=datetime.utcnow) roles = db.Column(db.UnicodeText()) # def __repr__(self): # return {"_id": self._id, "_node_id": self.node_id, "username": self.username} def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) # This is required as we added the underscore to id changing from the default def get_id(self): return int(self._id)
class UserRevision(UserMixin, db.Model): """User revision table""" _version = db.Column(db.Integer, primary_key=True, index=True) # Revision override username = db.Column(db.String(64), index=True, unique=True) email = db.Column(db.String(120), index=True, unique=True) password_hash = db.Column(db.String(128)) last_login = db.Column(db.DateTime, default=datetime.utcnow) roles = db.Column(db.UnicodeText()) def __repr__(self): return { "_id": self._id, "_node_id": self.node_id, "username": self.username } def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password)
# Everything is versioned, this combines to be a second primary key in revision tables db.Model._version = db.Column(db.Integer, index=True) # Everything not a node itself has a node and this is it's ID db.Model._node_id = db.Column(db.Integer, index=True) # Every database row has a hash of it's serialized database object values without the # hashes before final save for gross row value checks db.Model._hash = db.Column(db.String(140)) # Every database row contains another hash like the base hash but which also includes # any previous _hash_chains to form a Merkel chain for transactional integrity checks db.Model._hash_chain = db.Column(db.String(140)) # Everything in the database is timestamped db.Model._timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow) # Everything in the database is potentially editable and therefore must be lockable db.Model._lock = db.Column(db.UnicodeText()) # Everything in the database has a state that we can check for db.Model._state = db.Column(db.String(100)) # Everything in the database has authorization metadata called "perms" for permissions db.Model._perms = db.Column(db.String(100)) class Node(db.Model): """The node model is the central organizing unit of the content model.""" """This is pervasive, to the extent that almost everything a user interacts with in the site is content organized by at least one node, including the users themselves. Nodes do not hold content themselves, but they reference content and the relationships of the content. Nodes may hold multiple content references, and content may even reference multiple other nodes, given the base constraint that nodes have only one immutable "first_child" and content rows can only ever have one immutable "node_id" (these constraints are within the content system).