diff --git a/backend/scripts/user-create.js b/backend/scripts/user-create.js index 2f98209..765de2c 100755 --- a/backend/scripts/user-create.js +++ b/backend/scripts/user-create.js @@ -8,72 +8,49 @@ */ require('dotenv').config(); -const { User } = require('../models'); -const bcrypt = require('bcrypt'); +const { + createOrUpdateUser, + validateEmail, + validatePassword, +} = require('../services/userService'); async function createUser() { const [email, password] = process.argv.slice(2); if (!email || password === undefined) { - console.error('❌ Usage: npm run user:create '); + console.error('Usage: npm run user:create '); console.error( 'Example: npm run user:create admin@example.com mypassword123' ); process.exit(1); } - // Basic password validation (check for empty or short passwords) - if (!password || password.length < 6) { - console.error('❌ Password must be at least 6 characters long'); + // Validate password + if (!validatePassword(password)) { + console.error('Password must be at least 6 characters long'); process.exit(1); } - // Enhanced email validation - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/; - - // Check for common invalid patterns - if ( - !email.includes('@') || - !email.includes('.') || - email.includes('@@') || - email.includes(' ') || - email.startsWith('@') || - email.endsWith('@') || - email.endsWith('.') || - email.includes('@.') || - email.includes('.@') || - !emailRegex.test(email) - ) { - console.error('❌ Invalid email format'); + // Validate email + if (!validateEmail(email)) { + console.error('Invalid email format'); process.exit(1); } try { console.log(`Creating user with email: ${email}`); - // Hash the password manually since the hook might not be working in this context - const hashedPassword = await bcrypt.hash(password, 10); - - // Find or create user (update password if exists) - const [user, created] = await User.findOrCreate({ - where: { email }, - defaults: { - email, - password_digest: hashedPassword, - }, - }); + const { user, created } = await createOrUpdateUser(email, password); if (!created) { - // User exists, update password - await user.update({ password_digest: hashedPassword }); - console.log('ℹ️ User exists, password updated'); + console.log('User exists, password updated'); } else { - console.log('✅ User created successfully'); + console.log('User created successfully'); } - console.log(`📧 Email: ${user.email}`); - console.log(`🆔 User ID: ${user.id}`); - console.log(`📅 Created: ${user.created_at}`); + console.log(`Email: ${user.email}`); + console.log(`User ID: ${user.id}`); + console.log(`Created: ${user.created_at}`); process.exit(0); } catch (error) { diff --git a/backend/services/userService.js b/backend/services/userService.js new file mode 100644 index 0000000..7a8c5ec --- /dev/null +++ b/backend/services/userService.js @@ -0,0 +1,67 @@ +'use strict'; + +const { User } = require('../models'); +const bcrypt = require('bcrypt'); + +/** + * Creates a user or updates password if user already exists + * @param {string} email - User email + * @param {string} password - User password (plain text) + * @returns {Promise<{user: User, created: boolean}>} User object and creation status + */ +async function createOrUpdateUser(email, password) { + const hashedPassword = await bcrypt.hash(password, 10); + + const [user, created] = await User.findOrCreate({ + where: { email }, + defaults: { + email, + password_digest: hashedPassword, + }, + }); + + // User exists, update password + if (!created) { + await user.update({ password_digest: hashedPassword }); + } + + return { user, created }; +} + +/** + * Validates email format + * @param {string} email - Email to validate + * @returns {boolean} True if valid + */ +function validateEmail(email) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/; + + // Check for common invalid patterns + return !( + !email.includes('@') || + !email.includes('.') || + email.includes('@@') || + email.includes(' ') || + email.startsWith('@') || + email.endsWith('@') || + email.endsWith('.') || + email.includes('@.') || + email.includes('.@') || + !emailRegex.test(email) + ); +} + +/** + * Validates password strength + * @param {string} password - Password to validate + * @returns {boolean} True if valid + */ +function validatePassword(password) { + return password && password.length >= 6; +} + +module.exports = { + createOrUpdateUser, + validateEmail, + validatePassword, +};