mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-13 06:28:24 +02:00
Merge branch 'main' into za/2520-admin-portfolio-view
This commit is contained in:
commit
5afad6b91d
11 changed files with 337 additions and 4 deletions
|
@ -513,9 +513,18 @@ function initializeWidgetOnList(list, parentId) {
|
||||||
var readonlyView = document.querySelector("#action-needed-reason-email-readonly");
|
var readonlyView = document.querySelector("#action-needed-reason-email-readonly");
|
||||||
|
|
||||||
let emailWasSent = document.getElementById("action-needed-email-sent");
|
let emailWasSent = document.getElementById("action-needed-email-sent");
|
||||||
let actionNeededEmailData = document.getElementById('action-needed-emails-data').textContent;
|
|
||||||
let actionNeededEmailsJson = JSON.parse(actionNeededEmailData);
|
|
||||||
|
|
||||||
|
let emailData = document.getElementById('action-needed-emails-data');
|
||||||
|
if (!emailData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let actionNeededEmailData = emailData.textContent;
|
||||||
|
if(!actionNeededEmailData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let actionNeededEmailsJson = JSON.parse(actionNeededEmailData);
|
||||||
const domainRequestId = actionNeededReasonDropdown ? document.querySelector("#domain_request_id").value : null
|
const domainRequestId = actionNeededReasonDropdown ? document.querySelector("#domain_request_id").value : null
|
||||||
const emailSentSessionVariableName = `actionNeededEmailSent-${domainRequestId}`;
|
const emailSentSessionVariableName = `actionNeededEmailSent-${domainRequestId}`;
|
||||||
const oldDropdownValue = actionNeededReasonDropdown ? actionNeededReasonDropdown.value : null;
|
const oldDropdownValue = actionNeededReasonDropdown ? actionNeededReasonDropdown.value : null;
|
||||||
|
@ -750,3 +759,118 @@ function initializeWidgetOnList(list, parentId) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
/** An IIFE for dynamically changing some fields on the portfolio admin model
|
||||||
|
*/
|
||||||
|
(function dynamicPortfolioFields(){
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
let isPortfolioPage = document.getElementById("portfolio_form");
|
||||||
|
if (!isPortfolioPage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// $ symbolically denotes that this is using jQuery
|
||||||
|
let $federalAgency = django.jQuery("#id_federal_agency");
|
||||||
|
let organizationType = document.getElementById("id_organization_type");
|
||||||
|
if ($federalAgency && organizationType) {
|
||||||
|
// Execute this function once on load
|
||||||
|
handleFederalAgencyChange($federalAgency, organizationType);
|
||||||
|
|
||||||
|
// Attach the change event listener
|
||||||
|
$federalAgency.on("change", function() {
|
||||||
|
handleFederalAgencyChange($federalAgency, organizationType);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle dynamically hiding the urbanization field
|
||||||
|
let urbanizationField = document.querySelector(".field-urbanization");
|
||||||
|
let stateTerritory = document.getElementById("id_state_territory");
|
||||||
|
if (urbanizationField && stateTerritory) {
|
||||||
|
// Execute this function once on load
|
||||||
|
handleStateTerritoryChange(stateTerritory, urbanizationField);
|
||||||
|
|
||||||
|
// Attach the change event listener for state/territory
|
||||||
|
stateTerritory.addEventListener("change", function() {
|
||||||
|
handleStateTerritoryChange(stateTerritory, urbanizationField);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleFederalAgencyChange(federalAgency, organizationType) {
|
||||||
|
// Set the org type to federal if an agency is selected
|
||||||
|
let selectedText = federalAgency.find("option:selected").text();
|
||||||
|
|
||||||
|
// There isn't a federal senior official associated with null records
|
||||||
|
if (!selectedText) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedText !== "Non-Federal Agency") {
|
||||||
|
if (organizationType.value !== "federal") {
|
||||||
|
organizationType.value = "federal";
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
if (organizationType.value === "federal") {
|
||||||
|
organizationType.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the associated senior official with this federal agency
|
||||||
|
let $seniorOfficial = django.jQuery("#id_senior_official");
|
||||||
|
if (!$seniorOfficial) {
|
||||||
|
console.log("Could not find the senior official field");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let seniorOfficialApi = document.getElementById("senior_official_from_agency_json_url").value;
|
||||||
|
fetch(`${seniorOfficialApi}?agency_name=${selectedText}`)
|
||||||
|
.then(response => {
|
||||||
|
const statusCode = response.status;
|
||||||
|
return response.json().then(data => ({ statusCode, data }));
|
||||||
|
})
|
||||||
|
.then(({ statusCode, data }) => {
|
||||||
|
if (data.error) {
|
||||||
|
// Clear the field if the SO doesn't exist.
|
||||||
|
if (statusCode === 404) {
|
||||||
|
$seniorOfficial.val("").trigger("change");
|
||||||
|
console.warn("Record not found: " + data.error);
|
||||||
|
}else {
|
||||||
|
console.error("Error in AJAX call: " + data.error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let seniorOfficialId = data.id;
|
||||||
|
let seniorOfficialName = [data.first_name, data.last_name].join(" ");
|
||||||
|
if (!seniorOfficialId || !seniorOfficialName || !seniorOfficialName.trim()){
|
||||||
|
// Clear the field if the SO doesn't exist
|
||||||
|
$seniorOfficial.val("").trigger("change");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the senior official to the dropdown.
|
||||||
|
// This format supports select2 - if we decide to convert this field in the future.
|
||||||
|
if ($seniorOfficial.find(`option[value='${seniorOfficialId}']`).length) {
|
||||||
|
// Select the value that is associated with the current Senior Official.
|
||||||
|
$seniorOfficial.val(seniorOfficialId).trigger("change");
|
||||||
|
} else {
|
||||||
|
// Create a DOM Option that matches the desired Senior Official. Then append it and select it.
|
||||||
|
let userOption = new Option(seniorOfficialName, seniorOfficialId, true, true);
|
||||||
|
$seniorOfficial.append(userOption).trigger("change");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => console.error("Error fetching senior official: ", error));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleStateTerritoryChange(stateTerritory, urbanizationField) {
|
||||||
|
let selectedValue = stateTerritory.value;
|
||||||
|
if (selectedValue === "PR") {
|
||||||
|
showElement(urbanizationField)
|
||||||
|
} else {
|
||||||
|
hideElement(urbanizationField)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
|
@ -1183,8 +1183,19 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
* @param {*} portfolio - the portfolio id
|
* @param {*} portfolio - the portfolio id
|
||||||
*/
|
*/
|
||||||
function loadDomains(page, sortBy = currentSortBy, order = currentOrder, scroll = scrollToTable, status = currentStatus, searchTerm = currentSearchTerm, portfolio = portfolioValue) {
|
function loadDomains(page, sortBy = currentSortBy, order = currentOrder, scroll = scrollToTable, status = currentStatus, searchTerm = currentSearchTerm, portfolio = portfolioValue) {
|
||||||
|
// fetch json of page of domais, given params
|
||||||
|
let baseUrl = document.getElementById("get_domains_json_url");
|
||||||
|
if (!baseUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let baseUrlValue = baseUrl.innerHTML;
|
||||||
|
if (!baseUrlValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// fetch json of page of domains, given params
|
// fetch json of page of domains, given params
|
||||||
let url = `/get-domains-json/?page=${page}&sort_by=${sortBy}&order=${order}&status=${status}&search_term=${searchTerm}`
|
let url = `${baseUrlValue}?page=${page}&sort_by=${sortBy}&order=${order}&status=${status}&search_term=${searchTerm}`
|
||||||
if (portfolio)
|
if (portfolio)
|
||||||
url += `&portfolio=${portfolio}`
|
url += `&portfolio=${portfolio}`
|
||||||
|
|
||||||
|
@ -1524,7 +1535,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
*/
|
*/
|
||||||
function loadDomainRequests(page, sortBy = currentSortBy, order = currentOrder, scroll = scrollToTable, searchTerm = currentSearchTerm) {
|
function loadDomainRequests(page, sortBy = currentSortBy, order = currentOrder, scroll = scrollToTable, searchTerm = currentSearchTerm) {
|
||||||
// fetch json of page of domain requests, given params
|
// fetch json of page of domain requests, given params
|
||||||
fetch(`/get-domain-requests-json/?page=${page}&sort_by=${sortBy}&order=${order}&search_term=${searchTerm}`)
|
let baseUrl = document.getElementById("get_domain_requests_json_url");
|
||||||
|
if (!baseUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let baseUrlValue = baseUrl.innerHTML;
|
||||||
|
if (!baseUrlValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(`${baseUrlValue}?page=${page}&sort_by=${sortBy}&order=${order}&search_term=${searchTerm}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ from registrar.views.report_views import (
|
||||||
|
|
||||||
from registrar.views.domain_request import Step
|
from registrar.views.domain_request import Step
|
||||||
from registrar.views.domain_requests_json import get_domain_requests_json
|
from registrar.views.domain_requests_json import get_domain_requests_json
|
||||||
|
from registrar.views.utility.api_views import get_senior_official_from_federal_agency_json
|
||||||
from registrar.views.domains_json import get_domains_json
|
from registrar.views.domains_json import get_domains_json
|
||||||
from registrar.views.utility import always_404
|
from registrar.views.utility import always_404
|
||||||
from api.views import available, get_current_federal, get_current_full
|
from api.views import available, get_current_federal, get_current_full
|
||||||
|
@ -128,6 +129,11 @@ urlpatterns = [
|
||||||
AnalyticsView.as_view(),
|
AnalyticsView.as_view(),
|
||||||
name="analytics",
|
name="analytics",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"admin/api/get-senior-official-from-federal-agency-json/",
|
||||||
|
get_senior_official_from_federal_agency_json,
|
||||||
|
name="get-senior-official-from-federal-agency-json",
|
||||||
|
),
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
path(
|
path(
|
||||||
"reports/export_data_type_user/",
|
"reports/export_data_type_user/",
|
||||||
|
|
|
@ -148,3 +148,12 @@ class Portfolio(TimeStampedModel):
|
||||||
def get_suborganizations(self):
|
def get_suborganizations(self):
|
||||||
"""Returns all suborganizations associated with this portfolio"""
|
"""Returns all suborganizations associated with this portfolio"""
|
||||||
return self.portfolio_suborganizations.all()
|
return self.portfolio_suborganizations.all()
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
"""Save override for custom properties"""
|
||||||
|
|
||||||
|
# The urbanization field is only intended for the state_territory puerto rico
|
||||||
|
if self.state_territory != self.StateTerritoryChoices.PUERTO_RICO and self.urbanization:
|
||||||
|
self.urbanization = None
|
||||||
|
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
{% extends 'django/admin/email_clipboard_change_form.html' %}
|
{% extends 'django/admin/email_clipboard_change_form.html' %}
|
||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% comment %} Stores the json endpoint in a url for easier access {% endcomment %}
|
||||||
|
{% url 'get-senior-official-from-federal-agency-json' as url %}
|
||||||
|
<input id="senior_official_from_agency_json_url" class="display-none" value="{{url}}" />
|
||||||
|
{{ block.super }}
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
{% block field_sets %}
|
{% block field_sets %}
|
||||||
{% for fieldset in adminform %}
|
{% for fieldset in adminform %}
|
||||||
{% comment %}
|
{% comment %}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
|
{% comment %} Stores the json endpoint in a url for easier access {% endcomment %}
|
||||||
|
{% url 'get_domain_requests_json' as url %}
|
||||||
|
<span id="get_domain_requests_json_url" class="display-none">{{url}}</span>
|
||||||
<section class="section--outlined domain-requests" id="domain-requests">
|
<section class="section--outlined domain-requests" id="domain-requests">
|
||||||
<div class="grid-row">
|
<div class="grid-row">
|
||||||
{% if not has_domain_requests_portfolio_permission %}
|
{% if not has_domain_requests_portfolio_permission %}
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% comment %} Stores the json endpoint in a url for easier access {% endcomment %}
|
||||||
|
{% url 'get_domains_json' as url %}
|
||||||
|
<span id="get_domains_json_url" class="display-none">{{url}}</span>
|
||||||
<section class="section--outlined domains{% if not has_domains_portfolio_permission %} margin-top-0{% endif %}" id="domains">
|
<section class="section--outlined domains{% if not has_domains_portfolio_permission %} margin-top-0{% endif %}" id="domains">
|
||||||
<div class="section--outlined__header margin-bottom-3 {% if not has_domains_portfolio_permission %} section--outlined__header--no-portfolio justify-content-space-between{% else %} grid-row{% endif %}">
|
<div class="section--outlined__header margin-bottom-3 {% if not has_domains_portfolio_permission %} section--outlined__header--no-portfolio justify-content-space-between{% else %} grid-row{% endif %}">
|
||||||
{% if not has_domains_portfolio_permission %}
|
{% if not has_domains_portfolio_permission %}
|
||||||
|
|
67
src/registrar/tests/test_api.py
Normal file
67
src/registrar/tests/test_api.py
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.test import TestCase, Client
|
||||||
|
from registrar.models import FederalAgency, SeniorOfficial, User
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from registrar.tests.common import create_superuser, create_user
|
||||||
|
|
||||||
|
|
||||||
|
class GetSeniorOfficialJsonTest(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.client = Client()
|
||||||
|
p = "password"
|
||||||
|
self.user = get_user_model().objects.create_user(username="testuser", password=p)
|
||||||
|
|
||||||
|
self.superuser = create_superuser()
|
||||||
|
self.analyst_user = create_user()
|
||||||
|
|
||||||
|
self.agency = FederalAgency.objects.create(agency="Test Agency")
|
||||||
|
self.senior_official = SeniorOfficial.objects.create(
|
||||||
|
first_name="John", last_name="Doe", title="Director", federal_agency=self.agency
|
||||||
|
)
|
||||||
|
|
||||||
|
self.api_url = reverse("get-senior-official-from-federal-agency-json")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
User.objects.all().delete()
|
||||||
|
SeniorOfficial.objects.all().delete()
|
||||||
|
FederalAgency.objects.all().delete()
|
||||||
|
|
||||||
|
def test_get_senior_official_json_authenticated_superuser(self):
|
||||||
|
"""Test that a superuser can fetch the senior official information."""
|
||||||
|
p = "adminpass"
|
||||||
|
self.client.login(username="superuser", password=p)
|
||||||
|
response = self.client.get(self.api_url, {"agency_name": "Test Agency"})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
data = response.json()
|
||||||
|
self.assertEqual(data["id"], self.senior_official.id)
|
||||||
|
self.assertEqual(data["first_name"], "John")
|
||||||
|
self.assertEqual(data["last_name"], "Doe")
|
||||||
|
self.assertEqual(data["title"], "Director")
|
||||||
|
|
||||||
|
def test_get_senior_official_json_authenticated_analyst(self):
|
||||||
|
"""Test that an analyst user can fetch the senior official's information."""
|
||||||
|
p = "userpass"
|
||||||
|
self.client.login(username="staffuser", password=p)
|
||||||
|
response = self.client.get(self.api_url, {"agency_name": "Test Agency"})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
data = response.json()
|
||||||
|
self.assertEqual(data["id"], self.senior_official.id)
|
||||||
|
self.assertEqual(data["first_name"], "John")
|
||||||
|
self.assertEqual(data["last_name"], "Doe")
|
||||||
|
self.assertEqual(data["title"], "Director")
|
||||||
|
|
||||||
|
def test_get_senior_official_json_unauthenticated(self):
|
||||||
|
"""Test that an unauthenticated user receives a 403 with an error message."""
|
||||||
|
p = "password"
|
||||||
|
self.client.login(username="testuser", password=p)
|
||||||
|
response = self.client.get(self.api_url, {"agency_name": "Test Agency"})
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
def test_get_senior_official_json_not_found(self):
|
||||||
|
"""Test that a request for a non-existent agency returns a 404 with an error message."""
|
||||||
|
p = "adminpass"
|
||||||
|
self.client.login(username="superuser", password=p)
|
||||||
|
response = self.client.get(self.api_url, {"agency_name": "Non-Federal Agency"})
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
data = response.json()
|
||||||
|
self.assertEqual(data["error"], "Senior Official not found")
|
|
@ -2266,3 +2266,57 @@ class TestDomainRequestIncomplete(TestCase):
|
||||||
self.domain_request.generic_org_type = None
|
self.domain_request.generic_org_type = None
|
||||||
self.domain_request.save()
|
self.domain_request.save()
|
||||||
self.assertFalse(self.domain_request._form_complete(request))
|
self.assertFalse(self.domain_request._form_complete(request))
|
||||||
|
|
||||||
|
|
||||||
|
class TestPortfolio(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.user, _ = User.objects.get_or_create(
|
||||||
|
username="intern@igorville.com", email="intern@igorville.com", first_name="Lava", last_name="World"
|
||||||
|
)
|
||||||
|
super().setUp()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super().tearDown()
|
||||||
|
Portfolio.objects.all().delete()
|
||||||
|
User.objects.all().delete()
|
||||||
|
|
||||||
|
def test_urbanization_field_resets_when_not_puetro_rico(self):
|
||||||
|
"""The urbanization field should only be populated when the state is puetro rico.
|
||||||
|
Otherwise, this field should be empty."""
|
||||||
|
# Start out as PR, then change the field
|
||||||
|
portfolio = Portfolio.objects.create(
|
||||||
|
creator=self.user,
|
||||||
|
organization_name="Test Portfolio",
|
||||||
|
state_territory=DomainRequest.StateTerritoryChoices.PUERTO_RICO,
|
||||||
|
urbanization="test",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(portfolio.urbanization, "test")
|
||||||
|
self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.PUERTO_RICO)
|
||||||
|
|
||||||
|
portfolio.state_territory = DomainRequest.StateTerritoryChoices.ALABAMA
|
||||||
|
portfolio.save()
|
||||||
|
|
||||||
|
self.assertEqual(portfolio.urbanization, None)
|
||||||
|
self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.ALABAMA)
|
||||||
|
|
||||||
|
def test_can_add_urbanization_field(self):
|
||||||
|
"""Ensures that you can populate the urbanization field when conditions are right"""
|
||||||
|
# Create a portfolio that cannot have this field
|
||||||
|
portfolio = Portfolio.objects.create(
|
||||||
|
creator=self.user,
|
||||||
|
organization_name="Test Portfolio",
|
||||||
|
state_territory=DomainRequest.StateTerritoryChoices.ALABAMA,
|
||||||
|
urbanization="test",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Implicitly check if this gets cleared on create. It should.
|
||||||
|
self.assertEqual(portfolio.urbanization, None)
|
||||||
|
self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.ALABAMA)
|
||||||
|
|
||||||
|
portfolio.state_territory = DomainRequest.StateTerritoryChoices.PUERTO_RICO
|
||||||
|
portfolio.urbanization = "test123"
|
||||||
|
portfolio.save()
|
||||||
|
|
||||||
|
self.assertEqual(portfolio.urbanization, "test123")
|
||||||
|
self.assertEqual(portfolio.state_territory, DomainRequest.StateTerritoryChoices.PUERTO_RICO)
|
||||||
|
|
|
@ -8,3 +8,4 @@ from .permission_views import (
|
||||||
DomainInvitationPermissionDeleteView,
|
DomainInvitationPermissionDeleteView,
|
||||||
DomainRequestWizardPermissionView,
|
DomainRequestWizardPermissionView,
|
||||||
)
|
)
|
||||||
|
from .api_views import get_senior_official_from_federal_agency_json
|
||||||
|
|
36
src/registrar/views/utility/api_views.py
Normal file
36
src/registrar/views/utility/api_views.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import logging
|
||||||
|
from django.http import JsonResponse
|
||||||
|
from django.forms.models import model_to_dict
|
||||||
|
from registrar.models import FederalAgency, SeniorOfficial
|
||||||
|
from django.contrib.admin.views.decorators import staff_member_required
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@staff_member_required
|
||||||
|
def get_senior_official_from_federal_agency_json(request):
|
||||||
|
"""Returns federal_agency information as a JSON"""
|
||||||
|
|
||||||
|
# This API is only accessible to admins and analysts
|
||||||
|
superuser_perm = request.user.has_perm("registrar.full_access_permission")
|
||||||
|
analyst_perm = request.user.has_perm("registrar.analyst_access_permission")
|
||||||
|
if not request.user.is_authenticated or not any([analyst_perm, superuser_perm]):
|
||||||
|
return JsonResponse({"error": "You do not have access to this resource"}, status=403)
|
||||||
|
|
||||||
|
agency_name = request.GET.get("agency_name")
|
||||||
|
agency = FederalAgency.objects.filter(agency=agency_name).first()
|
||||||
|
senior_official = SeniorOfficial.objects.filter(federal_agency=agency).first()
|
||||||
|
if agency and senior_official:
|
||||||
|
# Convert the agency object to a dictionary
|
||||||
|
so_dict = model_to_dict(senior_official)
|
||||||
|
|
||||||
|
# The phone number field isn't json serializable, so we
|
||||||
|
# convert this to a string first if it exists.
|
||||||
|
if "phone" in so_dict and so_dict.get("phone"):
|
||||||
|
so_dict["phone"] = str(so_dict["phone"])
|
||||||
|
|
||||||
|
return JsonResponse(so_dict)
|
||||||
|
else:
|
||||||
|
return JsonResponse({"error": "Senior Official not found"}, status=404)
|
Loading…
Add table
Add a link
Reference in a new issue