252 lines
5.5 KiB
Markdown
252 lines
5.5 KiB
Markdown
# 🐛 Available Users API 500 Error - Fixed
|
|
|
|
## Issue
|
|
|
|
**Error**: 500 Internal Server Error
|
|
**Endpoint**: `GET /api/members/users/available/:groupId`
|
|
**URL**: https://chitfund.deepteklabs.com/api/members/users/available/d3ac73b2-305f-49c8-82d6-84076235f9c3
|
|
|
|
**SQL Error**: `syntax error at or near "SELECT"`
|
|
|
|
---
|
|
|
|
## Root Cause
|
|
|
|
The SQL subquery in `NOT IN` clause was **missing parentheses**:
|
|
|
|
```sql
|
|
-- ❌ WRONG (Missing parentheses)
|
|
WHERE "User"."id" NOT IN
|
|
SELECT user_id FROM group_members ...
|
|
|
|
-- ✅ CORRECT (With parentheses)
|
|
WHERE "User"."id" NOT IN (
|
|
SELECT user_id FROM group_members ...
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## The Fix
|
|
|
|
### File: `backend/src/controllers/memberController.js`
|
|
|
|
**Before** (Missing parentheses):
|
|
```javascript
|
|
id: {
|
|
[Op.notIn]: require('sequelize').literal(`
|
|
SELECT user_id FROM group_members
|
|
WHERE group_id = '${groupId}' AND status = 'active'
|
|
`)
|
|
}
|
|
```
|
|
|
|
**After** (With parentheses):
|
|
```javascript
|
|
const { sequelize } = require('../config/database');
|
|
|
|
id: {
|
|
[Op.notIn]: sequelize.literal(`(
|
|
SELECT user_id FROM group_members
|
|
WHERE group_id = '${groupId}' AND status = 'active'
|
|
)`)
|
|
}
|
|
```
|
|
|
|
### Changes Made:
|
|
1. ✅ **Added parentheses** around subquery: `(SELECT ...)`
|
|
2. ✅ **Imported sequelize** from database config (cleaner)
|
|
|
|
---
|
|
|
|
## What This Endpoint Does
|
|
|
|
Returns a list of users who are **NOT** already members of a specific chit group. Used when a manager wants to add new members to a group.
|
|
|
|
### Request:
|
|
```
|
|
GET /api/members/users/available/:groupId?page=1&limit=50&search=john
|
|
```
|
|
|
|
### Response:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"users": [
|
|
{
|
|
"id": "uuid",
|
|
"full_name": "John Doe",
|
|
"mobile_number": "9876543210",
|
|
"email": "john@example.com",
|
|
"address": "123 Main St",
|
|
"emergency_contact": "9999999999",
|
|
"created_at": "2025-11-06T..."
|
|
}
|
|
],
|
|
"pagination": {
|
|
"currentPage": 1,
|
|
"totalPages": 1,
|
|
"totalItems": 5,
|
|
"itemsPerPage": 50
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## How to Deploy
|
|
|
|
```bash
|
|
# 1. Commit changes
|
|
git add backend/src/controllers/memberController.js
|
|
git commit -m "Fix available users API - add parentheses to subquery"
|
|
git push origin prodnew
|
|
|
|
# 2. Deploy to production
|
|
ssh luckychit@192.168.8.148
|
|
cd /home/luckychit/apps/chitfund
|
|
./scripts/deploy.sh backend
|
|
|
|
# 3. Test it works
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"https://chitfund.deepteklabs.com/api/members/users/available/YOUR_GROUP_ID"
|
|
```
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
### Test 1: Get Available Users
|
|
```bash
|
|
curl -H "Authorization: Bearer MANAGER_TOKEN" \
|
|
"https://chitfund.deepteklabs.com/api/members/users/available/d3ac73b2-305f-49c8-82d6-84076235f9c3"
|
|
```
|
|
|
|
**Should return**: List of users not in the group
|
|
|
|
### Test 2: With Search
|
|
```bash
|
|
curl -H "Authorization: Bearer MANAGER_TOKEN" \
|
|
"https://chitfund.deepteklabs.com/api/members/users/available/d3ac73b2-305f-49c8-82d6-84076235f9c3?search=john"
|
|
```
|
|
|
|
**Should return**: Filtered users matching "john"
|
|
|
|
### Test 3: With Pagination
|
|
```bash
|
|
curl -H "Authorization: Bearer MANAGER_TOKEN" \
|
|
"https://chitfund.deepteklabs.com/api/members/users/available/d3ac73b2-305f-49c8-82d6-84076235f9c3?page=1&limit=10"
|
|
```
|
|
|
|
**Should return**: First 10 available users
|
|
|
|
---
|
|
|
|
## SQL Syntax Rules
|
|
|
|
### NOT IN with Subquery
|
|
|
|
**Always wrap subquery in parentheses:**
|
|
|
|
```sql
|
|
-- ✅ CORRECT
|
|
WHERE id NOT IN (
|
|
SELECT user_id FROM table
|
|
)
|
|
|
|
-- ❌ WRONG
|
|
WHERE id NOT IN
|
|
SELECT user_id FROM table
|
|
```
|
|
|
|
### EXISTS Alternative (Better Performance)
|
|
|
|
For better performance, consider using `NOT EXISTS`:
|
|
|
|
```javascript
|
|
// Alternative implementation (faster for large datasets)
|
|
id: {
|
|
[Op.notIn]: sequelize.literal(`(
|
|
SELECT gm.user_id
|
|
FROM group_members gm
|
|
WHERE gm.group_id = '${groupId}'
|
|
AND gm.status = 'active'
|
|
)`)
|
|
}
|
|
|
|
// Or using NOT EXISTS:
|
|
where: sequelize.literal(`
|
|
NOT EXISTS (
|
|
SELECT 1 FROM group_members gm
|
|
WHERE gm.user_id = "User"."id"
|
|
AND gm.group_id = '${groupId}'
|
|
AND gm.status = 'active'
|
|
)
|
|
`)
|
|
```
|
|
|
|
---
|
|
|
|
## Security Note
|
|
|
|
⚠️ **SQL Injection Risk**: The current code uses string interpolation for `groupId`:
|
|
|
|
```javascript
|
|
WHERE group_id = '${groupId}' // ⚠️ Vulnerable to SQL injection
|
|
```
|
|
|
|
### Recommended Fix (Future):
|
|
|
|
Use Sequelize's replacements for safer queries:
|
|
|
|
```javascript
|
|
id: {
|
|
[Op.notIn]: sequelize.literal(`(
|
|
SELECT user_id FROM group_members
|
|
WHERE group_id = :groupId AND status = 'active'
|
|
)`),
|
|
}
|
|
// Then use replacements in the query
|
|
{
|
|
replacements: { groupId },
|
|
type: sequelize.QueryTypes.SELECT
|
|
}
|
|
```
|
|
|
|
**For now**: The route is protected with `requireManager` middleware, so only authenticated managers can access it. Still, consider improving this for better security.
|
|
|
|
---
|
|
|
|
## Related Endpoints
|
|
|
|
All working correctly:
|
|
- ✅ `POST /api/members/:groupId/members` - Add member to group
|
|
- ✅ `GET /api/members/:groupId/members` - Get group members
|
|
- ✅ `GET /api/members/:groupId/members/:memberId` - Get member details
|
|
- ✅ `PUT /api/members/:groupId/members/:memberId/status` - Update member status
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
**Problem**: SQL syntax error - missing parentheses around NOT IN subquery
|
|
**Solution**: Added parentheses: `NOT IN (SELECT ...)`
|
|
**Impact**: Managers can now see available users to add to groups
|
|
**Status**: ✅ Fixed
|
|
**Deploy**: `./scripts/deploy.sh backend`
|
|
|
|
---
|
|
|
|
## Files Changed
|
|
|
|
- `backend/src/controllers/memberController.js` ✅ Fixed
|
|
|
|
---
|
|
|
|
**The available users API should now work correctly!** 🎉
|
|
|
|
Managers can now see which users are available to add to their chit groups.
|
|
|