-
Notifications
You must be signed in to change notification settings - Fork 468
[feat] Extend organizations (multi-orgs, verified domains, sso providers)
#3141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
93923f3
d28653f
6275659
89e0cba
0a739cd
ba31a73
57e07ed
6b8ec0e
1fe6378
1ac4d39
325d571
23b05c0
b0e9904
e301624
d73c4e5
3ebb2e5
6677a34
eda50bf
c4914c1
1fadbfe
3a1883c
c3eb5b5
da2cadb
5075c3f
adae343
88b0321
75905df
a4a0e3e
f2d0cd2
5e3a0f4
07f4e18
e6d9a76
13f9214
6411e4f
ccf7969
b0761a2
8e34e79
a79d87b
22f97d7
bd0b417
50ceed9
31b8cdf
c416cd8
269f886
943d304
2305e1c
aed9351
72b3c9a
3f99ce5
9ce5afe
d9d6858
d80eb78
52ba44b
417dae2
fc5c4cc
2e460fc
f5b359d
60c2b4c
b09dcab
5257fa1
bec26bf
3d96395
f8a0ae6
f4856d1
deb0d96
2f37d39
36b9e81
986e550
7bd3073
f3309fd
4f8e077
fbf2cba
710daa4
89f2c0a
35b2d5d
0a7fa80
ac2ef9f
1f0890c
cf3161c
6a4866d
5f01c15
08ee759
7bac587
31be0ce
8758eb7
9dc2599
a8986d6
3d13f61
d48efc4
fc49664
93ceec9
09a16d3
47f4ce6
6617b89
306e9a7
7cfa317
620ac3f
0718d75
67eb181
2e858c2
5ac29f8
29648d6
5ae542b
fa73ef5
8f99c1b
dcdaae8
7a49469
b1d9d3e
5ba6d05
f32a7ba
e8b4653
c02e397
f80c7f2
d1160b6
917bf86
64ec605
82baa27
08b0570
d19d89d
9ca8486
6ee876f
3476b16
70114dc
c2be3bc
30af014
2a22514
61f1907
75efc91
99d8f6d
85c457e
0208d70
4e6b771
9b12cf1
fdec3af
058f5bf
1f5c3bb
b37c133
15e736c
d1658d9
0ac6508
ba0b205
311584e
1da3afb
69e9db8
1f62c0b
fe8c7b9
3cae37b
fdd1374
66c9dd1
564c61b
ce85f39
bd2c1c8
c13c5b3
7f2e29d
b044932
6390f94
aba48ff
d842983
7858e1a
2c0f1e3
a755cca
df98370
18a430e
4726683
73afd3b
83f0470
8b71986
e41b262
5c6729f
51f9590
ab58697
369be5d
047e242
7f0c6c1
a051dcd
e0c2564
cc255ad
7616cb3
e1eea57
6858f04
50f6bc1
31c507b
017088a
0a3a545
d8c0a0f
1cc8112
8a055b0
b1e2664
ccd6087
f4be4d7
f0beb20
710bdf9
bf20e23
e44550a
6b2194b
796eacf
87fa2b5
2b87214
66b9a1d
3b81c05
30f9fb4
aaaca36
0b8183f
a1ded86
50bbd77
840fcc1
ce3ba20
93eee32
33ebca9
c252958
5350265
c2eccc9
2900e8c
cac2df7
6fd4ca7
9e7960f
d9feb15
eef9477
d8364c7
6497bfe
074f73d
adc5272
3c4fd59
a57b9e3
44b7efc
d46b80c
7f99d05
4311c14
0db7343
bef1188
4c291e4
9d14463
f5606dd
31f9e85
3e9aefb
3399f74
9369f19
8cd277a
d4e0bea
80e046a
dded104
2b5f929
6ab63ba
bfa0a6d
9a6e99b
7193da2
6d9b9be
c228f9e
f07148c
96cc1c3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| from datetime import datetime | ||
| from uuid import UUID | ||
| from pydantic import BaseModel | ||
| from typing import Optional, List, Dict, Any | ||
|
|
||
|
|
||
| # ============================================================================ | ||
| # ORGANIZATION POLICIES | ||
| # ============================================================================ | ||
|
|
||
|
|
||
| class OrganizationPolicy(BaseModel): | ||
| id: UUID | ||
| organization_id: UUID | ||
| allowed_methods: List[str] | ||
| invitation_only: bool | ||
| domains_only: bool | ||
| disable_root: bool | ||
| created_at: datetime | ||
| updated_at: Optional[datetime] | ||
|
|
||
| class Config: | ||
| from_attributes = True | ||
|
|
||
|
|
||
| class OrganizationPolicyCreate(BaseModel): | ||
| organization_id: UUID | ||
| allowed_methods: List[str] = ["email:otp", "social:*"] | ||
| invitation_only: bool = True | ||
| domains_only: bool = False | ||
| disable_root: bool = False | ||
|
|
||
|
|
||
| class OrganizationPolicyUpdate(BaseModel): | ||
| allowed_methods: Optional[List[str]] = None | ||
| invitation_only: Optional[bool] = None | ||
| domains_only: Optional[bool] = None | ||
| disable_root: Optional[bool] = None | ||
|
|
||
|
|
||
| # ============================================================================ | ||
| # ORGANIZATION DOMAINS | ||
| # ============================================================================ | ||
|
|
||
|
|
||
| class OrganizationDomain(BaseModel): | ||
| id: UUID | ||
| organization_id: UUID | ||
| domain: str | ||
| verified: bool | ||
| verification_token: Optional[str] | ||
| created_at: datetime | ||
| updated_at: Optional[datetime] | ||
|
|
||
| class Config: | ||
| from_attributes = True | ||
|
|
||
|
|
||
| class OrganizationDomainCreate(BaseModel): | ||
| organization_id: UUID | ||
| domain: str | ||
| verification_token: Optional[str] = None | ||
|
|
||
|
|
||
| # ============================================================================ | ||
| # ORGANIZATION PROVIDERS | ||
| # ============================================================================ | ||
|
|
||
|
|
||
| class OrganizationProvider(BaseModel): | ||
| id: UUID | ||
| organization_id: UUID | ||
| slug: str | ||
| name: str | ||
| description: Optional[str] | ||
| enabled: bool | ||
| domain_id: Optional[UUID] | ||
| config: Dict[str, Any] | ||
| created_at: datetime | ||
| updated_at: Optional[datetime] | ||
|
|
||
| class Config: | ||
| from_attributes = True | ||
|
|
||
|
|
||
| class OrganizationProviderCreate(BaseModel): | ||
| organization_id: UUID | ||
| slug: str | ||
| name: str | ||
| description: Optional[str] = None | ||
| enabled: bool = True | ||
| domain_id: Optional[UUID] = None | ||
| config: Dict[str, Any] | ||
|
|
||
|
|
||
| class OrganizationProviderUpdate(BaseModel): | ||
| name: Optional[str] = None | ||
| description: Optional[str] = None | ||
| enabled: Optional[bool] = None | ||
| domain_id: Optional[UUID] = None | ||
| config: Optional[Dict[str, Any]] = None | ||
|
|
||
|
|
||
| # ============================================================================ | ||
| # ORGANIZATION INVITATIONS | ||
| # ============================================================================ | ||
|
|
||
|
|
||
| class OrganizationInvitation(BaseModel): | ||
| id: UUID | ||
| organization_id: UUID | ||
| email: str | ||
| role: str | ||
| token: str | ||
| status: str | ||
| expires_at: Optional[datetime] | ||
| created_at: datetime | ||
| updated_at: Optional[datetime] | ||
|
|
||
| class Config: | ||
| from_attributes = True | ||
|
|
||
|
|
||
| class OrganizationInvitationCreate(BaseModel): | ||
| organization_id: UUID | ||
| email: str | ||
| role: str | ||
| token: str | ||
| expires_at: Optional[datetime] = None |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| import uuid_utils.compat as uuid | ||
| from sqlalchemy import Column, String, UUID, Boolean, ARRAY | ||
| from sqlalchemy.dialects.postgresql import JSONB | ||
|
|
||
| from oss.src.dbs.postgres.shared.dbas import ( | ||
| LegacyLifecycleDBA, | ||
| HeaderDBA, | ||
| OrganizationScopeDBA, | ||
| ) | ||
|
|
||
|
|
||
| class OrganizationPolicyDBA(OrganizationScopeDBA, LegacyLifecycleDBA): | ||
| __abstract__ = True | ||
|
|
||
| id = Column( | ||
| UUID(as_uuid=True), | ||
| primary_key=True, | ||
| default=uuid.uuid7, | ||
| unique=True, | ||
| nullable=False, | ||
| ) | ||
| allowed_methods = Column( | ||
| ARRAY(String), | ||
| nullable=False, | ||
| server_default="{}", | ||
| ) | ||
| invitation_only = Column( | ||
| Boolean, | ||
| nullable=False, | ||
| server_default="true", | ||
| ) | ||
| domains_only = Column( | ||
| Boolean, | ||
| nullable=False, | ||
| server_default="false", | ||
| ) | ||
| disable_root = Column( | ||
| Boolean, | ||
| nullable=False, | ||
| server_default="false", | ||
| ) | ||
|
|
||
|
|
||
| class OrganizationDomainDBA(OrganizationScopeDBA, LegacyLifecycleDBA): | ||
| __abstract__ = True | ||
|
|
||
| id = Column( | ||
| UUID(as_uuid=True), | ||
| primary_key=True, | ||
| default=uuid.uuid7, | ||
| unique=True, | ||
| nullable=False, | ||
| ) | ||
| domain = Column( | ||
| String, | ||
| nullable=False, | ||
| ) | ||
| verified = Column( | ||
| Boolean, | ||
| nullable=False, | ||
| server_default="false", | ||
| ) | ||
| verification_token = Column( | ||
| String, | ||
| nullable=True, | ||
| ) | ||
|
|
||
|
|
||
| class OrganizationProviderDBA(OrganizationScopeDBA, HeaderDBA, LegacyLifecycleDBA): | ||
| __abstract__ = True | ||
|
|
||
| id = Column( | ||
| UUID(as_uuid=True), | ||
| primary_key=True, | ||
| default=uuid.uuid7, | ||
| unique=True, | ||
| nullable=False, | ||
| ) | ||
| slug = Column( | ||
| String, | ||
| nullable=False, | ||
| ) | ||
| enabled = Column( | ||
| Boolean, | ||
| nullable=False, | ||
| server_default="true", | ||
| ) | ||
| domain_id = Column( | ||
| UUID(as_uuid=True), | ||
| nullable=True, | ||
| ) | ||
| config = Column( | ||
| JSONB(none_as_null=True), | ||
| nullable=False, | ||
| ) | ||
|
|
||
|
|
||
| class OrganizationInvitationDBA(OrganizationScopeDBA, LegacyLifecycleDBA): | ||
|
||
| __abstract__ = True | ||
|
|
||
| id = Column( | ||
| UUID(as_uuid=True), | ||
| primary_key=True, | ||
| default=uuid.uuid7, | ||
| unique=True, | ||
| nullable=False, | ||
| ) | ||
| email = Column( | ||
| String, | ||
| nullable=False, | ||
| ) | ||
| role = Column( | ||
| String, | ||
| nullable=False, | ||
| ) | ||
| token = Column( | ||
| String, | ||
| nullable=False, | ||
| ) | ||
| status = Column( | ||
| String, | ||
| nullable=False, | ||
| server_default="pending", | ||
| ) | ||
| expires_at = Column( | ||
| UUID(as_uuid=True), | ||
| nullable=True, | ||
| ) | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| from sqlalchemy import ( | ||
| ForeignKeyConstraint, | ||
| UniqueConstraint, | ||
| Index, | ||
| ) | ||
|
|
||
| from oss.src.dbs.postgres.shared.base import Base | ||
| from ee.src.dbs.postgres.organizations.dbas import ( | ||
| OrganizationPolicyDBA, | ||
| OrganizationDomainDBA, | ||
| OrganizationProviderDBA, | ||
| OrganizationInvitationDBA, | ||
| ) | ||
|
|
||
|
|
||
| class OrganizationPolicyDBE(Base, OrganizationPolicyDBA): | ||
| __tablename__ = "organization_policies" | ||
|
|
||
| __table_args__ = ( | ||
| ForeignKeyConstraint( | ||
| ["organization_id"], | ||
| ["organizations.id"], | ||
| ondelete="CASCADE", | ||
| ), | ||
| UniqueConstraint( | ||
| "organization_id", | ||
| name="uq_organization_policies_org", | ||
| ), | ||
| ) | ||
|
|
||
|
|
||
| class OrganizationDomainDBE(Base, OrganizationDomainDBA): | ||
| __tablename__ = "organization_domains" | ||
|
|
||
| __table_args__ = ( | ||
| ForeignKeyConstraint( | ||
| ["organization_id"], | ||
| ["organizations.id"], | ||
| ondelete="CASCADE", | ||
| ), | ||
| UniqueConstraint( | ||
| "domain", | ||
| name="uq_organization_domains_domain", | ||
| ), | ||
| Index( | ||
| "ix_organization_domains_org_verified", | ||
| "organization_id", | ||
| "verified", | ||
| ), | ||
| ) | ||
|
|
||
|
|
||
| class OrganizationProviderDBE(Base, OrganizationProviderDBA): | ||
| __tablename__ = "organization_providers" | ||
|
|
||
| __table_args__ = ( | ||
| ForeignKeyConstraint( | ||
| ["organization_id"], | ||
| ["organizations.id"], | ||
| ondelete="CASCADE", | ||
| ), | ||
| ForeignKeyConstraint( | ||
| ["domain_id"], | ||
| ["organization_domains.id"], | ||
| ondelete="SET NULL", | ||
| ), | ||
| UniqueConstraint( | ||
| "organization_id", | ||
| "slug", | ||
| name="uq_organization_providers_org_slug", | ||
| ), | ||
| Index( | ||
| "ix_organization_providers_org_enabled", | ||
| "organization_id", | ||
| "enabled", | ||
| ), | ||
| ) | ||
|
|
||
|
|
||
| class OrganizationInvitationDBE(Base, OrganizationInvitationDBA): | ||
| __tablename__ = "organization_invitations" | ||
|
|
||
| __table_args__ = ( | ||
| ForeignKeyConstraint( | ||
| ["organization_id"], | ||
| ["organizations.id"], | ||
| ondelete="CASCADE", | ||
| ), | ||
| UniqueConstraint( | ||
| "token", | ||
| name="uq_organization_invitations_token", | ||
| ), | ||
| Index( | ||
| "ix_organization_invitations_org_email_status", | ||
| "organization_id", | ||
| "email", | ||
| "status", | ||
| ), | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent base class usage: OSS uses
LifecycleDBAwhile EE usesLegacyLifecycleDBA. This inconsistency may lead to differences in table schemas and lifecycle field behavior between OSS and EE editions for the same tables.