Zelyanoth commited on
Commit
29ca009
·
1 Parent(s): 34289ef

**Add scheduling and publishing flags and update app.py**

Browse files

- Introduce flags for various actions in `functi.py` to manage state and ensure thread safety.
- Update `app.py` to include a new flag `has_navigated` and adjust logging configuration.
- Enhance the `add_scheduling` function to handle scheduling with improved time management and database interactions.
- Modify the post publishing function to include a reset mechanism for the publishing flag using a timer.
- Ensure the code is more robust and maintainable with clear state management.

.vscode/settings.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "taipyStudio.gUI.elementsFilePaths": []
3
+ }
__pycache__/Post_management.cpython-311.pyc CHANGED
Binary files a/__pycache__/Post_management.cpython-311.pyc and b/__pycache__/Post_management.cpython-311.pyc differ
 
__pycache__/Source_manage.cpython-311.pyc CHANGED
Binary files a/__pycache__/Source_manage.cpython-311.pyc and b/__pycache__/Source_manage.cpython-311.pyc differ
 
__pycache__/functi.cpython-311.pyc CHANGED
Binary files a/__pycache__/functi.cpython-311.pyc and b/__pycache__/functi.cpython-311.pyc differ
 
app.py CHANGED
@@ -8,10 +8,11 @@ from flask import Flask, request
8
  from urllib.parse import urlparse, parse_qs
9
  import time
10
  import logging
 
11
  logging.getLogger('requests_oauthlib').setLevel(logging.DEBUG)
12
 
13
  mssage_callback = "Authentification success, close this tabs and return to the login page"
14
-
15
 
16
  import requests
17
 
 
8
  from urllib.parse import urlparse, parse_qs
9
  import time
10
  import logging
11
+
12
  logging.getLogger('requests_oauthlib').setLevel(logging.DEBUG)
13
 
14
  mssage_callback = "Authentification success, close this tabs and return to the login page"
15
+ has_navigated = False
16
 
17
  import requests
18
 
functi.py CHANGED
@@ -21,6 +21,21 @@ from apscheduler.triggers.cron import CronTrigger
21
  apsched = BackgroundScheduler()
22
  apsched.start()
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  Linked_account_name = " "
25
  Linked_social_network = " "
26
  data_schedule ={}
@@ -194,10 +209,34 @@ def planifier_ligne(id_schedule, id_social, user_id, schedule_time_str, ss, adju
194
 
195
  def add_scheduling(state):
196
  """Add new scheduling with thread safety"""
197
- try:
198
- if isinstance(state.day_value, list):
199
- for day in state.day_value:
200
- timesche = f"{day} {int(state.time_value_hour)}:{int(state.time_value_minute)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
  # Get current schedule
203
  df = db_manager.fetch_schedule_table()
@@ -218,40 +257,25 @@ def add_scheduling(state):
218
  timesche,
219
  final_time
220
  )
221
- else:
222
- timesche = f"{state.day_value} {int(state.time_value_hour)}:{int(state.time_value_minute)}"
223
 
224
- # Get current schedule
225
  df = db_manager.fetch_schedule_table()
 
226
 
227
- if not df.empty:
228
- df, final_time = add_request(df, timesche)
229
- else:
230
- jour, horaire = timesche.split()
231
- horaire = horaire.replace(';', ':')
232
- h, m = map(int, horaire.split(':'))
233
- m -= 7 # 7 minutes before for generation
234
- final_time = f"{jour} {h}:{m:02d}"
235
-
236
- # Add to database
237
- db_manager.create_scheduling_for_user(
238
- state.user_inf.user.id,
239
- state.Linked_social_network,
240
- timesche,
241
- final_time
242
- )
243
-
244
- # Refresh the schedule after adding
245
- df = db_manager.fetch_schedule_table()
246
- state.data_schedule = db_manager.fetch_schedule_table_acc(state.user_inf.user.id)
247
-
248
- # Reschedule all tasks
249
- replanifier_toutes_les_tâches(df)
250
 
251
- print(f"✅ Scheduling added successfully", flush=True)
252
 
253
- except Exception as e:
254
- print(f"❌ Error in add_scheduling: {e}", flush=True)
 
 
 
 
 
 
 
255
 
256
  def planning():
257
  df = db_manager.fetch_schedule_table()
@@ -259,188 +283,295 @@ def planning():
259
  replanifier_toutes_les_tâches(df)
