diff --git a/src/djangooidc/status.py b/src/djangooidc/status.py new file mode 100644 index 000000000..c016b63c6 --- /dev/null +++ b/src/djangooidc/status.py @@ -0,0 +1,81 @@ +""" +Descriptive HTTP status codes, for code readability. + +See RFC 2616 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html +And RFC 6585 - http://tools.ietf.org/html/rfc6585 +And RFC 4918 - https://tools.ietf.org/html/rfc4918 +""" +from __future__ import unicode_literals + + +def is_informational(code): + return code >= 100 and code <= 199 + + +def is_success(code): + return code >= 200 and code <= 299 + + +def is_redirect(code): + return code >= 300 and code <= 399 + + +def is_client_error(code): + return code >= 400 and code <= 499 + + +def is_server_error(code): + return code >= 500 and code <= 599 + + +HTTP_100_CONTINUE = 100 +HTTP_101_SWITCHING_PROTOCOLS = 101 +HTTP_200_OK = 200 +HTTP_201_CREATED = 201 +HTTP_202_ACCEPTED = 202 +HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203 +HTTP_204_NO_CONTENT = 204 +HTTP_205_RESET_CONTENT = 205 +HTTP_206_PARTIAL_CONTENT = 206 +HTTP_207_MULTI_STATUS = 207 +HTTP_300_MULTIPLE_CHOICES = 300 +HTTP_301_MOVED_PERMANENTLY = 301 +HTTP_302_FOUND = 302 +HTTP_303_SEE_OTHER = 303 +HTTP_304_NOT_MODIFIED = 304 +HTTP_305_USE_PROXY = 305 +HTTP_306_RESERVED = 306 +HTTP_307_TEMPORARY_REDIRECT = 307 +HTTP_400_BAD_REQUEST = 400 +HTTP_401_UNAUTHORIZED = 401 +HTTP_402_PAYMENT_REQUIRED = 402 +HTTP_403_FORBIDDEN = 403 +HTTP_404_NOT_FOUND = 404 +HTTP_405_METHOD_NOT_ALLOWED = 405 +HTTP_406_NOT_ACCEPTABLE = 406 +HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407 +HTTP_408_REQUEST_TIMEOUT = 408 +HTTP_409_CONFLICT = 409 +HTTP_410_GONE = 410 +HTTP_411_LENGTH_REQUIRED = 411 +HTTP_412_PRECONDITION_FAILED = 412 +HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413 +HTTP_414_REQUEST_URI_TOO_LONG = 414 +HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415 +HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416 +HTTP_417_EXPECTATION_FAILED = 417 +HTTP_422_UNPROCESSABLE_ENTITY = 422 +HTTP_423_LOCKED = 423 +HTTP_424_FAILED_DEPENDENCY = 424 +HTTP_428_PRECONDITION_REQUIRED = 428 +HTTP_429_TOO_MANY_REQUESTS = 429 +HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431 +HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451 +HTTP_500_INTERNAL_SERVER_ERROR = 500 +HTTP_501_NOT_IMPLEMENTED = 501 +HTTP_502_BAD_GATEWAY = 502 +HTTP_503_SERVICE_UNAVAILABLE = 503 +HTTP_504_GATEWAY_TIMEOUT = 504 +HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505 +HTTP_507_INSUFFICIENT_STORAGE = 507 +HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511 diff --git a/src/djangooidc/templates/djangooidc/base.html b/src/djangooidc/templates/djangooidc/base.html new file mode 100644 index 000000000..da96cb666 --- /dev/null +++ b/src/djangooidc/templates/djangooidc/base.html @@ -0,0 +1,30 @@ + + + + + {% block title %}{% endblock %} + + + +{% block content %}{% endblock %} + + \ No newline at end of file diff --git a/src/djangooidc/templates/djangooidc/error.html b/src/djangooidc/templates/djangooidc/error.html new file mode 100644 index 000000000..8e092b60b --- /dev/null +++ b/src/djangooidc/templates/djangooidc/error.html @@ -0,0 +1,33 @@ +{% extends "djangooidc/base.html" %} + +{% block title %}Error{% endblock %} + +{% block content %} +
+
OpenID Connect authentication has failed
+
+
Error message is: {{ error }}
+ {% if callback %} +
Query content was:
+
+ + + + + + + + + {% for key,value in callback.items %} + + + + + {% endfor %} + +
KeyValue
{{ key }}{{ value }}
+
+ {% endif %} +
+
+{% endblock %} \ No newline at end of file diff --git a/src/djangooidc/templates/djangooidc/login.html b/src/djangooidc/templates/djangooidc/login.html new file mode 100644 index 000000000..26e09886f --- /dev/null +++ b/src/djangooidc/templates/djangooidc/login.html @@ -0,0 +1,36 @@ +{% extends "djangooidc/base.html" %} +{% block title %}Login{% endblock %} +{% block content %} +
+
Please log in with one of the following methods:
+
+
Application login
+
+ {% csrf_token %} + {{ ilform }} + + +
+
+ + {% if op_list %} +
+
Log in with one of the following systems
+ {% for op_name in op_list %} + {{ op_name }}  + {% endfor %} +
+ {% endif %} + + {% if dynamic %} +
+
Log in in with an OpenID Connect provider of your choice
+
+ {% csrf_token %} + {{ form }} + +
+
+ {% endif %} +
+{% endblock %} \ No newline at end of file diff --git a/src/docker-compose.yml b/src/docker-compose.yml index d104a4c15..e034fb869 100644 --- a/src/docker-compose.yml +++ b/src/docker-compose.yml @@ -10,10 +10,6 @@ services: - db working_dir: /app entrypoint: python /app/docker_entrypoint.py - deploy: - restart_policy: - condition: on-failure - max_attempts: 5 environment: # Send stdout and stderr straight to the terminal without buffering - PYTHONUNBUFFERED=yup @@ -36,8 +32,7 @@ services: - "8080:8080" # command: "python" command: > - bash -c " python manage.py migrate && - python manage.py runserver 0.0.0.0:8080" + bash -c " python manage.py migrate && python manage.py runserver 0.0.0.0:8080" db: image: postgres:latest diff --git a/src/registrar/assets/sass/_theme/_uswds-theme-custom-styles.scss b/src/registrar/assets/sass/_theme/_uswds-theme-custom-styles.scss index aab929a51..74ad72cad 100644 --- a/src/registrar/assets/sass/_theme/_uswds-theme-custom-styles.scss +++ b/src/registrar/assets/sass/_theme/_uswds-theme-custom-styles.scss @@ -26,4 +26,3 @@ i.e. p { color: color('blue-10v'); } - diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index b17a0e4ce..422e224e2 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -164,6 +164,7 @@ TEMPLATES = [ "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", "registrar.context_processors.language_code", + "registrar.context_processors.canonical_path", ], }, }, diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py index 95802704f..37a0d754c 100644 --- a/src/registrar/config/urls.py +++ b/src/registrar/config/urls.py @@ -7,7 +7,7 @@ For more information see: from django.contrib import admin from django.urls import include, path -from registrar.views import health, index +from registrar.views import health, index, whoami urlpatterns = [ path("", index.index, name="home"), diff --git a/src/registrar/context_processors.py b/src/registrar/context_processors.py index 6e104b66d..51a420fca 100644 --- a/src/registrar/context_processors.py +++ b/src/registrar/context_processors.py @@ -11,3 +11,12 @@ def language_code(request): TEMPLATES dict of our settings file). """ return {"LANGUAGE_CODE": settings.LANGUAGE_CODE} + +def canonical_path(request): + """Add a canonical URL to the template context. + + To make a correct "rel=canonical" link in the HTML page, we need to + construct an absolute URL for the page, and we can't do that in the + template itself, so we do it here and pass the information on. + """ + return {"CANONICAL_PATH": request.build_absolute_uri(request.path)} diff --git a/src/registrar/templates/base.html b/src/registrar/templates/base.html index 3c303013d..39cc31809 100644 --- a/src/registrar/templates/base.html +++ b/src/registrar/templates/base.html @@ -7,28 +7,26 @@ {% block title %}{% endblock %} - {{ site.name }} + .gov Registrar {% block extra_title %}{% endblock %} {% block viewport_meta %} - + {% endblock %} {% block extra_meta %}{% endblock extra_meta %} - {# TO-DO: Determine if is desirable #} - {# TO-DO: set defaults for these #} {% block css %} - - + + {% endblock %} {% block canonical %} - + {% endblock %} @@ -49,154 +47,136 @@ Skip to main content -
-
-
-
-
- U.S. flag -
-
-

