Esempio n. 1
0
class RecommendationTagsAssoc(db.Model):  # type: ignore
    __bind_key__ = 'experiment_service'
    __tablename__ = "recommendation_tags_assoc"
    recommendation_id = db.Column(UUIDType,
                                  db.ForeignKey('recommendation.id'),
                                  primary_key=True)
    tag_id = db.Column(db.Integer,
                       db.ForeignKey('recommendation_tag.id'),
                       primary_key=True)
Esempio n. 2
0
class OrgsMembers(db.Model):  # type: ignore
    __bind_key__ = 'dashboard_service'
    __tablename__ = "orgs_members"
    org_id = db.Column(UUIDType(binary=False),
                       db.ForeignKey('org.id'),
                       primary_key=True)
    account_id = db.Column(UUIDType(binary=False),
                           db.ForeignKey('user_account.id'),
                           primary_key=True)
    is_owner = db.Column(db.Boolean(), default=False)
    account = db.relationship('UserAccount')
    organization = db.relationship('Org')
Esempio n. 3
0
class WorkpacesMembers(db.Model):  # type: ignore
    __bind_key__ = 'dashboard_service'
    __tablename__ = "workspaces_members"
    workspace_id = db.Column(UUIDType(binary=False),
                             db.ForeignKey('workspace.id'),
                             primary_key=True)
    account_id = db.Column(UUIDType(binary=False),
                           db.ForeignKey('user_account.id'),
                           primary_key=True)
    is_owner = db.Column(db.Boolean(), default=False)
    account = db.relationship('UserAccount')
    workspace = db.relationship('Workspace')
Esempio n. 4
0
class AccessToken(db.Model, OAuth2TokenMixin):  # type: ignore
    __bind_key__ = 'auth_service'
    id = db.Column(UUIDType(binary=False),
                   primary_key=True,
                   unique=True,
                   default=uuid.uuid4)
    name = db.Column(db.String(), nullable=False)
    account_id = db.Column(UUIDType(binary=False),
                           db.ForeignKey('account.id', ondelete='CASCADE'),
                           nullable=False)
    last_used_on = db.Column(db.DateTime())

    def to_dict(self):
        last_used = None
        if self.last_used_on:
            last_used = "{}Z".format(self.last_used_on.isoformat())

        return {
            "id": shortuuid.encode(self.id),
            "name": self.name,
            "account_id": shortuuid.encode(self.account_id),
            "access_token": self.access_token,
            "refresh_token": self.refresh_token,
            "client_id": self.client_id,
            "scope": self.scope,
            "token_type": self.token_type,
            "issued_at": self.issued_at,
            "expires_in": self.expires_in,
            "last_used": last_used,
            "revoked": self.revoked
        }
Esempio n. 5
0
class UserPrivacy(db.Model):  # type: ignore
    __bind_key__ = 'dashboard_service'
    id = db.Column(UUIDType(binary=False),
                   primary_key=True,
                   default=uuid.uuid4)
    account_id = db.Column(UUIDType(binary=False),
                           db.ForeignKey('user_account.id'),
                           nullable=False)
    last_changed = db.Column(db.DateTime(), server_default=func.now())
    details = db.Column(JSONB())
Esempio n. 6
0
class Client(db.Model, OAuth2ClientMixin):  # type: ignore
    __bind_key__ = 'auth_service'
    id = db.Column(db.Integer, primary_key=True)
    account_id = db.Column(UUIDType(binary=False),
                           db.ForeignKey('account.id', ondelete='CASCADE'),
                           nullable=False)

    def to_dict(self):
        return {
            "id": self.id,
            "client_id": self.client_id,
            "client_secret": self.client_secret
        }
Esempio n. 7
0
class LocalAccount(db.Model):  # type: ignore
    __bind_key__ = 'auth_service'

    id = db.Column(UUIDType(binary=False),
                   primary_key=True,
                   unique=True,
                   default=uuid.uuid4)
    account_id = db.Column(UUIDType(binary=False),
                           db.ForeignKey('account.id', ondelete='CASCADE'),
                           nullable=False)
    username = db.Column(db.String, nullable=False, unique=True, index=True)
    password = db.Column(PasswordType(schemes=['pbkdf2_sha512'], ),
                         unique=False,
                         nullable=False)
