from django.views.decorators.csrf import csrf_exempt from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required, user_passes_test from django.http import JsonResponse, HttpResponse from django.views.decorators.http import require_POST from django.utils import timezone import json from .models import ( Bhagat, Event, Attendance, PushSubscription, Notification, Region, BhajanCategory, Bhajan, OptionPoll, Poll, Books, Sections, Chapters, Gallery, Wallpaper ) from django.conf import settings from django.core import serializers from django.db.models import Q import requests from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import AllowAny from rest_framework.response import Response from .utils import jwt_required from rest_framework_simplejwt.tokens import RefreshToken from pywebpush import webpush, WebPushException def gCaptchaVerifer(token): secret_key = settings.RECAPTCHA_SECRET_KEY data = {"response": token, "secret": secret_key} resp = requests.post("https://www.google.com/recaptcha/api/siteverify", data=data) return resp.json() def is_superadmin(user): return user.user_type == "superadmin" def is_regionadmin(user): return user.user_type == "regionadmin" def is_monitor(user): return user.user_type == "monitor" def dataEntry(request): # with open("./api/bhajanData.json", "r",encoding="utf-8") as f: # data = json.load(f)["Prasang"] # for bhajan in data: # category = BhajanCategory.objects.filter(link=bhajan['CatId']).first() # Bhajan.objects.create( # title=bhajan['title'], # title_guj=bhajan['title_guj'], # category=category, # lyrics=bhajan['lyrics'], # isEng = bhajan['isEng'], # isHnd = bhajan['isHnd'], # isGer = bhajan['isGer'], # isAudio = bhajan['isAudio'], # audio_url=bhajan['audio_url'] if bhajan['isAudio'] else "" # ) # print(bhajan['title']) return HttpResponse("Data Entry Page") def bhajanCategoryList(request): categories = BhajanCategory.objects.all() categoryArr = [] for category in categories: categoryArr.append( {"name": category.name, "link": category.link, "icon": category.icon if category.icon else None} ) lyricsBase = ( "https://huggingface.co/spaces/thejagstudio/MusicStore/raw/main/HTML Files/" ) audioBase = "https://huggingface.co/spaces/thejagstudio/MusicStore/resolve/main/Bhajan Audio/" return JsonResponse( {"categories": categoryArr, "lyricsBase": lyricsBase, "audioBase": audioBase} ) def bhajanList(request, catLink): if catLink == "all-kirtan": bhajans = Bhajan.objects.all() category = "All Kirtan" else: bhajans = Bhajan.objects.filter(category__link=catLink) category = BhajanCategory.objects.get(link=catLink).name bhajanArr = [] for bhajan in bhajans: bhajanArr.append( { "id": bhajan.bhajanId, "title": bhajan.title, "title_guj": bhajan.title_guj, "lyrics": bhajan.lyrics, "audio_url": bhajan.audio_url, "isEng": bhajan.isEng, "isHnd": bhajan.isHnd, "isGer": bhajan.isGer, "isAudio": bhajan.isAudio, } ) lyricsBase = ( "https://huggingface.co/spaces/thejagstudio/MusicStore/raw/main/HTML Files/" ) audioBase = "https://huggingface.co/spaces/thejagstudio/MusicStore/resolve/main/Bhajan Audio/" return JsonResponse( { "bhajans": bhajanArr, "lyricsBase": lyricsBase, "audioBase": audioBase, "category": category, } ) def bhajanDetail(request, bhajanId): bhajan = Bhajan.objects.filter(bhajanId=bhajanId).first() if not bhajan: return JsonResponse({"error": "Bhajan not found"}) else: return JsonResponse( { "id": bhajan.bhajanId, "title": bhajan.title, "title_guj": bhajan.title_guj, "category": bhajan.category.name, "lyrics": bhajan.lyrics, "audio_url": bhajan.audio_url, "isEng": bhajan.isEng, "isHnd": bhajan.isHnd, "isGer": bhajan.isGer, "isAudio": bhajan.isAudio, "lyricsBase": "https://huggingface.co/spaces/thejagstudio/MusicStore/raw/main/HTML Files/", "audioBase": "https://huggingface.co/spaces/thejagstudio/MusicStore/resolve/main/Bhajan Audio/", } ) def eventList(request): events = Event.objects.all() eventArr = [] for event in events: # convert date to Sept 26,2024 | 8:30 - 9:30 dateFormatted = ( event.date.strftime("%b %d, %Y") + " | " + event.date.strftime("%I:%M %p") + " - " + event.time.strftime("%I:%M %p") ) eventArr.append( { "title": event.title, "description": event.description, "date": dateFormatted, "day": int(event.date.strftime("%d")), "month": int(event.date.strftime("%m")), "year": int(event.date.strftime("%Y")), "created_by": event.created_by.__str__(), "region": event.region.name, "is_approved": event.is_approved, "color": event.color, } ) return JsonResponse({"events": eventArr}) @jwt_required() def notification(request): notifications = Notification.objects.all() notificationArr = [] for notification in notifications: notificationArr.append( { "sender": notification.sender.__str__(), "category": notification.sender.user_type, "title": notification.title, "content": notification.content, "timestamp": notification.timestamp.strftime("%b %d, %Y | %I:%M %p"), "notification_type": notification.notification_type, } ) return JsonResponse({"notifications": notificationArr}) @user_passes_test(is_superadmin) @csrf_exempt @jwt_required() def send_notification(request): if request.method == "POST": content = request.POST.get("content") recipient_type = request.POST.get("recipient_type") notification = Notification.objects.create( sender=request.user, content=content, notification_type="custom" ) # Send web push notifications subscriptions = PushSubscription.objects.all() for subscription in subscriptions: send_push_notification( subscription, { "title": "New Notification", "content": content, "url": "/notifications", }, ) return JsonResponse({"status": "success"}) return JsonResponse({"status": "error"}) def birthday_notifications(): today = timezone.now().date() birthday_users = Bhagat.objects.filter( birthday__month=today.month, birthday__day=today.day ) for user in birthday_users: notification = Notification.objects.create( sender=Bhagat.objects.get(user_type="superadmin"), content=f"Happy Birthday to {user.get_full_name()}!", notification_type="birthday", ) notification.recipients.set(Bhagat.objects.all()) @csrf_exempt def login(request): if request.method == "POST": username = request.POST.get("username") password = request.POST.get("password") captcha_response = request.POST.get("captcha_response") # Verify captcha result = gCaptchaVerifer(captcha_response) if not result.get("success"): return JsonResponse({"error": "Invalid Captcha", "status": "error"}) # Authenticate user user = Bhagat.objects.filter(username=username).first() if user is not None and user.check_password(password): # Generate tokens refresh = RefreshToken.for_user(user) return JsonResponse( { "status": "success", "tokens": { "access_token": str(refresh.access_token), "refresh_token": str(refresh), }, "user": { "id": user.id, "username": user.username, "first_name": user.first_name, "last_name": user.last_name, "email": user.email, "phone": user.phone, "region": user.region.name, "user_type": user.user_type, "profile_image": user.profile_image.url if user.profile_image else None, }, } ) return JsonResponse({"error": "Invalid credentials", "status": "error"}) return JsonResponse({"error": "Invalid Method", "status": "error"}) @csrf_exempt @jwt_required() def logout(request): if request.method == "POST": refresh_token = request.POST.get("refresh_token") if not refresh_token: return JsonResponse( {"error": "Refresh token is required", "status": "error"} ) else: try: refresh = RefreshToken(refresh_token) refresh.blacklist() return JsonResponse( {"status": "success", "message": "Successfully logged out"} ) except Exception as e: return JsonResponse( {"error": "Invalid token | " + str(e), "status": "error"} ) return JsonResponse({"status": "error", "error": "Invalid Method"}) @jwt_required() def get_user_profile(request): try: user = request.user return JsonResponse( { "status": "success", "user": { "id": user.id, "username": user.username, "first_name": user.first_name, "last_name": user.last_name, "email": user.email, "phone": user.phone, "region": user.region.name, "user_type": user.user_type, "profile_image": user.profile_image.url if user.profile_image else None, }, } ) except Exception as e: return JsonResponse({"status": "error", "error": str(e)}) @csrf_exempt @jwt_required() def profile_updater(request): if request.method == "POST": try: user = request.user first_name = request.POST.get("first_name") if first_name: user.first_name = first_name last_name = request.POST.get("last_name") if last_name: user.last_name = last_name email = request.POST.get("email") if email: user.email = email phone = request.POST.get("phone") if phone: user.phone = phone region_name = request.POST.get("region") if region_name: user.region = Region.objects.get(name=region_name) birth_date = request.POST.get("birth_date") if birth_date: user.birthday = birth_date street_name = request.POST.get("street_name") if street_name: user.streetName = street_name pincode = request.POST.get("pincode") if pincode: user.pincode = pincode city = request.POST.get("city") if city: user.city = city state = request.POST.get("state") if state: user.state = state country = request.POST.get("country") if country: user.country = country profile_image = request.FILES.get("profile_image") if profile_image: user.profile_image = profile_image user.save() return JsonResponse( {"status": "success", "message": "Profile updated successfully"} ) except Exception as e: return JsonResponse({"status": "error", "error": str(e)}) else: user = request.user regions = Region.objects.all() data = { "first_name": user.first_name, "last_name": user.last_name, "email": user.email, "phone": user.phone, "region": user.region.name, "birth_date": user.birthday, "street_name": user.streetName, "pincode": user.pincode, "city": user.city, "state": user.state, "country": user.country, "profile_image": user.profile_image, } return JsonResponse( { "status": "success", "regions": [region.name for region in regions], "user": data, } ) @jwt_required() def bhaktoList(request): current_user = request.user bhaktos = Bhagat.objects.filter(assigned_to=current_user).all() bhaktoArr = [] for bhakto in bhaktos: bhaktoArr.append( { "id": bhakto.id, "first_name": bhakto.first_name, "last_name": bhakto.last_name, "region": bhakto.region.name, "user_type": bhakto.user_type, "profile_image": bhakto.profile_image.url if bhakto.profile_image else None, } ) return JsonResponse({"bhaktos": bhaktoArr}) @api_view(["POST"]) @permission_classes([AllowAny]) def send_otp(request): try: data = json.loads(request.body) phone = data.get("phone") if not phone: return JsonResponse( {"status": "error", "error": "Phone number is required"} ) # Check if user exists user = Bhagat.objects.filter(phone=phone).first() if not user: return JsonResponse( {"status": "error", "error": "No account found with this phone number"} ) # Generate dummy OTP (in production, use proper OTP generation and SMS service) otp = "123456" # Dummy OTP for testing print(f"Generated OTP for {phone}: {otp}") # This simulates sending OTP # In production, store OTP with timestamp in database or cache # For now, we'll just return success return JsonResponse({"status": "success", "message": "OTP sent successfully"}) except Exception as e: return JsonResponse({"status": "error", "error": str(e)}) @api_view(["POST"]) @permission_classes([AllowAny]) def verify_otp(request): try: data = json.loads(request.body) phone = data.get("phone") otp = data.get("otp") if not phone or not otp: return JsonResponse( {"status": "error", "error": "Phone number and OTP are required"} ) # For demo purposes, accept any 6-digit OTP if otp == "123456": # Dummy verification return JsonResponse( {"status": "success", "message": "OTP verified successfully"} ) return JsonResponse({"status": "error", "error": "Invalid OTP"}) except Exception as e: return JsonResponse({"status": "error", "error": str(e)}) @api_view(["POST"]) @jwt_required() @csrf_exempt @permission_classes([AllowAny]) def change_password(request): try: data = json.loads(request.body) new_password = data.get("new_password") if not new_password: return JsonResponse( { "status": "error", "error": "Phone number and new password are required", } ) # Update user's password user = request.user if not user: return JsonResponse({"status": "error", "error": "User not found"}) user.password = new_password user.save() return JsonResponse( {"status": "success", "message": "Password changed successfully"} ) except Exception as e: return JsonResponse({"status": "error", "error": str(e)}) @jwt_required() @api_view(["POST"]) @csrf_exempt @permission_classes([AllowAny]) def save_push_subscription(request): try: subscription_data = json.loads(request.body) user = request.user pushUser = PushSubscription.objects.filter(user=user).first() if pushUser: pushUser.endpoint = subscription_data["endpoint"] pushUser.p256dh = subscription_data["keys"]["p256dh"] pushUser.auth = subscription_data["keys"]["auth"] pushUser.save() else: PushSubscription.objects.create( user=user, endpoint=subscription_data["endpoint"], p256dh=subscription_data["keys"]["p256dh"], auth=subscription_data["keys"]["auth"], ) return JsonResponse({"status": "success"}) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}) def send_push_notification(subscription, message): try: webpush( subscription_info={ "endpoint": subscription.endpoint, "keys": {"p256dh": subscription.p256dh, "auth": subscription.auth}, }, data=json.dumps(message), vapid_private_key=settings.WEBPUSH_SETTINGS["VAPID_PRIVATE_KEY"], vapid_claims={ "sub": f"mailto:{settings.WEBPUSH_SETTINGS['VAPID_ADMIN_EMAIL']}" }, ) except WebPushException as e: print(f"Web push failed: {e}") @api_view(["GET", "POST"]) @jwt_required() @csrf_exempt @permission_classes([AllowAny]) def polls(request): if request.method == "GET": user = request.user polls = Poll.objects.filter(participants=user) pollArr = [] for poll in polls: # Poll verification: Remove votes from users who are not in poll participants # This ensures data integrity when displaying poll results for option in poll.options.all(): # Get all voters for this option voters_to_remove = [] for voter in option.voters.all(): if voter not in poll.participants.all(): voters_to_remove.append(voter) # Remove invalid votes if voters_to_remove: option.voters.remove(*voters_to_remove) # Use the same data structure as the POST endpoint for consistency poll_data = { "id": poll.id, "question": poll.question, "image": poll.image.url if poll.image else None, "options": [], "created_by": { "id": poll.created_by.id, "first_name": poll.created_by.first_name, "last_name": poll.created_by.last_name, "profile_image": poll.created_by.profile_image.url if poll.created_by.profile_image else None, }, "created_at": poll.created_at, } total_voters = poll.participants.count() for option in poll.options.all(): vote_count = option.voters.count() percentage = (vote_count / total_voters * 100) if total_voters > 0 else 0 poll_data["options"].append({ "id": option.id, "optionText": option.optionText, "count": vote_count, "precentage": percentage, # Note: keeping the typo for consistency "voters": [ { "id": voter.id, "first_name": voter.first_name, "last_name": voter.last_name, "profile_image": voter.profile_image.url if voter.profile_image else None, } for voter in option.voters.all() ] }) pollArr.append(poll_data) return JsonResponse({"data": pollArr}) if request.method == "POST": data = json.loads(request.body) user = request.user poll_id = data.get("poll_id") option_id = data.get("option_id") if not poll_id or not option_id: return JsonResponse( {"status": "error", "message": "Poll ID and option ID are required"} ) try: poll = Poll.objects.get(id=poll_id) option = OptionPoll.objects.get(id=option_id) # Check if user is a participant in this poll if user not in poll.participants.all(): return JsonResponse( {"status": "error", "message": "You are not a participant in this poll"} ) # Poll verification: Remove votes from users who are not in poll participants # This prevents API spamming and ensures only valid participants can vote for existing_option in poll.options.all(): # Get all voters for this option voters_to_remove = [] for voter in existing_option.voters.all(): if voter not in poll.participants.all(): voters_to_remove.append(voter) # Remove invalid votes if voters_to_remove: existing_option.voters.remove(*voters_to_remove) # Check if user has already voted for this exact option (prevent duplicate/unnecessary update) if user in option.voters.all(): # User already voted for this option, just return current poll data without error pass else: # Remove user's previous votes for this poll (if any) - allows vote changing for existing_option in poll.options.all(): if user in existing_option.voters.all(): existing_option.voters.remove(user) # Add user to the new option option.voters.add(user) # Recalculate percentages and return updated poll data poll_data = { "id": poll.id, "question": poll.question, "image": poll.image.url if poll.image else None, "options": [], "created_by": { "id": poll.created_by.id, "first_name": poll.created_by.first_name, "last_name": poll.created_by.last_name, "profile_image": poll.created_by.profile_image.url if poll.created_by.profile_image else None, }, "created_at": poll.created_at, } total_voters = poll.participants.count() for opt in poll.options.all(): vote_count = opt.voters.count() percentage = (vote_count / total_voters * 100) if total_voters > 0 else 0 poll_data["options"].append({ "id": opt.id, "optionText": opt.optionText, "count": vote_count, "precentage": percentage, # Note: keeping the typo for consistency "voters": [ { "id": voter.id, "first_name": voter.first_name, "last_name": voter.last_name, "profile_image": voter.profile_image.url if voter.profile_image else None, } for voter in opt.voters.all() ] }) return JsonResponse( { "status": "success", "message": "Vote updated successfully", "poll": poll_data } ) except Poll.DoesNotExist: return JsonResponse({"status": "error", "message": "Poll not found"}) except OptionPoll.DoesNotExist: return JsonResponse({"status": "error", "message": "Option not found"}) @api_view(["GET"]) @jwt_required() @permission_classes([AllowAny]) def voterList(request, id): user = request.user try: poll = Poll.objects.filter(participants=user).get(id=id) # Poll verification: Remove votes from users who are not in poll participants # This ensures data integrity when displaying voter lists for option in poll.options.all(): # Get all voters for this option voters_to_remove = [] for voter in option.voters.all(): if voter not in poll.participants.all(): voters_to_remove.append(voter) # Remove invalid votes if voters_to_remove: option.voters.remove(*voters_to_remove) options = poll.options.all() optionsList = [] for option in options: tempOption = {} tempOption["id"] = option.id tempOption["optionText"] = option.optionText tempOption["count"] = option.voters.count() tempOption["voters"] = [] for voter in option.voters.all(): tempOption["voters"].append( { "id": voter.id, "first_name": voter.first_name, "last_name": voter.last_name, "profile_image": voter.profile_image.url if voter.profile_image else None, } ) optionsList.append(tempOption) return JsonResponse({"data": optionsList}) except Poll.DoesNotExist: return JsonResponse( {"error": "Poll may not exist or you may not have access to it"} ) @api_view(["POST"]) @jwt_required() @csrf_exempt @permission_classes([AllowAny]) def create_poll(request): try: user = request.user # Check if user is authorized to create polls (superadmin, regionadmin or karyakarta) if user.user_type not in ["superadmin", "regionadmin", "karyakarta"]: return JsonResponse( {"status": "error", "message": "You are not authorized to create polls"} ) question = request.POST.get("question") image = request.FILES.get("image") options = json.loads(request.POST.get("options", "[]")) participants = json.loads(request.POST.get("participants", "[]")) delivery_type = request.POST.get("delivery_type", "all") if not question: return JsonResponse( {"status": "error", "message": "Question is required"} ) if not options or len(options) < 2: return JsonResponse( {"status": "error", "message": "At least 2 options are required"} ) # Create the poll poll = Poll.objects.create( question=question, created_by=user, image=image if image else None ) # Add options for option_text in options: if option_text.strip(): # Only add non-empty options option = OptionPoll.objects.create(optionText=option_text.strip()) poll.options.add(option) # Determine participants based on delivery_type participant_users = [] if delivery_type == "all": participant_users = Bhagat.objects.all() elif delivery_type == "region": region_id = participants[0] if isinstance(participants, list) and len(participants) > 0 else participants participant_users = Bhagat.objects.filter(region_id=region_id) elif delivery_type == "usertype": user_type = participants[0] if isinstance(participants, list) and len(participants) > 0 else participants participant_users = Bhagat.objects.filter(user_type=user_type) elif delivery_type == "individualuser": participant_ids = [p if isinstance(p, int) else p.get('id') for p in participants] participant_users = Bhagat.objects.filter(id__in=participant_ids) # Add participants to poll if participant_users: poll.participants.set(participant_users) # Ensure creator is a participant if user not in poll.participants.all(): poll.participants.add(user) poll.save() return JsonResponse( { "status": "success", "message": "Poll created successfully", "poll_id": poll.id, "participants_count": poll.participants.count() } ) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}) @api_view(["PUT"]) @jwt_required() @csrf_exempt @permission_classes([AllowAny]) def edit_poll(request, poll_id): """ Edit a poll (only the creator can edit their own poll) """ try: user = request.user # Get the poll poll = Poll.objects.get(id=poll_id) # Check if user is the creator of the poll if poll.created_by.id != user.id: return JsonResponse( {"status": "error", "message": "You are not authorized to edit this poll"} ) # Get updated data question = request.POST.get("question") image = request.FILES.get("image") options = json.loads(request.POST.get("options", "[]")) participants = json.loads(request.POST.get("participants", "[]")) delivery_type = request.POST.get("delivery_type", "all") remove_image = request.POST.get("remove_image", "false") == "true" # Update question if question: poll.question = question # Handle image update/removal if remove_image and poll.image: poll.image.delete() poll.image = None elif image: # Delete old image if exists if poll.image: poll.image.delete() poll.image = image # Update options if provided if options and len(options) >= 2: # Get existing options existing_options = list(poll.options.all()) # Clear all current options poll.options.clear() # Delete old option objects for old_option in existing_options: old_option.delete() # Create new options for option_text in options: if option_text.strip(): option = OptionPoll.objects.create(optionText=option_text.strip()) poll.options.add(option) # Update participants if provided if delivery_type: participant_users = [] if delivery_type == "all": participant_users = Bhagat.objects.all() elif delivery_type == "region": region_id = participants[0] if isinstance(participants, list) and len(participants) > 0 else participants participant_users = Bhagat.objects.filter(region_id=region_id) elif delivery_type == "usertype": user_type = participants[0] if isinstance(participants, list) and len(participants) > 0 else participants participant_users = Bhagat.objects.filter(user_type=user_type) elif delivery_type == "individualuser": participant_ids = [p if isinstance(p, int) else p.get('id') for p in participants] participant_users = Bhagat.objects.filter(id__in=participant_ids) # Update participants if participant_users: poll.participants.set(participant_users) # Ensure creator is a participant if user not in poll.participants.all(): poll.participants.add(user) poll.save() # Return updated poll data poll_data = { "id": poll.id, "question": poll.question, "image": poll.image.url if poll.image else None, "options": [], "created_by": { "id": poll.created_by.id, "first_name": poll.created_by.first_name, "last_name": poll.created_by.last_name, "profile_image": poll.created_by.profile_image.url if poll.created_by.profile_image else None, }, "created_at": poll.created_at, } total_voters = poll.participants.count() for opt in poll.options.all(): vote_count = opt.voters.count() percentage = (vote_count / total_voters * 100) if total_voters > 0 else 0 poll_data["options"].append({ "id": opt.id, "optionText": opt.optionText, "count": vote_count, "precentage": percentage, "voters": [ { "id": voter.id, "first_name": voter.first_name, "last_name": voter.last_name, "profile_image": voter.profile_image.url if voter.profile_image else None, } for voter in opt.voters.all() ] }) return JsonResponse( { "status": "success", "message": "Poll updated successfully", "poll": poll_data } ) except Poll.DoesNotExist: return JsonResponse({"status": "error", "message": "Poll not found"}) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}) @api_view(["DELETE"]) @jwt_required() @csrf_exempt @permission_classes([AllowAny]) def delete_poll(request, poll_id): """ Delete a poll (only the creator can delete their own poll) """ try: user = request.user # Get the poll poll = Poll.objects.get(id=poll_id) # Check if user is the creator of the poll if poll.created_by.id != user.id: return JsonResponse( {"status": "error", "message": "You are not authorized to delete this poll"} ) # Delete the poll image if it exists if poll.image: poll.image.delete() # Delete all options associated with the poll for option in poll.options.all(): option.delete() # Delete the poll itself poll.delete() return JsonResponse( { "status": "success", "message": "Poll deleted successfully" } ) except Poll.DoesNotExist: return JsonResponse({"status": "error", "message": "Poll not found"}) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}) @api_view(["GET"]) @permission_classes([AllowAny]) def bookList(request): books = Books.objects.all().order_by("index") bookArr = [] for book in books: bookArr.append( { "id": book.id, "urlId": book.urlId, "title": book.title, "author": book.author, "description": book.description, "poster": book.poster.url if book.poster else None, "pdf": book.pdf.url if book.pdf else None, "isPdf": book.isPdf, "hasSections": book.hasSections, } ) return JsonResponse({"books": bookArr}) @api_view(["GET"]) @permission_classes([AllowAny]) def bookDetail(request, urlId): book = Books.objects.filter(urlId=urlId).first() if not book: return JsonResponse({"error": "Book not found"}, status=404) sections = [] if book.hasSections: bookSections = Sections.objects.filter(book=book) for section in bookSections: chapters = [] bookChapters = Chapters.objects.filter(section=section) for chapter in bookChapters: chapters.append( { "id": chapter.id, "urlId": chapter.urlId, "data": chapter.data, "title": chapter.title, } ) sections.append( {"id": section.id, "title": section.title, "chapters": chapters} ) return JsonResponse( { "book": { "id": book.id, "urlId": book.urlId, "title": book.title, "author": book.author, "description": book.description, "poster": book.poster.url if book.poster else None, "pdf": book.pdf.url if book.pdf else None, "isPdf": book.isPdf, "hasSections": book.hasSections, "sections": sections if book.hasSections else None, } } ) @api_view(["GET"]) @permission_classes([AllowAny]) def bookChapterDetail(request, urlId, chapterId): book = Books.objects.filter(urlId=urlId).first() chapter = Chapters.objects.filter(urlId=chapterId, book=book).first() if not chapter: return JsonResponse({"error": "Chapter not found"}, status=404) return JsonResponse( { "chapter": { "id": chapter.id, "urlId": chapter.urlId, "title": chapter.title, "data": chapter.data, "book": { "id": chapter.book.id, "title": chapter.book.title, "author": chapter.book.author, "poster": chapter.book.poster.url if chapter.book.poster else None, "pdf": chapter.book.pdf.url if chapter.book.pdf else None, }, } } ) @api_view(["GET"]) def data(request): with open("swamini_vato_data.json", "r", encoding="utf-8") as file: data = json.load(file) book = Books.objects.get(id=1) i = 1 for section in data: section_obj = Sections.objects.create(title=section["section_title_gu"], urlId=section["section_title_gu"].lower().replace(" ", "-").replace("(", "").replace(")", "").replace("/", "-"), isPdf=False, book=book, hasChapters=True) for vato in section["chapter"]: Chapters.objects.create( section=section_obj, book=book, title=vato["gujarati_title"], urlId=str(i), data=vato, isPdf=False, ) i = i + 1 print(f"Added vato: {vato['gujarati_title']}") print(f"Added section: {section['section_title_gu']}") return JsonResponse({"data": ""}) @api_view(["GET"]) @jwt_required() def gallery_list(request): """ Get gallery images for the current user based on their region and user type. Returns today's images, or if not available, the most recent previous day's images. """ user = request.user today = timezone.now().date() # Build base query based on user type and region if user.user_type == "superadmin": base_query = Gallery.objects.all() elif user.user_type == "regionadmin": base_query = Gallery.objects.filter(region=user.region) else: # Regular users see images from their region base_query = Gallery.objects.filter( Q(region=user.region) | Q(region__name="All") ) # First, try to get today's images gallery_images = base_query.filter(date=today).order_by('-uploaded_at') # If no images for today, get the most recent previous day's images if not gallery_images.exists(): # Get the most recent date with images latest_date = base_query.values_list('date', flat=True).order_by('-date').first() if latest_date: gallery_images = base_query.filter(date=latest_date).order_by('-uploaded_at') gallery_arr = [] for image in gallery_images: gallery_arr.append({ "id": image.id, "image": image.image.url if image.image else None, "date": image.date.strftime("%B %d, %Y"), "region": image.region.name if image.region else None, "uploaded_at": image.uploaded_at.strftime("%b %d, %Y | %I:%M %p") }) return JsonResponse({"gallery": gallery_arr}) @api_view(["GET"]) @jwt_required() def gallery_all_list(request): """ Get all gallery images for the current user based on their region and user type. Returns all images in chronological order (newest first). """ user = request.user # Build base query based on user type and region if user.user_type == "superadmin": base_query = Gallery.objects.all() elif user.user_type == "regionadmin": base_query = Gallery.objects.filter(region=user.region) else: # Regular users see images from their region base_query = Gallery.objects.filter( Q(region=user.region) | Q(region__name="All") ) # Get all images ordered by upload date (newest first) gallery_images = base_query.order_by('-uploaded_at') gallery_arr = [] for image in gallery_images: gallery_arr.append({ "id": image.id, "image": image.image.url if image.image else None, "date": image.date.strftime("%B %d, %Y"), "region": image.region.name if image.region else None, "uploaded_at": image.uploaded_at.strftime("%b %d, %Y | %I:%M %p") }) return JsonResponse({"gallery": gallery_arr}) @api_view(["POST"]) @jwt_required() @csrf_exempt def upload_gallery_image(request): """ Upload new gallery image (only for regionadmin and superadmin) """ user = request.user # Check if user is authorized to upload images if user.user_type not in ["superadmin", "regionadmin"]: return JsonResponse({ "status": "error", "message": "You are not authorized to upload gallery images" }) try: # Handle bulk image upload images = request.FILES.getlist('images') if not images: return JsonResponse({ "status": "error", "message": "At least one image is required" }) uploaded_images = [] today = timezone.now().date() # Create gallery entries for each image with today's date for image in images: gallery_image = Gallery.objects.create( image=image, region=user.region, date=today ) uploaded_images.append({ "id": gallery_image.id, "image": gallery_image.image.url if gallery_image.image else None, "date": gallery_image.date.strftime("%B %d, %Y"), "region": gallery_image.region.name if gallery_image.region else None, "uploaded_at": gallery_image.uploaded_at.strftime("%b %d, %Y | %I:%M %p") }) return JsonResponse({ "status": "success", "message": f"Successfully uploaded {len(uploaded_images)} images", "images": uploaded_images }) except Exception as e: return JsonResponse({ "status": "error", "message": str(e) }) @api_view(["DELETE"]) @jwt_required() def delete_gallery_image(request, image_id): """ Delete gallery image (only for superadmin or the uploader) """ user = request.user try: gallery_image = Gallery.objects.get(id=image_id) # Check permissions: superadmin can delete any, regionadmin can delete their own if user.user_type != "superadmin" and gallery_image.uploaded_by != user: return JsonResponse({ "status": "error", "message": "You are not authorized to delete this image" }) # Delete the image file if gallery_image.image: gallery_image.image.delete() # Delete the gallery entry gallery_image.delete() return JsonResponse({ "status": "success", "message": "Gallery image deleted successfully" }) except Gallery.DoesNotExist: return JsonResponse({ "status": "error", "message": "Gallery image not found" }) except Exception as e: return JsonResponse({ "status": "error", "message": str(e) }) @api_view(["GET"]) @jwt_required() def wallpaper_list(request): """ Get all wallpaper images for the current user based on their region and user type. Returns all images in chronological order (newest first). """ base_query = Wallpaper.objects.all() # Get all images ordered by upload date (newest first) wallpaper_images = base_query.order_by('-uploaded_at') wallpaper_arr = [] for image in wallpaper_images: wallpaper_arr.append({ "id": image.id, "image": image.image.url if image.image else None, "uploaded_at": image.uploaded_at.strftime("%b %d, %Y | %I:%M %p") }) return JsonResponse({"wallpaper": wallpaper_arr})