@@ -127,8 +127,10 @@ async def validation_exception_handler(request, exc):
127127
128128@app .get (
129129 '/search' ,
130- response_model = SearchGetResponse ,
131- responses = {'500' : {'model' : ErrorResponse }},
130+ response_model = None ,
131+ responses = {
132+ '200' : {'model' : SearchGetResponse },
133+ '500' : {'model' : ErrorResponse }},
132134)
133135async def get_search (
134136 # Used in for full text search
@@ -153,86 +155,94 @@ async def get_search(
153155 """
154156 search listings
155157 """
156- price_order = 0
157158 limit = min (max (limit , 1 ), 30 )
158- try :
159- if query :
160- # Full text search
161- search_stage = {
162- "$search" : {
163- "index" : "Full_text_index_listings" ,
164- "text" : {
165- "query" : query ,
166- "path" : {
167- "wildcard" : "*" ,
168- },
159+
160+ # Selecting which order to sort by
161+ # Default to most recent first
162+ sort_field = {"date_posted" : - 1 }
163+ if price_type == "price-high-to-low" :
164+ sort_field = {"price" : - 1 }
165+ elif price_type == "price-low-to-high" :
166+ sort_field = {"price" : 1 }
167+ elif price_type == "date-recent" :
168+ sort_field = {"date_posted" : - 1 }
169+
170+ if query :
171+ # Full text search
172+ search_stage = {
173+ "$search" : {
174+ "index" : "full_text_index_listings_11APR2025" ,
175+ "text" : {
176+ "query" : query ,
177+ "path" : {
178+ "wildcard" : "*" ,
169179 },
180+ "fuzzy" : {
181+ "maxEdits" : 2 ,
182+ "prefixLength" : 0 ,
183+ "maxExpansions" : 50
184+ }
170185 },
171- }
172- else :
173- search_stage = {"$search" : {
174- "index" : "Full_text_index_listings" ,
186+ "sort" : sort_field ,
187+ },
188+ }
189+ else :
190+ search_stage = {
191+ "$search" : {
192+ "index" : "full_text_index_listings_11APR2025" ,
175193 # This is always true; essentially just gets all documents
176194 "exists" : {"path" : "_id" },
177- }}
178-
179- if next :
180- search_stage ["$search" ]["searchAfter" ] = next
195+ "sort" : sort_field ,
196+ },
197+ }
181198
182- # Selecting which order to sort by
183- # Default to most recent first
184- sort_stage = {"$sort" : {"date_posted" : - 1 }}
185- if price_type == "price-high-to-low" :
186- sort_stage = {"$sort" : {"price" : - 1 }}
187- elif price_type == "price-low-to-high" :
188- sort_stage = {"$sort" : {"price" : 1 }}
189- elif price_type == "date-recent" :
190- sort_stage = {"$sort" : {"date_posted" : - 1 }}
199+ if next :
200+ search_stage ["$search" ]["searchAfter" ] = next
191201
192- pipeline = [
193- search_stage ,
194- # Price filter with stable sort using _id as tiebreaker
195- {"$sort" : {"price" : price_order , "_id" : 1 }
196- } if price_order in [- 1 , 1 ] else {"$sort" : {"_id" : 1 }},
197- # Lower and upper limits of price (0 -> +inf by default)
198- {
199- "$match" : {
200- "price" : {"$gte" : lower_price , "$lte" : upper_price }}} if price_type is not None else None ,
201- # Condition filter
202- {
203- "$match" : {
204- "condition" : condition }} if condition else None ,
205- # Date filter
206- {
207- "$match" : {
208- "date_posted" : {"$gte" : dateutil_parse (date_range ).isoformat ()}}}
209- if date_range is not None else None ,
210- {
211- "$match" : {
212- "campus" : campus }} if campus else None ,
213- {"$limit" : limit },
214- {"$project" : {
215- "id" : {"$toString" : "$_id" },
216- "title" : 1 ,
217- "price" : 1 ,
218- "description" : 1 ,
219- "seller_id" : 1 ,
220- "pictures" : 1 ,
221- "condition" : 1 ,
222- "category" : 1 ,
223- "date_posted" : 1 ,
224- "campus" : 1 ,
225- # Provide pagination tokens generated by Atlas Search
226- # so that clients can provide this on next query
227- "paginationToken" : {"$meta" : "searchSequenceToken" },
228- }}
229- ]
202+ pipeline = [
203+ search_stage ,
204+ # Lower and upper limits of price (0 -> +inf by default)
205+ {
206+ "$match" : {
207+ "price" : {"$gte" : lower_price , "$lte" : upper_price }}} if price_type is not None else None ,
208+ # Condition filter
209+ {
210+ "$match" : {
211+ "condition" : condition }} if condition else None ,
212+ # Date filter
213+ {
214+ "$match" : {
215+ "date_posted" : {"$gte" : dateutil_parse (date_range ).isoformat ()}}}
216+ if date_range is not None else None ,
217+ # Campus filter
218+ {
219+ "$match" : {
220+ "campus" : campus }} if campus else None ,
221+ {"$limit" : limit },
222+ {"$project" : {
223+ "id" : {"$toString" : "$_id" },
224+ "title" : 1 ,
225+ "price" : 1 ,
226+ "description" : 1 ,
227+ "seller_id" : 1 ,
228+ "pictures" : 1 ,
229+ "condition" : 1 ,
230+ "category" : 1 ,
231+ "date_posted" : 1 ,
232+ "campus" : 1 ,
233+ # Provide pagination tokens generated by Atlas Search
234+ # so that clients can provide this on next query
235+ "paginationToken" : {"$meta" : "searchSequenceToken" },
236+ }}
237+ ]
238+
239+ # Clean the pipeline of any None values
240+ pipeline = [stage for stage in pipeline if stage is not None ]
230241
231- # Clean the pipeline of any None values
232- pipeline = [stage for stage in pipeline if stage is not None ]
242+ try :
233243
234244 cursor = listings_collection .aggregate (pipeline )
235- listings = await cursor .to_list (length = limit )
245+ listings = await cursor .to_list ()
236246
237247 # Prepping to return
238248 response_data = [
@@ -251,17 +261,19 @@ async def get_search(
251261 for listing in listings
252262 ]
253263
264+ print ([(listing ["_id" ], listing ["price" ]) for listing in listings ])
265+
254266 if not response_data :
255267 return SearchGetResponse (listings = [],
256268 total = 0 ,
257- next_page_token = None )
269+ next_page_token = "" )
258270
259271 listings = ListingsGetResponseAll (
260272 listings = response_data ,
261273 total = len (response_data ),
262274 next_page_token = listings [- 1 ].get ("paginationToken" )
263275 )
264-
276+ print ( f"Next page token: { listings . next_page_token } " )
265277 return SearchGetResponse (listings = listings .listings ,
266278 total = listings .total ,
267279 next_page_token = listings .next_page_token )
@@ -327,6 +339,7 @@ async def get_listing(listing_id: str) -> Union[ListingGetResponseItem, ErrorRes
327339 "campus" : 1 ,
328340 "date_posted" : 1 ,
329341 "seller_name" : "$seller_doc.display_name" ,
342+ "seller_email" : "$seller_doc.email" ,
330343 }
331344 }
332345 ]
@@ -346,6 +359,7 @@ async def get_listing(listing_id: str) -> Union[ListingGetResponseItem, ErrorRes
346359 description = listing .get ("description" ),
347360 seller_id = listing .get ("seller_id" ),
348361 seller_name = listing .get ("seller_name" , "" ),
362+ seller_email = listing .get ("seller_email" , "" ),
349363 pictures = listing .get ("pictures" , []),
350364 category = listing .get ("category" ),
351365 condition = listing .get ("condition" ),
@@ -358,8 +372,10 @@ async def get_listing(listing_id: str) -> Union[ListingGetResponseItem, ErrorRes
358372
359373
360374@app .get ('/listings' ,
361- response_model = ListingsGetResponseAll ,
362- responses = {'500' : {'model' : ErrorResponse }},
375+ response_model = None ,
376+ responses = {
377+ '200' : {'model' : ListingsGetResponseAll },
378+ '500' : {'model' : ErrorResponse }},
363379 )
364380async def get_listings (
365381 query : Optional [str ] = Query (None , description = "query" ),
@@ -378,7 +394,7 @@ async def get_listings(
378394 print ("GOT Query" , query )
379395 search_stage = {
380396 "$search" : {
381- "index" : "Full_text_index_listings " ,
397+ "index" : "full_text_index_listings_11APR2025 " ,
382398 "text" : {
383399 "query" : query ,
384400 "path" : {
@@ -391,7 +407,7 @@ async def get_listings(
391407 print ("NO QUERY" )
392408 search_stage = {
393409 "$search" : {
394- "index" : "Full_text_index_listings " ,
410+ "index" : "full_text_index_listings_11APR2025 " ,
395411 # This is always true; essentially just gets all documents
396412 "exists" : {"path" : "_id" },
397413 }
@@ -426,7 +442,7 @@ async def get_listings(
426442 listings = await cursor .to_list (length = limit )
427443
428444 if not listings :
429- return ListingsGetResponseAll (listings = [], total = 0 , next_page_token = None )
445+ return ListingsGetResponseAll (listings = [], total = 0 , next_page_token = "" )
430446
431447 # Convert documents to Pydantic models
432448 response_data = [
@@ -474,11 +490,9 @@ async def post_listings(
474490 Create a new listing
475491 """
476492 try :
477-
478493 # Prepare data for MongoDB
479494 listing_data = body .dict ()
480- listing_data ["date_posted" ] = datetime .now (
481- timezone .utc ).isoformat () # Ensure date is handled properly
495+ listing_data ["date_posted" ] = datetime .now (timezone .utc )
482496 listing_data ["seller_id" ] = current_user ["id" ]
483497
484498 # Insert into MongoDB
@@ -670,7 +684,6 @@ async def delete_saved_item(saved_item_id: str = Query(..., description="ID of t
670684 return ErrorResponse (detail = "Internal Server Error. Please try again later." )
671685
672686
673-
674687######################################## USER ENDPOINTS ########################################
675688
676689
0 commit comments