Как заставить таймер не сбрасываться при перезагрузки страницы или отправки post-запросов сервера, а запомнить время первоначальной загрузки страницы?

настройки жизни сессии SESSION_COOKIE_AGE=120 (2 минуты)

При первом рендере страницы шаблона confirm_email.html загружается форма ввода кода из 6 полей, если не вводить код(бездействовать) и подождать то каждую минуту будет проверяться слаться get запрос из скрипта check_session.js каждую минуту во вьюшку CheckSession и она будет отдавать json ответ обратно и за 30 секунд до окончания жизни сессии сработает скрипт timer.js и после окончания 2 минут скриптом check_session.js пользователь будет перенаправлен на главную страницу- здесь все хорошо!!!!

Теперь сам вопрос: Если при первом рендере страницы шаблона confirm_email.html (например страница загрузилась в 18:00:00) загружается форма ввода кода из 6 полей, и допустим ты через 30 секунд(в 18:00:30) (до этого времени ты бездействовал) ты вводишь неправильный код то отправляется post запрос во вьюшку ConfirmEmail и скрипт check_session.js будет слать запрос во вьюшку CheckSession от этого времени, от post запроса, то есть скрипт отправит запрос в 18:01:30 то есть через минуту от post запроса, но не от того времени как загрузилась страница в 18:00:00

Нужно, чтобы запомнилось время первоначальной загрузки страницы, и get запросы также отправлялись через минуту, но при отправке post запроса на сервер(при вводе в формы неправильного кода) таймер не сбрасывался и не слал get запрос через минуту от этого post-запроса!!!

views.py ConfirmEmail:

class ConfirmEmail(SuccessMessageMixin,View):
    template_name = 'mos_sel/confirm_email.html'
    success_message='Пользователь %(username)s был успешно создан.\nЗалогиньтесь, чтобы продолжить'

    def get(self, request, *args, **kwargs):
        form = EmailConfirmationForm()
        user_email = request.session.get('email','')
        username = request.session.get('username', user_email.split('@')[0])
        anonymized_email = request.session.get('anonymized_email', '')
        if not user_email:  # Если сессия истекла
            User = get_user_model()
            user = User.objects.get(email=user_email)
            user.delete()  # Удалить пользователя
            # Удаляем email_confirmed из сессии и обновляем сессию
            del request.session['email']
            request.session.modified = True
            return redirect(reverse_lazy('Login'))  # Перенаправить на главную страницу
        request.session['email_confirmed'] = False
        request.session['last_activity'] = tz.now().isoformat()
        return render(request, self.template_name, {'form': form, 'user_email': user_email, 'username': username, 'show_modal': True,'session_timeout': settings.SESSION_COOKIE_AGE,})  

    def post(self, request, *args, **kwargs):
        user_email = request.session.get('email', '')
        print(f'сессия email_confirmed вначале post {request.session["email_confirmed"]}')
        if not user_email:  # Если сессия истекла
            User = get_user_model()
            user = User.objects.get(email=user_email)
            user.delete()  # Удалить пользователя
            return redirect(reverse_lazy('Login'))  # Перенаправить на главную страницу
        form = EmailConfirmationForm(request.POST)
        username = request.session.get('username', user_email.split('@')[0])
        anonymized_email = request.session.get('anonymized_email', '')
        if form.is_valid():
            code = form.cleaned_data['code1'] + form.cleaned_data['code2'] + form.cleaned_data['code3'] + form.cleaned_data['code4'] + form.cleaned_data['code5'] + form.cleaned_data['code6']
            User = get_user_model()
            user = User.objects.get(email=user_email)
            email_confirmation = EmailConfirmation.objects.filter(
                code=code,
                user=user
                ).first()
            if email_confirmation:
                email_confirmation.delete()
                user.is_active = True
                user.email_confirmed = True  # Устанавливаем email_confirmed в True
                request.session['email_confirmed'] = True
                user.save()
                success_message = self.success_message % dict(username=username,)
                messages.success(request, success_message)
                return redirect(reverse_lazy('SuccessMessage'))
               
            else:
                messages.error(request, 'Неправильный код. Попробуйте снова.')
        else:
            messages.error(request, 'Код введен неверно.')
        return render(request, self.template_name, {'form': form, 'user_email': user_email, 'username': username, 'show_modal': True,'session_timeout': settings.SESSION_COOKIE_AGE,})

