-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Frontend/231/submit-form #383
Changes from 47 commits
826ffbe
c4a95ae
aed59f5
719fb28
7cc59cd
cc6aa2d
0a6dea7
a275240
a6ffe9e
b9acf63
dd360db
93ff1b8
ff8ae09
979ed1a
57eda4a
47a7eb9
30f7a94
df647b2
aa76d4d
4ee034d
394c7e3
252cf67
c58af7e
3e6ed16
a6076a3
4a920b8
ef918b1
17b8d94
726a4e2
6fea305
d856179
43e29d3
4f2c347
5f873c1
da4ae94
455fe5b
0726c1f
21914f7
8f198d8
c4ef509
4fa3eaf
1ada22a
e40ff9d
4d0dbf1
5e9a559
4625a77
55aa54d
339396d
fa3ad0f
2c4b32b
b121da6
59f7259
4931a11
567e570
e85f72f
cbe3ab6
4e7c430
64f6068
987da47
b80ac89
849d7af
fafa313
4306d46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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/` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using a patch instead of a post, required changes on both ends of the stack. |
||
|
||
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."] | ||
} | ||
``` | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding fixtures for STT and Region |
||
|
||
|
||
@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() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,21 @@ def get_code(self, obj): | |
return obj.code | ||
|
||
|
||
class STTUpdateSerializer(serializers.ModelSerializer): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Serializer for updating STTs |
||
"""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.""" | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
"""Generate test data for stts.""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Factories for STTs and Regions. |
||
|
||
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) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,18 +5,11 @@ | |
from django.contrib import admin | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We made some changes to the urls to house the app urls inside the app for easier reference. |
||
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))] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,9 @@ | |
|
||
from rest_framework.response import Response | ||
from rest_framework.views import APIView | ||
from rest_framework.permissions import AllowAny | ||
from django.utils import timezone | ||
from ..serializers import UserProfileSerializer | ||
|
||
logger = logging.getLogger() | ||
logger.setLevel(logging.INFO) | ||
|
@@ -14,18 +16,16 @@ class AuthorizationCheck(APIView): | |
|
||
query_string = False | ||
pattern_name = "authorization-check" | ||
permission_classes = [AllowAny] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add special permission for the authorization check to allow requests from any user. The response indicates the users authorization. |
||
|
||
def get(self, request, *args, **kwargs): | ||
"""Handle get request and authenticate user.""" | ||
user = request.user | ||
serializer = UserProfileSerializer(user) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the serializer for consistent user output. |
||
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, | ||
} | ||
logger.info( | ||
"Auth check PASS for user: %s on %s", user.username, timezone.now() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,14 @@ | ||
"""Serialize user data.""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We made updates to the user serializer to give a consistent response with the |
||
|
||
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.""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using a more general name for this, because it is now used for both authorization-check and set-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"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In order to add STT to auth-check, and email to set-profile, so they'd have the same payload. |
||
|
||
"""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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,4 +14,5 @@ def user_data(): | |
"last_name": "Smith", | ||
"password": "correcthorsebatterystaple", | ||
"auth_token": "xxx", | ||
"stt": "Michigan", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added STT to the user fixture |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,8 @@ | |
|
||
import factory | ||
|
||
from tdpservice.stts.test.factories import STTFactory | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add STT to user factory |
||
|
||
|
||
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): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updating documentation to reflect the change from a
POST
endpoint to aPATCH
endpoint.