The new updates of partners and user
Made-with: Cursor
This commit is contained in:
946
accounts/api.py
Normal file
946
accounts/api.py
Normal file
@@ -0,0 +1,946 @@
|
||||
from django.http import JsonResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.forms.models import model_to_dict
|
||||
from django.contrib.auth import authenticate, logout
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.authtoken.models import Token
|
||||
import json
|
||||
|
||||
from .models import User
|
||||
from mobile_api.utils import validate_token_and_get_user
|
||||
|
||||
|
||||
def _partner_user_to_dict(user, request=None):
|
||||
"""Serialize partner-related User for JSON (same structure as _user_to_dict)."""
|
||||
data = model_to_dict(
|
||||
user,
|
||||
fields=[
|
||||
"id",
|
||||
"username",
|
||||
"email",
|
||||
"phone_number",
|
||||
"role",
|
||||
"is_staff",
|
||||
"is_customer",
|
||||
"is_user",
|
||||
"pincode",
|
||||
"district",
|
||||
"state",
|
||||
"country",
|
||||
"place",
|
||||
"latitude",
|
||||
"longitude",
|
||||
"first_name",
|
||||
"last_name",
|
||||
],
|
||||
)
|
||||
# Add profile picture URL if exists
|
||||
if getattr(user, "profile_picture", None):
|
||||
if request:
|
||||
data["profile_picture"] = request.build_absolute_uri(user.profile_picture.url)
|
||||
else:
|
||||
data["profile_picture"] = user.profile_picture.url
|
||||
else:
|
||||
data["profile_picture"] = None
|
||||
return data
|
||||
|
||||
|
||||
def _user_to_dict(user, request=None):
|
||||
"""Serialize any User for JSON (admin/staff or partner)."""
|
||||
return _partner_user_to_dict(user, request)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class PartnerLoginAPI(APIView):
|
||||
"""
|
||||
Partner Login API.
|
||||
Body: username (or email), password (required).
|
||||
Returns: token, user data.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
# Parse JSON or form data
|
||||
is_multipart = request.content_type and "multipart/form-data" in request.content_type
|
||||
if is_multipart:
|
||||
data = request.POST.dict()
|
||||
else:
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "Invalid JSON"},
|
||||
status=400,
|
||||
)
|
||||
|
||||
username = data.get("username") or data.get("email")
|
||||
password = data.get("password")
|
||||
|
||||
if not username or not password:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "username and password are required."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
# Authenticate user
|
||||
user = authenticate(request, username=username, password=password)
|
||||
if not user:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "Invalid username or password."},
|
||||
status=401,
|
||||
)
|
||||
|
||||
# Check if user has partner role
|
||||
partner_roles = ["partner", "partner_manager", "partner_staff"]
|
||||
if user.role not in partner_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to access partner portal."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
# Get or create token
|
||||
token, _ = Token.objects.get_or_create(user=user)
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Login successful",
|
||||
"token": token.key,
|
||||
"user": _partner_user_to_dict(user, request),
|
||||
},
|
||||
status=200,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class PartnerLogoutAPI(APIView):
|
||||
"""
|
||||
Partner Logout API.
|
||||
Body: token, username (required).
|
||||
Returns: success message.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True)
|
||||
if error_response:
|
||||
return error_response
|
||||
|
||||
# Check if user has partner role
|
||||
partner_roles = ["partner", "partner_manager", "partner_staff"]
|
||||
if user.role not in partner_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to access partner portal."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
# Delete token
|
||||
token.delete()
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Logged out successfully.",
|
||||
},
|
||||
status=200,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class PartnerDashboardAPI(APIView):
|
||||
"""
|
||||
Partner Dashboard API.
|
||||
Body: token, username (required).
|
||||
Returns: dashboard statistics.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True)
|
||||
if error_response:
|
||||
return error_response
|
||||
|
||||
# Check if user has partner role
|
||||
partner_roles = ["partner", "partner_manager", "partner_staff"]
|
||||
if user.role not in partner_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to access this page."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
# Get statistics for partner users (including partner_customer)
|
||||
all_partner_roles = ["partner", "partner_manager", "partner_staff", "partner_customer"]
|
||||
partner_users = User.objects.filter(role__in=all_partner_roles)
|
||||
total_partner_users = partner_users.count()
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"dashboard": {
|
||||
"total_partner_users": total_partner_users,
|
||||
},
|
||||
},
|
||||
status=200,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class PartnerListUsersAPI(APIView):
|
||||
"""
|
||||
Partner List Users API.
|
||||
Body: token, username (required);
|
||||
role (optional filter: partner, partner_manager, partner_staff, partner_customer).
|
||||
Returns: list of partner users.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True)
|
||||
if error_response:
|
||||
return error_response
|
||||
|
||||
# Check if user has partner role
|
||||
partner_roles = ["partner", "partner_manager", "partner_staff"]
|
||||
if user.role not in partner_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to access this page."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
# Filter users by partner-related roles
|
||||
all_partner_roles = ["partner", "partner_manager", "partner_staff", "partner_customer"]
|
||||
qs = User.objects.filter(role__in=all_partner_roles).order_by("-id")
|
||||
|
||||
# Optional role filter
|
||||
role_filter = data.get("role")
|
||||
if role_filter:
|
||||
if role_filter not in all_partner_roles:
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "error",
|
||||
"message": f"Invalid role filter. Must be one of: {', '.join(all_partner_roles)}",
|
||||
},
|
||||
status=400,
|
||||
)
|
||||
qs = qs.filter(role=role_filter)
|
||||
|
||||
users = [_partner_user_to_dict(u, request) for u in qs]
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"users": users,
|
||||
"total_count": len(users),
|
||||
},
|
||||
status=200,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class PartnerCreateUserAPI(APIView):
|
||||
"""
|
||||
Partner Create User API.
|
||||
Body: token, username, username (for new user), email, password, role (required);
|
||||
full_name, phone_number, pincode, district, state, country, place, latitude, longitude (optional).
|
||||
Returns: created user data.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True)
|
||||
if error_response:
|
||||
return error_response
|
||||
|
||||
# Check if user has partner role
|
||||
partner_roles = ["partner", "partner_manager", "partner_staff"]
|
||||
if user.role not in partner_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to access this page."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
# Extract user data
|
||||
new_username = data.get("username")
|
||||
email = data.get("email")
|
||||
password = data.get("password")
|
||||
role = data.get("role")
|
||||
full_name = data.get("full_name", "").strip()
|
||||
|
||||
if not all([new_username, email, password, role]):
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "error",
|
||||
"message": "username, email, password, and role are required.",
|
||||
},
|
||||
status=400,
|
||||
)
|
||||
|
||||
# Validate role - must be one of the partner-related roles
|
||||
valid_partner_roles = ["partner", "partner_manager", "partner_staff", "partner_customer"]
|
||||
if role not in valid_partner_roles:
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "error",
|
||||
"message": f"Invalid role. Must be one of: {', '.join(valid_partner_roles)}",
|
||||
},
|
||||
status=400,
|
||||
)
|
||||
|
||||
# Check if username already exists
|
||||
if User.objects.filter(username=new_username).exists():
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "Username already exists."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
# Check if email already exists
|
||||
if User.objects.filter(email=email).exists():
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "Email already exists."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
# Create user
|
||||
new_user = User.objects.create_user(
|
||||
username=new_username,
|
||||
email=email,
|
||||
password=password,
|
||||
role=role,
|
||||
phone_number=data.get("phone_number"),
|
||||
pincode=data.get("pincode"),
|
||||
district=data.get("district"),
|
||||
state=data.get("state"),
|
||||
country=data.get("country"),
|
||||
place=data.get("place"),
|
||||
)
|
||||
|
||||
# Handle full_name - split into first_name and last_name
|
||||
if full_name:
|
||||
parts = full_name.split(None, 1)
|
||||
new_user.first_name = parts[0]
|
||||
if len(parts) > 1:
|
||||
new_user.last_name = parts[1]
|
||||
|
||||
# Set location coordinates if provided
|
||||
if data.get("latitude") is not None:
|
||||
try:
|
||||
latitude = float(data["latitude"])
|
||||
if latitude < -90 or latitude > 90:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "latitude must be between -90 and 90."},
|
||||
status=400,
|
||||
)
|
||||
new_user.latitude = latitude
|
||||
except (TypeError, ValueError):
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "latitude must be numeric."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
if data.get("longitude") is not None:
|
||||
try:
|
||||
longitude = float(data["longitude"])
|
||||
if longitude < -180 or longitude > 180:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "longitude must be between -180 and 180."},
|
||||
status=400,
|
||||
)
|
||||
new_user.longitude = longitude
|
||||
except (TypeError, ValueError):
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "longitude must be numeric."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
# Handle profile picture upload if provided
|
||||
if "profile_picture" in request.FILES:
|
||||
new_user.profile_picture = request.FILES["profile_picture"]
|
||||
|
||||
new_user.save()
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"message": f"User created successfully with role: {role}.",
|
||||
"user": _partner_user_to_dict(new_user, request),
|
||||
},
|
||||
status=201,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class PartnerUpdateUserAPI(APIView):
|
||||
"""
|
||||
Partner Update User API.
|
||||
Body: token, username, user_id (required);
|
||||
email, phone_number, role, full_name, pincode, district, state,
|
||||
country, place, latitude, longitude, password, profile_picture (optional).
|
||||
Returns: updated user data.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True)
|
||||
if error_response:
|
||||
return error_response
|
||||
|
||||
# Check if user has partner role
|
||||
partner_roles = ["partner", "partner_manager", "partner_staff"]
|
||||
if user.role not in partner_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to access this page."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
user_id = data.get("user_id")
|
||||
if not user_id:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "user_id is required."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
try:
|
||||
target_user = User.objects.get(id=user_id)
|
||||
except User.DoesNotExist:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "User not found."},
|
||||
status=404,
|
||||
)
|
||||
|
||||
# Validate that the user has a partner-related role
|
||||
all_partner_roles = ["partner", "partner_manager", "partner_staff", "partner_customer"]
|
||||
if target_user.role not in all_partner_roles:
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "error",
|
||||
"message": "User is not a partner-related user. Only users with partner roles can be updated.",
|
||||
},
|
||||
status=400,
|
||||
)
|
||||
|
||||
# Update fields if provided
|
||||
if data.get("email") is not None:
|
||||
new_email = data["email"]
|
||||
# Check if email already exists for another user
|
||||
if User.objects.filter(email=new_email).exclude(id=user_id).exists():
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "Email already exists for another user."},
|
||||
status=400,
|
||||
)
|
||||
target_user.email = new_email
|
||||
|
||||
if data.get("phone_number") is not None:
|
||||
target_user.phone_number = data["phone_number"] or None
|
||||
|
||||
if data.get("role") is not None:
|
||||
new_role = data["role"]
|
||||
if new_role not in all_partner_roles:
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "error",
|
||||
"message": f"Invalid role. Must be one of: {', '.join(all_partner_roles)}",
|
||||
},
|
||||
status=400,
|
||||
)
|
||||
target_user.role = new_role
|
||||
|
||||
# Handle full_name
|
||||
if data.get("full_name"):
|
||||
full_name = data["full_name"].strip()
|
||||
if full_name:
|
||||
parts = full_name.split(None, 1)
|
||||
target_user.first_name = parts[0]
|
||||
if len(parts) > 1:
|
||||
target_user.last_name = parts[1]
|
||||
else:
|
||||
target_user.last_name = ""
|
||||
|
||||
if "pincode" in data:
|
||||
target_user.pincode = data["pincode"] or None
|
||||
if "district" in data:
|
||||
target_user.district = data["district"] or None
|
||||
if "state" in data:
|
||||
target_user.state = data["state"] or None
|
||||
if "country" in data:
|
||||
target_user.country = data["country"] or None
|
||||
if "place" in data:
|
||||
target_user.place = data["place"] or None
|
||||
|
||||
if data.get("latitude") is not None:
|
||||
try:
|
||||
latitude = float(data["latitude"])
|
||||
if latitude < -90 or latitude > 90:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "latitude must be between -90 and 90."},
|
||||
status=400,
|
||||
)
|
||||
target_user.latitude = latitude
|
||||
except (TypeError, ValueError):
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "latitude must be numeric."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
if data.get("longitude") is not None:
|
||||
try:
|
||||
longitude = float(data["longitude"])
|
||||
if longitude < -180 or longitude > 180:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "longitude must be between -180 and 180."},
|
||||
status=400,
|
||||
)
|
||||
target_user.longitude = longitude
|
||||
except (TypeError, ValueError):
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "longitude must be numeric."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
# Handle profile picture upload if provided
|
||||
if "profile_picture" in request.FILES:
|
||||
target_user.profile_picture = request.FILES["profile_picture"]
|
||||
|
||||
# Handle password update if provided
|
||||
if data.get("password"):
|
||||
target_user.set_password(data["password"])
|
||||
|
||||
target_user.save()
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Partner user updated successfully.",
|
||||
"user": _partner_user_to_dict(target_user, request),
|
||||
},
|
||||
status=200,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class PartnerDeleteUserAPI(APIView):
|
||||
"""
|
||||
Partner Delete User API.
|
||||
Body: token, username, user_id (required).
|
||||
Returns: success message.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True)
|
||||
if error_response:
|
||||
return error_response
|
||||
|
||||
# Check if user has partner role
|
||||
partner_roles = ["partner", "partner_manager", "partner_staff"]
|
||||
if user.role not in partner_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to access this page."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
user_id = data.get("user_id")
|
||||
if not user_id:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "user_id is required."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
try:
|
||||
target_user = User.objects.get(id=user_id)
|
||||
except User.DoesNotExist:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "User not found."},
|
||||
status=404,
|
||||
)
|
||||
|
||||
# Validate that the user has a partner-related role
|
||||
all_partner_roles = ["partner", "partner_manager", "partner_staff", "partner_customer"]
|
||||
if target_user.role not in all_partner_roles:
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "error",
|
||||
"message": "User is not a partner-related user. Only users with partner roles can be deleted.",
|
||||
},
|
||||
status=400,
|
||||
)
|
||||
|
||||
# Prevent deleting yourself
|
||||
if target_user.id == user.id:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You cannot delete your own account."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
username = target_user.username
|
||||
target_user.delete()
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"message": f"Partner user '{username}' deleted successfully.",
|
||||
},
|
||||
status=200,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class LoginAPI(APIView):
|
||||
"""
|
||||
Admin/Staff Login API (accounts).
|
||||
Body: username (or email), password (required).
|
||||
Returns: token and user details for admin/manager/staff roles.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
# Parse JSON or form data
|
||||
is_multipart = request.content_type and "multipart/form-data" in request.content_type
|
||||
if is_multipart:
|
||||
data = request.POST.dict()
|
||||
else:
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "Invalid JSON"},
|
||||
status=400,
|
||||
)
|
||||
|
||||
username = data.get("username") or data.get("email")
|
||||
password = data.get("password")
|
||||
|
||||
if not username or not password:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "username and password are required."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
user = authenticate(request, username=username, password=password)
|
||||
if not user:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "Invalid username or password."},
|
||||
status=401,
|
||||
)
|
||||
|
||||
# Only allow admin/manager/staff to use this login
|
||||
allowed_roles = ["admin", "manager", "staff"]
|
||||
if user.role not in allowed_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to access the admin portal."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
token, _ = Token.objects.get_or_create(user=user)
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Login successful",
|
||||
"token": token.key,
|
||||
"user": _user_to_dict(user, request),
|
||||
},
|
||||
status=200,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class LogoutAPI(APIView):
|
||||
"""
|
||||
Logout API for token-based sessions.
|
||||
Body: token, username (required).
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True)
|
||||
if error_response:
|
||||
return error_response
|
||||
|
||||
logout(request)
|
||||
token.delete()
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Logout successful.",
|
||||
},
|
||||
status=200,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class UserListAPI(APIView):
|
||||
"""
|
||||
List users (admin / manager / staff only).
|
||||
Body: token, username (required); optional role filter.
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True)
|
||||
if error_response:
|
||||
return error_response
|
||||
|
||||
# Only allow admin/manager/staff to list users
|
||||
allowed_roles = ["admin", "manager", "staff"]
|
||||
if user.role not in allowed_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to list users."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
qs = User.objects.all().order_by("-id")
|
||||
role_filter = data.get("role")
|
||||
if role_filter:
|
||||
qs = qs.filter(role=role_filter)
|
||||
|
||||
users = [_user_to_dict(u, request) for u in qs]
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"users": users,
|
||||
"total_count": len(users),
|
||||
},
|
||||
status=200,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class UserCreateAPI(APIView):
|
||||
"""
|
||||
Create a user (admin / manager / staff only).
|
||||
Body: token, username, new_username, email, password, role ('admin'|'manager'|'staff'), phone_number (optional).
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True)
|
||||
if error_response:
|
||||
return error_response
|
||||
|
||||
allowed_roles = ["admin", "manager", "staff"]
|
||||
if user.role not in allowed_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to create users."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
new_username = data.get("username") or data.get("new_username")
|
||||
email = data.get("email")
|
||||
password = data.get("password")
|
||||
role = data.get("role")
|
||||
|
||||
if not all([new_username, email, password, role]):
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "error",
|
||||
"message": "username, email, password, and role are required.",
|
||||
},
|
||||
status=400,
|
||||
)
|
||||
|
||||
valid_roles = ["admin", "manager", "staff"]
|
||||
if role not in valid_roles:
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "error",
|
||||
"message": f"Invalid role. Must be one of: {', '.join(valid_roles)}",
|
||||
},
|
||||
status=400,
|
||||
)
|
||||
|
||||
if User.objects.filter(username=new_username).exists():
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "Username already exists."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
if User.objects.filter(email=email).exists():
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "Email already exists."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
new_user = User.objects.create_user(
|
||||
username=new_username,
|
||||
email=email,
|
||||
password=password,
|
||||
role=role,
|
||||
phone_number=data.get("phone_number"),
|
||||
)
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"message": f"User created successfully with role: {role}.",
|
||||
"user": _user_to_dict(new_user, request),
|
||||
},
|
||||
status=201,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class UserUpdateAPI(APIView):
|
||||
"""
|
||||
Update a user (admin / manager / staff only).
|
||||
Body: token, username, user_id (required); email, phone_number, role (optional).
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True)
|
||||
if error_response:
|
||||
return error_response
|
||||
|
||||
allowed_roles = ["admin", "manager", "staff"]
|
||||
if user.role not in allowed_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to update users."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
user_id = data.get("user_id")
|
||||
if not user_id:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "user_id is required."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
try:
|
||||
target_user = User.objects.get(id=user_id)
|
||||
except User.DoesNotExist:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "User not found."},
|
||||
status=404,
|
||||
)
|
||||
|
||||
if data.get("email") is not None:
|
||||
new_email = data["email"]
|
||||
if User.objects.filter(email=new_email).exclude(id=user_id).exists():
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "Email already exists for another user."},
|
||||
status=400,
|
||||
)
|
||||
target_user.email = new_email
|
||||
|
||||
if data.get("phone_number") is not None:
|
||||
target_user.phone_number = data["phone_number"] or None
|
||||
|
||||
if data.get("role") is not None:
|
||||
new_role = data["role"]
|
||||
valid_roles = ["admin", "manager", "staff"]
|
||||
if new_role not in valid_roles:
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "error",
|
||||
"message": f"Invalid role. Must be one of: {', '.join(valid_roles)}",
|
||||
},
|
||||
status=400,
|
||||
)
|
||||
target_user.role = new_role
|
||||
|
||||
target_user.save()
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"message": "User updated successfully.",
|
||||
"user": _user_to_dict(target_user, request),
|
||||
},
|
||||
status=200,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class UserDeleteAPI(APIView):
|
||||
"""
|
||||
Delete a user (admin / manager / staff only).
|
||||
Body: token, username, user_id (required).
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user, token, data, error_response = validate_token_and_get_user(request, error_status_code=True)
|
||||
if error_response:
|
||||
return error_response
|
||||
|
||||
allowed_roles = ["admin", "manager", "staff"]
|
||||
if user.role not in allowed_roles:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You are not authorized to delete users."},
|
||||
status=403,
|
||||
)
|
||||
|
||||
user_id = data.get("user_id")
|
||||
if not user_id:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "user_id is required."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
try:
|
||||
target_user = User.objects.get(id=user_id)
|
||||
except User.DoesNotExist:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "User not found."},
|
||||
status=404,
|
||||
)
|
||||
|
||||
if target_user.id == user.id:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "You cannot delete your own account."},
|
||||
status=400,
|
||||
)
|
||||
|
||||
username = target_user.username
|
||||
target_user.delete()
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
"message": f"User '{username}' deleted successfully.",
|
||||
},
|
||||
status=200,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
@@ -88,3 +88,110 @@ class LoginForm(AuthenticationForm):
|
||||
"placeholder": "Enter password"
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
class PartnerUserForm(forms.ModelForm):
|
||||
full_name = forms.CharField(
|
||||
max_length=150,
|
||||
required=True,
|
||||
label="Full Name"
|
||||
)
|
||||
password = forms.CharField(
|
||||
widget=forms.PasswordInput,
|
||||
label="Password",
|
||||
required=True,
|
||||
help_text="Required for new users. Leave blank if you don't want to change the password when editing."
|
||||
)
|
||||
confirm_password = forms.CharField(
|
||||
widget=forms.PasswordInput,
|
||||
label="Confirm Password",
|
||||
required=True
|
||||
)
|
||||
|
||||
phone_number = forms.CharField(
|
||||
max_length=15,
|
||||
required=False,
|
||||
label="Phone Number"
|
||||
)
|
||||
|
||||
ROLE_CHOICES = [
|
||||
('partner', 'Partner'),
|
||||
('partner_manager', 'Partner Manager'),
|
||||
('partner_staff', 'Partner Staff'),
|
||||
('partner_customer', 'Partner Customer'),
|
||||
]
|
||||
|
||||
role = forms.ChoiceField(
|
||||
choices=ROLE_CHOICES,
|
||||
required=True,
|
||||
label="Role"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ["username", "email", "phone_number", "role"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
for field in self.fields.values():
|
||||
field.widget.attrs.update({"class": "form-control"})
|
||||
|
||||
# Make password fields optional for updates, required for new users
|
||||
if self.instance and self.instance.pk:
|
||||
self.fields['password'].required = False
|
||||
self.fields['confirm_password'].required = False
|
||||
# Pre-populate full_name from first_name and last_name
|
||||
if self.instance.first_name or self.instance.last_name:
|
||||
self.fields['full_name'].initial = f"{self.instance.first_name} {self.instance.last_name}".strip()
|
||||
else:
|
||||
# For new users, password is required
|
||||
self.fields['password'].required = True
|
||||
self.fields['confirm_password'].required = True
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
password = cleaned_data.get("password")
|
||||
confirm_password = cleaned_data.get("confirm_password")
|
||||
|
||||
# For new users, password is required
|
||||
if not self.instance or not self.instance.pk:
|
||||
if not password:
|
||||
self.add_error("password", "Password is required for new users.")
|
||||
if not confirm_password:
|
||||
self.add_error("confirm_password", "Please confirm your password.")
|
||||
|
||||
# Validate password match if password is provided
|
||||
if password or confirm_password:
|
||||
if password != confirm_password:
|
||||
self.add_error("confirm_password", "Passwords do not match!")
|
||||
|
||||
return cleaned_data
|
||||
|
||||
def save(self, commit=True):
|
||||
user = super().save(commit=False)
|
||||
|
||||
# Set password - required for new users, optional for updates
|
||||
password = self.cleaned_data.get('password')
|
||||
if password:
|
||||
user.set_password(password)
|
||||
elif not user.pk:
|
||||
# New user must have a password
|
||||
raise ValueError("Password is required for new users.")
|
||||
|
||||
# Save phone_number and role to the User model
|
||||
user.phone_number = self.cleaned_data.get("phone_number")
|
||||
user.role = self.cleaned_data.get("role")
|
||||
|
||||
# Handle full_name - split into first_name and last_name
|
||||
full_name = self.cleaned_data.get("full_name", "").strip()
|
||||
if full_name:
|
||||
parts = full_name.split(None, 1)
|
||||
user.first_name = parts[0]
|
||||
if len(parts) > 1:
|
||||
user.last_name = parts[1]
|
||||
else:
|
||||
user.last_name = ""
|
||||
|
||||
if commit:
|
||||
user.save()
|
||||
return user
|
||||
|
||||
18
accounts/migrations/0008_alter_user_role.py
Normal file
18
accounts/migrations/0008_alter_user_role.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.27 on 2026-03-13 16:55
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0007_alter_user_profile_picture'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='role',
|
||||
field=models.CharField(choices=[('admin', 'Admin'), ('manager', 'Manager'), ('staff', 'Staff'), ('customer', 'Customer'), ('partner', 'Partner'), ('partner_manager', 'Partner Manager'), ('partner_staff', 'Partner Staff'), ('partner_customer', 'Partner Customer')], default='Staff', max_length=20),
|
||||
),
|
||||
]
|
||||
20
accounts/migrations/0009_user_partner.py
Normal file
20
accounts/migrations/0009_user_partner.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Generated by Django 4.2.27 on 2026-03-14 07:00
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('partner', '0001_initial'),
|
||||
('accounts', '0008_alter_user_role'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='partner',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='partner.partner'),
|
||||
),
|
||||
]
|
||||
@@ -2,18 +2,24 @@ from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
|
||||
from accounts.manager import UserManager
|
||||
|
||||
from partner.models import Partner
|
||||
ROLE_CHOICES = (
|
||||
('admin', 'Admin'),
|
||||
('manager', 'Manager'),
|
||||
('staff', 'Staff'),
|
||||
('customer', 'Customer'),
|
||||
('partner', 'Partner'),
|
||||
('partner_manager', 'Partner Manager'),
|
||||
('partner_staff', 'Partner Staff'),
|
||||
('partner_customer', 'Partner Customer'),
|
||||
)
|
||||
|
||||
|
||||
class User(AbstractUser):
|
||||
phone_number = models.CharField(max_length=15, blank=True, null=True)
|
||||
role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='Staff')
|
||||
|
||||
partner = models.ForeignKey(Partner, on_delete=models.CASCADE, blank=True, null=True)
|
||||
|
||||
is_staff = models.BooleanField(default=False)
|
||||
is_customer = models.BooleanField(default=False)
|
||||
is_user = models.BooleanField(default=False)
|
||||
|
||||
@@ -1,14 +1,37 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
from . import views, api
|
||||
|
||||
app_name = 'accounts'
|
||||
app_name = "accounts"
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', views.login_view, name='login'),
|
||||
path('logout/', views.logout_view, name='logout'),
|
||||
path('dashboard/', views.dashboard, name='dashboard'),
|
||||
path('users/', views.UserListView.as_view(), name='user_list'),
|
||||
path('users/add/', views.UserCreateView.as_view(), name='user_add'),
|
||||
path('users/<int:pk>/edit/', views.UserUpdateView.as_view(), name='user_edit'),
|
||||
path('users/<int:pk>/delete/', views.UserDeleteView.as_view(), name='user_delete'),
|
||||
path("login/", views.login_view, name="login"),
|
||||
path("logout/", views.logout_view, name="logout"),
|
||||
path("dashboard/", views.dashboard, name="dashboard"),
|
||||
path("users/", views.UserListView.as_view(), name="user_list"),
|
||||
path("users/add/", views.UserCreateView.as_view(), name="user_add"),
|
||||
path("users/<int:pk>/edit/", views.UserUpdateView.as_view(), name="user_edit"),
|
||||
path("users/<int:pk>/delete/", views.UserDeleteView.as_view(), name="user_delete"),
|
||||
]
|
||||
|
||||
|
||||
# Core account APIs (admin/staff)
|
||||
urlpatterns += [
|
||||
path("api/login/", api.LoginAPI.as_view(), name="api_login"),
|
||||
path("api/logout/", api.LogoutAPI.as_view(), name="api_logout"),
|
||||
path("api/users/list/", api.UserListAPI.as_view(), name="api_user_list"),
|
||||
path("api/users/create/", api.UserCreateAPI.as_view(), name="api_user_create"),
|
||||
path("api/users/update/", api.UserUpdateAPI.as_view(), name="api_user_update"),
|
||||
path("api/users/delete/", api.UserDeleteAPI.as_view(), name="api_user_delete"),
|
||||
]
|
||||
|
||||
|
||||
# Partner APIs
|
||||
urlpatterns += [
|
||||
path("api/partner/login/", api.PartnerLoginAPI.as_view(), name="partner_api_login"),
|
||||
path("api/partner/logout/", api.PartnerLogoutAPI.as_view(), name="partner_api_logout"),
|
||||
path("api/partner/dashboard/", api.PartnerDashboardAPI.as_view(), name="partner_api_dashboard"),
|
||||
path("api/partner/users/list/", api.PartnerListUsersAPI.as_view(), name="partner_api_user_list"),
|
||||
path("api/partner/users/create/", api.PartnerCreateUserAPI.as_view(), name="partner_api_user_create"),
|
||||
path("api/partner/users/update/", api.PartnerUpdateUserAPI.as_view(), name="partner_api_user_update"),
|
||||
path("api/partner/users/delete/", api.PartnerDeleteUserAPI.as_view(), name="partner_api_user_delete"),
|
||||
]
|
||||
@@ -1,16 +1,16 @@
|
||||
from django.shortcuts import render
|
||||
from django.shortcuts import render, redirect
|
||||
from django.views import generic
|
||||
from django.urls import reverse_lazy
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
|
||||
from .models import User
|
||||
from .forms import LoginForm
|
||||
from .forms import UserForm
|
||||
from .forms import LoginForm, UserForm, PartnerUserForm
|
||||
from events.models import Event
|
||||
from master_data.models import EventType
|
||||
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.shortcuts import redirect
|
||||
from django.contrib import messages
|
||||
from eventify_logger.services import log
|
||||
|
||||
|
||||
def dashboard(request):
|
||||
@@ -62,16 +62,150 @@ def login_view(request):
|
||||
user = form.get_user()
|
||||
login(request, user)
|
||||
if user.role == 'admin' or user.role == 'manager' or user.role == 'staff':
|
||||
log("info", "Admin/Manager/Staff login", request=request, user=user)
|
||||
return redirect("accounts:dashboard")
|
||||
else:
|
||||
log("warning", "Login attempt - user not authorized", request=request, user=user)
|
||||
messages.error(request, "You are not authorized to access this page.")
|
||||
else:
|
||||
log("warning", "Invalid login attempt", request=request)
|
||||
messages.error(request, "Invalid username or password")
|
||||
|
||||
return render(request, "accounts/login.html", {"form": form})
|
||||
|
||||
|
||||
def logout_view(request):
|
||||
if request.user.is_authenticated:
|
||||
log("info", "User logout", request=request, user=request.user)
|
||||
logout(request)
|
||||
messages.success(request, "You have been logged out successfully.")
|
||||
return redirect("accounts:login")
|
||||
return redirect("accounts:login")
|
||||
|
||||
|
||||
# Partner Views Mixin
|
||||
class PartnerRequiredMixin(LoginRequiredMixin):
|
||||
"""Mixin to ensure user has partner role (partner, partner_manager, partner_staff)"""
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_authenticated:
|
||||
return self.handle_no_permission()
|
||||
partner_roles = ['partner', 'partner_manager', 'partner_staff']
|
||||
if request.user.role not in partner_roles:
|
||||
raise PermissionDenied("You are not authorized to access this page.")
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
# Partner Login/Logout/Dashboard
|
||||
def partner_login_view(request):
|
||||
if request.user.is_authenticated:
|
||||
partner_roles = ['partner', 'partner_manager', 'partner_staff']
|
||||
if request.user.role in partner_roles:
|
||||
return redirect("accounts:partner_dashboard")
|
||||
else:
|
||||
messages.error(request, "You are not authorized to access partner portal.")
|
||||
return redirect("accounts:login")
|
||||
|
||||
form = LoginForm(request, data=request.POST or None)
|
||||
|
||||
if request.method == "POST":
|
||||
if form.is_valid():
|
||||
user = form.get_user()
|
||||
partner_roles = ['partner', 'partner_manager', 'partner_staff']
|
||||
if user.role in partner_roles:
|
||||
log("info", "Partner portal login", request=request, user=user)
|
||||
login(request, user)
|
||||
return redirect("accounts:partner_dashboard")
|
||||
else:
|
||||
log("warning", "Partner login - user not authorized", request=request, user=user)
|
||||
messages.error(request, "You are not authorized to access partner portal.")
|
||||
else:
|
||||
log("warning", "Partner portal - invalid login attempt", request=request)
|
||||
messages.error(request, "Invalid username or password")
|
||||
|
||||
return render(request, "partner/login.html", {"form": form})
|
||||
|
||||
|
||||
def partner_logout_view(request):
|
||||
if request.user.is_authenticated:
|
||||
log("info", "Partner portal logout", request=request, user=request.user)
|
||||
logout(request)
|
||||
messages.success(request, "You have been logged out successfully.")
|
||||
return redirect("accounts:partner_login")
|
||||
|
||||
|
||||
def partner_dashboard(request):
|
||||
"""Partner dashboard view"""
|
||||
partner_roles = ['partner', 'partner_manager', 'partner_staff']
|
||||
if not request.user.is_authenticated or request.user.role not in partner_roles:
|
||||
messages.error(request, "You are not authorized to access this page.")
|
||||
return redirect("accounts:partner_login")
|
||||
|
||||
# Get statistics for partner users (including partner_customer)
|
||||
all_partner_roles = ['partner', 'partner_manager', 'partner_staff', 'partner_customer']
|
||||
partner_users = User.objects.filter(role__in=all_partner_roles)
|
||||
total_partner_users = partner_users.count()
|
||||
|
||||
# You can add more partner-specific statistics here
|
||||
# For example, events created by partner, bookings, etc.
|
||||
|
||||
return render(request, 'partner/dashboard.html', {
|
||||
'total_partner_users': total_partner_users,
|
||||
})
|
||||
|
||||
|
||||
# Partner User Management Views
|
||||
class PartnerUserListView(PartnerRequiredMixin, generic.ListView):
|
||||
model = User
|
||||
template_name = 'partner/user_list.html'
|
||||
context_object_name = 'users'
|
||||
paginate_by = 20
|
||||
|
||||
def get_queryset(self):
|
||||
"""Filter users to show only partner-related roles"""
|
||||
partner_roles = ['partner', 'partner_manager', 'partner_staff', 'partner_customer']
|
||||
return User.objects.filter(role__in=partner_roles).order_by('-id')
|
||||
|
||||
|
||||
class PartnerUserCreateView(PartnerRequiredMixin, generic.CreateView):
|
||||
model = User
|
||||
form_class = PartnerUserForm
|
||||
template_name = 'partner/user_form.html'
|
||||
success_url = reverse_lazy('accounts:partner_user_list')
|
||||
|
||||
def form_valid(self, form):
|
||||
messages.success(self.request, "Partner user created successfully.")
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class PartnerUserUpdateView(PartnerRequiredMixin, generic.UpdateView):
|
||||
model = User
|
||||
form_class = PartnerUserForm
|
||||
template_name = 'partner/user_form.html'
|
||||
success_url = reverse_lazy('accounts:partner_user_list')
|
||||
|
||||
def get_queryset(self):
|
||||
"""Only allow editing users with partner-related roles"""
|
||||
partner_roles = ['partner', 'partner_manager', 'partner_staff', 'partner_customer']
|
||||
return User.objects.filter(role__in=partner_roles)
|
||||
|
||||
def form_valid(self, form):
|
||||
messages.success(self.request, "Partner user updated successfully.")
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class PartnerUserDeleteView(PartnerRequiredMixin, generic.DeleteView):
|
||||
model = User
|
||||
template_name = 'partner/user_confirm_delete.html'
|
||||
success_url = reverse_lazy('accounts:partner_user_list')
|
||||
|
||||
def get_queryset(self):
|
||||
"""Only allow deleting users with partner-related roles"""
|
||||
partner_roles = ['partner', 'partner_manager', 'partner_staff', 'partner_customer']
|
||||
return User.objects.filter(role__in=partner_roles)
|
||||
|
||||
def delete(self, request, *args, **kwargs):
|
||||
# Prevent users from deleting themselves
|
||||
if self.get_object().id == request.user.id:
|
||||
messages.error(request, "You cannot delete your own account.")
|
||||
return redirect(self.success_url)
|
||||
messages.success(request, "Partner user deleted successfully.")
|
||||
return super().delete(request, *args, **kwargs)
|
||||
Reference in New Issue
Block a user