@@ -58,6 +58,7 @@ def __init__(self, database_path: str):
5858
5959 # Migrate existing tables: add new columns if missing
6060 self ._migrate_trusted_users ()
61+ self ._migrate_user_warnings ()
6162
6263 def _migrate_trusted_users (self ) -> None :
6364 """Add new columns to trusted_users if missing."""
@@ -80,7 +81,24 @@ def _migrate_trusted_users(self) -> None:
8081 logger .info (f"Migrated trusted_users: added { col } column" )
8182 conn .commit ()
8283
83- def get_or_create_user_warning (self , user_id : int , group_id : int ) -> UserWarning :
84+ def _migrate_user_warnings (self ) -> None :
85+ """Add warning_kind column to user_warnings if missing."""
86+ with self ._engine .connect () as conn :
87+ columns = {
88+ row [1 ] for row in conn .exec_driver_sql (
89+ "PRAGMA table_info(user_warnings)"
90+ ).fetchall ()
91+ }
92+ if "warning_kind" not in columns :
93+ conn .exec_driver_sql (
94+ "ALTER TABLE user_warnings ADD COLUMN warning_kind TEXT DEFAULT 'profile'"
95+ )
96+ logger .info ("Migrated user_warnings: added warning_kind column" )
97+ conn .commit ()
98+
99+ def get_or_create_user_warning (
100+ self , user_id : int , group_id : int , warning_kind : str = "profile"
101+ ) -> UserWarning :
84102 """
85103 Get existing warning record or create a new one.
86104
@@ -90,6 +108,7 @@ def get_or_create_user_warning(self, user_id: int, group_id: int) -> UserWarning
90108 Args:
91109 user_id: Telegram user ID.
92110 group_id: Telegram group ID.
111+ warning_kind: Discriminator for the warning source.
93112
94113 Returns:
95114 UserWarning: Active warning record for the user.
@@ -99,13 +118,14 @@ def get_or_create_user_warning(self, user_id: int, group_id: int) -> UserWarning
99118 statement = select (UserWarning ).where (
100119 UserWarning .user_id == user_id ,
101120 UserWarning .group_id == group_id ,
121+ UserWarning .warning_kind == warning_kind ,
102122 ~ UserWarning .is_restricted ,
103123 )
104124 record = session .exec (statement ).first ()
105125
106126 if record :
107127 logger .info (
108- f"Returning existing warning for user_id={ user_id } , group_id={ group_id } "
128+ f"Returning existing warning for user_id={ user_id } , group_id={ group_id } , kind= { warning_kind } "
109129 )
110130 return record
111131
@@ -116,16 +136,19 @@ def get_or_create_user_warning(self, user_id: int, group_id: int) -> UserWarning
116136 message_count = 1 ,
117137 first_warned_at = datetime .now (UTC ),
118138 last_message_at = datetime .now (UTC ),
139+ warning_kind = warning_kind ,
119140 )
120141 session .add (new_record )
121142 session .commit ()
122143 session .refresh (new_record )
123144 logger .info (
124- f"Created new warning for user_id={ user_id } , group_id={ group_id } "
145+ f"Created new warning for user_id={ user_id } , group_id={ group_id } , kind= { warning_kind } "
125146 )
126147 return new_record
127148
128- def increment_message_count (self , user_id : int , group_id : int ) -> UserWarning :
149+ def increment_message_count (
150+ self , user_id : int , group_id : int , warning_kind : str = "profile"
151+ ) -> UserWarning :
129152 """
130153 Increment message count for an existing warning record.
131154
@@ -135,6 +158,7 @@ def increment_message_count(self, user_id: int, group_id: int) -> UserWarning:
135158 Args:
136159 user_id: Telegram user ID.
137160 group_id: Telegram group ID.
161+ warning_kind: Discriminator for the warning source.
138162
139163 Returns:
140164 UserWarning: Updated warning record.
@@ -146,6 +170,7 @@ def increment_message_count(self, user_id: int, group_id: int) -> UserWarning:
146170 statement = select (UserWarning ).where (
147171 UserWarning .user_id == user_id ,
148172 UserWarning .group_id == group_id ,
173+ UserWarning .warning_kind == warning_kind ,
149174 ~ UserWarning .is_restricted ,
150175 )
151176 record = session .exec (statement ).first ()
@@ -157,15 +182,17 @@ def increment_message_count(self, user_id: int, group_id: int) -> UserWarning:
157182 session .commit ()
158183 session .refresh (record )
159184 logger .info (
160- f"Incremented message count for user_id={ user_id } , group_id={ group_id } , new_count={ record .message_count } "
185+ f"Incremented message count for user_id={ user_id } , group_id={ group_id } , kind= { warning_kind } , new_count={ record .message_count } "
161186 )
162187 return record
163188
164189 raise ValueError (
165- f"No warning record found for user { user_id } in group { group_id } "
190+ f"No warning record found for user { user_id } in group { group_id } (kind= { warning_kind } ) "
166191 )
167192
168- def mark_user_restricted (self , user_id : int , group_id : int ) -> UserWarning :
193+ def mark_user_restricted (
194+ self , user_id : int , group_id : int , warning_kind : str = "profile"
195+ ) -> UserWarning :
169196 """
170197 Mark user as restricted after reaching threshold.
171198
@@ -175,6 +202,7 @@ def mark_user_restricted(self, user_id: int, group_id: int) -> UserWarning:
175202 Args:
176203 user_id: Telegram user ID.
177204 group_id: Telegram group ID.
205+ warning_kind: Discriminator for the warning source.
178206
179207 Returns:
180208 UserWarning: Updated warning record.
@@ -186,6 +214,7 @@ def mark_user_restricted(self, user_id: int, group_id: int) -> UserWarning:
186214 statement = select (UserWarning ).where (
187215 UserWarning .user_id == user_id ,
188216 UserWarning .group_id == group_id ,
217+ UserWarning .warning_kind == warning_kind ,
189218 ~ UserWarning .is_restricted ,
190219 )
191220 record = session .exec (statement ).first ()
@@ -198,15 +227,17 @@ def mark_user_restricted(self, user_id: int, group_id: int) -> UserWarning:
198227 session .commit ()
199228 session .refresh (record )
200229 logger .info (
201- f"Marked user as restricted: user_id={ user_id } , group_id={ group_id } "
230+ f"Marked user as restricted: user_id={ user_id } , group_id={ group_id } , kind= { warning_kind } "
202231 )
203232 return record
204233
205234 raise ValueError (
206- f"No warning record found for user { user_id } in group { group_id } "
235+ f"No warning record found for user { user_id } in group { group_id } (kind= { warning_kind } ) "
207236 )
208237
209- def is_user_restricted_by_bot (self , user_id : int , group_id : int ) -> bool :
238+ def is_user_restricted_by_bot (
239+ self , user_id : int , group_id : int , warning_kind : str = "profile"
240+ ) -> bool :
210241 """
211242 Check if user was restricted by this bot.
212243
@@ -217,6 +248,7 @@ def is_user_restricted_by_bot(self, user_id: int, group_id: int) -> bool:
217248 Args:
218249 user_id: Telegram user ID.
219250 group_id: Telegram group ID.
251+ warning_kind: Discriminator for the warning source.
220252
221253 Returns:
222254 bool: True if user was restricted by this bot.
@@ -225,13 +257,16 @@ def is_user_restricted_by_bot(self, user_id: int, group_id: int) -> bool:
225257 statement = select (UserWarning ).where (
226258 UserWarning .user_id == user_id ,
227259 UserWarning .group_id == group_id ,
260+ UserWarning .warning_kind == warning_kind ,
228261 UserWarning .is_restricted ,
229262 UserWarning .restricted_by_bot ,
230263 )
231264 record = session .exec (statement ).first ()
232265 return record is not None
233266
234- def mark_user_unrestricted (self , user_id : int , group_id : int ) -> None :
267+ def mark_user_unrestricted (
268+ self , user_id : int , group_id : int , warning_kind : str = "profile"
269+ ) -> None :
235270 """
236271 Clear bot restriction flag after user is unrestricted via DM.
237272
@@ -241,11 +276,13 @@ def mark_user_unrestricted(self, user_id: int, group_id: int) -> None:
241276 Args:
242277 user_id: Telegram user ID.
243278 group_id: Telegram group ID.
279+ warning_kind: Discriminator for the warning source.
244280 """
245281 with Session (self ._engine ) as session :
246282 statement = select (UserWarning ).where (
247283 UserWarning .user_id == user_id ,
248284 UserWarning .group_id == group_id ,
285+ UserWarning .warning_kind == warning_kind ,
249286 UserWarning .is_restricted ,
250287 UserWarning .restricted_by_bot ,
251288 )
@@ -256,10 +293,12 @@ def mark_user_unrestricted(self, user_id: int, group_id: int) -> None:
256293 session .add (record )
257294 session .commit ()
258295 logger .info (
259- f"Cleared restriction flag: user_id={ user_id } , group_id={ group_id } "
296+ f"Cleared restriction flag: user_id={ user_id } , group_id={ group_id } , kind= { warning_kind } "
260297 )
261298
262- def delete_user_warnings (self , user_id : int , group_id : int ) -> int :
299+ def delete_user_warnings (
300+ self , user_id : int , group_id : int , warning_kind : str = "profile"
301+ ) -> int :
263302 """
264303 Delete all warning records for a user in a specific group.
265304
@@ -269,6 +308,7 @@ def delete_user_warnings(self, user_id: int, group_id: int) -> int:
269308 Args:
270309 user_id: Telegram user ID.
271310 group_id: Telegram group ID.
311+ warning_kind: Discriminator for the warning source.
272312
273313 Returns:
274314 int: Number of warning records deleted.
@@ -277,16 +317,19 @@ def delete_user_warnings(self, user_id: int, group_id: int) -> int:
277317 delete_statement = delete (UserWarning ).where (
278318 UserWarning .user_id == user_id ,
279319 UserWarning .group_id == group_id ,
320+ UserWarning .warning_kind == warning_kind ,
280321 )
281322 result = session .exec (delete_statement )
282323 session .commit ()
283324 count = result .rowcount
284325 logger .info (
285- f"Deleted warnings: user_id={ user_id } , group_id={ group_id } , count={ count } "
326+ f"Deleted warnings: user_id={ user_id } , group_id={ group_id } , kind= { warning_kind } , count={ count } "
286327 )
287328 return count
288329
289- def get_active_user_warning (self , user_id : int , group_id : int ) -> UserWarning | None :
330+ def get_active_user_warning (
331+ self , user_id : int , group_id : int , warning_kind : str = "profile"
332+ ) -> UserWarning | None :
290333 """
291334 Get an existing active (non-restricted) warning record without creating one.
292335
@@ -297,6 +340,7 @@ def get_active_user_warning(self, user_id: int, group_id: int) -> UserWarning |
297340 Args:
298341 user_id: Telegram user ID.
299342 group_id: Telegram group ID.
343+ warning_kind: Discriminator for the warning source.
300344
301345 Returns:
302346 UserWarning | None: Active warning record, or None if none exists.
@@ -305,6 +349,7 @@ def get_active_user_warning(self, user_id: int, group_id: int) -> UserWarning |
305349 statement = select (UserWarning ).where (
306350 UserWarning .user_id == user_id ,
307351 UserWarning .group_id == group_id ,
352+ UserWarning .warning_kind == warning_kind ,
308353 ~ UserWarning .is_restricted ,
309354 )
310355 return session .exec (statement ).first ()
@@ -540,14 +585,15 @@ def get_trusted_users(self) -> list[TrustedUser]:
540585 return list (session .exec (statement ).all ())
541586
542587 def get_warnings_past_time_threshold_for_group (
543- self , group_id : int , threshold : timedelta
588+ self , group_id : int , threshold : timedelta , warning_kind : str = "profile"
544589 ) -> list [UserWarning ]:
545590 """
546591 Find active warnings for a specific group that exceeded the time threshold.
547592
548593 Args:
549594 group_id: Telegram group ID to filter by.
550595 threshold: Time duration since first warning to trigger restriction.
596+ warning_kind: Discriminator for the warning source.
551597
552598 Returns:
553599 list[UserWarning]: Warning records that should be auto-restricted.
@@ -556,6 +602,7 @@ def get_warnings_past_time_threshold_for_group(
556602 cutoff_time = datetime .now (UTC ) - threshold
557603 statement = select (UserWarning ).where (
558604 UserWarning .group_id == group_id ,
605+ UserWarning .warning_kind == warning_kind ,
559606 ~ UserWarning .is_restricted ,
560607 UserWarning .first_warned_at <= cutoff_time ,
561608 )
0 commit comments