block user in django admin
This commit is contained in:
1 parent
089db0afa4
commit
fe7a10cb61
19 files changed
+574
-11
No files matched your search
@@ -2,3 +2,6 @@ from django.apps import AppConfig
|
||||
class AccountsConfig(AppConfig):
|
||||
name = "apps.accounts"
|
||||
|
||||
def ready(self):
|
||||
from . import customer_access # Register the login-session receiver.
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
"""Restrictions for full customer logins; staff and scoped links stay independent."""
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import logout
|
||||
from django.contrib.auth.signals import user_logged_in
|
||||
from django.dispatch import receiver
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from django.views.decorators.cache import never_cache
|
||||
from django.views.decorators.http import require_GET
|
||||
from django.utils.cache import add_never_cache_headers
|
||||
|
||||
from apps.customers.models import CustomerProfile
|
||||
from .models import User
|
||||
|
||||
|
||||
ACCESS_VERSION_KEY = "customer_login_access_version"
|
||||
BLOCK_REASON_KEY = "customer_login_block_reason"
|
||||
DEFAULT_BLOCK_REASON = "ورود شما مسدود شده است. برای پیگیری با پشتیبانی تماس بگیرید."
|
||||
|
||||
|
||||
def is_customer_login(user):
|
||||
return user.account_type == User.AccountType.CUSTOMER and not (user.is_staff or user.is_superuser)
|
||||
|
||||
|
||||
def customer_login_profile(user):
|
||||
if not is_customer_login(user):
|
||||
return None
|
||||
return CustomerProfile.objects.filter(user_id=user.pk).first()
|
||||
|
||||
|
||||
def blocked_login_reason(mobile):
|
||||
user = User.objects.filter(mobile=mobile).first()
|
||||
profile = customer_login_profile(user) if user else None
|
||||
if profile and profile.login_blocked:
|
||||
return profile.login_block_reason.strip() or DEFAULT_BLOCK_REASON
|
||||
return ""
|
||||
|
||||
|
||||
@receiver(user_logged_in, dispatch_uid="customer_login_access_version")
|
||||
def remember_customer_access(sender, request, user, **kwargs):
|
||||
if not is_customer_login(user):
|
||||
return
|
||||
profile = customer_login_profile(user)
|
||||
request.session[ACCESS_VERSION_KEY] = profile.login_access_version if profile else 0
|
||||
request.session.pop(BLOCK_REASON_KEY, None)
|
||||
|
||||
|
||||
class CustomerLoginAccessMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
if request.user.is_authenticated:
|
||||
profile = customer_login_profile(request.user)
|
||||
if profile and (
|
||||
profile.login_blocked
|
||||
or request.session.get(ACCESS_VERSION_KEY, 0) != profile.login_access_version
|
||||
):
|
||||
logout(request)
|
||||
if profile.login_blocked:
|
||||
request.session[BLOCK_REASON_KEY] = profile.login_block_reason.strip() or DEFAULT_BLOCK_REASON
|
||||
else:
|
||||
messages.error(request, "نشست قبلی شما باطل شده است. لطفاً دوباره وارد شوید.")
|
||||
if request.path == reverse("accounts:login_access"):
|
||||
response = JsonResponse({"authenticated": False, "login_url": reverse("accounts:login")})
|
||||
else:
|
||||
response = redirect("accounts:login")
|
||||
add_never_cache_headers(response)
|
||||
return response
|
||||
return self.get_response(request)
|
||||
|
||||
|
||||
@never_cache
|
||||
@require_GET
|
||||
def customer_login_access(request):
|
||||
return JsonResponse({
|
||||
"authenticated": request.user.is_authenticated,
|
||||
"login_url": reverse("accounts:login"),
|
||||
})
|
||||
@@ -1,9 +1,11 @@
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
from .customer_access import customer_login_access
|
||||
|
||||
app_name = "accounts"
|
||||
urlpatterns = [
|
||||
path("login/access/", customer_login_access, name="login_access"),
|
||||
path("", views.home, name="home"),
|
||||
path("login/", views.customer_login, name="login"),
|
||||
path("login/password/", views.customer_password_login, name="password_login"),
|
||||
|
||||
+16
-2
@@ -14,6 +14,7 @@ from django.db import transaction
|
||||
from django.db.models import F
|
||||
from .models import MagicLinkAccessLog, OTPChallenge, TicketMagicLink, User
|
||||
from .magic_access import grant_ticket_magic_access
|
||||
from .customer_access import BLOCK_REASON_KEY, blocked_login_reason
|
||||
from apps.integrations.sms.providers import SMSResult, get_sms_provider
|
||||
import logging
|
||||
|
||||
@@ -46,7 +47,11 @@ def customer_login(request):
|
||||
_remember_destination(request)
|
||||
if response:=_authenticated_home(request): return response
|
||||
form = MobileForm(request.POST or None)
|
||||
block_reason = request.session.pop(BLOCK_REASON_KEY, "")
|
||||
if request.method == "POST" and form.is_valid():
|
||||
block_reason = blocked_login_reason(form.cleaned_data["mobile"])
|
||||
if block_reason:
|
||||
return render(request, "accounts/customer_login.html", {"form": form, "block_reason": block_reason})
|
||||
challenge = None
|
||||
try:
|
||||
challenge, code = OTPChallenge.issue(form.cleaned_data["mobile"], request)
|
||||
@@ -62,13 +67,18 @@ def customer_login(request):
|
||||
challenge.delete()
|
||||
logger.exception("OTP SMS delivery failed")
|
||||
form.add_error(None, "ارسال پیامک ورود در حال حاضر ممکن نیست؛ لطفاً کمی بعد دوباره تلاش کنید.")
|
||||
return render(request, "accounts/customer_login.html", {"form": form})
|
||||
return render(request, "accounts/customer_login.html", {"form": form, "block_reason": block_reason})
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
def verify_otp(request):
|
||||
if response:=_authenticated_home(request): return response
|
||||
challenge = get_object_or_404(OTPChallenge, pk=request.session.get("otp_challenge_id"))
|
||||
form = OTPForm(request.POST or None)
|
||||
block_reason = blocked_login_reason(challenge.mobile)
|
||||
if block_reason:
|
||||
request.session.pop("otp_challenge_id", None)
|
||||
request.session[BLOCK_REASON_KEY] = block_reason
|
||||
return redirect("accounts:login")
|
||||
if request.method == "POST" and form.is_valid():
|
||||
if challenge.verify(form.cleaned_data["code"]):
|
||||
user, created = User.objects.get_or_create(mobile=challenge.mobile, defaults={"username": f"customer_{challenge.mobile[3:]}", "account_type": User.AccountType.CUSTOMER})
|
||||
@@ -86,12 +96,16 @@ def customer_password_login(request):
|
||||
_remember_destination(request)
|
||||
if response:=_authenticated_home(request): return response
|
||||
form=CustomerPasswordLoginForm(request.POST or None)
|
||||
block_reason = request.session.pop(BLOCK_REASON_KEY, "")
|
||||
if request.method=="POST" and form.is_valid():
|
||||
block_reason = blocked_login_reason(form.cleaned_data["mobile"])
|
||||
if block_reason:
|
||||
return render(request, "accounts/customer_password_login.html", {"form": form, "block_reason": block_reason})
|
||||
user=form.authenticate(request)
|
||||
if user and user.is_active:
|
||||
login(request,user); return redirect(_login_destination(request))
|
||||
form.add_error(None,"شماره موبایل یا رمز عبور صحیح نیست.")
|
||||
return render(request,"accounts/customer_password_login.html",{"form":form})
|
||||
return render(request,"accounts/customer_password_login.html",{"form":form,"block_reason":block_reason})
|
||||
|
||||
@login_required
|
||||
@require_http_methods(["GET","POST"])
|
||||
|
||||
Reference in new issue
Block a user