Skip to content

Commit 51ec507

Browse files
taimoor-ahmed-1Taimoor  Ahmed
andauthored
fix: Log missing content mapping in mongo2mysql cmd (#220)
The Mongo→MySQL migration could crash when a MongoContent mapping was missing, e.g.: forum.backends.mysql.models.MongoContent.DoesNotExist at create_or_update_comment This change makes the migration resilient by logging the relevant IDs and continuing. create_or_update_comment: catch missing thread/parent mappings and missing target objects; log and return create_or_update_edit_history: guard missing mapping/target objects; log and return create_or_update_abuse_flaggers: guard missing mapping/target objects; log and return migrate_subscriptions: guard missing mapping/target objects; log and continue close: #211 Co-authored-by: Taimoor Ahmed <taimoor.ahmed@A006-01711.local>
1 parent 9e32834 commit 51ec507

File tree

1 file changed

+76
-9
lines changed

1 file changed

+76
-9
lines changed

forum/migration_helpers.py

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Migration commands helper methods."""
22

33
from typing import Any
4+
import logging
45

56
from django.contrib.auth.models import User # pylint: disable=E5142
67
from django.core.management.base import OutputWrapper
@@ -25,6 +26,9 @@
2526
from forum.utils import make_aware, get_trunc_title
2627

2728

29+
logger = logging.getLogger(__name__)
30+
31+
2832
def get_user_or_none(user_id: Any) -> User | None:
2933
"""Get a user by ID or return None if not found."""
3034
try:
@@ -125,15 +129,39 @@ def create_or_update_comment(comment_data: dict[str, Any]) -> None:
125129
if not author:
126130
return
127131
mongo_thread_id = str(comment_data["comment_thread_id"])
128-
mongo_thread = MongoContent.objects.get(mongo_id=mongo_thread_id)
129-
thread = CommentThread.objects.get(pk=mongo_thread.content_object_id)
132+
mongo_thread = MongoContent.objects.filter(mongo_id=mongo_thread_id).first()
133+
if not mongo_thread:
134+
logger.warning(
135+
f"Thread mapping not found for comment {comment_data.get('_id')} "
136+
f"(mongo_thread_id={mongo_thread_id})"
137+
)
138+
return
139+
thread = CommentThread.objects.filter(pk=mongo_thread.content_object_id).first()
140+
if not thread:
141+
logger.warning(
142+
f"Skipping comment {comment_data.get('_id')}: thread object not found "
143+
f"(content_object_id={mongo_thread.content_object_id})"
144+
)
145+
return
130146
parent = None
131147
if "parent_id" in comment_data and comment_data["parent_id"] != "None":
132148
parent_id = str(comment_data["parent_id"])
133-
mongo_parent_comment = MongoContent.objects.get(mongo_id=parent_id)
149+
mongo_parent_comment = MongoContent.objects.filter(mongo_id=parent_id).first()
150+
if not mongo_parent_comment:
151+
logger.warning(
152+
f"Parent mapping not found for comment {comment_data.get('_id')} "
153+
f"(parent_id={parent_id})"
154+
)
155+
return
134156
parent = Comment.objects.filter(
135157
id=mongo_parent_comment.content_object_id
136158
).first()
159+
if not parent:
160+
logger.warning(
161+
f"Skipping comment {comment_data.get('_id')}: parent object not found "
162+
f"(parent_content_object_id={mongo_parent_comment.content_object_id})"
163+
)
164+
return
137165

138166
mongo_comment, _ = MongoContent.objects.get_or_create(
139167
mongo_id=str(comment_data["_id"])
@@ -186,8 +214,21 @@ def create_or_update_edit_history(content: dict[str, Any]) -> None:
186214
"""Create or update edit history for a content."""
187215
edit_history = content.get("edit_history", [])
188216
content_type = CommentThread if content["_type"] == "CommentThread" else Comment
189-
mongo_content = MongoContent.objects.get(mongo_id=str(content["_id"]))
190-
content_object = content_type.objects.get(pk=mongo_content.content_object_id)
217+
mongo_content = MongoContent.objects.filter(mongo_id=str(content["_id"])).first()
218+
if not mongo_content:
219+
logger.warning(
220+
f"Skipping edit history for content {content.get('_id')}: mapping not found"
221+
)
222+
return
223+
content_object = content_type.objects.filter(
224+
pk=mongo_content.content_object_id
225+
).first()
226+
if not content_object:
227+
logger.warning(
228+
f"Skipping edit history for content {content.get('_id')}: target object not found "
229+
f"(content_object_id={mongo_content.content_object_id})"
230+
)
231+
return
191232
for edit in edit_history:
192233
editor = get_user_or_none(edit["author_id"])
193234
if not editor:
@@ -207,8 +248,21 @@ def create_or_update_edit_history(content: dict[str, Any]) -> None:
207248
def create_or_update_abuse_flaggers(content: dict[str, Any]) -> None:
208249
"""Create or update abuse flaggers for content."""
209250
content_type = CommentThread if content["_type"] == "CommentThread" else Comment
210-
mongo_content = MongoContent.objects.get(mongo_id=str(content["_id"]))
211-
content_object = content_type.objects.get(pk=mongo_content.content_object_id)
251+
mongo_content = MongoContent.objects.filter(mongo_id=str(content["_id"])).first()
252+
if not mongo_content:
253+
logger.warning(
254+
f"Skipping abuse flaggers for content {content.get('_id')}: mapping not found"
255+
)
256+
return
257+
content_object = content_type.objects.filter(
258+
pk=mongo_content.content_object_id
259+
).first()
260+
if not content_object:
261+
logger.warning(
262+
f"Skipping abuse flaggers for content {content.get('_id')}: target object not found "
263+
f"(content_object_id={mongo_content.content_object_id})"
264+
)
265+
return
212266
for user_id in content["abuse_flaggers"]:
213267
user = get_user_or_none(user_id)
214268
if not user:
@@ -245,8 +299,21 @@ def migrate_subscriptions(db: Database[dict[str, Any]], content_id: str) -> None
245299
content_type = (
246300
CommentThread if sub["source_type"] == "CommentThread" else Comment
247301
)
248-
mongo_content = MongoContent.objects.get(mongo_id=str(content_id))
249-
content = content_type.objects.get(pk=mongo_content.content_object_id)
302+
mongo_content = MongoContent.objects.filter(mongo_id=str(content_id)).first()
303+
if not mongo_content:
304+
logger.warning(
305+
f"Skipping subscription for source {content_id}: mapping not found"
306+
)
307+
continue
308+
content = content_type.objects.filter(
309+
pk=mongo_content.content_object_id
310+
).first()
311+
if not content:
312+
logger.warning(
313+
f"Skipping subscription for source {content_id}: target object not found "
314+
f"(content_object_id={mongo_content.content_object_id})"
315+
)
316+
continue
250317
if content:
251318
Subscription.objects.update_or_create(
252319
subscriber=user,

0 commit comments

Comments
 (0)