adamshafishaik commited on
Commit
dbfb079
·
1 Parent(s): a918a86

fix: article validation failing for Pydantic models

Browse files

- Update is_valid_article to check both camelCase (API) and snake_case (Model) fields
- Fix normalize_article_date to support published_at
- Ensure image_url is preserved during sanitization

app/utils/data_validation.py CHANGED
@@ -65,15 +65,18 @@ def is_valid_article(article: Union[Dict, 'Article']) -> bool:
65
  return False
66
 
67
  # Required: Published date
68
- if not article_dict.get('publishedAt'):
69
  return False
70
 
71
  # Optional but validate if present: Image URL
72
- if article_dict.get('image'):
73
- image_url = article_dict['image'].strip()
74
- if image_url and not image_url.startswith(('http://', 'https://')):
75
- # Invalid image URL - set to None
76
- article_dict['image'] = None
 
 
 
77
 
78
  return True
79
 
@@ -112,10 +115,12 @@ def sanitize_article(article: Union[Dict, 'Article']) -> Dict:
112
  description = re.sub(r'\s+', ' ', description)
113
  description = description[:2000]
114
 
115
- # Clean image URL
116
- image_url = article_dict.get('image', '').strip() if article_dict.get('image') else None
 
 
117
  if image_url:
118
- image_url = image_url[:1000]
119
  if not image_url.startswith(('http://', 'https://')):
120
  image_url = None
121
 
@@ -130,16 +135,32 @@ def sanitize_article(article: Union[Dict, 'Article']) -> Dict:
130
  quality_score = calculate_quality_score(article_dict)
131
 
132
  # Handle publishedAt (convert datetime to ISO string if needed)
133
- published_at = article_dict.get('publishedAt')
 
 
134
  if isinstance(published_at, datetime):
135
  published_at = published_at.isoformat()
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  return {
138
  'title': title,
139
  'url': url,
140
  'description': description or '',
141
- 'image': image_url,
142
- 'publishedAt': published_at,
 
 
143
  'source': source,
144
  'category': article_dict.get('category', '').strip()[:100],
145
  'slug': slug,
 
65
  return False
66
 
67
  # Required: Published date
68
+ if not (article_dict.get('publishedAt') or article_dict.get('published_at')):
69
  return False
70
 
71
  # Optional but validate if present: Image URL
72
+ # Handle both 'image' (raw API) and 'image_url' (Pydantic/DB)
73
+ image_url = article_dict.get('image') or article_dict.get('image_url')
74
+ if image_url:
75
+ image_url = str(image_url).strip()
76
+ if not image_url.startswith(('http://', 'https://')):
77
+ # Invalid image URL - remove both keys to be safe
78
+ if 'image' in article_dict: article_dict['image'] = None
79
+ if 'image_url' in article_dict: article_dict['image_url'] = None
80
 
81
  return True
82
 
 
115
  description = re.sub(r'\s+', ' ', description)
116
  description = description[:2000]
117
 
118
+ # Clean image URL - Support both keys
119
+ raw_image = article_dict.get('image') or article_dict.get('image_url')
120
+ image_url = str(raw_image).strip() if raw_image else None
121
+
122
  if image_url:
123
+ image_url = image_url[:2048] # Increased to match DB schema (was 1000)
124
  if not image_url.startswith(('http://', 'https://')):
125
  image_url = None
126
 
 
135
  quality_score = calculate_quality_score(article_dict)
136
 
137
  # Handle publishedAt (convert datetime to ISO string if needed)
138
+ # Check both keys
139
+ published_at = article_dict.get('publishedAt') or article_dict.get('published_at')
140
+
141
  if isinstance(published_at, datetime):
142
  published_at = published_at.isoformat()
143
+ elif not published_at:
144
+ # Fallback to current time if missing
145
+ published_at = datetime.now().isoformat()
146
+
147
+ # Return standardized dict (using camelCase for legacy compatibility or standardized snake_case?)
148
+ # The AppwriteDatabase understands both, checking 'published_at' OR 'publishedAt'.
149
+ # But usually it's best to standardize on what the DB considers 'canonical'.
150
+ # However, this function `sanitize_article` returns a dict that replaces the original object.
151
+ # We should probably return both or standardize on snake_case?
152
+ # Existing code returned 'publishedAt', 'image'.
153
+ # Let's keep returning 'publishedAt' for backward compat with whatever else uses this,
154
+ # BUT explicitly set the values we found.
155
 
156
  return {
157
  'title': title,
158
  'url': url,
159
  'description': description or '',
160
+ 'image': image_url, # Legacy key
161
+ 'image_url': image_url, # Modern key
162
+ 'publishedAt': published_at, # Legacy key
163
+ 'published_at': published_at, # Modern key
164
  'source': source,
165
  'category': article_dict.get('category', '').strip()[:100],
166
  'slug': slug,
app/utils/date_parser.py CHANGED
@@ -74,19 +74,25 @@ def normalize_article_date(article):
74
  article_dict = dict(article)
75
 
76
  # Normalize the date
77
- if 'publishedAt' in article_dict:
78
- published_at = article_dict['publishedAt']
 
 
79
  # Handle datetime objects
80
  if isinstance(published_at, datetime):
81
- article_dict['publishedAt'] = published_at.astimezone(timezone.utc).isoformat().replace('+00:00', 'Z')
82
  elif isinstance(published_at, str):
83
- article_dict['publishedAt'] = parse_date_to_iso(published_at)
84
  else:
85
  # Unknown type, use current time
86
- article_dict['publishedAt'] = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z')
87
  else:
88
  # If missing, use current time
89
- article_dict['publishedAt'] = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z')
 
 
 
 
90
 
91
  return article_dict
92
 
 
74
  article_dict = dict(article)
75
 
76
  # Normalize the date
77
+ # Check both keys
78
+ published_at = article_dict.get('publishedAt') or article_dict.get('published_at')
79
+
80
+ if published_at:
81
  # Handle datetime objects
82
  if isinstance(published_at, datetime):
83
+ iso_date = published_at.astimezone(timezone.utc).isoformat().replace('+00:00', 'Z')
84
  elif isinstance(published_at, str):
85
+ iso_date = parse_date_to_iso(published_at)
86
  else:
87
  # Unknown type, use current time
88
+ iso_date = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z')
89
  else:
90
  # If missing, use current time
91
+ iso_date = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z')
92
+
93
+ # Set both keys to ensure compatibility
94
+ article_dict['publishedAt'] = iso_date
95
+ article_dict['published_at'] = iso_date
96
 
97
  return article_dict
98