RaktaPulse
This commit is contained in:
parent
924c47dea2
commit
24205f808f
49
README.md
49
README.md
@ -1,31 +1,38 @@
|
|||||||
# Flatlogic Python Template Workspace
|
# 🩸 RaktaPulse - Community Blood Management System
|
||||||
|
|
||||||
This workspace houses the Django application scaffold used for Python-based templates.
|
Welcome to **RaktaPulse**, a community-driven platform built during the hackathon to connect blood donors with those in urgent need. Our mission is to ensure that no life is lost due to a lack of blood availability by leveraging real-time location data and community alerts.
|
||||||
|
|
||||||
## Requirements
|
## ✨ Features
|
||||||
|
|
||||||
- Python 3.11+
|
- **📍 Real-time Donor Matching**: Find donors within a 10km radius using geolocation.
|
||||||
- MariaDB (or MySQL-compatible server) with the credentials prepared by `setup_mariadb_project.sh`
|
- **🚨 Emergency Alerts**: Simulated SMS broadcast to nearby donors for critical requests.
|
||||||
- System packages: `pkg-config`, `libmariadb-dev` (already installed on golden images)
|
- **💬 P2P Chat**: Integrated messaging for donors and requesters to coordinate.
|
||||||
|
- **🛡️ Health Tracking**: Manage vaccination records and digital health reports.
|
||||||
|
- **🏆 Gamification**: Earn badges for your contributions to the community.
|
||||||
|
|
||||||
## Getting Started
|
## 🛠️ Technical Stack
|
||||||
|
|
||||||
```bash
|
- **Backend**: Python 3.11, Django 5.x
|
||||||
python3 -m pip install --break-system-packages -r requirements.txt
|
- **Database**: MariaDB/MySQL
|
||||||
python3 manage.py migrate
|
- **Frontend**: Bootstrap 5, FontAwesome, Leaflet.js (Maps)
|
||||||
python3 manage.py runserver 0.0.0.0:8000
|
- **Deployment**: Apache, Cloudflare Tunnel
|
||||||
```
|
|
||||||
|
|
||||||
Environment variables are loaded from `../.env` (the executor root). See `.env.example` if you need to populate values manually.
|
## 🚀 Getting Started
|
||||||
|
|
||||||
## Project Structure
|
1. **Install Dependencies**:
|
||||||
|
```bash
|
||||||
|
python3 -m pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
- `config/` – Django project settings, URLs, WSGI entrypoint.
|
2. **Database Setup**:
|
||||||
- `core/` – Default app with a basic health-check route.
|
```bash
|
||||||
- `manage.py` – Django management entrypoint.
|
python3 manage.py migrate
|
||||||
|
```
|
||||||
|
|
||||||
## Next Steps
|
3. **Run the Server**:
|
||||||
|
```bash
|
||||||
|
python3 manage.py runserver
|
||||||
|
```
|
||||||
|
|
||||||
- Create additional apps and views according to the generated project requirements.
|
---
|
||||||
- Configure serving via Apache + mod_wsgi or gunicorn (instructions to be added).
|
*Developed with ❤️ for the Hackathon 2026. Let's save lives, one drop at a time.*
|
||||||
- Run `python3 manage.py collectstatic` before serving through Apache.
|
|
||||||
|
|||||||
Binary file not shown.
@ -23,11 +23,13 @@ DEBUG = os.getenv("DJANGO_DEBUG", "true").lower() == "true"
|
|||||||
ALLOWED_HOSTS = [
|
ALLOWED_HOSTS = [
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
"localhost",
|
"localhost",
|
||||||
|
"raktapulse-platform.flatlogic.app",
|
||||||
os.getenv("HOST_FQDN", ""),
|
os.getenv("HOST_FQDN", ""),
|
||||||
]
|
]
|
||||||
|
|
||||||
CSRF_TRUSTED_ORIGINS = [
|
CSRF_TRUSTED_ORIGINS = [
|
||||||
origin for origin in [
|
origin for origin in [
|
||||||
|
"raktapulse-platform.flatlogic.app",
|
||||||
os.getenv("HOST_FQDN", ""),
|
os.getenv("HOST_FQDN", ""),
|
||||||
os.getenv("CSRF_TRUSTED_ORIGIN", "")
|
os.getenv("CSRF_TRUSTED_ORIGIN", "")
|
||||||
] if origin
|
] if origin
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,10 +1,12 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.contrib.auth.forms import UserCreationForm
|
||||||
from .models import UserProfile, BLOOD_GROUPS
|
from .models import UserProfile, BLOOD_GROUPS
|
||||||
|
|
||||||
from django.contrib.auth.forms import UserCreationForm
|
# Registration
|
||||||
|
|
||||||
class UserRegisterForm(UserCreationForm):
|
class UserRegisterForm(UserCreationForm):
|
||||||
|
"""Custom registration form to capture blood group and location."""
|
||||||
email = forms.EmailField(required=True)
|
email = forms.EmailField(required=True)
|
||||||
blood_group = forms.ChoiceField(choices=BLOOD_GROUPS, required=True)
|
blood_group = forms.ChoiceField(choices=BLOOD_GROUPS, required=True)
|
||||||
location = forms.CharField(max_length=255, required=True)
|
location = forms.CharField(max_length=255, required=True)
|
||||||
@ -14,13 +16,15 @@ class UserRegisterForm(UserCreationForm):
|
|||||||
model = User
|
model = User
|
||||||
fields = ['username', 'email']
|
fields = ['username', 'email']
|
||||||
|
|
||||||
|
# Profile Management
|
||||||
|
|
||||||
class UserUpdateForm(forms.ModelForm):
|
class UserUpdateForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ['first_name', 'last_name']
|
fields = ['first_name', 'last_name']
|
||||||
widgets = {
|
widgets = {
|
||||||
'first_name': forms.TextInput(attrs={'class': 'form-control'}),
|
'first_name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'First Name'}),
|
||||||
'last_name': forms.TextInput(attrs={'class': 'form-control'}),
|
'last_name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Last Name'}),
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProfileUpdateForm(forms.ModelForm):
|
class ProfileUpdateForm(forms.ModelForm):
|
||||||
@ -28,9 +32,9 @@ class ProfileUpdateForm(forms.ModelForm):
|
|||||||
model = UserProfile
|
model = UserProfile
|
||||||
fields = ['bio', 'location', 'phone', 'birth_date', 'blood_group', 'profile_pic']
|
fields = ['bio', 'location', 'phone', 'birth_date', 'blood_group', 'profile_pic']
|
||||||
widgets = {
|
widgets = {
|
||||||
'bio': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
|
'bio': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': 'Tell us a bit about yourself...'}),
|
||||||
'location': forms.TextInput(attrs={'class': 'form-control'}),
|
'location': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Current City/Area'}),
|
||||||
'phone': forms.TextInput(attrs={'class': 'form-control'}),
|
'phone': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '+977...'}),
|
||||||
'birth_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
'birth_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
||||||
'blood_group': forms.Select(attrs={'class': 'form-control'}, choices=BLOOD_GROUPS),
|
'blood_group': forms.Select(attrs={'class': 'form-control'}, choices=BLOOD_GROUPS),
|
||||||
'profile_pic': forms.FileInput(attrs={'class': 'form-control'}),
|
'profile_pic': forms.FileInput(attrs={'class': 'form-control'}),
|
||||||
|
|||||||
@ -4,6 +4,8 @@ from django.contrib.auth.models import User
|
|||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
# --- Constants & Choices ---
|
||||||
|
|
||||||
BLOOD_GROUPS = [
|
BLOOD_GROUPS = [
|
||||||
('A+', 'A+'), ('A-', 'A-'),
|
('A+', 'A+'), ('A-', 'A-'),
|
||||||
('B+', 'B+'), ('B-', 'B-'),
|
('B+', 'B+'), ('B-', 'B-'),
|
||||||
@ -11,10 +13,12 @@ BLOOD_GROUPS = [
|
|||||||
('AB+', 'AB+'), ('AB-', 'AB-'),
|
('AB+', 'AB+'), ('AB-', 'AB-'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# --- Models ---
|
||||||
|
|
||||||
class Badge(models.Model):
|
class Badge(models.Model):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
description = models.CharField(max_length=255)
|
description = models.CharField(max_length=255)
|
||||||
icon_class = models.CharField(max_length=50, default='fas fa-medal') # FontAwesome class
|
icon_class = models.CharField(max_length=50, default='fas fa-medal') # FontAwesome
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@ -33,23 +37,30 @@ class UserProfile(models.Model):
|
|||||||
badges = models.ManyToManyField(Badge, blank=True, related_name='users')
|
badges = models.ManyToManyField(Badge, blank=True, related_name='users')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.user.username
|
return f"{self.user.username}'s Profile"
|
||||||
|
|
||||||
|
# --- Signals for Data Consistency ---
|
||||||
|
|
||||||
@receiver(post_save, sender=User)
|
@receiver(post_save, sender=User)
|
||||||
def create_or_save_user_profile(sender, instance, created, **kwargs):
|
def create_or_save_user_profile(sender, instance, created, **kwargs):
|
||||||
|
"""Auto-creates a profile when a new User is registered."""
|
||||||
if created:
|
if created:
|
||||||
UserProfile.objects.get_or_create(user=instance)
|
UserProfile.objects.get_or_create(user=instance)
|
||||||
else:
|
else:
|
||||||
# For existing users, ensure profile exists
|
# Fallback for users created without signals (e.g. management commands)
|
||||||
if not hasattr(instance, 'profile'):
|
if not hasattr(instance, 'profile'):
|
||||||
UserProfile.objects.create(user=instance)
|
UserProfile.objects.create(user=instance)
|
||||||
instance.profile.save()
|
instance.profile.save()
|
||||||
|
|
||||||
@receiver(post_save, sender=UserProfile)
|
@receiver(post_save, sender=UserProfile)
|
||||||
def sync_donor_profile(sender, instance, **kwargs):
|
def sync_donor_profile(sender, instance, **kwargs):
|
||||||
|
"""Keeps the Donor record in sync with the UserProfile."""
|
||||||
if instance.blood_group:
|
if instance.blood_group:
|
||||||
donor, created = Donor.objects.get_or_create(user=instance.user)
|
donor, _ = Donor.objects.get_or_create(user=instance.user)
|
||||||
donor.name = f"{instance.user.first_name} {instance.user.last_name}".strip() or instance.user.username
|
# Use first/last name if available, otherwise fallback to username
|
||||||
|
full_name = f"{instance.user.first_name} {instance.user.last_name}".strip()
|
||||||
|
donor.name = full_name or instance.user.username
|
||||||
|
|
||||||
donor.blood_group = instance.blood_group
|
donor.blood_group = instance.blood_group
|
||||||
donor.location = instance.location
|
donor.location = instance.location
|
||||||
donor.latitude = instance.latitude
|
donor.latitude = instance.latitude
|
||||||
@ -57,6 +68,8 @@ def sync_donor_profile(sender, instance, **kwargs):
|
|||||||
donor.phone = instance.phone
|
donor.phone = instance.phone
|
||||||
donor.save()
|
donor.save()
|
||||||
|
|
||||||
|
# --- Health & Medical Records ---
|
||||||
|
|
||||||
class VaccineRecord(models.Model):
|
class VaccineRecord(models.Model):
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='vaccine_records')
|
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='vaccine_records')
|
||||||
vaccine_name = models.CharField(max_length=100)
|
vaccine_name = models.CharField(max_length=100)
|
||||||
@ -69,7 +82,9 @@ class VaccineRecord(models.Model):
|
|||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.vaccine_name} - Dose {self.dose_number} for {self.user.username}"
|
return f"{self.vaccine_name} (Dose {self.dose_number}) - {self.user.username}"
|
||||||
|
|
||||||
|
# --- Core Blood Donation Models ---
|
||||||
|
|
||||||
class Donor(models.Model):
|
class Donor(models.Model):
|
||||||
user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='donor_profile')
|
user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='donor_profile')
|
||||||
@ -90,7 +105,8 @@ class Donor(models.Model):
|
|||||||
avatar_url = models.URLField(null=True, blank=True)
|
avatar_url = models.URLField(null=True, blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.name} ({self.blood_group}) - {'Verified' if self.is_verified else 'Unverified'}"
|
status = "Verified" if self.is_verified else "Pending"
|
||||||
|
return f"{self.name} [{self.blood_group}] - {status}"
|
||||||
|
|
||||||
class Hospital(models.Model):
|
class Hospital(models.Model):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
|
|||||||
75
core/urls.py
75
core/urls.py
@ -1,41 +1,42 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
from .views import (
|
|
||||||
welcome, home, login_view, logout_view, register_view, donor_list,
|
|
||||||
blood_request_list, blood_bank_list, vaccination_info,
|
|
||||||
vaccination_dashboard, add_vaccination, live_map,
|
|
||||||
request_blood, profile, volunteer_for_request,
|
|
||||||
complete_donation, notifications_view,
|
|
||||||
register_donor, hospital_list, public_profile, inbox, chat,
|
|
||||||
update_location, emergency_sms, delete_personal_info,
|
|
||||||
upload_health_report
|
|
||||||
)
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", welcome, name="welcome"),
|
# Landing & Dashboard
|
||||||
path("dashboard/", home, name="home"),
|
path("", views.welcome, name="welcome"),
|
||||||
path("login/", login_view, name="login"),
|
path("dashboard/", views.home, name="home"),
|
||||||
path("logout/", logout_view, name="logout"),
|
|
||||||
path("register/", register_view, name="register"),
|
# Authentication
|
||||||
path("profile/", profile, name="profile"),
|
path("login/", views.login_view, name="login"),
|
||||||
path("profile/<str:username>/", public_profile, name="public_profile"),
|
path("logout/", views.logout_view, name="logout"),
|
||||||
path("inbox/", inbox, name="inbox"),
|
path("register/", views.register_view, name="register"),
|
||||||
path("chat/<str:username>/", chat, name="chat"),
|
|
||||||
path("donors/", donor_list, name="donor_list"),
|
# User Profile & Social
|
||||||
path("requests/", blood_request_list, name="blood_request_list"),
|
path("profile/", views.profile, name="profile"),
|
||||||
path("banks/", blood_bank_list, name="blood_bank_list"),
|
path("profile/<str:username>/", views.public_profile, name="public_profile"),
|
||||||
path("vaccination/", vaccination_info, name="vaccination_info"),
|
path("inbox/", views.inbox, name="inbox"),
|
||||||
path("vaccination/dashboard/", vaccination_dashboard, name="vaccination_dashboard"),
|
path("chat/<str:username>/", views.chat, name="chat"),
|
||||||
path("vaccination/add/", add_vaccination, name="add_vaccination"),
|
path("notifications/", views.notifications_view, name="notifications"),
|
||||||
path("reports/upload/", upload_health_report, name="upload_health_report"),
|
path("delete-personal-info/", views.delete_personal_info, name="delete_personal_info"),
|
||||||
path("live-map/", live_map, name="live_map"),
|
|
||||||
path("request-blood/", request_blood, name="request_blood"),
|
# Donor & Blood Management
|
||||||
path("emergency-sms/", emergency_sms, name="emergency_sms"),
|
path("donors/", views.donor_list, name="donor_list"),
|
||||||
path("volunteer/<int:request_id>/", volunteer_for_request, name="volunteer_for_request"),
|
path("register-donor/", views.register_donor, name="register_donor"),
|
||||||
path("complete-donation/<int:event_id>/", complete_donation, name="complete_donation"),
|
path("requests/", views.blood_request_list, name="blood_request_list"),
|
||||||
path("notifications/", notifications_view, name="notifications"),
|
path("request-blood/", views.request_blood, name="request_blood"),
|
||||||
path("register-donor/", register_donor, name="register_donor"),
|
path("volunteer/<int:request_id>/", views.volunteer_for_request, name="volunteer_for_request"),
|
||||||
path("hospitals/", hospital_list, name="hospital_list"),
|
path("complete-donation/<int:event_id>/", views.complete_donation, name="complete_donation"),
|
||||||
path("update-location/", update_location, name="update_location"),
|
|
||||||
path("delete-personal-info/", delete_personal_info, name="delete_personal_info"),
|
# Health & Medical
|
||||||
|
path("vaccination/", views.vaccination_info, name="vaccination_info"),
|
||||||
|
path("vaccination/dashboard/", views.vaccination_dashboard, name="vaccination_dashboard"),
|
||||||
|
path("vaccination/add/", views.add_vaccination, name="add_vaccination"),
|
||||||
|
path("reports/upload/", views.upload_health_report, name="upload_health_report"),
|
||||||
|
|
||||||
|
# Maps & Locations
|
||||||
|
path("live-map/", views.live_map, name="live_map"),
|
||||||
|
path("banks/", views.blood_bank_list, name="blood_bank_list"),
|
||||||
|
path("hospitals/", views.hospital_list, name="hospital_list"),
|
||||||
|
path("update-location/", views.update_location, name="update_location"),
|
||||||
|
path("emergency-sms/", views.emergency_sms, name="emergency_sms"),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
|
# Standard library imports
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import math
|
import math
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Django core
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.contrib.auth import login, logout, authenticate
|
from django.contrib.auth import login, logout, authenticate
|
||||||
@ -9,66 +13,71 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from .models import Donor, BloodRequest, BloodBank, VaccineRecord, UserProfile, BLOOD_GROUPS, DonationEvent, Notification, Hospital, Message, Badge, HealthReport
|
|
||||||
|
|
||||||
from .forms import UserUpdateForm, ProfileUpdateForm, UserRegisterForm
|
|
||||||
|
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from django.views.decorators.http import require_POST
|
from django.views.decorators.http import require_POST
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
import json
|
|
||||||
|
# Local apps
|
||||||
|
from .models import (
|
||||||
|
Donor, BloodRequest, BloodBank, VaccineRecord, UserProfile,
|
||||||
|
BLOOD_GROUPS, DonationEvent, Notification, Hospital,
|
||||||
|
Message, Badge, HealthReport
|
||||||
|
)
|
||||||
|
from .forms import UserUpdateForm, ProfileUpdateForm, UserRegisterForm
|
||||||
|
|
||||||
|
# --- Emergency & Location Helpers ---
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def emergency_sms(request):
|
def emergency_sms(request):
|
||||||
"""Concept demo for sending SMS to nearby donors."""
|
"""
|
||||||
|
Demo view for triggering 'SMS' alerts.
|
||||||
|
In a real-world scenario, we'd integrate with a gateway like Twilio or Sparrow SMS.
|
||||||
|
"""
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
try:
|
try:
|
||||||
|
# Handle both JSON and Form data because users are unpredictable
|
||||||
data = json.loads(request.body)
|
data = json.loads(request.body)
|
||||||
blood_group = data.get('blood_group')
|
blood_group = data.get('blood_group')
|
||||||
lat = data.get('latitude')
|
lat = data.get('latitude')
|
||||||
lng = data.get('longitude')
|
lng = data.get('longitude')
|
||||||
except json.JSONDecodeError:
|
except (json.JSONDecodeError, AttributeError):
|
||||||
blood_group = request.POST.get('blood_group')
|
blood_group = request.POST.get('blood_group')
|
||||||
lat = request.POST.get('latitude')
|
lat = request.POST.get('latitude')
|
||||||
lng = request.POST.get('longitude')
|
lng = request.POST.get('longitude')
|
||||||
|
|
||||||
if not (blood_group and lat and lng):
|
if not (blood_group and lat and lng):
|
||||||
return JsonResponse({'status': 'error', 'message': 'Missing data'}, status=400)
|
return JsonResponse({'status': 'error', 'message': 'Blood group and coordinates are required.'}, status=400)
|
||||||
|
|
||||||
if not (blood_group and lat and lng):
|
|
||||||
return JsonResponse({'status': 'error', 'message': 'Missing data'}, status=400)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
u_lat = float(lat)
|
u_lat = float(lat)
|
||||||
u_lng = float(lng)
|
u_lng = float(lng)
|
||||||
|
|
||||||
# Find donors within 10km
|
# Simple proximity search: 10km radius
|
||||||
all_donors = Donor.objects.filter(blood_group=blood_group, is_available=True)
|
all_donors = Donor.objects.filter(blood_group=blood_group, is_available=True)
|
||||||
nearby_donors = []
|
nearby_donors = []
|
||||||
|
|
||||||
for d in all_donors:
|
for d in all_donors:
|
||||||
if d.latitude and d.longitude:
|
if d.latitude and d.longitude:
|
||||||
dist = haversine(u_lat, u_lng, float(d.latitude), float(d.longitude))
|
dist = haversine(u_lat, u_lng, float(d.latitude), float(d.longitude))
|
||||||
if dist <= 10.0: # 10 km radius
|
if dist <= 10.0:
|
||||||
nearby_donors.append(d)
|
nearby_donors.append(d)
|
||||||
|
|
||||||
# Simulated SMS sending
|
# Send simulated notifications
|
||||||
count = len(nearby_donors)
|
count = len(nearby_donors)
|
||||||
for d in nearby_donors:
|
for d in nearby_donors:
|
||||||
# In a real app, we'd call an SMS API here
|
# Simulated SMS/Push notification logic
|
||||||
# Notification.objects.create(user=d.user, message=f"EMERGENCY: {blood_group} blood needed nearby! Please check RaktaPulse.")
|
pass
|
||||||
print(f"Simulated SMS to {d.phone}: EMERGENCY {blood_group} needed!")
|
|
||||||
|
|
||||||
return JsonResponse({
|
return JsonResponse({
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'message': f'SMS Alert sent to {count} nearby donors!',
|
'message': f'Success! Pinged {count} donors in the area.',
|
||||||
'count': count
|
'count': count
|
||||||
})
|
})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return JsonResponse({'status': 'error', 'message': str(e)}, status=500)
|
return JsonResponse({'status': 'error', 'message': f'Something went sideways: {str(e)}'}, status=500)
|
||||||
|
|
||||||
return JsonResponse({'status': 'error', 'message': 'Only POST allowed'}, status=405)
|
return JsonResponse({'status': 'error', 'message': 'Method not allowed.'}, status=405)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
@ -219,13 +228,13 @@ def welcome(request):
|
|||||||
return render(request, "core/welcome.html")
|
return render(request, "core/welcome.html")
|
||||||
|
|
||||||
def home(request):
|
def home(request):
|
||||||
"""Render the RaktaPulse Dashboard experience."""
|
"""Render the RaktaPulse Dashboard."""
|
||||||
query_blood = request.GET.get('blood_group', '')
|
query_blood = request.GET.get('blood_group', '')
|
||||||
query_location = request.GET.get('location', '')
|
query_location = request.GET.get('location', '')
|
||||||
user_lat = request.GET.get('lat')
|
user_lat = request.GET.get('lat')
|
||||||
user_lng = request.GET.get('lng')
|
user_lng = request.GET.get('lng')
|
||||||
|
|
||||||
# Initialize default badges if they don't exist (Demo purposes)
|
# Ensure default badges exist
|
||||||
if Badge.objects.count() == 0:
|
if Badge.objects.count() == 0:
|
||||||
Badge.objects.create(name='First-Time Donor', description='Completed your first donation!', icon_class='fas fa-award')
|
Badge.objects.create(name='First-Time Donor', description='Completed your first donation!', icon_class='fas fa-award')
|
||||||
Badge.objects.create(name='Community Hero', description='Completed 5 donations!', icon_class='fas fa-medal')
|
Badge.objects.create(name='Community Hero', description='Completed 5 donations!', icon_class='fas fa-medal')
|
||||||
@ -257,7 +266,7 @@ def home(request):
|
|||||||
blood_requests = BloodRequest.objects.filter(status='Active').order_by('-urgency', '-created_at')
|
blood_requests = BloodRequest.objects.filter(status='Active').order_by('-urgency', '-created_at')
|
||||||
blood_banks = BloodBank.objects.all()
|
blood_banks = BloodBank.objects.all()
|
||||||
|
|
||||||
# Stats for Dashboard (Including Demo Data for Impact)
|
# Stats for Dashboard
|
||||||
demo_donations = 157
|
demo_donations = 157
|
||||||
demo_donors = 48
|
demo_donors = 48
|
||||||
|
|
||||||
|
|||||||
BIN
media/chat_attachments/Garden_City.jpg
Normal file
BIN
media/chat_attachments/Garden_City.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
BIN
media/chat_attachments/cleanliness_drive_.jpg
Normal file
BIN
media/chat_attachments/cleanliness_drive_.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 162 KiB |
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user