mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-01-01 20:27:02 -05:00
feat: Implement initial schema and add various API, service, and management command enhancements across the application.
This commit is contained in:
@@ -81,21 +81,15 @@ class AccountService:
|
||||
"""
|
||||
# Verify old password
|
||||
if not user.check_password(old_password):
|
||||
logger.warning(
|
||||
f"Password change failed: incorrect current password for user {user.id}"
|
||||
)
|
||||
return {
|
||||
'success': False,
|
||||
'message': "Current password is incorrect",
|
||||
'redirect_url': None
|
||||
}
|
||||
logger.warning(f"Password change failed: incorrect current password for user {user.id}")
|
||||
return {"success": False, "message": "Current password is incorrect", "redirect_url": None}
|
||||
|
||||
# Validate new password
|
||||
if not AccountService.validate_password(new_password):
|
||||
return {
|
||||
'success': False,
|
||||
'message': "Password must be at least 8 characters and contain uppercase, lowercase, and numbers",
|
||||
'redirect_url': None
|
||||
"success": False,
|
||||
"message": "Password must be at least 8 characters and contain uppercase, lowercase, and numbers",
|
||||
"redirect_url": None,
|
||||
}
|
||||
|
||||
# Update password
|
||||
@@ -111,9 +105,9 @@ class AccountService:
|
||||
logger.info(f"Password changed successfully for user {user.id}")
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'message': "Password changed successfully. Please check your email for confirmation.",
|
||||
'redirect_url': None
|
||||
"success": True,
|
||||
"message": "Password changed successfully. Please check your email for confirmation.",
|
||||
"redirect_url": None,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
@@ -125,9 +119,7 @@ class AccountService:
|
||||
"site_name": site.name,
|
||||
}
|
||||
|
||||
email_html = render_to_string(
|
||||
"accounts/email/password_change_confirmation.html", context
|
||||
)
|
||||
email_html = render_to_string("accounts/email/password_change_confirmation.html", context)
|
||||
|
||||
try:
|
||||
EmailService.send_email(
|
||||
@@ -166,26 +158,17 @@ class AccountService:
|
||||
}
|
||||
"""
|
||||
if not new_email:
|
||||
return {
|
||||
'success': False,
|
||||
'message': "New email is required"
|
||||
}
|
||||
return {"success": False, "message": "New email is required"}
|
||||
|
||||
# Check if email is already in use
|
||||
if User.objects.filter(email=new_email).exclude(id=user.id).exists():
|
||||
return {
|
||||
'success': False,
|
||||
'message': "This email address is already in use"
|
||||
}
|
||||
return {"success": False, "message": "This email address is already in use"}
|
||||
|
||||
# Generate verification token
|
||||
token = get_random_string(64)
|
||||
|
||||
# Create or update email verification record
|
||||
EmailVerification.objects.update_or_create(
|
||||
user=user,
|
||||
defaults={"token": token}
|
||||
)
|
||||
EmailVerification.objects.update_or_create(user=user, defaults={"token": token})
|
||||
|
||||
# Store pending email
|
||||
user.pending_email = new_email
|
||||
@@ -196,18 +179,10 @@ class AccountService:
|
||||
|
||||
logger.info(f"Email change initiated for user {user.id} to {new_email}")
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'message': "Verification email sent to your new email address"
|
||||
}
|
||||
return {"success": True, "message": "Verification email sent to your new email address"}
|
||||
|
||||
@staticmethod
|
||||
def _send_email_verification(
|
||||
request: HttpRequest,
|
||||
user: User,
|
||||
new_email: str,
|
||||
token: str
|
||||
) -> None:
|
||||
def _send_email_verification(request: HttpRequest, user: User, new_email: str, token: str) -> None:
|
||||
"""Send email verification for email change."""
|
||||
from django.urls import reverse
|
||||
|
||||
@@ -245,22 +220,14 @@ class AccountService:
|
||||
Dictionary with success status and message
|
||||
"""
|
||||
try:
|
||||
verification = EmailVerification.objects.select_related("user").get(
|
||||
token=token
|
||||
)
|
||||
verification = EmailVerification.objects.select_related("user").get(token=token)
|
||||
except EmailVerification.DoesNotExist:
|
||||
return {
|
||||
'success': False,
|
||||
'message': "Invalid or expired verification token"
|
||||
}
|
||||
return {"success": False, "message": "Invalid or expired verification token"}
|
||||
|
||||
user = verification.user
|
||||
|
||||
if not user.pending_email:
|
||||
return {
|
||||
'success': False,
|
||||
'message': "No pending email change found"
|
||||
}
|
||||
return {"success": False, "message": "No pending email change found"}
|
||||
|
||||
# Update email
|
||||
old_email = user.email
|
||||
@@ -273,10 +240,7 @@ class AccountService:
|
||||
|
||||
logger.info(f"Email changed for user {user.id} from {old_email} to {user.email}")
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'message': "Email address updated successfully"
|
||||
}
|
||||
return {"success": True, "message": "Email address updated successfully"}
|
||||
|
||||
|
||||
class UserDeletionService:
|
||||
@@ -337,39 +301,17 @@ class UserDeletionService:
|
||||
|
||||
# Count submissions before transfer
|
||||
submission_counts = {
|
||||
"park_reviews": getattr(
|
||||
user, "park_reviews", user.__class__.objects.none()
|
||||
).count(),
|
||||
"ride_reviews": getattr(
|
||||
user, "ride_reviews", user.__class__.objects.none()
|
||||
).count(),
|
||||
"uploaded_park_photos": getattr(
|
||||
user, "uploaded_park_photos", user.__class__.objects.none()
|
||||
).count(),
|
||||
"uploaded_ride_photos": getattr(
|
||||
user, "uploaded_ride_photos", user.__class__.objects.none()
|
||||
).count(),
|
||||
"top_lists": getattr(
|
||||
user, "top_lists", user.__class__.objects.none()
|
||||
).count(),
|
||||
"edit_submissions": getattr(
|
||||
user, "edit_submissions", user.__class__.objects.none()
|
||||
).count(),
|
||||
"photo_submissions": getattr(
|
||||
user, "photo_submissions", user.__class__.objects.none()
|
||||
).count(),
|
||||
"moderated_park_reviews": getattr(
|
||||
user, "moderated_park_reviews", user.__class__.objects.none()
|
||||
).count(),
|
||||
"moderated_ride_reviews": getattr(
|
||||
user, "moderated_ride_reviews", user.__class__.objects.none()
|
||||
).count(),
|
||||
"handled_submissions": getattr(
|
||||
user, "handled_submissions", user.__class__.objects.none()
|
||||
).count(),
|
||||
"handled_photos": getattr(
|
||||
user, "handled_photos", user.__class__.objects.none()
|
||||
).count(),
|
||||
"park_reviews": getattr(user, "park_reviews", user.__class__.objects.none()).count(),
|
||||
"ride_reviews": getattr(user, "ride_reviews", user.__class__.objects.none()).count(),
|
||||
"uploaded_park_photos": getattr(user, "uploaded_park_photos", user.__class__.objects.none()).count(),
|
||||
"uploaded_ride_photos": getattr(user, "uploaded_ride_photos", user.__class__.objects.none()).count(),
|
||||
"top_lists": getattr(user, "top_lists", user.__class__.objects.none()).count(),
|
||||
"edit_submissions": getattr(user, "edit_submissions", user.__class__.objects.none()).count(),
|
||||
"photo_submissions": getattr(user, "photo_submissions", user.__class__.objects.none()).count(),
|
||||
"moderated_park_reviews": getattr(user, "moderated_park_reviews", user.__class__.objects.none()).count(),
|
||||
"moderated_ride_reviews": getattr(user, "moderated_ride_reviews", user.__class__.objects.none()).count(),
|
||||
"handled_submissions": getattr(user, "handled_submissions", user.__class__.objects.none()).count(),
|
||||
"handled_photos": getattr(user, "handled_photos", user.__class__.objects.none()).count(),
|
||||
}
|
||||
|
||||
# Transfer all submissions to deleted user
|
||||
@@ -440,11 +382,17 @@ class UserDeletionService:
|
||||
return False, "Cannot delete the system deleted user placeholder"
|
||||
|
||||
if user.is_superuser:
|
||||
return False, "Superuser accounts cannot be deleted for security reasons. Please contact system administrator or remove superuser privileges first."
|
||||
return (
|
||||
False,
|
||||
"Superuser accounts cannot be deleted for security reasons. Please contact system administrator or remove superuser privileges first.",
|
||||
)
|
||||
|
||||
# Check if user has critical admin role
|
||||
if user.role == User.Roles.ADMIN and user.is_staff:
|
||||
return False, "Admin accounts with staff privileges cannot be deleted. Please remove admin privileges first or contact system administrator."
|
||||
return (
|
||||
False,
|
||||
"Admin accounts with staff privileges cannot be deleted. Please remove admin privileges first or contact system administrator.",
|
||||
)
|
||||
|
||||
# Add any other business rules here
|
||||
|
||||
@@ -492,9 +440,7 @@ class UserDeletionService:
|
||||
site = Site.objects.get_current()
|
||||
except Site.DoesNotExist:
|
||||
# Fallback to default site
|
||||
site = Site.objects.get_or_create(
|
||||
id=1, defaults={"domain": "localhost:8000", "name": "localhost:8000"}
|
||||
)[0]
|
||||
site = Site.objects.get_or_create(id=1, defaults={"domain": "localhost:8000", "name": "localhost:8000"})[0]
|
||||
|
||||
# Prepare email context
|
||||
context = {
|
||||
@@ -502,9 +448,7 @@ class UserDeletionService:
|
||||
"verification_code": deletion_request.verification_code,
|
||||
"expires_at": deletion_request.expires_at,
|
||||
"site_name": getattr(settings, "SITE_NAME", "ThrillWiki"),
|
||||
"frontend_domain": getattr(
|
||||
settings, "FRONTEND_DOMAIN", "http://localhost:3000"
|
||||
),
|
||||
"frontend_domain": getattr(settings, "FRONTEND_DOMAIN", "http://localhost:3000"),
|
||||
}
|
||||
|
||||
# Render email content
|
||||
@@ -564,11 +508,9 @@ The ThrillWiki Team
|
||||
ValueError: If verification fails
|
||||
"""
|
||||
try:
|
||||
deletion_request = UserDeletionRequest.objects.get(
|
||||
verification_code=verification_code
|
||||
)
|
||||
deletion_request = UserDeletionRequest.objects.get(verification_code=verification_code)
|
||||
except UserDeletionRequest.DoesNotExist:
|
||||
raise ValueError("Invalid verification code")
|
||||
raise ValueError("Invalid verification code") from None
|
||||
|
||||
# Check if request is still valid
|
||||
if not deletion_request.is_valid():
|
||||
|
||||
Reference in New Issue
Block a user