Esempio n. 8
0
class ProviderToken(db.Model, OAuth2TokenMixin):  # type: ignore
    __bind_key__ = 'auth_service'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20), nullable=False)
    account_id = db.Column(UUIDType(binary=False),
                           db.ForeignKey('account.id', ondelete='CASCADE'))
    account = db.relationship('Account')

    def to_dict(self):
        return {
            "id": self.id,
            "access_token": self.access_token,
            "token_type": self.token_type,
            "refresh_token": self.refresh_token,
            "expires_at": self.expires_in,
            "revoked": self.revoked
        }
Esempio n. 9
0
class Execution(db.Model):  # type: ignore
    __bind_key__ = 'experiment_service'
    __table_args__ = (db.UniqueConstraint('timestamp',
                                          'experiment_id',
                                          name='index_per_experiment_uniq'), )

    id = db.Column(UUIDType(binary=False),
                   primary_key=True,
                   default=uuid.uuid4)
    account_id = db.Column(UUIDType(binary=False), nullable=False, index=True)
    timestamp = db.Column(
        db.BigInteger,
        default=lambda: int(datetime.utcnow().timestamp() * 1000))
    org_id = db.Column(UUIDType(binary=False), nullable=False, index=True)
    workspace_id = db.Column(UUIDType(binary=False),
                             nullable=False,
                             index=True)
    experiment_id = db.Column(UUIDType(binary=False),
                              db.ForeignKey('experiment.id',
                                            ondelete='CASCADE'),
                              nullable=False)
    status = db.Column(db.String)
    payload = db.Column(JSONB())

    def to_dict(self, visibility: str = "status") -> Dict[str, Any]:
        result = {
            "id": shortuuid.encode(self.id),
            "timestamp": self.timestamp,
            "org": shortuuid.encode(self.org_id),
            "workspace": shortuuid.encode(self.workspace_id),
            "experiment": shortuuid.encode(self.experiment_id)
        }

        if visibility == "full":
            result["status"] = self.status
            result["result"] = self.payload
        elif visibility == "full":
            result["status"] = self.status
        return result
