@@ -133,56 +133,73 @@ async def init_default_roles_and_permissions(db: AsyncSession) -> None:
133133 """
134134 Initialize default roles and permissions in the database.
135135
136- This function is idempotent - it only creates entries that don't exist yet.
137- It will not modify existing roles or permissions .
136+ This function is truly idempotent - it creates missing permissions and roles
137+ without modifying existing ones. Each permission and role is checked individually .
138138 """
139139 try :
140- # Check if permissions already exist
141- result = await db .execute (select (Permission ).limit (1 ))
142- existing_permissions = result .scalar_one_or_none ()
140+ logger .info ("[SEED] Checking default permissions and roles..." )
143141
144- if existing_permissions :
145- logger . info ( "[SEED] Permissions already exist, skipping seed" )
146- return
142+ # Get existing permissions by name
143+ result = await db . execute ( select ( Permission ) )
144+ existing_permissions = { p . name : p for p in result . scalars (). all ()}
147145
148- logger .info ("[SEED] Initializing default permissions and roles..." )
146+ # Create missing permissions
147+ permission_objects : dict [str , Permission ] = dict (existing_permissions )
148+ permissions_created = 0
149149
150- # Create permissions
151- permission_objects = {}
152150 for perm_data in DEFAULT_PERMISSIONS :
153- permission = Permission (
154- name = perm_data ["name" ],
155- display_name = perm_data ["display_name" ],
156- description = perm_data ["description" ],
157- resource = perm_data ["resource" ],
158- )
159- db .add (permission )
160- permission_objects [perm_data ["name" ]] = permission
161- logger .info (f"[SEED] Created permission: { perm_data ['name' ]} " )
162-
163- # Flush to get permission IDs
164- await db .flush ()
165-
166- # Create roles with their permissions
167- for role_data in DEFAULT_ROLES :
168- role = Role (
169- name = role_data ["name" ],
170- display_name = role_data ["display_name" ],
171- description = role_data ["description" ],
172- is_system = role_data ["is_system" ],
173- )
151+ if perm_data ["name" ] not in existing_permissions :
152+ permission = Permission (
153+ name = perm_data ["name" ],
154+ display_name = perm_data ["display_name" ],
155+ description = perm_data ["description" ],
156+ resource = perm_data ["resource" ],
157+ )
158+ db .add (permission )
159+ permission_objects [perm_data ["name" ]] = permission
160+ permissions_created += 1
161+ logger .info (f"[SEED] Created permission: { perm_data ['name' ]} " )
162+
163+ if permissions_created > 0 :
164+ await db .flush ()
165+ logger .info (f"[SEED] Created { permissions_created } missing permission(s)" )
166+ else :
167+ logger .info ("[SEED] All permissions already exist" )
174168
175- # Assign permissions to role
176- permissions_list = cast (list [str ], role_data ["permissions" ])
177- for perm_name in permissions_list :
178- if perm_name in permission_objects :
179- role .permissions .append (permission_objects [perm_name ])
169+ # Get existing roles by name
170+ result = await db .execute (select (Role ))
171+ existing_roles = {r .name : r for r in result .scalars ().all ()}
180172
181- db . add ( role )
182- logger . info ( f"[SEED] Created role: { role_data [ 'name' ] } with { len ( permissions_list ) } permissions" )
173+ # Create missing roles with their permissions
174+ roles_created = 0
183175
184- await db .commit ()
185- logger .info ("[SEED] Default roles and permissions initialized successfully" )
176+ for role_data in DEFAULT_ROLES :
177+ if role_data ["name" ] not in existing_roles :
178+ role = Role (
179+ name = role_data ["name" ],
180+ display_name = role_data ["display_name" ],
181+ description = role_data ["description" ],
182+ is_system = role_data ["is_system" ],
183+ )
184+
185+ # Assign permissions to role
186+ permissions_list = cast (list [str ], role_data ["permissions" ])
187+ for perm_name in permissions_list :
188+ if perm_name in permission_objects :
189+ role .permissions .append (permission_objects [perm_name ])
190+
191+ db .add (role )
192+ roles_created += 1
193+ logger .info (f"[SEED] Created role: { role_data ['name' ]} with { len (permissions_list )} permissions" )
194+
195+ if roles_created > 0 :
196+ await db .commit ()
197+ logger .info (f"[SEED] Created { roles_created } missing role(s)" )
198+ elif permissions_created > 0 :
199+ await db .commit ()
200+ logger .info ("[SEED] All roles already exist, committed new permissions" )
201+ else :
202+ logger .info ("[SEED] All roles and permissions already exist, nothing to do" )
186203
187204 except Exception as e :
188205 logger .error (f"[SEED] Error initializing roles and permissions: { e } " )
0 commit comments