Skip to content

Commit

Permalink
Merge branch 'miscs'
Browse files Browse the repository at this point in the history
  • Loading branch information
Jenselme committed Jan 25, 2025
2 parents 597fde3 + 42aac51 commit 5e44f30
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 43 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
## Unreleased

- Correct footer background on dark mode.
- Prevent articles to be read on scroll before initial scroll to top on page load.
- Force re-authentication before managing tokens.
- Allow users to change their passwords.

## 24.12.6

Expand Down
3 changes: 3 additions & 0 deletions legadilo/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@
from http import HTTPStatus

import pytest
from allauth.conftest import reauthentication_bypass as allauth_reauthentication_bypass
from django.urls import reverse

from legadilo.core.models import Timezone
from legadilo.users.models import User
from legadilo.users.tests.factories import UserFactory, UserSettingsFactory

reauthentication_bypass = allauth_reauthentication_bypass


@pytest.fixture(autouse=True)
def _setup_settings(settings, tmpdir):
Expand Down
17 changes: 11 additions & 6 deletions legadilo/static/js/list_of_articles.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
return;
}

console.log("Setting up read on scroll.");
// Force a scroll to top after reloading the page: previously read articles won’t be there
// anymore and the back button of the browser will preserve scroll. We may end up marking some
// articles as read when we shouldn’t. Clicking the back button on the details page doesn’t have
Expand All @@ -66,12 +67,16 @@
// correctly triggers the scroll to top code. However, when the browser is reopened, it did not.
// it seems that the browser is restoring the scroll with a little delay after the scroll to
// top had run. Hence, this timeout block. Improve this if you have a cleaner solution.
setTimeout(() => window.scroll(0, 0), 500);

// Wait before reading on scroll: the user may scroll up again!
const readOnScrollDebounced = debounce(readOnScroll, 1_000);
document.addEventListener("scrollend", readOnScrollDebounced);
console.log("Read on scroll setup!");
// We don’t start marking articles as read until the scroll is done: it can take a while and on
// some occasions, we may start marking articles as read before the scroll is done.
setTimeout(() => {
window.scroll(0, 0);
// Wait before reading on scroll: the user may scroll up again! We don’t want to mark articles
// as read in this case.
const readOnScrollDebounced = debounce(readOnScroll, 1_000);
document.addEventListener("scrollend", readOnScrollDebounced);
console.log("Read on scroll setup!");
}, 500);
};

const readOnScroll = () => {
Expand Down
3 changes: 3 additions & 0 deletions legadilo/templates/users/user_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ <h2>{{ object.email }}</h2>
<a class="btn btn-primary"
href="{% url 'users:update_settings' %}"
role="button">{% translate "My settings" %}</a>
<a class="btn btn-primary"
href="{% url 'account_change_password' %}"
role="button">{% translate "Change password" %}</a>
<a class="btn btn-primary" href="{% url 'mfa_index' %}" role="button">{% translate "Two-Factor Authentication" %}</a>
</div>
<div class="col-sm-12 mt-1">
Expand Down
30 changes: 18 additions & 12 deletions legadilo/users/tests/views/test_manage_tokens_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ def test_list_not_logged_in(self, client):

assert_redirected_to_login_page(response)

def test_list(self, logged_in_sync_client, other_user, django_assert_num_queries):
def test_list(
self, logged_in_sync_client, other_user, django_assert_num_queries, reauthentication_bypass
):
ApplicationTokenFactory(user=other_user)

with django_assert_num_queries(8):
with django_assert_num_queries(8), reauthentication_bypass():
response = logged_in_sync_client.get(self.url)

assert response.status_code == HTTPStatus.OK
Expand All @@ -54,9 +56,9 @@ def test_list(self, logged_in_sync_client, other_user, django_assert_num_queries
assert list(response.context_data["tokens"]) == [self.application_token]

def test_create_token_invalid_form(
self, user, logged_in_sync_client, django_assert_num_queries
self, user, logged_in_sync_client, django_assert_num_queries, reauthentication_bypass
):
with django_assert_num_queries(8):
with django_assert_num_queries(8), reauthentication_bypass():
response = logged_in_sync_client.post(self.url, data={})

assert response.status_code == HTTPStatus.BAD_REQUEST
Expand All @@ -65,8 +67,10 @@ def test_create_token_invalid_form(
assert response.context_data["new_application_token_secret"] is None
assert response.context_data["form"].errors == {"title": ["This field is required."]}

def test_create_token(self, user, logged_in_sync_client, django_assert_num_queries):
with django_assert_num_queries(11):
def test_create_token(
self, user, logged_in_sync_client, django_assert_num_queries, reauthentication_bypass
):
with django_assert_num_queries(11), reauthentication_bypass():
response = logged_in_sync_client.post(self.url, data={"title": "Test token"})

assert response.status_code == HTTPStatus.OK
Expand All @@ -81,8 +85,10 @@ def test_create_token(self, user, logged_in_sync_client, django_assert_num_queri
assert len(response.context_data["new_application_token_secret"]) == 67
assert list(response.context_data["tokens"]) == [new_token, self.application_token]

def test_create_duplicated_token(self, logged_in_sync_client, django_assert_num_queries):
with django_assert_num_queries(12):
def test_create_duplicated_token(
self, logged_in_sync_client, django_assert_num_queries, reauthentication_bypass
):
with django_assert_num_queries(12), reauthentication_bypass():
response = logged_in_sync_client.post(
self.url, data={"title": self.application_token.title}
)
Expand All @@ -101,9 +107,9 @@ def test_create_duplicated_token(self, logged_in_sync_client, django_assert_num_
]

def test_create_token_with_validity_end(
self, user, logged_in_sync_client, django_assert_num_queries
self, user, logged_in_sync_client, django_assert_num_queries, reauthentication_bypass
):
with django_assert_num_queries(11):
with django_assert_num_queries(11), reauthentication_bypass():
response = logged_in_sync_client.post(
self.url, data={"title": "Test token", "validity_end": "2024-11-24 12:00:00Z"}
)
Expand All @@ -116,11 +122,11 @@ def test_create_token_with_validity_end(
assert new_token.validity_end == utcdt(2024, 11, 24, 12)

def test_create_token_with_validity_end_in_timezone(
self, user, logged_in_sync_client, django_assert_num_queries
self, user, logged_in_sync_client, django_assert_num_queries, reauthentication_bypass
):
new_york_tz, _created = Timezone.objects.get_or_create(name="America/New_York")

with django_assert_num_queries(12):
with django_assert_num_queries(12), reauthentication_bypass():
response = logged_in_sync_client.post(
self.url,
data={
Expand Down
3 changes: 2 additions & 1 deletion legadilo/users/views/manage_tokens_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from http import HTTPStatus

from allauth.account.decorators import reauthentication_required
from django import forms
from django.contrib import messages
from django.contrib.auth.decorators import login_required
Expand Down Expand Up @@ -56,7 +57,7 @@ def clean(self):
)


@login_required
@reauthentication_required
@require_http_methods(["GET", "POST"])
def manage_tokens_view(request: AuthenticatedHttpRequest) -> TemplateResponse:
form = CreateTokenForm(initial={"timezone": request.user.settings.timezone})
Expand Down
48 changes: 24 additions & 24 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 5e44f30

Please sign in to comment.