Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions packages/recovery-system/backend/scripts/seed-counselors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import mongoose from 'mongoose';
import dotenv from 'dotenv';
import User from '../src/models/User';
import Counselor from '../src/models/Counselor';

dotenv.config();

const MONGO_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/relife';

async function seed() {
try {
console.log('🌱 Starting seed...');

// Connect to MongoDB
await mongoose.connect(MONGO_URI);
console.log('✅ Connected to MongoDB');

// Clear existing data (optional - comment out if you want to keep data)
// await User.deleteMany({});
// await Counselor.deleteMany({});
// console.log('🗑️ Cleared existing data');

// Create test users for counselors
const testUsers = [
{
name: 'Dr. Sarah Johnson',
email: 'sarah@example.com',
image: 'https://api.example.com/avatar1.jpg'
},
{
name: 'Dr. Michael Chen',
email: 'michael@example.com',
image: 'https://api.example.com/avatar2.jpg'
},
{
name: 'Dr. Emma Wilson',
email: 'emma@example.com',
image: 'https://api.example.com/avatar3.jpg'
}
];

const createdUsers = [];
for (const userData of testUsers) {
const existingUser = await User.findOne({ email: userData.email });
if (!existingUser) {
const user = await User.create(userData);
createdUsers.push(user);
console.log(`✅ Created user: ${user.name}`);
} else {
createdUsers.push(existingUser);
console.log(`ℹ️ User already exists: ${existingUser.name}`);
}
}

// Generate test slots (next 7 days, 4 slots per day)
function generateSlots() {
const slots = [];
const now = new Date();

for (let day = 0; day < 7; day++) {
const date = new Date(now);
date.setDate(date.getDate() + day);

// Morning slot
const morning = new Date(date);
morning.setHours(9, 0, 0, 0);
const morningEnd = new Date(morning);
morningEnd.setHours(10, 0, 0, 0);
slots.push({ start: morning, end: morningEnd, isBooked: false });

// Mid-morning slot
const midMorning = new Date(date);
midMorning.setHours(11, 0, 0, 0);
const midMorningEnd = new Date(midMorning);
midMorningEnd.setHours(12, 0, 0, 0);
slots.push({ start: midMorning, end: midMorningEnd, isBooked: false });

// Afternoon slot
const afternoon = new Date(date);
afternoon.setHours(14, 0, 0, 0);
const afternoonEnd = new Date(afternoon);
afternoonEnd.setHours(15, 0, 0, 0);
slots.push({ start: afternoon, end: afternoonEnd, isBooked: false });

// Late afternoon slot
const lateAfternoon = new Date(date);
lateAfternoon.setHours(16, 0, 0, 0);
const lateAfternoonEnd = new Date(lateAfternoon);
lateAfternoonEnd.setHours(17, 0, 0, 0);
slots.push({ start: lateAfternoon, end: lateAfternoonEnd, isBooked: false });
}

return slots;
}

// Create counselor profiles
const counselorData = [
{
userId: createdUsers[0]._id,
credentials: {
degree: 'Master of Science in Counseling',
license: 'LPC-001001',
licenseState: 'California',
yearsOfExperience: 5,
certifications: ['Addiction Specialist', 'SAMHSA Certified']
},
specializations: ['addiction', 'substance_abuse', 'relapse_prevention'],
bio: 'Dr. Sarah Johnson is a certified addiction recovery counselor with 5 years of experience helping clients overcome substance abuse and addiction. She specializes in motivational interviewing and cognitive behavioral therapy. Sarah is passionate about helping others on their recovery journey.',
isVerified: true,
hourlyRate: 50,
ratingCount: 12,
availableSlots: generateSlots()
},
{
userId: createdUsers[1]._id,
credentials: {
degree: 'PhD in Clinical Psychology',
license: 'MFT-001002',
licenseState: 'New York',
yearsOfExperience: 8,
certifications: ['Trauma-Informed Care', 'EMDR Certified']
},
specializations: ['anxiety', 'depression', 'trauma', 'ptsd'],
bio: 'Dr. Michael Chen is a licensed clinical psychologist with 8 years of experience in treating anxiety, depression, and trauma-related disorders. He has helped over 500 clients achieve significant improvements in their mental health through evidence-based therapeutic approaches and compassionate care.',
isVerified: true,
hourlyRate: 60,
ratingCount: 25,
availableSlots: generateSlots()
},
{
userId: createdUsers[2]._id,
credentials: {
degree: 'Master of Marriage and Family Therapy',
license: 'LMFT-001003',
licenseState: 'Texas',
yearsOfExperience: 10,
certifications: ['Family Systems Therapy', 'Child Psychology']
},
specializations: ['family_therapy', 'group_therapy', 'teen_counseling', 'stress_management'],
bio: 'Dr. Emma Wilson is a licensed marriage and family therapist with over 10 years of clinical experience. She specializes in working with families, teens, and individuals experiencing life transitions. Emma is dedicated to helping clients build stronger relationships and develop healthy coping strategies.',
isVerified: true,
hourlyRate: 75,
ratingCount: 40,
availableSlots: generateSlots()
}
];

for (const counselor of counselorData) {
const existingCounselor = await Counselor.findOne({ userId: counselor.userId });
if (!existingCounselor) {
await Counselor.create(counselor);
console.log(`✅ Created counselor: ${counselor.specializations.join(', ')} - ${counselor.availableSlots.length} slots`);
} else {
console.log(`ℹ️ Counselor already exists for user: ${counselor.userId}`);
}
}

console.log('\n🎉 Seed completed successfully!');
console.log('\n📋 Summary:');
console.log(` - Users created: ${createdUsers.length}`);
console.log(` - Counselors with slots added`);
console.log('\n🚀 You can now test the API endpoints!');

} catch (error) {
console.error('❌ Seed failed:', error);
process.exit(1);
} finally {
await mongoose.connection.close();
console.log('\n✅ MongoDB connection closed');
process.exit(0);
}
}