260
 
261
  def post_publishing(state) :
 
 
262
 
263
- resp = db_manager.fetching_user_identif(state.user_inf.user.id,state.social_network)
264
- data = pd.DataFrame(resp.data)
265
 
266
- first = data[data['social_network'] == state.social_network].iloc[0]
267
- token_value = first["token"]
268
- sub_value = first["sub"]
269
 
270
- url = "https://api.linkedin.com/v2/ugcPosts"
271
- headers = {
272
- "Authorization": f"Bearer {token_value}",
273
- "X-Restli-Protocol-Version": "2.0.0",
274
- "Content-Type": "application/json"
275
- }
276
- body = {
277
- "author": f"urn:li:person:{sub_value}",
278
- "lifecycleState": "PUBLISHED",
279
- "specificContent": {
280
- "com.linkedin.ugc.ShareContent": {
281
- "shareCommentary": {
282
- "text": state.generated_post
283
- },
284
- "shareMediaCategory": "NONE"
 
 
 
 
285
  }
286
- },
287
- "visibility": {
288
- "com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"
289
  }
290
- }
291
 
292
- resp = requests.post(url, headers=headers, json=body)
293
- print([resp.status_code, resp.text],flush = True)
 
 
 
 
 
 
 
294
 
295
  def post_generation(state) :
296
- state.generated_post = client.predict(
297
- code=state.user_inf.user.id,
298
- api_name="/poster_linkedin"
299
- )
 
 
 
 
 
 
 
 
 
300
 
301
  def authen(state) :
302
- if state.Linked_social_network == "Linkedin" :
303
- print("jhdijb",flush = True)
304
- state.urlss, state.states = linkedin.authorization_url(
305
- 'https://www.linkedin.com/oauth/v2/authorization'
306
- )
 
 
307
  navigate(state, state.urlss)
308
 
 
 
 
 
 
 
 
309
  def on_my_clicking(state, action, payload) :
310
- print(action,flush = True)
311
- print(payload["args"][0],flush = True)
312
- if payload["args"][0] == "Accueil" :
313
- on_logout(state)
314
- navigate(state, payload["args"][0])
 
 
 
 
 
 
 
 
315
 
316
  return " "
317
 
318
  def add_source(state) :
 
 
319
 
320
- result = client.predict(
321
- rss_link=state.source_ + "__thi_irrh'èçs_my_id__! "+state.user_inf.user.id,
322
- api_name="/ajouter_rss"
323
- )
324
 
325
- state.source_add_message = result
326
- data = db_manager.fetch_source_table(state.user_inf.user.id)
327
- state.Source_table = pd.DataFrame(data)
328
 
329
- def delete_source(state, var_name: str, payload: dict) :
330
- state.Source_table_before = state.Source_table
331
- state.get_gui().table_on_delete(state, var_name, payload)
 
 
 
332
 
333
- diff = state.Source_table_before.merge(state.Source_table, how="outer", indicator=True) \
334
- .query('_merge != "both"') \
335
- .drop(columns='_merge')
336
- valeurs = diff['id'].tolist()
337
- db_manager.delete_from_table("Source",valeurs)
 
 
 
 
 
 
 
 
 
 
 
 
 
338
 
339
  def delete_account(state, var_name: str, payload: dict) :
340
- state.data_account_before = state.data_account
341
- state.get_gui().table_on_delete(state, var_name, payload)
342
-
343
- diff = state.data_account_before.merge(state.data_account, how="outer", indicator=True) \
344
- .query('_merge != "both"') \
345
- .drop(columns='_merge')
346
- valeurs = diff['id'].tolist()
347
- db_manager.delete_from_table("Social_network",valeurs)
 
 
 
 
 
 
 
 
 
348
 
349
  def delete_schedule(state, var_name: str, payload: dict) :
350
- state.data_schedule_before = state.data_schedule
351
- state.get_gui().table_on_delete(state, var_name, payload)
352
-
353
- diff = state.data_schedule_before.merge(state.data_schedule, how="outer", indicator=True) \
354
- .query('_merge != "both"') \
355
- .drop(columns='_merge')
356
- valeurs = diff['id'].tolist()
357
- db_manager.delete_from_table("Scheduling",valeurs)
 
 
 
 
 
 
 
 
 
358
 
359
  def on_login(state, payload):
360
  """Handle login form submission"""
361
- time.sleep(0.7)
362
- email = state.login_email
363
- password = state.login_password
364
-
365
- if not email or not password:
366
- state.message = "Please enter both email and password"
367
- return
368
-
369
- success, message, user_inf = db_manager.authenticate_user(email, password)
370
-
371
- if user_inf is None:
372
- # Handle the case when authentication fails
373
- state.message = message
374
- return
375
-
376
- if success:
377
- state.current_user = email
378
- data = db_manager.fetch_source_table(user_inf.user.id)
379
- dataac = db_manager.fetch_account_table(user_inf.user.id)
380
- state.data_schedule = db_manager.fetch_schedule_table_acc(user_inf.user.id)
381
- state.data_account = pd.DataFrame(dataac)
382
- state.Source_table = pd.DataFrame(data)
383
- navigate(state, "Source_Management")
384
- state.is_logged_in = True
385
- state.message = f"Welcome back, {email}!"
386
- # Clear form
387
- state.login_email = ""
388
- state.login_password = ""
389
- else:
390
- if message == "Compte non confirmé":
391
- state.message = "Votre compte n'est pas encore activé. Veuillez vérifier votre email pour activer votre compte."
392
- elif message == "Compte non existant":
393
- state.message = "Email ou mot de passe incorrect."
394
  else:
395
- state.message = "Email ou mot de passe incorrect."
 
 
 
 
 
 
 
 
 
 
 
 
396
 
397
  def on_register(state):
398
  """Handle registration form submission"""
399
- time.sleep(0.7)
400
- email = state.register_email
401
- password = state.register_password
402
- confirm_password = state.confirm_password
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
403
 
404
- if not email or not password or not confirm_password:
405
- state.message = "Please fill in all fields"
406
- return
 
 
 
407
 
408
- if password != confirm_password:
409
- state.message = "Passwords do not match"
410
- return
411
 
412
- if len(password) < 8:
413
- state.message = "Password must be at least 8 characters long"
414
- return
415
 
416
- success, message,user_inf = db_manager.create_user(email, password) # type: ignore
 
 
 
 
417
 
418
- if success:
419
- state.message = "Un lien d'activation a été envoyé à votre adresse email. Veuillez vérifier votre boîte de réception pour activer votre compte."
420
- state.show_register = False
421
- # Clear form
 
 
 
 
 
 
 
 
 
 
 
422
  state.register_email = ""
423
  state.register_password = ""
424
  state.confirm_password = ""
425
- else:
426
- state.message = message or "Erreur lors de l'inscription. Veuillez réessayer."
427
-
428
- def on_logout(state):
429
 
430
- """Handle logout"""
431
-
432
- state.current_user = None
433
- state.is_logged_in = False
434
- state.message = "Logged out successfully"
435
- state.login_email = ""
436
- state.login_password = ""
437
-
438
- def toggle_register(state):
439
- """Toggle between login and register forms"""
440
- state.show_register = not state.show_register
441
- state.message = ""
442
- state.login_email = ""
443
- state.login_password = ""
444
- state.register_email = ""
445
- state.register_password = ""
446
- state.confirm_password = ""
 
21
  apsched = BackgroundScheduler()
22
  apsched.start()
23
 
24
+ # Create flags for each action
25
+ has_on_my_clicking = False
26
+ has_add_source = False
27
+ has_authen = False
28
+ has_post_generation = False
29
+ has_post_publishing = False
30
+ has_add_scheduling = False
31
+ has_on_login = False
32
+ has_on_register = False
33
+ has_on_logout = False
34
+ has_toggle_register = False
35
+ has_delete_account = False
36
+ has_delete_schedule = False
37
+ has_delete_source = False
38
+
39
  Linked_account_name = " "
40
  Linked_social_network = " "
41
  data_schedule ={}
 
209
 
210
  def add_scheduling(state):
211
  """Add new scheduling with thread safety"""