- An official website of the United States government -

- -
- -
-
-
-
-
- -
-

- Official websites use .gov
A - .gov website belongs to an official government - organization in the United States. +

+
+
+
+
+ U.S. flag +
+
+

+ An official website of the United States government +

+
+
-
- -
-

- Secure .gov websites use HTTPS
A - lock ( - - - - - ) or https:// means you’ve safely connected to - the .gov website. Share sensitive information only on official, - secure websites. -

+
+
+
+
+ +
+

+ Official websites use .gov
A + .gov website belongs to an official government + organization in the United States. +

+
+
+
+ +
+

+ Secure .gov websites use HTTPS
A + lock ( + + + + + ) or https:// means you’ve safely connected to + the .gov website. Share sensitive information only on official, + secure websites. +

+
-
-
+ {% block banner %} - {% endblock banner %} {% block usa_overlay %}
{% endblock %}
- {% block messages %} - {% if messages %} - - {% endif %} - {% endblock %} + {% block messages %} + {% if messages %} + + {% endif %} + {% endblock %} - {% block section_nav %}{% endblock %} + {% block section_nav %}{% endblock %} -
- {% block hero %}{% endblock %} - {% block content %}{% endblock %} -
+
+ {% block hero %}{% endblock %} + {% block content %}{% endblock %} +
-
{% block complementary %}{% endblock %}
+
{% block complementary %}{% endblock %}
- {% block content_bottom %}{% endblock %} + {% block content_bottom %}{% endblock %} +
+ + {% block init_js %}{% endblock %}{# useful for vars and other initializations #} @@ -208,8 +188,6 @@ {% block extrascript %}{% endblock %} - {# asynchronous analytics #} - + diff --git a/src/registrar/templates/home.html b/src/registrar/templates/home.html index 14b0164ed..cdc81e36a 100644 --- a/src/registrar/templates/home.html +++ b/src/registrar/templates/home.html @@ -3,14 +3,14 @@ {% block title %} Hello {% endblock %} {% block hero %} -
-
-
-

- Welcome to the .gov registrar -

+
+
+
+

+ Welcome to the .gov registrar +

-
+
{% endblock %} {% block content %} @@ -23,4 +23,4 @@

Click here to log in.

{% endif %} -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/src/registrar/templates/whoami.html b/src/registrar/templates/whoami.html index 9ad156c33..7fde3f786 100644 --- a/src/registrar/templates/whoami.html +++ b/src/registrar/templates/whoami.html @@ -2,17 +2,8 @@ {% extends 'base.html' %} {% block title %} Hello {% endblock %} -{% block hero %} -
-
-
-

- This is sample content. - This is only sample content. -

-

{{ name }} You'll want to replace it with content of your own.

- -
-
-
+{% block content %} +

Hello {{ user.last_name|default:"No last name given" }}, {{ user.first_name|default:"No first name given" }} <{{ user.email }}>!

+ +

Click here to log out

{% endblock %} diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py index 72aa19efc..4044f42d4 100644 --- a/src/registrar/tests/test_views.py +++ b/src/registrar/tests/test_views.py @@ -1,11 +1,38 @@ from django.test import Client, TestCase +from django.contrib.auth.models import User -class HealthTest(TestCase): +class TestViews(TestCase): def setUp(self): self.client = Client() def test_health_check_endpoint(self): response = self.client.get("/health/") - self.assertEqual(response.status_code, 200) - self.assertContains(response, "OK") + self.assertContains(response, "OK", status_code=200) + + def test_home_page(self): + """Home page should be available without a login.""" + response = self.client.get("/") + self.assertContains(response, "registrar", status_code=200) + self.assertContains(response, "log in") + + def test_whoami_page(self): + """User information appears on the whoami page.""" + username = "test_user" + first_name = "First" + last_name = "Last" + email = "info@example.com" + user = User.objects.create( + username=username, first_name=first_name, last_name=last_name, email=email + ) + self.client.force_login(user) + response = self.client.get("/whoami") + self.assertContains(response, first_name) + self.assertContains(response, last_name) + self.assertContains(response, email) + + def test_whoami_page_no_user(self): + """Whoami page not accessible without a logged-in user.""" + response = self.client.get("/whoami") + self.assertEqual(response.status_code, 302) + self.assertIn("?next=/whoami", response.headers["Location"]) diff --git a/src/registrar/views/health.py b/src/registrar/views/health.py index 53179382a..6f7c6c9f7 100644 --- a/src/registrar/views/health.py +++ b/src/registrar/views/health.py @@ -1,7 +1,26 @@ from django.http import HttpResponse +from django.contrib.auth.decorators import login_required +from django.shortcuts import render def health(request): return HttpResponse( 'OK - Get.govOK' ) + + +@login_required +def home(request): + return render( + request, + "testapp/result.html", + { + "userinfo": request.session["userinfo"] + if "userinfo" in request.session.keys() + else None + }, + ) + + +def unprotected(request): + return render(request, "testapp/unprotected.html") diff --git a/src/registrar/views/index.py b/src/registrar/views/index.py index 6fd69f61f..8017062dd 100644 --- a/src/registrar/views/index.py +++ b/src/registrar/views/index.py @@ -1,6 +1,7 @@ from django.shortcuts import render +from django.contrib.auth.decorators import login_required def index(request): - context = {"name": "World!"} - return render(request, "whoami.html", context) + """This page is available to anyone without logging in.""" + return render(request, "home.html") diff --git a/src/registrar/views/whoami.py b/src/registrar/views/whoami.py new file mode 100644 index 000000000..53ad0aa00 --- /dev/null +++ b/src/registrar/views/whoami.py @@ -0,0 +1,8 @@ +from django.shortcuts import render +from django.contrib.auth.decorators import login_required + +@login_required +def whoami(request): + """This is the first page someone goes to after logging in.""" + return render(request, "whoami.html") +