seed();
7 changes: 6 additions & 1 deletion packages/recovery-system/backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import progressRoutes from "./routes/index";
import journalRoutes from "./routes/journal.routes";
import communityRoutes from "./routes/community.routes";
import counselorRoutes from "./routes/counselor.routes";
import bookingRoutes from "./routes/booking.routes";
import { isAuth } from "./middleware/isAuth";
import { getProfile, updateProfile, getProfileDetails } from "./controllers/auth.controller";
import { getProfile, updateProfile, getProfileDetails, signUp } from "./controllers/auth.controller";
import chatRoutes from "./routes/chat.routes";
import gamesRoutes from "./routes/games.routes";
//import analyzer from 'express-api-timer';
Expand Down Expand Up @@ -40,6 +41,7 @@ app.use(helmet());
app.get("/api/auth/me", isAuth, getProfile);
app.put("/api/auth/profile", isAuth, updateProfile);
app.get("/api/auth/profile/details", isAuth, getProfileDetails);
app.post("/api/auth/register", signUp);


// Auth routes (BetterAuth catch-all)
Expand All @@ -61,6 +63,9 @@ app.use('/api/community', communityRoutes);
// Counselor Routes
app.use('/api/counselor', counselorRoutes);

// Booking Routes
app.use('/api', bookingRoutes);

// Chat Routes
app.use('/api/chat', chatRoutes);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Request, Response } from 'express';
import Counselor from '../models/Counselor';
// import User from '../models/User';
import { ValidationCredentials, ValidateSpecialization, validationBio } from '../utils/counselorValidation';

// POST /api/counselors
Expand Down Expand Up @@ -107,4 +108,74 @@ export const getCounselorProfile = async (req: Request, res: Response) => {
} catch (error) {
return res.status(500).json({ error: 'Failed to get counselor profile' });
}
};

