Merge pull request #147 from cisagov/nmb/whomami

Add logged-in /whoami page
This commit is contained in:
Neil MartinsenBurrell 2022-09-30 09:20:13 -05:00 committed by GitHub
commit 18ee041e52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 174 additions and 171 deletions

View file

@ -26,7 +26,7 @@ services:
# Run Django in debug mode on local
- DJANGO_DEBUG=True
# Tell Django where it is being hosted
- DJANGO_BASE_URL="localhost:8080"
- DJANGO_BASE_URL=http://localhost:8080
# --- These keys are obtained from `.env` file ---
# Set a private JWT signing key for Login.gov
- DJANGO_SECRET_LOGIN_KEY

View file

@ -22,8 +22,7 @@ i.e.
@use "uswds-core" as *;
// Test custom style
p {
color: color('blue-10v');
}
// Test custom style (except this has not enough contrast)
//p {
// color: color('blue-10v');
//}

View file

@ -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",
],
},
},
@ -379,7 +380,7 @@ AUTHENTICATION_BACKENDS = [
# this is where unauthenticated requests are redirected when using
# the login_required() decorator, LoginRequiredMixin, or AccessMixin
LOGIN_URL = "openid/openid/login"
LOGIN_URL = "openid/login"
# where to go after logging out
LOGOUT_REDIRECT_URL = "home"
@ -405,10 +406,8 @@ OIDC_PROVIDERS = {
},
"client_registration": {
"client_id": "cisa_dotgov_registrar",
"redirect_uris": [f"https://{env_base_url}/openid/callback/login/"],
"post_logout_redirect_uris": [
f"https://{env_base_url}/openid/callback/logout/"
],
"redirect_uris": [f"{env_base_url}/openid/callback/login/"],
"post_logout_redirect_uris": [f"{env_base_url}/openid/callback/logout/"],
"token_endpoint_auth_method": ["private_key_jwt"],
"sp_private_key": secret_login_key,
},

View file

@ -7,10 +7,11 @@ For more information see:
from django.contrib import admin
from django.urls import include, path
from registrar.views import health, index, profile
from registrar.views import health, index, profile, whoami
urlpatterns = [
path("", index.index, name="home"),
path("whoami", whoami.whoami, name="whoami"),
path("admin/", admin.site.urls),
path("health/", health.health),
path("edit_profile/", profile.edit_profile, name="edit-profile"),

View file

@ -11,3 +11,13 @@ 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)}

View file

