Sync student_progression + various cleaning / debug

This commit is contained in:
Adrien Ufferte
2025-06-23 15:21:16 +02:00
parent d344acb22d
commit 3be3e5bc49
7 changed files with 81 additions and 19 deletions
+5 -5
View File
@@ -8,11 +8,11 @@ enum Level {
Adult Adult
} }
@export var code: int @export var code: int = 0
@export var name: String @export var name: String = ""
@export var level: Level @export var level: Level = Level.Beginner
@export var age: int @export var age: int = 0
@export var last_modified: String @export var last_modified: String = ""
func to_dict() -> Dictionary: func to_dict() -> Dictionary:
return { return {
+7 -1
View File
@@ -9,8 +9,9 @@ enum Status{
Completed, Completed,
} }
@export var version: float = 1.0 @export var version: String = ProjectSettings.get_setting("application/config/version")
@export var unlocks: Dictionary = {} @export var unlocks: Dictionary = {}
@export var last_modified: String = ""
func _init() -> void: func _init() -> void:
@@ -47,6 +48,9 @@ func init_unlocks() -> bool:
unlocks[1]["look_and_learn"] = Status.Unlocked unlocks[1]["look_and_learn"] = Status.Unlocked
has_changes = true has_changes = true
if has_changes:
last_modified = Time.get_datetime_string_from_system(true)
return has_changes return has_changes
@@ -75,6 +79,7 @@ func look_and_learn_completed(lesson_number: int) -> bool:
for index: int in range(3): for index: int in range(3):
unlocks[lesson_number]["games"][index] = Status.Unlocked unlocks[lesson_number]["games"][index] = Status.Unlocked
last_modified = Time.get_datetime_string_from_system(true)
unlocks_changed.emit() unlocks_changed.emit()
return true 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): if all_completed and unlocks.has(lesson_number + 1):
unlocks[lesson_number + 1]["look_and_learn"] = Status.Unlocked unlocks[lesson_number + 1]["look_and_learn"] = Status.Unlocked
last_modified = Time.get_datetime_string_from_system(true)
unlocks_changed.emit() unlocks_changed.emit()
return true return true
-1
View File
@@ -1,4 +1,3 @@
@tool
extends Control extends Control
class_name Minigame class_name Minigame
@@ -1,4 +1,3 @@
@tool
extends Minigame extends Minigame
class_name WordsMinigame class_name WordsMinigame
+1 -1
View File
@@ -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 str_body: String = body.get_string_from_utf8()
var result: Variant = JSON.parse_string(str_body) var result: Variant = JSON.parse_string(str_body)
if result is Dictionary or result is Array: 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) Logger.trace("JSON Body received :\n%s" % pretty)
else: else:
Logger.trace("Body received = %s" % body.get_string_from_utf8()) Logger.trace("Body received = %s" % body.get_string_from_utf8())
+28 -10
View File
@@ -1,4 +1,3 @@
@tool
extends Node 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) var resource: Resource = ResourceLoader.load(path)
if resource == null: if resource == null:
#TODO REPLACE WITH LOGGER Logger.error("UserDataManager: Loading failed after correction: " + path)
push_error("UserDataManager: Loading failed after correction: " + path)
else: else:
#TODO REPLACE WITH LOGGER Logger.trace("UserDataManager: Loading success: " + path)
print("UserDataManager: Loading success: " + path)
return resource return resource
func set_device_id(device: int) -> bool: 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: 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): if not teacher_settings or not teacher_settings.students.has(device):
return return
@@ -453,7 +457,7 @@ func get_student_progression_for_code(device: int, code: int) -> StudentProgress
else: else:
progression = StudentProgression.new() progression = StudentProgression.new()
DirAccess.make_dir_recursive_absolute(student_path) DirAccess.make_dir_recursive_absolute(student_path)
#ResourceSaver.save(student_progression, progression_path) ResourceSaver.save(student_progression, progression_path)
return progression return progression
@@ -654,6 +658,20 @@ func move_user_device_folder(old_device: String, new_device: String, student_cod
save_teacher_settings() save_teacher_settings()
func find_student_dir(student_code: int) -> String: 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 teacher_path: String = "user://".path_join(_device_settings.teacher)
var dir: DirAccess = DirAccess.open(teacher_path) var dir: DirAccess = DirAccess.open(teacher_path)
if not dir: if not dir:
@@ -675,9 +693,10 @@ func find_student_dir(student_code: int) -> String:
lang_subdir.list_dir_begin() lang_subdir.list_dir_begin()
var sub_file: String = lang_subdir.get_next() var sub_file: String = lang_subdir.get_next()
while sub_file != "": while sub_file != "":
if lang_subdir.current_is_dir() and sub_file == str(student_code): if lang_subdir.current_is_dir():
var student_path: String = lang_dir.path_join(sub_file) var result: Variant = match_callback.call(device_dir, lang_dir, sub_file)
return student_path if result != "":
return result
sub_file = lang_subdir.get_next() sub_file = lang_subdir.get_next()
lang_subdir.list_dir_end() lang_subdir.list_dir_end()
else: else:
@@ -687,7 +706,6 @@ func find_student_dir(student_code: int) -> String:
dir.list_dir_end() dir.list_dir_end()
return "" return ""
func save_all() -> void: func save_all() -> void:
_save_device_settings() _save_device_settings()
save_teacher_settings() save_teacher_settings()
@@ -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) server_student_unix_time = Time.get_unix_time_from_datetime_string(student_dic.updated_at as String)
else: else:
Logger.warn("UserDatabaseSynchronizer: Student %d received from server has no timestamp" % code_to_check) 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 var server_student_remediation_gp_unix_time: int = -1
if student_dic.has("gp_remediation_last_modified"): if student_dic.has("gp_remediation_last_modified"):
if student_dic.gp_remediation_last_modified != null && student_dic.gp_remediation_last_modified is String: 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) server_student_remediation_words_unix_time = Time.get_unix_time_from_datetime_string(student_dic.words_remediation_last_modified as String)
else: else:
server_student_remediation_words_unix_time = 0 server_student_remediation_words_unix_time = 0
var found: bool = false var found: bool = false
need_update_students[code_to_check] = {} need_update_students[code_to_check] = {}
for device: int in UserDataManager.teacher_settings.students.keys(): 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: else:
need_update_students[code_to_check].merge({"data": UpdateNeeded.FromServer}) 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 # Synchronize student remediation
var student_remediation: UserRemediation = UserDataManager.get_student_remediation_data(code_to_check) var student_remediation: UserRemediation = UserDataManager.get_student_remediation_data(code_to_check)
if student_remediation != null: 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: elif student_update == UpdateNeeded.FromServer:
student_block["need_update"] = true 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 # Traitement des remediations scores
var student_remediation: UserRemediation = UserDataManager.get_student_remediation_data(student_code) var student_remediation: UserRemediation = UserDataManager.get_student_remediation_data(student_code)