import re from django.contrib.auth import logout from django.db import transaction from django.db.models import F from django.shortcuts import redirect, render from django.utils import timezone from django.views.decorators.cache import never_cache from django.views.decorators.http import require_http_methods from . import access, services from .models import PaymentAccessLink @never_cache @require_http_methods(['GET', 'POST']) def open_link(request, token): # Keep previously issued long links valid until their original expiry/revocation. link = access.active_links().filter(token_hash=access.token_digest(token)).first() if re.fullmatch(r'(?:[a-z0-9]{10}|[A-Za-z0-9_-]{43})', token) else None if link is None: return access.unavailable_link(request) if request.user.is_authenticated and request.user.pk != link.customer_id: confirmed = request.method == 'POST' and request.POST.get('action') == 'logout_and_open' and request.POST.get('account_id') == str(request.user.pk) if not confirmed: response = render(request, 'payments/link_confirmation.html') response['Referrer-Policy'] = 'same-origin' response['X-Robots-Tag'] = 'noindex, nofollow' return response logout(request) if not request.user.is_authenticated: access.grant_payment_access(request, link) with transaction.atomic(): PaymentAccessLink.objects.filter(pk=link.pk).update(view_count=F('view_count') + 1, last_used_at=timezone.now()) services.audit(None, 'PAYMENT_LINK_OPENED', link, { 'ip_address': request.META.get('REMOTE_ADDR', ''), 'user_agent': request.META.get('HTTP_USER_AGENT', '')[:500]}) target = link.receipt or link.notice response = redirect('payments:receipt_detail' if link.receipt_id else 'payments:notice_detail', public_id=target.public_id) response['Referrer-Policy'] = 'no-referrer' response['X-Robots-Tag'] = 'noindex, nofollow' return response