Data synchronization v2

This commit is contained in:
Adrien Ufferte
2025-05-27 11:04:52 +02:00
parent 976d96d814
commit 71f001befb
13 changed files with 234 additions and 109 deletions
+13
View File
@@ -87,6 +87,19 @@ func update_user_data(teacher: TeacherSettings, timestamp: String, force: bool =
await _post_json_request("update_user_data", data)
return _response()
func update_student_remediation_data(student_code: int, student_remediation: UserRemediation) -> Dictionary:
if not student_remediation:
Logger.trace("ServerManager: Cannot update studient remediation data because data does not exists")
success = true
code = -1
json = {}
return _response()
var tuple_list: Array = []
for key: int in student_remediation.gps_scores.keys():
tuple_list.append([key, student_remediation.gps_scores[key]])
var data: Dictionary = {"student_id": student_code, "score_remediation": tuple_list}
await _post_json_request("submit_gp_remediation", data)
return _response()
# p_student must have a device key
# it can contain a name, level and age key for parents
+22 -4
View File
@@ -326,12 +326,20 @@ func update_configuration(configuration: Dictionary) -> bool:
return true
func get_number_of_students() -> int:
if not teacher_settings:
return 0
return teacher_settings.get_number_of_students()
#endregion
#region Student settings
func get_student_folder() -> String:
return _device_settings.get_folder_path().path_join(student)
func get_student_folder(student_code: int = 0) -> String:
if student_code == 0:
return _device_settings.get_folder_path().path_join(student)
else:
return _device_settings.get_folder_path().path_join(str(student_code))
#endregion
@@ -389,8 +397,8 @@ func save_student_progression_for_code(device: int, code: int, progression: User
#region Student remediation
func _get_student_remediation_path() -> String:
return get_student_folder().path_join("remediation.tres")
func _get_student_remediation_path(student_code: int = 0) -> String:
return get_student_folder(student_code).path_join("remediation.tres")
func _load_student_remediation() -> void:
if FileAccess.file_exists(_get_student_remediation_path()):
@@ -403,7 +411,17 @@ func _load_student_remediation() -> void:
_student_remediation.score_changed.connect(_save_student_remediation)
func get_student_remediation_data(student_code: int) -> UserRemediation:
var remediation_data_path: String = _get_student_remediation_path(student_code)
if FileAccess.file_exists(remediation_data_path):
var student_remediation: UserRemediation
student_remediation = load(remediation_data_path)
return student_remediation
Logger.trace("UserDataManager: Remediation data of student code %d not found" % student_code)
return null
func _save_student_remediation() -> void:
_student_remediation.last_modified = Time.get_datetime_string_from_system(true)
ResourceSaver.save(_student_remediation, _get_student_remediation_path())
func get_GP_remediation_score(GPID: int) -> int:
@@ -0,0 +1,150 @@
extends Node
class_name UserDataBaseSynchronizer
var synchronizing: bool = false
var localStringTime: String= ""
var account_type_option_button: OptionButton
var education_method_option_button: OptionButton
var loading_popup: LoadingPopup
var sync_choice_popup: ConfirmPopup
func startSync() -> void:
synchronizing = true
loading_popup.set_finished(false)
loading_popup.set_text("SYNCHRONIZATION_INITIALISATION")
await setLoadingProgression(0.0)
loading_popup.show()
func stopSync(success: bool = false) -> void:
synchronizing = false
if success:
await setLoadingProgression(100.0, 1.0)
loading_popup.set_text("SYNCHRONIZATION_SUCCESS")
loading_popup.set_finished(true)
func on_synchronize_button_pressed() -> void:
#synchronizing = false
#await ServerManager.update_user_data(UserDataManager.teacher_settings, "2025-05-23T09:39:47", true)
#return
Logger.trace("SettingsTeacherSettings: Start synchronizing user data.")
if synchronizing:
Logger.trace("SettingsTeacherSettings: User synchronization already started, cancel double-call.")
return
startSync()
var resGetTeacherTimestamp: Dictionary = await ServerManager.get_user_data_timestamp()
if resGetTeacherTimestamp.success:
Logger.trace("SettingsTeacherSettings: Server timestamp for user data = " + str(resGetTeacherTimestamp.body["last_modified"]))
else:
Logger.trace("Cannot get server timestamp for user data. Canceling synchronization.")
loading_popup.set_text("SYNCHRONIZATION_ERROR_NO_SERVER")
stopSync()
return
var unixTimeServer: int = Time.get_unix_time_from_datetime_string(resGetTeacherTimestamp.body["last_modified"] as String)
localStringTime = UserDataManager.teacher_settings.last_modified
if localStringTime == "":
var localResult: Dictionary = UserDataManager.get_latest_modification(UserDataManager.get_teacher_folder())
if localResult.error == OK:
localStringTime = Time.get_datetime_string_from_datetime_dict(localResult.modification_date as Dictionary, false)
Logger.trace("SettingsTeacherSettings: Local user file timestamp = " + localStringTime)
else:
Logger.warn("SettingsTeacherSettings: Cannot find modification date for local user data: " + error_string(localResult.error as int))
loading_popup.set_text("SYNCHRONIZATION_ERROR_NO_LOCAL_TIMESTAMP")
stopSync()
return
var localUnixTime: int = Time.get_unix_time_from_datetime_string(localStringTime)
if localUnixTime == unixTimeServer:
Logger.trace("SettingsTeacherSettings: User data timestamp is the same in local and on server. No synchronization necessary")
elif localUnixTime > unixTimeServer:
on_sync_choice_local()
return
else:
Logger.trace("SettingsTeacherSettings: Local user data timestamp is obsolete, we need to choose a priority")
sync_choice_popup.show()
return
stopSync(true)
func on_sync_choice_server() -> void:
Logger.trace("SettingsTeacherSettings: Synchronization priority defined to server")
await setLoadingProgression(1.0)
var resGetUserData: Dictionary = await ServerManager.get_user_data()
if resGetUserData.success:
if resGetUserData.has("body"):
# {"email": "cvbn@yopmail.com", "account_type": 0, "education_method": 0, "created_at": "2025-05-15T12:27:34Z", "last_modified": "2025-05-22T14:05:42Z"}
var resultBody: Dictionary = resGetUserData.body
if resultBody.has("account_type"):
UserDataManager.teacher_settings.account_type = resultBody.account_type
account_type_option_button.select(UserDataManager.teacher_settings.account_type)
else:
Logger.warn("SettingsTeacherSettings: user data received from the server has no account_type")
if resultBody.has("education_method"):
UserDataManager.teacher_settings.education_method = resultBody.education_method
education_method_option_button.select(UserDataManager.teacher_settings.education_method)
else:
Logger.warn("SettingsTeacherSettings: user data received from the server has no education_method")
else:
Logger.warn("SettingsTeacherSettings: user data received from the server has no body")
loading_popup.set_text("SYNCHRONIZATION_ERROR_NO_BODY_FROM_SERVER")
stopSync()
return
else:
if resGetUserData.has("body"):
Logger.warn("SettingsTeacherSettings: Failed to get user data from the server: %s" % resGetUserData.body)
else:
Logger.warn("SettingsTeacherSettings: Failed to get user data from the server")
loading_popup.set_text("SYNCHRONIZATION_ERROR_SERVER")
stopSync()
return
stopSync(true)
func on_sync_choice_local() -> void:
Logger.trace("SettingsTeacherSettings: Synchronization priority defined to local")
var numberOfStudents: int = UserDataManager.get_number_of_students()
var numberOfUpdatesToDo: int = numberOfStudents + 1 # +1 for user data
var percentOfUpdateForEachStep: float = 100.0/numberOfUpdatesToDo
var currentUpdateProgression: float = 0.0
await setLoadingProgression(1.0)
loading_popup.set_text("SYNCHRONIZING_USER")
var resSetUserData: Dictionary = await ServerManager.update_user_data(UserDataManager.teacher_settings, localStringTime, true)
if resSetUserData.success:
Logger.trace("SettingsTeacherSettings: user data successfully sent to the server")
currentUpdateProgression += percentOfUpdateForEachStep
await setLoadingProgression(currentUpdateProgression)
else:
Logger.warn("SettingsTeacherSettings: Failed to send update of user data to the server: %s" % resSetUserData.body)
loading_popup.set_text("SYNCHRONIZATION_ERROR_FAIL_SEND_DATA_USER")
stopSync()
return
for student_data: StudentData in UserDataManager.teacher_settings.get_all_students_data():
var gp_remediation_scores: UserRemediation = UserDataManager.get_student_remediation_data(student_data.code)
# TODO YA UN SOUCI ICI AVEC LA TRADUCTION
var sync_student_text: String = tr("SYNCHRONIZING_STUDENT_%S")
#loading_popup.set_text("Synchro de l'élève %s" % student_data.name)
loading_popup.set_text(sync_student_text % student_data.name)
var resUpdateStudentRemediationScores: Dictionary = await ServerManager.update_student_remediation_data(student_data.code, gp_remediation_scores)
currentUpdateProgression += percentOfUpdateForEachStep
await setLoadingProgression(currentUpdateProgression)
if resUpdateStudentRemediationScores.success:
continue
else:
loading_popup.set_text("SYNCHRONIZATION_ERROR_FAIL_SEND_DATA_STUDENT")
# TODO : TRADUCTION DES MESSAGES D'ERREUR DE LOADING POPUP !!!!!
Logger.warn("SettingsTeacherSettings: Failed to send update of student data to the server: %s" % resUpdateStudentRemediationScores.body)
stopSync()
return
stopSync(true)
func setLoadingProgression(value: float, wait_time: float = 0.2) -> void:
loading_popup.set_progress(value)
await loading_popup.get_tree().create_timer(wait_time).timeout
@@ -0,0 +1 @@
uid://cn7e1aqdwr6x8