212
+ if not state.has_add_scheduling:
213
+ state.has_add_scheduling = True
214
+ try:
215
+ if isinstance(state.day_value, list):
216
+ for day in state.day_value:
217
+ timesche = f"{day} {int(state.time_value_hour)}:{int(state.time_value_minute)}"
218
+
219
+ # Get current schedule
220
+ df = db_manager.fetch_schedule_table()
221
+
222
+ if not df.empty:
223
+ df, final_time = add_request(df, timesche)
224
+ else:
225
+ jour, horaire = timesche.split()
226
+ horaire = horaire.replace(';', ':')
227
+ h, m = map(int, horaire.split(':'))
228
+ m -= 7 # 7 minutes before for generation
229
+ final_time = f"{jour} {h}:{m:02d}"
230
+
231
+ # Add to database
232
+ db_manager.create_scheduling_for_user(
233
+ state.user_inf.user.id,
234
+ state.Linked_social_network,
235
+ timesche,
236
+ final_time
237
+ )
238
+ else:
239
+ timesche = f"{state.day_value} {int(state.time_value_hour)}:{int(state.time_value_minute)}"
240
 
241
  # Get current schedule
242
  df = db_manager.fetch_schedule_table()
 
257
  timesche,
258
  final_time
259
  )
 
 
260
 
261
+ # Refresh the schedule after adding
262
  df = db_manager.fetch_schedule_table()
263
+ state.data_schedule = db_manager.fetch_schedule_table_acc(state.user_inf.user.id)
264
 
265
+ # Reschedule all tasks
266
+ replanifier_toutes_les_tâches(df)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
 
268
+ print(f"✅ Scheduling added successfully", flush=True)
269
 
270
+ except Exception as e:
271
+ print(f"❌ Error in add_scheduling: {e}", flush=True)
272
+
273
+ # Programmer la réinitialisation du flag dans 2 secondes
274
+ def reset_flag():
275
+ state.has_add_scheduling = False
276
+ timer = threading.Timer(2.0, reset_flag)
277
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
278
+ timer.start()
279
 
280
  def planning():
281
  df = db_manager.fetch_schedule_table()
 
283
  replanifier_toutes_les_tâches(df)
284
 
285
  def post_publishing(state) :
286
+ if not state.has_post_publishing:
287
+ state.has_post_publishing = True
288
 
289
+ resp = db_manager.fetching_user_identif(state.user_inf.user.id,state.social_network)
290
+ data = pd.DataFrame(resp.data)
291
 
292
+ first = data[data['social_network'] == state.social_network].iloc[0]
293
+ token_value = first["token"]
294
+ sub_value = first["sub"]
295
 
296
+ url = "https://api.linkedin.com/v2/ugcPosts"
297
+ headers = {
298
+ "Authorization": f"Bearer {token_value}",
299
+ "X-Restli-Protocol-Version": "2.0.0",
300
+ "Content-Type": "application/json"
301
+ }
302
+ body = {
303
+ "author": f"urn:li:person:{sub_value}",
304
+ "lifecycleState": "PUBLISHED",
305
+ "specificContent": {
306
+ "com.linkedin.ugc.ShareContent": {
307
+ "shareCommentary": {
308
+ "text": state.generated_post
309
+ },
310
+ "shareMediaCategory": "NONE"
311
+ }
312
+ },
313
+ "visibility": {
314
+ "com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"
315
  }
 
 
 
316
  }
 
317
 
318
+ resp = requests.post(url, headers=headers, json=body)
319
+ print([resp.status_code, resp.text],flush = True)
320
+
321
+ # Programmer la réinitialisation du flag dans 2 secondes
322
+ def reset_flag():
323
+ state.has_post_publishing = False
324
+ timer = threading.Timer(2.0, reset_flag)
325
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
326
+ timer.start()
327
 
328
  def post_generation(state) :
329
+ if not state.has_post_generation:
330
+ state.has_post_generation = True
331
+ state.generated_post = client.predict(
332
+ code=state.user_inf.user.id,
333
+ api_name="/poster_linkedin"
334
+ )
335
+
336
+ # Programmer la réinitialisation du flag dans 2 secondes
337
+ def reset_flag():
338
+ state.has_post_generation = False
339
+ timer = threading.Timer(2.0, reset_flag)
340
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
341
+ timer.start()
342
 
343
  def authen(state) :
344
+ if not state.has_authen:
345
+ state.has_authen = True
346
+ if state.Linked_social_network == "Linkedin" :
347
+ print("jhdijb",flush = True)
348
+ state.urlss, state.states = linkedin.authorization_url(
349
+ 'https://www.linkedin.com/oauth/v2/authorization'
350
+ )
351
  navigate(state, state.urlss)
352
 
