/** * Global Profile Plugin - Profiles Routes * * Handles profiles listing and search API endpoints */ const sdk = require('../../../includes/plugins/sdk'); const { getAllProfilesFromDB } = require('../database'); const { dbErrorResponse } = require('../db-errors'); /** * Handle profiles-related routes */ async function handleProfilesRoutes(req, res, path, query, method) { // GET /api/profiles - List all profiles with search/filter, pagination, and sorting if (path === 'api/profiles' && method === 'GET') { try { const search = query.search || ''; const tagFilter = query.tag || ''; const limit = parseInt(query.limit || '100', 10); const offset = parseInt(query.offset || '0', 10); const sort = query.sort || 'lastUpdated'; // lastUpdated, displayName // Validate pagination params if (limit < 1 || limit > 1000) { return sdk.router.error(res, 'Limit must be between 1 and 1000', 400); } if (offset < 0) { return sdk.router.error(res, 'Offset must be >= 0', 400); } if (sort !== 'lastUpdated' && sort !== 'displayName') { return sdk.router.error(res, 'Sort must be either "lastUpdated" or "displayName"', 400); } const allProfiles = await getAllProfilesFromDB(); let filtered = allProfiles; // Apply search filter if (search) { const searchLower = search.toLowerCase(); filtered = filtered.filter(p => (p.displayName && p.displayName.toLowerCase().includes(searchLower)) || (p.bio && p.bio.toLowerCase().includes(searchLower)) ); } // Apply tag filter if (tagFilter) { filtered = filtered.filter(p => { try { const tags = p.tags ? JSON.parse(p.tags) : []; return tags.some(tag => tag.toLowerCase() === tagFilter.toLowerCase()); } catch (err) { return false; } }); } // Sort if (sort === 'lastUpdated') { filtered.sort((a, b) => { const aTime = a.lastUpdated || 0; const bTime = b.lastUpdated || 0; return bTime - aTime; // Descending (newest first) }); } else if (sort === 'displayName') { filtered.sort((a, b) => { const aName = (a.displayName || '').toLowerCase(); const bName = (b.displayName || '').toLowerCase(); return aName.localeCompare(bName); // Ascending (A-Z) }); } const total = filtered.length; // Paginate const paginated = filtered.slice(offset, offset + limit); // Parse JSON fields and add online status const profiles = paginated.map(p => { try { p.customFields = p.customFields ? JSON.parse(p.customFields) : {}; p.tags = p.tags ? JSON.parse(p.tags) : []; } catch (err) { p.customFields = {}; p.tags = []; } // Add online status p.online = sdk.state.peerIds.includes(p.peerId); return p; }); return sdk.router.json(res, { profiles, pagination: { total, limit, offset, hasMore: offset + limit < total } }); } catch (err) { sdk.log.error('global.profile', `Error getting profiles: ${err.message}`); const { status, body } = dbErrorResponse(err); return sdk.router.json(res, body, status, req); } } return false; // Not handled by this module } module.exports = { handleProfilesRoutes };