diff --git a/api/siteapp/serializers/location.py b/api/siteapp/serializers/location.py
new file mode 100644
index 000000000..fc5a07761
--- /dev/null
+++ b/api/siteapp/serializers/location.py
@@ -0,0 +1,19 @@
+from rest_framework import serializers
+from api.base.serializers.types import ReadOnlySerializer, WriteOnlySerializer
+from siteapp.models import Location
+
+class SimpleLocationSerializer(ReadOnlySerializer):
+ class Meta:
+ model = Location
+ fields = ['title', 'address_type', 'street', 'apt', 'city', 'state', 'zipcode', 'country']
+
+class DetailedLocationSerializer(SimpleLocationSerializer):
+ class Meta:
+ model = Location
+ fields = SimpleLocationSerializer.Meta.fields + ['uuid', 'remarks']
+
+class WriteLocationSerializer(WriteOnlySerializer):
+ uuid = serializers.UUIDField(format='hex_verbose')
+ class Meta:
+ model = Location
+ fields = ['uuid', 'title', 'address_type', 'street', 'apt', 'city', 'state', 'zipcode', 'country', 'remarks']
diff --git a/api/siteapp/urls.py b/api/siteapp/urls.py
index 33943b468..fb430012c 100644
--- a/api/siteapp/urls.py
+++ b/api/siteapp/urls.py
@@ -14,6 +14,7 @@
from api.siteapp.views.appointment import AppointmentViewSet
from api.siteapp.views.request import RequestViewSet
from api.siteapp.views.proposal import ProposalViewSet
+from api.siteapp.views.location import LocationViewSet
router = routers.DefaultRouter()
router.register(r'organizations', OrganizationViewSet)
@@ -28,6 +29,7 @@
router.register(r'appointments', AppointmentViewSet)
router.register(r'requests', RequestViewSet)
router.register(r'proposals', ProposalViewSet)
+router.register(r'locations', LocationViewSet)
project_router = NestedSimpleRouter(router, r'projects', lookup='projects')
diff --git a/api/siteapp/views/location.py b/api/siteapp/views/location.py
new file mode 100644
index 000000000..6e288f5d5
--- /dev/null
+++ b/api/siteapp/views/location.py
@@ -0,0 +1,23 @@
+from django.db.models import Q
+from rest_framework import filters
+
+from api.base.views.base import SerializerClasses
+from api.base.views.viewsets import ReadWriteViewSet
+from api.siteapp.serializers.location import SimpleLocationSerializer, DetailedLocationSerializer, WriteLocationSerializer
+from siteapp.models import Location
+
+class LocationViewSet(ReadWriteViewSet):
+ queryset = Location.objects.all()
+
+ search_fields = ['street']
+ filter_backends = (filters.SearchFilter,)
+
+ serializer_classes = SerializerClasses(retrieve=DetailedLocationSerializer,
+ list=SimpleLocationSerializer,
+ create=WriteLocationSerializer,
+ update=WriteLocationSerializer,
+ destroy=WriteLocationSerializer,
+ )
+
+ def search(self, request, keyword):
+ return Q(name__icontains=keyword)
\ No newline at end of file
diff --git a/controls/migrations/0074_auto_20220531_1518.py b/controls/migrations/0074_auto_20220531_1518.py
new file mode 100644
index 000000000..eb118e308
--- /dev/null
+++ b/controls/migrations/0074_auto_20220531_1518.py
@@ -0,0 +1,39 @@
+# Generated by Django 3.2.13 on 2022-05-31 15:18
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('siteapp', '0066_auto_20220531_1518'),
+ ('controls', '0073_auto_20220516_1548'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='element',
+ name='appointments',
+ field=models.ManyToManyField(blank=True, related_name='element', to='siteapp.Appointment'),
+ ),
+ migrations.AlterField(
+ model_name='element',
+ name='requests',
+ field=models.ManyToManyField(blank=True, related_name='element', to='siteapp.Request'),
+ ),
+ migrations.AlterField(
+ model_name='element',
+ name='tags',
+ field=models.ManyToManyField(blank=True, related_name='element', to='siteapp.Tag'),
+ ),
+ migrations.AlterField(
+ model_name='system',
+ name='proposals',
+ field=models.ManyToManyField(blank=True, related_name='system', to='siteapp.Proposal'),
+ ),
+ migrations.AlterField(
+ model_name='system',
+ name='tags',
+ field=models.ManyToManyField(blank=True, related_name='system', to='siteapp.Tag'),
+ ),
+ ]
diff --git a/controls/views.py b/controls/views.py
index de6b25ad8..11e89c27a 100644
--- a/controls/views.py
+++ b/controls/views.py
@@ -53,6 +53,7 @@
from .models import *
from .utilities import *
from siteapp.utils.views_helper import project_context
+from siteapp.models import Role, Party, Appointment, Request, Proposal, Location
from integrations.models import Integration
logging.basicConfig()
@@ -967,12 +968,74 @@ def as_json(self):
control_implementations = []
props = []
orgs = list(Organization.objects.all()) # TODO: orgs need uuids, not sure which orgs to use for a component
- parties = [{"uuid": str(uuid.uuid4()), "type": "organization", "name": org.name} for org in orgs]
- responsible_roles = [{
- "role-id": "supplier",# TODO: Not sure what this refers to
- "party-uuids": [ str(party.get("uuid")) for party in parties ]
+
+ list_of_parties = []
+ list_of_roles = []
+ list_of_resp_parties = []
+ list_of_resp_roles = []
+ list_of_locations = []
+
+ for location in Location.objects.all():
+ # import ipdb; ipdb.set_trace()
+ loc = {
+ "uuid": str(location.uuid),
+ "title": location.title,
+ "address": {
+ "type": location.address_type,
+ "addr-lines": [location.apt, location.street],
+ "city": location.city,
+ "state": location.state,
+ "postal-code": location.zipcode,
+ },
+ "remarks": location.remarks,
+ }
+ list_of_locations.append(loc)
+ for appointment in self.element.appointments.all():
+ party = {
+ "uuid": str(appointment.party.uuid),
+ "type": appointment.party.party_type,
+ "name": appointment.party.name,
+ "short-name": appointment.party.short_name,
+ "email-addresses": appointment.party.email,
+ "telephone-numbers": appointment.party.phone_number,
+ }
+ role = {
+ "id": appointment.role.role_id,
+ "title": appointment.role.title,
+ "short-name": appointment.role.short_name,
+ "description": appointment.role.description,
+ }
+ respParty = {
+ 'role-id': role["id"],
+ 'party-uuids': [party["uuid"]]
+ }
+
+ if len(list_of_resp_parties) == 0:
+ list_of_resp_parties.append(respParty)
+
+ if role["id"] in [x['role-id'] for x in list_of_resp_parties]:
+ for x in list_of_resp_parties:
+ if x['role-id'] == role["id"] and party['uuid'] not in x['party-uuids']:
+ x['party-uuids'].append(party["uuid"])
+ else:
+ list_of_resp_parties.append(respParty)
+
+ if party not in list_of_parties:
+ list_of_parties.append(party)
- }]
+ if role not in list_of_roles:
+ list_of_roles.append(role)
+
+ parties = [
+ {
+ "uuid": str(uuid.uuid4()),
+ "type": "organization",
+ "name": org.name
+ } for org in orgs]
+ parties.extend(list_of_parties)
+
+
+
of = {
"component-definition": {
"uuid": str(uuid4()),
@@ -981,7 +1044,11 @@ def as_json(self):
"last-modified": self.element.updated.replace(microsecond=0).isoformat(),
"version": self.element.updated.replace(microsecond=0).isoformat(),
"oscal-version": self.element.oscal_version,
- "parties": parties
+
+ "roles": list_of_roles,
+ "locations": list_of_locations,
+ "parties": parties,
+ "responsible-parties": list_of_resp_parties,
},
"components": [
{
@@ -989,7 +1056,7 @@ def as_json(self):
"type": self.element.component_type.lower() if self.element.component_type is not None else "software",
"title": self.element.full_name or self.element.name,
"description": self.element.description,
- "responsible-roles": responsible_roles, # TODO: gathering party-uuids, just filling for now
+ "responsible-roles": list_of_resp_roles, #TODO: Need to add responsible roles
"props": props,
"control-implementations": control_implementations
}
diff --git a/frontend/src/components/cmpt_parties/cmpt_parties.js b/frontend/src/components/cmpt_parties/cmpt_parties.js
index 0e40c6d4b..6d12aff13 100644
--- a/frontend/src/components/cmpt_parties/cmpt_parties.js
+++ b/frontend/src/components/cmpt_parties/cmpt_parties.js
@@ -112,6 +112,7 @@ export const ComponentParties = ({ elementId, poc_users, isOwner }) => {
});
const [tempRoleToAdd, setTempRoleToAdd] = useState([]);
const [partyNamesList, setPartyNamesList] = useState([]);
+ const [allPartiesNames, setAllPartiesNames] = useState([]);
const editToolTip = (