Skip to content

Commit

Permalink
Merge branch 'main' into CA-674-Step-1.4
Browse files Browse the repository at this point in the history
  • Loading branch information
Mohamed-Hacene committed Dec 5, 2024
2 parents 5eeb5a3 + 225db00 commit cdae724
Show file tree
Hide file tree
Showing 66 changed files with 934 additions and 395 deletions.
1 change: 0 additions & 1 deletion .github/workflows/functional-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ jobs:
run: |
touch .env
echo PUBLIC_BACKEND_API_URL=http://localhost:8000/api >> .env
- name: Create backend environment variables file
working-directory: ${{ env.backend-directory }}
run: |
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/startup-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ jobs:
working-directory: ${{ env.frontend-directory }}
run: |
response=$(curl -d "[email protected]&password=1234" -H "Origin: https://localhost:8443" https://localhost:8443/login\?/login -k)
server_reponse='{"type":"redirect","status":302,"location":""}'
server_reponse='{"type":"redirect","status":302,"location":"/"}'
echo "[SERVER_RESPONSE] $response"
echo "[EXPECTED_RESPONSE] $server_reponse"
if [[ "$response" == "$server_reponse" ]]; then
echo "Success"
exit 0
Expand Down Expand Up @@ -265,7 +267,9 @@ jobs:
working-directory: ${{ env.frontend-directory }}
run: |
response=$(curl -d "[email protected]&password=1234" -H "Origin: https://localhost:8443" https://localhost:8443/login\?/login -k)
server_reponse='{"type":"redirect","status":302,"location":""}'
server_reponse='{"type":"redirect","status":302,"location":"/"}'
echo "[SERVER_RESPONSE] $response"
echo "[EXPECTED_RESPONSE] $server_reponse"
if [[ "$response" == "$server_reponse" ]]; then
echo "Success"
exit 0
Expand Down
2 changes: 0 additions & 2 deletions backend/.meta

This file was deleted.

2 changes: 0 additions & 2 deletions backend/ciso_assistant/.meta

This file was deleted.

2 changes: 1 addition & 1 deletion backend/ciso_assistant/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ def set_ciso_assistant_url(_, __, event_dict):
("es", "Spanish"),
("de", "German"),
("it", "Italian"),
("nd", "Dutch"),
("nl", "Dutch"),
("pl", "Polish"),
("pt", "Portuguese"),
("ar", "Arabic"),
Expand Down
2 changes: 1 addition & 1 deletion backend/core/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1278,7 +1278,7 @@ def duplicate_and_link_object(new_obj, duplicate_object, target_folder, field_na

# Get parent and sub-folders of the target folder
target_parent_folders = target_folder.get_parent_folders()
sub_folders = target_folder.sub_folders()
sub_folders = target_folder.get_sub_folders()

# Get all related objects for the specified field
related_objects = getattr(source_object, field_name).all()
Expand Down
3 changes: 0 additions & 3 deletions backend/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1787,9 +1787,6 @@ def risk_assessments(self):
def projects(self):
return {risk_assessment.project for risk_assessment in self.risk_assessments}

def parent_project(self):
pass

def __str__(self):
return self.name

Expand Down
11 changes: 9 additions & 2 deletions backend/core/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,15 @@ class AppliedControlReadSerializer(AppliedControlWriteSerializer):

ranking_score = serializers.IntegerField(source="get_ranking_score")
owner = FieldsRelatedField(many=True)
has_evidences = serializers.BooleanField()
eta_missed = serializers.BooleanField()
# These properties shouldn't be displayed in the frontend detail view as they are simple derivations from fields already displayed in the detail view.
# has_evidences = serializers.BooleanField()
# eta_missed = serializers.BooleanField()


class AppliedControlDuplicateSerializer(BaseModelSerializer):
class Meta:
model = AppliedControl
fields = ["name", "description", "folder"]


class PolicyWriteSerializer(AppliedControlWriteSerializer):
Expand Down
3 changes: 2 additions & 1 deletion backend/core/startup.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,8 @@ def startup(sender: AppConfig, **kwargs):

# Create default Qualifications
try:
Qualification.create_default_qualifications()
if Qualification.objects.count() == 0:
Qualification.create_default_qualifications()
except Exception as e:
logger.error("Error creating default qualifications", exc_info=e)

Expand Down
1 change: 1 addition & 0 deletions backend/core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
path("iam/", include("iam.urls")),
path("serdes/", include("serdes.urls")),
path("settings/", include("global_settings.urls")),
path("user-preferences/", UserPreferencesView.as_view(), name="user-preferences"),
path("ebios-rm/", include("ebios_rm.urls")),
path("csrf/", get_csrf_token, name="get_csrf_token"),
path("build/", get_build, name="get_build"),
Expand Down
114 changes: 85 additions & 29 deletions backend/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
from rest_framework.renderers import JSONRenderer
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN
from rest_framework.utils.serializer_helpers import ReturnDict
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
Expand Down Expand Up @@ -299,7 +298,7 @@ def quality_check_detail(self, request, pk):
}
return Response(res)
else:
return Response(status=HTTP_403_FORBIDDEN)
return Response(status=status.HTTP_403_FORBIDDEN)

@action(detail=False, methods=["get"])
def ids(self, request):
Expand Down Expand Up @@ -612,7 +611,7 @@ def quality_check_detail(self, request, pk):
risk_assessment = self.get_object()
return Response(risk_assessment.quality_check())
else:
return Response(status=HTTP_403_FORBIDDEN)
return Response(status=status.HTTP_403_FORBIDDEN)

@action(detail=True, methods=["get"], name="Get treatment plan data")
def plan(self, request, pk):
Expand Down Expand Up @@ -645,7 +644,7 @@ def plan(self, request, pk):
return Response(risk_assessment)

else:
return Response(status=HTTP_403_FORBIDDEN)
return Response(status=status.HTTP_403_FORBIDDEN)

@action(detail=True, name="Get treatment plan CSV")
def treatment_plan_csv(self, request, pk):
Expand Down Expand Up @@ -705,7 +704,9 @@ def treatment_plan_csv(self, request, pk):

return response
else:
return Response({"error": "Permission denied"}, status=HTTP_403_FORBIDDEN)
return Response(
{"error": "Permission denied"}, status=status.HTTP_403_FORBIDDEN
)

@action(detail=True, name="Get risk assessment CSV")
def risk_assessment_csv(self, request, pk):
Expand Down Expand Up @@ -767,7 +768,9 @@ def risk_assessment_csv(self, request, pk):

return response
else:
return Response({"error": "Permission denied"}, status=HTTP_403_FORBIDDEN)
return Response(
{"error": "Permission denied"}, status=status.HTTP_403_FORBIDDEN
)

@action(detail=True, name="Get risk assessment PDF")
def risk_assessment_pdf(self, request, pk):
Expand Down Expand Up @@ -1021,6 +1024,7 @@ def export_csv(self, request):
"csf_function",
"status",
"eta",
"priority",
"owner",
]
writer.writerow(columns)
Expand All @@ -1034,6 +1038,7 @@ def export_csv(self, request):
control.csf_function,
control.status,
control.eta,
control.priority,
]
if len(control.owner.all()) > 0:
owners = ",".join([o.email for o in control.owner.all()])
Expand Down Expand Up @@ -1157,6 +1162,53 @@ def get_timeline_info(self, request):
colorMap[domain.name] = next(color_cycle)
return Response({"entries": entries, "colorMap": colorMap})