@ -7,7 +7,7 @@
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>
{% block title %}{% endblock %}
{{ site.name }}
.gov Registrar
{% block extra_title %}{% endblock %}
</title>
<meta name="description" content="{% block description %}{% endblock %}">
@ -16,8 +16,6 @@
{% endblock %}
{% block extra_meta %}{% endblock extra_meta %}
{# TO-DO: Determine if <link rel="manifest" href="site.webmanifest"> is desirable #}
{# TO-DO: set defaults for these #}
<link rel="shortcut icon" href="{% static 'img/favicon.png' %}">
<link rel="apple-touch-icon" href="{% static 'img/touch-icon.png' %}">
@ -28,7 +26,7 @@
{% endblock %}
{% block canonical %}
<link rel="canonical" href="{{ current_path }}">
<link rel="canonical" href="{{ CANONICAL_PATH }}">
{% endblock %}
@ -49,16 +47,12 @@
<script src="{% static 'js/uswds.min.js' %}" defer></script>
<a class="usa-skipnav" href="#main-content">Skip to main content</a>
<section class="usa-banner" aria-label="Official government website">
<section class="usa-banner" aria-label="Official government website">
<div class="usa-accordion">
<header class="usa-banner__header">
<div class="usa-banner__inner">
<div class="grid-col-auto">
<img
class="usa-banner__header-flag"
src="{% static 'img/us_flag_small.png' %}"
alt="U.S. flag"
/>
<img class="usa-banner__header-flag" src="{% static 'img/us_flag_small.png' %}" alt="U.S. flag" />
</div>
<div class="grid-col-fill tablet:grid-col-auto">
<p class="usa-banner__header-text">
@ -68,28 +62,17 @@
Heres how you know
</p>
</div>
<button
class="usa-accordion__button usa-banner__button"
aria-expanded="false"
aria-controls="gov-banner-default-default"
>
<button class="usa-accordion__button usa-banner__button" aria-expanded="false"
aria-controls="gov-banner-default-default">
<span class="usa-banner__button-text">Heres how you know</span>
</button>
</div>
</header>
<div
class="usa-banner__content usa-accordion__content"
id="gov-banner-default-default"
>
<div class="usa-banner__content usa-accordion__content" id="gov-banner-default-default">
<div class="grid-row grid-gap-lg">
<div class="usa-banner__guidance tablet:grid-col-6">
<img
class="usa-banner__icon usa-media-block__img"
src="{% static 'img/icon-dot-gov.svg' %}"
role="img"
alt=""
aria-hidden="true"
/>
<img class="usa-banner__icon usa-media-block__img" src="{% static 'img/icon-dot-gov.svg' %}" role="img"
alt="" aria-hidden="true" />
<div class="usa-media-block__body">
<p>
<strong>Official websites use .gov</strong><br />A
@ -99,37 +82,20 @@
</div>
</div>
<div class="usa-banner__guidance tablet:grid-col-6">
<img
class="usa-banner__icon usa-media-block__img"
src="{% static 'img/icon-https.svg' %}"
role="img"
alt=""
aria-hidden="true"
/>
<img class="usa-banner__icon usa-media-block__img" src="{% static 'img/icon-https.svg' %}" role="img" alt=""
aria-hidden="true" />
<div class="usa-media-block__body">
<p>
<strong>Secure .gov websites use HTTPS</strong><br />A
<strong>lock</strong> (
<span class="icon-lock"
><svg
xmlns="http://www.w3.org/2000/svg"
width="52"
height="64"
viewBox="0 0 52 64"
class="usa-banner__lock-image"
role="img"
aria-labelledby="banner-lock-title-default banner-lock-description-default"
focusable="false"
>
<span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" width="52" height="64"
viewBox="0 0 52 64" class="usa-banner__lock-image" role="img"
aria-labelledby="banner-lock-title-default banner-lock-description-default" focusable="false">
<title id="banner-lock-title-default">Lock</title>
<desc id="banner-lock-description-default">A locked padlock</desc>
<path
fill="#000000"
fill-rule="evenodd"
d="M26 0c10.493 0 19 8.507 19 19v9h3a4 4 0 0 1 4 4v28a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V32a4 4 0 0 1 4-4h3v-9C7 8.507 15.507 0 26 0zm0 8c-5.979 0-10.843 4.77-10.996 10.712L15 19v9h22v-9c0-6.075-4.925-11-11-11z"
/>
</svg> </span
>) or <strong>https://</strong> means youve safely connected to
<path fill="#000000" fill-rule="evenodd"
d="M26 0c10.493 0 19 8.507 19 19v9h3a4 4 0 0 1 4 4v28a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V32a4 4 0 0 1 4-4h3v-9C7 8.507 15.507 0 26 0zm0 8c-5.979 0-10.843 4.77-10.996 10.712L15 19v9h22v-9c0-6.075-4.925-11-11-11z" />
</svg> </span>) or <strong>https://</strong> means youve safely connected to
the .gov website. Share sensitive information only on official,
secure websites.
</p>
@ -138,19 +104,18 @@
</div>
</div>
</div>
</section>
</section>
{% block banner %}
<header class="usa-header usa-header-extended" role="banner">
<header class="usa-header usa-header-basic" role="navigation">
<div class="usa-nav-container">
<div class="usa-navbar">
{% block logo %}
<div class="usa-logo" id="extended-logo">
<em class="usa-logo-text">
<a href="/"
title="Home"
aria-label="Home">
{% block site_name %}{{ site.name }}{% endblock %}
<em class="usa-logo__text">
<a href="/" title="Home" aria-label="Home">
{% block site_name %}Home{% endblock %}
</a>
</em>
</div>
@ -158,8 +123,23 @@
<button class="usa-menu-btn">Menu</button>
</div>
{% block usa_nav %}
<nav>
<button type="button" class="usa-nav__close">
<img src="/public/img/usa-icons/close.svg" role="img" alt="Close" />
</button>
<ul class="usa-nav__primary usa-accordion">
<li class="usa-nav__primary-item">
{% if user.is_authenticated %}
User: <a href="/whoami">{{ user.get_username }}</a>
{% else %}
<a href="/openid/login">Sign in</a>
{% endif %}
</li>
</ul>
</nav>
{% block usa_nav_secondary %}{% endblock %}
{% endblock %}
</div>
</header>
{% endblock banner %}
{% block usa_overlay %}<div class="usa-overlay"></div>{% endblock %}
@ -168,7 +148,7 @@
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
<li{% if message.tags %} class="{{ message.tags }}" {% endif %}>
{{ message }}
</li>
{% endfor %}
@ -193,7 +173,7 @@
{% endblock %}
{% block footer %}
<div>
<p class="copyright">&copy; {{ now.year }} {{ site.name }}</p>
<p class="copyright">&copy; {% now "Y" %} CISA .gov Registrar</p>
</div>
{% endblock %}
</footer>
@ -208,8 +188,6 @@
{% block extrascript %}{% endblock %}
{# asynchronous analytics #}
<script async id="_fed_an_ua_tag" src="https://dap.digitalgov.gov/Universal­Federated­Analytics­M
in.js?agency={{ AGENCY }}"></script>
</body>
</html>

View file

@ -3,21 +3,20 @@
{% block title %} Hello {% endblock %}
{% block hero %}
<section class="usa-hero">
<section class="usa-hero">
<div class="usa-grid">
<div class="usa-hero-callout usa-section-dark">
<h2>
<span class="usa-hero-callout-alt">Welcome to the .gov registrar</span>
</h2>
</div>
</section>
</section>
{% endblock %}
{% block content %}
<p>This is the .gov registrar.</p>
{% if user.is_authenticated %}
<p><b>Hello {{ user.id }}</b></p>
<p><a href="/openid/logout/">Click here to log out.</a></p>
{% else %}
<p><a href="/openid/login/">Click here to log in.</a></p>

View file

@ -2,17 +2,8 @@
{% extends 'base.html' %}
{% block title %} Hello {% endblock %}
{% block hero %}
<section class="usa-hero">
<div class="usa-grid">
<div class="usa-hero-callout usa-section-dark">
<h2>
<span class="usa-hero-callout-alt">This is sample content.</span>
This is only sample content.
</h2>
<p> {{ name }} You'll want to replace it with content of your own.</p>
<button class="usa-button usa-button--accent-cool">Click a usa button</button>
</div>
</div>
</section>
{% block content %}
<p> Hello {{ user.last_name|default:"No last name given" }}, {{ user.first_name|default:"No first name given" }} &lt;{{ user.email }}&gt;! </p>
<p><a href="/openid/logout">Click here to log out</a></p>
{% endblock %}

View file

@ -2,14 +2,25 @@ from django.test import Client, TestCase
from django.contrib.auth import get_user_model
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_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"])
class LoggedInTests(TestCase):
@ -23,6 +34,13 @@ class LoggedInTests(TestCase):
)
self.client.force_login(self.user)
def test_whoami_page(self):
"""User information appears on the whoami page."""
response = self.client.get("/whoami")
self.assertContains(response, self.user.first_name)
self.assertContains(response, self.user.last_name)
self.assertContains(response, self.user.email)
def test_edit_profile(self):
response = self.client.get("/edit_profile/")
self.assertContains(response, "Display Name")

View file

@ -2,5 +2,5 @@ from django.shortcuts import render
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")

View file

@ -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")