Esempio n. 10
0
class Org(db.Model):  # type: ignore
    __bind_key__ = 'dashboard_service'

    id = db.Column(UUIDType(binary=False),
                   primary_key=True,
                   default=uuid.uuid4)
    # only set when this is a personal org linked to a single account,
    # otherwise it's not set
    account_id = db.Column(UUIDType(binary=False),
                           db.ForeignKey('user_account.id'),
                           nullable=True)
    name = db.Column(db.String(), nullable=False, unique=True)
    name_lower = db.Column(db.String(), nullable=False, unique=True)
    kind = db.Column(db.Enum(OrgType),
                     nullable=False,
                     default=OrgType.personal)
    created_on = db.Column(db.DateTime(), server_default=func.now())
    workspaces = db.relationship('Workspace',
                                 backref='org',
                                 cascade="all, delete-orphan")
    settings = db.Column(JSONB(), nullable=False, default=DEFAULT_ORG_SETTINGS)

    def to_dict(self, public_workspaces_only: bool = False):
        workspaces = []
        for w in self.workspaces:
            if public_workspaces_only and w.kind != WorkspaceType.public:
                continue

            workspaces.append({"id": shortuuid.encode(w.id), "name": w.name})

        return {
            "id": shortuuid.encode(self.id),
            "name": self.name,
            "settings": self.settings,
            "type": self.kind.value,
            "created_on": "{}Z".format(self.created_on.isoformat()),
            "workspaces": workspaces
        }

    def to_short_dict(self):
        return {
            "id": shortuuid.encode(self.id),
            "name": self.name,
            "created_on": "{}Z".format(self.created_on.isoformat()),
            "settings": self.settings,
            "type": self.kind.value
        }

    @staticmethod
    def get_next_available_name(suggested_name: str) -> str:
        """
        Return the next available name prefixed by the given suggested name and
        suffixed by a number between 0 and 1000.

        If `suggested_name` is not used yet, return it as the available name
        """
        while True:
            has_org = Org.query.filter(Org.name == suggested_name).first()
            if not has_org:
                return suggested_name
            suggested_name = "{}{}".format(suggested_name,
                                           secrets.randbelow(1000))

    @staticmethod
    def get_by_id(org_id: Union[str, uuid.UUID]) -> 'Org':
        """
        Lookup an organization by its identifier
        """
        return Org.query.filter(Org.id == org_id).first()

    @staticmethod
    def find_by_name(org_name: str) -> 'Org':
        """
        Lookup an organization by its name
        """
        return Org.query.filter(Org.name_lower == org_name.lower()).first()

    def find_workspace_by_name(self,
                               workspace_name: str) -> Optional[Workspace]:
        """
        Lookup a workspace in the organization by its name
        """
        w_name = workspace_name.lower()
        for workspace in self.workspaces:
            if workspace.name_lower == w_name:
                return workspace

        return None

    def is_member(self, account_id: Union[str, uuid.UUID]) -> bool:
        """
        Return `True` when the given account is a member of the organization
        """
        return OrgsMembers.query.filter(
            OrgsMembers.org_id == self.id,
            OrgsMembers.account_id == account_id).first() is not None

    def is_owner(self, account_id: Union[str, uuid.UUID]) -> bool:
        """
        Return `True` when the given account is an owner of the organization
        """
        return OrgsMembers.query.filter(
            OrgsMembers.org_id == self.id, OrgsMembers.is_owner == True,
            OrgsMembers.account_id == account_id).first() is not None

    def has_single_owner(self) -> bool:
        """
        Return `True` if only one owner exists for this organization
        """
        return OrgsMembers.query.filter(
            OrgsMembers.org_id == self.id,
            OrgsMembers.is_owner == True).count() == 1

    def make_member(self, account_id: Union[str, uuid.UUID]):
        """
        Turn an user as a member only of this organization.

        The user must already be part of this organization, this is mostly
        therefore useful when moving an owner down to simple member.
        """
        membership = OrgsMembers.query.filter(
            OrgsMembers.org_id == self.id,
            OrgsMembers.account_id == account_id).first()
        if membership:
            membership.is_owner = False

    def make_owner(self, account_id: Union[str, uuid.UUID]):
        """
        Turn an user as an owner of this organization.
        """
        membership = OrgsMembers.query.filter(
            OrgsMembers.org_id == self.id,
            OrgsMembers.account_id == account_id).first()
        if membership:
            membership.is_owner = True

    def add_member(self, account_id: Union[str, uuid.UUID]) -> OrgsMembers:
        """
        Add this user to the organization as a member
        """
        membership = OrgsMembers(org_id=self.id, account_id=account_id)
        db.session.add(membership)
        return membership

    def remove_member(self, account_id: Union[str, uuid.UUID]):
        """
        Remove this member from the organization
        """
        OrgsMembers.query.filter(
            OrgsMembers.org_id == self.id,
            OrgsMembers.account_id == account_id).delete()

    def get_public_workspace_ids(self) -> List[uuid.UUID]:
        """
        List all public workspaces in this organization and return their
        identifiers
        """
        result = db.session.query(Workspace.id).filter(
            Workspace.org_id == self.id,
            Workspace.kind == WorkspaceType.public).all()
        if not result:
            return []

        return result[0]
