from datetime import datetime, timedelta from flask.ext.login import UserMixin from sqlalchemy.orm import backref from sqlalchemy.sql import func, expression from app import db, pad, login from padlite import APIException from utils.apimixin import APIMixin from utils.login import user_cls def column(*args, **kwargs): """ I want to have a Column with nullable defaults to True. """ kwargs["nullable"] = kwargs.get("nullable", False) return db.Column(*args, **kwargs) class SessionMixin(object): @classmethod def create(cls, *args, **kwargs): obj = cls(*args, **kwargs) db.session.add(obj) return obj @user_cls(login) class User(UserMixin, APIMixin, SessionMixin, db.Model): __tablename__ = 'users' id = column(db.Integer, primary_key=True) name = column(db.String(255), unique=True) email = column(db.String(255)) last_login = column(db.DateTime(timezone=True), default=func.now()) active = column(db.Boolean, default=True, server_default=expression.true()) admin = column(db.Boolean, default=False, server_default=expression.false()) def __str__(self): return self.name def __repr__(self): return '' % self.name def create_api_object(self): self.api_id = pad.createAuthor(self.name) def remove_api_object(self): # authors could not be deleted with padlite api pass class Group(APIMixin, SessionMixin, db.Model): __tablename__ = 'groups' id = column(db.Integer, primary_key=True) name = column(db.String(255), unique=True) public = column(db.Boolean, default=False, server_default=expression.false()) browsable = column(db.Boolean, default=False, server_default=expression.false()) description = column(db.Text, nullable=True) def __str__(self): return self.name def __repr__(self): return '' % self.name def create_api_object(self): self.api_id = pad.createGroup() def remove_api_object(self): pad.deleteGroup(self.api_id) class Member(SessionMixin, db.Model): __tablename__ = 'members' id = column(db.Integer, primary_key=True) group_id = column(db.Integer, db.ForeignKey('groups.id')) user_id = column(db.Integer, db.ForeignKey('users.id')) manager = column(db.Boolean, server_default=expression.false()) admin = column(db.Boolean, server_default=expression.false()) active = column(db.Boolean, server_default=expression.false()) user = db.relationship( "User", backref=backref("memberships", cascade="delete")) group = db.relationship( "Group", backref=backref("members", cascade="delete")) def __str__(self): return "%s member of %s" % (self.user.name, self.group.name) def __repr__(self): return "" % (self.user, self.group) class Session(APIMixin, SessionMixin, db.Model): __tablename__ = 'sessions' id = column(db.Integer, primary_key=True) user_id = column(db.Integer, db.ForeignKey('users.id')) group_id = column(db.Integer, db.ForeignKey('groups.id')) uuid = column(db.String(36)) valid_until = column(db.DateTime(timezone=True)) user = db.relationship( "User", backref=backref("sessions", cascade="delete")) group = db.relationship( "Group", backref=backref("sessions", cascade="delete")) def __repr__(self): return "" % (self.user) def create_api_object(self): self.valid_until = datetime.now() + timedelta(hours=4) self.api_id = pad.createSession( self.group.get_api_id(), self.user.get_api_id(), self.valid_until.strftime("%s")) def remove_api_object(self): try: pad.deleteSession(self.api_id) except APIException as e: # we want to ignore code 1 = sessionID does not exist if e.code != 1: raise def is_valid(self): if self.api_id is None: return True if self.valid_until is not None: if datetime.now() + timedelta(minutes=30) < self.valid_until: return True return False class Pad(APIMixin, SessionMixin, db.Model): __tablename__ = 'pads' __table_args__ = ( db.UniqueConstraint('name', 'group_id'), ) id = column(db.Integer, primary_key=True) name = column(db.String(255)) group_id = column(db.Integer, db.ForeignKey('groups.id')) created = column(db.DateTime(timezone=True), default=func.now()) public = column(db.Boolean, default=False, server_default=expression.false()) password = column(db.String(255), default='', nullable=True) group = db.relationship( "Group", backref=backref("pads", order_by="desc(Pad.created)", cascade="delete")) def __str__(self): return self.name def __repr__(self): return "" % (self.name, self.group) def create_api_object(self): self.api_id = pad.createGroupPad( self.group.get_api_id(), self.name, 'testing') def remove_api_object(self): pad.deletePad(self.api_id) def after_commit(self): if self.api_id is not None: pad.setPublicStatus(self.api_id, self.public) pad.setPassword(self.api_id, self.password)