mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-05 17:28:31 +02:00
Initial architecture
This commit is contained in:
parent
8b41e70840
commit
75499337e0
12 changed files with 238 additions and 61 deletions
|
@ -104,7 +104,7 @@ urlpatterns = [
|
|||
# We embed the current user ID here, but we have a permission check
|
||||
# that ensures the user is who they say they are.
|
||||
"finish-user-setup/<int:pk>",
|
||||
views.FinishContactProfileSetupView.as_view(),
|
||||
views.ContactProfileSetupView.as_view(),
|
||||
name="finish-contact-profile-setup",
|
||||
),
|
||||
path(
|
||||
|
|
|
@ -126,11 +126,11 @@ class UserFixture:
|
|||
"last_name": "Osos-Analyst",
|
||||
"email": "kosos@truss.works",
|
||||
},
|
||||
{
|
||||
"username": "2cc0cde8-8313-4a50-99d8-5882e71443e8",
|
||||
"first_name": "Zander-Analyst",
|
||||
"last_name": "Adkinson-Analyst",
|
||||
},
|
||||
# {
|
||||
# "username": "2cc0cde8-8313-4a50-99d8-5882e71443e8",
|
||||
# "first_name": "Zander-Analyst",
|
||||
# "last_name": "Adkinson-Analyst",
|
||||
# },
|
||||
{
|
||||
"username": "57ab5847-7789-49fe-a2f9-21d38076d699",
|
||||
"first_name": "Paul-Analyst",
|
||||
|
|
42
src/registrar/forms/contact.py
Normal file
42
src/registrar/forms/contact.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
from django import forms
|
||||
from phonenumber_field.modelfields import PhoneNumberField # type: ignore
|
||||
from django.core.validators import MaxLengthValidator
|
||||
|
||||
|
||||
class ContactForm(forms.Form):
|
||||
"""Form for adding or editing a contact"""
|
||||
|
||||
first_name = forms.CharField(
|
||||
label="First name / given name",
|
||||
error_messages={"required": "Enter your first name / given name."},
|
||||
)
|
||||
middle_name = forms.CharField(
|
||||
required=False,
|
||||
label="Middle name (optional)",
|
||||
)
|
||||
last_name = forms.CharField(
|
||||
label="Last name / family name",
|
||||
error_messages={"required": "Enter your last name / family name."},
|
||||
)
|
||||
title = forms.CharField(
|
||||
label="Title or role in your organization",
|
||||
error_messages={
|
||||
"required": ("Enter your title or role in your organization (e.g., Chief Information Officer).")
|
||||
},
|
||||
)
|
||||
email = forms.EmailField(
|
||||
label="Email",
|
||||
max_length=None,
|
||||
error_messages={"invalid": ("Enter your email address in the required format, like name@example.com.")},
|
||||
validators=[
|
||||
MaxLengthValidator(
|
||||
320,
|
||||
message="Response must be less than 320 characters.",
|
||||
)
|
||||
],
|
||||
)
|
||||
phone = PhoneNumberField(
|
||||
label="Phone",
|
||||
error_messages={"invalid": "Enter a valid 10-digit phone number.", "required": "Enter your phone number."},
|
||||
)
|
||||
|
|
@ -202,7 +202,7 @@ NameserverFormset = formset_factory(
|
|||
validate_max=True,
|
||||
)
|
||||
|
||||
|
||||
# TODO - refactor, wait until daves PR
|
||||
class ContactForm(forms.ModelForm):
|
||||
"""Form for updating contacts."""
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ from registrar.forms.utility.wizard_form_helper import (
|
|||
from registrar.models import Contact, DomainRequest, DraftDomain, Domain, FederalAgency
|
||||
from registrar.templatetags.url_helpers import public_site_url
|
||||
from registrar.utility.enums import ValidationReturnType
|
||||
from registrar.forms import ContactForm
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -385,7 +386,7 @@ class PurposeForm(RegistrarForm):
|
|||
)
|
||||
|
||||
|
||||
class YourContactForm(RegistrarForm):
|
||||
class YourContactForm(RegistrarForm, ContactForm):
|
||||
JOIN = "submitter"
|
||||
|
||||
def to_database(self, obj):
|
||||
|
@ -408,40 +409,6 @@ class YourContactForm(RegistrarForm):
|
|||
contact = getattr(obj, "submitter", None)
|
||||
return super().from_database(contact)
|
||||
|
||||
first_name = forms.CharField(
|
||||
label="First name / given name",
|
||||
error_messages={"required": "Enter your first name / given name."},
|
||||
)
|
||||
middle_name = forms.CharField(
|
||||
required=False,
|
||||
label="Middle name (optional)",
|
||||
)
|
||||
last_name = forms.CharField(
|
||||
label="Last name / family name",
|
||||
error_messages={"required": "Enter your last name / family name."},
|
||||
)
|
||||
title = forms.CharField(
|
||||
label="Title or role in your organization",
|
||||
error_messages={
|
||||
"required": ("Enter your title or role in your organization (e.g., Chief Information Officer).")
|
||||
},
|
||||
)
|
||||
email = forms.EmailField(
|
||||
label="Email",
|
||||
max_length=None,
|
||||
error_messages={"invalid": ("Enter your email address in the required format, like name@example.com.")},
|
||||
validators=[
|
||||
MaxLengthValidator(
|
||||
320,
|
||||
message="Response must be less than 320 characters.",
|
||||
)
|
||||
],
|
||||
)
|
||||
phone = PhoneNumberField(
|
||||
label="Phone",
|
||||
error_messages={"invalid": "Enter a valid 10-digit phone number.", "required": "Enter your phone number."},
|
||||
)
|
||||
|
||||
|
||||
class OtherContactsYesNoForm(BaseYesNoForm):
|
||||
"""The yes/no field for the OtherContacts form."""
|
||||
|
|
|
@ -21,7 +21,12 @@ class RegistrarForm(forms.Form):
|
|||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault("label_suffix", "")
|
||||
# save a reference to a domain request object
|
||||
self.domain_request = kwargs.pop("domain_request", None)
|
||||
if "domain_request" in kwargs:
|
||||
self.domain_request = kwargs.pop("domain_request", None)
|
||||
|
||||
if "contact" in kwargs:
|
||||
self.contact = kwargs.pop("contact", None)
|
||||
|
||||
super(RegistrarForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def to_database(self, obj: DomainRequest | Contact):
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
from django.db import models
|
||||
|
||||
from .utility.time_stamped_model import TimeStampedModel
|
||||
|
||||
from phonenumber_field.modelfields import PhoneNumberField # type: ignore
|
||||
|
||||
|
||||
class Contact(TimeStampedModel):
|
||||
"""Contact information follows a similar pattern for each contact."""
|
||||
|
||||
|
|
|
@ -1,7 +1,72 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static url_helpers %}
|
||||
{% load static form_helpers url_helpers field_helpers %}
|
||||
{% block title %} Finish setting up your profile {% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>TEST</h2>
|
||||
<div class="grid-container">
|
||||
<div class="grid-row grid-gap">
|
||||
<div class="tablet:grid-col">
|
||||
<main id="main-content" class="grid-container">
|
||||
{% include "includes/form_messages.html" %}
|
||||
{% comment %}
|
||||
Repurposed from domain_request_form.html
|
||||
{% endcomment %}
|
||||
{% for outer in forms %}
|
||||
{% if outer|isformset %}
|
||||
{% for inner in outer.forms %}
|
||||
{% include "includes/form_errors.html" with form=inner %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% include "includes/form_errors.html" with form=outer %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<h1>Finish setting up your profile</h1>
|
||||
|
||||
<p>
|
||||
We <a href="#">require</a> that you maintain accurate contact information.
|
||||
The details you provide will only be used to support the administration of .gov and won’t be made public.
|
||||
</p>
|
||||
|
||||
<h2>What contact information should we use to reach you?</h2>
|
||||
<p>
|
||||
Review the details below and update any required information.
|
||||
Note that editing this information won’t affect your Login.gov account information.
|
||||
</p>
|
||||
{# TODO: maybe remove this? #}
|
||||
<p>Required information is marked with an asterisk (*).</p>
|
||||
<form id="step__{{steps.current}}" class="usa-form usa-form--large" method="post" novalidate>
|
||||
{% csrf_token %}
|
||||
<fieldset class="usa-fieldset">
|
||||
<legend class="usa-sr-only">
|
||||
Your contact information
|
||||
</legend>
|
||||
|
||||
{% input_with_errors forms.0.first_name %}
|
||||
|
||||
{% input_with_errors forms.0.middle_name %}
|
||||
|
||||
{% input_with_errors forms.0.last_name %}
|
||||
|
||||
{% input_with_errors forms.0.title %}
|
||||
|
||||
{% input_with_errors forms.0.email %}
|
||||
|
||||
{% with add_class="usa-input--medium" %}
|
||||
{% input_with_errors forms.0.phone %}
|
||||
{% endwith %}
|
||||
|
||||
</fieldset>
|
||||
<div>
|
||||
<button type="submit" name="submit_button" class="usa-button">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
{% block form_fields %}{% endblock %}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
|
|
|
@ -14,5 +14,8 @@ from .domain import (
|
|||
DomainInvitationDeleteView,
|
||||
DomainDeleteUserView,
|
||||
)
|
||||
from .contact import (
|
||||
ContactProfileSetupView,
|
||||
)
|
||||
from .health import *
|
||||
from .index import *
|
||||
|
|
107
src/registrar/views/contact.py
Normal file
107
src/registrar/views/contact.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
from registrar.forms.contact import ContactForm
|
||||
from registrar.views.utility.permission_views import ContactPermissionView
|
||||
from django.views.generic.edit import FormMixin
|
||||
|
||||
|
||||
# TODO we can and probably should generalize this at this rate.
|
||||
class BaseContactView(ContactPermissionView):
|
||||
def get(self, request, *args, **kwargs):
|
||||
self._set_contact(request)
|
||||
context = self.get_context_data(object=self.object)
|
||||
return self.render_to_response(context)
|
||||
|
||||
# TODO - this deserves a small refactor
|
||||
def _set_contact(self, request):
|
||||
"""
|
||||
get domain from session cache or from db and set
|
||||
to self.object
|
||||
set session to self for downstream functions to
|
||||
update session cache
|
||||
"""
|
||||
self.session = request.session
|
||||
|
||||
contact_pk = "contact:" + str(self.kwargs.get("pk"))
|
||||
cached_contact = self.session.get(contact_pk)
|
||||
|
||||
if cached_contact:
|
||||
self.object = cached_contact
|
||||
else:
|
||||
self.object = self.get_object()
|
||||
self._update_session_with_contact()
|
||||
|
||||
def _update_session_with_contact(self):
|
||||
"""
|
||||
Set contact pk in the session cache
|
||||
"""
|
||||
domain_pk = "contact:" + str(self.kwargs.get("pk"))
|
||||
self.session[domain_pk] = self.object
|
||||
|
||||
|
||||
class ContactFormBaseView(BaseContactView, FormMixin):
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""Form submission posts to this view.
|
||||
|
||||
This post method harmonizes using BaseContactView and FormMixin
|
||||
"""
|
||||
# Set the current contact object in cache
|
||||
self._set_contact(request)
|
||||
|
||||
# Get the current form and validate it
|
||||
form = self.get_form()
|
||||
return self.check_form(form)
|
||||
|
||||
# TODO rename?
|
||||
def check_form(self, form):
|
||||
return self.form_valid(form) if form.is_valid() else self.form_invalid(form)
|
||||
|
||||
def form_valid(self, form):
|
||||
# updates session cache with contact
|
||||
self._update_session_with_contact()
|
||||
|
||||
# superclass has the redirect
|
||||
return super().form_valid(form)
|
||||
|
||||
def form_invalid(self, form):
|
||||
# updates session cache with contact
|
||||
self._update_session_with_contact()
|
||||
|
||||
# superclass has the redirect
|
||||
return super().form_invalid(form)
|
||||
|
||||
|
||||
class ContactProfileSetupView(ContactPermissionView):
|
||||
"""This view forces the user into providing additional details that
|
||||
we may have missed from Login.gov"""
|
||||
template_name = "finish_contact_setup.html"
|
||||
form_class = ContactForm
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self._get_contact(request)
|
||||
context = self.get_context_data(object=self.object)
|
||||
return self.render_to_response(context)
|
||||
|
||||
def _get_contact(self, request):
|
||||
"""
|
||||
get domain from session cache or from db and set
|
||||
to self.object
|
||||
set session to self for downstream functions to
|
||||
update session cache
|
||||
"""
|
||||
self.session = request.session
|
||||
|
||||
contact_pk = "contact:" + str(self.kwargs.get("pk"))
|
||||
cached_contact = self.session.get(contact_pk)
|
||||
|
||||
if cached_contact:
|
||||
self.object = cached_contact
|
||||
else:
|
||||
self.object = self.get_object()
|
||||
self._set_session_contact_pk()
|
||||
|
||||
def _set_session_contact_pk(self):
|
||||
"""
|
||||
Set contact pk in the session cache
|
||||
"""
|
||||
domain_pk = "contact:" + str(self.kwargs.get("pk"))
|
||||
self.session[domain_pk] = self.object
|
||||
|
|
@ -14,7 +14,7 @@ from registrar.models.contact import Contact
|
|||
from registrar.models.user import User
|
||||
from registrar.utility import StrEnum
|
||||
from registrar.views.utility import StepsHelper
|
||||
from registrar.views.utility.permission_views import DomainRequestPermissionDeleteView, ContactPermissionView
|
||||
from registrar.views.utility.permission_views import DomainRequestPermissionDeleteView
|
||||
|
||||
from .utility import (
|
||||
DomainRequestPermissionView,
|
||||
|
@ -820,9 +820,3 @@ class DomainRequestDeleteView(DomainRequestPermissionDeleteView):
|
|||
duplicates = [item for item, count in object_dict.items() if count > 1]
|
||||
return duplicates
|
||||
|
||||
|
||||
class FinishContactProfileSetupView(ContactPermissionView):
|
||||
"""This view forces the user into providing additional details that
|
||||
we may have missed from Login.gov"""
|
||||
template_name = "finish_contact_setup.html"
|
||||
forms = [forms.YourContactForm]
|
||||
|
|
|
@ -153,11 +153,7 @@ class ContactPermissionView(ContactPermission, DetailView, abc.ABC):
|
|||
|
||||
# DetailView property for what model this is viewing
|
||||
model = Contact
|
||||
# variable name in template context for the model object
|
||||
context_object_name = "Contact"
|
||||
object: Contact
|
||||
|
||||
# Abstract property enforces NotImplementedError on an attribute.
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def template_name(self):
|
||||
raise NotImplementedError
|
||||
# variable name in template context for the model object
|
||||
context_object_name = "contact"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue