diff --git a/resources/user/student_data.gd b/resources/user/student_data.gd index c466ef7e..3cd06635 100644 --- a/resources/user/student_data.gd +++ b/resources/user/student_data.gd @@ -8,11 +8,11 @@ enum Level { Adult } -@export var code: int -@export var name: String -@export var level: Level -@export var age: int -@export var last_modified: String +@export var code: int = 0 +@export var name: String = "" +@export var level: Level = Level.Beginner +@export var age: int = 0 +@export var last_modified: String = "" func to_dict() -> Dictionary: return { diff --git a/resources/user/student_progression.gd b/resources/user/student_progression.gd index 58528953..592000d8 100644 --- a/resources/user/student_progression.gd +++ b/resources/user/student_progression.gd @@ -9,8 +9,9 @@ enum Status{ Completed, } -@export var version: float = 1.0 +@export var version: String = ProjectSettings.get_setting("application/config/version") @export var unlocks: Dictionary = {} +@export var last_modified: String = "" func _init() -> void: @@ -47,6 +48,9 @@ func init_unlocks() -> bool: unlocks[1]["look_and_learn"] = Status.Unlocked has_changes = true + if has_changes: + last_modified = Time.get_datetime_string_from_system(true) + return has_changes @@ -75,6 +79,7 @@ func look_and_learn_completed(lesson_number: int) -> bool: for index: int in range(3): unlocks[lesson_number]["games"][index] = Status.Unlocked + last_modified = Time.get_datetime_string_from_system(true) unlocks_changed.emit() return true @@ -94,5 +99,6 @@ func game_completed(lesson_number: int, game_number: int) -> bool: if all_completed and unlocks.has(lesson_number + 1): unlocks[lesson_number + 1]["look_and_learn"] = Status.Unlocked + last_modified = Time.get_datetime_string_from_system(true) unlocks_changed.emit() return true diff --git a/sources/minigames/base/base_minigame.gd b/sources/minigames/base/base_minigame.gd index 43174a50..073ff5a8 100644 --- a/sources/minigames/base/base_minigame.gd +++ b/sources/minigames/base/base_minigame.gd @@ -1,4 +1,3 @@ -@tool extends Control class_name Minigame diff --git a/sources/minigames/base/words/words_minigame.gd b/sources/minigames/base/words/words_minigame.gd index 98f88a24..8f09e658 100644 --- a/sources/minigames/base/words/words_minigame.gd +++ b/sources/minigames/base/words/words_minigame.gd @@ -1,4 +1,3 @@ -@tool extends Minigame class_name WordsMinigame diff --git a/sources/utils/autoloads/server_manager.gd b/sources/utils/autoloads/server_manager.gd index aa61441f..c27cad92 100644 --- a/sources/utils/autoloads/server_manager.gd +++ b/sources/utils/autoloads/server_manager.gd @@ -238,7 +238,7 @@ func _on_http_request_request_completed(result_code: int, response_code: int, _h var str_body: String = body.get_string_from_utf8() var result: Variant = JSON.parse_string(str_body) if result is Dictionary or result is Array: - var pretty = JSON.stringify(result, "\t") + var pretty: String = JSON.stringify(result, "\t") Logger.trace("JSON Body received :\n%s" % pretty) else: Logger.trace("Body received = %s" % body.get_string_from_utf8()) diff --git a/sources/utils/autoloads/user_data_manager.gd b/sources/utils/autoloads/user_data_manager.gd index 5ff46a5e..7e47930c 100644 --- a/sources/utils/autoloads/user_data_manager.gd +++ b/sources/utils/autoloads/user_data_manager.gd @@ -1,4 +1,3 @@ -@tool extends Node @@ -149,11 +148,9 @@ func safe_load_and_fix_resource(path: String, old_texts: Array[String], new_text var resource: Resource = ResourceLoader.load(path) if resource == null: - #TODO REPLACE WITH LOGGER - push_error("UserDataManager: Loading failed after correction: " + path) + Logger.error("UserDataManager: Loading failed after correction: " + path) else: - #TODO REPLACE WITH LOGGER - print("UserDataManager: Loading success: " + path) + Logger.trace("UserDataManager: Loading success: " + path) return resource func set_device_id(device: int) -> bool: @@ -437,6 +434,13 @@ func _on_user_progression_unlocks_changed() -> void: func get_student_progression_for_code(device: int, code: int) -> StudentProgression: + if device == 0: + var device_path: String = find_device_dir_for_student(code) + var device_name: String = device_path.get_file() + if device_name.is_valid_int(): + device = int(device_name) + else: + return null if not teacher_settings or not teacher_settings.students.has(device): return @@ -453,7 +457,7 @@ func get_student_progression_for_code(device: int, code: int) -> StudentProgress else: progression = StudentProgression.new() DirAccess.make_dir_recursive_absolute(student_path) - #ResourceSaver.save(student_progression, progression_path) + ResourceSaver.save(student_progression, progression_path) return progression @@ -654,6 +658,20 @@ func move_user_device_folder(old_device: String, new_device: String, student_cod save_teacher_settings() func find_student_dir(student_code: int) -> String: + @warning_ignore("unused_parameter") + return _scan_teacher_devices(func(device_dir: String, lang_dir: String, sub_file: String) -> String: + if sub_file == str(student_code): + return lang_dir.path_join(sub_file) + return "") + +func find_device_dir_for_student(student_code: int) -> String: + @warning_ignore("unused_parameter") + return _scan_teacher_devices(func(device_dir: String, lang_dir: String, sub_file: String) -> String: + if sub_file == str(student_code): + return device_dir + return "") + +func _scan_teacher_devices(match_callback: Callable) -> String: var teacher_path: String = "user://".path_join(_device_settings.teacher) var dir: DirAccess = DirAccess.open(teacher_path) if not dir: @@ -675,9 +693,10 @@ func find_student_dir(student_code: int) -> String: lang_subdir.list_dir_begin() var sub_file: String = lang_subdir.get_next() while sub_file != "": - if lang_subdir.current_is_dir() and sub_file == str(student_code): - var student_path: String = lang_dir.path_join(sub_file) - return student_path + if lang_subdir.current_is_dir(): + var result: Variant = match_callback.call(device_dir, lang_dir, sub_file) + if result != "": + return result sub_file = lang_subdir.get_next() lang_subdir.list_dir_end() else: @@ -687,7 +706,6 @@ func find_student_dir(student_code: int) -> String: dir.list_dir_end() return "" - func save_all() -> void: _save_device_settings() save_teacher_settings() diff --git a/sources/utils/autoloads/user_database_synchronizer.gd b/sources/utils/autoloads/user_database_synchronizer.gd index fa652877..6bed6bcc 100644 --- a/sources/utils/autoloads/user_database_synchronizer.gd +++ b/sources/utils/autoloads/user_database_synchronizer.gd @@ -105,6 +105,14 @@ func _determine_students_update(response_body: Dictionary, need_update_user: Upd server_student_unix_time = Time.get_unix_time_from_datetime_string(student_dic.updated_at as String) else: Logger.warn("UserDatabaseSynchronizer: Student %d received from server has no timestamp" % code_to_check) + + var server_student_progression_unix_time: int = -1 + if student_dic.has("progression_last_modified"): + if student_dic.progression_last_modified != null && student_dic.progression_last_modified is String: + server_student_progression_unix_time = Time.get_unix_time_from_datetime_string(student_dic.progression_last_modified as String) + else: + server_student_progression_unix_time = 0 + var server_student_remediation_gp_unix_time: int = -1 if student_dic.has("gp_remediation_last_modified"): if student_dic.gp_remediation_last_modified != null && student_dic.gp_remediation_last_modified is String: @@ -123,6 +131,7 @@ func _determine_students_update(response_body: Dictionary, need_update_user: Upd server_student_remediation_words_unix_time = Time.get_unix_time_from_datetime_string(student_dic.words_remediation_last_modified as String) else: server_student_remediation_words_unix_time = 0 + var found: bool = false need_update_students[code_to_check] = {} for device: int in UserDataManager.teacher_settings.students.keys(): @@ -141,6 +150,17 @@ func _determine_students_update(response_body: Dictionary, need_update_user: Upd else: need_update_students[code_to_check].merge({"data": UpdateNeeded.FromServer}) + # Synchronize student progression + var student_progression: StudentProgression = UserDataManager.get_student_progression_for_code(device, code_to_check) + var local_student_progression_unix_time: int = Time.get_unix_time_from_datetime_string(student_progression.last_modified) + if local_student_progression_unix_time == server_student_progression_unix_time: + Logger.trace("UserDatabaseSynchronizer: Student %d progression data timestamp is the same in local and on server. No synchronization necessary" % code_to_check) + need_update_students[code_to_check].merge({"progression": UpdateNeeded.Nothing}) + elif local_student_progression_unix_time > server_student_progression_unix_time: + need_update_students[code_to_check].merge({"progression": UpdateNeeded.FromLocal}) + else: + need_update_students[code_to_check].merge({"progression": UpdateNeeded.FromServer}) + # Synchronize student remediation var student_remediation: UserRemediation = UserDataManager.get_student_remediation_data(code_to_check) if student_remediation != null: @@ -244,6 +264,26 @@ func _build_message_to_server(need_update_user: UpdateNeeded, need_update_studen elif student_update == UpdateNeeded.FromServer: student_block["need_update"] = true + + # Traitement des data de progression + var student_progression: StudentProgression = UserDataManager.get_student_progression_for_code(0, student_code) + if student_progression == null: + Logger.trace("Cannot find progression data for student %s" % str(student_code)) + elif student_entry.has("progression"): + var progression_block: Dictionary = {} + if student_entry.progression == UpdateNeeded.FromLocal: + progression_block = { + "version": student_progression.version, + "unlocked": student_progression.unlocks, + "updated_at": student_progression.last_modified + } + elif student_entry.progression == UpdateNeeded.FromServer: + progression_block = {"need_update": true} + elif student_entry.progression == UpdateNeeded.DeleteServer: + progression_block = {"delete": true} +# + if progression_block.size() > 0: + student_block["progression"] = progression_block # Traitement des remediations scores var student_remediation: UserRemediation = UserDataManager.get_student_remediation_data(student_code)