@action(
detail=True,
name="Duplicate applied control",
methods=["post"],
serializer_class=AppliedControlDuplicateSerializer,
)
def duplicate(self, request, pk):
(object_ids_view, _, _) = RoleAssignment.get_accessible_object_ids(
Folder.get_root_folder(), request.user, AppliedControl
)
if UUID(pk) not in object_ids_view:
return Response(
{"results": "applied control duplicated"},
status=status.HTTP_404_NOT_FOUND,
)

applied_control = self.get_object()
data = request.data
new_folder = Folder.objects.get(id=data["folder"])
duplicate_applied_control = AppliedControl.objects.create(
reference_control=applied_control.reference_control,
name=data["name"],
description=data["description"],
folder=new_folder,
ref_id=applied_control.ref_id,
category=applied_control.category,
csf_function=applied_control.csf_function,
priority=applied_control.priority,
status=applied_control.status,
start_date=applied_control.start_date,
eta=applied_control.eta,
expiry_date=applied_control.expiry_date,
link=applied_control.link,
effort=applied_control.effort,
cost=applied_control.cost,
)
duplicate_applied_control.owner.set(applied_control.owner.all())
if data["duplicate_evidences"]:
duplicate_related_objects(
applied_control, duplicate_applied_control, new_folder, "evidences"
)
duplicate_applied_control.save()

