This commit is contained in:
David Kennedy 2024-05-09 11:14:49 -04:00
parent 1b6e6debf6
commit 948afab166
No known key found for this signature in database
GPG key ID: 6528A5386E66B96B
7 changed files with 109 additions and 17 deletions

View file

@ -178,6 +178,11 @@ urlpatterns = [
views.DomainAddUserView.as_view(),
name="domain-users-add",
),
path(
"user-profile",
views.UserProfileView.as_view(),
name="user-profile",
),
path(
"invitation/<int:pk>/delete",
views.DomainInvitationDeleteView.as_view(http_method_names=["post"]),

View file

@ -158,8 +158,11 @@
</li>
<li class="usa-nav__primary-item display-flex flex-align-center margin-left-2">
<span class="text-base"> | </span>
<a href="{% url 'logout' %}"><span class="text-primary">Sign out</span></a>
<a href="{% url 'user-profile' %}"><span class="text-primary">Your profile</span></a>
</li>
<li class="usa-nav__primary-item display-flex flex-align-center margin-left-2">
<span class="text-base"> | </span>
<a href="{% url 'logout' %}"><span class="text-primary">Sign out</span></a>
{% else %}
<a href="{% url 'login' %}"><span>Sign in</span></a>
{% endif %}

View file

@ -3,25 +3,36 @@
{% block title %}
Edit your User Profile |
{% endblock title %}
{% load static url_helpers %}
{% block content %}
<main id="main-content" class="grid-container">
<form class="usa-form usa-form--large" method="post" enctype="multipart/form-data">
<fieldset class="usa-fieldset">
<legend class="usa-legend usa-legend--large">Your profile</legend>
<p>
Required fields are marked with an asterisk (<abbr
title="required"
class="usa-hint usa-hint--required"
>*</abbr>).
<div class="grid-col desktop:grid-offset-2 desktop:grid-col-8">
<a href="{% url 'home' %}" class="breadcrumb__back">
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
<use xlink:href="{% static 'img/sprite.svg' %}#arrow_back"></use>
</svg>
<p class="margin-left-05 margin-top-0 margin-bottom-0 line-height-sans-1">
Back to manage your domains
</p>
{% for field in profile_form %}
<label class="usa-label" for="id_{{ field.name }}">{{ field.label }}</label>
{{ field }}
{% endfor %}
</fieldset>
<button type="submit" class="usa-button usa-button--big">Save Changes</button>
</form>
</a>
<h1>Your profile</h1>
<p>We require that you maintain accurate contact information. The details you provide will only be used to support the administration of .gov and wont be made public.</p>
<h2>Contact information</h2>
<p>Review the details below and update any required information. Note that editing this information wont affect your Login.gov account information.</p>
{% include "includes/required_fields.html" %}
<form class="usa-form usa-form--large" method="post" enctype="multipart/form-data">
<fieldset class="usa-fieldset">
<legend class="usa-legend usa-legend--large">Your profile</legend>
{% for field in profile_form %}
<label class="usa-label" for="id_{{ field.name }}">{{ field.label }}</label>
{{ field }}
{% endfor %}
</fieldset>
<button type="submit" class="usa-button">Save</button>
</form>
</main>
{% endblock content %}

View file

@ -14,5 +14,6 @@ from .domain import (
DomainInvitationDeleteView,
DomainDeleteUserView,
)
from .user_profile import UserProfileView
from .health import *
from .index import *

View file

@ -0,0 +1,36 @@
"""Views for a User Profile.
"""
import logging
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.db import IntegrityError
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.urls import reverse
from django.views.generic.edit import FormMixin
from django.conf import settings
from registrar.models import (
User,
)
from registrar.views.utility.permission_views import UserProfilePermissionView
logger = logging.getLogger(__name__)
class UserProfileView(UserProfilePermissionView):
"""
Base View for the Domain. Handles getting and setting the domain
in session cache on GETs. Also provides methods for getting
and setting the domain in cache
"""
template_name = "profile.html"
# Override get_object to return the logged-in user
def get_object(self, queryset=None):
return self.request.user # Returns the logged-in user

View file

@ -382,3 +382,18 @@ class DomainInvitationPermission(PermissionsLoginMixin):
return False
return True
class UserProfilePermission(PermissionsLoginMixin):
"""Permission mixin that redirects to user profile if user
has access, otherwise 403"""
def has_permission(self):
"""Check if this user has access.
If the user is authenticated, they have access
"""
if not self.request.user.is_authenticated:
return False
return True

View file

@ -2,8 +2,9 @@
import abc # abstract base class
from django.contrib.auth import get_user_model
from django.views.generic import DetailView, DeleteView, TemplateView
from registrar.models import Domain, DomainRequest, DomainInvitation
from registrar.models import Domain, DomainRequest, DomainInvitation, User
from registrar.models.user_domain_role import UserDomainRole
from .mixins import (
@ -13,6 +14,7 @@ from .mixins import (
DomainInvitationPermission,
DomainRequestWizardPermission,
UserDeleteDomainRolePermission,
UserProfilePermission,
)
import logging
@ -142,3 +144,22 @@ class UserDomainRolePermissionDeleteView(UserDeleteDomainRolePermission, DeleteV
# variable name in template context for the model object
context_object_name = "userdomainrole"
class UserProfilePermissionView(UserProfilePermission, DetailView, abc.ABC):
"""Abstract base view for user profile view that enforces permissions.
This abstract view cannot be instantiated. Actual views must specify
`template_name`.
"""
# DetailView property for what model this is viewing
model = get_user_model()
# variable name in template context for the model object
context_object_name = "user"
# Abstract property enforces NotImplementedError on an attribute.
@property
@abc.abstractmethod
def template_name(self):
raise NotImplementedError