dataflow-core 2.1.15rc1__py3-none-any.whl → 2.1.15rc3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dataflow-core might be problematic. Click here for more details.
- authenticator/dataflowhubauthenticator.py +19 -41
- dataflow/dataflow.py +45 -69
- dataflow/environment.py +20 -11
- dataflow/models/__init__.py +5 -3
- dataflow/models/app_types.py +8 -3
- dataflow/models/connection.py +5 -4
- dataflow/models/dataflow_zone.py +2 -3
- dataflow/models/environment.py +64 -21
- dataflow/models/git_ssh.py +2 -1
- dataflow/models/org_associations.py +38 -0
- dataflow/models/organization.py +78 -0
- dataflow/models/pinned_projects.py +2 -2
- dataflow/models/project_details.py +9 -6
- dataflow/models/recent_project_studio.py +1 -1
- dataflow/models/role.py +12 -6
- dataflow/models/role_server.py +2 -5
- dataflow/models/role_zone.py +8 -3
- dataflow/models/server_config.py +9 -5
- dataflow/models/team.py +10 -4
- dataflow/models/user.py +49 -12
- dataflow/models/user_team.py +1 -4
- dataflow/models/variables.py +6 -4
- dataflow/secrets_manager/service.py +11 -9
- dataflow/utils/get_current_user.py +51 -28
- {dataflow_core-2.1.15rc1.dist-info → dataflow_core-2.1.15rc3.dist-info}/METADATA +2 -1
- dataflow_core-2.1.15rc3.dist-info/RECORD +63 -0
- {dataflow_core-2.1.15rc1.dist-info → dataflow_core-2.1.15rc3.dist-info}/top_level.txt +1 -0
- dfmigration/__init__.py +0 -0
- dfmigration/env.py +45 -0
- dfmigration/versions/001_initial_baseline_migration.py +20 -0
- dfmigration/versions/__init__.py +0 -0
- dataflow/models/user_environment.py +0 -16
- dataflow_core-2.1.15rc1.dist-info/RECORD +0 -58
- {dataflow_core-2.1.15rc1.dist-info → dataflow_core-2.1.15rc3.dist-info}/WHEEL +0 -0
- {dataflow_core-2.1.15rc1.dist-info → dataflow_core-2.1.15rc3.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from sqlalchemy import Column , Integer, String, Boolean, ForeignKey, UniqueConstraint, Enum
|
|
2
|
+
from sqlalchemy.orm import relationship
|
|
3
|
+
from dataflow.db import Base
|
|
4
|
+
import enum
|
|
5
|
+
from dataflow.models.environment import EnvType
|
|
6
|
+
|
|
7
|
+
class OrganizationUser(Base):
|
|
8
|
+
"""
|
|
9
|
+
Association Table between USER, ROLE, and ORGANIZATION
|
|
10
|
+
"""
|
|
11
|
+
__tablename__ = "ORGANIZATION_USER"
|
|
12
|
+
__table_args__ = (UniqueConstraint('org_id', 'user_id', name='uq_org_user'),)
|
|
13
|
+
|
|
14
|
+
org_id = Column(Integer, ForeignKey('ORGANIZATION.id', ondelete="CASCADE"), primary_key=True, nullable=False)
|
|
15
|
+
user_id = Column(Integer, ForeignKey('USER.user_id', ondelete="CASCADE"), primary_key=True, nullable=False)
|
|
16
|
+
role_id = Column(Integer, ForeignKey('ROLE.id', ondelete="SET NULL"), nullable=False)
|
|
17
|
+
active_env_short_name = Column(String, nullable=True)
|
|
18
|
+
active_env_type = Column(Enum(EnvType), nullable=True)
|
|
19
|
+
active_server_id = Column(Integer, ForeignKey('CUSTOM_SERVER.id', ondelete="SET NULL"))
|
|
20
|
+
show_server_page = Column(Boolean, default = True, server_default='true')
|
|
21
|
+
monthly_allocation = Column(Integer, nullable=True, default=0, server_default='0')
|
|
22
|
+
|
|
23
|
+
# Relationships
|
|
24
|
+
user = relationship("User", back_populates="org_user_assocs")
|
|
25
|
+
role = relationship("Role", back_populates="org_user_assocs")
|
|
26
|
+
organization = relationship("Organization", back_populates="org_user_assocs")
|
|
27
|
+
|
|
28
|
+
class OrganizationServer(Base):
|
|
29
|
+
__tablename__ = "ORGANIZATION_SERVER"
|
|
30
|
+
|
|
31
|
+
org_id = Column(Integer, ForeignKey('ORGANIZATION.id', ondelete="CASCADE"), primary_key=True, nullable=False)
|
|
32
|
+
server_id = Column(Integer, ForeignKey('SERVER_CONFIG.id', ondelete="CASCADE"), primary_key=True, nullable=False)
|
|
33
|
+
|
|
34
|
+
class OrganizationAppType(Base):
|
|
35
|
+
__tablename__ = "ORGANIZATION_APP_TYPE"
|
|
36
|
+
|
|
37
|
+
org_id = Column(Integer, ForeignKey('ORGANIZATION.id', ondelete="CASCADE"), primary_key=True, nullable=False)
|
|
38
|
+
app_type_id = Column(Integer, ForeignKey('APP_TYPE.id', ondelete="CASCADE"), primary_key=True, nullable=False)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from sqlalchemy import (
|
|
2
|
+
Column, Integer, String, Enum, DateTime, ForeignKey, Index, text
|
|
3
|
+
)
|
|
4
|
+
import uuid, enum
|
|
5
|
+
from sqlalchemy.dialects.postgresql import JSONB, UUID
|
|
6
|
+
from sqlalchemy.sql import func
|
|
7
|
+
from sqlalchemy.orm import relationship
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from dataflow.db import Base
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Organization(Base):
|
|
13
|
+
"""
|
|
14
|
+
Organization model for the database.
|
|
15
|
+
"""
|
|
16
|
+
__tablename__ = "ORGANIZATION"
|
|
17
|
+
|
|
18
|
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
19
|
+
uid = Column(UUID(as_uuid=True), default=uuid.uuid4, nullable=False, unique=True, server_default=text("gen_random_uuid()"))
|
|
20
|
+
name = Column(String(255), nullable=False, unique=True)
|
|
21
|
+
invite_code = Column(String(64), nullable=False, unique=True)
|
|
22
|
+
email_domain = Column(String(255), nullable=False, unique=True)
|
|
23
|
+
spark_enabled_zones = Column(JSONB, default=func.json([]), server_default=text("'[]'::jsonb")) # List of zone IDs where Spark is enabled
|
|
24
|
+
created_at = Column(DateTime, default=datetime.utcnow, server_default=func.now())
|
|
25
|
+
|
|
26
|
+
# Association object link
|
|
27
|
+
org_user_assocs = relationship("OrganizationUser", back_populates="organization", cascade="all, delete-orphan")
|
|
28
|
+
custom_servers = relationship("CustomServerConfig")
|
|
29
|
+
onboarding_requests = relationship("UserOnboarding", back_populates="organization", cascade="all, delete-orphan")
|
|
30
|
+
servers = relationship("ServerConfig", secondary="ORGANIZATION_SERVER", back_populates="organizations")
|
|
31
|
+
apps = relationship("AppType", secondary="ORGANIZATION_APP_TYPE", back_populates="organizations")
|
|
32
|
+
roles = relationship("Role", cascade="all, delete-orphan")
|
|
33
|
+
environments = relationship("Environment", back_populates="organization")
|
|
34
|
+
|
|
35
|
+
class OnboardingStatus(enum.Enum):
|
|
36
|
+
pending = 'pending'
|
|
37
|
+
rejected = 'rejected'
|
|
38
|
+
accepted = 'accepted'
|
|
39
|
+
|
|
40
|
+
class OrganizationOnboarding(Base):
|
|
41
|
+
__tablename__ = 'ORGANIZATION_ONBOARDING'
|
|
42
|
+
# This prevents an org from having more than one active ('pending' or 'accepted') application
|
|
43
|
+
# while allowing multiple 'rejected' entries.
|
|
44
|
+
__table_args__ = (
|
|
45
|
+
Index(
|
|
46
|
+
'idx_pending_org_application',
|
|
47
|
+
'name',
|
|
48
|
+
unique=True,
|
|
49
|
+
postgresql_where=Column('status').in_([
|
|
50
|
+
OnboardingStatus.pending.value,
|
|
51
|
+
OnboardingStatus.accepted.value
|
|
52
|
+
])
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
57
|
+
|
|
58
|
+
name = Column(String(255), nullable=False)
|
|
59
|
+
age = Column(Integer, nullable=True)
|
|
60
|
+
domain = Column(String(255), nullable=True)
|
|
61
|
+
no_of_employees = Column(String(50), nullable=True)
|
|
62
|
+
address = Column(String(500), nullable=True)
|
|
63
|
+
|
|
64
|
+
admin_first_name = Column(String(100), nullable=False)
|
|
65
|
+
admin_last_name = Column(String(100), nullable=True)
|
|
66
|
+
admin_designation = Column(String(100), nullable=False)
|
|
67
|
+
admin_email = Column(String(255), nullable=False, unique=True)
|
|
68
|
+
admin_username = Column(String(100), nullable=False, unique=True)
|
|
69
|
+
admin_password = Column(String(255), nullable=False)
|
|
70
|
+
|
|
71
|
+
discovery_source = Column(String(255), nullable=True)
|
|
72
|
+
additional_info = Column(String(1000), nullable=True)
|
|
73
|
+
size_of_data = Column(String(100), nullable=True)
|
|
74
|
+
|
|
75
|
+
user_id = Column(Integer, ForeignKey('USER.user_id'), nullable=False)
|
|
76
|
+
status = Column(Enum(OnboardingStatus), default=OnboardingStatus.pending, nullable=False)
|
|
77
|
+
|
|
78
|
+
user = relationship("User", back_populates="organization_onboarding")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from sqlalchemy import Column, Integer, ForeignKey, DateTime, UniqueConstraint
|
|
1
|
+
from sqlalchemy import Column, Integer, ForeignKey, DateTime, UniqueConstraint, func
|
|
2
2
|
from dataflow.db import Base
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
|
|
@@ -8,7 +8,7 @@ class PinnedProject(Base):
|
|
|
8
8
|
id = Column(Integer, primary_key=True)
|
|
9
9
|
user_id = Column(Integer, ForeignKey('USER.user_id', ondelete="CASCADE"), index=True)
|
|
10
10
|
project_id = Column(Integer, ForeignKey('PROJECT_DETAIL.project_id', ondelete="CASCADE"), index=True)
|
|
11
|
-
pinned_at = Column(DateTime, default=datetime.utcnow)
|
|
11
|
+
pinned_at = Column(DateTime, default=datetime.utcnow, server_default=func.now())
|
|
12
12
|
|
|
13
13
|
__table_args__ = (
|
|
14
14
|
UniqueConstraint("user_id", "project_id", name="uix_user_project"),
|
|
@@ -1,23 +1,26 @@
|
|
|
1
|
-
from sqlalchemy import Column, String, Enum, DateTime, Integer, func, ForeignKey
|
|
1
|
+
from sqlalchemy import Column, String, Enum, DateTime, Integer, func, ForeignKey, UniqueConstraint
|
|
2
2
|
from sqlalchemy.orm import relationship
|
|
3
3
|
from dataflow.db import Base
|
|
4
4
|
|
|
5
5
|
class ProjectDetails(Base):
|
|
6
6
|
__tablename__ = "PROJECT_DETAIL"
|
|
7
|
+
__table_args__ = (UniqueConstraint('org_id', 'slug', name='uq_project_org_slug'),)
|
|
7
8
|
|
|
8
9
|
project_id = Column(Integer, primary_key=True, autoincrement=True)
|
|
9
10
|
project_name = Column(String, nullable=False)
|
|
10
11
|
git_url = Column(String)
|
|
11
12
|
git_branch = Column(String, nullable=True)
|
|
12
13
|
git_folder = Column(String, nullable=True)
|
|
13
|
-
type = Column(String, ForeignKey('
|
|
14
|
-
slug = Column(String, nullable=False
|
|
14
|
+
type = Column(String, ForeignKey('APP_TYPE.name'), nullable=False)
|
|
15
|
+
slug = Column(String, nullable=False)
|
|
15
16
|
runtime = Column(String, nullable=False)
|
|
16
|
-
py_env = Column(
|
|
17
|
+
py_env = Column(Integer, nullable=True)
|
|
17
18
|
launch_url = Column(String, nullable=True)
|
|
18
|
-
status = Column(Enum("pending", "created" ,"deployed", "stopped", "failed", name="deployment_status"), default="created")
|
|
19
|
+
status = Column(Enum("pending", "created" ,"deployed", "stopped", "failed", name="deployment_status"), default="created", server_default="created")
|
|
19
20
|
last_deployed = Column(DateTime, nullable=True)
|
|
20
21
|
created_at = Column(DateTime, nullable=False, server_default=func.now())
|
|
21
22
|
created_by = Column(String, nullable=False)
|
|
23
|
+
org_id = Column(Integer, ForeignKey('ORGANIZATION.id', ondelete='CASCADE'), nullable=False)
|
|
24
|
+
airflow_config_file = Column(String, nullable=True)
|
|
22
25
|
|
|
23
|
-
app_type = relationship("AppType")
|
|
26
|
+
app_type = relationship("AppType")
|
|
@@ -12,7 +12,7 @@ class RecentProjectStudio(Base):
|
|
|
12
12
|
project_name = Column(String, nullable=False)
|
|
13
13
|
project_path = Column(String, nullable=False)
|
|
14
14
|
last_opened_date = Column(DateTime, server_default=func.now(), nullable=False)
|
|
15
|
-
remember = Column(Boolean, default=False)
|
|
15
|
+
remember = Column(Boolean, default=False, server_default='false')
|
|
16
16
|
|
|
17
17
|
__table_args__ = (
|
|
18
18
|
UniqueConstraint(user_name, project_path, app_name, name='user_name_project_path_app_name_unique'),
|
dataflow/models/role.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""models.py"""
|
|
2
|
-
from sqlalchemy import Column, Integer, String, Enum
|
|
2
|
+
from sqlalchemy import Column, Integer, String, Enum, ForeignKey, UniqueConstraint
|
|
3
3
|
from sqlalchemy.orm import relationship
|
|
4
4
|
from dataflow.db import Base
|
|
5
5
|
import enum
|
|
@@ -11,19 +11,25 @@ class BaseRoleField(enum.Enum):
|
|
|
11
11
|
|
|
12
12
|
class Role(Base):
|
|
13
13
|
"""
|
|
14
|
-
Table
|
|
14
|
+
Table ROLE
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
__tablename__='ROLE'
|
|
18
|
+
__table_args__ = (
|
|
19
|
+
UniqueConstraint('name', 'org_id', name='uq_role_name_org'),
|
|
20
|
+
)
|
|
18
21
|
|
|
19
22
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True, nullable=False)
|
|
20
|
-
name = Column(String,
|
|
23
|
+
name = Column(String, nullable=False)
|
|
24
|
+
org_id = Column(Integer, ForeignKey('ORGANIZATION.id'))
|
|
21
25
|
description = Column(String, nullable=True)
|
|
22
|
-
base_role = Column(Enum(BaseRoleField), nullable=False, default=BaseRoleField.user)
|
|
26
|
+
base_role = Column(Enum(BaseRoleField), nullable=False, default=BaseRoleField.user, server_default=BaseRoleField.user.value)
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
role_server_assocs = relationship("RoleServer", back_populates="role")
|
|
28
|
+
# Relationships
|
|
26
29
|
role_zone_assocs = relationship("RoleZone", back_populates="role")
|
|
30
|
+
org_user_assocs = relationship("OrganizationUser", back_populates="role", cascade="all, delete-orphan")
|
|
31
|
+
organization = relationship("Organization", back_populates="roles")
|
|
32
|
+
servers = relationship("CustomServerConfig", secondary="ROLE_SERVER", back_populates="roles")
|
|
27
33
|
|
|
28
34
|
def __repr__(self):
|
|
29
35
|
return f"<Role(id={self.id}, name='{self.name}', base_role='{self.base_role}')>"
|
dataflow/models/role_server.py
CHANGED
|
@@ -5,10 +5,7 @@ from dataflow.db import Base
|
|
|
5
5
|
|
|
6
6
|
class RoleServer(Base):
|
|
7
7
|
__tablename__ = 'ROLE_SERVER'
|
|
8
|
-
__table_args__ = (UniqueConstraint('role_id', '
|
|
8
|
+
__table_args__ = (UniqueConstraint('role_id', 'custom_server_id', name='_role_server_uc'),)
|
|
9
9
|
|
|
10
10
|
role_id = Column(Integer, ForeignKey('ROLE.id', ondelete="CASCADE"), nullable=False, primary_key=True)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
role = relationship("Role", back_populates="role_server_assocs")
|
|
14
|
-
server = relationship("CustomServerConfig", back_populates="role_server_assocs")
|
|
11
|
+
custom_server_id = Column(Integer, ForeignKey('CUSTOM_SERVER.id', ondelete="CASCADE"), nullable=False, primary_key=True)
|
dataflow/models/role_zone.py
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
from typing import Dict, List, Optional
|
|
2
|
-
from sqlalchemy import Column, Integer, ForeignKey, UniqueConstraint, Boolean
|
|
2
|
+
from sqlalchemy import Column, Integer, ForeignKey, UniqueConstraint, Boolean, Index
|
|
3
3
|
from sqlalchemy.orm import relationship
|
|
4
4
|
from dataflow.db import Base
|
|
5
5
|
|
|
6
6
|
class RoleZone(Base):
|
|
7
7
|
__tablename__ = 'ROLE_ZONE'
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
role_id = Column(Integer, ForeignKey('ROLE.id', ondelete="CASCADE"), primary_key=True)
|
|
10
10
|
zone_id = Column(Integer, ForeignKey('DATAFLOW_ZONE.id', ondelete="CASCADE"), primary_key=True)
|
|
11
|
-
is_default = Column(Boolean, default=False, nullable=False)
|
|
11
|
+
is_default = Column(Boolean, default=False, nullable=False, server_default='false')
|
|
12
|
+
|
|
13
|
+
__table_args__ = (
|
|
14
|
+
Index('idx_role_runtime_default', 'role_id', unique=True,
|
|
15
|
+
postgresql_where=is_default.is_(True)),
|
|
16
|
+
)
|
|
12
17
|
|
|
13
18
|
role = relationship("Role", back_populates="role_zone_assocs")
|
|
14
19
|
zone = relationship("DataflowZone", back_populates="role_zone_assocs")
|
dataflow/models/server_config.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from sqlalchemy import Column, Integer, String, Boolean, Text, ForeignKey
|
|
1
|
+
from sqlalchemy import Column, Integer, String, Boolean, Text, ForeignKey, text
|
|
2
2
|
from sqlalchemy.dialects.postgresql import JSONB
|
|
3
3
|
from sqlalchemy.sql import func
|
|
4
4
|
from sqlalchemy.orm import relationship
|
|
@@ -14,20 +14,24 @@ class ServerConfig(Base):
|
|
|
14
14
|
ram = Column(String, nullable=False)
|
|
15
15
|
cpu = Column(String, nullable=False)
|
|
16
16
|
gpu = Column(String)
|
|
17
|
-
default = Column(Boolean, default=False)
|
|
18
|
-
tags = Column(JSONB, default=func.json([]))
|
|
17
|
+
default = Column(Boolean, default=False, server_default='false')
|
|
18
|
+
tags = Column(JSONB, default=func.json([]), server_default=text("'[]'::jsonb"))
|
|
19
19
|
description = Column(Text, nullable=True)
|
|
20
|
-
kubespawner_override = Column(JSONB, default=func.json({}))
|
|
20
|
+
kubespawner_override = Column(JSONB, default=func.json({}), server_default=text("'{}'::jsonb"))
|
|
21
21
|
|
|
22
|
+
# Relationships
|
|
23
|
+
organizations = relationship("Organization", secondary="ORGANIZATION_SERVER", back_populates="servers")
|
|
22
24
|
|
|
23
25
|
class CustomServerConfig(Base):
|
|
24
26
|
__tablename__ = "CUSTOM_SERVER"
|
|
25
27
|
|
|
26
28
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
27
29
|
base_server_id = Column(Integer, ForeignKey(ServerConfig.id, ondelete="CASCADE"), nullable=False)
|
|
30
|
+
org_id = Column(Integer, ForeignKey('ORGANIZATION.id', ondelete="CASCADE"), nullable=False)
|
|
28
31
|
display_name = Column(String, nullable=False, unique=True, index=True)
|
|
29
32
|
description = Column(Text, nullable=True)
|
|
30
33
|
|
|
31
34
|
# Relationship to the server_config table
|
|
32
35
|
server_config = relationship(ServerConfig)
|
|
33
|
-
|
|
36
|
+
organization = relationship("Organization", back_populates="custom_servers")
|
|
37
|
+
roles = relationship("Role", secondary="ROLE_SERVER", back_populates="servers")
|
dataflow/models/team.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""models.py"""
|
|
2
|
-
from sqlalchemy import Column, Integer, String
|
|
2
|
+
from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint
|
|
3
3
|
from sqlalchemy.orm import relationship
|
|
4
4
|
from dataflow.db import Base
|
|
5
5
|
|
|
@@ -9,9 +9,15 @@ class Team(Base):
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
__tablename__='TEAM'
|
|
12
|
+
__table_args__ = (
|
|
13
|
+
UniqueConstraint('team_name', 'org_id', name='uc_team_name_org_id'),
|
|
14
|
+
)
|
|
12
15
|
|
|
13
16
|
team_id = Column(Integer, primary_key=True, index=True, autoincrement=True, nullable=False)
|
|
14
|
-
team_name = Column(String,
|
|
17
|
+
team_name = Column(String, nullable=False)
|
|
18
|
+
org_id = Column(Integer, ForeignKey('ORGANIZATION.id', ondelete="CASCADE"), nullable=False)
|
|
15
19
|
description = Column(String, nullable=True)
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
|
|
21
|
+
# relationships
|
|
22
|
+
users = relationship("User", secondary="USER_TEAM", back_populates="teams")
|
|
23
|
+
organization = relationship("Organization")
|
dataflow/models/user.py
CHANGED
|
@@ -1,31 +1,68 @@
|
|
|
1
1
|
"""models.py"""
|
|
2
|
-
from sqlalchemy import Column, Integer, String, Boolean, LargeBinary, ForeignKey
|
|
2
|
+
from sqlalchemy import Column, Integer, String, Boolean, LargeBinary, Enum, ForeignKey, DateTime, func
|
|
3
|
+
from sqlalchemy.dialects.postgresql import ENUM
|
|
4
|
+
from sqlalchemy import Index
|
|
3
5
|
from sqlalchemy.orm import relationship
|
|
4
6
|
from dataflow.db import Base
|
|
7
|
+
import enum
|
|
5
8
|
|
|
6
9
|
class User(Base):
|
|
7
10
|
"""
|
|
8
11
|
Table USER
|
|
9
12
|
"""
|
|
10
|
-
|
|
11
|
-
__tablename__='USER'
|
|
13
|
+
__tablename__ = 'USER'
|
|
12
14
|
|
|
13
15
|
user_id = Column(Integer, primary_key=True, index=True, autoincrement=True, nullable=False)
|
|
14
16
|
user_name = Column(String, unique=True, nullable=False)
|
|
15
17
|
first_name = Column(String)
|
|
16
18
|
last_name = Column(String)
|
|
17
19
|
email = Column(String, unique=True)
|
|
18
|
-
role_id = Column(Integer, ForeignKey('ROLE.id'), nullable=False)
|
|
19
20
|
image = Column(LargeBinary)
|
|
20
21
|
image_url = Column(String, nullable=True)
|
|
21
|
-
active = Column(Boolean, nullable=False, default=True)
|
|
22
|
+
active = Column(Boolean, nullable=False, default=True, server_default='true')
|
|
22
23
|
password = Column(String, nullable=False)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
active_org_id = Column(Integer, ForeignKey('ORGANIZATION.id'))
|
|
25
|
+
|
|
26
|
+
# Relationships
|
|
27
|
+
org_user_assocs = relationship("OrganizationUser", back_populates="user", cascade="all, delete-orphan")
|
|
28
|
+
teams = relationship("Team", secondary="USER_TEAM", back_populates="users")
|
|
29
|
+
onboarding_requests = relationship("UserOnboarding", back_populates="user", cascade="all, delete-orphan")
|
|
30
|
+
organization_onboarding = relationship("OrganizationOnboarding", back_populates="user", cascade="all, delete-orphan")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class OnboardingStatus(enum.Enum):
|
|
34
|
+
pending = 'pending'
|
|
35
|
+
rejected = 'rejected'
|
|
36
|
+
accepted = 'accepted'
|
|
37
|
+
|
|
38
|
+
class UserOnboarding(Base):
|
|
39
|
+
"""
|
|
40
|
+
SQLAlchemy model for the "USER_ONBOARDING" table.
|
|
41
|
+
This table stores user applications to organizations.
|
|
42
|
+
"""
|
|
43
|
+
__tablename__ = "USER_ONBOARDING"
|
|
44
|
+
# This prevents a user from having more than one active ('pending' or 'accepted') application
|
|
45
|
+
# for a given organization, while allowing multiple 'rejected' entries.
|
|
46
|
+
__table_args__ = (
|
|
47
|
+
Index(
|
|
48
|
+
'idx_pending_user_org_application',
|
|
49
|
+
'user_id',
|
|
50
|
+
'org_id',
|
|
51
|
+
unique=True,
|
|
52
|
+
postgresql_where=Column('status').in_([
|
|
53
|
+
OnboardingStatus.pending.value,
|
|
54
|
+
OnboardingStatus.accepted.value
|
|
55
|
+
])
|
|
56
|
+
),
|
|
57
|
+
)
|
|
28
58
|
|
|
29
|
-
|
|
59
|
+
id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
|
|
60
|
+
user_id = Column(Integer, ForeignKey("USER.user_id", ondelete="CASCADE"), nullable=False)
|
|
61
|
+
org_id = Column(Integer, ForeignKey("ORGANIZATION.id", ondelete="CASCADE"), nullable=False)
|
|
62
|
+
status = Column(Enum(OnboardingStatus, name='onboarding_status'), nullable=False, default=OnboardingStatus.pending.value, server_default='pending')
|
|
63
|
+
created_at = Column(DateTime, default=func.now(), nullable=False, server_default=func.now())
|
|
64
|
+
updated_at = Column(DateTime, default=func.now(), onupdate=func.now(), nullable=False, server_default=func.now())
|
|
30
65
|
|
|
31
|
-
|
|
66
|
+
# Relationships
|
|
67
|
+
user = relationship("User", back_populates="onboarding_requests")
|
|
68
|
+
organization = relationship("Organization", back_populates="onboarding_requests")
|
dataflow/models/user_team.py
CHANGED
|
@@ -8,7 +8,4 @@ class UserTeam(Base):
|
|
|
8
8
|
__table_args__ = (UniqueConstraint('user_id', 'team_id', name='_user_team_uc'),)
|
|
9
9
|
|
|
10
10
|
user_id = Column(Integer, ForeignKey('USER.user_id', ondelete="CASCADE"), nullable=False, primary_key=True)
|
|
11
|
-
team_id = Column(Integer, ForeignKey('TEAM.team_id', ondelete="CASCADE"), nullable=False, primary_key=True)
|
|
12
|
-
|
|
13
|
-
user = relationship("User", back_populates="user_team_assocs")
|
|
14
|
-
team = relationship("Team", back_populates="user_team_assocs")
|
|
11
|
+
team_id = Column(Integer, ForeignKey('TEAM.team_id', ondelete="CASCADE"), nullable=False, primary_key=True)
|
dataflow/models/variables.py
CHANGED
|
@@ -14,7 +14,8 @@ class Variable(Base):
|
|
|
14
14
|
__tablename__ = 'VARIABLE'
|
|
15
15
|
|
|
16
16
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True, nullable=False)
|
|
17
|
-
key = Column(String, nullable=False)
|
|
17
|
+
key = Column(String, index=True, nullable=False)
|
|
18
|
+
org_id = Column(Integer, ForeignKey("ORGANIZATION.id"), index=True, nullable=False)
|
|
18
19
|
value = Column(Text, nullable=False)
|
|
19
20
|
type = Column(String, nullable=False)
|
|
20
21
|
description = Column(Text, nullable=True)
|
|
@@ -24,11 +25,12 @@ class Variable(Base):
|
|
|
24
25
|
created_at = Column(DateTime, server_default=func.now())
|
|
25
26
|
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
|
26
27
|
created_by = Column(String, ForeignKey('USER.user_name'), nullable=True)
|
|
27
|
-
is_active = Column(Boolean, default=True, nullable=False)
|
|
28
|
+
is_active = Column(Boolean, default=True, nullable=False, server_default='true')
|
|
28
29
|
datatype = Column(Enum(DataType, name="data_type"), nullable=False)
|
|
29
|
-
set_as_env = Column(Boolean, default=False, nullable=False)
|
|
30
|
+
set_as_env = Column(Boolean, default=False, nullable=False, server_default='false')
|
|
31
|
+
|
|
30
32
|
|
|
31
33
|
__table_args__ = (
|
|
32
34
|
CheckConstraint(type.in_(['variable', 'secret']), name='check_variable_type'),
|
|
33
|
-
UniqueConstraint('key', 'runtime', 'slug', 'created_by', name='unique_key'),
|
|
35
|
+
UniqueConstraint('key', 'org_id', 'runtime', 'slug', 'created_by', name='unique_key'),
|
|
34
36
|
)
|
|
@@ -117,27 +117,29 @@ class _BaseAccessor(ABC):
|
|
|
117
117
|
# These classes implement the logic for building the vault path based on the context.
|
|
118
118
|
# --------------------------------------------------------------------------
|
|
119
119
|
class _RuntimeAccessor(_BaseAccessor):
|
|
120
|
-
def __init__(self, secret_manager: SecretManager, runtime_env: str, slug: str = None):
|
|
120
|
+
def __init__(self, secret_manager: SecretManager, org_id: str, runtime_env: str, slug: str = None):
|
|
121
121
|
super().__init__(secret_manager)
|
|
122
|
+
self.org_id = org_id
|
|
122
123
|
self.runtime_env = runtime_env
|
|
123
124
|
self.slug = slug
|
|
124
125
|
|
|
125
126
|
def _get_vault_path(self, secret_type: str, key: str) -> str:
|
|
126
127
|
# Special case for git-ssh in runtime context
|
|
127
128
|
if secret_type == "git-ssh":
|
|
128
|
-
return f"{self.runtime_env}-{secret_type}-{self.slug}"
|
|
129
|
+
return f"{self.org_id}-{self.runtime_env}-{secret_type}-{self.slug}"
|
|
129
130
|
|
|
130
131
|
# Standard format for all other secret types
|
|
131
132
|
context = self.slug if self.slug else "global"
|
|
132
|
-
return f"{self.runtime_env}-{context}-{secret_type}-{key}"
|
|
133
|
+
return f"{self.org_id}-{self.runtime_env}-{context}-{secret_type}-{key}"
|
|
133
134
|
|
|
134
135
|
class _StudioAccessor(_BaseAccessor):
|
|
135
|
-
def __init__(self, secret_manager: SecretManager, user_name: str):
|
|
136
|
+
def __init__(self, secret_manager: SecretManager, org_id: str, user_name: str):
|
|
136
137
|
super().__init__(secret_manager)
|
|
138
|
+
self.org_id = org_id
|
|
137
139
|
self.user_name = user_name
|
|
138
140
|
|
|
139
141
|
def _get_vault_path(self, secret_type: str, key: str) -> str:
|
|
140
|
-
return f"{self.user_name}-{secret_type}-{key}"
|
|
142
|
+
return f"{self.org_id}-{self.user_name}-{secret_type}-{key}"
|
|
141
143
|
|
|
142
144
|
# --------------------------------------------------------------------------
|
|
143
145
|
# PUBLIC INTERFACE CLASS
|
|
@@ -147,10 +149,10 @@ class SecretsService:
|
|
|
147
149
|
def __init__(self, secret_manager: SecretManager):
|
|
148
150
|
self._secret_manager = secret_manager
|
|
149
151
|
|
|
150
|
-
def runtime(self, env: str, slug: str = None) -> _RuntimeAccessor:
|
|
152
|
+
def runtime(self, org_id: int, env: str, slug: str = None) -> _RuntimeAccessor:
|
|
151
153
|
"""Sets the context to RUNTIME and returns the appropriate accessor."""
|
|
152
|
-
return _RuntimeAccessor(self._secret_manager, env, slug)
|
|
154
|
+
return _RuntimeAccessor(self._secret_manager, str(org_id), env, slug)
|
|
153
155
|
|
|
154
|
-
def studio(self, user: str) -> _StudioAccessor:
|
|
156
|
+
def studio(self, org_id: int, user: str) -> _StudioAccessor:
|
|
155
157
|
"""Sets the context to STUDIO and returns the appropriate accessor."""
|
|
156
|
-
return _StudioAccessor(self._secret_manager, user)
|
|
158
|
+
return _StudioAccessor(self._secret_manager, str(org_id), user)
|
|
@@ -1,37 +1,60 @@
|
|
|
1
|
-
from fastapi import HTTPException
|
|
1
|
+
from fastapi import HTTPException
|
|
2
2
|
from sqlalchemy.orm import Session
|
|
3
|
-
from
|
|
4
|
-
from dataflow.models import
|
|
3
|
+
from sqlalchemy import and_
|
|
4
|
+
from dataflow.models import (
|
|
5
|
+
user as m_user,
|
|
6
|
+
session as m_session,
|
|
7
|
+
org_associations as m_org_associations,
|
|
8
|
+
role as m_role,
|
|
9
|
+
organization as m_organization
|
|
10
|
+
)
|
|
5
11
|
|
|
6
12
|
def get_user_from_session(session_id: str, db: Session):
|
|
7
13
|
"""
|
|
8
|
-
Retrieve
|
|
9
|
-
|
|
10
|
-
Args:
|
|
11
|
-
session_id (str): The unique session identifier
|
|
12
|
-
db (Session): Database session
|
|
13
|
-
|
|
14
|
-
Returns:
|
|
15
|
-
User: User object if found
|
|
16
|
-
|
|
17
|
-
Raises:
|
|
18
|
-
HTTPException: If session is invalid or user not found
|
|
14
|
+
Retrieve user information based on the session ID.
|
|
19
15
|
"""
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
user = (
|
|
17
|
+
db.query(
|
|
18
|
+
m_user.User,
|
|
19
|
+
m_org_associations.OrganizationUser.role_id,
|
|
20
|
+
m_role.Role.name,
|
|
21
|
+
m_role.Role.base_role,
|
|
22
|
+
m_org_associations.OrganizationUser.active_server_id,
|
|
23
|
+
m_org_associations.OrganizationUser.show_server_page,
|
|
24
|
+
m_org_associations.OrganizationUser.active_env_short_name,
|
|
25
|
+
m_org_associations.OrganizationUser.active_env_type,
|
|
26
|
+
m_org_associations.OrganizationUser.monthly_allocation,
|
|
27
|
+
m_organization.Organization.uid
|
|
28
|
+
)
|
|
29
|
+
.join(m_session.Session, m_session.Session.user_id == m_user.User.user_id)
|
|
30
|
+
.outerjoin(
|
|
31
|
+
m_org_associations.OrganizationUser,
|
|
32
|
+
and_(
|
|
33
|
+
m_org_associations.OrganizationUser.user_id == m_user.User.user_id,
|
|
34
|
+
m_org_associations.OrganizationUser.org_id == m_user.User.active_org_id
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
.outerjoin(m_role.Role, m_role.Role.id == m_org_associations.OrganizationUser.role_id)
|
|
38
|
+
.outerjoin(
|
|
39
|
+
m_organization.Organization,
|
|
40
|
+
m_organization.Organization.id == m_user.User.active_org_id # join to Organization
|
|
41
|
+
)
|
|
42
|
+
.filter(m_session.Session.session_id == session_id)
|
|
43
|
+
.first()
|
|
44
|
+
)
|
|
23
45
|
|
|
24
|
-
user = db.query(m_user.User).filter(m_user.User.user_id == session_record.user_id).first()
|
|
25
46
|
if not user:
|
|
26
|
-
raise HTTPException(status_code=
|
|
27
|
-
|
|
28
|
-
base_role = user.role_details.base_role
|
|
29
|
-
role_id = user.role_details.id
|
|
30
|
-
role_name = user.role_details.name
|
|
31
|
-
user.base_role = base_role
|
|
32
|
-
user.role = role_name
|
|
33
|
-
user.role_id = role_id
|
|
34
|
-
|
|
35
|
-
return user
|
|
47
|
+
raise HTTPException(status_code=401, detail="Invalid session")
|
|
36
48
|
|
|
49
|
+
user_obj, role_id, role_name, base_role, active_server_id, show_server_page, active_env_short_name, active_env_type, monthly_allocation, uid = user
|
|
50
|
+
user_obj.role_id = role_id
|
|
51
|
+
user_obj.role = role_name
|
|
52
|
+
user_obj.base_role = base_role
|
|
53
|
+
user_obj.current_server_id = active_server_id
|
|
54
|
+
user_obj.show_server_page = show_server_page
|
|
55
|
+
user_obj.active_env = active_env_short_name
|
|
56
|
+
user_obj.active_env_type = active_env_type
|
|
57
|
+
user_obj.monthly_allocation = monthly_allocation
|
|
58
|
+
user_obj.org_uid = str(uid)
|
|
37
59
|
|
|
60
|
+
return user_obj
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dataflow-core
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.15rc3
|
|
4
4
|
Summary: Dataflow core package
|
|
5
5
|
Author: Dataflow
|
|
6
6
|
Author-email:
|
|
7
7
|
Requires-Dist: sqlalchemy
|
|
8
|
+
Requires-Dist: alembic
|
|
8
9
|
Requires-Dist: boto3
|
|
9
10
|
Requires-Dist: psycopg2-binary
|
|
10
11
|
Requires-Dist: pymysql
|