return Response(
{"results": AppliedControlReadSerializer(duplicate_applied_control).data}
)

@action(detail=False, methods=["get"])
def ids(self, request):
my_map = dict()
Expand Down Expand Up @@ -1330,7 +1382,7 @@ def update(self, request, *args, **kwargs):
_data = {
"non_field_errors": "The justification can only be edited by the approver"
}
return Response(data=_data, status=HTTP_400_BAD_REQUEST)
return Response(data=_data, status=status.HTTP_400_BAD_REQUEST)
else:
return super().update(request, *args, **kwargs)

Expand Down Expand Up @@ -1442,7 +1494,7 @@ def update(self, request: Request, *args, **kwargs) -> Response:
if str(admin_group.pk) not in new_user_groups:
return Response(
{"error": "attemptToRemoveOnlyAdminUserGroup"},
status=HTTP_403_FORBIDDEN,
status=status.HTTP_403_FORBIDDEN,
)

return super().update(request, *args, **kwargs)
Expand All @@ -1454,7 +1506,7 @@ def destroy(self, request, *args, **kwargs):
if number_of_admin_users == 1:
return Response(
{"error": "attemptToDeleteOnlyAdminAccountError"},
status=HTTP_403_FORBIDDEN,
status=status.HTTP_403_FORBIDDEN,
)

return super().destroy(request, *args, **kwargs)
Expand Down Expand Up @@ -1683,6 +1735,29 @@ def my_assignments(self, request):
)


class UserPreferencesView(APIView):
permission_classes = [permissions.IsAuthenticated]

def get(self, request) -> Response:
return Response(request.user.preferences, status=status.HTTP_200_OK)

def patch(self, request) -> Response:
new_language = request.data.get("lang")
if new_language is None or new_language not in (
lang[0] for lang in settings.LANGUAGES
):
logger.error(
f"Error in UserPreferencesView: new_language={new_language} available languages={[lang[0] for lang in settings.LANGUAGES]}"
)
return Response(
{"error": "This language doesn't exist."},
status=status.HTTP_400_BAD_REQUEST,
)
request.user.preferences["lang"] = new_language
request.user.save()
return Response({}, status=status.HTTP_200_OK)


@cache_page(60 * SHORT_CACHE_TTL)
@vary_on_cookie
@api_view(["GET"])
Expand Down Expand Up @@ -2003,26 +2078,7 @@ def action_plan(self, request, pk):
)
)
applied_controls = [
{
"id": applied_control.id,
"name": applied_control.name,
"description": applied_control.description,
"status": applied_control.status,
"category": applied_control.category,
"csf_function": applied_control.csf_function,
"eta": applied_control.eta,
"expiry_date": applied_control.expiry_date,
"link": applied_control.link,
"effort": applied_control.effort,
"cost": applied_control.cost,
"owners": [
{
"id": owner.id,
"email": owner.email,
}
for owner in applied_control.owner.all()
],
}
AppliedControlReadSerializer(applied_control).data
for applied_control in AppliedControl.objects.filter(
requirement_assessments__in=requirement_assessments_objects
).distinct()
Expand Down
Loading

0 comments on commit cdae724

Please sign in to comment.