3
3
from datetime import datetime , UTC , timedelta
4
4
from typing import Optional , List
5
5
from sqlmodel import SQLModel , Field , Relationship
6
- from sqlalchemy import Column , Enum as SQLAlchemyEnum
6
+ from sqlalchemy import Column , Enum as SQLAlchemyEnum , ForeignKey
7
7
8
8
9
9
def utc_time ():
@@ -26,16 +26,21 @@ class ValidPermissions(Enum):
26
26
27
27
class UserOrganizationLink (SQLModel , table = True ):
28
28
id : Optional [int ] = Field (default = None , primary_key = True )
29
- user_id : int = Field (foreign_key = "user.id" , ondelete = "CASCADE" )
30
- organization_id : int = Field (
31
- foreign_key = "organization.id" , ondelete = "CASCADE" )
29
+ user_id : int = Field (foreign_key = "user.id" )
30
+ organization_id : int = Field (foreign_key = "organization.id" )
32
31
role_id : int = Field (foreign_key = "role.id" )
33
32
created_at : datetime = Field (default_factory = utc_time )
34
33
updated_at : datetime = Field (default_factory = utc_time )
35
34
36
- user : "User" = Relationship (back_populates = "organization_links" )
37
- organization : "Organization" = Relationship (back_populates = "user_links" )
38
- role : "Role" = Relationship (back_populates = "user_links" )
35
+ user : "User" = Relationship (
36
+ back_populates = "organization_links"
37
+ )
38
+ organization : "Organization" = Relationship (
39
+ back_populates = "user_links"
40
+ )
41
+ role : "Role" = Relationship (
42
+ back_populates = "user_links"
43
+ )
39
44
40
45
41
46
class RolePermissionLink (SQLModel , table = True ):
@@ -46,17 +51,35 @@ class RolePermissionLink(SQLModel, table=True):
46
51
updated_at : datetime = Field (default_factory = utc_time )
47
52
48
53
54
+ class Permission (SQLModel , table = True ):
55
+ """
56
+ Represents a permission that can be assigned to a role. Should not be
57
+ modified unless the application logic and ValidPermissions enum change.
58
+ """
59
+ id : Optional [int ] = Field (default = None , primary_key = True )
60
+ name : ValidPermissions = Field (
61
+ sa_column = Column (SQLAlchemyEnum (ValidPermissions , create_type = False )))
62
+ created_at : datetime = Field (default_factory = utc_time )
63
+ updated_at : datetime = Field (default_factory = utc_time )
64
+
65
+ roles : List ["Role" ] = Relationship (
66
+ back_populates = "permissions" ,
67
+ link_model = RolePermissionLink
68
+ )
69
+
70
+
49
71
class Organization (SQLModel , table = True ):
50
72
id : Optional [int ] = Field (default = None , primary_key = True )
51
73
name : str
52
74
created_at : datetime = Field (default_factory = utc_time )
53
75
updated_at : datetime = Field (default_factory = utc_time )
54
76
55
77
user_links : List [UserOrganizationLink ] = Relationship (
56
- back_populates = "organization" )
57
- users : List ["User" ] = Relationship (
58
- back_populates = "organizations" ,
59
- link_model = UserOrganizationLink
78
+ back_populates = "organization" ,
79
+ sa_relationship_kwargs = {
80
+ "cascade" : "all, delete-orphan" ,
81
+ "passive_deletes" : True
82
+ }
60
83
)
61
84
roles : List ["Role" ] = Relationship (back_populates = "organization" )
62
85
@@ -87,25 +110,9 @@ class Role(SQLModel, table=True):
87
110
)
88
111
89
112
90
- class Permission (SQLModel , table = True ):
91
- """
92
- Represents a permission that can be assigned to a role.
93
- """
94
- id : Optional [int ] = Field (default = None , primary_key = True )
95
- name : ValidPermissions = Field (
96
- sa_column = Column (SQLAlchemyEnum (ValidPermissions , create_type = False )))
97
- created_at : datetime = Field (default_factory = utc_time )
98
- updated_at : datetime = Field (default_factory = utc_time )
99
-
100
- roles : List ["Role" ] = Relationship (
101
- back_populates = "permissions" ,
102
- link_model = RolePermissionLink
103
- )
104
-
105
-
106
113
class PasswordResetToken (SQLModel , table = True ):
107
114
id : Optional [int ] = Field (default = None , primary_key = True )
108
- user_id : Optional [int ] = Field (foreign_key = "user.id" , ondelete = "CASCADE" )
115
+ user_id : Optional [int ] = Field (foreign_key = "user.id" )
109
116
token : str = Field (default_factory = lambda : str (
110
117
uuid4 ()), index = True , unique = True )
111
118
expires_at : datetime = Field (
@@ -116,6 +123,7 @@ class PasswordResetToken(SQLModel, table=True):
116
123
back_populates = "password_reset_tokens" )
117
124
118
125
126
+ # TODO: Prevent deleting a user who is sole owner of an organization
119
127
class User (SQLModel , table = True ):
120
128
id : Optional [int ] = Field (default = None , primary_key = True )
121
129
name : str
@@ -126,11 +134,16 @@ class User(SQLModel, table=True):
126
134
updated_at : datetime = Field (default_factory = utc_time )
127
135
128
136
organization_links : List [UserOrganizationLink ] = Relationship (
129
- back_populates = "user"
130
- )
131
- organizations : List [ "Organization" ] = Relationship (
132
- back_populates = "users" ,
133
- link_model = UserOrganizationLink
137
+ back_populates = "user" ,
138
+ sa_relationship_kwargs = {
139
+ "cascade" : "all, delete-orphan" ,
140
+ "passive_deletes" : True
141
+ }
134
142
)
135
143
password_reset_tokens : List ["PasswordResetToken" ] = Relationship (
136
- back_populates = "user" )
144
+ back_populates = "user" ,
145
+ sa_relationship_kwargs = {
146
+ "cascade" : "all, delete-orphan" ,
147
+ "passive_deletes" : True
148
+ }
149
+ )
0 commit comments