353
+ # Programmer la réinitialisation du flag dans 2 secondes
354
+ def reset_flag():
355
+ state.has_authen = False
356
+ timer = threading.Timer(2.0, reset_flag)
357
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
358
+ timer.start()
359
+
360
  def on_my_clicking(state, action, payload) :
361
+ if not state.has_on_my_clicking:
362
+ state.has_on_my_clicking = True
363
+ print(action,flush = True)
364
+ print(payload["args"][0],flush = True)
365
+ if payload["args"][0] == "Accueil" :
366
+ on_logout(state)
367
+ navigate(state, payload["args"][0])
368
+ # Programmer la réinitialisation du flag dans 2 secondes
369
+ def reset_flag():
370
+ state.has_on_my_clicking = False
371
+ timer = threading.Timer(2.0, reset_flag)
372
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
373
+ timer.start()
374
 
375
  return " "
376
 
377
  def add_source(state) :
378
+ if not state.has_add_source:
379
+ state.has_add_source = True
380
 
381
+ result = client.predict(
382
+ rss_link=state.source_ + "__thi_irrh'èçs_my_id__! "+state.user_inf.user.id,
383
+ api_name="/ajouter_rss"
384
+ )
385
 
386
+ state.source_add_message = result
387
+ data = db_manager.fetch_source_table(state.user_inf.user.id)
388
+ state.Source_table = pd.DataFrame(data)
389
 
390
+ # Programmer la réinitialisation du flag dans 2 secondes
391
+ def reset_flag():
392
+ state.has_add_source = False
393
+ timer = threading.Timer(2.0, reset_flag)
394
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
395
+ timer.start()
396
 
397
+ def delete_source(state, var_name: str, payload: dict) :
398
+ if not state.has_delete_source:
399
+ state.has_delete_source = True
400
+ state.Source_table_before = state.Source_table
401
+ state.get_gui().table_on_delete(state, var_name, payload)
402
+
403
+ diff = state.Source_table_before.merge(state.Source_table, how="outer", indicator=True) \
404
+ .query('_merge != "both"') \
405
+ .drop(columns='_merge')
406
+ valeurs = diff['id'].tolist()
407
+ db_manager.delete_from_table("Source",valeurs)
408
+
409
+ # Programmer la réinitialisation du flag dans 2 secondes
410
+ def reset_flag():
411
+ state.has_delete_source = False
412
+ timer = threading.Timer(2.0, reset_flag)
413
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
414
+ timer.start()
415
 
416
  def delete_account(state, var_name: str, payload: dict) :
417
+ if not state.has_delete_account:
418
+ state.has_delete_account = True
419
+ state.data_account_before = state.data_account
420
+ state.get_gui().table_on_delete(state, var_name, payload)
421
+
422
+ diff = state.data_account_before.merge(state.data_account, how="outer", indicator=True) \
423
+ .query('_merge != "both"') \
424
+ .drop(columns='_merge')
425
+ valeurs = diff['id'].tolist()
426
+ db_manager.delete_from_table("Social_network",valeurs)
427
+
428
+ # Programmer la réinitialisation du flag dans 2 secondes
429
+ def reset_flag():
430
+ state.has_delete_account = False
431
+ timer = threading.Timer(2.0, reset_flag)
432
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
433
+ timer.start()
434
 
435
  def delete_schedule(state, var_name: str, payload: dict) :
436
+ if not state.has_delete_schedule:
437
+ state.has_delete_schedule = True
438
+ state.data_schedule_before = state.data_schedule
439
+ state.get_gui().table_on_delete(state, var_name, payload)
440
+
441
+ diff = state.data_schedule_before.merge(state.data_schedule, how="outer", indicator=True) \
442
+ .query('_merge != "both"') \
443
+ .drop(columns='_merge')
444
+ valeurs = diff['id'].tolist()
445
+ db_manager.delete_from_table("Scheduling",valeurs)
446
+
447
+ # Programmer la réinitialisation du flag dans 2 secondes
448
+ def reset_flag():
449
+ state.has_delete_schedule = False
450
+ timer = threading.Timer(2.0, reset_flag)
451
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
452
+ timer.start()
453
 
454
  def on_login(state, payload):
455
  """Handle login form submission"""
