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 19 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
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
3 changes: 2 additions & 1 deletion tdrs-backend/tdpservice/stts/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@


@admin.register(STT)
class STTAdmin(ReadOnlyAdminMixin, admin.ModelAdmin):
class STTAdmin(admin.ModelAdmin):
"""Read-only Admin class for STT models."""

readonly_fields = ['type', 'code', 'code_number', 'name', 'region', 'filenames', 'stt_code', 'state']
list_display = [field.name for field in STT._meta.fields]


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def _get_states():
type=STT.EntityType.STATE,
filenames=json.loads(row["filenames"].replace('\'', '"')),
stt_code=row["STT_CODE"],
ssp=row["SSP"] == "1",
)
for row in reader
]
Expand All @@ -49,6 +50,7 @@ def _get_territories():
type=STT.EntityType.TERRITORY,
filenames=json.loads(row["filenames"].replace('\'', '"')),
stt_code=row["STT_CODE"],
ssp=row["SSP"] == "1",
)
for row in reader
]
Expand All @@ -65,6 +67,7 @@ def _populate_tribes():
type=STT.EntityType.TRIBE,
filenames=json.loads(row["filenames"].replace('\'', '"')),
stt_code=row["STT_CODE"],
ssp=row["SSP"] == "1",
)
for row in reader
]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,49 +1,8 @@
# Generated by Django 3.2.13 on 2022-06-08 14:43
# Generated by Django 3.2.15 on 2022-11-01 21:40

import csv
import json
from pathlib import Path

from django.core.management import call_command
from django.db import migrations, models


def add_filenames(apps, schema_editor):
call_command("populate_stts")
data_dir = Path(__file__).resolve().parent.parent /"management" / "commands" / "data"
STT = apps.get_model('stts','STT')

fieldnames = ["Code", "Name", "Region", "STT_CODE", "Sample", "SSP", "SSN_Encrypted", "filenames"]
with open(data_dir / "states.csv", "r") as csvfile:
reader = csv.DictReader(csvfile)
rows=[]
for row in reader:
filenames = row["filenames"] = row["filenames"].replace('\'', '"')
rows.append(row)
state = STT.objects.get(name=row["Name"])
state.filenames = json.loads(filenames)
state.save()

with open(data_dir / "tribes.csv", "r") as csvfile:
reader = csv.DictReader(csvfile)
rows=[]
for row in reader:
filenames = row["filenames"] = row["filenames"].replace('\'', '"')
rows.append(row)
tribe = STT.objects.get(name=row["Name"])
tribe.filenames = json.loads(filenames)
tribe.save()

with open(data_dir / "territories.csv", "r") as csvfile:
reader = csv.DictReader(csvfile)
rows=[]
for row in reader:
filenames = row["filenames"] = row["filenames"].replace('\'', '"')
rows.append(row)
territory = STT.objects.get(name=row["Name"])
territory.filenames = json.loads(filenames)
territory.save()

class Migration(migrations.Migration):

dependencies = [
Expand All @@ -56,6 +15,4 @@ class Migration(migrations.Migration):
name='filenames',
field=models.JSONField(blank=True, max_length=512, null=True),
),
migrations.RunPython(add_filenames)
]

18 changes: 18 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,18 @@
# Generated by Django 3.2.15 on 2022-11-02 16:39

from django.db import migrations, models


class Migration(migrations.Migration):

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

operations = [
migrations.AddField(
model_name='stt',
name='ssp',
field=models.BooleanField(default=False),
),
]
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()
})
})
Loading