@@ -94,15 +94,17 @@ def add_task_account(username, is_official, lms_enabled):
9494 "username" : str (username ),
9595 "isOfficial" : bool (is_official ),
9696 "lmsEnabled" : bool (lms_enabled ),
97+ "completedTasks" : [],
98+ "recordedItemIdsByTask" : {},
9799 'tiers' : {
98- 'easy' : {"completedTasks" : [] },
99- 'medium' : {"completedTasks" : [] },
100- 'hard' : {"completedTasks" : [] },
101- 'elite' : {"completedTasks" : [] },
102- 'master' : {"completedTasks" : [] },
103- 'passive' : {"completedTasks" : [] },
104- 'extra' : {"completedTasks" : [] },
105- 'pets' : {"completedTasks" : [] },
100+ 'easy' : {},
101+ 'medium' : {},
102+ 'hard' : {},
103+ 'elite' : {},
104+ 'master' : {},
105+ 'passive' : {},
106+ 'extra' : {},
107+ 'pets' : {},
106108 }
107109 })
108110
@@ -280,15 +282,14 @@ def __set_task_complete(username: str, tier: str, task_id: str, complete: bool,
280282 completed_at_iso : str | None = None ,
281283 completed_item_ids : list [int ] | None = None ):
282284 task_coll = mydb ['taskLists' ]
283- cleaned_tier = tier .replace ("Tasks" , "" )
284285 if complete :
285286 completed_date = __parse_completed_iso (completed_at_iso ) or datetime .now (timezone .utc )
286287 safe_completed_item_ids = __sanitize_item_ids (completed_item_ids )
287288 task_coll .update_one (
288289 {"username" : username },
289290 {
290291 "$pull" : {
291- f"tiers. { cleaned_tier } . completedTasks" : {
292+ " completedTasks" : {
292293 "id" : task_id
293294 }
294295 }
@@ -298,10 +299,10 @@ def __set_task_complete(username: str, tier: str, task_id: str, complete: bool,
298299 {"username" : username },
299300 {
300301 "$push" : {
301- f"tiers. { cleaned_tier } . completedTasks" : {
302+ " completedTasks" : {
302303 "id" : task_id ,
303304 "completedDate" : completed_date ,
304- "completedItemIds " : safe_completed_item_ids
305+ "retainedItemIds " : safe_completed_item_ids
305306 }
306307 }
307308 }
@@ -310,7 +311,7 @@ def __set_task_complete(username: str, tier: str, task_id: str, complete: bool,
310311 {"username" : username },
311312 {
312313 "$set" : {
313- f"tiers. { cleaned_tier } . recordedItemIdsByTask.{ task_id } " : safe_completed_item_ids
314+ f"recordedItemIdsByTask.{ task_id } " : safe_completed_item_ids
314315 }
315316 }
316317 )
@@ -322,7 +323,7 @@ def __set_task_complete(username: str, tier: str, task_id: str, complete: bool,
322323 },
323324 {
324325 "$pull" : {
325- f"tiers. { cleaned_tier } . completedTasks" : {"id" : task_id }
326+ " completedTasks" : {"id" : task_id }
326327 }
327328 })
328329 return None , []
@@ -742,6 +743,8 @@ def update_imported_tasks(username: str, all_tasks: list, username2: str,
742743
743744 diaries = coll .find_one ({'username' : username }, {
744745 '_id' : 0 ,
746+ 'completedTasks' : 1 ,
747+ 'recordedItemIdsByTask' : 1 ,
745748 'tiers.easy.completedTasks' : 1 ,
746749 'tiers.medium.completedTasks' : 1 ,
747750 'tiers.hard.completedTasks' : 1 ,
@@ -752,22 +755,74 @@ def update_imported_tasks(username: str, all_tasks: list, username2: str,
752755 'tiers.elite.recordedItemIdsByTask' : 1 ,
753756 })
754757
758+ if not diaries :
759+ return
760+
755761 def sanitize_recorded_map (value ):
756762 if not isinstance (value , dict ):
757763 return {}
758764 return {str (task_id ): __sanitize_item_ids (item_ids ) for task_id , item_ids in value .items ()}
759765
760- existing_recorded_easy = sanitize_recorded_map (diaries ['tiers' ]['easy' ].get ('recordedItemIdsByTask' , {}))
761- existing_recorded_medium = sanitize_recorded_map (diaries ['tiers' ]['medium' ].get ('recordedItemIdsByTask' , {}))
762- existing_recorded_hard = sanitize_recorded_map (diaries ['tiers' ]['hard' ].get ('recordedItemIdsByTask' , {}))
763- existing_recorded_elite = sanitize_recorded_map (diaries ['tiers' ]['elite' ].get ('recordedItemIdsByTask' , {}))
766+ tiers_data = diaries .get ('tiers' , {}) if isinstance (diaries .get ('tiers' , {}), dict ) else {}
764767
765- def existing_completed_date_map (completed_tasks ):
766- output = {}
767- for entry in completed_tasks :
768+ existing_root_recorded = sanitize_recorded_map (diaries .get ('recordedItemIdsByTask' , {}))
769+
770+ existing_recorded_easy = sanitize_recorded_map (tiers_data .get ('easy' , {}).get ('recordedItemIdsByTask' , {}))
771+ existing_recorded_medium = sanitize_recorded_map (tiers_data .get ('medium' , {}).get ('recordedItemIdsByTask' , {}))
772+ existing_recorded_hard = sanitize_recorded_map (tiers_data .get ('hard' , {}).get ('recordedItemIdsByTask' , {}))
773+ existing_recorded_elite = sanitize_recorded_map (tiers_data .get ('elite' , {}).get ('recordedItemIdsByTask' , {}))
774+ if not existing_root_recorded :
775+ existing_root_recorded = {
776+ ** existing_recorded_easy ,
777+ ** existing_recorded_medium ,
778+ ** existing_recorded_hard ,
779+ ** existing_recorded_elite ,
780+ }
781+
782+ lms_enabled = get_user (username ).lms_enabled
783+ tier_task_ids = {
784+ 'easy' : {task .id for task in tasklists .list_for_tier ('easy' , lms_enabled )},
785+ 'medium' : {task .id for task in tasklists .list_for_tier ('medium' , lms_enabled )},
786+ 'hard' : {task .id for task in tasklists .list_for_tier ('hard' , lms_enabled )},
787+ 'elite' : {task .id for task in tasklists .list_for_tier ('elite' , lms_enabled )},
788+ }
789+
790+ def normalize_completed_entries (value ):
791+ if not isinstance (value , list ):
792+ return []
793+ output = []
794+ for entry in value :
795+ if not isinstance (entry , dict ):
796+ continue
768797 task_id = entry .get ('id' )
769798 if not task_id :
770799 continue
800+ retained_item_ids = entry .get ('retainedItemIds' )
801+ if retained_item_ids is None :
802+ retained_item_ids = entry .get ('completedItemIds' , [])
803+ output .append ({
804+ 'id' : str (task_id ),
805+ 'completedDate' : entry .get ('completedDate' ),
806+ 'retainedItemIds' : __sanitize_item_ids (retained_item_ids ),
807+ })
808+ return output
809+
810+ existing_root_completed = normalize_completed_entries (diaries .get ('completedTasks' , []))
811+ if not existing_root_completed :
812+ existing_root_completed = (
813+ normalize_completed_entries (tiers_data .get ('easy' , {}).get ('completedTasks' , [])) +
814+ normalize_completed_entries (tiers_data .get ('medium' , {}).get ('completedTasks' , [])) +
815+ normalize_completed_entries (tiers_data .get ('hard' , {}).get ('completedTasks' , [])) +
816+ normalize_completed_entries (tiers_data .get ('elite' , {}).get ('completedTasks' , []))
817+ )
818+
819+ def existing_completed_date_map (tier_name ):
820+ output = {}
821+ valid_ids = tier_task_ids [tier_name ]
822+ for entry in existing_root_completed :
823+ task_id = entry .get ('id' )
824+ if not task_id or task_id not in valid_ids :
825+ continue
771826 completed_date = entry .get ('completedDate' )
772827 if completed_date is None :
773828 continue
@@ -776,10 +831,10 @@ def existing_completed_date_map(completed_tasks):
776831 output [task_id ] = normalized_date
777832 return output
778833
779- existing_completed_dates_easy = existing_completed_date_map (diaries [ 'tiers' ][ ' easy']. get ( 'completedTasks' , []) )
780- existing_completed_dates_medium = existing_completed_date_map (diaries [ 'tiers' ][ ' medium']. get ( 'completedTasks' , []) )
781- existing_completed_dates_hard = existing_completed_date_map (diaries [ 'tiers' ][ ' hard']. get ( 'completedTasks' , []) )
782- existing_completed_dates_elite = existing_completed_date_map (diaries [ 'tiers' ][ ' elite']. get ( 'completedTasks' , []) )
834+ existing_completed_dates_easy = existing_completed_date_map (' easy' )
835+ existing_completed_dates_medium = existing_completed_date_map (' medium' )
836+ existing_completed_dates_hard = existing_completed_date_map (' hard' )
837+ existing_completed_dates_elite = existing_completed_date_map (' elite' )
783838
784839 if overwrite_temple_timestamps :
785840 tier_existing_dates = [
@@ -805,77 +860,91 @@ def existing_completed_date_map(completed_tasks):
805860 imported_recorded_hard = sanitize_recorded_map (recorded_item_ids_by_tier .get ('hard' , {}))
806861 imported_recorded_elite = sanitize_recorded_map (recorded_item_ids_by_tier .get ('elite' , {}))
807862
808- merged_recorded_easy = {** existing_recorded_easy , ** imported_recorded_easy }
809- merged_recorded_medium = {** existing_recorded_medium , ** imported_recorded_medium }
810- merged_recorded_hard = {** existing_recorded_hard , ** imported_recorded_hard }
811- merged_recorded_elite = {** existing_recorded_elite , ** imported_recorded_elite }
863+ merged_root_recorded = {
864+ ** existing_root_recorded ,
865+ ** imported_recorded_easy ,
866+ ** imported_recorded_medium ,
867+ ** imported_recorded_hard ,
868+ ** imported_recorded_elite ,
869+ }
812870
813- coll .update_one ({'username' : username }, {
814- '$set' : {
815- 'tiers.easy.completedTasks' : [],
816- 'tiers.medium.completedTasks' : [],
817- 'tiers.hard.completedTasks' : [],
818- 'tiers.elite.completedTasks' : [],
819- }
820- })
871+ imported_root_completed = []
872+ for tier_tasks in all_tasks :
873+ for imported_task in tier_tasks :
874+ task_id = imported_task .get ('id' )
875+ if not task_id :
876+ continue
877+ imported_root_completed .append ({
878+ 'id' : str (task_id ),
879+ 'completedDate' : imported_task .get ('completedDate' ),
880+ 'retainedItemIds' : [],
881+ })
882+
883+ import_tier_task_ids = set ().union (
884+ tier_task_ids ['easy' ],
885+ tier_task_ids ['medium' ],
886+ tier_task_ids ['hard' ],
887+ tier_task_ids ['elite' ],
888+ )
889+
890+ preserved_non_import_entries = []
891+ for entry in existing_root_completed :
892+ if entry ['id' ] not in import_tier_task_ids :
893+ preserved_non_import_entries .append (entry )
894+
895+ merged_root_completed = preserved_non_import_entries + imported_root_completed
821896
822897 coll .update_one ({'username' : username }, {
823898 '$set' : {
824- 'tiers.easy.completedTasks' : all_tasks [0 ],
825- 'tiers.medium.completedTasks' : all_tasks [1 ],
826- 'tiers.hard.completedTasks' : all_tasks [2 ],
827- 'tiers.elite.completedTasks' : all_tasks [3 ],
828- 'tiers.easy.recordedItemIdsByTask' : merged_recorded_easy ,
829- 'tiers.medium.recordedItemIdsByTask' : merged_recorded_medium ,
830- 'tiers.hard.recordedItemIdsByTask' : merged_recorded_hard ,
831- 'tiers.elite.recordedItemIdsByTask' : merged_recorded_elite ,
899+ 'completedTasks' : merged_root_completed ,
900+ 'recordedItemIdsByTask' : merged_root_recorded ,
832901 }
833902 })
834903
835904 coll .update_one ({'username' : username }, {'$set' : {'ign' : username2 }})
836905
837- for diary in diaries [ 'tiers' ][ 'easy' ][ 'completedTasks' ] :
906+ for diary in existing_root_completed :
838907 if diary ['id' ] in easy_diaries :
839908 __set_task_complete (
840909 username ,
841910 'easyTasks' ,
842911 diary ['id' ],
843912 True ,
844913 __datetime_to_iso (diary .get ('completedDate' )),
845- diary .get ('completedItemIds ' , []),
914+ diary .get ('retainedItemIds ' , []),
846915 )
847916
848- for diary in diaries [ 'tiers' ][ 'medium' ][ 'completedTasks' ] :
917+ for diary in existing_root_completed :
849918 if diary ['id' ] in medium_diaries :
850919 __set_task_complete (
851920 username ,
852921 'mediumTasks' ,
853922 diary ['id' ],
854923 True ,
855924 __datetime_to_iso (diary .get ('completedDate' )),
856- diary .get ('completedItemIds ' , []),
925+ diary .get ('retainedItemIds ' , []),
857926 )
858927
859- for diary in diaries [ 'tiers' ][ 'hard' ][ 'completedTasks' ] :
928+ for diary in existing_root_completed :
860929 if diary ['id' ] in hard_diaries :
861930 __set_task_complete (
862931 username ,
863932 'hardTasks' ,
864933 diary ['id' ],
865934 True ,
866935 __datetime_to_iso (diary .get ('completedDate' )),
867- diary .get ('completedItemIds ' , []),
936+ diary .get ('retainedItemIds ' , []),
868937 )
869938
870- for diary in diaries [ 'tiers' ][ 'elite' ][ 'completedTasks' ] :
939+ for diary in existing_root_completed :
871940 if diary ['id' ] in elite_diaries :
872941 __set_task_complete (
873942 username ,
874943 'eliteTasks' ,
875944 diary ['id' ],
876945 True ,
877946 __datetime_to_iso (diary .get ('completedDate' )),
878- diary .get ('completedItemIds ' , []),
947+ diary .get ('retainedItemIds ' , []),
879948 )
880949
881950
0 commit comments