Skip to content

Commit

Permalink
Merge pull request #631 from alan-turing-institute/develop
Browse files Browse the repository at this point in the history
Deployment to Prod on October 9th
  • Loading branch information
cptanalatriste authored Oct 9, 2024
2 parents 5516608 + f09b173 commit b0ee281
Show file tree
Hide file tree
Showing 27 changed files with 1,126 additions and 335 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/frontend-docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
--build-arg NEXTAUTH_SECRET=${{ secrets.NEXTAUTH_SECRET }} \
--build-arg NEXT_PUBLIC_API_URL=${{ secrets.NEXT_PUBLIC_API_URL }} \
--build-arg API_URL=https://eap-backend.azurewebsites.net/ \
--build-arg NEXTAUTH_URL=${{ secrets.NEXTAUTH_URL }} \
--build-arg NEXTAUTH_URL=${{ secrets.NEXT_PUBLIC_API_URL }} \
-t turingassuranceplatform/eap_frontend:main \
-t turingassuranceplatform/eap_frontend:${{ env.commit_date }}.${{ env.sha_short }} \
-f docker/staging/Dockerfile .
Expand Down
80 changes: 80 additions & 0 deletions eap_backend/eap_api/migrations/0024_auto_20240926_1231.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Generated by Django 3.2.8 on 2024-09-26 12:31

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("eap_api", "0023_assurancecaseimage"),
]

operations = [
migrations.AddField(
model_name="comment",
name="context",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="comments",
to="eap_api.context",
),
),
migrations.AddField(
model_name="comment",
name="evidence",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="comments",
to="eap_api.evidence",
),
),
migrations.AddField(
model_name="comment",
name="goal",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="comments",
to="eap_api.toplevelnormativegoal",
),
),
migrations.AddField(
model_name="comment",
name="property_claim",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="comments",
to="eap_api.propertyclaim",
),
),
migrations.AddField(
model_name="comment",
name="strategy",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="comments",
to="eap_api.strategy",
),
),
migrations.AlterField(
model_name="comment",
name="assurance_case",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="comments",
to="eap_api.assurancecase",
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 3.2.8 on 2024-09-30 09:21

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("eap_api", "0024_auto_20240926_1231"),
]

operations = [
migrations.AlterField(
model_name="assurancecaseimage",
name="assurance_case",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="case_image",
to="eap_api.assurancecase",
unique=True,
),
),
]
76 changes: 59 additions & 17 deletions eap_backend/eap_api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,6 @@ def was_published_recently(self):
return self.created_date >= timezone.now() - datetime.timedelta(days=1)


class Comment(models.Model):
author = models.ForeignKey(
EAPUser, related_name="comments", on_delete=models.CASCADE
)
assurance_case = models.ForeignKey(
AssuranceCase, related_name="comments", on_delete=models.CASCADE
)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)

def __str__(self):
return f"Comment by {self.author} on {self.assurance_case}"

class Meta:
ordering = ["created_at"]


class TopLevelNormativeGoal(CaseItem):
keywords = models.CharField(max_length=3000)
assurance_case = models.ForeignKey(
Expand Down Expand Up @@ -254,5 +237,64 @@ class AssuranceCaseImage(models.Model):
AssuranceCase,
related_name="case_image",
on_delete=models.CASCADE,
unique=True,
)
image = models.ImageField(upload_to="images/", default=None)


class Comment(models.Model):
author = models.ForeignKey(
EAPUser, related_name="comments", on_delete=models.CASCADE
)

assurance_case = models.ForeignKey(
AssuranceCase,
related_name="comments",
on_delete=models.CASCADE,
null=True,
default=None,
)
goal = models.ForeignKey(
TopLevelNormativeGoal,
related_name="comments",
on_delete=models.CASCADE,
default=None,
null=True,
)
strategy = models.ForeignKey(
Strategy,
related_name="comments",
on_delete=models.CASCADE,
default=None,
null=True,
)
property_claim = models.ForeignKey(
PropertyClaim,
related_name="comments",
on_delete=models.CASCADE,
default=None,
null=True,
)
evidence = models.ForeignKey(
Evidence,
related_name="comments",
on_delete=models.CASCADE,
default=None,
null=True,
)
context = models.ForeignKey(
Context,
related_name="comments",
on_delete=models.CASCADE,
default=None,
null=True,
)

content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)

def __str__(self):
return f"Comment by {self.author} on {self.assurance_case}"

class Meta:
ordering = ["created_at"]
13 changes: 13 additions & 0 deletions eap_backend/eap_api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ class Meta:
"id",
"author",
"assurance_case",
"goal",
"strategy",
"property_claim",
"evidence",
"context",
"content",
"created_at",
)
Expand Down Expand Up @@ -391,6 +396,14 @@ class Meta:
model = AssuranceCaseImage
fields = ("id", "assurance_case_id", "image")

def create(self, validated_data: dict):
case_image, _ = AssuranceCaseImage.objects.update_or_create(
assurance_case=validated_data.get("assurance_case"),
defaults={"image": validated_data.get("image")},
)

return case_image


