import { Request, Response } from 'express'; import bcrypt from 'bcryptjs'; import jwt from 'jsonwebtoken'; import { AppDataSource } from '../config/database'; import { User } from '../entities/User'; import { CreatorProfile } from '../entities/CreatorProfile'; const userRepository = AppDataSource.getRepository(User); const profileRepository = AppDataSource.getRepository(CreatorProfile); export class CreatorAuthController { async register(req: Request, res: Response) { try { const { fullName, username, email, password, profileImage, bio, organization, role, website, linkedinUrl, githubUrl, huggingfaceUrl, primaryLanguages, frameworks, agentSpecialties, preferredCompute, endpointHosting, walletAddress, bankAccount, preferredCurrency, country, taxId, idDocumentUrl, } = req.body; if (!fullName || !username || !email || !password) { return res.status(400).json({ error: 'fullName, username, email and password are required' }); } // Username stored without leading @ const cleanUsername = String(username).replace(/^@+/, '').toLowerCase(); // Uniqueness checks const existingUser = await userRepository.findOne({ where: { email } }); if (existingUser) return res.status(400).json({ error: 'Email already in use' }); const existingProfile = await profileRepository.findOne({ where: { username: cleanUsername } }); if (existingProfile) return res.status(400).json({ error: 'Username already in use' }); const hashedPassword = await bcrypt.hash(password, 10); // Create user const user = userRepository.create({ email, password: hashedPassword, name: fullName, isCreator: true, isAdmin: false }); const savedUser = await userRepository.save(user); // Normalize arrays const normArray = (v: any) => { if (!v) return [] as string[]; if (Array.isArray(v)) return v; try { return JSON.parse(v); } catch { return [String(v)]; } }; // Create profile const profile = profileRepository.create({ userId: savedUser.id, fullName, username: cleanUsername, profileImage, bio, organization, role, website, linkedinUrl, githubUrl, huggingfaceUrl, primaryLanguages: normArray(primaryLanguages), frameworks: normArray(frameworks), agentSpecialties: normArray(agentSpecialties), preferredCompute, endpointHosting, walletAddress, bankAccount: bankAccount ? (typeof bankAccount === 'string' ? JSON.parse(bankAccount) : bankAccount) : undefined, preferredCurrency, country, taxId, idDocumentUrl, }); await profileRepository.save(profile); // Token const token = jwt.sign( { id: savedUser.id, email: savedUser.email, isAdmin: savedUser.isAdmin }, process.env.JWT_SECRET!, { expiresIn: '7d' } ); res.status(201).json({ token, user: { id: savedUser.id, email: savedUser.email, name: savedUser.name, isCreator: true } }); } catch (error: any) { console.error('Creator register error:', error); res.status(500).json({ error: error.message || 'Failed to register creator' }); } } async login(req: Request, res: Response) { try { const { email, password } = req.body; if (!email || !password) return res.status(400).json({ error: 'Email and password are required' }); const user = await userRepository.findOne({ where: { email } }); if (!user || !user.isCreator) return res.status(401).json({ error: 'Invalid credentials' }); const isValid = await bcrypt.compare(password, user.password); if (!isValid) return res.status(401).json({ error: 'Invalid credentials' }); const token = jwt.sign( { id: user.id, email: user.email, isAdmin: user.isAdmin }, process.env.JWT_SECRET!, { expiresIn: '7d' } ); // Fetch profile brief const profile = await profileRepository.findOne({ where: { userId: user.id } }); res.json({ token, user: { id: user.id, email: user.email, name: user.name, isCreator: user.isCreator, profile: profile ? { username: profile.username, fullName: profile.fullName } : null, }, }); } catch (error: any) { console.error('Creator login error:', error); res.status(500).json({ error: error.message || 'Failed to login creator' }); } } }