Set up the basic structure and core functionality for the application
Initialize project with UI components, core libraries, and basic app structure. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 556aa286-edd2-4cea-8583-f4fc3cfd119b
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
import { Request, Response } from 'express';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { storage } from '../storage';
|
||||
import { loginSchema, registerSchema } from '@shared/schema';
|
||||
import { AuthenticatedRequest } from '../middleware/auth';
|
||||
|
||||
export const authController = {
|
||||
async register(req: Request, res: Response) {
|
||||
try {
|
||||
const validatedData = registerSchema.parse(req.body);
|
||||
|
||||
// Check if user already exists
|
||||
const existingUser = await storage.getUserByEmail(validatedData.email);
|
||||
if (existingUser) {
|
||||
return res.status(400).json({ error: 'User already exists with this email' });
|
||||
}
|
||||
|
||||
const existingUsername = await storage.getUserByUsername(validatedData.username);
|
||||
if (existingUsername) {
|
||||
return res.status(400).json({ error: 'Username already taken' });
|
||||
}
|
||||
|
||||
// Hash password
|
||||
const saltRounds = 12;
|
||||
const hashedPassword = await bcrypt.hash(validatedData.password, saltRounds);
|
||||
|
||||
// Create user
|
||||
const user = await storage.createUser({
|
||||
username: validatedData.username,
|
||||
email: validatedData.email,
|
||||
password: hashedPassword,
|
||||
role: validatedData.role || 'standard',
|
||||
firstName: validatedData.firstName,
|
||||
lastName: validatedData.lastName,
|
||||
onboardingComplete: false,
|
||||
voiceEnabled: true,
|
||||
ttsEnabled: true
|
||||
});
|
||||
|
||||
// Remove password from response
|
||||
const { password, ...userWithoutPassword } = user;
|
||||
|
||||
res.status(201).json({
|
||||
message: 'User created successfully',
|
||||
user: userWithoutPassword
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Registration error:', error);
|
||||
if (error instanceof Error && error.name === 'ZodError') {
|
||||
return res.status(400).json({ error: 'Invalid input data', details: error.message });
|
||||
}
|
||||
res.status(500).json({ error: 'Failed to create user' });
|
||||
}
|
||||
},
|
||||
|
||||
async login(req: Request, res: Response) {
|
||||
try {
|
||||
const validatedData = loginSchema.parse(req.body);
|
||||
|
||||
const user = await storage.getUserByEmail(validatedData.email);
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: 'Invalid email or password' });
|
||||
}
|
||||
|
||||
const isValidPassword = await bcrypt.compare(validatedData.password, user.password);
|
||||
if (!isValidPassword) {
|
||||
return res.status(401).json({ error: 'Invalid email or password' });
|
||||
}
|
||||
|
||||
// Use passport login
|
||||
req.login(user, (err) => {
|
||||
if (err) {
|
||||
console.error('Login error:', err);
|
||||
return res.status(500).json({ error: 'Login failed' });
|
||||
}
|
||||
|
||||
const { password, ...userWithoutPassword } = user;
|
||||
res.json({
|
||||
message: 'Login successful',
|
||||
user: userWithoutPassword
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
if (error instanceof Error && error.name === 'ZodError') {
|
||||
return res.status(400).json({ error: 'Invalid input data' });
|
||||
}
|
||||
res.status(500).json({ error: 'Login failed' });
|
||||
}
|
||||
},
|
||||
|
||||
async logout(req: Request, res: Response) {
|
||||
req.logout((err) => {
|
||||
if (err) {
|
||||
console.error('Logout error:', err);
|
||||
return res.status(500).json({ error: 'Logout failed' });
|
||||
}
|
||||
res.json({ message: 'Logout successful' });
|
||||
});
|
||||
},
|
||||
|
||||
async me(req: AuthenticatedRequest, res: Response) {
|
||||
try {
|
||||
if (!req.user) {
|
||||
return res.status(401).json({ error: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const { password, ...userWithoutPassword } = req.user;
|
||||
res.json({ user: userWithoutPassword });
|
||||
} catch (error) {
|
||||
console.error('Get user error:', error);
|
||||
res.status(500).json({ error: 'Failed to get user information' });
|
||||
}
|
||||
},
|
||||
|
||||
async updateProfile(req: AuthenticatedRequest, res: Response) {
|
||||
try {
|
||||
if (!req.user) {
|
||||
return res.status(401).json({ error: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const allowedUpdates = ['firstName', 'lastName', 'voiceEnabled', 'ttsEnabled'];
|
||||
const updates: any = {};
|
||||
|
||||
for (const field of allowedUpdates) {
|
||||
if (req.body[field] !== undefined) {
|
||||
updates[field] = req.body[field];
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(updates).length === 0) {
|
||||
return res.status(400).json({ error: 'No valid fields to update' });
|
||||
}
|
||||
|
||||
const updatedUser = await storage.updateUser(req.user.id, updates);
|
||||
if (!updatedUser) {
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
}
|
||||
|
||||
const { password, ...userWithoutPassword } = updatedUser;
|
||||
res.json({
|
||||
message: 'Profile updated successfully',
|
||||
user: userWithoutPassword
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Update profile error:', error);
|
||||
res.status(500).json({ error: 'Failed to update profile' });
|
||||
}
|
||||
},
|
||||
|
||||
async completeOnboarding(req: AuthenticatedRequest, res: Response) {
|
||||
try {
|
||||
if (!req.user) {
|
||||
return res.status(401).json({ error: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const { role, preferences } = req.body;
|
||||
|
||||
// Update user onboarding status and role if provided
|
||||
const updates: any = { onboardingComplete: true };
|
||||
if (role && ['standard', 'pro', 'admin'].includes(role)) {
|
||||
updates.role = role;
|
||||
}
|
||||
|
||||
const updatedUser = await storage.updateUser(req.user.id, updates);
|
||||
if (!updatedUser) {
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
}
|
||||
|
||||
// Save user preferences if provided
|
||||
if (preferences) {
|
||||
await storage.updateUserPreferences(req.user.id, preferences);
|
||||
}
|
||||
|
||||
const { password, ...userWithoutPassword } = updatedUser;
|
||||
res.json({
|
||||
message: 'Onboarding completed successfully',
|
||||
user: userWithoutPassword
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Complete onboarding error:', error);
|
||||
res.status(500).json({ error: 'Failed to complete onboarding' });
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user