33from pymongo import MongoClient
44from pymongo .database import Database
55from pymongo .collection import Collection
6- from typing import Any , Dict , List , Optional
76from pymongo .errors import ConnectionFailure
7+ from typing import Any , Dict , List , Optional , Tuple
88
99
1010class NoticeDB :
@@ -87,21 +87,46 @@ def delete_successful_ntfy_subscribers(self, notice_uid: str) -> None:
8787
8888 # Update the document to set the subscribers list to an empty list
8989 collection .delete_one ({"uid" : uid })
90-
91- def find_new_notices (self , uid_list : List [str ]) -> List [str ]:
92- """Find and return the list of UIDs that have not been sent."""
93- # Query for UIDs that exist in the database
94- query = {"UID" : {"$in" : uid_list }}
95- sent_notices = self .__find_many (query , {"UID" : 1 })
96-
97- # Extract UIDs that are already sent
98- sent_uids = set ()
99- if sent_notices :
100- sent_uids = {notice ["UID" ] for notice in sent_notices }
101-
102- # Return UIDs that are not sent
103- return [uid for uid in uid_list if uid not in sent_uids ]
10490
91+ def find_to_send_notices (self , latest_X_notices : List [Dict [str , str ]]) -> Tuple [List [Dict [str , str ]], List [Dict [str , str ]]]:
92+ """Find new and modified notices compared to existing records in the database."""
93+ # Check if latest_X_notices is empty
94+ if not latest_X_notices :
95+ return [], []
96+
97+ # Prepare a query to match all notices
98+ latest_X_uids = [notice ['UID' ] for notice in latest_X_notices ]
99+ query = {"UID" : {"$in" : latest_X_uids }}
100+
101+ # Find all existing notices that match any of the criteria
102+ existing_notices = self .__find_many (query )
103+ if not existing_notices :
104+ return latest_X_notices , []
105+
106+ # Create a mapping of existing notices by UID
107+ existing_notices_map = {notice ['UID' ]: notice for notice in existing_notices }
108+
109+ new_notices , modified_notices = [], []
110+ for latest_notice in latest_X_notices :
111+ uid = latest_notice .get ('UID' )
112+
113+ if uid not in existing_notices_map :
114+ # New notice
115+ new_notices .append (latest_notice )
116+ else :
117+ # Check if the notice is modified
118+ existing_notice = existing_notices_map [uid ]
119+ is_modified = any (
120+ existing_notice .get (key ) != value
121+ for key , value in latest_notice .items ()
122+ if key != 'BodyData'
123+ )
124+
125+ if is_modified :
126+ modified_notices .append (latest_notice )
127+
128+ return new_notices , modified_notices
129+
105130 def save_notice (self , document : Dict ) -> str :
106131 return self .__insert_one (document )
107132
@@ -115,8 +140,17 @@ def __get_collection(self) -> Collection:
115140 def __insert_one (self , document : Dict ) -> str :
116141 """Insert single document and return inserted ID."""
117142 collection = self .__get_collection ()
118- result = collection .insert_one (document )
119- return str (result .inserted_id )
143+
144+ uid = document .get ('UID' )
145+ # Use replace_one with upsert=True to overwrite or insert
146+ result = collection .replace_one (
147+ {"UID" : uid }, # Match criteria
148+ document , # New document to replace with
149+ upsert = True # Insert if not exists
150+ )
151+
152+ # Return the ID of the document
153+ return str (result .upserted_id if result .upserted_id else uid )
120154
121155 # Read operations
122156 def __find_many (self , query : Optional [Dict ] = None , projection : Optional [Dict ] = None ) -> Optional [List ]:
0 commit comments