views.py ConfirmEmail:

class ConfirmEmail(SuccessMessageMixin,View):
    template_name = 'mos_sel/confirm_email.html'
    success_message='Пользователь %(username)s был успешно создан.\nЗалогиньтесь, чтобы продолжить'

    def get(self, request, *args, **kwargs):
        form = EmailConfirmationForm()
        user_email = request.session.get('email','')
        username = request.session.get('username', user_email.split('@')[0])
        anonymized_email = request.session.get('anonymized_email', '')
        if not user_email:  # Если сессия истекла
            User = get_user_model()
            user = User.objects.get(email=user_email)
            user.delete()  # Удалить пользователя
            # Удаляем email_confirmed из сессии и обновляем сессию
            del request.session['email']
            request.session.modified = True
            return redirect(reverse_lazy('Login'))  # Перенаправить на главную страницу
        request.session['email_confirmed'] = False
        request.session['last_activity'] = tz.now().isoformat()
        return render(request, self.template_name, {'form': form, 'user_email': user_email, 'username': username, 'show_modal': True,'session_timeout': settings.SESSION_COOKIE_AGE,})  

    def post(self, request, *args, **kwargs):
        user_email = request.session.get('email', '')
        print(f'сессия email_confirmed вначале post {request.session["email_confirmed"]}')
        if not user_email:  # Если сессия истекла
            User = get_user_model()
            user = User.objects.get(email=user_email)
            user.delete()  # Удалить пользователя
            return redirect(reverse_lazy('Login'))  # Перенаправить на главную страницу
        form = EmailConfirmationForm(request.POST)
        username = request.session.get('username', user_email.split('@')[0])
        anonymized_email = request.session.get('anonymized_email', '')
        if form.is_valid():
            code = form.cleaned_data['code1'] + form.cleaned_data['code2'] + form.cleaned_data['code3'] + form.cleaned_data['code4'] + form.cleaned_data['code5'] + form.cleaned_data['code6']
            User = get_user_model()
            user = User.objects.get(email=user_email)
            email_confirmation = EmailConfirmation.objects.filter(
                code=code,
                user=user
                ).first()
            if email_confirmation:
                email_confirmation.delete()
                user.is_active = True
                user.email_confirmed = True  # Устанавливаем email_confirmed в True
                request.session['email_confirmed'] = True
                user.save()
                success_message = self.success_message % dict(username=username,)
                messages.success(request, success_message)
                return redirect(reverse_lazy('SuccessMessage'))
               
            else:
                messages.error(request, 'Неправильный код. Попробуйте снова.')
        else:
            messages.error(request, 'Код введен неверно.')
        return render(request, self.template_name, {'form': form, 'user_email': user_email, 'username': username, 'show_modal': True,'session_timeout': settings.SESSION_COOKIE_AGE,})

template confirm_email.html

<body id='custom_background_image' data-session-timeout="{{ session_timeout }}" data-last-activity="{{ request.session.last_activity }}" data-url="{% url 'check_session' %}">
<div class="container">
    <!-- Задний фон -->
    <div class="overlay"></div>
    <!-- Модальное окно -->
    <div class="modal fade {% if show_modal %}show d-block{% endif %}" id="confirmEmailModal" tabindex="-1" aria-labelledby="confirmEmailModalLabel" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered mx-auto my-custom-modal">
            <div class="modal-content " id="modal_background_color">
                <div class="modal-header">
                    <h5 class="modal-title text-center" id="confirmEmailModalLabel"><strong>Завершение регистрации </strong></h5>
                    <button type="button" id="close_registr_modal" data-url="{% url 'Home' %}" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <div id="insert_timer"></div>
                    {% if messages %}
                    <div class="alert alert-danger">
                        <strong>Ошибка подтверждения:</strong><br>
                        {% for message in messages %}
                            {{ message }}
                        {% endfor %}
                    </div>
                    {% endif %}
                    <p> <strong> Введите код подтверждения </strong></p>
                    
                    <p>  Приветствуем Вас, <strong> {{ username }}</strong>!</p>
                    <div class="text mb-4">Мы отправили 6-значный код на <strong>{{ user_email }}</strong>
                    Подтвердите, что номер принадлежит вам, чтобы обезопасить свою учетную запись
                    </div>
                    <form method="post">
                        {% csrf_token %}
                        <div class="form-group row justify-content-between">
                            <div class="col"><input type="text" name="code1" maxlength="1" class="form-control digit-input" id="code1"></div>
                            <div class="col"><input type="text" name="code2" maxlength="1" class="form-control digit-input" id="code2"></div>
                            <div class="col"><input type="text" name="code3" maxlength="1" class="form-control digit-input" id="code3"></div>
                            <div class="col"><input type="text" name="code4" maxlength="1" class="form-control digit-input" id="code4"></div>
                            <div class="col"><input type="text" name="code5" maxlength="1" class="form-control digit-input" id="code5"></div>
                            <div class="col"><input type="text" name="code6" maxlength="1" class="form-control digit-input" id="code6"></div>
                        </div>
                        <div class="d-flex justify-content-end mt-2 mb-1">
                            <button type="submit" id="confirm_code" class="btn btn-primary">Подтвердить</button>
                        </div>
                        </form>
                </div>
            </div>
        </div>
    </div>