/**
* GET /api/counselors
* Get all counselors with optional filters
*/
export const getAllCounselors = async (req: Request, res: Response) => {
try {
const { specialty, specializations, isVerified } = req.query;

const filters: any = { isActive: true };

// Support both 'specialty' and 'specializations' query params
const specParam = (specialty || specializations) as string;
if (specParam) {
filters.specializations = { $in: [specParam.toLowerCase()] };
}

if (isVerified !== undefined) {
filters.isVerified = isVerified === 'true';
}

const counselors = await Counselor.find(filters)
.select('-credentials.license -availability')
.populate('userId', 'name email')
.sort({ rating: -1 });

return res.status(200).json({
message: 'Counselors retrieved successfully',
count: counselors.length,
counselors,
});
} catch (error: any) {
console.error('Error fetching counselors:', error.message || error);
return res.status(500).json({
error: 'Failed to fetch counselors',
details: process.env.NODE_ENV === 'development' ? error.message : undefined
});
}
};

/**
* GET /api/counselors/:id
* Get a single counselor by ID
*/
export const getCounselorById = async (req: Request, res: Response) => {
try {
const { id } = req.params;

// Validate ObjectId format
if (!id.match(/^[0-9a-fA-F]{24}$/)) {
return res.status(400).json({ error: 'Invalid counselor ID format' });
}

const counselor = await Counselor.findById(id)
.select('-credentials.license')
.populate('userId', 'name email');

if (!counselor) {
return res.status(404).json({ error: 'Counselor not found' });
}

return res.status(200).json({
message: 'Counselor retrieved successfully',
counselor,
});
} catch (error) {
console.error('Error fetching counselor:', error);
return res.status(500).json({ error: 'Failed to fetch counselor' });
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const getProfile = async (req: Request, res: Response) => {
return res.status(404).json({ error: 'User not found' });
}

res.json({ user: fullUser });
return res.json({ user: fullUser });
} catch (error) {
return res.status(500).json({ error: 'Failed to get profile' });
}
Expand Down Expand Up @@ -74,7 +74,7 @@ export const updateProfile = async (req: Request, res: Response) => {
return res.status(404).json({ error: 'User not found' });
}

res.json({ user: updatedUser, message: 'Profile updated successfully' });
return res.json({ user: updatedUser, message: 'Profile updated successfully' });
} catch (error) {
return res.status(500).json({ error: 'Failed to update profile' });
}
Expand All @@ -100,8 +100,67 @@ export const getProfileDetails = async (req: Request, res: Response) => {
return res.status(404).json({ error: 'User profile not found' });
}

res.json({ profile: userProfile });
return res.json({ profile: userProfile });
} catch (error) {
return res.status(500).json({ error: 'Failed to get profile details' });
}
};

/**
* Custom sign-up endpoint for testing
* @route POST /api/auth/register
* Creates a new user with email/password
*/
export const signUp = async (req: Request, res: Response) => {
try {
const { name, email, password, role } = req.body;

// Validate inputs
if (!name || !email || !password) {
return res.status(400).json({ error: 'Name, email, and password are required' });
}

// Check if user already exists
const existingUser = await User.findOne({ email });
if (existingUser) {
return res.status(400).json({ error: 'Email already registered' });
}

// Create new user
const newUser = new User({
name,
email,
role: role || 'user',
emailVerified: false,
accountStatus: 'active'
});

// Note: In production, use proper password hashing (bcrypt, argon2, etc.)
// For now, storing plaintext (for testing only)
(newUser as any).password = password;

await newUser.save();

// Generate a simple JWT token for testing
const token = Buffer.from(JSON.stringify({
id: newUser._id,
email: newUser.email,
name: newUser.name,
role: newUser.role
})).toString('base64');

return res.status(201).json({
token,
user: {
_id: newUser._id,
name: newUser.name,
email: newUser.email,
role: newUser.role
},
message: 'User registered successfully'
});
} catch (error: any) {
console.error('Sign up error:', error);
return res.status(500).json({ error: 'Failed to register user' });
}
};
Loading
Loading