Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions core/utils/tests_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from unittest import TestCase
from unittest.mock import MagicMock, patch

from langcodes import Language

from core.utils.utils import _get_user, language_iso


class LanguageIsoTests(TestCase):
"""Tests for the ``language_iso`` helper."""

def test_normalises_pt_br(self):
self.assertEqual(language_iso("pt-BR"), "pt")

def test_normalises_en_us(self):
self.assertEqual(language_iso("en-US"), "en")

def test_normalises_es_419(self):
self.assertEqual(language_iso("es-419"), "es")

def test_simple_code_unchanged(self):
self.assertEqual(language_iso("fr"), "fr")

def test_empty_string_returns_empty(self):
self.assertEqual(language_iso(""), "")

def test_none_returns_empty(self):
self.assertEqual(language_iso(None), "")

def test_invalid_code_returns_empty(self):
self.assertEqual(language_iso("zzzzzz"), "")


class GetUserTests(TestCase):
"""Tests for the ``_get_user`` helper."""

@patch("core.utils.utils.get_user_model")
def test_resolves_by_request_user_id(self, mock_get_user_model):
mock_user_model = MagicMock()
mock_get_user_model.return_value = mock_user_model
request = MagicMock()
request.user_id = 42
sentinel = object()
mock_user_model.objects.get.return_value = sentinel

result = _get_user(request)

mock_user_model.objects.get.assert_called_once_with(pk=42)
self.assertIs(result, sentinel)

@patch("core.utils.utils.get_user_model")
def test_falls_back_to_user_id(self, mock_get_user_model):
mock_user_model = MagicMock()
mock_get_user_model.return_value = mock_user_model
request = MagicMock(spec=[]) # no user_id attribute
sentinel = object()
mock_user_model.objects.get.return_value = sentinel

result = _get_user(request, user_id=7)

mock_user_model.objects.get.assert_called_once_with(pk=7)
self.assertIs(result, sentinel)

@patch("core.utils.utils.get_user_model")
def test_falls_back_to_username(self, mock_get_user_model):
mock_user_model = MagicMock()
mock_get_user_model.return_value = mock_user_model
request = MagicMock(spec=[]) # no user_id attribute
sentinel = object()
mock_user_model.objects.get.return_value = sentinel

result = _get_user(request, username="alice")

mock_user_model.objects.get.assert_called_once_with(username="alice")
self.assertIs(result, sentinel)

@patch("core.utils.utils.get_user_model")
def test_user_id_preferred_over_username(self, mock_get_user_model):
mock_user_model = MagicMock()
mock_get_user_model.return_value = mock_user_model
request = MagicMock(spec=[]) # no user_id attribute
sentinel = object()
mock_user_model.objects.get.return_value = sentinel

result = _get_user(request, username="alice", user_id=7)

mock_user_model.objects.get.assert_called_once_with(pk=7)
self.assertIs(result, sentinel)
56 changes: 56 additions & 0 deletions core/utils/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import logging

from django.contrib.auth import get_user_model

from langcodes import Language

from core.utils.requester import NonRetryableError, fetch_data


logger = logging.getLogger(__name__)

__all__ = [
"fetch_data",
"language_iso",
"NonRetryableError",
"_get_user",
]


def language_iso(code):
"""Normalize a language code to its shortest ISO 639 form.

Uses the ``langcodes`` library to parse ``code`` and return the two-letter
language subtag when valid (e.g. ``"pt-BR"`` → ``"pt"``).

Returns an empty string when the code is ``None``, empty or cannot be
parsed into a valid language.
"""
if not code:
return ""
try:
lang = Language.get(code)
if lang.is_valid():
return lang.language or ""
except ValueError:
pass
return ""


def _get_user(request, username=None, user_id=None):
"""Resolve the acting user from the current request context.

Attempts to look up the user by ``request.user_id`` first. If that
attribute is missing (``AttributeError``), falls back to ``user_id``
or ``username``.

Returns ``None`` when no lookup parameter is available.
"""
User = get_user_model()
try:
return User.objects.get(pk=request.user_id)
except AttributeError:
if user_id:
return User.objects.get(pk=user_id)
if username:
return User.objects.get(username=username)
4 changes: 4 additions & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ git+https://git@github.com/scieloorg/packtools@4.12.6#egg=packtools
# Langdetect
# ------------------------------------------------------------------------------
langdetect~=1.0.9

# Langcodes
# ------------------------------------------------------------------------------
langcodes==3.5.1 # https://pypi.org/project/langcodes/