import os import sys from bson.objectid import ObjectId from datetime import datetime import sqlalchemy as db from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship, sessionmaker, scoped_session BLOCKSIZE = 1024 ** 2 class Types(object): class ObjectId(db.TypeDecorator): impl = db.UnicodeText def process_bind_param(self, value : ObjectId, dialect) -> str: return str(value) def process_result_value(self, value : str, dialect) -> ObjectId: if value in [None, "None"]: return ObjectId("0" * 24) return ObjectId(value) class List(db.TypeDecorator): impl = db.UnicodeText def process_bind_param(self, value : list, dialect) -> str: return ";".join(i.replace(";", ",") for i in value) def process_result_value(self, value : str, dialect) -> list: return value.split(";") if value else [] Base = declarative_base() class User(Base): __tablename__ = "users" id = db.Column(Types.ObjectId, primary_key=True, default=ObjectId) name = db.Column(db.UnicodeText, nullable=False) email = db.Column(db.UnicodeText) hash = db.Column(db.String(512), nullable=False) def json(self): return { "id" : self.id, "name" : self.name, "email" : self.email } class Upload(Base): __tablename__ = "uploads" id = db.Column(Types.ObjectId, primary_key=True, default=ObjectId) title = db.Column(db.UnicodeText, nullable=False) author_id = db.Column(Types.ObjectId, db.ForeignKey("users.id"), default=lambda: ObjectId("0"*24)) description = db.Column(db.UnicodeText, default="") slug = db.Column(db.Text, nullable=False) tags = db.Column(Types.List, default=list) created_at = db.Column(db.DateTime, nullable=False, default=datetime.now) updated_at = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now) readonly = db.Column(db.Boolean, nullable=True, default=bool) version = db.Column(db.Unicode(10), nullable=True) author = relationship("User", lazy="subquery") files = relationship("File", back_populates="upload", lazy="subquery") comments = relationship("Comment", back_populates="upload", lazy="subquery") votes = relationship("Vote", back_populates="upload", lazy="subquery") def json(self): return { "id" : self.id, "title" : self.title, "author" : self.author.json() if self.author else {"name" : ""}, "description" : self.description, "slug" : self.slug, "tags" : self.tags, "createdAt" : self.created_at.isoformat(), "updatedAt" : self.updated_at.isoformat(), "version" : self.version } class File(Base): __tablename__ = "files" id = db.Column(Types.ObjectId, primary_key=True, default=ObjectId) name = db.Column(db.Unicode(255), nullable=False) hash = db.Column(db.String(40), nullable=False) content_type = db.Column(db.String(255), default="application/octet-stream") length = db.Column(db.BigInteger, default=0) date = db.Column(db.DateTime, nullable=False, default=datetime.now) upload_id = db.Column(Types.ObjectId, db.ForeignKey("uploads.id")) download_url = db.Column(db.Text) upload = relationship("Upload", back_populates="files", lazy="subquery") def json(self): return { "id" : self.id, "filename" : self.name, "metadata" : { "hashes" : { "sha1" : self.hash } }, "aliases" : None, "content-type" : self.content_type, "length" : self.length, "chunkSize" : BLOCKSIZE, "uploadDate" : self.date.isoformat() } class Comment(Base): __tablename__ = "comments" id = db.Column(Types.ObjectId, primary_key=True, default=ObjectId) author_id = db.Column(Types.ObjectId, db.ForeignKey("users.id")) upload_id = db.Column(Types.ObjectId, db.ForeignKey("uploads.id")) created_at = db.Column(db.DateTime, nullable=False, default=datetime.now) updated_at = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now) body = db.Column(db.UnicodeText, nullable=False) author = relationship("User", lazy="subquery") upload = relationship("Upload", back_populates="comments", lazy="subquery") votes = relationship("CommentVote", back_populates="comment", lazy="subquery") def json(self): return { "id" : self.id, "body" : self.body, "author" : self.author.json(), "upload" : self.upload.id, "createdAt" : self.created_at.isoformat(), "updatedAt" : self.updated_at.isoformat() } class Vote(Base): __tablename__ = "votes" id = db.Column(Types.ObjectId, primary_key=True, default=ObjectId) author_id = db.Column(Types.ObjectId, db.ForeignKey("users.id")) upload_id = db.Column(Types.ObjectId, db.ForeignKey("uploads.id")) impact = db.Column(db.Integer, nullable=False) author = relationship("User", lazy="subquery") upload = relationship("Upload", back_populates="votes", lazy="subquery") def json(self): return { "id" : self.id, "author" : self.author.json(), "upload" : self.upload.id, "impact" : self.impact } class CommentVote(Base): __tablename__ = "commentvotes" id = db.Column(Types.ObjectId, primary_key=True, default=ObjectId) author_id = db.Column(Types.ObjectId, db.ForeignKey("users.id")) comment_id = db.Column(Types.ObjectId, db.ForeignKey("comments.id")) impact = db.Column(db.Integer, nullable=False) author = relationship("User", lazy="subquery") comment = relationship("Comment", back_populates="votes", lazy="subquery") def json(self): return { "id" : self.id, "author" : self.author.json(), "comment" : self.comment.id, "impact" : self.impact } #class Dependency(Base): #__tablename__ = "dependencies" #id = db.Column(db.Integer, primary_key=True, default=ObjectId) #target_id = db.Column(Types.ObjectId, db.ForeignKey("uploads.id")) ##dependency_id = db.Column(Types.ObjectId, db.ForeignKey("uploads.id")) #target = relationship("Upload", foreign_keys=[target_id]) ##dependency = relationship("Upload", foreign_keys=[dependency_id]) engine = db.create_engine("sqlite:///parry.db") Base.metadata.bind = engine Base.metadata.create_all(engine) DBSession = scoped_session(sessionmaker(bind=engine))