class User(db.Model, UserMixin): """ Represent a user. """ id = db.Column(db.Integer, primary_key=True) login = db.Column(db.String(30), unique=True, nullable=False) pwdhash = db.Column(db.String(), nullable=False) created_at = db.Column(db.DateTime(), default=datetime.utcnow) last_seen = db.Column(db.DateTime(), default=datetime.utcnow) apikey = db.Column(db.String(), default=secrets.token_urlsafe(50)) public_profile = db.Column(db.Boolean(), default=True) # user rights is_active = db.Column(db.Boolean(), default=False) is_admin = db.Column(db.Boolean(), default=False) is_api = db.Column(db.Boolean(), default=False) # relationships organizations = db.relationship( "Organization", secondary=lambda: association_table_organization, backref="users", ) objects = db.relationship("JsonObject", backref="creator", lazy="dynamic", cascade="all,delete-orphan") schemas = db.relationship("Schema", backref="creator", lazy="dynamic", cascade="all,delete-orphan") def get_id(self): """ Return the id of the user. """ return self.id def check_password(self, password): """ Check the password of the user. """ return check_password_hash(self.pwdhash, password) def generate_apikey(self): self.apikey = secrets.token_urlsafe(50) def __str__(self): return self.login @validates("login") def validates_login(self, key, value): assert 3 <= len(value) <= 30, AssertionError( "maximum length for login: 30") return re.sub("[^a-zA-Z0-9_.]", "", value.strip())
class JsonObject(db.Model): """Represent a JSON object. """ id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Text(), nullable=False) description = db.Column(db.Text(), nullable=False) last_updated = db.Column(db.DateTime(), default=datetime.utcnow()) json_object = db.Column(JSONB, default={}) # relationship licenses = db.relationship("License", secondary=lambda: association_table_license, backref="objects") refers_to = db.relationship( "JsonObject", secondary=lambda: association_table_jsonobject, primaryjoin=association_table_jsonobject.c.jsonobject_refers_to_id == id, secondaryjoin=association_table_jsonobject.c. jsonobject_referred_to_by_id == id, backref="referred_to_by", ) # foreign keys org_id = db.Column(db.Integer(), db.ForeignKey("organization.id"), nullable=False) creator_id = db.Column(db.Integer(), db.ForeignKey("user.id"), nullable=False) schema_id = db.Column(db.Integer(), db.ForeignKey("schema.id"), nullable=False)
class License(db.Model): """Represent a license. https://opensource.org/licenses/alphabetical """ id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(), default="", nullable=False, unique=True) license_id = db.Column(db.String(), default="", nullable=False, unique=True) created_at = db.Column(db.DateTime(), default=datetime.utcnow) def __str__(self): return self.name
class Schema(db.Model): """Represent a JSON schema.""" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100)) description = db.Column(db.String(500)) last_updated = db.Column(db.DateTime(), default=datetime.utcnow) json_schema = db.Column(JSONB, default={}) # relationship objects = db.relationship("JsonObject", backref="schema", lazy="dynamic", cascade="all,delete-orphan") licenses = db.relationship("License", secondary=lambda: association_table_license, backref="schemas") # foreign keys org_id = db.Column(db.Integer(), db.ForeignKey("organization.id"), default=None) creator_id = db.Column(db.Integer(), db.ForeignKey("user.id"), default=None)
class Organization(db.Model): """Represent an organization.""" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), unique=True) description = db.Column(db.String(500), default="") organization_type = db.Column(db.String(100), default="") website = db.Column(db.String(100), default="") last_updated = db.Column(db.DateTime(), default=datetime.utcnow) is_membership_restricted = db.Column(db.Boolean(), default=True) # relationship objects = db.relationship( "JsonObject", backref="organization", lazy="dynamic", cascade="all,delete-orphan", ) schemas = db.relationship("Schema", backref="organization", lazy="dynamic", cascade="all,delete-orphan") def __str__(self): return self.name def __eq__(self, obj): return self.id == obj.id
class Version(db.Model): """Represent a version of an object (only the fields 'name', 'description', 'json_object' and 'last_updated' are versioned).""" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Text(), nullable=False) description = db.Column(db.Text(), nullable=False) last_updated = db.Column(db.DateTime(), default=datetime.utcnow) json_object = db.Column(JSONB, default={}) # relationships editor = db.relationship("User", backref="versions") # foreign keys object_id = db.Column(db.Integer(), db.ForeignKey("json_object.id"), nullable=False) editor_id = db.Column(db.Integer(), db.ForeignKey("user.id"), nullable=False)
from datetime import datetime from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy import event from mosp.bootstrap import db association_table_license = db.Table( "association_schemas_licenses", db.metadata, db.Column("schema_id", db.Integer, db.ForeignKey("schema.id")), db.Column("license_id", db.Integer, db.ForeignKey("license.id")), ) class Schema(db.Model): """Represent a JSON schema.""" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100)) description = db.Column(db.String(500)) last_updated = db.Column(db.DateTime(), default=datetime.utcnow) json_schema = db.Column(JSONB, default={}) # relationship objects = db.relationship("JsonObject", backref="schema", lazy="dynamic", cascade="all,delete-orphan") licenses = db.relationship("License", secondary=lambda: association_table_license, backref="schemas")
import re import secrets from datetime import datetime from flask_login import UserMixin from sqlalchemy.orm import validates from werkzeug.security import check_password_hash from validate_email import validate_email from mosp.bootstrap import db association_table_organization = db.Table( "association_users_organizations", db.metadata, db.Column("user_id", db.Integer, db.ForeignKey("user.id")), db.Column("organization_id", db.Integer, db.ForeignKey("organization.id")), ) class User(db.Model, UserMixin): """ Represent a user. """ id = db.Column(db.Integer, primary_key=True) login = db.Column(db.String(30), unique=True, nullable=False) pwdhash = db.Column(db.String(), nullable=False) email = db.Column(db.String(256), nullable=False) created_at = db.Column(db.DateTime(), default=datetime.utcnow) last_seen = db.Column(db.DateTime(), default=datetime.utcnow) apikey = db.Column(db.String(100), default=secrets.token_urlsafe(64))
from datetime import datetime from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy import event from mosp.bootstrap import db association_table_license = db.Table( "association_jsonobjects_licenses", db.metadata, db.Column("json_object_id", db.Integer, db.ForeignKey("json_object.id")), db.Column("license_id", db.Integer, db.ForeignKey("license.id")), ) association_table_jsonobject = db.Table( "association_jsonobject_jsonobject", db.metadata, db.Column("jsonobject_refers_to_id", db.Integer, db.ForeignKey("json_object.id")), db.Column("jsonobject_referred_to_by_id", db.Integer, db.ForeignKey("json_object.id")), ) class JsonObject(db.Model): """Represent a JSON object. """ id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Text(), nullable=False) description = db.Column(db.Text(), nullable=False) last_updated = db.Column(db.DateTime(), default=datetime.utcnow())
class JsonObject(db.Model): """Represent a JSON object.""" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Text(), nullable=False) description = db.Column(db.Text(), nullable=False) last_updated = db.Column(db.DateTime(), default=datetime.utcnow) json_object = db.Column(JSONB, default={}) is_locked = db.Column(db.Boolean(), default=False) # foreign keys org_id = db.Column(db.Integer(), db.ForeignKey("organization.id"), nullable=False) schema_id = db.Column(db.Integer(), db.ForeignKey("schema.id"), nullable=False) creator_id = db.Column(db.Integer(), db.ForeignKey("user.id"), nullable=False) editor_id = db.Column(db.Integer(), db.ForeignKey("user.id"), nullable=False) # relationships collections = db.relationship( "Collection", secondary=lambda: association_table_collection, backref="objects") licenses = db.relationship("License", secondary=lambda: association_table_license, backref="objects") refers_to = db.relationship( "JsonObject", secondary=lambda: association_table_jsonobject, primaryjoin=association_table_jsonobject.c.jsonobject_refers_to_id == id, secondaryjoin=association_table_jsonobject.c. jsonobject_referred_to_by_id == id, backref="referred_to_by", ) versions = db.relationship("Version", backref="head", lazy="dynamic", cascade="all,delete-orphan") creator = db.relationship( "User", backref=backref("creator", uselist=False), uselist=False, foreign_keys=[creator_id], ) editor = db.relationship( "User", backref=backref("editor", uselist=False), uselist=False, foreign_keys=[editor_id], ) def __eq__(self, other): return self.id == other.id def create_new_version(self, obj: Union["JsonObject", None] = None) -> Version: """Create a new Version object from the JsonObject given in parameter or from the current object (self). Returns the new Version object.""" if not obj: obj = self new_version = Version( name=obj.name, description=obj.description, last_updated=obj.last_updated, json_object=obj.json_object, object_id=obj.id, editor_id=obj.editor_id, ) db.session.add(new_version) db.session.commit() return new_version def restore_from_version(self, version: Version): """Update the current JsonObject (self) with the specified Version object.""" schema = Schema.query.filter(Schema.id == self.schema_id) try: # check that the Version to restore validates the current schema. jsonschema.validate(version.json_object, schema.first().json_schema) except jsonschema.exceptions.ValidationError: raise Exception( "The version to restore is not validated by the current schema." ) self.name = version.name self.description = version.description self.json_object = version.json_object db.session.commit() return self