</div>
</div>
</body>

views.py CheckSession:

class CheckSession(View):
    def get(self, request, *args, **kwargs):
        # Проверка времени последней активности
        last_activity_str = request.session.get('last_activity', None)
        if last_activity_str:
            last_activity = datetime.fromisoformat(last_activity_str)
        else:
            last_activity = tz.now()
        session_timeout = tz.timedelta(seconds=settings.SESSION_COOKIE_AGE)
        email_confirmed = False
        if tz.now() - last_activity > session_timeout:
            User = get_user_model()
            users = User.objects.filter(email=request.session.get('email', ''))
            if users.exists():
                user = users.first()
                user.delete()
            # Если прошло более 5 минут, считаем сессию подтвержденной фиктивно
            email_confirmed = True
        # Обновляем состояние сессии
        request.session['email_confirmed'] = email_confirmed
        request.session.save()
        # Возвращаем JsonResponse без 'last_activity'
        return JsonResponse({'email_confirmed': email_confirmed})
    
    @csrf_exempt
    def post(self, request, *args, **kwargs):
        try:
            user = User.objects.get(email=request.session.get('email', ''))
            if not user.email_confirmed:
                user.delete()
                # Удаляем email_confirmed из сессии и обновляем сессию
                del request.session['email_confirmed']
                request.session.modified = True
                return JsonResponse({'email_confirmed': False})
            else:
                return JsonResponse({'email_confirmed': True})
        except User.DoesNotExist:
            return JsonResponse({'error': 'User does not exist.'})

check_session.js :

let checkSessionUrl;
var body = document.querySelector('body[data-url]');
let navbar = document.querySelector('nav[data-url]');

if (body) {
    checkSessionUrl = body.getAttribute('data-url');
} else if (navbar) {
    checkSessionUrl = navbar.getAttribute('data-url');
}

if (checkSessionUrl) {
    function checkSession() {
        fetch(checkSessionUrl)
            .then(response => response.json())
            .then(data => {
                if (data.email_confirmed === true) {
                        window.location.href = "/";                  
                }
            });
    }
    // Check the session every 1 minute 
    setInterval(checkSession, 60000);
}

timer.js :

let session_timeout;
let last_activ;
var body = document.querySelector('body');

if (body) {
    session_timeout = body.getAttribute('data-session-timeout');
    last_activ = body.getAttribute('data-last-activity');

    const sessionExpiryTime = session_timeout * 1000;
    console.log(session_timeout);
    console.log(sessionExpiryTime);
    const warningTime = 30 * 1000;
    const lastActivity = new Date(last_activ);
    console.log(lastActivity);
    const sessionExpiryDate = new Date(lastActivity.getTime() + sessionExpiryTime);

    function checkSession() {
        const timeLeft = sessionExpiryDate - new Date();

        // Найдите div с помощью его id
        const warningDiv = document.getElementById('insert_timer');

        if (warningDiv) {
            // Установите его содержимое только если элемент найден
            if (timeLeft <= warningTime) {
                warningDiv.textContent = 'Ваша сессия истекает через ' + Math.round(timeLeft / 1000) + ' секунд';
            }

                 
        }
    }

    setInterval(checkSession, 1000);
}

Ответы (0 шт):