ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
at master 2.8 kB view raw
1import { AuthenticatedHandler } from "./core/types"; 2import { MatchRepository } from "./repositories"; 3import { successResponse } from "./utils"; 4import { withAuthErrorHandling } from "./core/middleware"; 5import { ValidationError, NotFoundError } from "./core/errors"; 6 7const DEFAULT_PAGE_SIZE = 50; 8const MAX_PAGE_SIZE = 100; 9 10const getUploadDetailsHandler: AuthenticatedHandler = async (context) => { 11 const uploadId = context.event.queryStringParameters?.uploadId; 12 const page = parseInt(context.event.queryStringParameters?.page || "1"); 13 const pageSize = Math.min( 14 parseInt( 15 context.event.queryStringParameters?.pageSize || 16 String(DEFAULT_PAGE_SIZE), 17 ), 18 MAX_PAGE_SIZE, 19 ); 20 21 if (!uploadId) { 22 throw new ValidationError("uploadId is required"); 23 } 24 25 if (page < 1 || pageSize < 1) { 26 throw new ValidationError("Invalid page or pageSize parameters"); 27 } 28 29 const matchRepo = new MatchRepository(); 30 31 // Fetch paginated results 32 const { results, totalUsers } = await matchRepo.getUploadDetails( 33 uploadId, 34 context.did, 35 page, 36 pageSize, 37 ); 38 39 if (totalUsers === 0) { 40 throw new NotFoundError("Upload not found"); 41 } 42 43 const totalPages = Math.ceil(totalUsers / pageSize); 44 45 // Group results by source username 46 const groupedResults = new Map<string, any>(); 47 48 results.forEach((row: any) => { 49 const username = row.source_username; 50 51 // Get or create the entry for this username 52 let userResult = groupedResults.get(username); 53 54 if (!userResult) { 55 userResult = { 56 sourceUser: { 57 username: username, 58 date: row.source_date || "", 59 }, 60 atprotoMatches: [], 61 }; 62 groupedResults.set(username, userResult); 63 } 64 65 // Add the match (if it exists) to the array 66 if (row.atproto_did) { 67 userResult.atprotoMatches.push({ 68 did: row.atproto_did, 69 handle: row.atproto_handle, 70 displayName: row.atproto_display_name, 71 avatar: row.atproto_avatar, 72 description: row.atproto_description, 73 matchScore: row.match_score, 74 postCount: row.post_count, 75 followerCount: row.follower_count, 76 foundAt: row.found_at, 77 dismissed: row.dismissed || false, 78 followStatus: row.follow_status || {}, 79 }); 80 } 81 }); 82 83 const searchResults = Array.from(groupedResults.values()); 84 85 return successResponse( 86 { 87 results: searchResults, 88 pagination: { 89 page, 90 pageSize, 91 totalPages, 92 totalUsers, 93 hasNextPage: page < totalPages, 94 hasPrevPage: page > 1, 95 }, 96 }, 97 200, 98 { 99 "Cache-Control": "private, max-age=600", 100 }, 101 ); 102}; 103 104export const handler = withAuthErrorHandling(getUploadDetailsHandler);