456
+ if not state.has_on_login:
457
+ state.has_on_login = True
458
+ time.sleep(0.7)
459
+ email = state.login_email
460
+ password = state.login_password
461
+
462
+ if not email or not password:
463
+ state.message = "Please enter both email and password"
464
+ return
465
+
466
+ success, message, user_inf = db_manager.authenticate_user(email, password)
467
+
468
+ if user_inf is None:
469
+ # Handle the case when authentication fails
470
+ state.message = message
471
+ return
472
+
473
+ if success:
474
+ state.current_user = email
475
+ data = db_manager.fetch_source_table(user_inf.user.id)
476
+ dataac = db_manager.fetch_account_table(user_inf.user.id)
477
+ state.data_schedule = db_manager.fetch_schedule_table_acc(user_inf.user.id)
478
+ state.data_account = pd.DataFrame(dataac)
479
+ state.Source_table = pd.DataFrame(data)
480
+ navigate(state, "Source_Management")
481
+ state.is_logged_in = True
482
+ state.message = f"Welcome back, {email}!"
483
+ # Clear form
484
+ state.login_email = ""
485
+ state.login_password = ""
 
 
 
486
  else:
487
+ if message == "Compte non confirmé":
488
+ state.message = "Votre compte n'est pas encore activé. Veuillez vérifier votre email pour activer votre compte."
489
+ elif message == "Compte non existant":
490
+ state.message = "Email ou mot de passe incorrect."
491
+ else:
492
+ state.message = "Email ou mot de passe incorrect."
493
+
494
+ # Programmer la réinitialisation du flag dans 2 secondes
495
+ def reset_flag():
496
+ state.has_on_login = False
497
+ timer = threading.Timer(2.0, reset_flag)
498
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
499
+ timer.start()
500
 
501
  def on_register(state):
502
  """Handle registration form submission"""
503
+ if not state.has_on_register:
504
+ state.has_on_register = True
505
+ time.sleep(0.7)
506
+ email = state.register_email
507
+ password = state.register_password
508
+ confirm_password = state.confirm_password
509
+
510
+ if not email or not password or not confirm_password:
511
+ state.message = "Please fill in all fields"
512
+ return
513
+
514
+ if password != confirm_password:
515
+ state.message = "Passwords do not match"
516
+ return
517
+
518
+ if len(password) < 8:
519
+ state.message = "Password must be at least 8 characters long"
520
+ return
521
+
522
+ success, message,user_inf = db_manager.create_user(email, password) # type: ignore
523
+
524
+ if success:
525
+ state.message = "Un lien d'activation a été envoyé à votre adresse email. Veuillez vérifier votre boîte de réception pour activer votre compte."
526
+ state.show_register = False
527
+ # Clear form
528
+ state.register_email = ""
529
+ state.register_password = ""
530
+ state.confirm_password = ""
531
+ else:
532
+ state.message = message or "Erreur lors de l'inscription. Veuillez réessayer."
533
 
534
+ # Programmer la réinitialisation du flag dans 2 secondes
535
+ def reset_flag():
536
+ state.has_on_register = False
537
+ timer = threading.Timer(2.0, reset_flag)
538
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
539
+ timer.start()
540
 
541
+ def on_logout(state):
542
+ if not state.has_on_logout:
543
+ state.has_on_logout = True
544
 
545
+ """Handle logout"""
 
 
546
 
547
+ state.current_user = None
548
+ state.is_logged_in = False
549
+ state.message = "Logged out successfully"
550
+ state.login_email = ""
551
+ state.login_password = ""
552
 
553
+ # Programmer la réinitialisation du flag dans 2 secondes
554
+ def reset_flag():
555
+ state.has_on_logout = False
556
+ timer = threading.Timer(2.0, reset_flag)
557
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
558
+ timer.start()
559
+
560
+ def toggle_register(state):
561
+ """Toggle between login and register forms"""
562
+ if not state.has_toggle_register:
563
+ state.has_toggle_register = True
564
+ state.show_register = not state.show_register
565
+ state.message = ""
566
+ state.login_email = ""
567
+ state.login_password = ""
568
  state.register_email = ""
569
  state.register_password = ""
570
  state.confirm_password = ""
 
 
 
 
571
 
572
+ # Programmer la réinitialisation du flag dans 2 secondes
573
+ def reset_flag():
574
+ state.has_toggle_register = False
575
+ timer = threading.Timer(2.0, reset_flag)
576
+ timer.daemon = True # permet de ne pas bloquer la fermeture de l’app
577
+ timer.start()