class StrategySerializer(serializers.ModelSerializer):
goal_id = serializers.PrimaryKeyRelatedField(
Expand Down
2 changes: 1 addition & 1 deletion eap_backend/eap_api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
name="attach_property_claim",
),
path(
"cases/<int:assurance_case_id>/comments/",
"<str:element_name>/<int:element_id>/comments/",
views.comment_list,
name="comment_list",
),
Expand Down
33 changes: 31 additions & 2 deletions eap_backend/eap_api/view_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import functools
from typing import Any, Callable, Literal, Optional, Union, cast
from typing import Any, Callable, Literal, Optional, Type, Union, cast

from django.db import models
from django.db.models.query import QuerySet
from django.forms.models import model_to_dict
from django.http import JsonResponse
Expand Down Expand Up @@ -245,6 +246,34 @@ def _move_to_sandbox(
case_item.save()


class CommentUtils:
@staticmethod
def get_model_instance(
element_name: str, element_id: int
) -> CaseItem | AssuranceCase:

model_class: Type[models.Model] | None = None

if element_name == "cases":
model_class = AssuranceCase
elif element_name == "propertyclaims":
model_class = PropertyClaim
elif element_name == "goals":
model_class = TopLevelNormativeGoal
elif element_name == "strategies":
model_class = Strategy
elif element_name == "contexts":
model_class = Context
elif element_name == "evidence":
model_class = Evidence

if model_class is None:
error_message: str = f"Invalid URL {element_name}/{element_id}"
raise ValueError(error_message)

return model_class.objects.get(pk=element_id)


class UpdateIdentifierUtils:
@staticmethod
def update_identifiers(
Expand Down Expand Up @@ -773,7 +802,7 @@ def save_json_tree(data, obj_type, parent_id=None, parent_type=None):


def get_case_permissions(
case: AssuranceCase, user: EAPUser
case: AssuranceCase | int | str, user: EAPUser
) -> Literal["manage"] | Literal["edit"] | Literal["review"] | Literal["view"] | None:
"""
See if the user is allowed to view or edit the case.
Expand Down
34 changes: 22 additions & 12 deletions eap_backend/eap_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@
StrategySerializer,
TopLevelNormativeGoalSerializer,
UsernameAwareUserSerializer,
get_case_id,
)
from .view_utils import (
CommentUtils,
SandboxUtils,
ShareAssuranceCaseUtils,
SocialAuthenticationUtils,
Expand Down Expand Up @@ -252,7 +254,6 @@ def case_list(request):
@api_view(["GET", "POST"])
@permission_classes([IsAuthenticated])
def case_image(request: HttpRequest, pk) -> Response:
print(f"{pk=}")
if request.method == "GET":
try:
assurance_case: AssuranceCaseImage = AssuranceCaseImage.objects.get(
Expand Down Expand Up @@ -904,24 +905,32 @@ def github_repository_list(request):

@api_view(["GET", "POST"])
@permission_classes([IsAuthenticated])
def comment_list(request, assurance_case_id):
def comment_list(request: HttpRequest, element_name: str, element_id: int):
"""
List all comments for an assurance case, or create a new comment.
List all comments for an case element, or create a new comment.
"""
permissions = get_case_permissions(assurance_case_id, request.user)
if permissions is None or permissions == "view":
return HttpResponse(status=403)
model_instance = CommentUtils.get_model_instance(element_name, element_id)
assurance_case_id: int | None = None
if isinstance(model_instance, AssuranceCase):
assurance_case_id = model_instance.pk
else:
assurance_case_id = get_case_id(model_instance)

permissions: str | None = get_case_permissions(
cast(int, assurance_case_id), cast(EAPUser, request.user)
)

if permissions is None:
return HttpResponse(status=status.HTTP_403_FORBIDDEN)

if request.method == "GET":
comments = Comment.objects.filter(assurance_case_id=assurance_case_id)
serializer = CommentSerializer(comments, many=True)
serializer = CommentSerializer(model_instance.comments, many=True)
return Response(serializer.data)

elif request.method == "POST":
if permissions not in ["manage", "edit", "review"]:
return HttpResponse(status=status.HTTP_403_FORBIDDEN)
data = request.data.copy()
data["assurance_case_id"] = (
assurance_case_id # Ensure assurance_case_id is set in the data
)
serializer = CommentSerializer(data=data)
if serializer.is_valid():
# Ensure the author is set to the current user
Expand All @@ -938,8 +947,9 @@ def comment_detail(request, pk):
"""
Retrieve, update or delete a specific comment.
"""

try:
comment = Comment.objects.get(id=pk)
comment = Comment.objects.get(id=pk, author=request.user)
except Comment.DoesNotExist:
return HttpResponse(status=404)

Expand Down
3 changes: 2 additions & 1 deletion eap_backend/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1767,7 +1767,8 @@ def _check_status_on_edit(self, status_code: int):
def _check_status_on_comment(self, status_code: int):
response_post: HttpResponse = self.client.post(
reverse(
"comment_list", kwargs={"assurance_case_id": self.assurance_case.pk}
"comment_list",
kwargs={"element_name": "cases", "element_id": self.assurance_case.pk},
),
data=json.dumps(
{"content": "A comment", "assurance_case": self.assurance_case.pk}
Expand Down
Loading

0 comments on commit b0ee281

Please sign in to comment.