mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 08:31:08 -05:00
remove backend
This commit is contained in:
41
apps/accounts/management/commands/check_all_social_tables.py
Normal file
41
apps/accounts/management/commands/check_all_social_tables.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from allauth.socialaccount.models import SocialApp, SocialAccount, SocialToken
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Check all social auth related tables"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Check SocialApp
|
||||
self.stdout.write("\nChecking SocialApp table:")
|
||||
for app in SocialApp.objects.all():
|
||||
self.stdout.write(
|
||||
f"ID: {app.pk}, Provider: {app.provider}, Name: {app.name}, Client ID: {
|
||||
app.client_id
|
||||
}"
|
||||
)
|
||||
self.stdout.write("Sites:")
|
||||
for site in app.sites.all():
|
||||
self.stdout.write(f" - {site.domain}")
|
||||
|
||||
# Check SocialAccount
|
||||
self.stdout.write("\nChecking SocialAccount table:")
|
||||
for account in SocialAccount.objects.all():
|
||||
self.stdout.write(
|
||||
f"ID: {account.pk}, Provider: {account.provider}, UID: {account.uid}"
|
||||
)
|
||||
|
||||
# Check SocialToken
|
||||
self.stdout.write("\nChecking SocialToken table:")
|
||||
for token in SocialToken.objects.all():
|
||||
self.stdout.write(
|
||||
f"ID: {token.pk}, Account: {token.account}, App: {token.app}"
|
||||
)
|
||||
|
||||
# Check Site
|
||||
self.stdout.write("\nChecking Site table:")
|
||||
for site in Site.objects.all():
|
||||
self.stdout.write(
|
||||
f"ID: {site.pk}, Domain: {site.domain}, Name: {site.name}"
|
||||
)
|
||||
22
apps/accounts/management/commands/check_social_apps.py
Normal file
22
apps/accounts/management/commands/check_social_apps.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Check social app configurations"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
social_apps = SocialApp.objects.all()
|
||||
|
||||
if not social_apps:
|
||||
self.stdout.write(self.style.ERROR("No social apps found"))
|
||||
return
|
||||
|
||||
for app in social_apps:
|
||||
self.stdout.write(self.style.SUCCESS(f"\nProvider: {app.provider}"))
|
||||
self.stdout.write(f"Name: {app.name}")
|
||||
self.stdout.write(f"Client ID: {app.client_id}")
|
||||
self.stdout.write(f"Secret: {app.secret}")
|
||||
self.stdout.write(
|
||||
f"Sites: {', '.join(str(site.domain) for site in app.sites.all())}"
|
||||
)
|
||||
28
apps/accounts/management/commands/cleanup_social_auth.py
Normal file
28
apps/accounts/management/commands/cleanup_social_auth.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import connection
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Clean up social auth tables and migrations"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
with connection.cursor() as cursor:
|
||||
# Drop social auth tables
|
||||
cursor.execute("DROP TABLE IF EXISTS socialaccount_socialapp")
|
||||
cursor.execute("DROP TABLE IF EXISTS socialaccount_socialapp_sites")
|
||||
cursor.execute("DROP TABLE IF EXISTS socialaccount_socialaccount")
|
||||
cursor.execute("DROP TABLE IF EXISTS socialaccount_socialtoken")
|
||||
|
||||
# Remove migration records
|
||||
cursor.execute("DELETE FROM django_migrations WHERE app='socialaccount'")
|
||||
cursor.execute(
|
||||
"DELETE FROM django_migrations WHERE app='accounts' "
|
||||
"AND name LIKE '%social%'"
|
||||
)
|
||||
|
||||
# Reset sequences
|
||||
cursor.execute("DELETE FROM sqlite_sequence WHERE name LIKE '%social%'")
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS("Successfully cleaned up social auth configuration")
|
||||
)
|
||||
75
apps/accounts/management/commands/cleanup_test_data.py
Normal file
75
apps/accounts/management/commands/cleanup_test_data.py
Normal file
@@ -0,0 +1,75 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth import get_user_model
|
||||
from apps.parks.models import ParkReview, Park, ParkPhoto
|
||||
from apps.rides.models import Ride, RidePhoto
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Cleans up test users and data created during e2e testing"
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
# Delete test users
|
||||
test_users = User.objects.filter(username__in=["testuser", "moderator"])
|
||||
count = test_users.count()
|
||||
test_users.delete()
|
||||
self.stdout.write(self.style.SUCCESS(f"Deleted {count} test users"))
|
||||
|
||||
# Delete test reviews
|
||||
reviews = ParkReview.objects.filter(
|
||||
user__username__in=["testuser", "moderator"]
|
||||
)
|
||||
count = reviews.count()
|
||||
reviews.delete()
|
||||
self.stdout.write(self.style.SUCCESS(f"Deleted {count} test reviews"))
|
||||
|
||||
# Delete test photos - both park and ride photos
|
||||
park_photos = ParkPhoto.objects.filter(
|
||||
uploader__username__in=["testuser", "moderator"]
|
||||
)
|
||||
park_count = park_photos.count()
|
||||
park_photos.delete()
|
||||
self.stdout.write(self.style.SUCCESS(f"Deleted {park_count} test park photos"))
|
||||
|
||||
ride_photos = RidePhoto.objects.filter(
|
||||
uploader__username__in=["testuser", "moderator"]
|
||||
)
|
||||
ride_count = ride_photos.count()
|
||||
ride_photos.delete()
|
||||
self.stdout.write(self.style.SUCCESS(f"Deleted {ride_count} test ride photos"))
|
||||
|
||||
# Delete test parks
|
||||
parks = Park.objects.filter(name__startswith="Test Park")
|
||||
count = parks.count()
|
||||
parks.delete()
|
||||
self.stdout.write(self.style.SUCCESS(f"Deleted {count} test parks"))
|
||||
|
||||
# Delete test rides
|
||||
rides = Ride.objects.filter(name__startswith="Test Ride")
|
||||
count = rides.count()
|
||||
rides.delete()
|
||||
self.stdout.write(self.style.SUCCESS(f"Deleted {count} test rides"))
|
||||
|
||||
# Clean up test files
|
||||
import os
|
||||
import glob
|
||||
|
||||
# Clean up test uploads
|
||||
media_patterns = [
|
||||
"media/uploads/test_*",
|
||||
"media/avatars/test_*",
|
||||
"media/park/test_*",
|
||||
"media/rides/test_*",
|
||||
]
|
||||
|
||||
for pattern in media_patterns:
|
||||
files = glob.glob(pattern)
|
||||
for f in files:
|
||||
try:
|
||||
os.remove(f)
|
||||
self.stdout.write(self.style.SUCCESS(f"Deleted {f}"))
|
||||
except OSError as e:
|
||||
self.stdout.write(self.style.WARNING(f"Error deleting {f}: {e}"))
|
||||
|
||||
self.stdout.write(self.style.SUCCESS("Test data cleanup complete"))
|
||||
55
apps/accounts/management/commands/create_social_apps.py
Normal file
55
apps/accounts/management/commands/create_social_apps.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.sites.models import Site
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Create social apps for authentication"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Get the default site
|
||||
site = Site.objects.get_or_create(
|
||||
id=1,
|
||||
defaults={
|
||||
"domain": "localhost:8000",
|
||||
"name": "ThrillWiki Development",
|
||||
},
|
||||
)[0]
|
||||
|
||||
# Create Discord app
|
||||
discord_app, created = SocialApp.objects.get_or_create(
|
||||
provider="discord",
|
||||
defaults={
|
||||
"name": "Discord",
|
||||
"client_id": "1299112802274902047",
|
||||
"secret": "ece7Pe_M4mD4mYzAgcINjTEKL_3ftL11",
|
||||
},
|
||||
)
|
||||
if not created:
|
||||
discord_app.client_id = "1299112802274902047"
|
||||
discord_app.secret = "ece7Pe_M4mD4mYzAgcINjTEKL_3ftL11"
|
||||
discord_app.save()
|
||||
discord_app.sites.add(site)
|
||||
self.stdout.write(f"{'Created' if created else 'Updated'} Discord app")
|
||||
|
||||
# Create Google app
|
||||
google_app, created = SocialApp.objects.get_or_create(
|
||||
provider="google",
|
||||
defaults={
|
||||
"name": "Google",
|
||||
"client_id": (
|
||||
"135166769591-nopcgmo0fkqfqfs9qe783a137mtmcrt2."
|
||||
"apps.googleusercontent.com"
|
||||
),
|
||||
"secret": "GOCSPX-Wd_0Ue0Ue0Ue0Ue0Ue0Ue0Ue0Ue",
|
||||
},
|
||||
)
|
||||
if not created:
|
||||
google_app.client_id = (
|
||||
"135166769591-nopcgmo0fkqfqfs9qe783a137mtmcrt2."
|
||||
"apps.googleusercontent.com"
|
||||
)
|
||||
google_app.secret = "GOCSPX-Wd_0Ue0Ue0Ue0Ue0Ue0Ue0Ue0Ue"
|
||||
google_app.save()
|
||||
google_app.sites.add(site)
|
||||
self.stdout.write(f"{'Created' if created else 'Updated'} Google app")
|
||||
58
apps/accounts/management/commands/create_test_users.py
Normal file
58
apps/accounts/management/commands/create_test_users.py
Normal file
@@ -0,0 +1,58 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth.models import Group, Permission, User
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Creates test users for e2e testing"
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
# Create regular test user
|
||||
if not User.objects.filter(username="testuser").exists():
|
||||
user = User.objects.create(
|
||||
username="testuser",
|
||||
email="testuser@example.com",
|
||||
)
|
||||
user.set_password("testpass123")
|
||||
user.save()
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f"Created test user: {user.get_username()}")
|
||||
)
|
||||
else:
|
||||
self.stdout.write(self.style.WARNING("Test user already exists"))
|
||||
|
||||
if not User.objects.filter(username="moderator").exists():
|
||||
moderator = User.objects.create(
|
||||
username="moderator",
|
||||
email="moderator@example.com",
|
||||
)
|
||||
moderator.set_password("modpass123")
|
||||
moderator.save()
|
||||
|
||||
# Create moderator group if it doesn't exist
|
||||
moderator_group, created = Group.objects.get_or_create(name="Moderators")
|
||||
|
||||
# Add relevant permissions
|
||||
permissions = Permission.objects.filter(
|
||||
codename__in=[
|
||||
"change_review",
|
||||
"delete_review",
|
||||
"change_park",
|
||||
"change_ride",
|
||||
"moderate_photos",
|
||||
"moderate_comments",
|
||||
]
|
||||
)
|
||||
moderator_group.permissions.add(*permissions)
|
||||
|
||||
# Add user to moderator group
|
||||
moderator.groups.add(moderator_group)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
f"Created moderator user: {moderator.get_username()}"
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.stdout.write(self.style.WARNING("Moderator user already exists"))
|
||||
|
||||
self.stdout.write(self.style.SUCCESS("Test users setup complete"))
|
||||
164
apps/accounts/management/commands/delete_user.py
Normal file
164
apps/accounts/management/commands/delete_user.py
Normal file
@@ -0,0 +1,164 @@
|
||||
"""
|
||||
Django management command to delete a user while preserving their submissions.
|
||||
|
||||
Usage:
|
||||
uv run manage.py delete_user <username>
|
||||
uv run manage.py delete_user --user-id <user_id>
|
||||
uv run manage.py delete_user <username> --dry-run
|
||||
"""
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from apps.accounts.models import User
|
||||
from apps.accounts.services import UserDeletionService
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Delete a user while preserving all their submissions"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
"username", nargs="?", type=str, help="Username of the user to delete"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--user-id",
|
||||
type=str,
|
||||
help="User ID of the user to delete (alternative to username)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="Show what would be deleted without actually deleting",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--force", action="store_true", help="Skip confirmation prompt"
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
username = options.get("username")
|
||||
user_id = options.get("user_id")
|
||||
dry_run = options.get("dry_run", False)
|
||||
force = options.get("force", False)
|
||||
|
||||
# Validate arguments
|
||||
if not username and not user_id:
|
||||
raise CommandError("You must provide either a username or --user-id")
|
||||
|
||||
if username and user_id:
|
||||
raise CommandError("You cannot provide both username and --user-id")
|
||||
|
||||
# Find the user
|
||||
try:
|
||||
if username:
|
||||
user = User.objects.get(username=username)
|
||||
else:
|
||||
user = User.objects.get(user_id=user_id)
|
||||
except User.DoesNotExist:
|
||||
identifier = username or user_id
|
||||
raise CommandError(f'User "{identifier}" does not exist')
|
||||
|
||||
# Check if user can be deleted
|
||||
can_delete, reason = UserDeletionService.can_delete_user(user)
|
||||
if not can_delete:
|
||||
raise CommandError(f"Cannot delete user: {reason}")
|
||||
|
||||
# Count submissions
|
||||
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(),
|
||||
}
|
||||
|
||||
total_submissions = sum(submission_counts.values())
|
||||
|
||||
# Display user information
|
||||
self.stdout.write(self.style.WARNING("\nUser Information:"))
|
||||
self.stdout.write(f" Username: {user.username}")
|
||||
self.stdout.write(f" User ID: {user.user_id}")
|
||||
self.stdout.write(f" Email: {user.email}")
|
||||
self.stdout.write(f" Date Joined: {user.date_joined}")
|
||||
self.stdout.write(f" Role: {user.role}")
|
||||
|
||||
# Display submission counts
|
||||
self.stdout.write(self.style.WARNING("\nSubmissions to preserve:"))
|
||||
for submission_type, count in submission_counts.items():
|
||||
if count > 0:
|
||||
self.stdout.write(
|
||||
f' {submission_type.replace("_", " ").title()}: {count}'
|
||||
)
|
||||
|
||||
self.stdout.write(f"\nTotal submissions: {total_submissions}")
|
||||
|
||||
if total_submissions > 0:
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
f'\nAll {total_submissions} submissions will be transferred to the "deleted_user" placeholder.'
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.stdout.write(
|
||||
self.style.WARNING("\nNo submissions found for this user.")
|
||||
)
|
||||
|
||||
if dry_run:
|
||||
self.stdout.write(self.style.SUCCESS("\n[DRY RUN] No changes were made."))
|
||||
return
|
||||
|
||||
# Confirmation prompt
|
||||
if not force:
|
||||
self.stdout.write(
|
||||
self.style.WARNING(
|
||||
f'\nThis will permanently delete the user "{user.username}" '
|
||||
f"but preserve all {total_submissions} submissions."
|
||||
)
|
||||
)
|
||||
confirm = input("Are you sure you want to continue? (yes/no): ")
|
||||
if confirm.lower() not in ["yes", "y"]:
|
||||
self.stdout.write(self.style.ERROR("Operation cancelled."))
|
||||
return
|
||||
|
||||
# Perform the deletion
|
||||
try:
|
||||
result = UserDeletionService.delete_user_preserve_submissions(user)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
f'\nSuccessfully deleted user "{result["deleted_user"]["username"]}"'
|
||||
)
|
||||
)
|
||||
|
||||
preserved_count = sum(result["preserved_submissions"].values())
|
||||
if preserved_count > 0:
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
f'Preserved {preserved_count} submissions under user "{result["transferred_to"]["username"]}"'
|
||||
)
|
||||
)
|
||||
|
||||
# Show detailed preservation summary
|
||||
self.stdout.write(self.style.WARNING("\nPreservation Summary:"))
|
||||
for submission_type, count in result["preserved_submissions"].items():
|
||||
if count > 0:
|
||||
self.stdout.write(
|
||||
f' {submission_type.replace("_", " ").title()}: {count}'
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
raise CommandError(f"Error deleting user: {str(e)}")
|
||||
18
apps/accounts/management/commands/fix_migration_history.py
Normal file
18
apps/accounts/management/commands/fix_migration_history.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import connection
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Fix migration history by removing rides.0001_initial"
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"DELETE FROM django_migrations WHERE app='rides' "
|
||||
"AND name='0001_initial';"
|
||||
)
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
"Successfully removed rides.0001_initial from migration history"
|
||||
)
|
||||
)
|
||||
38
apps/accounts/management/commands/fix_social_apps.py
Normal file
38
apps/accounts/management/commands/fix_social_apps.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
from django.contrib.sites.models import Site
|
||||
import os
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Fix social app configurations"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Delete all existing social apps
|
||||
SocialApp.objects.all().delete()
|
||||
self.stdout.write("Deleted all existing social apps")
|
||||
|
||||
# Get the default site
|
||||
site = Site.objects.get(id=1)
|
||||
|
||||
# Create Google provider
|
||||
google_app = SocialApp.objects.create(
|
||||
provider="google",
|
||||
name="Google",
|
||||
client_id=os.getenv("GOOGLE_CLIENT_ID"),
|
||||
secret=os.getenv("GOOGLE_CLIENT_SECRET"),
|
||||
)
|
||||
google_app.sites.add(site)
|
||||
self.stdout.write(f"Created Google app with client_id: {google_app.client_id}")
|
||||
|
||||
# Create Discord provider
|
||||
discord_app = SocialApp.objects.create(
|
||||
provider="discord",
|
||||
name="Discord",
|
||||
client_id=os.getenv("DISCORD_CLIENT_ID"),
|
||||
secret=os.getenv("DISCORD_CLIENT_SECRET"),
|
||||
)
|
||||
discord_app.sites.add(site)
|
||||
self.stdout.write(
|
||||
f"Created Discord app with client_id: {discord_app.client_id}"
|
||||
)
|
||||
54
apps/accounts/management/commands/generate_letter_avatars.py
Normal file
54
apps/accounts/management/commands/generate_letter_avatars.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import os
|
||||
|
||||
|
||||
def generate_avatar(letter):
|
||||
"""Generate an avatar for a given letter or number"""
|
||||
avatar_size = (100, 100)
|
||||
background_color = (0, 123, 255) # Blue background
|
||||
text_color = (255, 255, 255) # White text
|
||||
font_size = 100
|
||||
|
||||
# Create a blank image with background color
|
||||
image = Image.new("RGB", avatar_size, background_color)
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
# Load a font
|
||||
font_path = "[AWS-SECRET-REMOVED]ans-Bold.ttf"
|
||||
font = ImageFont.truetype(font_path, font_size)
|
||||
|
||||
# Calculate text size and position using textbbox
|
||||
text_bbox = draw.textbbox((0, 0), letter, font=font)
|
||||
text_width, text_height = (
|
||||
text_bbox[2] - text_bbox[0],
|
||||
text_bbox[3] - text_bbox[1],
|
||||
)
|
||||
text_position = (
|
||||
(avatar_size[0] - text_width) / 2,
|
||||
(avatar_size[1] - text_height) / 2,
|
||||
)
|
||||
|
||||
# Draw the text on the image
|
||||
draw.text(text_position, letter, font=font, fill=text_color)
|
||||
|
||||
# Ensure the avatars directory exists
|
||||
avatar_dir = "avatars/letters"
|
||||
if not os.path.exists(avatar_dir):
|
||||
os.makedirs(avatar_dir)
|
||||
|
||||
# Save the image to the avatars directory
|
||||
avatar_path = os.path.join(avatar_dir, f"{letter}_avatar.png")
|
||||
image.save(avatar_path)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Generate avatars for letters A-Z and numbers 0-9"
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
characters = [chr(i) for i in range(65, 91)] + [
|
||||
str(i) for i in range(10)
|
||||
] # A-Z and 0-9
|
||||
for char in characters:
|
||||
generate_avatar(char)
|
||||
self.stdout.write(self.style.SUCCESS(f"Generated avatar for {char}"))
|
||||
15
apps/accounts/management/commands/regenerate_avatars.py
Normal file
15
apps/accounts/management/commands/regenerate_avatars.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from apps.accounts.models import UserProfile
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Regenerate default avatars for users without an uploaded avatar"
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
profiles = UserProfile.objects.filter(avatar="")
|
||||
for profile in profiles:
|
||||
# This will trigger the avatar generation logic in the save method
|
||||
profile.save()
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f"Regenerated avatar for {profile.user.username}")
|
||||
)
|
||||
108
apps/accounts/management/commands/reset_db.py
Normal file
108
apps/accounts/management/commands/reset_db.py
Normal file
@@ -0,0 +1,108 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import connection
|
||||
from django.contrib.auth.hashers import make_password
|
||||
import uuid
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Reset database and create admin user"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.stdout.write("Resetting database...")
|
||||
|
||||
# Drop all tables
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
DO $$ DECLARE
|
||||
r RECORD;
|
||||
BEGIN
|
||||
FOR r IN (
|
||||
SELECT tablename FROM pg_tables
|
||||
WHERE schemaname = current_schema()
|
||||
) LOOP
|
||||
EXECUTE 'DROP TABLE IF EXISTS ' || \
|
||||
quote_ident(r.tablename) || ' CASCADE';
|
||||
END LOOP;
|
||||
END $$;
|
||||
"""
|
||||
)
|
||||
|
||||
# Reset sequences
|
||||
cursor.execute(
|
||||
"""
|
||||
DO $$ DECLARE
|
||||
r RECORD;
|
||||
BEGIN
|
||||
FOR r IN (
|
||||
SELECT sequencename FROM pg_sequences
|
||||
WHERE schemaname = current_schema()
|
||||
) LOOP
|
||||
EXECUTE 'ALTER SEQUENCE ' || \
|
||||
quote_ident(r.sequencename) || ' RESTART WITH 1';
|
||||
END LOOP;
|
||||
END $$;
|
||||
"""
|
||||
)
|
||||
|
||||
self.stdout.write("All tables dropped and sequences reset.")
|
||||
|
||||
# Run migrations
|
||||
from django.core.management import call_command
|
||||
|
||||
call_command("migrate")
|
||||
|
||||
self.stdout.write("Migrations applied.")
|
||||
|
||||
# Create superuser using raw SQL
|
||||
try:
|
||||
with connection.cursor() as cursor:
|
||||
# Create user
|
||||
user_id = str(uuid.uuid4())[:10]
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO accounts_user (
|
||||
username, password, email, is_superuser, is_staff,
|
||||
is_active, date_joined, user_id, first_name,
|
||||
last_name, role, is_banned, ban_reason,
|
||||
theme_preference
|
||||
) VALUES (
|
||||
'admin', %s, 'admin@thrillwiki.com', true, true,
|
||||
true, NOW(), %s, '', '', 'SUPERUSER', false, '',
|
||||
'light'
|
||||
) RETURNING id;
|
||||
""",
|
||||
[make_password("admin"), user_id],
|
||||
)
|
||||
|
||||
result = cursor.fetchone()
|
||||
if result is None:
|
||||
raise Exception("Failed to create user - no ID returned")
|
||||
user_db_id = result[0]
|
||||
|
||||
# Create profile
|
||||
profile_id = str(uuid.uuid4())[:10]
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO accounts_userprofile (
|
||||
profile_id, display_name, pronouns, bio,
|
||||
twitter, instagram, youtube, discord,
|
||||
coaster_credits, dark_ride_credits,
|
||||
flat_ride_credits, water_ride_credits,
|
||||
user_id, avatar
|
||||
) VALUES (
|
||||
%s, 'Admin', 'they/them', 'ThrillWiki Administrator',
|
||||
'', '', '', '',
|
||||
0, 0, 0, 0,
|
||||
%s, ''
|
||||
);
|
||||
""",
|
||||
[profile_id, user_db_id],
|
||||
)
|
||||
|
||||
self.stdout.write("Superuser created.")
|
||||
except Exception as e:
|
||||
self.stdout.write(self.style.ERROR(f"Error creating superuser: {str(e)}"))
|
||||
raise
|
||||
|
||||
self.stdout.write(self.style.SUCCESS("Database reset complete."))
|
||||
39
apps/accounts/management/commands/reset_social_apps.py
Normal file
39
apps/accounts/management/commands/reset_social_apps.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
from django.contrib.sites.models import Site
|
||||
from django.db import connection
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Reset social apps configuration"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Delete all social apps using raw SQL to bypass Django's ORM
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute("DELETE FROM socialaccount_socialapp_sites")
|
||||
cursor.execute("DELETE FROM socialaccount_socialapp")
|
||||
|
||||
# Get the default site
|
||||
site = Site.objects.get(id=1)
|
||||
|
||||
# Create Discord app
|
||||
discord_app = SocialApp.objects.create(
|
||||
provider="discord",
|
||||
name="Discord",
|
||||
client_id="1299112802274902047",
|
||||
secret="ece7Pe_M4mD4mYzAgcINjTEKL_3ftL11",
|
||||
)
|
||||
discord_app.sites.add(site)
|
||||
self.stdout.write(f"Created Discord app with ID: {discord_app.pk}")
|
||||
|
||||
# Create Google app
|
||||
google_app = SocialApp.objects.create(
|
||||
provider="google",
|
||||
name="Google",
|
||||
client_id=(
|
||||
"135166769591-nopcgmo0fkqfqfs9qe783a137mtmcrt2.apps.googleusercontent.com"
|
||||
),
|
||||
secret="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",
|
||||
)
|
||||
google_app.sites.add(site)
|
||||
self.stdout.write(f"Created Google app with ID: {google_app.pk}")
|
||||
24
apps/accounts/management/commands/reset_social_auth.py
Normal file
24
apps/accounts/management/commands/reset_social_auth.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import connection
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Reset social auth configuration"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
with connection.cursor() as cursor:
|
||||
# Delete all social apps
|
||||
cursor.execute("DELETE FROM socialaccount_socialapp")
|
||||
cursor.execute("DELETE FROM socialaccount_socialapp_sites")
|
||||
|
||||
# Reset sequences
|
||||
cursor.execute(
|
||||
"DELETE FROM sqlite_sequence WHERE name='socialaccount_socialapp'"
|
||||
)
|
||||
cursor.execute(
|
||||
"DELETE FROM sqlite_sequence WHERE name='socialaccount_socialapp_sites'"
|
||||
)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS("Successfully reset social auth configuration")
|
||||
)
|
||||
44
apps/accounts/management/commands/setup_groups.py
Normal file
44
apps/accounts/management/commands/setup_groups.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth.models import Group
|
||||
from apps.accounts.models import User
|
||||
from apps.accounts.signals import create_default_groups
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Set up default groups and permissions for user roles"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.stdout.write("Creating default groups and permissions...")
|
||||
|
||||
try:
|
||||
# Create default groups with permissions
|
||||
create_default_groups()
|
||||
|
||||
# Sync existing users with groups based on their roles
|
||||
users = User.objects.exclude(role=User.Roles.USER)
|
||||
for user in users:
|
||||
group = Group.objects.filter(name=user.role).first()
|
||||
if group:
|
||||
user.groups.add(group)
|
||||
|
||||
# Update staff/superuser status based on role
|
||||
if user.role == User.Roles.SUPERUSER:
|
||||
user.is_superuser = True
|
||||
user.is_staff = True
|
||||
elif user.role in [User.Roles.ADMIN, User.Roles.MODERATOR]:
|
||||
user.is_staff = True
|
||||
user.save()
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS("Successfully set up groups and permissions")
|
||||
)
|
||||
|
||||
# Print summary
|
||||
for group in Group.objects.all():
|
||||
self.stdout.write(f"\nGroup: {group.name}")
|
||||
self.stdout.write("Permissions:")
|
||||
for perm in group.permissions.all():
|
||||
self.stdout.write(f" - {perm.codename}")
|
||||
|
||||
except Exception as e:
|
||||
self.stdout.write(self.style.ERROR(f"Error setting up groups: {str(e)}"))
|
||||
16
apps/accounts/management/commands/setup_site.py
Normal file
16
apps/accounts/management/commands/setup_site.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Set up default site"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Delete any existing sites
|
||||
Site.objects.all().delete()
|
||||
|
||||
# Create default site
|
||||
site = Site.objects.create(
|
||||
id=1, domain="localhost:8000", name="ThrillWiki Development"
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS(f"Created site: {site.domain}"))
|
||||
129
apps/accounts/management/commands/setup_social_auth.py
Normal file
129
apps/accounts/management/commands/setup_social_auth.py
Normal file
@@ -0,0 +1,129 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.sites.models import Site
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Sets up social authentication apps"
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
# Load environment variables
|
||||
load_dotenv()
|
||||
|
||||
# Get environment variables
|
||||
google_client_id = os.getenv("GOOGLE_CLIENT_ID")
|
||||
google_client_secret = os.getenv("GOOGLE_CLIENT_SECRET")
|
||||
discord_client_id = os.getenv("DISCORD_CLIENT_ID")
|
||||
discord_client_secret = os.getenv("DISCORD_CLIENT_SECRET")
|
||||
|
||||
# DEBUG: Log environment variable values
|
||||
self.stdout.write(
|
||||
f"DEBUG: google_client_id type: {type(google_client_id)}, value: {
|
||||
google_client_id
|
||||
}"
|
||||
)
|
||||
self.stdout.write(
|
||||
f"DEBUG: google_client_secret type: {type(google_client_secret)}, value: {
|
||||
google_client_secret
|
||||
}"
|
||||
)
|
||||
self.stdout.write(
|
||||
f"DEBUG: discord_client_id type: {type(discord_client_id)}, value: {
|
||||
discord_client_id
|
||||
}"
|
||||
)
|
||||
self.stdout.write(
|
||||
f"DEBUG: discord_client_secret type: {type(discord_client_secret)}, value: {
|
||||
discord_client_secret
|
||||
}"
|
||||
)
|
||||
|
||||
if not all(
|
||||
[
|
||||
google_client_id,
|
||||
google_client_secret,
|
||||
discord_client_id,
|
||||
discord_client_secret,
|
||||
]
|
||||
):
|
||||
self.stdout.write(
|
||||
self.style.ERROR("Missing required environment variables")
|
||||
)
|
||||
self.stdout.write(
|
||||
f"DEBUG: google_client_id is None: {google_client_id is None}"
|
||||
)
|
||||
self.stdout.write(
|
||||
f"DEBUG: google_client_secret is None: {google_client_secret is None}"
|
||||
)
|
||||
self.stdout.write(
|
||||
f"DEBUG: discord_client_id is None: {discord_client_id is None}"
|
||||
)
|
||||
self.stdout.write(
|
||||
f"DEBUG: discord_client_secret is None: {discord_client_secret is None}"
|
||||
)
|
||||
return
|
||||
|
||||
# Get or create the default site
|
||||
site, _ = Site.objects.get_or_create(
|
||||
id=1, defaults={"domain": "localhost:8000", "name": "localhost"}
|
||||
)
|
||||
|
||||
# Set up Google
|
||||
google_app, created = SocialApp.objects.get_or_create(
|
||||
provider="google",
|
||||
defaults={
|
||||
"name": "Google",
|
||||
"client_id": google_client_id,
|
||||
"secret": google_client_secret,
|
||||
},
|
||||
)
|
||||
if not created:
|
||||
self.stdout.write(
|
||||
f"DEBUG: About to assign google_client_id: {google_client_id} (type: {
|
||||
type(google_client_id)
|
||||
})"
|
||||
)
|
||||
if google_client_id is not None and google_client_secret is not None:
|
||||
google_app.client_id = google_client_id
|
||||
google_app.secret = google_client_secret
|
||||
google_app.save()
|
||||
self.stdout.write("DEBUG: Successfully updated Google app")
|
||||
else:
|
||||
self.stdout.write(
|
||||
self.style.ERROR(
|
||||
"Google client_id or secret is None, skipping update."
|
||||
)
|
||||
)
|
||||
google_app.sites.add(site)
|
||||
|
||||
# Set up Discord
|
||||
discord_app, created = SocialApp.objects.get_or_create(
|
||||
provider="discord",
|
||||
defaults={
|
||||
"name": "Discord",
|
||||
"client_id": discord_client_id,
|
||||
"secret": discord_client_secret,
|
||||
},
|
||||
)
|
||||
if not created:
|
||||
self.stdout.write(
|
||||
f"DEBUG: About to assign discord_client_id: {discord_client_id} (type: {
|
||||
type(discord_client_id)
|
||||
})"
|
||||
)
|
||||
if discord_client_id is not None and discord_client_secret is not None:
|
||||
discord_app.client_id = discord_client_id
|
||||
discord_app.secret = discord_client_secret
|
||||
discord_app.save()
|
||||
self.stdout.write("DEBUG: Successfully updated Discord app")
|
||||
else:
|
||||
self.stdout.write(
|
||||
self.style.ERROR(
|
||||
"Discord client_id or secret is None, skipping update."
|
||||
)
|
||||
)
|
||||
discord_app.sites.add(site)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS("Successfully set up social auth apps"))
|
||||
70
apps/accounts/management/commands/setup_social_auth_admin.py
Normal file
70
apps/accounts/management/commands/setup_social_auth_admin.py
Normal file
@@ -0,0 +1,70 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.sites.models import Site
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Set up social authentication through admin interface"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Get or create the default site
|
||||
site, _ = Site.objects.get_or_create(
|
||||
id=1,
|
||||
defaults={
|
||||
"domain": "localhost:8000",
|
||||
"name": "ThrillWiki Development",
|
||||
},
|
||||
)
|
||||
if not _:
|
||||
site.domain = "localhost:8000"
|
||||
site.name = "ThrillWiki Development"
|
||||
site.save()
|
||||
self.stdout.write(f"{'Created' if _ else 'Updated'} site: {site.domain}")
|
||||
|
||||
# Create superuser if it doesn't exist
|
||||
if not User.objects.filter(username="admin").exists():
|
||||
admin_user = User.objects.create(
|
||||
username="admin",
|
||||
email="admin@example.com",
|
||||
is_staff=True,
|
||||
is_superuser=True,
|
||||
)
|
||||
admin_user.set_password("admin")
|
||||
admin_user.save()
|
||||
self.stdout.write("Created superuser: admin/admin")
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
"""
|
||||
Social auth setup instructions:
|
||||
|
||||
1. Run the development server:
|
||||
uv run manage.py runserver_plus
|
||||
|
||||
2. Go to the admin interface:
|
||||
http://localhost:8000/admin/
|
||||
|
||||
3. Log in with:
|
||||
Username: admin
|
||||
Password: admin
|
||||
|
||||
4. Add social applications:
|
||||
- Go to "Social applications" under "Social Accounts"
|
||||
- Add Discord app:
|
||||
Provider: discord
|
||||
Name: Discord
|
||||
Client id: 1299112802274902047
|
||||
Secret key: ece7Pe_M4mD4mYzAgcINjTEKL_3ftL11
|
||||
Sites: Add "localhost:8000"
|
||||
|
||||
- Add Google app:
|
||||
Provider: google
|
||||
Name: Google
|
||||
Client id: 135166769591-nopcgmo0fkqfqfs9qe783a137mtmcrt2.apps.googleusercontent.com
|
||||
Secret key: GOCSPX-Wd_0Ue0Ue0Ue0Ue0Ue0Ue0Ue0Ue
|
||||
Sites: Add "localhost:8000"
|
||||
"""
|
||||
)
|
||||
)
|
||||
47
apps/accounts/management/commands/setup_social_providers.py
Normal file
47
apps/accounts/management/commands/setup_social_providers.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Set up social authentication providers for development"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Get the current site
|
||||
site = Site.objects.get_current()
|
||||
self.stdout.write(f"Setting up social providers for site: {site}")
|
||||
|
||||
# Clear existing social apps to avoid duplicates
|
||||
deleted_count = SocialApp.objects.all().delete()[0]
|
||||
self.stdout.write(f"Cleared {deleted_count} existing social apps")
|
||||
|
||||
# Create Google social app
|
||||
google_app = SocialApp.objects.create(
|
||||
provider="google",
|
||||
name="Google",
|
||||
client_id="demo-google-client-id.apps.googleusercontent.com",
|
||||
secret="demo-google-client-secret",
|
||||
key="",
|
||||
)
|
||||
google_app.sites.add(site)
|
||||
self.stdout.write(self.style.SUCCESS("✅ Created Google social app"))
|
||||
|
||||
# Create Discord social app
|
||||
discord_app = SocialApp.objects.create(
|
||||
provider="discord",
|
||||
name="Discord",
|
||||
client_id="demo-discord-client-id",
|
||||
secret="demo-discord-client-secret",
|
||||
key="",
|
||||
)
|
||||
discord_app.sites.add(site)
|
||||
self.stdout.write(self.style.SUCCESS("✅ Created Discord social app"))
|
||||
|
||||
# List all social apps
|
||||
self.stdout.write("\nConfigured social apps:")
|
||||
for app in SocialApp.objects.all():
|
||||
self.stdout.write(f"- {app.name} ({app.provider}): {app.client_id}")
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f"\nTotal social apps: {SocialApp.objects.count()}")
|
||||
)
|
||||
61
apps/accounts/management/commands/test_discord_auth.py
Normal file
61
apps/accounts/management/commands/test_discord_auth.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.test import Client
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Test Discord OAuth2 authentication flow"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
client = Client(HTTP_HOST="localhost:8000")
|
||||
|
||||
# Get Discord app
|
||||
try:
|
||||
discord_app = SocialApp.objects.get(provider="discord")
|
||||
self.stdout.write("Found Discord app configuration:")
|
||||
self.stdout.write(f"Client ID: {discord_app.client_id}")
|
||||
|
||||
# Test login URL
|
||||
login_url = "/accounts/discord/login/"
|
||||
response = client.get(login_url, HTTP_HOST="localhost:8000")
|
||||
self.stdout.write(f"\nTesting login URL: {login_url}")
|
||||
self.stdout.write(f"Status code: {response.status_code}")
|
||||
|
||||
if response.status_code == 302:
|
||||
redirect_url = response["Location"]
|
||||
self.stdout.write(f"Redirects to: {redirect_url}")
|
||||
|
||||
# Parse OAuth2 parameters
|
||||
self.stdout.write("\nOAuth2 Parameters:")
|
||||
if "client_id=" in redirect_url:
|
||||
self.stdout.write("✓ client_id parameter present")
|
||||
if "redirect_uri=" in redirect_url:
|
||||
self.stdout.write("✓ redirect_uri parameter present")
|
||||
if "scope=" in redirect_url:
|
||||
self.stdout.write("✓ scope parameter present")
|
||||
if "response_type=" in redirect_url:
|
||||
self.stdout.write("✓ response_type parameter present")
|
||||
if "code_challenge=" in redirect_url:
|
||||
self.stdout.write("✓ PKCE enabled (code_challenge present)")
|
||||
|
||||
# Show callback URL
|
||||
callback_url = "http://localhost:8000/accounts/discord/login/callback/"
|
||||
self.stdout.write(
|
||||
"\nCallback URL to configure in Discord Developer Portal:"
|
||||
)
|
||||
self.stdout.write(callback_url)
|
||||
|
||||
# Show frontend login URL
|
||||
frontend_url = "http://localhost:5173"
|
||||
self.stdout.write("\nFrontend configuration:")
|
||||
self.stdout.write(f"Frontend URL: {frontend_url}")
|
||||
self.stdout.write("Discord login button should use:")
|
||||
self.stdout.write("/accounts/discord/login/?process=login")
|
||||
|
||||
# Show allauth URLs
|
||||
self.stdout.write("\nAllauth URLs:")
|
||||
self.stdout.write("Login URL: /accounts/discord/login/?process=login")
|
||||
self.stdout.write("Callback URL: /accounts/discord/login/callback/")
|
||||
|
||||
except SocialApp.DoesNotExist:
|
||||
self.stdout.write(self.style.ERROR("Discord app not found"))
|
||||
@@ -0,0 +1,23 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Update social apps to be associated with all sites"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Get all sites
|
||||
sites = Site.objects.all()
|
||||
|
||||
# Update each social app
|
||||
for app in SocialApp.objects.all():
|
||||
self.stdout.write(f"Updating {app.provider} app...")
|
||||
# Clear existing sites
|
||||
app.sites.clear()
|
||||
# Add all sites
|
||||
for site in sites:
|
||||
app.sites.add(site)
|
||||
self.stdout.write(
|
||||
f"Added sites: {', '.join(site.domain for site in sites)}"
|
||||
)
|
||||
39
apps/accounts/management/commands/verify_discord_settings.py
Normal file
39
apps/accounts/management/commands/verify_discord_settings.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Verify Discord OAuth2 settings"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Get Discord app
|
||||
try:
|
||||
discord_app = SocialApp.objects.get(provider="discord")
|
||||
self.stdout.write("Found Discord app configuration:")
|
||||
self.stdout.write(f"Client ID: {discord_app.client_id}")
|
||||
self.stdout.write(f"Secret: {discord_app.secret}")
|
||||
|
||||
# Get sites
|
||||
sites = discord_app.sites.all()
|
||||
self.stdout.write("\nAssociated sites:")
|
||||
for site in sites:
|
||||
self.stdout.write(f"- {site.domain} ({site.name})")
|
||||
|
||||
# Show callback URL
|
||||
callback_url = "http://localhost:8000/accounts/discord/login/callback/"
|
||||
self.stdout.write(
|
||||
"\nCallback URL to configure in Discord Developer Portal:"
|
||||
)
|
||||
self.stdout.write(callback_url)
|
||||
|
||||
# Show OAuth2 settings
|
||||
self.stdout.write("\nOAuth2 settings in settings.py:")
|
||||
discord_settings = settings.SOCIALACCOUNT_PROVIDERS.get("discord", {})
|
||||
self.stdout.write(
|
||||
f"PKCE Enabled: {discord_settings.get('OAUTH_PKCE_ENABLED', False)}"
|
||||
)
|
||||
self.stdout.write(f"Scopes: {discord_settings.get('SCOPE', [])}")
|
||||
|
||||
except SocialApp.DoesNotExist:
|
||||
self.stdout.write(self.style.ERROR("Discord app not found"))
|
||||
Reference in New Issue
Block a user