Esempio n. 11
0
class Workspace(db.Model):  # type: ignore
    __bind_key__ = 'dashboard_service'
    __table_args__ = (db.UniqueConstraint('name',
                                          'org_id',
                                          name='workspace_org_uniq'), )

    id = db.Column(UUIDType(binary=False),
                   primary_key=True,
                   default=uuid.uuid4)
    name = db.Column(db.String(), nullable=False)
    name_lower = db.Column(db.String(), nullable=False)
    kind = db.Column(db.Enum(WorkspaceType),
                     nullable=False,
                     default=WorkspaceType.personal)
    org_id = db.Column(UUIDType(binary=False),
                       db.ForeignKey('org.id'),
                       nullable=False)
    settings = db.Column(JSONB(),
                         nullable=False,
                         default=DEFAULT_WORKSPACE_SETTINGS)

    def to_dict(self):
        return {
            "id": shortuuid.encode(self.id),
            "name": self.name,
            "type": self.kind.value,
            "org": {
                "id": shortuuid.encode(self.org_id),
                "name": self.org.name,
                "type": self.org.kind.value
            },
            "settings": self.settings
        }

    def to_short_dict(self):
        return {
            "id": shortuuid.encode(self.id),
            "name": self.name,
            "type": self.kind.value,
            "settings": self.settings
        }

    @staticmethod
    def find_by_name(workspace_name: str) -> 'Workspace':
        """
        Get a workspace by its name
        """
        return Workspace.query.filter(
            Workspace.name_lower == workspace_name.lower()).first()

    @staticmethod
    def get_by_id(workspace_id: Union[str, uuid.UUID]) -> 'Workspace':
        """
        Get a workspace by its identifier
        """
        return Workspace.query.filter(Workspace.id == workspace_id).first()

    def is_collaborator(self, account_id: Union[str, uuid.UUID]) -> bool:
        """
        Return `True` when the given account is a collaborator to this
        workspace
        """
        return WorkpacesMembers.query.filter(
            WorkpacesMembers.workspace_id == self.id,
            WorkpacesMembers.account_id == account_id).first() is not None

    def is_owner(self, account_id: Union[str, uuid.UUID]) -> bool:
        """
        Return `True` when the given account is an owner of the workspace
        """
        return WorkpacesMembers.query.filter(
            WorkpacesMembers.workspace_id == self.id,
            WorkpacesMembers.is_owner == True,
            WorkpacesMembers.account_id == account_id).first() is not None

    def has_single_owner(self) -> bool:
        """
        Return `True` if only one owner exists for this workspace
        """
        return WorkpacesMembers.query.filter(
            WorkpacesMembers.workspace_id == self.id,
            WorkpacesMembers.is_owner == True).count() == 1

    def make_collaborator(self, account_id: Union[str, uuid.UUID]):
        """
        Turn an user as a collaborator only of this workspace.
        """
        membership = WorkpacesMembers.query.filter(
            WorkpacesMembers.workspace_id == self.id,
            WorkpacesMembers.account_id == account_id).first()
        if membership:
            membership.is_owner = False

    def make_owner(self, account_id: Union[str, uuid.UUID]):
        """
        Turn an user as an owner of this workspace.
        """
        membership = WorkpacesMembers.query.filter(
            WorkpacesMembers.workspace_id == self.id,
            WorkpacesMembers.account_id == account_id).first()
        if membership:
            membership.is_owner = True

    def add_collaborator(self, account_id: Union[str, uuid.UUID]) \
            -> WorkpacesMembers:
        """
        Add this user to the organization as a collaborator
        """
        membership = WorkpacesMembers(workspace_id=self.id,
                                      account_id=account_id)
        db.session.add(membership)
        return membership

    def remove_collaborator(self, account_id: Union[str, uuid.UUID]):
        """
        Remove this collaborator from the organization
        """
        WorkpacesMembers.query.filter(
            WorkpacesMembers.workspace_id == self.id,
            WorkpacesMembers.account_id == account_id).delete()
Esempio n. 12
0
class UserInfo(db.Model):  # type: ignore
    __bind_key__ = 'dashboard_service'
    id = db.Column(UUIDType(binary=False),
                   primary_key=True,
                   default=uuid.uuid4)
    account_id = db.Column(UUIDType(binary=False),
                           db.ForeignKey('user_account.id'),
                           nullable=False)
    last_updated = db.Column(db.DateTime(),
                             server_default=func.now(),
                             onupdate=func.current_timestamp())
    verified_email = db.Column(db.Boolean(), default=False)

    # values for search purpose mostly
    username = db.Column(db.String, index=True, nullable=True)
    fullname = db.Column(db.String, index=True, nullable=True)

    details = db.Column(EncryptedType(db.String, get_user_info_secret_key,
                                      AesEngine, 'pkcs5'),
                        nullable=False)

    @staticmethod
    def get_for_account(account_id: Union[str, uuid.UUID]) -> 'UserInfo':
        """
        Lookup user info for the given user account
        """
        return UserInfo.query.filter(UserInfo.account_id == account_id).first()

    @property
    def profile(self) -> Dict[str, Any]:
        """
        The user's profile
        """
        return json.loads(self.details)

    @profile.setter
    def profile(self, p: Dict[str, Any]):
        """
        Set the user's profile from the given payload

        The payload is serialized to JSON and stored in the `details`
        property
        """
        self.details = json.dumps(p)

    def to_dict(self):
        return {
            "id": shortuuid.encode(self.id),
            "account": shortuuid.encode(self.account.id),
            "profile": self.profile
        }

    def to_public_dict(self):
        p = self.profile

        return {
            "id": shortuuid.encode(self.id),
            "username": p.get("preferred_username"),
            "name": p.get("name"),
            "picture": p.get("picture")
        }