enflow-api / controllers /department_controller.py
dhruv575
Fixing member removal
48424ee
from flask import jsonify, request
from models.department import Department
from models.user import User
import csv
import io
import bcrypt
import random
import string
import logging
# Configure logging
logger = logging.getLogger(__name__)
def generate_random_password(length=12):
"""Generate a random password"""
characters = string.ascii_letters + string.digits
return ''.join(random.choice(characters) for _ in range(length))
def create_department():
"""Create a new department with its first admin user"""
data = request.get_json()
# Check if required fields are present
required_fields = ['name', 'address', 'website', 'admin_email', 'admin_name', 'admin_password']
for field in required_fields:
if field not in data:
return jsonify({'message': f'Missing required field: {field}'}), 400
# Check if department with this name already exists
existing_department = Department.find_by_name(data['name'])
if existing_department:
return jsonify({'message': 'Department with this name already exists'}), 400
# Check if user with this email already exists
existing_user = User.find_by_email(data['admin_email'])
if existing_user:
return jsonify({'message': 'User with this email already exists'}), 400
try:
# Log the request data for debugging
logger.info(f"Creating new department with data: {data}")
# Create department
department = Department(
name=data['name'],
address=data['address'],
website=data['website']
)
# Save department and log the result
save_result = department.save()
logger.info(f"Department saved with _id: {department._id}, save result: {save_result}")
# Create admin user
hashed_password = User.hash_password(data['admin_password'])
admin_user = User(
email=data['admin_email'],
name=data['admin_name'],
password=hashed_password,
permissions='Admin',
position=data.get('admin_position', 'Administrator'),
department_id=department._id
)
# Save user and log the result
user_save_result = admin_user.save()
logger.info(f"Admin user saved with _id: {admin_user._id}, save result: {user_save_result}")
# Add admin to department members and log the result
member_add_result = department.add_member(admin_user._id)
logger.info(f"Adding admin user to department members, result: {member_add_result}")
# Check if the member was added correctly
updated_department = Department.find_by_id(department._id)
logger.info(f"Updated department members: {updated_department.members if updated_department else 'Department not found'}")
# Return success response with detailed information
return jsonify({
'message': 'Department and admin user created successfully',
'department': {
**department.to_dict(),
'members_debug': [str(member) for member in department.members]
},
'admin_user': admin_user.to_dict(),
'success': True
}), 201
except Exception as e:
import traceback
logger.error(f"Error creating department: {str(e)}")
logger.error(f"Traceback: {traceback.format_exc()}")
return jsonify({'message': f'Error creating department: {str(e)}'}), 500
def get_department(department_id):
"""Get department by ID"""
department = Department.find_by_id(department_id)
if not department:
return jsonify({'message': 'Department not found'}), 404
return jsonify({'department': department.to_dict()}), 200
def update_department(department_id):
"""Update department details"""
department = Department.find_by_id(department_id)
if not department:
return jsonify({'message': 'Department not found'}), 404
data = request.get_json()
# Update fields if provided
if 'name' in data:
department.name = data['name']
if 'address' in data:
department.address = data['address']
if 'website' in data:
department.website = data['website']
# Save changes
if department.save():
return jsonify({'message': 'Department updated successfully', 'department': department.to_dict()}), 200
else:
return jsonify({'message': 'Failed to update department'}), 500
def delete_department(department_id):
"""Delete a department"""
department = Department.find_by_id(department_id)
if not department:
return jsonify({'message': 'Department not found'}), 404
# Delete all users in the department
users = User.find_by_department(department_id)
for user in users:
user.delete()
# Delete the department
if department.delete():
return jsonify({'message': 'Department and all its users deleted successfully'}), 200
else:
return jsonify({'message': 'Failed to delete department'}), 500
def get_all_departments():
"""Get all departments"""
departments = Department.get_all()
return jsonify({'departments': [department.to_dict() for department in departments]}), 200
def add_members_csv(department_id):
"""Add multiple members to a department using CSV upload"""
department = Department.find_by_id(department_id)
if not department:
return jsonify({'message': 'Department not found'}), 404
if 'file' not in request.files:
return jsonify({'message': 'No file part'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'message': 'No selected file'}), 400
if file and file.filename.endswith('.csv'):
try:
# Read CSV data
csv_data = file.read().decode('utf-8')
csv_reader = csv.DictReader(io.StringIO(csv_data))
# Process each row
new_users = []
errors = []
required_fields = ['email', 'name', 'position', 'permissions']
for row_index, row in enumerate(csv_reader, start=1):
# Check if all required fields are present
missing_fields = [field for field in required_fields if field not in row or not row[field]]
if missing_fields:
errors.append(f"Row {row_index}: Missing required fields: {', '.join(missing_fields)}")
continue
# Check if user already exists
if User.find_by_email(row['email']):
errors.append(f"Row {row_index}: User with email {row['email']} already exists")
continue
# Check if permissions are valid
if row['permissions'] not in ['Admin', 'User']:
row['permissions'] = 'User' # Default to User if invalid
# Generate random password
password = generate_random_password()
hashed_password = User.hash_password(password)
# Create new user
user = User(
email=row['email'],
name=row['name'],
password=hashed_password,
permissions=row['permissions'],
position=row['position'],
department_id=department._id
)
if user.save():
# Add user to department
department.add_member(user._id)
# Store for response (including the raw password)
user_dict = user.to_dict()
user_dict['raw_password'] = password
new_users.append(user_dict)
else:
errors.append(f"Row {row_index}: Failed to save user {row['email']}")
# Return results
return jsonify({
'message': f"Processed {len(new_users)} new users with {len(errors)} errors",
'new_users': new_users,
'errors': errors
}), 200
except Exception as e:
logger.error(f"Error processing CSV: {str(e)}")
return jsonify({'message': f'Error processing CSV: {str(e)}'}), 500
else:
return jsonify({'message': 'File must be a CSV'}), 400
def add_member(department_id, current_user=None):
"""Add a single member to a department"""
department = Department.find_by_id(department_id)
if not department:
return jsonify({'message': 'Department not found'}), 404
data = request.get_json()
# Check if required fields are present
required_fields = ['email', 'name', 'position', 'permissions']
for field in required_fields:
if field not in data:
return jsonify({'message': f'Missing required field: {field}'}), 400
# Check if user already exists
if User.find_by_email(data['email']):
return jsonify({'message': 'User with this email already exists'}), 400
# Check if permissions are valid
if data['permissions'] not in ['Admin', 'User']:
data['permissions'] = 'User' # Default to User if invalid
try:
# Generate random password if not provided
password = data.get('password', generate_random_password())
hashed_password = User.hash_password(password)
# Create new user
user = User(
email=data['email'],
name=data['name'],
password=hashed_password,
permissions=data['permissions'],
position=data['position'],
department_id=department._id
)
if user.save():
# Add user to department
department.add_member(user._id)
# Return the raw password in the response
user_dict = user.to_dict()
user_dict['raw_password'] = password
return jsonify({
'message': 'User added successfully',
'user': user_dict
}), 201
else:
return jsonify({'message': 'Failed to save user'}), 500
except Exception as e:
logger.error(f"Error adding member: {str(e)}")
return jsonify({'message': f'Error adding member: {str(e)}'}), 500
def get_department_members(department_id, current_user=None):
"""Get all members of a department"""
# Log input parameters
logger.info(f"get_department_members called with department_id: {department_id}")
if current_user:
logger.info(f"Current user: {current_user._id}, {current_user.email}, Department: {current_user.department_id}")
# Find department by ID
department = Department.find_by_id(department_id)
if not department:
logger.error(f"Department with ID {department_id} not found")
return jsonify({'message': 'Department not found'}), 404
# Log department info
logger.info(f"Found department: {department.name}, ID: {department._id}")
logger.info(f"Department members list (raw): {department.members}")
logger.info(f"Department has {len(department.members)} members in its members array")
# Find users by department
logger.info(f"Calling User.find_by_department with department_id: {department_id}")
users = User.find_by_department(department_id)
# Log result
logger.info(f"User.find_by_department returned {len(users)} users")
for user in users:
logger.info(f"Found user: {user._id}, {user.email}, Department: {user.department_id}")
# Return response
return jsonify({'members': [user.to_dict() for user in users]}), 200
def remove_member(department_id, user_id, current_user=None):
"""Remove a member from a department"""
department = Department.find_by_id(department_id)
if not department:
return jsonify({'message': 'Department not found'}), 404
user = User.find_by_id(user_id)
if not user:
return jsonify({'message': 'User not found'}), 404
# Check if user belongs to the department
if str(user.department_id) != str(department._id):
return jsonify({'message': 'User does not belong to this department'}), 400
# Remove user from department
if department.remove_member(user_id) and user.delete():
return jsonify({'message': 'User removed successfully'}), 200
else:
return jsonify({'message': 'Failed to remove user'}), 500
def update_member_permissions(department_id, user_id, current_user=None):
"""Update a member's permissions"""
department = Department.find_by_id(department_id)
if not department:
return jsonify({'message': 'Department not found'}), 404
user = User.find_by_id(user_id)
if not user:
return jsonify({'message': 'User not found'}), 404
# Check if user belongs to the department
if str(user.department_id) != str(department._id):
return jsonify({'message': 'User does not belong to this department'}), 400
data = request.get_json()
# Check if permissions are provided
if 'permissions' not in data:
return jsonify({'message': 'Permissions not provided'}), 400
# Check if permissions are valid
if data['permissions'] not in ['Admin', 'User']:
return jsonify({'message': 'Invalid permissions. Must be "Admin" or "User"'}), 400
# Update permissions
user.permissions = data['permissions']
if user.save():
return jsonify({'message': 'User permissions updated successfully', 'user': user.to_dict()}), 200
else:
return jsonify({'message': 'Failed to update user permissions'}), 500
def debug_department(department_id, current_user=None):
"""Debug endpoint to get detailed information about a department and its members"""
logger.info(f"debug_department called with department_id: {department_id}")
if current_user:
logger.info(f"Called by user: {current_user._id}, {current_user.email}, Permissions: {current_user.permissions}")
# Find department directly from MongoDB
from db import get_departments_collection, get_users_collection
from bson import ObjectId
dept_id_obj = ObjectId(department_id) if isinstance(department_id, str) else department_id
logger.info(f"Looking up department with ObjectId: {dept_id_obj}")
# Get raw department data
departments_collection = get_departments_collection()
department_data = departments_collection.find_one({"_id": dept_id_obj})
if not department_data:
logger.error(f"Department with ID {department_id} not found in database")
return jsonify({'message': 'Department not found'}), 404
# Get department object
department = Department.find_by_id(department_id)
# Get users collection
users_collection = get_users_collection()
# Find all users in database
all_users = list(users_collection.find())
logger.info(f"Total users in database: {len(all_users)}")
# Collect user info for all department members
member_info = []
for member_id in department_data.get('members', []):
# Try to find user by ID
user_data = users_collection.find_one({"_id": member_id})
if user_data:
member_info.append({
"user_id": str(member_id),
"found_in_db": True,
"email": user_data.get('email'),
"name": user_data.get('name'),
"department_id": str(user_data.get('department_id')) if user_data.get('department_id') else None
})
else:
member_info.append({
"user_id": str(member_id),
"found_in_db": False
})
# Find all users with this department_id
users_with_dept = list(users_collection.find({"department_id": dept_id_obj}))
logger.info(f"Found {len(users_with_dept)} users with department_id matching {dept_id_obj}")
users_info = []
for user_data in users_with_dept:
users_info.append({
"user_id": str(user_data.get('_id')),
"email": user_data.get('email'),
"name": user_data.get('name'),
"in_members_array": any(str(user_data.get('_id')) == str(m) for m in department_data.get('members', []))
})
# Build response with detailed info
response = {
"department": {
"_id": str(department_data.get('_id')),
"name": department_data.get('name'),
"raw_members": [str(m) for m in department_data.get('members', [])],
"member_count": len(department_data.get('members', [])),
"members_detail": member_info
},
"users_with_department_id": {
"count": len(users_with_dept),
"users": users_info
}
}
return jsonify(response), 200