freealberta/influence/app/controllers/usersController.js

338 lines
12 KiB
JavaScript

const nocodbService = require('../services/nocodb');
const { sendLoginDetails } = require('../services/email');
const { sanitizeUser, extractId } = require('../utils/helpers');
class UsersController {
async getAll(req, res) {
try {
console.log('UsersController.getAll called');
console.log('Users table ID:', nocodbService.tableIds.users);
if (!nocodbService.tableIds.users) {
console.error('Users table not configured in environment');
return res.status(500).json({
success: false,
error: 'Users table not configured. Please set NOCODB_TABLE_USERS in your environment variables.'
});
}
console.log('Fetching users from NocoDB...');
const response = await nocodbService.getAll(nocodbService.tableIds.users, {
limit: 100
});
const users = response.list || [];
console.log(`Retrieved ${users.length} users from database`);
// Remove password field from response for security
const safeUsers = users.map(sanitizeUser);
res.json({
success: true,
users: safeUsers
});
} catch (error) {
console.error('Error fetching users:', error);
res.status(500).json({
success: false,
error: 'Failed to fetch users: ' + error.message
});
}
}
async create(req, res) {
try {
const { email, password, name, phone, isAdmin, userType, expireDays } = req.body;
if (!email || !password) {
return res.status(400).json({
success: false,
error: 'Email and password are required'
});
}
if (!nocodbService.tableIds.users) {
return res.status(500).json({
success: false,
error: 'Users table not configured'
});
}
// Check if user already exists
console.log(`Checking if user exists with email: ${email}`);
let existingUser = null;
try {
existingUser = await nocodbService.getUserByEmail(email);
console.log('Existing user check result:', existingUser ? 'User exists' : 'User does not exist');
} catch (error) {
console.error('Error checking for existing user:', error.message);
// Continue with creation if check fails - NocoDB will handle the unique constraint
}
if (existingUser) {
console.log('Existing user found:', { id: existingUser.ID || existingUser.Id || existingUser.id, email: existingUser.Email || existingUser.email });
return res.status(400).json({
success: false,
error: 'User with this email already exists'
});
}
// Calculate expiration date for temp users
let expiresAt = null;
if (userType === 'temp' && expireDays) {
const expirationDate = new Date();
expirationDate.setDate(expirationDate.getDate() + expireDays);
expiresAt = expirationDate.toISOString();
}
// Create new user - use the exact column titles from NocoDB schema
const userData = {
Email: email,
Name: name || '',
Password: password,
Phone: phone || '',
Admin: isAdmin === true,
'User Type': userType || 'user',
ExpiresAt: expiresAt,
ExpireDays: userType === 'temp' ? expireDays : null,
'Last Login': null
};
const response = await nocodbService.create(
nocodbService.tableIds.users,
userData
);
res.status(201).json({
success: true,
message: 'User created successfully',
user: {
id: extractId(response),
email: email,
name: name,
phone: phone,
admin: isAdmin,
userType: userType,
expiresAt: expiresAt
}
});
} catch (error) {
console.error('Error creating user:', error);
// Check if it's a unique constraint violation (email already exists)
if (error.response?.data?.code === '23505' ||
error.response?.data?.message?.includes('already exists') ||
error.message?.includes('already exists')) {
return res.status(400).json({
success: false,
error: 'A user with this email address already exists'
});
}
res.status(500).json({
success: false,
error: 'Failed to create user: ' + (error.message || 'Unknown error')
});
}
}
async delete(req, res) {
try {
const userId = req.params.id;
if (!nocodbService.tableIds.users) {
return res.status(500).json({
success: false,
error: 'Users table not configured'
});
}
// Don't allow admins to delete themselves
if (userId === req.session.userId) {
return res.status(400).json({
success: false,
error: 'Cannot delete your own account'
});
}
await nocodbService.deleteUser(userId);
res.json({
success: true,
message: 'User deleted successfully'
});
} catch (error) {
console.error('Error deleting user:', error);
res.status(500).json({
success: false,
error: 'Failed to delete user'
});
}
}
async sendLoginDetails(req, res) {
try {
const userId = req.params.id;
if (!nocodbService.tableIds.users) {
return res.status(500).json({
success: false,
error: 'Users table not configured'
});
}
// Get user data from database
const user = await nocodbService.getById(
nocodbService.tableIds.users,
userId
);
if (!user) {
return res.status(404).json({
success: false,
error: 'User not found'
});
}
// Send login details email
await sendLoginDetails(user);
res.json({
success: true,
message: 'Login details sent successfully'
});
} catch (error) {
console.error('Error sending login details:', error);
res.status(500).json({
success: false,
error: 'Failed to send login details'
});
}
}
async emailAllUsers(req, res) {
try {
const { subject, content } = req.body;
if (!subject || !content) {
return res.status(400).json({
success: false,
error: 'Subject and content are required'
});
}
if (!nocodbService.tableIds.users) {
return res.status(500).json({
success: false,
error: 'Users table not configured'
});
}
// Get all users
const response = await nocodbService.getAll(nocodbService.tableIds.users, {
limit: 1000
});
const users = response.list || [];
if (users.length === 0) {
return res.status(400).json({
success: false,
error: 'No users found to email'
});
}
// Import email service
const { sendEmail } = require('../services/email');
const emailTemplates = require('../services/emailTemplates');
// Convert rich text content to plain text for the text version
const stripHtmlTags = (html) => {
return html.replace(/<[^>]*>/g, '').replace(/\s+/g, ' ').trim();
};
// Prepare base template variables
const baseTemplateVariables = {
APP_NAME: 'BNKops Influence - User Broadcast',
EMAIL_SUBJECT: subject,
EMAIL_CONTENT: content,
EMAIL_CONTENT_TEXT: stripHtmlTags(content),
SENDER_NAME: req.session.userName || req.session.userEmail || 'Administrator',
TIMESTAMP: new Date().toLocaleString()
};
// Send emails to all users
const emailResults = [];
const failedEmails = [];
for (const user of users) {
try {
const userVariables = {
...baseTemplateVariables,
USER_NAME: user.Name || user.name || user.Email || user.email || 'User',
USER_EMAIL: user.Email || user.email
};
const emailContent = await emailTemplates.render('user-broadcast', userVariables);
await sendEmail({
to: user.Email || user.email,
subject: subject,
text: emailContent.text,
html: emailContent.html
});
emailResults.push({
email: user.Email || user.email,
name: user.Name || user.name || user.Email || user.email,
success: true
});
console.log(`Sent broadcast email to: ${user.Email || user.email}`);
} catch (emailError) {
console.error(`Failed to send broadcast email to ${user.Email || user.email}:`, emailError);
failedEmails.push({
email: user.Email || user.email,
name: user.Name || user.name || user.Email || user.email,
error: emailError.message
});
}
}
const successCount = emailResults.length;
const failCount = failedEmails.length;
if (successCount === 0) {
return res.status(500).json({
success: false,
error: 'Failed to send any emails',
details: failedEmails
});
}
res.json({
success: true,
message: `Sent email to ${successCount} user${successCount !== 1 ? 's' : ''}${failCount > 0 ? `, ${failCount} failed` : ''}`,
results: {
successful: emailResults,
failed: failedEmails,
total: users.length,
subject: subject
}
});
} catch (error) {
console.error('Error sending broadcast email:', error);
res.status(500).json({
success: false,
error: 'Failed to send broadcast email'
});
}
}
}
module.exports = new UsersController();