@@ -163,6 +163,156 @@ def get_role(role: str):
163163
164164class ManageUsers :
165165
166+ @app .command ()
167+ @update_sqlite_path
168+ def load_users (input_file : str ,
169+ sqlite_path : Optional [str ] = None ,
170+ json : Optional [bool ] = False ):
171+ """Load users from a JSON file.
172+
173+ Expected JSON format:
174+ {
175+ "users": [
176+ {
177+ "username": "user@example.com",
178+ "email": "user@example.com",
179+ "password": "password123",
180+ "role": "User",
181+ "active": true,
182+ "auth_source": "internal"
183+ },
184+ {
185+ "username": "ldap_user",
186+ "email": "ldap@example.com",
187+ "role": "Administrator",
188+ "active": true,
189+ "auth_source": "ldap"
190+ }
191+ ]
192+ }
193+ """
194+ from urllib .parse import unquote
195+
196+ print ('----------' )
197+ print ('Loading users from:' , input_file )
198+ print ('SQLite pgAdmin config:' , config .SQLITE_PATH )
199+ print ('----------' )
200+
201+ # Parse the input file path
202+ try :
203+ file_path = unquote (input_file )
204+ except Exception as e :
205+ print (str (e ))
206+ return _handle_error (str (e ), True )
207+
208+ # Read and parse JSON file
209+ try :
210+ with open (file_path ) as f :
211+ data = jsonlib .load (f )
212+ except jsonlib .decoder .JSONDecodeError as e :
213+ return _handle_error (
214+ gettext ("Error parsing input file %s: %s" % (file_path , e )),
215+ True )
216+ except Exception as e :
217+ return _handle_error (
218+ gettext ("Error reading input file %s: [%d] %s" %
219+ (file_path , e .errno , e .strerror )), True )
220+
221+ # Validate JSON structure
222+ if 'users' not in data :
223+ return _handle_error (
224+ gettext ("Invalid JSON format: 'users' key not found" ), True )
225+
226+ users_data = data ['users' ]
227+ if not isinstance (users_data , list ):
228+ return _handle_error (
229+ gettext ("Invalid JSON format: 'users' must be a list" ), True )
230+
231+ created_count = 0
232+ skipped_count = 0
233+ error_count = 0
234+
235+ app = create_app (config .APP_NAME + '-cli' )
236+ with app .test_request_context ():
237+ for user_entry in users_data :
238+ try :
239+ # Validate required fields
240+ if 'username' not in user_entry and 'email' not in user_entry :
241+ print (f"Skipping user: missing 'username' or 'email'" )
242+ error_count += 1
243+ continue
244+
245+ # Determine auth_source (default to internal)
246+ auth_source = user_entry .get ('auth_source' , INTERNAL )
247+
248+ # Build user data dict
249+ user_data = {
250+ 'username' : user_entry .get ('username' ,
251+ user_entry .get ('email' )),
252+ 'email' : user_entry .get ('email' ),
253+ 'role' : user_entry .get ('role' , 'User' ),
254+ 'active' : user_entry .get ('active' , True ),
255+ 'auth_source' : auth_source
256+ }
257+
258+ # For internal auth, password is required
259+ if auth_source == INTERNAL :
260+ if 'password' not in user_entry :
261+ print (f"Skipping user '{ user_data ['username' ]} ': "
262+ f"password required for internal auth" )
263+ error_count += 1
264+ continue
265+ user_data ['newPassword' ] = user_entry ['password' ]
266+ user_data ['confirmPassword' ] = user_entry ['password' ]
267+
268+ # Check if user already exists
269+ uid = ManageUsers .get_user (
270+ username = user_data ['username' ],
271+ auth_source = auth_source )
272+ if uid :
273+ print (f"Skipping user '{ user_data ['username' ]} ': "
274+ f"already exists" )
275+ skipped_count += 1
276+ continue
277+
278+ # Get role ID
279+ rid = ManageRoles .get_role (user_data ['role' ])
280+ if rid is None :
281+ print (f"Skipping user '{ user_data ['username' ]} ': "
282+ f"role '{ user_data ['role' ]} ' does not exist" )
283+ error_count += 1
284+ continue
285+
286+ user_data ['role' ] = rid
287+
288+ # Validate password length for internal users
289+ if auth_source == INTERNAL :
290+ if len (user_data ['newPassword' ]) < 6 :
291+ print (f"Skipping user '{ user_data ['username' ]} ': "
292+ f"password must be at least 6 characters" )
293+ error_count += 1
294+ continue
295+
296+ # Create the user
297+ status , msg = create_user (user_data )
298+ if status :
299+ print (f"Created user: { user_data ['username' ]} " )
300+ created_count += 1
301+ else :
302+ print (f"Error creating user '{ user_data ['username' ]} '"
303+ f": { msg } " )
304+ error_count += 1
305+
306+ except Exception as e :
307+ print (f"Error processing user entry: { str (e )} " )
308+ error_count += 1
309+
310+ print ('----------' )
311+ print (f"Users created: { created_count } " )
312+ print (f"Users skipped (already exist): { skipped_count } " )
313+ print (f"Errors: { error_count } " )
314+ print ('----------' )
315+
166316 @app .command ()
167317 @update_sqlite_path
168318 def add_user (email : str , password : str ,
0 commit comments