Upload 4 files
Browse files- codebase/auth.py +88 -0
- codebase/database.py +3 -0
- codebase/email.py +133 -0
- codebase/profile.py +228 -0
codebase/auth.py
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import re
|
2 |
+
import hashlib
|
3 |
+
import time
|
4 |
+
from datetime import datetime, timedelta
|
5 |
+
|
6 |
+
class AuthenticationManager:
|
7 |
+
def __init__(self):
|
8 |
+
self.failed_attempts = {}
|
9 |
+
self.session_timeout = 7200 # 2 hours in seconds
|
10 |
+
|
11 |
+
def validate_password(self, password):
|
12 |
+
"""Validate password meets security requirements"""
|
13 |
+
if len(password) < 8:
|
14 |
+
return False, "Password must be at least 8 characters"
|
15 |
+
|
16 |
+
# Fixed regex to properly handle special characters
|
17 |
+
if not re.match(r'^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};:,.<>?]+$', password):
|
18 |
+
return False, "Password contains invalid characters"
|
19 |
+
|
20 |
+
return True, "Password valid"
|
21 |
+
|
22 |
+
def authenticate_user(self, username, password):
|
23 |
+
"""Authenticate user with username and password"""
|
24 |
+
try:
|
25 |
+
# Check for account lockout
|
26 |
+
if self.is_account_locked(username):
|
27 |
+
return False, "Account temporarily locked due to too many failed attempts"
|
28 |
+
|
29 |
+
# Validate credentials
|
30 |
+
if self.verify_credentials(username, password):
|
31 |
+
self.reset_failed_attempts(username)
|
32 |
+
return True, "Authentication successful"
|
33 |
+
else:
|
34 |
+
self.record_failed_attempt(username)
|
35 |
+
return False, "Invalid username or password"
|
36 |
+
|
37 |
+
except Exception as e:
|
38 |
+
return False, f"Authentication error: {str(e)}"
|
39 |
+
|
40 |
+
def verify_credentials(self, username, password):
|
41 |
+
"""Verify user credentials against database"""
|
42 |
+
# Simplified credential check
|
43 |
+
valid_users = {
|
44 |
+
"admin": "admin123",
|
45 |
+
"user1": "password123",
|
46 |
+
"[email protected]": "test123!"
|
47 |
+
}
|
48 |
+
return valid_users.get(username) == password
|
49 |
+
|
50 |
+
def is_account_locked(self, username):
|
51 |
+
"""Check if account is temporarily locked"""
|
52 |
+
if username not in self.failed_attempts:
|
53 |
+
return False
|
54 |
+
|
55 |
+
attempts, last_attempt = self.failed_attempts[username]
|
56 |
+
if attempts >= 5 and time.time() - last_attempt < 900: # 15 minutes
|
57 |
+
return True
|
58 |
+
return False
|
59 |
+
|
60 |
+
def record_failed_attempt(self, username):
|
61 |
+
"""Record a failed login attempt"""
|
62 |
+
current_time = time.time()
|
63 |
+
if username in self.failed_attempts:
|
64 |
+
attempts, _ = self.failed_attempts[username]
|
65 |
+
self.failed_attempts[username] = (attempts + 1, current_time)
|
66 |
+
else:
|
67 |
+
self.failed_attempts[username] = (1, current_time)
|
68 |
+
|
69 |
+
def reset_failed_attempts(self, username):
|
70 |
+
"""Reset failed attempts for user"""
|
71 |
+
if username in self.failed_attempts:
|
72 |
+
del self.failed_attempts[username]
|
73 |
+
|
74 |
+
def create_session(self, username):
|
75 |
+
"""Create user session with timeout"""
|
76 |
+
session_data = {
|
77 |
+
'username': username,
|
78 |
+
'created_at': datetime.now(),
|
79 |
+
'expires_at': datetime.now() + timedelta(seconds=self.session_timeout),
|
80 |
+
'session_id': hashlib.sha256(f"{username}{time.time()}".encode()).hexdigest()
|
81 |
+
}
|
82 |
+
return session_data
|
83 |
+
|
84 |
+
def validate_session(self, session_id):
|
85 |
+
"""Validate if session is still active"""
|
86 |
+
# This would typically check against a session store
|
87 |
+
# For demo purposes, assuming session validation logic
|
88 |
+
return True # Simplified
|
codebase/database.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
def connect_to_db():
|
2 |
+
print("Connecting to database...")
|
3 |
+
return True
|
codebase/email.py
ADDED
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import smtplib
|
2 |
+
import ssl
|
3 |
+
from email.mime.text import MIMEText
|
4 |
+
from email.mime.multipart import MIMEMultipart
|
5 |
+
from email.template import Template
|
6 |
+
import logging
|
7 |
+
|
8 |
+
class EmailService:
|
9 |
+
def __init__(self, smtp_server="smtp.gmail.com", smtp_port=587):
|
10 |
+
self.smtp_server = smtp_server
|
11 |
+
self.smtp_port = smtp_port
|
12 |
+
self.username = None
|
13 |
+
self.password = None
|
14 |
+
self.logger = logging.getLogger(__name__)
|
15 |
+
|
16 |
+
def configure_smtp(self, username, password):
|
17 |
+
"""Configure SMTP credentials"""
|
18 |
+
self.username = username
|
19 |
+
self.password = password
|
20 |
+
|
21 |
+
def send_password_reset_email(self, recipient_email, reset_token):
|
22 |
+
"""Send password reset email to user"""
|
23 |
+
try:
|
24 |
+
# Create message
|
25 |
+
message = MIMEMultipart("alternative")
|
26 |
+
message["Subject"] = "Password Reset Request"
|
27 |
+
message["From"] = self.username
|
28 |
+
message["To"] = recipient_email
|
29 |
+
|
30 |
+
# Create HTML content
|
31 |
+
html_content = self._generate_reset_email_html(reset_token)
|
32 |
+
html_part = MIMEText(html_content, "html")
|
33 |
+
message.attach(html_part)
|
34 |
+
|
35 |
+
# Send email
|
36 |
+
return self._send_email(message)
|
37 |
+
|
38 |
+
except Exception as e:
|
39 |
+
self.logger.error(f"Error sending password reset email: {str(e)}")
|
40 |
+
return False, f"Failed to send email: {str(e)}"
|
41 |
+
|
42 |
+
def send_notification_email(self, recipient_email, subject, content):
|
43 |
+
"""Send general notification email"""
|
44 |
+
try:
|
45 |
+
message = MIMEMultipart()
|
46 |
+
message["Subject"] = subject
|
47 |
+
message["From"] = self.username
|
48 |
+
message["To"] = recipient_email
|
49 |
+
|
50 |
+
text_part = MIMEText(content, "plain")
|
51 |
+
message.attach(text_part)
|
52 |
+
|
53 |
+
return self._send_email(message)
|
54 |
+
|
55 |
+
except Exception as e:
|
56 |
+
self.logger.error(f"Error sending notification email: {str(e)}")
|
57 |
+
return False, f"Failed to send email: {str(e)}"
|
58 |
+
|
59 |
+
def _send_email(self, message):
|
60 |
+
"""Internal method to send email via SMTP"""
|
61 |
+
try:
|
62 |
+
# Create secure connection
|
63 |
+
context = ssl.create_default_context()
|
64 |
+
|
65 |
+
with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
|
66 |
+
server.starttls(context=context)
|
67 |
+
|
68 |
+
# Check if credentials are configured
|
69 |
+
if not self.username or not self.password:
|
70 |
+
raise Exception("SMTP credentials not configured")
|
71 |
+
|
72 |
+
server.login(self.username, self.password)
|
73 |
+
|
74 |
+
# Send email
|
75 |
+
text = message.as_string()
|
76 |
+
server.sendmail(message["From"], message["To"], text)
|
77 |
+
|
78 |
+
self.logger.info(f"Email sent successfully to {message['To']}")
|
79 |
+
return True, "Email sent successfully"
|
80 |
+
|
81 |
+
except smtplib.SMTPAuthenticationError:
|
82 |
+
error_msg = "SMTP authentication failed - check credentials"
|
83 |
+
self.logger.error(error_msg)
|
84 |
+
return False, error_msg
|
85 |
+
|
86 |
+
except smtplib.SMTPConnectError:
|
87 |
+
error_msg = "Failed to connect to SMTP server"
|
88 |
+
self.logger.error(error_msg)
|
89 |
+
return False, error_msg
|
90 |
+
|
91 |
+
except Exception as e:
|
92 |
+
error_msg = f"Unexpected error sending email: {str(e)}"
|
93 |
+
self.logger.error(error_msg)
|
94 |
+
return False, error_msg
|
95 |
+
|
96 |
+
def _generate_reset_email_html(self, reset_token):
|
97 |
+
"""Generate HTML content for password reset email"""
|
98 |
+
html_template = """
|
99 |
+
<!DOCTYPE html>
|
100 |
+
<html>
|
101 |
+
<head>
|
102 |
+
<meta charset="utf-8">
|
103 |
+
<title>Password Reset</title>
|
104 |
+
</head>
|
105 |
+
<body>
|
106 |
+
<div style="max-width: 600px; margin: 0 auto; padding: 20px;">
|
107 |
+
<h2>Password Reset Request</h2>
|
108 |
+
<p>You have requested a password reset for your account.</p>
|
109 |
+
<p>Click the link below to reset your password:</p>
|
110 |
+
<a href="https://yourapp.com/reset-password?token={token}"
|
111 |
+
style="background-color: #4CAF50; color: white; padding: 10px 20px;
|
112 |
+
text-decoration: none; border-radius: 4px;">
|
113 |
+
Reset Password
|
114 |
+
</a>
|
115 |
+
<p>If you did not request this reset, please ignore this email.</p>
|
116 |
+
<p>This link will expire in 24 hours.</p>
|
117 |
+
</div>
|
118 |
+
</body>
|
119 |
+
</html>
|
120 |
+
"""
|
121 |
+
return html_template.format(token=reset_token)
|
122 |
+
|
123 |
+
def test_connection(self):
|
124 |
+
"""Test SMTP connection and configuration"""
|
125 |
+
try:
|
126 |
+
context = ssl.create_default_context()
|
127 |
+
with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
|
128 |
+
server.starttls(context=context)
|
129 |
+
if self.username and self.password:
|
130 |
+
server.login(self.username, self.password)
|
131 |
+
return True, "SMTP connection successful"
|
132 |
+
except Exception as e:
|
133 |
+
return False, f"SMTP connection failed: {str(e)}"
|
codebase/profile.py
ADDED
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import sqlite3
|
3 |
+
from datetime import datetime
|
4 |
+
from typing import Dict, Optional, List
|
5 |
+
|
6 |
+
class UserProfileManager:
|
7 |
+
"""Manages user profile data and operations"""
|
8 |
+
|
9 |
+
def __init__(self, db_path="users.db"):
|
10 |
+
self.db_path = db_path
|
11 |
+
self.init_database()
|
12 |
+
|
13 |
+
def init_database(self):
|
14 |
+
"""Initialize the user profile database"""
|
15 |
+
try:
|
16 |
+
with sqlite3.connect(self.db_path) as conn:
|
17 |
+
cursor = conn.cursor()
|
18 |
+
cursor.execute("""
|
19 |
+
CREATE TABLE IF NOT EXISTS user_profiles (
|
20 |
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
21 |
+
username VARCHAR(50) UNIQUE NOT NULL,
|
22 |
+
email VARCHAR(100) UNIQUE NOT NULL,
|
23 |
+
first_name VARCHAR(50),
|
24 |
+
last_name VARCHAR(50),
|
25 |
+
profile_data TEXT,
|
26 |
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
27 |
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
28 |
+
)
|
29 |
+
""")
|
30 |
+
conn.commit()
|
31 |
+
except Exception as e:
|
32 |
+
print(f"Database initialization error: {e}")
|
33 |
+
|
34 |
+
def create_profile(self, username: str, email: str, first_name: str = "",
|
35 |
+
last_name: str = "", additional_data: Dict = None) -> bool:
|
36 |
+
"""Create a new user profile"""
|
37 |
+
try:
|
38 |
+
profile_data = json.dumps(additional_data or {})
|
39 |
+
|
40 |
+
with sqlite3.connect(self.db_path) as conn:
|
41 |
+
cursor = conn.cursor()
|
42 |
+
cursor.execute("""
|
43 |
+
INSERT INTO user_profiles
|
44 |
+
(username, email, first_name, last_name, profile_data)
|
45 |
+
VALUES (?, ?, ?, ?, ?)
|
46 |
+
""", (username, email, first_name, last_name, profile_data))
|
47 |
+
conn.commit()
|
48 |
+
return True
|
49 |
+
|
50 |
+
except sqlite3.IntegrityError:
|
51 |
+
return False # Username or email already exists
|
52 |
+
except Exception as e:
|
53 |
+
print(f"Profile creation error: {e}")
|
54 |
+
return False
|
55 |
+
|
56 |
+
def get_profile(self, username: str) -> Optional[Dict]:
|
57 |
+
"""Retrieve user profile by username"""
|
58 |
+
try:
|
59 |
+
with sqlite3.connect(self.db_path) as conn:
|
60 |
+
cursor = conn.cursor()
|
61 |
+
cursor.execute("""
|
62 |
+
SELECT id, username, email, first_name, last_name,
|
63 |
+
profile_data, created_at, updated_at
|
64 |
+
FROM user_profiles
|
65 |
+
WHERE username = ?
|
66 |
+
""", (username,))
|
67 |
+
|
68 |
+
row = cursor.fetchone()
|
69 |
+
if row:
|
70 |
+
return {
|
71 |
+
'id': row[0],
|
72 |
+
'username': row[1],
|
73 |
+
'email': row[2],
|
74 |
+
'first_name': row[3],
|
75 |
+
'last_name': row[4],
|
76 |
+
'profile_data': json.loads(row[5] or '{}'),
|
77 |
+
'created_at': row[6],
|
78 |
+
'updated_at': row[7]
|
79 |
+
}
|
80 |
+
return None
|
81 |
+
|
82 |
+
except Exception as e:
|
83 |
+
print(f"Profile retrieval error: {e}")
|
84 |
+
return None
|
85 |
+
|
86 |
+
def update_profile(self, username: str, updates: Dict) -> bool:
|
87 |
+
"""Update user profile information"""
|
88 |
+
try:
|
89 |
+
# Build dynamic update query
|
90 |
+
update_fields = []
|
91 |
+
update_values = []
|
92 |
+
|
93 |
+
allowed_fields = ['email', 'first_name', 'last_name', 'profile_data']
|
94 |
+
|
95 |
+
for field, value in updates.items():
|
96 |
+
if field in allowed_fields:
|
97 |
+
if field == 'profile_data':
|
98 |
+
value = json.dumps(value)
|
99 |
+
update_fields.append(f"{field} = ?")
|
100 |
+
update_values.append(value)
|
101 |
+
|
102 |
+
if not update_fields:
|
103 |
+
return False # No valid fields to update
|
104 |
+
|
105 |
+
# Add updated_at timestamp
|
106 |
+
update_fields.append("updated_at = ?")
|
107 |
+
update_values.append(datetime.now().isoformat())
|
108 |
+
|
109 |
+
# Add username for WHERE clause
|
110 |
+
update_values.append(username)
|
111 |
+
|
112 |
+
query = f"""
|
113 |
+
UPDATE user_profiles
|
114 |
+
SET {', '.join(update_fields)}
|
115 |
+
WHERE username = ?
|
116 |
+
"""
|
117 |
+
|
118 |
+
with sqlite3.connect(self.db_path) as conn:
|
119 |
+
cursor = conn.cursor()
|
120 |
+
cursor.execute(query, update_values)
|
121 |
+
conn.commit()
|
122 |
+
|
123 |
+
return cursor.rowcount > 0 # True if row was updated
|
124 |
+
|
125 |
+
except sqlite3.IntegrityError:
|
126 |
+
return False # Constraint violation (e.g., duplicate email)
|
127 |
+
except Exception as e:
|
128 |
+
print(f"Profile update error: {e}")
|
129 |
+
return False
|
130 |
+
|
131 |
+
def delete_profile(self, username: str) -> bool:
|
132 |
+
"""Delete user profile"""
|
133 |
+
try:
|
134 |
+
with sqlite3.connect(self.db_path) as conn:
|
135 |
+
cursor = conn.cursor()
|
136 |
+
cursor.execute("DELETE FROM user_profiles WHERE username = ?", (username,))
|
137 |
+
conn.commit()
|
138 |
+
return cursor.rowcount > 0
|
139 |
+
|
140 |
+
except Exception as e:
|
141 |
+
print(f"Profile deletion error: {e}")
|
142 |
+
return False
|
143 |
+
|
144 |
+
def list_profiles(self, limit: int = 50, offset: int = 0) -> List[Dict]:
|
145 |
+
"""List user profiles with pagination"""
|
146 |
+
try:
|
147 |
+
with sqlite3.connect(self.db_path) as conn:
|
148 |
+
cursor = conn.cursor()
|
149 |
+
cursor.execute("""
|
150 |
+
SELECT id, username, email, first_name, last_name, created_at
|
151 |
+
FROM user_profiles
|
152 |
+
ORDER BY created_at DESC
|
153 |
+
LIMIT ? OFFSET ?
|
154 |
+
""", (limit, offset))
|
155 |
+
|
156 |
+
profiles = []
|
157 |
+
for row in cursor.fetchall():
|
158 |
+
profiles.append({
|
159 |
+
'id': row[0],
|
160 |
+
'username': row[1],
|
161 |
+
'email': row[2],
|
162 |
+
'first_name': row[3],
|
163 |
+
'last_name': row[4],
|
164 |
+
'created_at': row[5]
|
165 |
+
})
|
166 |
+
|
167 |
+
return profiles
|
168 |
+
|
169 |
+
except Exception as e:
|
170 |
+
print(f"Profile listing error: {e}")
|
171 |
+
return []
|
172 |
+
|
173 |
+
def search_profiles(self, search_term: str) -> List[Dict]:
|
174 |
+
"""Search profiles by username, email, or name"""
|
175 |
+
try:
|
176 |
+
search_pattern = f"%{search_term}%"
|
177 |
+
|
178 |
+
with sqlite3.connect(self.db_path) as conn:
|
179 |
+
cursor = conn.cursor()
|
180 |
+
cursor.execute("""
|
181 |
+
SELECT id, username, email, first_name, last_name, created_at
|
182 |
+
FROM user_profiles
|
183 |
+
WHERE username LIKE ? OR email LIKE ?
|
184 |
+
OR first_name LIKE ? OR last_name LIKE ?
|
185 |
+
ORDER BY username
|
186 |
+
""", (search_pattern, search_pattern, search_pattern, search_pattern))
|
187 |
+
|
188 |
+
profiles = []
|
189 |
+
for row in cursor.fetchall():
|
190 |
+
profiles.append({
|
191 |
+
'id': row[0],
|
192 |
+
'username': row[1],
|
193 |
+
'email': row[2],
|
194 |
+
'first_name': row[3],
|
195 |
+
'last_name': row[4],
|
196 |
+
'created_at': row[5]
|
197 |
+
})
|
198 |
+
|
199 |
+
return profiles
|
200 |
+
|
201 |
+
except Exception as e:
|
202 |
+
print(f"Profile search error: {e}")
|
203 |
+
return []
|
204 |
+
|
205 |
+
# API endpoints for profile management
|
206 |
+
def handle_profile_update_api(request_data: Dict) -> Dict:
|
207 |
+
"""Handle API request for profile updates"""
|
208 |
+
try:
|
209 |
+
username = request_data.get('username')
|
210 |
+
updates = request_data.get('updates', {})
|
211 |
+
|
212 |
+
if not username:
|
213 |
+
return {'error': 'Username is required', 'status': 400}
|
214 |
+
|
215 |
+
profile_manager = UserProfileManager()
|
216 |
+
|
217 |
+
# Check if profile exists
|
218 |
+
if not profile_manager.get_profile(username):
|
219 |
+
return {'error': 'Profile not found', 'status': 404}
|
220 |
+
|
221 |
+
# Attempt to update profile
|
222 |
+
if profile_manager.update_profile(username, updates):
|
223 |
+
return {'message': 'Profile updated successfully', 'status': 200}
|
224 |
+
else:
|
225 |
+
return {'error': 'Failed to update profile', 'status': 500}
|
226 |
+
|
227 |
+
except Exception as e:
|
228 |
+
return {'error': f'Internal server error: {str(e)}', 'status': 500}
|