diff --git a/tdrs-backend/docs/api/set_profile.md b/tdrs-backend/docs/api/set_profile.md
index bf720dd06..e16c6dc5f 100644
--- a/tdrs-backend/docs/api/set_profile.md
+++ b/tdrs-backend/docs/api/set_profile.md
@@ -1,12 +1,12 @@
# Set Profile
-Accepts a POST request from [authenticated](api/authentication.md) users to update the first name and last name on their profile.
+Accepts a PATCH request from [authenticated](api/authentication.md) users to update the first name and last name on their profile.
----
**Request**:
-`Post` `v1/set_profile/`
+`PATCH` `v1/set_profile/`
Parameters:
@@ -15,14 +15,24 @@ Parameters:
- JSON request body with the following **required** fields :
```
{
- "first_name":"John",
- "last_name":"Jones"
+ "first_name": "John",
+ "last_name": "Jones",
+ "stt": {
+ "id": 1
+ }
}
```
-*Note:*
+*Notes:*
-- Authorization Protected
+### Fields
+* first_name: string (first name of user)
+* last_name: string (last name of user)
+* stt: object
+ * id: integer (id of the State, Tribe or Terrritory)
+
+
+Authorization Protected
**Response**:
@@ -31,12 +41,27 @@ Content-Type application/json
200 Ok
{
- "first_name":"John",
- "last_name":"Jones"
+ "first_name": "John",
+ "last_name": "Jones",
+ "stt": {
+ "id": 1,
+ "type": "state",
+ "code": "AL",
+ "name": "Alabama"
+ }
}
```
-This will return a JSON response with the authenticated users first name and last name as defined in their request JSON.
+This will return a JSON response with the authenticated user's data as defined in their request JSON.
+
+### Fields
+* first_name: string (first name of user)
+* last_name: string (last name of user)
+* stt: object
+ * id: integer (id of the State, Tribe or Terrritory)
+ * type: string (identifies it as a State, Tribe or Territory)
+ * code: string (abbreviation)
+ * string (name of State, Tribe or Territory)
----
**Failure to Authenticate Response:**
@@ -63,4 +88,4 @@ Content-Type application/json
"first_name":["This field is required."],
"last_name":["This field is required."]
}
-```
\ No newline at end of file
+```
diff --git a/tdrs-backend/tdpservice/conftest.py b/tdrs-backend/tdpservice/conftest.py
index cd2ede2d5..ff44896fe 100644
--- a/tdrs-backend/tdpservice/conftest.py
+++ b/tdrs-backend/tdpservice/conftest.py
@@ -3,6 +3,7 @@
from rest_framework.test import APIClient
from tdpservice.users.test.factories import UserFactory
+from tdpservice.stts.test.factories import STTFactory, RegionFactory
@pytest.fixture(scope="function")
@@ -15,3 +16,15 @@ def api_client():
def user():
"""Return a basic, non-admin user."""
return UserFactory.create()
+
+
+@pytest.fixture
+def stt():
+ """Return an STT."""
+ return STTFactory.create()
+
+
+@pytest.fixture
+def region():
+ """Return a region."""
+ return RegionFactory.create()
diff --git a/tdrs-backend/tdpservice/stts/serializers.py b/tdrs-backend/tdpservice/stts/serializers.py
index 05541b084..cbd311b1b 100644
--- a/tdrs-backend/tdpservice/stts/serializers.py
+++ b/tdrs-backend/tdpservice/stts/serializers.py
@@ -23,6 +23,21 @@ def get_code(self, obj):
return obj.code
+class STTUpdateSerializer(serializers.ModelSerializer):
+ """STT serializer."""
+
+ class Meta:
+ """Metadata."""
+
+ model = STT
+ fields = ["id"]
+ extra_kwargs = {"id": {"read_only": False}}
+
+ def to_representation(self, instance):
+ """Allow update with only the ID field."""
+ return STTSerializer(instance).data
+
+
class RegionSerializer(serializers.ModelSerializer):
"""Region serializer."""
diff --git a/tdrs-backend/tdpservice/stts/test/factories.py b/tdrs-backend/tdpservice/stts/test/factories.py
new file mode 100644
index 000000000..18f3fced6
--- /dev/null
+++ b/tdrs-backend/tdpservice/stts/test/factories.py
@@ -0,0 +1,38 @@
+"""Generate test data for stts."""
+
+import factory
+from ..models import STT, Region
+
+
+class RegionFactory(factory.django.DjangoModelFactory):
+ """Generate test data for regions."""
+
+ class Meta:
+ """Metadata for regions."""
+
+ model = "stts.Region"
+
+ id = factory.Sequence(int)
+
+ @classmethod
+ def _create(cls, model_class, *args, **kwargs):
+ return Region.objects.create(*args, **kwargs)
+
+
+class STTFactory(factory.django.DjangoModelFactory):
+ """Generate test data for stts."""
+
+ class Meta:
+ """Hardcoded metata data for stts."""
+
+ model = "stts.STT"
+
+ id = factory.Sequence(int)
+ name = factory.Sequence(lambda n: "teststt%d" % n)
+ code = "TT"
+ type = "STATE"
+ region = factory.SubFactory(RegionFactory)
+
+ @classmethod
+ def _create(cls, model_class, *args, **kwargs):
+ return STT.objects.create(*args, **kwargs)
diff --git a/tdrs-backend/tdpservice/urls.py b/tdrs-backend/tdpservice/urls.py
index 3e61d83c8..2629207d9 100755
--- a/tdrs-backend/tdpservice/urls.py
+++ b/tdrs-backend/tdpservice/urls.py
@@ -5,18 +5,11 @@
from django.contrib import admin
from django.urls import include, path, re_path, reverse_lazy
from django.views.generic.base import RedirectView
-
-from rest_framework.routers import DefaultRouter
-
from .users.api.authorization_check import AuthorizationCheck
from .users.api.login import TokenAuthorizationOIDC
from .users.api.login_redirect_oidc import LoginRedirectOIDC
from .users.api.logout import LogoutUser
from .users.api.logout_redirect_oidc import LogoutRedirectOIDC
-from .users import views
-
-router = DefaultRouter()
-router.register("users", views.UserViewSet)
urlpatterns = [
path("admin/", admin.site.urls),
@@ -25,13 +18,12 @@
path("logout", LogoutUser.as_view(), name="logout"),
path("logout/oidc", LogoutRedirectOIDC.as_view(), name="oidc-logout"),
path("auth_check", AuthorizationCheck.as_view(), name="authorization-check"),
+ path("users/", include("tdpservice.users.urls")),
path("stts/", include("tdpservice.stts.urls")),
# the 'api-root' from django rest-frameworks default router
# http://www.django-rest-framework.org/api-guide/routers/#defaultrouter
re_path(r"^$", RedirectView.as_view(url=reverse_lazy("api-root"), permanent=False)),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
-urlpatterns += router.urls
-
# Add 'prefix' to all urlpatterns to make it easier to version/group endpoints
urlpatterns = [path("v1/", include(urlpatterns))]
diff --git a/tdrs-backend/tdpservice/users/api/authorization_check.py b/tdrs-backend/tdpservice/users/api/authorization_check.py
index ce3ce3839..05172ee75 100644
--- a/tdrs-backend/tdpservice/users/api/authorization_check.py
+++ b/tdrs-backend/tdpservice/users/api/authorization_check.py
@@ -3,7 +3,10 @@
from rest_framework.response import Response
from rest_framework.views import APIView
+from rest_framework.permissions import AllowAny
+from django.middleware import csrf
from django.utils import timezone
+from ..serializers import UserProfileSerializer
logger = logging.getLogger()
logger.setLevel(logging.INFO)
@@ -14,23 +17,24 @@ class AuthorizationCheck(APIView):
query_string = False
pattern_name = "authorization-check"
+ permission_classes = [AllowAny]
def get(self, request, *args, **kwargs):
"""Handle get request and authenticate user."""
user = request.user
+ serializer = UserProfileSerializer(user)
if user.is_authenticated:
auth_params = {
"authenticated": True,
- "user": {
- "email": user.username,
- "first_name": user.first_name,
- "last_name": user.last_name,
- },
+ "user": serializer.data,
+ "csrf": csrf.get_token(request),
}
logger.info(
"Auth check PASS for user: %s on %s", user.username, timezone.now()
)
- return Response(auth_params)
+ res = Response(auth_params)
+ res['Access-Control-Allow-Headers'] = "X-CSRFToken"
+ return res
else:
logger.info("Auth check FAIL for user on %s", timezone.now())
return Response({"authenticated": False})
diff --git a/tdrs-backend/tdpservice/users/serializers.py b/tdrs-backend/tdpservice/users/serializers.py
index 546aa7a8e..3168e1a02 100644
--- a/tdrs-backend/tdpservice/users/serializers.py
+++ b/tdrs-backend/tdpservice/users/serializers.py
@@ -1,8 +1,14 @@
"""Serialize user data."""
+import logging
from rest_framework import serializers
from .models import User
+from tdpservice.stts.serializers import STTUpdateSerializer
+
+logger = logging.getLogger()
+logger.setLevel(logging.INFO)
+logger.addHandler(logging.StreamHandler())
class UserSerializer(serializers.ModelSerializer):
@@ -48,17 +54,29 @@ class Meta:
extra_kwargs = {"password": {"write_only": True}}
-class SetUserProfileSerializer(serializers.ModelSerializer):
+class UserProfileSerializer(serializers.ModelSerializer):
"""Serializer used for setting a user's profile."""
+ stt = STTUpdateSerializer(required=True)
+ email = serializers.SerializerMethodField("get_email")
+
class Meta:
"""Metadata."""
model = User
- fields = ["first_name", "last_name"]
+ fields = ["first_name", "last_name", "stt", "email"]
"""Enforce first and last name to be in API call and not empty"""
extra_kwargs = {
"first_name": {"allow_blank": False, "required": True},
"last_name": {"allow_blank": False, "required": True},
}
+
+ def update(self, instance, validated_data):
+ """Update the user with the STT."""
+ instance.stt_id = validated_data.pop("stt")["id"]
+ return super().update(instance, validated_data)
+
+ def get_email(self, obj):
+ """Return the user's email address."""
+ return obj.username
diff --git a/tdrs-backend/tdpservice/users/test/conftest.py b/tdrs-backend/tdpservice/users/test/conftest.py
index e3aa49f1f..b2a153bdb 100644
--- a/tdrs-backend/tdpservice/users/test/conftest.py
+++ b/tdrs-backend/tdpservice/users/test/conftest.py
@@ -14,4 +14,5 @@ def user_data():
"last_name": "Smith",
"password": "correcthorsebatterystaple",
"auth_token": "xxx",
+ "stt": "Michigan",
}
diff --git a/tdrs-backend/tdpservice/users/test/factories.py b/tdrs-backend/tdpservice/users/test/factories.py
index 5dcdb0d06..f4b797905 100644
--- a/tdrs-backend/tdpservice/users/test/factories.py
+++ b/tdrs-backend/tdpservice/users/test/factories.py
@@ -2,6 +2,8 @@
import factory
+from tdpservice.stts.test.factories import STTFactory
+
class UserFactory(factory.django.DjangoModelFactory):
"""Generate test data for users."""
@@ -13,13 +15,14 @@ class Meta:
django_get_or_create = ("username",)
id = factory.Faker("uuid4")
- username = factory.Sequence(lambda n: f"testuser{n}")
+ username = factory.Sequence(lambda n: "testuser%d" % n)
password = "test_password" # Static password so we can login.
email = factory.Faker("email")
first_name = factory.Faker("first_name")
last_name = factory.Faker("last_name")
is_active = True
is_staff = False
+ stt = factory.SubFactory(STTFactory)
@classmethod
def _create(cls, model_class, *args, **kwargs):
diff --git a/tdrs-backend/tdpservice/users/test/test_api.py b/tdrs-backend/tdpservice/users/test/test_api.py
index a5f848c3f..e0fbb1657 100644
--- a/tdrs-backend/tdpservice/users/test/test_api.py
+++ b/tdrs-backend/tdpservice/users/test/test_api.py
@@ -2,6 +2,7 @@
from django.contrib.auth import get_user_model
import pytest
from rest_framework import status
+from ...stts.models import STT
User = get_user_model()
@@ -43,52 +44,95 @@ def test_create_user(api_client, user_data):
def test_set_profile_data(api_client, user):
"""Test profile data can be set."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ stt = STT.objects.first()
+ response = api_client.patch(
"/v1/users/set_profile/",
- {"first_name": "Joe", "last_name": "Bloggs"},
+ {"first_name": "Joe", "last_name": "Bloggs", "stt": {"id": stt.id}},
+ format="json",
)
assert response.status_code == status.HTTP_200_OK
- assert response.data == {"first_name": "Joe", "last_name": "Bloggs"}
+ assert response.data == {
+ "email": user.username,
+ "first_name": "Joe",
+ "last_name": "Bloggs",
+ "stt": {
+ "id": stt.id,
+ "type": stt.type,
+ "code": stt.code,
+ "name": stt.name,
+ },
+ }
user.refresh_from_db()
assert user.first_name == "Joe"
assert user.last_name == "Bloggs"
+ assert user.stt.name == stt.name
@pytest.mark.django_db
def test_set_profile_data_last_name_apostrophe(api_client, user):
"""Test profile data last name can be set with an apostrophe."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ stt = STT.objects.first()
+ response = api_client.patch(
"/v1/users/set_profile/",
- {"first_name": "Mike", "last_name": "O'Hare"},
+ {"first_name": "Mike", "last_name": "O'Hare", "stt": {"id": stt.id}},
+ format="json",
)
assert response.status_code == status.HTTP_200_OK
- assert response.data == {"first_name": "Mike", "last_name": "O'Hare"}
+ assert response.data == {
+ "email": user.username,
+ "first_name": "Mike",
+ "last_name": "O'Hare",
+ "stt": {
+ "id": stt.id,
+ "type": stt.type,
+ "code": stt.code,
+ "name": stt.name,
+ },
+ }
user.refresh_from_db()
assert user.first_name == "Mike"
assert user.last_name == "O'Hare"
+ assert user.stt.name == stt.name
@pytest.mark.django_db
def test_set_profile_data_first_name_apostrophe(api_client, user):
"""Test profile data first name can be set with an apostrophe."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ stt = STT.objects.first()
+ response = api_client.patch(
"/v1/users/set_profile/",
- {"first_name": "Pat'Jack", "last_name": "Smith"},
+ {
+ "first_name": "Pat'Jack",
+ "last_name": "Smith",
+ "stt": {"id": stt.id},
+ },
+ format="json",
)
assert response.status_code == status.HTTP_200_OK
- assert response.data == {"first_name": "Pat'Jack", "last_name": "Smith"}
+ assert response.data == {
+ "email": user.username,
+ "first_name": "Pat'Jack",
+ "last_name": "Smith",
+ "stt": {
+ "id": stt.id,
+ "type": stt.type,
+ "code": stt.code,
+ "name": stt.name,
+ },
+ }
user.refresh_from_db()
assert user.first_name == "Pat'Jack"
assert user.last_name == "Smith"
+ assert user.stt.name == stt.name
@pytest.mark.django_db
def test_set_profile_data_empty_first_name(api_client, user):
"""Test profile data cannot be be set if first name is blank."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ response = api_client.patch(
"/v1/users/set_profile/",
{"first_name": "", "last_name": "Jones"},
)
@@ -99,7 +143,7 @@ def test_set_profile_data_empty_first_name(api_client, user):
def test_set_profile_data_empty_last_name(api_client, user):
"""Test profile data cannot be set last name is blank."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ response = api_client.patch(
"/v1/users/set_profile/",
{"first_name": "John", "last_name": ""},
)
@@ -110,7 +154,7 @@ def test_set_profile_data_empty_last_name(api_client, user):
def test_set_profile_data_empty_first_name_and_last_name(api_client, user):
"""Test profile data cannot be set if first and last name are blank."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ response = api_client.patch(
"/v1/users/set_profile/",
{"first_name": "", "last_name": ""},
)
@@ -121,90 +165,192 @@ def test_set_profile_data_empty_first_name_and_last_name(api_client, user):
def test_set_profile_data_special_last_name(api_client, user):
"""Test profile data can be set if last name has multipe special characters."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ stt = STT.objects.first()
+ response = api_client.patch(
"/v1/users/set_profile/",
- {"first_name": "John", "last_name": "Smith-O'Hare"},
+ {
+ "first_name": "John",
+ "last_name": "Smith-O'Hare",
+ "stt": {"id": stt.id},
+ },
+ format="json",
)
assert response.status_code == status.HTTP_200_OK
- assert response.data == {"first_name": "John", "last_name": "Smith-O'Hare"}
+ assert response.data == {
+ "email": user.username,
+ "first_name": "John",
+ "last_name": "Smith-O'Hare",
+ "stt": {
+ "id": stt.id,
+ "type": stt.type,
+ "code": stt.code,
+ "name": stt.name,
+ },
+ }
user.refresh_from_db()
assert user.first_name == "John"
assert user.last_name == "Smith-O'Hare"
+ assert user.stt.name == stt.name
@pytest.mark.django_db
def test_set_profile_data_special_first_name(api_client, user):
"""Test profile data can be set if first name has multiple special characters."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ stt = STT.objects.first()
+ response = api_client.patch(
"/v1/users/set_profile/",
- {"first_name": "John-Tom'", "last_name": "Jacobs"},
+ {
+ "first_name": "John-Tom'",
+ "last_name": "Jacobs",
+ "stt": {"id": stt.id},
+ },
+ format="json",
)
assert response.status_code == status.HTTP_200_OK
- assert response.data == {"first_name": "John-Tom'", "last_name": "Jacobs"}
+ assert response.data == {
+ "email": user.username,
+ "first_name": "John-Tom'",
+ "last_name": "Jacobs",
+ "stt": {
+ "id": stt.id,
+ "type": stt.type,
+ "code": stt.code,
+ "name": stt.name,
+ },
+ }
user.refresh_from_db()
assert user.first_name == "John-Tom'"
assert user.last_name == "Jacobs"
+ assert user.stt.name == stt.name
@pytest.mark.django_db
def test_set_profile_data_spaced_last_name(api_client, user):
"""Test profile data can be set if last name has a space."""
+ stt = STT.objects.first()
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ response = api_client.patch(
"/v1/users/set_profile/",
- {"first_name": "Joan", "last_name": "Mary Ann"},
+ {
+ "first_name": "Joan",
+ "last_name": "Mary Ann",
+ "stt": {"id": stt.id},
+ },
+ format="json",
)
assert response.status_code == status.HTTP_200_OK
- assert response.data == {"first_name": "Joan", "last_name": "Mary Ann"}
+ assert response.data == {
+ "email": user.username,
+ "first_name": "Joan",
+ "last_name": "Mary Ann",
+ "stt": {
+ "id": stt.id,
+ "type": stt.type,
+ "code": stt.code,
+ "name": stt.name,
+ },
+ }
user.refresh_from_db()
assert user.first_name == "Joan"
assert user.last_name == "Mary Ann"
+ assert user.stt.name == stt.name
@pytest.mark.django_db
def test_set_profile_data_spaced_first_name(api_client, user):
"""Test profile data can be set if first name has a space."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ stt = STT.objects.first()
+ response = api_client.patch(
"/v1/users/set_profile/",
- {"first_name": "John Jim", "last_name": "Smith"},
+ {
+ "first_name": "John Jim",
+ "last_name": "Smith",
+ "stt": {"id": stt.id},
+ },
+ format="json",
)
assert response.status_code == status.HTTP_200_OK
- assert response.data == {"first_name": "John Jim", "last_name": "Smith"}
+ assert response.data == {
+ "email": user.username,
+ "first_name": "John Jim",
+ "last_name": "Smith",
+ "stt": {
+ "id": stt.id,
+ "type": stt.type,
+ "code": stt.code,
+ "name": stt.name,
+ },
+ }
user.refresh_from_db()
assert user.first_name == "John Jim"
assert user.last_name == "Smith"
+ assert user.stt.name == stt.name
@pytest.mark.django_db
def test_set_profile_data_last_name_with_tilde_over_char(api_client, user):
"""Test profile data can be set if last name includes a tilde character."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ stt = STT.objects.first()
+ response = api_client.patch(
"/v1/users/set_profile/",
- {"first_name": "Max", "last_name": "Grecheñ"},
+ {
+ "first_name": "Max",
+ "last_name": "Grecheñ",
+ "stt": {"id": stt.id},
+ },
+ format="json",
)
assert response.status_code == status.HTTP_200_OK
- assert response.data == {"first_name": "Max", "last_name": "Grecheñ"}
+ assert response.data == {
+ "email": user.username,
+ "first_name": "Max",
+ "last_name": "Grecheñ",
+ "stt": {
+ "id": stt.id,
+ "type": stt.type,
+ "code": stt.code,
+ "name": stt.name,
+ },
+ }
user.refresh_from_db()
assert user.first_name == "Max"
assert user.last_name == "Grecheñ"
+ assert user.stt.name == stt.name
@pytest.mark.django_db
def test_set_profile_data_last_name_with_tilde(api_client, user):
"""Test profile data can be set if last name includes alternate tilde character."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ stt = STT.objects.first()
+ response = api_client.patch(
"/v1/users/set_profile/",
- {"first_name": "Max", "last_name": "Glen~"},
+ {
+ "first_name": "Max",
+ "last_name": "Glen~",
+ "stt": {"id": stt.id},
+ },
+ format="json",
)
assert response.status_code == status.HTTP_200_OK
- assert response.data == {"first_name": "Max", "last_name": "Glen~"}
+ assert response.data == {
+ "email": user.username,
+ "first_name": "Max",
+ "last_name": "Glen~",
+ "stt": {
+ "id": stt.id,
+ "type": stt.type,
+ "code": stt.code,
+ "name": stt.name,
+ },
+ }
user.refresh_from_db()
assert user.first_name == "Max"
assert user.last_name == "Glen~"
+ assert user.stt.name == stt.name
@pytest.mark.django_db
@@ -213,20 +359,34 @@ def test_set_profile_data_extra_field_include_required(api_client, user):
with pytest.raises(AttributeError):
"""This test will fail if it does not trigger an AttributeError exception"""
api_client.login(username=user.username, password="test_password")
- response = api_client.post(
+ stt = STT.objects.first()
+ response = api_client.patch(
"/v1/users/set_profile/",
{
"first_name": "Heather",
"last_name": "Class",
"middle_initial": "Unknown",
+ "stt": {"id": stt.id},
},
+ format="json",
)
assert response.status_code == status.HTTP_200_OK
"""Test to ensure response data does not include unknown field"""
- assert response.data == {"first_name": "Heather", "last_name": "Class"}
+ assert response.data == {
+ "email": user.username,
+ "first_name": "Heather",
+ "last_name": "Class",
+ "stt": {
+ "id": stt.id,
+ "type": stt.type,
+ "code": stt.code,
+ "name": stt.name,
+ },
+ }
user.refresh_from_db()
assert user.first_name == "Heather"
assert user.last_name == "Class"
+ assert user.stt.name == stt.name
"""Test fails if AttributeError exception isn't thrown"""
assert user.middle_name == "Unknown"
@@ -235,7 +395,12 @@ def test_set_profile_data_extra_field_include_required(api_client, user):
def test_set_profile_data_missing_last_name_field(api_client, user):
"""Test profile data cannot be set if last name field is missing."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post("/v1/users/set_profile/", {"first_name": "Heather"})
+ response = api_client.patch(
+ "/v1/users/set_profile/",
+ {
+ "first_name": "Heather",
+ },
+ )
assert response.status_code == status.HTTP_400_BAD_REQUEST
@@ -243,5 +408,10 @@ def test_set_profile_data_missing_last_name_field(api_client, user):
def test_set_profile_data_missing_first_name_field(api_client, user):
"""Test profile data cannot be set if first name field is missing."""
api_client.login(username=user.username, password="test_password")
- response = api_client.post("/v1/users/set_profile/", {"last_name": "Heather"})
+ response = api_client.patch(
+ "/v1/users/set_profile/",
+ {
+ "last_name": "Heather",
+ },
+ )
assert response.status_code == status.HTTP_400_BAD_REQUEST
diff --git a/tdrs-backend/tdpservice/users/test/test_auth_check.py b/tdrs-backend/tdpservice/users/test/test_auth_check.py
index 9fde7a388..cdc4fef18 100644
--- a/tdrs-backend/tdpservice/users/test/test_auth_check.py
+++ b/tdrs-backend/tdpservice/users/test/test_auth_check.py
@@ -3,13 +3,15 @@
import pytest
from django.urls import reverse
from rest_framework import status
+from ..serializers import UserProfileSerializer
@pytest.mark.django_db
-def test_auth_check_endpoint_with_no_user(api_client, user):
- """If there is no user auth_check should return FORBIDDEN."""
+def test_auth_check_endpoint_with_no_user(api_client):
+ """If there is no user auth_check should return 200 with unauthorized message."""
response = api_client.get(reverse("authorization-check"))
- assert response.status_code == status.HTTP_403_FORBIDDEN
+ assert response.status_code == status.HTTP_200_OK
+ assert response.data["authenticated"] is False
@pytest.mark.django_db
@@ -18,6 +20,8 @@ def test_auth_check_endpoint_with_authenticated_user(api_client, user):
api_client.login(username=user.username, password="test_password")
response = api_client.get(reverse("authorization-check"))
assert response.status_code == status.HTTP_200_OK
+ assert user.is_authenticated is True
+ assert response.data["authenticated"] is True
@pytest.mark.django_db
@@ -25,7 +29,8 @@ def test_auth_check_endpoint_with_bad_user(api_client):
"""If the user doesn't exist, auth_check should not authenticate."""
api_client.login(username="nonexistent", password="test_password")
response = api_client.get(reverse("authorization-check"))
- assert response.status_code == status.HTTP_403_FORBIDDEN
+ assert response.status_code == status.HTTP_200_OK
+ assert response.data["authenticated"] is False
@pytest.mark.django_db
@@ -33,7 +38,8 @@ def test_auth_check_endpoint_with_unauthorized_email(api_client):
"""If the user has an email address not in the system it should not authenticate."""
api_client.login(username="bademail@example.com", password="test_password")
response = api_client.get(reverse("authorization-check"))
- assert response.status_code == status.HTTP_403_FORBIDDEN
+ assert response.status_code == status.HTTP_200_OK
+ assert response.data["authenticated"] is False
@pytest.mark.django_db
@@ -51,3 +57,12 @@ def test_auth_check_returns_user_email(api_client, user):
api_client.login(username=user.username, password="test_password")
response = api_client.get(reverse("authorization-check"))
assert response.data["user"]["email"] == user.username
+
+
+@pytest.mark.django_db
+def test_auth_check_returns_user_stt(api_client, user):
+ """If user is authenticated auth_check should return user data."""
+ api_client.login(username=user.username, password="test_password")
+ serializer = UserProfileSerializer(user)
+ response = api_client.get(reverse("authorization-check"))
+ assert response.data["user"]["stt"] == serializer.data["stt"]
diff --git a/tdrs-backend/tdpservice/users/urls.py b/tdrs-backend/tdpservice/users/urls.py
new file mode 100644
index 000000000..61273758e
--- /dev/null
+++ b/tdrs-backend/tdpservice/users/urls.py
@@ -0,0 +1,12 @@
+"""Routing for Users."""
+
+from rest_framework.routers import DefaultRouter
+from . import views
+
+router = DefaultRouter()
+
+router.register("", views.UserViewSet)
+
+urlpatterns = []
+
+urlpatterns += router.urls
diff --git a/tdrs-backend/tdpservice/users/views.py b/tdrs-backend/tdpservice/users/views.py
index 29a8036b9..faaf52318 100644
--- a/tdrs-backend/tdpservice/users/views.py
+++ b/tdrs-backend/tdpservice/users/views.py
@@ -11,7 +11,7 @@
from django.utils import timezone
from .serializers import (
CreateUserSerializer,
- SetUserProfileSerializer,
+ UserProfileSerializer,
UserSerializer,
)
@@ -26,7 +26,7 @@ class UserViewSet(
):
"""User accounts viewset."""
- queryset = User.objects.all()
+ queryset = User.objects.select_related("stt")
def get_permissions(self):
"""Get permissions for the viewset."""
@@ -40,10 +40,10 @@ def get_serializer_class(self):
"""Return the serializer class."""
return {
"create": CreateUserSerializer,
- "set_profile": SetUserProfileSerializer,
+ "set_profile": UserProfileSerializer,
}.get(self.action, UserSerializer)
- @action(methods=["POST"], detail=False)
+ @action(methods=["PATCH"], detail=False)
def set_profile(self, request, pk=None):
"""Set a user's profile data."""
serializer = self.get_serializer(self.request.user, request.data)
diff --git a/tdrs-frontend/package.json b/tdrs-frontend/package.json
index 9fb3a5d73..7cf87738d 100755
--- a/tdrs-frontend/package.json
+++ b/tdrs-frontend/package.json
@@ -7,6 +7,7 @@
"@fortawesome/free-solid-svg-icons": "^5.14.0",
"@fortawesome/react-fontawesome": "^0.1.11",
"axios": "^0.20.0",
+ "axios-cookiejar-support": "^1.0.1",
"babel-eslint": "10",
"classnames": "^2.2.6",
"concurrently": "^5.3.0",
@@ -28,6 +29,7 @@
"redux-oidc": "^4.0.0-beta1",
"redux-thunk": "^2.3.0",
"seamless-immutable": "^7.1.3",
+ "tough-cookie": "^4.0.0",
"typescript": "^3.9.7",
"uswds": "^2.9.0"
},
diff --git a/tdrs-frontend/src/App.js b/tdrs-frontend/src/App.js
index adca6fad3..214d9cf03 100644
--- a/tdrs-frontend/src/App.js
+++ b/tdrs-frontend/src/App.js
@@ -17,7 +17,15 @@ import Footer from './components/Footer'
function App() {
return (
<>
-
+ {
+ if (e.charCode === 32) {
+ window.location.href = '#main-content'
+ }
+ }}
+ >
Skip to main content
+
Please enter your information to request access from an OFA administrator
@@ -129,70 +160,22 @@ function EditProfile() { > There are {Object.keys(errors).length} errors in this form