diff --git a/client/src/components/Ht/HtTooltip/HtTooltip.tsx b/client/src/components/Ht/HtTooltip/HtTooltip.tsx index ec65f04d5..74e9afff5 100644 --- a/client/src/components/Ht/HtTooltip/HtTooltip.tsx +++ b/client/src/components/Ht/HtTooltip/HtTooltip.tsx @@ -1,8 +1,7 @@ import { faInfoCircle } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { OverlayTrigger, Tooltip } from 'react-bootstrap'; -import { TooltipProps } from 'react-bootstrap'; import { ReactElement } from 'react'; +import { OverlayTrigger, Tooltip, TooltipProps } from 'react-bootstrap'; // see react-bootstrap OverlayTrigger for additional props that could be added // https://react-bootstrap.github.io/components/overlays/#overlay-trigger-props @@ -40,7 +39,7 @@ interface InfoTooltipProps { export function InfoIconTooltip({ message }: InfoTooltipProps) { return ( - + ); } diff --git a/client/src/components/UserProfile/MyOrgSites.tsx b/client/src/components/UserProfile/MyOrgSites.tsx new file mode 100644 index 000000000..0693bc969 --- /dev/null +++ b/client/src/components/UserProfile/MyOrgSites.tsx @@ -0,0 +1,35 @@ +import { HaztrakSite } from 'components/HaztrakSite'; +import React from 'react'; +import { Row, Table } from 'react-bootstrap'; +import { useGetOrgSitesQuery } from 'store'; +import { HaztrakProfileOrg } from 'store/profileSlice/profile.slice'; + +interface MyOrgSitesProps { + org: HaztrakProfileOrg; +} + +export function MyOrgSites({ org }: MyOrgSitesProps) { + const { data, isLoading, error } = useGetOrgSitesQuery(org.id); + return ( + + + + + + + + + + {data && + Object.values(data as HaztrakSite[]).map((site) => ( + + + + + ))} + +
EPA IDSite Type
{site.handler.epaSiteId}{site.handler.siteType}
+ Contact your Haztrak admin obtain access to additional sites within your organization +
+ ); +} diff --git a/client/src/components/UserProfile/SitePermissions.tsx b/client/src/components/UserProfile/MySitePermissions.tsx similarity index 80% rename from client/src/components/UserProfile/SitePermissions.tsx rename to client/src/components/UserProfile/MySitePermissions.tsx index 8ce6fe5fa..2b209363e 100644 --- a/client/src/components/UserProfile/SitePermissions.tsx +++ b/client/src/components/UserProfile/MySitePermissions.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Table } from 'react-bootstrap'; +import { Row, Table } from 'react-bootstrap'; import { Link } from 'react-router-dom'; import { HaztrakProfileSite } from 'store'; @@ -7,11 +7,10 @@ interface SitePermissionsProps { sites?: Record; } -export function SitePermissions({ sites }: SitePermissionsProps) { +export function MySitePermissions({ sites }: SitePermissionsProps) { return ( -
-

Site Permissions

- + +
@@ -34,6 +33,6 @@ export function SitePermissions({ sites }: SitePermissionsProps) { ))}
EPA ID
-
+ ); } diff --git a/client/src/components/UserProfile/UserOrg.tsx b/client/src/components/UserProfile/UserOrg.tsx new file mode 100644 index 000000000..0c14005bf --- /dev/null +++ b/client/src/components/UserProfile/UserOrg.tsx @@ -0,0 +1,59 @@ +import { faCheck, faX } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { MyOrgSites } from 'components/UserProfile/MyOrgSites'; +import { MySitePermissions } from 'components/UserProfile/MySitePermissions'; +import React from 'react'; +import { Col, Row, Tab, Tabs } from 'react-bootstrap'; +import { ProfileState } from 'store'; +import { HaztrakProfileOrg } from 'store/profileSlice/profile.slice'; + +interface MandatoryOrgProfile extends ProfileState { + org: HaztrakProfileOrg; +} + +interface UserOrgProps { + profile: MandatoryOrgProfile; +} + +export function UserOrg({ profile }: UserOrgProps) { + return ( + <> + +
+

Organization

+ +
+ Name +
+

{profile.org.name ?? 'My Organization'}

+ + +
+ Integrated with Rcrainfo? +
+

+ {profile.org.rcrainfoIntegrated ? ( + + Yes + + ) : ( + + No + + )} +

+ +
+ + + + + + + + + + + + ); +} diff --git a/client/src/components/UserProfile/UserProfile.tsx b/client/src/components/UserProfile/UserProfile.tsx index 4662cd9bc..f6de13762 100644 --- a/client/src/components/UserProfile/UserProfile.tsx +++ b/client/src/components/UserProfile/UserProfile.tsx @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { zodResolver } from '@hookform/resolvers/zod'; import { AxiosError } from 'axios'; import { HtForm, HtSpinner } from 'components/Ht'; -import { SitePermissions } from 'components/UserProfile/SitePermissions'; +import { UserOrg } from 'components/UserProfile/UserOrg'; import React, { createRef, useState } from 'react'; import { Button, Col, Container, Form, Row } from 'react-bootstrap'; import { useForm } from 'react-hook-form'; @@ -127,19 +127,7 @@ export function UserProfile({ user, profile }: UserProfileProps) { - {profile?.org && ( - <> - - -

{profile.org.name ?? 'My Organization'}

- -
- - - - - )} - +
{!editable ? ( <> @@ -174,6 +162,8 @@ export function UserProfile({ user, profile }: UserProfileProps) { )}
+ {/* @ts-ignore */} + {profile.org && } ); diff --git a/client/src/store/haztrakApiSlice.ts b/client/src/store/haztrakApiSlice.ts index 04e84af06..12fdaa630 100644 --- a/client/src/store/haztrakApiSlice.ts +++ b/client/src/store/haztrakApiSlice.ts @@ -1,5 +1,6 @@ import { BaseQueryFn, createApi } from '@reduxjs/toolkit/dist/query/react'; import { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'; +import { HaztrakSite } from 'components/HaztrakSite'; import { Code } from 'components/Manifest/WasteLine/wasteLineSchema'; import { RcraSite } from 'components/RcraSite'; import { htApi } from 'services'; @@ -99,6 +100,9 @@ export const haztrakApi = createApi({ getDotIdNumbers: build.query, string>({ query: (id) => ({ url: 'rcra/waste/dot/id', method: 'get', params: { q: id } }), }), + getOrgSites: build.query, string>({ + query: (id) => ({ url: `org/${id}/site`, method: 'get', params: { q: id } }), + }), }), }); @@ -109,4 +113,5 @@ export const { useGetFedWasteCodesQuery, useGetStateWasteCodesQuery, useGetDotIdNumbersQuery, + useGetOrgSitesQuery, } = haztrakApi; diff --git a/client/src/store/index.ts b/client/src/store/index.ts index 3e0dd5ba2..21a4d1847 100644 --- a/client/src/store/index.ts +++ b/client/src/store/index.ts @@ -17,6 +17,7 @@ export { useGetTaskStatusQuery, useSearchRcrainfoSitesQuery, useSearchRcraSitesQuery, + useGetOrgSitesQuery, } from 'store/haztrakApiSlice'; // Authentication Slice diff --git a/client/src/store/profileSlice/profile.slice.ts b/client/src/store/profileSlice/profile.slice.ts index 9c948c483..24ba4b37f 100644 --- a/client/src/store/profileSlice/profile.slice.ts +++ b/client/src/store/profileSlice/profile.slice.ts @@ -17,7 +17,7 @@ export interface ProfileState { error?: string; } -interface HaztrakProfileOrg { +export interface HaztrakProfileOrg { id: string; name: string; rcrainfoIntegrated: boolean; diff --git a/server/apps/core/migrations/0001_initial.py b/server/apps/core/migrations/0001_initial.py index 62a8fe5f5..b7af7d12b 100644 --- a/server/apps/core/migrations/0001_initial.py +++ b/server/apps/core/migrations/0001_initial.py @@ -1,143 +1,67 @@ -# Generated by Django 4.2.1 on 2023-06-12 18:32 +# Generated by Django 4.2.7 on 2023-11-20 16:47 -from django.conf import settings import django.contrib.auth.models import django.contrib.auth.validators from django.db import migrations, models -import django.db.models.deletion import django.utils.timezone +import uuid class Migration(migrations.Migration): + initial = True dependencies = [ - ("auth", "0012_alter_user_first_name_max_length"), ] operations = [ migrations.CreateModel( - name="HaztrakUser", + name='HaztrakUser', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("password", models.CharField(max_length=128, verbose_name="password")), - ( - "last_login", - models.DateTimeField(blank=True, null=True, verbose_name="last login"), - ), - ( - "is_superuser", - models.BooleanField( - default=False, - help_text="Designates that this user has all permissions without explicitly assigning them.", - verbose_name="superuser status", - ), - ), - ( - "username", - models.CharField( - error_messages={"unique": "A user with that username already exists."}, - help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", - max_length=150, - unique=True, - validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], - verbose_name="username", - ), - ), - ( - "first_name", - models.CharField(blank=True, max_length=150, verbose_name="first name"), - ), - ( - "last_name", - models.CharField(blank=True, max_length=150, verbose_name="last name"), - ), - ( - "email", - models.EmailField(blank=True, max_length=254, verbose_name="email address"), - ), - ( - "is_staff", - models.BooleanField( - default=False, - help_text="Designates whether the user can log into this admin site.", - verbose_name="staff status", - ), - ), - ( - "is_active", - models.BooleanField( - default=True, - help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", - verbose_name="active", - ), - ), - ( - "date_joined", - models.DateTimeField( - default=django.utils.timezone.now, verbose_name="date joined" - ), - ), - ( - "groups", - models.ManyToManyField( - blank=True, - help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", - related_name="user_set", - related_query_name="user", - to="auth.group", - verbose_name="groups", - ), - ), - ( - "user_permissions", - models.ManyToManyField( - blank=True, - help_text="Specific permissions for this user.", - related_name="user_set", - related_query_name="user", - to="auth.permission", - verbose_name="user permissions", - ), - ), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ], options={ - "verbose_name": "user", - "verbose_name_plural": "users", - "abstract": False, + 'verbose_name': 'User', + 'verbose_name_plural': 'Users', + 'ordering': ['username'], }, managers=[ - ("objects", django.contrib.auth.models.UserManager()), + ('objects', django.contrib.auth.models.UserManager()), ], ), migrations.CreateModel( - name="RcraProfile", + name='HaztrakProfile', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ], + options={ + 'verbose_name': 'Haztrak Profile', + 'ordering': ['user__username'], + 'default_related_name': 'haztrak_profile', + }, + ), + migrations.CreateModel( + name='RcraProfile', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("rcra_api_key", models.CharField(blank=True, max_length=128, null=True)), - ("rcra_api_id", models.CharField(blank=True, max_length=128, null=True)), - ("rcra_username", models.CharField(blank=True, max_length=128, null=True)), - ("phone_number", models.CharField(blank=True, max_length=15, null=True)), - ("email", models.EmailField(max_length=254)), - ( - "user", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL - ), - ), + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('rcra_api_key', models.CharField(blank=True, max_length=128, null=True)), + ('rcra_api_id', models.CharField(blank=True, max_length=128, null=True)), + ('rcra_username', models.CharField(blank=True, max_length=128, null=True)), + ('phone_number', models.CharField(blank=True, max_length=15, null=True)), + ('email', models.EmailField(max_length=254)), ], options={ - "ordering": ["rcra_username"], + 'ordering': ['rcra_username'], }, ), ] diff --git a/server/apps/core/migrations/0002_haztrakprofile.py b/server/apps/core/migrations/0002_haztrakprofile.py deleted file mode 100644 index 7beec3f50..000000000 --- a/server/apps/core/migrations/0002_haztrakprofile.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 4.2.7 on 2023-11-08 23:01 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("core", "0001_initial"), - ] - - operations = [ - migrations.CreateModel( - name="HaztrakProfile", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "user", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="haztrak_profile", - to=settings.AUTH_USER_MODEL, - ), - ), - ], - options={ - "verbose_name": "Haztrak Profile", - }, - ), - ] diff --git a/server/apps/core/migrations/0002_initial.py b/server/apps/core/migrations/0002_initial.py new file mode 100644 index 000000000..75eedc2d8 --- /dev/null +++ b/server/apps/core/migrations/0002_initial.py @@ -0,0 +1,44 @@ +# Generated by Django 4.2.7 on 2023-11-20 16:47 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('sites', '0001_initial'), + ('core', '0001_initial'), + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.AddField( + model_name='haztrakprofile', + name='org', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='haztrak_profiles', to='sites.haztrakorg'), + ), + migrations.AddField( + model_name='haztrakprofile', + name='rcrainfo_profile', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='haztrak_profile', to='core.rcraprofile'), + ), + migrations.AddField( + model_name='haztrakprofile', + name='user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='haztrak_profile', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='haztrakuser', + name='groups', + field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups'), + ), + migrations.AddField( + model_name='haztrakuser', + name='user_permissions', + field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions'), + ), + ] diff --git a/server/apps/core/migrations/0003_alter_haztrakprofile_options_and_more.py b/server/apps/core/migrations/0003_alter_haztrakprofile_options_and_more.py deleted file mode 100644 index f068d58ad..000000000 --- a/server/apps/core/migrations/0003_alter_haztrakprofile_options_and_more.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 4.2.7 on 2023-11-14 15:00 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0002_haztrakprofile'), - ] - - operations = [ - migrations.AlterModelOptions( - name='haztrakprofile', - options={'default_related_name': 'haztrak_profile', 'ordering': ['user__username'], 'verbose_name': 'Haztrak Profile'}, - ), - migrations.AlterModelOptions( - name='haztrakuser', - options={'ordering': ['username'], 'verbose_name': 'User', 'verbose_name_plural': 'Users'}, - ), - migrations.RemoveField( - model_name='rcraprofile', - name='user', - ), - migrations.AddField( - model_name='haztrakprofile', - name='rcrainfo_profile', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='haztrak_profile', to='core.rcraprofile'), - ), - ] diff --git a/server/apps/core/migrations/0004_haztrakprofile_org.py b/server/apps/core/migrations/0004_haztrakprofile_org.py deleted file mode 100644 index de2d75a3b..000000000 --- a/server/apps/core/migrations/0004_haztrakprofile_org.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2.7 on 2023-11-16 01:31 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('sites', '0004_alter_rcrasite_options_and_more'), - ('core', '0003_alter_haztrakprofile_options_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='haztrakprofile', - name='org', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='haztrak_profiles', to='sites.haztrakorg'), - ), - ] diff --git a/server/apps/core/models.py b/server/apps/core/models.py index d61ef5534..3cfd5b949 100644 --- a/server/apps/core/models.py +++ b/server/apps/core/models.py @@ -1,26 +1,11 @@ +import uuid + from django.contrib.auth.models import AbstractUser from django.db import models from haztrak import settings -class CoreBaseModel(models.Model): - """Base class for all apps.core models""" - - class Meta: - abstract = True - ordering = ["pk"] - - def __str__(self): - return f"{self.__class__.__name__}" - - def __repr__(self): - field_values = ", ".join( - f"{field.name}={getattr(self, field.name)!r}" for field in self._meta.fields - ) - return f"<{self.__class__.__name__}({field_values})>" - - class HaztrakUser(AbstractUser): """Haztrak abstract user model. It simply inherits from Django's AbstractUser model.""" @@ -29,15 +14,26 @@ class Meta: verbose_name_plural = "Users" ordering = ["username"] + id = models.UUIDField( + primary_key=True, + editable=False, + default=uuid.uuid4, + ) + pass -class HaztrakProfile(CoreBaseModel): +class HaztrakProfile(models.Model): class Meta: verbose_name = "Haztrak Profile" ordering = ["user__username"] default_related_name = "haztrak_profile" + id = models.UUIDField( + primary_key=True, + editable=False, + default=uuid.uuid4, + ) user = models.OneToOneField( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, @@ -67,7 +63,7 @@ def __str__(self): return f"{self.user.username}" -class RcraProfile(CoreBaseModel): +class RcraProfile(models.Model): """ Contains a user's RcraProfile information, such as username, and API credentials. Has a one-to-one relationship with the User model. @@ -76,6 +72,11 @@ class RcraProfile(CoreBaseModel): class Meta: ordering = ["rcra_username"] + id = models.UUIDField( + primary_key=True, + editable=False, + default=uuid.uuid4, + ) rcra_api_key = models.CharField( max_length=128, null=True, diff --git a/server/apps/sites/migrations/0001_initial.py b/server/apps/sites/migrations/0001_initial.py index ea9a12858..53a17932c 100644 --- a/server/apps/sites/migrations/0001_initial.py +++ b/server/apps/sites/migrations/0001_initial.py @@ -1,396 +1,156 @@ -# Generated by Django 4.2.1 on 2023-06-12 18:32 +# Generated by Django 4.2.7 on 2023-11-20 16:47 import apps.sites.models.contact_models +from django.conf import settings import django.core.validators from django.db import migrations, models import django.db.models.deletion +import uuid class Migration(migrations.Migration): + initial = True dependencies = [ - ("core", "0001_initial"), + ('core', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name="Address", + name='Address', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('street_number', models.CharField(blank=True, max_length=12, null=True)), + ('address1', models.CharField(max_length=50, verbose_name='address 1')), + ('address2', models.CharField(blank=True, default=None, max_length=50, null=True, verbose_name='address 2')), + ('city', models.CharField(blank=True, max_length=25, null=True)), + ('state', models.CharField(blank=True, choices=[('AK', 'Alaska'), ('AL', 'Alabama'), ('AP', 'Armed Forces Pacific'), ('AR', 'Arkansas'), ('AZ', 'Arizona'), ('CA', 'California'), ('CO', 'Colorado'), ('CT', 'Connecticut'), ('DC', 'Washington DC'), ('DE', 'Delaware'), ('FL', 'Florida'), ('GA', 'Georgia'), ('GU', 'Guam'), ('HI', 'Hawaii'), ('IA', 'Iowa'), ('ID', 'Idaho'), ('IL', 'Illinois'), ('IN', 'Indiana'), ('KS', 'Kansas'), ('KY', 'Kentucky'), ('LA', 'Louisiana'), ('MA', 'Massachusetts'), ('MD', 'Maryland'), ('ME', 'Maine'), ('MI', 'Michigan'), ('MN', 'Minnesota'), ('MO', 'Missouri'), ('MS', 'Mississippi'), ('MT', 'Montana'), ('NC', 'North Carolina'), ('ND', 'North Dakota'), ('NE', 'Nebraska'), ('NH', 'New Hampshire'), ('NJ', 'New Jersey'), ('NM', 'New Mexico'), ('NV', 'Nevada'), ('NY', 'New York'), ('OH', 'Ohio'), ('OK', 'Oklahoma'), ('OR', 'Oregon'), ('PA', 'Pennsylvania'), ('PR', 'Puerto Rico'), ('RI', 'Rhode Island'), ('SC', 'South Carolina'), ('SD', 'South Dakota'), ('TN', 'Tennessee'), ('TX', 'Texas'), ('UT', 'Utah'), ('VA', 'Virginia'), ('VI', 'Virgin Islands'), ('VT', 'Vermont'), ('WA', 'Washington'), ('WI', 'Wisconsin'), ('WV', 'West Virginia'), ('WY', 'Wyoming'), ('XA', 'REGION 01 PURVIEW'), ('XB', 'REGION 02 PURVIEW'), ('XC', 'REGION 03 PURVIEW'), ('XD', 'REGION 04 PURVIEW'), ('XE', 'REGION 05 PURVIEW'), ('XF', 'REGION 06 PURVIEW'), ('XG', 'REGION 07 PURVIEW'), ('XH', 'REGION 08 PURVIEW'), ('XI', 'REGION 09 PURVIEW'), ('XJ', 'REGION 10 PURVIEW')], max_length=3, null=True)), + ('country', models.CharField(blank=True, choices=[('US', 'United States'), ('MX', 'Mexico'), ('CA', 'Canada')], max_length=3, null=True)), + ('zip', models.CharField(blank=True, max_length=5, null=True)), + ], + options={ + 'ordering': ['address1'], + }, + ), + migrations.CreateModel( + name='Contact', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("street_number", models.CharField(blank=True, max_length=12, null=True)), - ("address1", models.CharField(max_length=50, verbose_name="address 1")), - ( - "address2", - models.CharField( - blank=True, - default=None, - max_length=50, - null=True, - verbose_name="address 2", - ), - ), - ("city", models.CharField(blank=True, max_length=25, null=True)), - ( - "state", - models.CharField( - blank=True, - choices=[ - ("AK", "Alaska"), - ("AL", "Alabama"), - ("AP", "Armed Forces Pacific"), - ("AR", "Arkansas"), - ("AZ", "Arizona"), - ("CA", "California"), - ("CO", "Colorado"), - ("CT", "Connecticut"), - ("DC", "Washington DC"), - ("DE", "Delaware"), - ("FL", "Florida"), - ("GA", "Georgia"), - ("GU", "Guam"), - ("HI", "Hawaii"), - ("IA", "Iowa"), - ("ID", "Idaho"), - ("IL", "Illinois"), - ("IN", "Indiana"), - ("KS", "Kansas"), - ("KY", "Kentucky"), - ("LA", "Louisiana"), - ("MA", "Massachusetts"), - ("MD", "Maryland"), - ("ME", "Maine"), - ("MI", "Michigan"), - ("MN", "Minnesota"), - ("MO", "Missouri"), - ("MS", "Mississippi"), - ("MT", "Montana"), - ("NC", "North Carolina"), - ("ND", "North Dakota"), - ("NE", "Nebraska"), - ("NH", "New Hampshire"), - ("NJ", "New Jersey"), - ("NM", "New Mexico"), - ("NV", "Nevada"), - ("NY", "New York"), - ("OH", "Ohio"), - ("OK", "Oklahoma"), - ("OR", "Oregon"), - ("PA", "Pennsylvania"), - ("PR", "Puerto Rico"), - ("RI", "Rhode Island"), - ("SC", "South Carolina"), - ("SD", "South Dakota"), - ("TN", "Tennessee"), - ("TX", "Texas"), - ("UT", "Utah"), - ("VA", "Virginia"), - ("VI", "Virgin Islands"), - ("VT", "Vermont"), - ("WA", "Washington"), - ("WI", "Wisconsin"), - ("WV", "West Virginia"), - ("WY", "Wyoming"), - ("XA", "REGION 01 PURVIEW"), - ("XB", "REGION 02 PURVIEW"), - ("XC", "REGION 03 PURVIEW"), - ("XD", "REGION 04 PURVIEW"), - ("XE", "REGION 05 PURVIEW"), - ("XF", "REGION 06 PURVIEW"), - ("XG", "REGION 07 PURVIEW"), - ("XH", "REGION 08 PURVIEW"), - ("XI", "REGION 09 PURVIEW"), - ("XJ", "REGION 10 PURVIEW"), - ], - max_length=3, - null=True, - ), - ), - ( - "country", - models.CharField( - blank=True, - choices=[("US", "United States"), ("MX", "Mexico"), ("CA", "Canada")], - max_length=3, - null=True, - ), - ), - ("zip", models.CharField(blank=True, max_length=5, null=True)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(blank=True, max_length=38, null=True)), + ('middle_initial', models.CharField(blank=True, max_length=1, null=True)), + ('last_name', models.CharField(blank=True, max_length=38, null=True)), + ('email', models.EmailField(blank=True, max_length=254, null=True)), + ('company_name', models.CharField(blank=True, max_length=80, null=True)), ], options={ - "ordering": ["address1"], + 'ordering': ['first_name'], }, ), migrations.CreateModel( - name="Contact", + name='HaztrakOrg', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("first_name", models.CharField(blank=True, max_length=38, null=True)), - ("middle_initial", models.CharField(blank=True, max_length=1, null=True)), - ("last_name", models.CharField(blank=True, max_length=38, null=True)), - ("email", models.EmailField(blank=True, max_length=254, null=True)), - ("company_name", models.CharField(blank=True, max_length=80, null=True)), + ('name', models.CharField(max_length=200, unique=True)), + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('admin', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), ], options={ - "ordering": ["first_name"], + 'verbose_name': 'Organization', + 'verbose_name_plural': 'Organizations', + 'ordering': ['name'], }, ), migrations.CreateModel( - name="RcraPhone", + name='HaztrakSite', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("number", apps.sites.models.contact_models.RcraPhoneNumber(max_length=12)), - ("extension", models.CharField(blank=True, max_length=6, null=True)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200, validators=[django.core.validators.MinLengthValidator(2, 'site aliases must be longer than 2 characters')], verbose_name='site alias')), + ('last_rcrainfo_manifest_sync', models.DateTimeField(blank=True, null=True, verbose_name='last RCRAInfo manifest sync date')), + ('org', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.haztrakorg')), ], options={ - "ordering": ["number"], + 'verbose_name': 'Haztrak Site', + 'verbose_name_plural': 'Haztrak Sites', + 'ordering': ['rcra_site__epa_id'], }, ), migrations.CreateModel( - name="RcraSite", + name='RcraPhone', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ( - "site_type", - models.CharField( - blank=True, - choices=[ - ("Tsdf", "Tsdf"), - ("Generator", "Generator"), - ("Transporter", "Transporter"), - ("Broker", "Broker"), - ], - max_length=20, - null=True, - ), - ), - ( - "epa_id", - models.CharField(max_length=25, unique=True, verbose_name="EPA ID number"), - ), - ("name", models.CharField(max_length=200)), - ("modified", models.BooleanField(blank=True, null=True)), - ("registered", models.BooleanField(blank=True, null=True)), - ( - "gis_primary", - models.BooleanField( - blank=True, default=False, null=True, verbose_name="GIS primary" - ), - ), - ( - "can_esign", - models.BooleanField( - blank=True, null=True, verbose_name="can electronically sign" - ), - ), - ( - "limited_esign", - models.BooleanField( - blank=True, null=True, verbose_name="limited electronic signing ability" - ), - ), - ( - "registered_emanifest_user", - models.BooleanField( - blank=True, - default=False, - null=True, - verbose_name="has registered e-manifest user", - ), - ), - ( - "contact", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sites.contact", - verbose_name="contact information", - ), - ), - ( - "emergency_phone", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sites.rcraphone", - ), - ), - ( - "mail_address", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="mail_address", - to="sites.address", - ), - ), - ( - "site_address", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="site_address", - to="sites.address", - ), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('number', apps.sites.models.contact_models.RcraPhoneNumber(max_length=12)), + ('extension', models.CharField(blank=True, max_length=6, null=True)), ], options={ - "ordering": ["epa_id"], + 'ordering': ['number'], }, ), migrations.CreateModel( - name="Site", + name='RcraSite', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ( - "name", - models.CharField( - max_length=200, - validators=[ - django.core.validators.MinValueValidator( - 2, "site aliases must be longer than 2 characters" - ) - ], - verbose_name="site alias", - ), - ), - ( - "last_rcra_sync", - models.DateTimeField( - blank=True, null=True, verbose_name="last sync with RCRAInfo" - ), - ), - ( - "rcra_site", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="sites.rcrasite", - verbose_name="rcra_site", - ), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('site_type', models.CharField(blank=True, choices=[('Generator', 'Generator'), ('Transporter', 'Transporter'), ('Tsdf', 'Tsdf'), ('Broker', 'Broker')], max_length=20, null=True)), + ('epa_id', models.CharField(max_length=25, unique=True, verbose_name='EPA ID number')), + ('name', models.CharField(max_length=200)), + ('modified', models.BooleanField(blank=True, null=True)), + ('registered', models.BooleanField(blank=True, null=True)), + ('gis_primary', models.BooleanField(blank=True, default=False, null=True, verbose_name='GIS primary')), + ('can_esign', models.BooleanField(blank=True, null=True, verbose_name='can electronically sign')), + ('limited_esign', models.BooleanField(blank=True, null=True, verbose_name='limited electronic signing ability')), + ('registered_emanifest_user', models.BooleanField(blank=True, default=False, null=True, verbose_name='has registered e-manifest user')), + ('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.contact', verbose_name='contact information')), + ('emergency_phone', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sites.rcraphone')), + ('mail_address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='mail_address', to='sites.address')), + ('site_address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='site_address', to='sites.address')), ], options={ - "verbose_name": "Haztrak Site", - "verbose_name_plural": "Haztrak Sites", - "ordering": ["rcra_site__epa_id"], + 'verbose_name': 'RCRAInfo Site', + 'verbose_name_plural': 'RCRAInfo Sites', + 'ordering': ['epa_id'], }, ), migrations.CreateModel( - name="RcraSitePermission", + name='SitePermissions', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("site_manager", models.BooleanField(default=False)), - ( - "annual_report", - models.CharField( - choices=[ - ("Certifier", "Certifier"), - ("Preparer", "Preparer"), - ("Viewer", "Viewer"), - ], - max_length=12, - ), - ), - ( - "biennial_report", - models.CharField( - choices=[ - ("Certifier", "Certifier"), - ("Preparer", "Preparer"), - ("Viewer", "Viewer"), - ], - max_length=12, - ), - ), - ( - "e_manifest", - models.CharField( - choices=[ - ("Certifier", "Certifier"), - ("Preparer", "Preparer"), - ("Viewer", "Viewer"), - ], - max_length=12, - ), - ), - ( - "my_rcra_id", - models.CharField( - choices=[ - ("Certifier", "Certifier"), - ("Preparer", "Preparer"), - ("Viewer", "Viewer"), - ], - max_length=12, - ), - ), - ( - "wiets", - models.CharField( - choices=[ - ("Certifier", "Certifier"), - ("Preparer", "Preparer"), - ("Viewer", "Viewer"), - ], - max_length=12, - ), - ), - ( - "profile", - models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - related_name="permissions", - to="core.rcraprofile", - ), - ), - ( - "site", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sites.site" - ), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('emanifest', models.CharField(choices=[('viewer', 'view'), ('editor', 'edit'), ('signer', 'sign')], default='view', max_length=6)), + ('profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='site_permissions', to='core.haztrakprofile')), + ('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.haztraksite')), ], options={ - "verbose_name": "RCRA Site Permission", - "ordering": ["site__rcra_site__epa_id"], + 'verbose_name': 'Site Permission', + 'verbose_name_plural': 'Site Permissions', + 'ordering': ['profile'], }, ), + migrations.CreateModel( + name='RcraSitePermissions', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('site_manager', models.BooleanField(default=False)), + ('annual_report', models.CharField(choices=[('Certifier', 'Certifier'), ('Preparer', 'Preparer'), ('Viewer', 'Viewer')], max_length=12)), + ('biennial_report', models.CharField(choices=[('Certifier', 'Certifier'), ('Preparer', 'Preparer'), ('Viewer', 'Viewer')], max_length=12)), + ('e_manifest', models.CharField(choices=[('Certifier', 'Certifier'), ('Preparer', 'Preparer'), ('Viewer', 'Viewer')], max_length=12)), + ('my_rcra_id', models.CharField(choices=[('Certifier', 'Certifier'), ('Preparer', 'Preparer'), ('Viewer', 'Viewer')], max_length=12)), + ('wiets', models.CharField(choices=[('Certifier', 'Certifier'), ('Preparer', 'Preparer'), ('Viewer', 'Viewer')], max_length=12)), + ('profile', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='permissions', to='core.rcraprofile')), + ('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.rcrasite')), + ], + options={ + 'verbose_name': 'RCRAInfo Permission', + 'verbose_name_plural': 'RCRAInfo Permissions', + 'ordering': ['site__epa_id'], + }, + ), + migrations.AddField( + model_name='haztraksite', + name='rcra_site', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='sites.rcrasite', verbose_name='rcra_site'), + ), migrations.AddField( - model_name="contact", - name="phone", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sites.rcraphone", - ), + model_name='contact', + name='phone', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sites.rcraphone'), ), ] diff --git a/server/apps/sites/migrations/0002_haztraksite_sitepermissions_and_more.py b/server/apps/sites/migrations/0002_haztraksite_sitepermissions_and_more.py deleted file mode 100644 index 9aa65e5b5..000000000 --- a/server/apps/sites/migrations/0002_haztraksite_sitepermissions_and_more.py +++ /dev/null @@ -1,135 +0,0 @@ -# Generated by Django 4.2.7 on 2023-11-08 23:01 - -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("core", "0002_haztrakprofile"), - ("sites", "0001_initial"), - ] - - operations = [ - migrations.CreateModel( - name="HaztrakSite", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "name", - models.CharField( - max_length=200, - validators=[ - django.core.validators.MinValueValidator( - 2, "site aliases must be longer than 2 characters" - ) - ], - verbose_name="site alias", - ), - ), - ( - "last_rcrainfo_manifest_sync", - models.DateTimeField( - blank=True, - null=True, - verbose_name="last RCRAInfo manifest sync date", - ), - ), - ( - "admin_rcrainfo_profile", - models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="core.rcraprofile", - ), - ), - ( - "rcra_site", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="sites.rcrasite", - verbose_name="rcra_site", - ), - ), - ], - options={ - "verbose_name": "Haztrak Site", - "verbose_name_plural": "Haztrak Sites", - "ordering": ["rcra_site__epa_id"], - }, - ), - migrations.CreateModel( - name="SitePermissions", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "emanifest", - models.CharField( - choices=[ - ("viewer", "view"), - ("editor", "edit"), - ("signer", "sign"), - ], - default="view", - max_length=6, - ), - ), - ( - "profile", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="site_permissions", - to="core.haztrakprofile", - ), - ), - ( - "site", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sites.haztraksite", - ), - ), - ], - options={ - "verbose_name": "Site Permissions", - }, - ), - migrations.RenameModel( - old_name="RcraSitePermission", - new_name="RcraSitePermissions", - ), - migrations.AlterModelOptions( - name="rcrasitepermissions", - options={ - "ordering": ["site__epa_id"], - "verbose_name": "RCRA Site Permission", - }, - ), - migrations.AlterField( - model_name="rcrasitepermissions", - name="site", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sites.rcrasite" - ), - ), - migrations.DeleteModel( - name="Site", - ), - ] diff --git a/server/apps/sites/migrations/0003_alter_haztraksite_admin_rcrainfo_profile_and_more.py b/server/apps/sites/migrations/0003_alter_haztraksite_admin_rcrainfo_profile_and_more.py deleted file mode 100644 index 5df328f08..000000000 --- a/server/apps/sites/migrations/0003_alter_haztraksite_admin_rcrainfo_profile_and_more.py +++ /dev/null @@ -1,26 +0,0 @@ -# Generated by Django 4.2.7 on 2023-11-09 14:33 - -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0002_haztrakprofile'), - ('sites', '0002_haztraksite_sitepermissions_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='haztraksite', - name='admin_rcrainfo_profile', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.rcraprofile', verbose_name='Admin'), - ), - migrations.AlterField( - model_name='haztraksite', - name='name', - field=models.CharField(max_length=200, validators=[django.core.validators.MinLengthValidator(2, 'site aliases must be longer than 2 characters')], verbose_name='site alias'), - ), - ] diff --git a/server/apps/sites/migrations/0004_alter_rcrasite_options_and_more.py b/server/apps/sites/migrations/0004_alter_rcrasite_options_and_more.py deleted file mode 100644 index 6c6607995..000000000 --- a/server/apps/sites/migrations/0004_alter_rcrasite_options_and_more.py +++ /dev/null @@ -1,57 +0,0 @@ -# Generated by Django 4.2.7 on 2023-11-16 01:31 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion -import uuid - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('sites', '0003_alter_haztraksite_admin_rcrainfo_profile_and_more'), - ] - - operations = [ - migrations.AlterModelOptions( - name='rcrasite', - options={'ordering': ['epa_id'], 'verbose_name': 'RCRAInfo Site', 'verbose_name_plural': 'RCRAInfo Sites'}, - ), - migrations.AlterModelOptions( - name='rcrasitepermissions', - options={'ordering': ['site__epa_id'], 'verbose_name': 'RCRAInfo Permission', 'verbose_name_plural': 'RCRAInfo Permissions'}, - ), - migrations.AlterModelOptions( - name='sitepermissions', - options={'ordering': ['profile'], 'verbose_name': 'Site Permission', 'verbose_name_plural': 'Site Permissions'}, - ), - migrations.RemoveField( - model_name='haztraksite', - name='admin_rcrainfo_profile', - ), - migrations.AlterField( - model_name='rcrasite', - name='site_type', - field=models.CharField(blank=True, choices=[('Generator', 'Generator'), ('Transporter', 'Transporter'), ('Tsdf', 'Tsdf'), ('Broker', 'Broker')], max_length=20, null=True), - ), - migrations.CreateModel( - name='HaztrakOrg', - fields=[ - ('name', models.CharField(max_length=200, unique=True)), - ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), - ('admin', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ], - options={ - 'verbose_name': 'Organization', - 'verbose_name_plural': 'Organizations', - 'ordering': ['name'], - }, - ), - migrations.AddField( - model_name='haztraksite', - name='org', - field=models.ForeignKey(default='efb9e104-7f61-4365-a9af-9d7b55c854c4', on_delete=django.db.models.deletion.CASCADE, to='sites.haztrakorg'), - preserve_default=False, - ), - ] diff --git a/server/apps/sites/services/__init__.py b/server/apps/sites/services/__init__.py index 9b4fa8740..1aa83d722 100644 --- a/server/apps/sites/services/__init__.py +++ b/server/apps/sites/services/__init__.py @@ -1,3 +1,4 @@ +from .org_services import get_org_sites from .rcra_profile_services import RcraProfileService from .rcra_site_services import RcraSiteService from .site_services import HaztrakSiteService diff --git a/server/apps/sites/services/org_services.py b/server/apps/sites/services/org_services.py index 921e11591..ac5d9fb55 100644 --- a/server/apps/sites/services/org_services.py +++ b/server/apps/sites/services/org_services.py @@ -1,4 +1,6 @@ -from apps.sites.models.site_models import HaztrakOrg +from django.db.models import QuerySet + +from apps.sites.models.site_models import HaztrakOrg, HaztrakSite def get_org(org_id: str) -> HaztrakOrg: @@ -24,3 +26,13 @@ def get_rcrainfo_api_credentials_by_user(user_id: str) -> tuple[str, str] | None return org.rcrainfo_api_id_key except HaztrakOrg.DoesNotExist: return None + + +def get_org_sites(org_id: str) -> [HaztrakSite]: + """Returns a tuple of (rcrainfo_api_id, rcrainfo_api_key) corresponding to the user's org""" + try: + sites: QuerySet = HaztrakSite.objects.filter(org_id=org_id) + sites.select_related("rcra_site") + return sites + except HaztrakSite.DoesNotExist: + return None diff --git a/server/apps/sites/tests/test_site_views.py b/server/apps/sites/tests/test_site_views.py index 5db9fe7fe..d0c55355d 100644 --- a/server/apps/sites/tests/test_site_views.py +++ b/server/apps/sites/tests/test_site_views.py @@ -1,7 +1,4 @@ -from typing import Optional - import pytest -from django.contrib.auth.models import User from rest_framework import status from rest_framework.test import APIClient, APIRequestFactory, force_authenticate @@ -123,3 +120,28 @@ def test_returns_formatted_http_response( # Assert assert response.headers["Content-Type"] == "application/json" assert response.status_code == status.HTTP_200_OK + + +class TestHaztrakOrgSitesListView: + URL = "/api/org" + + def test_returns_list_of_organizations_sites( + self, + user_factory, + haztrak_site_factory, + haztrak_profile_factory, + haztrak_site_permission_factory, + haztrak_org_factory, + ): + # Arrange + user = user_factory() + org = haztrak_org_factory() + haztrak_site_factory(org=org) + client = APIClient() + client.force_authenticate(user=user) + # Act + response = client.get(f"{self.URL}/{org.id}/site") + # Assert + assert response.headers["Content-Type"] == "application/json" + assert response.status_code == status.HTTP_200_OK + assert len(response.data) == 1 diff --git a/server/apps/sites/urls.py b/server/apps/sites/urls.py index e136e473b..ea5b7eca2 100644 --- a/server/apps/sites/urls.py +++ b/server/apps/sites/urls.py @@ -2,10 +2,11 @@ from apps.sites.views import ( # type: ignore HandlerSearchView, + HaztrakOrgSitesListView, + HaztrakSiteListView, RcraSiteSearchView, RcraSiteView, SiteDetailView, - SiteListView, ) urlpatterns = [ @@ -19,7 +20,8 @@ ), ), # Site - path("site", SiteListView.as_view()), + path("site", HaztrakSiteListView.as_view()), path("site/search", RcraSiteSearchView.as_view()), path("site/", SiteDetailView.as_view()), + path("org//site", HaztrakOrgSitesListView.as_view()), ] diff --git a/server/apps/sites/views.py b/server/apps/sites/views.py index a0da30c86..53f5c02c1 100644 --- a/server/apps/sites/views.py +++ b/server/apps/sites/views.py @@ -11,17 +11,14 @@ from apps.sites.models import HaztrakSite, RcraSite, RcraSiteType # type: ignore from apps.sites.serializers import HaztrakSiteSerializer, RcraSiteSerializer # type: ignore -from apps.sites.services import RcraSiteService # type: ignore +from apps.sites.services import RcraSiteService, get_org_sites # type: ignore from apps.sites.services.rcra_site_services import query_rcra_sites logger = logging.getLogger(__name__) -class SiteListView(ListAPIView): - """ - SiteListView is a ListAPIView that returns haztrak sites that the current - user has access to. - """ +class HaztrakSiteListView(ListAPIView): + """that returns haztrak sites that the current user has access to.""" serializer_class = HaztrakSiteSerializer @@ -56,6 +53,16 @@ def get_queryset(self): return queryset +class HaztrakOrgSitesListView(APIView): + """Retrieve a list of sites for a given HaztrakOrg""" + + @method_decorator(cache_page(60 * 15)) + def get(self, request, *args, **kwargs): + haztrak_sites = get_org_sites(self.kwargs["org_id"]) + serializer = HaztrakSiteSerializer(haztrak_sites, many=True) + return Response(data=serializer.data, status=status.HTTP_200_OK) + + @extend_schema( description="Retrieve details on a rcra_site stored in the Haztrak database", ) diff --git a/server/apps/trak/migrations/0001_initial.py b/server/apps/trak/migrations/0001_initial.py index ce6cc4d69..6593568b9 100644 --- a/server/apps/trak/migrations/0001_initial.py +++ b/server/apps/trak/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.1 on 2023-06-12 18:32 +# Generated by Django 4.2.7 on 2023-11-20 16:47 import apps.trak.models.contact_models import apps.trak.models.manifest_models @@ -7,652 +7,249 @@ class Migration(migrations.Migration): + initial = True dependencies = [ - ("sites", "0001_initial"), + ('sites', '0001_initial'), ] operations = [ migrations.CreateModel( - name="AdditionalInfo", + name='AdditionalInfo', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('original_mtn', models.JSONField(blank=True, help_text='Original manifest tracking number of rejected manifestRegex expression validation: [0-9]{9}[A-Z]{3}', null=True, validators=[apps.trak.models.manifest_models.validate_mtn])), + ('new_destination', models.CharField(blank=True, choices=[('GEN', 'Generator'), ('TSD', 'Tsdf')], help_text='Destination of the new manifest created during rejection or residue.', max_length=255, null=True)), + ('consent_number', models.CharField(blank=True, max_length=12, null=True)), + ('comments', models.JSONField(blank=True, null=True)), + ('handling_instructions', models.CharField(blank=True, help_text='Special Handling Instructions', max_length=4000, null=True)), + ], + options={ + 'verbose_name': 'Additional Info', + 'verbose_name_plural': 'Additional Info', + }, + ), + migrations.CreateModel( + name='DotLookup', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ( - "original_mtn", - models.JSONField( - blank=True, - help_text="Original manifest tracking number of rejected manifestRegex expression validation: [0-9]{9}[A-Z]{3}", - null=True, - validators=[apps.trak.models.manifest_models.validate_mtn], - ), - ), - ( - "new_destination", - models.CharField( - blank=True, - choices=[("GEN", "Generator"), ("TSD", "Tsdf")], - help_text="Destination of the new manifest created during rejection or residue.", - max_length=255, - null=True, - ), - ), - ("consent_number", models.CharField(blank=True, max_length=12, null=True)), - ("comments", models.JSONField(blank=True, null=True)), - ( - "handling_instructions", - models.CharField( - blank=True, - help_text="Special Handling Instructions", - max_length=4000, - null=True, - ), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('value', models.CharField(max_length=255)), + ('value_type', models.CharField(choices=[('ID', 'Id'), ('GROUP', 'Group'), ('NAME', 'Name'), ('CLASS', 'Class')], max_length=5)), ], options={ - "verbose_name": "Additional Info", - "verbose_name_plural": "Additional Info", + 'verbose_name': 'DOT lookup', + 'verbose_name_plural': 'DOT lookups', + 'ordering': ['value_type', 'value'], }, ), migrations.CreateModel( - name="Handler", + name='Handler', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], options={ - "ordering": ["rcra_site"], + 'ordering': ['rcra_site'], }, ), migrations.CreateModel( - name="Manifest", + name='Manifest', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("created_date", models.DateTimeField(auto_now=True, null=True)), - ("update_date", models.DateTimeField(auto_now=True)), - ( - "mtn", - models.CharField( - default=apps.trak.models.manifest_models.draft_mtn, - max_length=30, - unique=True, - validators=[apps.trak.models.manifest_models.validate_mtn], - verbose_name="manifest Tracking Number", - ), - ), - ( - "status", - models.CharField( - choices=[ - ("NotAssigned", "Not Assigned"), - ("Pending", "Pending"), - ("Scheduled", "Scheduled"), - ("InTransit", "In Transit"), - ("ReadyForSignature", "Ready for Signature"), - ("Signed", "Signed"), - ("Corrected", "Corrected"), - ("UnderCorrection", "Under Correction"), - ("MtnValidationFailed", "MTN Validation Failed"), - ], - default="NotAssigned", - max_length=25, - ), - ), - ( - "submission_type", - models.CharField( - choices=[ - ("FullElectronic", "Full Electronic"), - ("DataImage5Copy", "Data + Image"), - ("Hybrid", "Hybrid"), - ("Image", "Image"), - ], - default="FullElectronic", - max_length=25, - ), - ), - ("signature_status", models.BooleanField(blank=True, null=True)), - ( - "origin_type", - models.CharField( - choices=[("Web", "Web"), ("Service", "Service"), ("Mail", "Mail")], - default="Service", - max_length=25, - ), - ), - ("shipped_date", models.DateTimeField(blank=True, null=True)), - ( - "potential_ship_date", - models.DateTimeField( - blank=True, null=True, verbose_name="potential ship date" - ), - ), - ("received_date", models.DateTimeField(blank=True, null=True)), - ("certified_date", models.DateTimeField(blank=True, null=True)), - ("certified_by", models.JSONField(blank=True, null=True)), - ("broker", models.JSONField(blank=True, null=True)), - ("rejection", models.BooleanField(blank=True, default=False)), - ( - "rejection_info", - models.JSONField(blank=True, null=True, verbose_name="Rejection Information"), - ), - ("discrepancy", models.BooleanField(blank=True, default=False)), - ("residue", models.BooleanField(blank=True, default=False)), - ( - "residue_new_mtn", - models.JSONField(blank=True, default=list, verbose_name="residue new MTN"), - ), - ( - "import_flag", - models.BooleanField(blank=True, default=False, verbose_name="import"), - ), - ( - "import_info", - models.JSONField(blank=True, null=True, verbose_name="import information"), - ), - ( - "contains_residue_or_rejection", - models.BooleanField( - blank=True, - null=True, - verbose_name="contains previous rejection or residue waste", - ), - ), - ("printed_document", models.JSONField(blank=True, null=True)), - ("form_document", models.JSONField(blank=True, null=True)), - ("correction_info", models.JSONField(blank=True, null=True)), - ("ppc_status", models.JSONField(blank=True, null=True, verbose_name="PPC info")), - ("locked", models.BooleanField(blank=True, null=True)), - ( - "lock_reason", - models.CharField( - blank=True, - choices=[ - ("ACS", "AsyncSign"), - ("ECB", "EpaChangeBiller"), - ("EPC", "EpaCorrection"), - ], - max_length=25, - null=True, - ), - ), - ("transfer_requested", models.BooleanField(blank=True, null=True)), - ("transfer_status", models.CharField(blank=True, max_length=200, null=True)), - ( - "original_sub_type", - models.CharField( - blank=True, - choices=[ - ("FullElectronic", "Full Electronic"), - ("DataImage5Copy", "Data + Image"), - ("Hybrid", "Hybrid"), - ("Image", "Image"), - ], - max_length=25, - null=True, - verbose_name="original submission type", - ), - ), - ("transfer_count", models.IntegerField(blank=True, null=True)), - ( - "next_transfer_time", - models.DateTimeField(blank=True, null=True, verbose_name="next transfer time"), - ), - ( - "additional_info", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="trak.additionalinfo", - ), - ), - ( - "generator", - models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - related_name="generator", - to="trak.handler", - ), - ), - ( - "tsdf", - models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - related_name="designated_facility", - to="trak.handler", - verbose_name="designated facility", - ), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_date', models.DateTimeField(auto_now=True, null=True)), + ('update_date', models.DateTimeField(auto_now=True)), + ('mtn', models.CharField(default=apps.trak.models.manifest_models.draft_mtn, max_length=30, unique=True, validators=[apps.trak.models.manifest_models.validate_mtn], verbose_name='manifest Tracking Number')), + ('status', models.CharField(choices=[('NotAssigned', 'Not Assigned'), ('Pending', 'Pending'), ('Scheduled', 'Scheduled'), ('InTransit', 'In Transit'), ('ReadyForSignature', 'Ready for Signature'), ('Signed', 'Signed'), ('Corrected', 'Corrected'), ('UnderCorrection', 'Under Correction'), ('MtnValidationFailed', 'MTN Validation Failed')], default='NotAssigned', max_length=25)), + ('submission_type', models.CharField(choices=[('FullElectronic', 'Full Electronic'), ('DataImage5Copy', 'Data + Image'), ('Hybrid', 'Hybrid'), ('Image', 'Image')], default='FullElectronic', max_length=25)), + ('signature_status', models.BooleanField(blank=True, null=True)), + ('origin_type', models.CharField(choices=[('Web', 'Web'), ('Service', 'Service'), ('Mail', 'Mail')], default='Service', max_length=25)), + ('shipped_date', models.DateTimeField(blank=True, null=True)), + ('potential_ship_date', models.DateTimeField(blank=True, null=True, verbose_name='potential ship date')), + ('received_date', models.DateTimeField(blank=True, null=True)), + ('certified_date', models.DateTimeField(blank=True, null=True)), + ('certified_by', models.JSONField(blank=True, null=True)), + ('broker', models.JSONField(blank=True, null=True)), + ('rejection', models.BooleanField(blank=True, null=True)), + ('rejection_info', models.JSONField(blank=True, null=True, verbose_name='Rejection Information')), + ('discrepancy', models.BooleanField(blank=True, default=False)), + ('residue', models.BooleanField(blank=True, default=False)), + ('residue_new_mtn', models.JSONField(blank=True, default=list, verbose_name='residue new MTN')), + ('import_flag', models.BooleanField(blank=True, default=False, verbose_name='import')), + ('import_info', models.JSONField(blank=True, null=True, verbose_name='import information')), + ('contains_residue_or_rejection', models.BooleanField(blank=True, null=True, verbose_name='contains previous rejection or residue waste')), + ('printed_document', models.JSONField(blank=True, null=True)), + ('form_document', models.JSONField(blank=True, null=True)), + ('correction_info', models.JSONField(blank=True, null=True)), + ('ppc_status', models.JSONField(blank=True, null=True, verbose_name='PPC info')), + ('locked', models.BooleanField(blank=True, null=True)), + ('lock_reason', models.CharField(blank=True, choices=[('ACS', 'AsyncSign'), ('ECB', 'EpaChangeBiller'), ('EPC', 'EpaCorrection')], max_length=25, null=True)), + ('transfer_requested', models.BooleanField(blank=True, null=True)), + ('transfer_status', models.CharField(blank=True, max_length=200, null=True)), + ('original_sub_type', models.CharField(blank=True, choices=[('FullElectronic', 'Full Electronic'), ('DataImage5Copy', 'Data + Image'), ('Hybrid', 'Hybrid'), ('Image', 'Image')], max_length=25, null=True, verbose_name='original submission type')), + ('transfer_count', models.IntegerField(blank=True, null=True)), + ('next_transfer_time', models.DateTimeField(blank=True, null=True, verbose_name='next transfer time')), + ('additional_info', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='trak.additionalinfo')), + ('generator', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='generator', to='trak.handler')), + ('tsdf', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='designated_facility', to='trak.handler', verbose_name='designated facility')), ], options={ - "ordering": ["update_date", "mtn"], + 'ordering': ['update_date', 'mtn'], }, ), migrations.CreateModel( - name="ManifestPhone", + name='ManifestPhone', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("number", apps.trak.models.contact_models.ManifestPhoneNumber(max_length=12)), - ("extension", models.CharField(blank=True, max_length=6, null=True)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('number', apps.trak.models.contact_models.ManifestPhoneNumber(max_length=12)), + ('extension', models.CharField(blank=True, max_length=6, null=True)), ], options={ - "ordering": ["number"], + 'ordering': ['number'], }, ), migrations.CreateModel( - name="PaperSignature", + name='PaperSignature', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("printed_name", models.CharField(max_length=255)), - ("sign_date", models.DateTimeField()), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('printed_name', models.CharField(max_length=255)), + ('sign_date', models.DateTimeField()), ], options={ - "ordering": ["pk"], - "abstract": False, + 'ordering': ['pk'], + 'abstract': False, }, ), migrations.CreateModel( - name="PortOfEntry", + name='PortOfEntry', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ( - "state", - models.CharField( - blank=True, - choices=[ - ("AK", "Alaska"), - ("AL", "Alabama"), - ("AP", "Armed Forces Pacific"), - ("AR", "Arkansas"), - ("AZ", "Arizona"), - ("CA", "California"), - ("CO", "Colorado"), - ("CT", "Connecticut"), - ("DC", "Washington DC"), - ("DE", "Delaware"), - ("FL", "Florida"), - ("GA", "Georgia"), - ("GU", "Guam"), - ("HI", "Hawaii"), - ("IA", "Iowa"), - ("ID", "Idaho"), - ("IL", "Illinois"), - ("IN", "Indiana"), - ("KS", "Kansas"), - ("KY", "Kentucky"), - ("LA", "Louisiana"), - ("MA", "Massachusetts"), - ("MD", "Maryland"), - ("ME", "Maine"), - ("MI", "Michigan"), - ("MN", "Minnesota"), - ("MO", "Missouri"), - ("MS", "Mississippi"), - ("MT", "Montana"), - ("NC", "North Carolina"), - ("ND", "North Dakota"), - ("NE", "Nebraska"), - ("NH", "New Hampshire"), - ("NJ", "New Jersey"), - ("NM", "New Mexico"), - ("NV", "Nevada"), - ("NY", "New York"), - ("OH", "Ohio"), - ("OK", "Oklahoma"), - ("OR", "Oregon"), - ("PA", "Pennsylvania"), - ("PR", "Puerto Rico"), - ("RI", "Rhode Island"), - ("SC", "South Carolina"), - ("SD", "South Dakota"), - ("TN", "Tennessee"), - ("TX", "Texas"), - ("UT", "Utah"), - ("VA", "Virginia"), - ("VI", "Virgin Islands"), - ("VT", "Vermont"), - ("WA", "Washington"), - ("WI", "Wisconsin"), - ("WV", "West Virginia"), - ("WY", "Wyoming"), - ("XA", "REGION 01 PURVIEW"), - ("XB", "REGION 02 PURVIEW"), - ("XC", "REGION 03 PURVIEW"), - ("XD", "REGION 04 PURVIEW"), - ("XE", "REGION 05 PURVIEW"), - ("XF", "REGION 06 PURVIEW"), - ("XG", "REGION 07 PURVIEW"), - ("XH", "REGION 08 PURVIEW"), - ("XI", "REGION 09 PURVIEW"), - ("XJ", "REGION 10 PURVIEW"), - ], - max_length=2, - null=True, - ), - ), - ("city_port", models.CharField(blank=True, max_length=100, null=True)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('state', models.CharField(blank=True, choices=[('AK', 'Alaska'), ('AL', 'Alabama'), ('AP', 'Armed Forces Pacific'), ('AR', 'Arkansas'), ('AZ', 'Arizona'), ('CA', 'California'), ('CO', 'Colorado'), ('CT', 'Connecticut'), ('DC', 'Washington DC'), ('DE', 'Delaware'), ('FL', 'Florida'), ('GA', 'Georgia'), ('GU', 'Guam'), ('HI', 'Hawaii'), ('IA', 'Iowa'), ('ID', 'Idaho'), ('IL', 'Illinois'), ('IN', 'Indiana'), ('KS', 'Kansas'), ('KY', 'Kentucky'), ('LA', 'Louisiana'), ('MA', 'Massachusetts'), ('MD', 'Maryland'), ('ME', 'Maine'), ('MI', 'Michigan'), ('MN', 'Minnesota'), ('MO', 'Missouri'), ('MS', 'Mississippi'), ('MT', 'Montana'), ('NC', 'North Carolina'), ('ND', 'North Dakota'), ('NE', 'Nebraska'), ('NH', 'New Hampshire'), ('NJ', 'New Jersey'), ('NM', 'New Mexico'), ('NV', 'Nevada'), ('NY', 'New York'), ('OH', 'Ohio'), ('OK', 'Oklahoma'), ('OR', 'Oregon'), ('PA', 'Pennsylvania'), ('PR', 'Puerto Rico'), ('RI', 'Rhode Island'), ('SC', 'South Carolina'), ('SD', 'South Dakota'), ('TN', 'Tennessee'), ('TX', 'Texas'), ('UT', 'Utah'), ('VA', 'Virginia'), ('VI', 'Virgin Islands'), ('VT', 'Vermont'), ('WA', 'Washington'), ('WI', 'Wisconsin'), ('WV', 'West Virginia'), ('WY', 'Wyoming'), ('XA', 'REGION 01 PURVIEW'), ('XB', 'REGION 02 PURVIEW'), ('XC', 'REGION 03 PURVIEW'), ('XD', 'REGION 04 PURVIEW'), ('XE', 'REGION 05 PURVIEW'), ('XF', 'REGION 06 PURVIEW'), ('XG', 'REGION 07 PURVIEW'), ('XH', 'REGION 08 PURVIEW'), ('XI', 'REGION 09 PURVIEW'), ('XJ', 'REGION 10 PURVIEW')], max_length=2, null=True)), + ('city_port', models.CharField(blank=True, max_length=100, null=True)), ], options={ - "verbose_name": "Port of Entry", - "verbose_name_plural": "Ports of Entry", + 'verbose_name': 'Port of Entry', + 'verbose_name_plural': 'Ports of Entry', }, ), migrations.CreateModel( - name="WasteCode", + name='WasteCode', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("description", models.TextField(blank=True, null=True)), - ("code", models.CharField(max_length=6, unique=True)), - ( - "code_type", - models.CharField(choices=[("ST", "State"), ("FD", "Federal")], max_length=2), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.CharField(max_length=6, unique=True)), + ('description', models.TextField(blank=True, null=True)), + ('code_type', models.CharField(choices=[('ST', 'State'), ('FD', 'Federal')], max_length=2)), + ('state_id', models.CharField(blank=True, choices=[('AK', 'Alaska'), ('AL', 'Alabama'), ('AP', 'Armed Forces Pacific'), ('AR', 'Arkansas'), ('AZ', 'Arizona'), ('CA', 'California'), ('CO', 'Colorado'), ('CT', 'Connecticut'), ('DC', 'District of Columbia'), ('DE', 'Delaware'), ('FL', 'Florida'), ('GA', 'Georgia'), ('GU', 'Guam'), ('HI', 'Hawaii'), ('IA', 'Iowa'), ('ID', 'Idaho'), ('IL', 'Illinois'), ('IN', 'Indiana'), ('KS', 'Kansas'), ('KY', 'Kentucky'), ('LA', 'Louisiana'), ('MA', 'Massachusetts'), ('MD', 'Maryland'), ('ME', 'Maine'), ('MI', 'Michigan'), ('MN', 'Minnesota'), ('MO', 'Missouri'), ('MS', 'Mississippi'), ('MT', 'Montana'), ('NC', 'North Carolina'), ('ND', 'North Dakota'), ('NE', 'Nebraska'), ('NH', 'New Hampshire'), ('NJ', 'New Jersey'), ('NM', 'New Mexico'), ('NV', 'Nevada'), ('NY', 'New York'), ('OH', 'Ohio'), ('OK', 'Oklahoma'), ('OR', 'Oregon'), ('PA', 'Pennsylvania'), ('PR', 'Puerto Rico'), ('RI', 'Rhode Island'), ('SC', 'South Carolina'), ('SD', 'South Dakota'), ('TN', 'Tennessee'), ('TX', 'Texas'), ('UT', 'Utah'), ('VA', 'Virginia'), ('VI', 'Virgin Islands'), ('VT', 'Vermont'), ('WA', 'Washington'), ('WI', 'Wisconsin'), ('WV', 'West Virginia'), ('WY', 'Wyoming')], max_length=3, null=True)), ], options={ - "ordering": ["code"], + 'ordering': ['code'], }, ), migrations.CreateModel( - name="WasteLine", + name='WasteLine', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("dot_hazardous", models.BooleanField(verbose_name="DOT hazardous")), - ( - "dot_info", - models.JSONField(blank=True, null=True, verbose_name="DOT information"), - ), - ("quantity", models.JSONField(blank=True, null=True)), - ("hazardous_waste", models.JSONField(blank=True, null=True)), - ("line_number", models.PositiveIntegerField(verbose_name="waste line number")), - ("br", models.BooleanField(verbose_name="BR info provided")), - ( - "br_info", - models.JSONField(blank=True, null=True, verbose_name="BR information"), - ), - ( - "management_method", - models.JSONField(blank=True, null=True, verbose_name="management method code"), - ), - ("pcb", models.BooleanField(verbose_name="contains PCBs")), - ( - "pcb_infos", - models.JSONField(blank=True, null=True, verbose_name="PCB information"), - ), - ( - "discrepancy_info", - models.JSONField( - blank=True, null=True, verbose_name="discrepancy-residue information" - ), - ), - ("epa_waste", models.BooleanField(verbose_name="EPA waste")), - ("additional_info", models.JSONField(blank=True, null=True)), - ( - "manifest", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="wastes", - to="trak.manifest", - ), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('dot_hazardous', models.BooleanField(verbose_name='DOT hazardous')), + ('dot_info', models.JSONField(blank=True, null=True, verbose_name='DOT information')), + ('quantity', models.JSONField(blank=True, null=True)), + ('hazardous_waste', models.JSONField(blank=True, null=True)), + ('line_number', models.PositiveIntegerField(verbose_name='waste line number')), + ('br', models.BooleanField(verbose_name='BR info provided')), + ('br_info', models.JSONField(blank=True, null=True, verbose_name='BR information')), + ('management_method', models.JSONField(blank=True, null=True, verbose_name='management method code')), + ('pcb', models.BooleanField(verbose_name='contains PCBs')), + ('pcb_infos', models.JSONField(blank=True, null=True, verbose_name='PCB information')), + ('discrepancy_info', models.JSONField(blank=True, null=True, verbose_name='discrepancy-residue information')), + ('epa_waste', models.BooleanField(verbose_name='EPA waste')), + ('additional_info', models.JSONField(blank=True, null=True)), + ('manifest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wastes', to='trak.manifest')), ], options={ - "ordering": ["manifest__mtn", "line_number"], + 'ordering': ['manifest__mtn', 'line_number'], }, ), migrations.CreateModel( - name="Signer", + name='Signer', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("rcra_user_id", models.CharField(blank=True, max_length=100, null=True)), - ("first_name", models.CharField(blank=True, max_length=38, null=True)), - ("middle_initial", models.CharField(blank=True, max_length=1, null=True)), - ("last_name", models.CharField(blank=True, max_length=38, null=True)), - ("email", models.CharField(blank=True, max_length=38, null=True)), - ("company_name", models.CharField(blank=True, max_length=80, null=True)), - ( - "contact_type", - models.CharField( - blank=True, - choices=[("EM", "Email"), ("VO", "Voice"), ("TX", "Text")], - max_length=2, - null=True, - ), - ), - ( - "signer_role", - models.CharField( - choices=[ - ("IN", "Industry"), - ("PP", "Ppc"), - ("EP", "Epa"), - ("ST", "State"), - ], - max_length=10, - null=True, - ), - ), - ( - "phone", - models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="trak.manifestphone", - ), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('rcra_user_id', models.CharField(blank=True, max_length=100, null=True)), + ('first_name', models.CharField(blank=True, max_length=38, null=True)), + ('middle_initial', models.CharField(blank=True, max_length=1, null=True)), + ('last_name', models.CharField(blank=True, max_length=38, null=True)), + ('email', models.CharField(blank=True, max_length=38, null=True)), + ('company_name', models.CharField(blank=True, max_length=80, null=True)), + ('contact_type', models.CharField(blank=True, choices=[('email', 'Email'), ('voice', 'Voice'), ('text', 'Text')], max_length=5, null=True)), + ('signer_role', models.CharField(choices=[('Industry', 'Industry'), ('PPC', 'Ppc'), ('EPA', 'Epa'), ('State', 'State')], max_length=10, null=True)), + ('phone', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='trak.manifestphone')), ], options={ - "ordering": ["first_name"], + 'ordering': ['first_name'], }, ), migrations.CreateModel( - name="ImportInfo", + name='ImportInfo', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("import_generator", models.JSONField(blank=True, null=True)), - ( - "port_of_entry", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.PROTECT, - to="trak.portofentry", - ), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('import_generator', models.JSONField(blank=True, null=True)), + ('port_of_entry', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='trak.portofentry')), ], options={ - "verbose_name": "Import Info", - "verbose_name_plural": "Import Info", + 'verbose_name': 'Import Info', + 'verbose_name_plural': 'Import Info', }, ), migrations.AddField( - model_name="handler", - name="paper_signature", - field=models.OneToOneField( - blank=True, - help_text="The signature associated with hazardous waste custody exchange", - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="trak.papersignature", - ), + model_name='handler', + name='paper_signature', + field=models.OneToOneField(blank=True, help_text='The signature associated with hazardous waste custody exchange', null=True, on_delete=django.db.models.deletion.CASCADE, to='trak.papersignature'), ), migrations.AddField( - model_name="handler", - name="rcra_site", - field=models.ForeignKey( - help_text="Hazardous waste rcra_site associated with the manifest", - on_delete=django.db.models.deletion.CASCADE, - to="sites.rcrasite", - ), + model_name='handler', + name='rcra_site', + field=models.ForeignKey(help_text='Hazardous waste rcra_site associated with the manifest', on_delete=django.db.models.deletion.CASCADE, to='sites.rcrasite'), ), migrations.CreateModel( - name="ESignature", + name='ESignature', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("sign_date", models.DateTimeField(blank=True, null=True)), - ("cromerr_activity_id", models.CharField(blank=True, max_length=100, null=True)), - ("cromerr_document_id", models.CharField(blank=True, max_length=100, null=True)), - ("on_behalf", models.BooleanField(blank=True, default=False, null=True)), - ( - "manifest_handler", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="e_signatures", - to="trak.handler", - ), - ), - ( - "signer", - models.OneToOneField( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="trak.signer", - ), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sign_date', models.DateTimeField(blank=True, null=True)), + ('cromerr_activity_id', models.CharField(blank=True, max_length=100, null=True)), + ('cromerr_document_id', models.CharField(blank=True, max_length=100, null=True)), + ('on_behalf', models.BooleanField(blank=True, default=False, null=True)), + ('manifest_handler', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='e_signatures', to='trak.handler')), + ('signer', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='trak.signer')), ], options={ - "verbose_name": "e-Signature", - "ordering": ["sign_date"], + 'verbose_name': 'e-Signature', + 'ordering': ['sign_date'], }, ), migrations.CreateModel( - name="CorrectionInfo", + name='CorrectionInfo', fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("version_number", models.IntegerField(blank=True, null=True)), - ("active", models.BooleanField(blank=True, null=True)), - ("ppc_active", models.BooleanField(blank=True, null=True)), - ("epa_site_id", models.CharField(blank=True, max_length=100, null=True)), - ( - "initiator_role", - models.CharField( - blank=True, - choices=[ - ("IN", "Industry"), - ("PP", "Ppc"), - ("EP", "Epa"), - ("ST", "State"), - ], - max_length=2, - null=True, - ), - ), - ( - "update_role", - models.CharField( - blank=True, - choices=[ - ("IN", "Industry"), - ("PP", "Ppc"), - ("EP", "Epa"), - ("ST", "State"), - ], - max_length=2, - null=True, - ), - ), - ( - "electronic_signature_info", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.PROTECT, - to="trak.esignature", - ), - ), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('version_number', models.IntegerField(blank=True, null=True)), + ('active', models.BooleanField(blank=True, null=True)), + ('ppc_active', models.BooleanField(blank=True, null=True)), + ('epa_site_id', models.CharField(blank=True, max_length=100, null=True)), + ('initiator_role', models.CharField(blank=True, choices=[('IN', 'Industry'), ('PP', 'Ppc'), ('EP', 'Epa'), ('ST', 'State')], max_length=2, null=True)), + ('update_role', models.CharField(blank=True, choices=[('IN', 'Industry'), ('PP', 'Ppc'), ('EP', 'Epa'), ('ST', 'State')], max_length=2, null=True)), + ('electronic_signature_info', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='trak.esignature')), ], options={ - "verbose_name": "Correction Info", - "verbose_name_plural": "Correction Info", + 'verbose_name': 'Correction Info', + 'verbose_name_plural': 'Correction Info', }, ), migrations.CreateModel( - name="Transporter", + name='Transporter', fields=[ - ( - "handler_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="trak.handler", - ), - ), - ("order", models.PositiveIntegerField()), - ( - "manifest", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="transporters", - to="trak.manifest", - ), - ), + ('handler_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='trak.handler')), + ('order', models.PositiveIntegerField()), + ('manifest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transporters', to='trak.manifest')), ], options={ - "ordering": ["manifest__mtn"], + 'ordering': ['manifest__mtn'], }, - bases=("trak.handler",), + bases=('trak.handler',), ), ] diff --git a/server/apps/trak/migrations/0003_state_waste_codes.py b/server/apps/trak/migrations/0002_state_waste_codes.py similarity index 98% rename from server/apps/trak/migrations/0003_state_waste_codes.py rename to server/apps/trak/migrations/0002_state_waste_codes.py index 6c8bb9f4d..c4a360221 100644 --- a/server/apps/trak/migrations/0003_state_waste_codes.py +++ b/server/apps/trak/migrations/0002_state_waste_codes.py @@ -172,7 +172,7 @@ def populate_state_waste_codes(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ("trak", "0002_wastecode_state_id"), # Replace with your app's initial migration + ("trak", "0001_initial"), ] operations = [ diff --git a/server/apps/trak/migrations/0002_wastecode_state_id.py b/server/apps/trak/migrations/0002_wastecode_state_id.py deleted file mode 100644 index c90a6e6b8..000000000 --- a/server/apps/trak/migrations/0002_wastecode_state_id.py +++ /dev/null @@ -1,78 +0,0 @@ -# Generated by Django 4.2.1 on 2023-06-21 21:18 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("trak", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="wastecode", - name="state_id", - field=models.CharField( - blank=True, - choices=[ - ("AK", "Alaska"), - ("AL", "Alabama"), - ("AP", "Armed Forces Pacific"), - ("AR", "Arkansas"), - ("AZ", "Arizona"), - ("CA", "California"), - ("CO", "Colorado"), - ("CT", "Connecticut"), - ("DC", "District of Columbia"), - ("DE", "Delaware"), - ("FL", "Florida"), - ("GA", "Georgia"), - ("GU", "Guam"), - ("HI", "Hawaii"), - ("IA", "Iowa"), - ("ID", "Idaho"), - ("IL", "Illinois"), - ("IN", "Indiana"), - ("KS", "Kansas"), - ("KY", "Kentucky"), - ("LA", "Louisiana"), - ("MA", "Massachusetts"), - ("MD", "Maryland"), - ("ME", "Maine"), - ("MI", "Michigan"), - ("MN", "Minnesota"), - ("MO", "Missouri"), - ("MS", "Mississippi"), - ("MT", "Montana"), - ("NC", "North Carolina"), - ("ND", "North Dakota"), - ("NE", "Nebraska"), - ("NH", "New Hampshire"), - ("NJ", "New Jersey"), - ("NM", "New Mexico"), - ("NV", "Nevada"), - ("NY", "New York"), - ("OH", "Ohio"), - ("OK", "Oklahoma"), - ("OR", "Oregon"), - ("PA", "Pennsylvania"), - ("PR", "Puerto Rico"), - ("RI", "Rhode Island"), - ("SC", "South Carolina"), - ("SD", "South Dakota"), - ("TN", "Tennessee"), - ("TX", "Texas"), - ("UT", "Utah"), - ("VA", "Virginia"), - ("VI", "Virgin Islands"), - ("VT", "Vermont"), - ("WA", "Washington"), - ("WI", "Wisconsin"), - ("WV", "West Virginia"), - ("WY", "Wyoming"), - ], - max_length=3, - null=True, - ), - ), - ] diff --git a/server/apps/trak/migrations/0004_federal_waste_codes.py b/server/apps/trak/migrations/0003_federal_waste_codes.py similarity index 99% rename from server/apps/trak/migrations/0004_federal_waste_codes.py rename to server/apps/trak/migrations/0003_federal_waste_codes.py index 69a9e2ed8..d1aa73ae8 100644 --- a/server/apps/trak/migrations/0004_federal_waste_codes.py +++ b/server/apps/trak/migrations/0003_federal_waste_codes.py @@ -751,7 +751,7 @@ def populate_federal_waste_codes(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ("trak", "0003_state_waste_codes"), + ("trak", "0002_state_waste_codes"), ] operations = [ diff --git a/server/apps/trak/migrations/0007_dot_id_numbers.py b/server/apps/trak/migrations/0004_dot_id_numbers.py similarity index 99% rename from server/apps/trak/migrations/0007_dot_id_numbers.py rename to server/apps/trak/migrations/0004_dot_id_numbers.py index cfe06755a..ae1963dd7 100644 --- a/server/apps/trak/migrations/0007_dot_id_numbers.py +++ b/server/apps/trak/migrations/0004_dot_id_numbers.py @@ -2382,7 +2382,7 @@ def populate_dot_id_numbers(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ("trak", "0006_dotoption"), + ("trak", "0003_federal_waste_codes"), ] operations = [ diff --git a/server/apps/trak/migrations/0005_alter_manifest_rejection.py b/server/apps/trak/migrations/0005_alter_manifest_rejection.py deleted file mode 100644 index 0e62fde02..000000000 --- a/server/apps/trak/migrations/0005_alter_manifest_rejection.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.4 on 2023-09-08 14:44 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("trak", "0004_federal_waste_codes"), - ] - - operations = [ - migrations.AlterField( - model_name="manifest", - name="rejection", - field=models.BooleanField(blank=True, null=True), - ), - ] diff --git a/server/apps/trak/migrations/0008_dot_packing_groups.py b/server/apps/trak/migrations/0005_dot_packing_groups.py similarity index 99% rename from server/apps/trak/migrations/0008_dot_packing_groups.py rename to server/apps/trak/migrations/0005_dot_packing_groups.py index f672f68b8..cca424185 100644 --- a/server/apps/trak/migrations/0008_dot_packing_groups.py +++ b/server/apps/trak/migrations/0005_dot_packing_groups.py @@ -83,7 +83,7 @@ def populate_dot_hazard_classes(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ("trak", "0007_dot_id_numbers"), + ("trak", "0004_dot_id_numbers"), ] operations = [ diff --git a/server/apps/trak/migrations/0009_dot_shipping_names.py b/server/apps/trak/migrations/0006_dot_shipping_names.py similarity index 99% rename from server/apps/trak/migrations/0009_dot_shipping_names.py rename to server/apps/trak/migrations/0006_dot_shipping_names.py index b51adbcbf..d78e2d3d6 100644 --- a/server/apps/trak/migrations/0009_dot_shipping_names.py +++ b/server/apps/trak/migrations/0006_dot_shipping_names.py @@ -2978,7 +2978,7 @@ def populate_dot_shipping_names(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ("trak", "0008_dot_packing_groups"), + ("trak", "0005_dot_packing_groups"), ] operations = [ diff --git a/server/apps/trak/migrations/0006_dotoption.py b/server/apps/trak/migrations/0006_dotoption.py deleted file mode 100644 index c6bb66010..000000000 --- a/server/apps/trak/migrations/0006_dotoption.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 4.2.5 on 2023-10-10 23:47 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("trak", "0005_alter_manifest_rejection"), - ] - - operations = [ - migrations.CreateModel( - name="DotLookup", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("value", models.CharField(max_length=255)), - ( - "value_type", - models.CharField( - choices=[ - ("ID", "Id"), - ("GROUP", "Group"), - ("NAME", "Name"), - ("CLASS", "Class"), - ], - max_length=5, - ), - ), - ], - options={ - "ordering": ["value_type", "value"], - }, - ), - ] diff --git a/server/apps/trak/migrations/0010_alter_signer_contact_type_alter_signer_signer_role.py b/server/apps/trak/migrations/0010_alter_signer_contact_type_alter_signer_signer_role.py deleted file mode 100644 index 94622b7b5..000000000 --- a/server/apps/trak/migrations/0010_alter_signer_contact_type_alter_signer_signer_role.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2.7 on 2023-11-12 14:34 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('trak', '0009_dot_shipping_names'), - ] - - operations = [ - migrations.AlterField( - model_name='signer', - name='contact_type', - field=models.CharField(blank=True, choices=[('email', 'Email'), ('voice', 'Voice'), ('text', 'Text')], max_length=5, null=True), - ), - migrations.AlterField( - model_name='signer', - name='signer_role', - field=models.CharField(choices=[('Industry', 'Industry'), ('PPC', 'Ppc'), ('EPA', 'Epa'), ('State', 'State')], max_length=10, null=True), - ), - ] diff --git a/server/apps/trak/migrations/0011_alter_dotlookup_options.py b/server/apps/trak/migrations/0011_alter_dotlookup_options.py deleted file mode 100644 index ca7c2df77..000000000 --- a/server/apps/trak/migrations/0011_alter_dotlookup_options.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.7 on 2023-11-14 15:00 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('trak', '0010_alter_signer_contact_type_alter_signer_signer_role'), - ] - - operations = [ - migrations.AlterModelOptions( - name='dotlookup', - options={'ordering': ['value_type', 'value'], 'verbose_name': 'DOT lookup', 'verbose_name_plural': 'DOT lookups'}, - ), - ] diff --git a/server/apps/trak/tests/conftest.py b/server/apps/trak/tests/conftest.py index 233bc857b..39812e519 100644 --- a/server/apps/trak/tests/conftest.py +++ b/server/apps/trak/tests/conftest.py @@ -1,7 +1,5 @@ -import random -import string -from datetime import UTC, datetime, timezone -from typing import Dict, List, Optional +from datetime import UTC, datetime +from typing import Optional import pytest from faker import Faker @@ -79,12 +77,21 @@ def create_waste_code( code: Optional[str] = "D001", description: Optional[str] = "IGNITABLE WASTE", code_type: Optional[WasteCode.CodeType] = WasteCode.CodeType.FEDERAL, + state_id: Optional[str] = "VA", ) -> WasteCode: - waste_code = WasteCode.objects.create( - code=code, - description=description, - code_type=code_type, - ) + if code_type == WasteCode.CodeType.STATE: + waste_code = WasteCode.objects.create( + code=code, + description=description, + code_type=code_type, + state_id=state_id, + ) + else: + waste_code = WasteCode.objects.create( + code=code, + description=description, + code_type=code_type, + ) return waste_code yield create_waste_code diff --git a/server/apps/trak/tests/views/test_waste_views.py b/server/apps/trak/tests/views/test_waste_views.py index 7a4b133ae..b4578f79d 100644 --- a/server/apps/trak/tests/views/test_waste_views.py +++ b/server/apps/trak/tests/views/test_waste_views.py @@ -54,8 +54,26 @@ def test_state_returns_200(self, factory, user): # Assert assert response.status_code == status.HTTP_200_OK - def test_state_waste_codes_returns_list_codes(self, factory, user): + def test_state_waste_codes_returns_list_codes(self, factory, user, waste_code_factory): # Arrange + waste_code_factory( + code="mock", + description="Ignitable", + code_type=WasteCode.CodeType.STATE, + state_id=WasteCode.VA, + ) + waste_code_factory( + code="foo", + description="Something else", + code_type=WasteCode.CodeType.STATE, + state_id=WasteCode.VA, + ) + waste_code_factory( + code="blah", + description="Corrosive", + code_type=WasteCode.CodeType.STATE, + state_id=WasteCode.VA, + ) number_state_codes = WasteCode.state.filter(state_id=WasteCode.VA).count() state_id = "VA" request = factory.get(f"{self.base_url}/state/{state_id}") diff --git a/server/fixtures/dev_data.yaml b/server/fixtures/dev_data.yaml index 51daf22dd..07d2d5eea 100644 --- a/server/fixtures/dev_data.yaml +++ b/server/fixtures/dev_data.yaml @@ -1,5 +1,5 @@ - model: core.haztrakuser - pk: 1 + pk: a0ba4966-aa53-44c8-be1a-0a0d2d6b6acd fields: password: pbkdf2_sha256$390000$iVFyQyb6N3g06Wan8YLnTv$MgFhKBvwPSwctgxWSviA/OXClEKtDXg87iPU+g9+Zjs= last_login: 2023-03-19 00:29:46.249589+00:00 @@ -14,7 +14,7 @@ groups: [] user_permissions: [] - model: core.haztrakuser - pk: 2 + pk: 4ac96f68-42cf-47ea-bffb-f24d423dbc35 fields: password: pbkdf2_sha256$390000$SB7EHpYC88CjsX5tcbxa8E$yh1TWONkGI2z/bjblkPSTyjpd1UdhnivPW5nzA9NGOk= last_login: null @@ -31,7 +31,7 @@ - model: authtoken.token pk: d9609d7764af771ee0def1db08dc7f90dd5e2d6d fields: - user: 2 + user: 4ac96f68-42cf-47ea-bffb-f24d423dbc35 created: 2022-12-18 13:10:40.552000+00:00 - model: sites.address pk: 1 @@ -127,13 +127,13 @@ limited_esign: true registered_emanifest_user: true - model: core.rcraprofile - pk: 1 + pk: 1fd27bec-8743-4eb3-a44c-fd063ea62021 fields: rcra_username: dpgraham4401 phone_number: null email: dpgraham4401@haztrak.net - model: core.rcraprofile - pk: 2 + pk: 192c73f4-24f1-4f21-8239-dee2da43c547 fields: rcra_username: emanifestpyuser1 phone_number: null @@ -142,18 +142,18 @@ pk: efb9e104-7f61-4365-a9af-9d7b55c854c4 fields: name: Generators Org LLC - admin: 1 + admin: a0ba4966-aa53-44c8-be1a-0a0d2d6b6acd - model: core.haztrakprofile - pk: 1 + pk: 186642a9-7b5f-4bcb-b328-0fdf8b43f191 fields: - user: 1 - rcrainfo_profile: 1 + user: a0ba4966-aa53-44c8-be1a-0a0d2d6b6acd + rcrainfo_profile: 1fd27bec-8743-4eb3-a44c-fd063ea62021 org: efb9e104-7f61-4365-a9af-9d7b55c854c4 - model: core.haztrakprofile - pk: 2 + pk: 87e355dd-1898-4a0a-81c3-1e9ac8473143 fields: - user: 2 - rcrainfo_profile: 2 + user: 4ac96f68-42cf-47ea-bffb-f24d423dbc35 + rcrainfo_profile: 192c73f4-24f1-4f21-8239-dee2da43c547 org: efb9e104-7f61-4365-a9af-9d7b55c854c4 - model: sites.haztraksite pk: 1 @@ -167,12 +167,12 @@ fields: site: 1 emanifest: signer - profile: 2 + profile: 87e355dd-1898-4a0a-81c3-1e9ac8473143 - model: sites.rcrasitepermissions pk: 1 fields: site: 1 - profile: 1 + profile: 192c73f4-24f1-4f21-8239-dee2da43c547 site_manager: true annual_report: Certifier biennial_report: Certifier