Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1755 - added ssp boolean to stt model #2211

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions tdrs-backend/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""Sets an env variable to indicate that we are running tests. This is used to run custom migrations during testing."""
import os

def pytest_sessionstart(session):
"""Set PYTEST env variable to indicate that we are running tests."""
os.environ['PYTEST'] = 'True'
3 changes: 2 additions & 1 deletion tdrs-backend/tdpservice/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ def base_data_file_data(fake_file_name, data_analyst):
"user": str(data_analyst.id),
"quarter": "Q1",
"year": 2020,
"stt": int(data_analyst.stt.id)
"stt": int(data_analyst.stt.id),
"ssp": False,
}


Expand Down
8 changes: 6 additions & 2 deletions tdrs-backend/tdpservice/data_files/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class DataFileSerializer(serializers.ModelSerializer):
file = serializers.FileField(write_only=True)
stt = serializers.PrimaryKeyRelatedField(queryset=STT.objects.all())
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
ssp = serializers.BooleanField(write_only=True)

class Meta:
"""Metadata."""
Expand All @@ -35,13 +36,16 @@ class Meta:
"year",
"quarter",
"section",
"created_at"
"created_at",
"ssp",
]

def create(self, validated_data):
"""Create a new entry with a new version number."""
ssp = validated_data.pop('ssp')
if ssp:
validated_data['section'] = 'SSP ' + validated_data['section']
data_file = DataFile.create_new_version(validated_data)

# Determine the matching ClamAVFileScan for this DataFile.
av_scan = ClamAVFileScan.objects.filter(
file_name=data_file.original_filename,
Expand Down
18 changes: 18 additions & 0 deletions tdrs-backend/tdpservice/data_files/test/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,24 @@ def test_download_data_file_file_rejected_for_other_stt(

assert response.status_code == status.HTTP_403_FORBIDDEN

def test_data_files_data_upload_ssp(
self, api_client, data_file_data,
):
"""Test that when Data Analysts upload file with ssp true the section name is updated."""
data_file_data['ssp'] = True

response = self.post_data_file_file(api_client, data_file_data)
assert response.data['section'] == 'SSP Active Case Data'

def test_data_files_data_upload_tanf(
self, api_client, data_file_data,
):
"""Test that when Data Analysts upload file with ssp true the section name is updated."""
data_file_data['ssp'] = False

response = self.post_data_file_file(api_client, data_file_data)
assert response.data['section'] == 'Active Case Data'

def test_data_analyst_gets_email_when_user_uploads_report_for_their_stt(
self, api_client, data_file_data, user
):
Expand Down
1 change: 0 additions & 1 deletion tdrs-backend/tdpservice/data_files/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ class DataFileViewSet(ModelViewSet):
def create(self, request, *args, **kwargs):
"""Override create to upload in case of successful scan."""
response = super().create(request, *args, **kwargs)

# Upload to ACF-TITAN only if file is passed the virus scan and created
if response.status_code == status.HTTP_201_CREATED or response.status_code == status.HTTP_200_OK:
sftp_task.upload.delay(
Expand Down
5 changes: 5 additions & 0 deletions tdrs-backend/tdpservice/stts/migrations/0005_stt_stt_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@ class Migration(migrations.Migration):
name='stt_code',
field=models.PositiveIntegerField(blank=True, null=True),
),
migrations.AddField(
model_name='stt',
name='ssp',
field=models.BooleanField(default=False),
),
]
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,4 @@ class Migration(migrations.Migration):
field=models.JSONField(blank=True, max_length=512, null=True),
),
migrations.RunPython(add_filenames)
]

]
47 changes: 47 additions & 0 deletions tdrs-backend/tdpservice/stts/migrations/0007_stt_ssp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Generated by Cameron
import csv
from pathlib import Path
from ..models import STT
import os

from django.db import migrations, models


def _update(path):
data_dir = Path(__file__).resolve().parent.parent /"management" / "commands" / "data"

with open(data_dir / path) as csvfile:
reader = csv.DictReader(csvfile)

for row in reader:
stt = STT.objects.get(code=row["Code"])
stt.ssp = row["SSP"] == "0"
stt.save()

def _update_stts(apps, schema_editor):
_update("states.csv")
_update("territories.csv")
_update("tribes.csv")


class Migration(migrations.Migration):

dependencies = [
n0remac marked this conversation as resolved.
Show resolved Hide resolved
('stts', '0006_alter_stt_filenames'),
]

is_pytest = os.environ.get('PYTEST')

if is_pytest:
operations = [
migrations.RunPython(_update_stts),
]
else:
operations = [
migrations.AddField(
model_name='stt',
name='ssp',
field=models.BooleanField(default=False),
),
migrations.RunPython(_update_stts),
]
2 changes: 2 additions & 0 deletions tdrs-backend/tdpservice/stts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class EntityType(models.TextChoices):
# Tribes have a state, which we need to store.
state = models.ForeignKey("self", on_delete=models.CASCADE, blank=True, null=True)

ssp = models.BooleanField(default=False, editable=True)

class Meta:
"""Metadata."""

Expand Down
2 changes: 1 addition & 1 deletion tdrs-backend/tdpservice/stts/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Meta:
"""Metadata."""

model = STT
fields = ["id", "type", "code", "name", "region"]
fields = ["id", "type", "code", "name", "region", "ssp"]

def get_code(self, obj):
"""Return the state code."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,14 @@ def test_user_can_request_access(api_client, user, stt):
"last_name": "Bloggs",
"access_request": False, # old value no longer touched
"account_approval_status": "Access request", # new value updated
"stt": {"id": stt.id, "type": stt.type, "code": stt.code, "name": stt.name, "region": stt.region.id},
"stt": {
"id": stt.id,
"type": stt.type,
"code": stt.code,
"name": stt.name,
"region": stt.region.id,
"ssp": False
},
"region": None,
"roles": [],
}
Expand Down
2 changes: 2 additions & 0 deletions tdrs-frontend/src/actions/reports.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export const submit =
uploadedFiles,
user,
year,
ssp,
}) =>
async (dispatch) => {
const submissionRequests = uploadedFiles.map((file) => {
Expand All @@ -161,6 +162,7 @@ export const submit =
year,
stt,
quarter,
ssp,
}
for (const [key, value] of Object.entries(dataFile)) {
formData.append(key, value)
Expand Down
38 changes: 36 additions & 2 deletions tdrs-frontend/src/components/Reports/Reports.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ function Reports() {
}

const currentStt = isOFAAdmin ? selectedStt : userProfileStt

const stt = sttList?.find((stt) => stt?.name === currentStt)
const [submittedHeader, setSubmittedHeader] = useState('')
const [fileType, setFileType] = useState('tanf')

const errorsCount = formValidation.errors

Expand Down Expand Up @@ -207,7 +207,40 @@ function Reports() {
/>
</div>
)}

{(stt?.ssp ? stt.ssp : false) && (
<div className="usa-form-group margin-top-4">
<fieldset className="usa-fieldset">
<legend className="usa-label text-bold">File Type</legend>
<div className="usa-radio">
<input
className="usa-radio__input"
id="tanf"
type="radio"
name="reportType"
value="tanf"
defaultChecked
onChange={() => setFileType('tanf')}
/>
<label className="usa-radio__label" htmlFor="tanf">
TANF
</label>
</div>
<div className="usa-radio">
<input
className="usa-radio__input"
id="ssp-moe"
type="radio"
name="reportType"
value="ssp-moe"
onChange={() => setFileType('ssp-moe')}
/>
<label className="usa-radio__label" htmlFor="ssp-moe">
SSP-MOE
</label>
</div>
</fieldset>
</div>
)}
<div
className={classNames('usa-form-group maxw-mobile margin-top-4', {
'usa-form-group--error': formValidation.year,
Expand Down Expand Up @@ -288,6 +321,7 @@ function Reports() {
{isUploadReportToggled && (
<UploadReport
stt={stt?.id}
ssp={fileType === 'ssp-moe'}
header={submittedHeader}
handleCancel={() => setIsToggled(false)}
/>
Expand Down
87 changes: 87 additions & 0 deletions tdrs-frontend/src/components/Reports/Reports.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,14 @@ describe('Reports', () => {
type: 'state',
code: 'AL',
name: 'Alabama',
ssp: true,
},
{
id: 2,
type: 'state',
code: 'AK',
name: 'Alaska',
ssp: false,
},
],
loading: false,
Expand Down Expand Up @@ -446,4 +448,89 @@ describe('Reports', () => {

expect(expected).toEqual(currentYear.toString())
})

it('Non OFA Admin should show the data files section when the user has an stt with ssp set to true', () => {
const store = mockStore({
...initialState,
auth: {
...initialState.auth,
user: {
...initialState.auth.user,
roles: [],
stt: {
name: 'Alabama',
},
},
},
})

const { getByText } = render(
<Provider store={store}>
<Reports />
</Provider>
)

expect(getByText('File Type')).toBeInTheDocument()
})

// should not reder the File Type section if the user is not an OFA Admin and the stt has ssp set to false
it('Non OFA Admin should not show the data files section when the user has an stt with ssp set to false', () => {
const store = mockStore({
...initialState,
auth: {
...initialState.auth,
user: {
...initialState.auth.user,
roles: [],
stt: {
name: 'Alaska',
},
},
},
})

const { queryByText } = render(
<Provider store={store}>
<Reports />
</Provider>
)

expect(queryByText('File Type')).not.toBeInTheDocument()
})

it('OFA Admin should see the data files section when they select a stt with ssp set to true', () => {
const store = mockStore({
...initialState,
reports: {
...initialState.reports,
stt: 'Alabama',
},
})

const { getByText } = render(
<Provider store={store}>
<Reports />
</Provider>
)

expect(getByText('File Type')).toBeInTheDocument()
})

it('OFA Admin should not see the data files section when they select a stt with ssp set to false', () => {
const store = mockStore({
...initialState,
reports: {
...initialState.reports,
stt: 'Alaska',
},
})

const { queryByText } = render(
<Provider store={store}>
<Reports />
</Provider>
)

expect(queryByText('File Type')).not.toBeInTheDocument()
})
})
2 changes: 1 addition & 1 deletion tdrs-frontend/src/components/Routes/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const AppRoutes = () => {
exact
path="/data-files"
element={
<PrivateRoute title="TANF Data Files">
<PrivateRoute title="Data Files">
<Reports />
</PrivateRoute>
}
Expand Down
3 changes: 2 additions & 1 deletion tdrs-frontend/src/components/UploadReport/UploadReport.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { submit } from '../../actions/reports'
import { useEventLogger } from '../../utils/eventLogger'
import { fileUploadSections } from '../../reducers/reports'

function UploadReport({ handleCancel, header, stt }) {
function UploadReport({ handleCancel, header, stt, ssp }) {
// The currently selected year from the reportingYears dropdown
const selectedYear = useSelector((state) => state.reports.year)
// The selected quarter in the dropdown tied to our redux `reports` state
Expand Down Expand Up @@ -74,6 +74,7 @@ function UploadReport({ handleCancel, header, stt }) {
stt,
uploadedFiles,
user,
ssp,
})
)
}
Expand Down