Skip to content

Commit

Permalink
[AMI-268] Enable comments field when suggesting ID (#376)
Browse files Browse the repository at this point in the history
* Add support the comments field when suggesting an ID
  • Loading branch information
mihow authored Apr 18, 2024
1 parent 5f35664 commit a4e4cec
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 3 deletions.
2 changes: 1 addition & 1 deletion ami/jobs/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def setUp(self):
self.job = Job.objects.create(project=self.project, name="Test job", delay=0)
self.user = User.objects.create_user( # type: ignore
email="[email protected]",
is_staff=True,
)
self.factory = APIRequestFactory()

Expand Down Expand Up @@ -99,7 +100,6 @@ def test_run_job(self):
jobs_run_url = reverse_with_params("api:job-run", args=[self.job.pk], params={"no_async": True})
self.client.force_authenticate(user=self.user)
resp = self.client.post(jobs_run_url)
self.client.force_authenticate(user=None)
self.assertEqual(resp.status_code, 200)
data = resp.json()
self.assertEqual(data["id"], self.job.pk)
Expand Down
2 changes: 2 additions & 0 deletions ami/main/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ class Meta:
"withdrawn",
"agreed_with_identification_id",
"agreed_with_prediction_id",
"comment",
"created_at",
"updated_at",
]
Expand Down Expand Up @@ -944,6 +945,7 @@ class Meta:
"taxon",
"user",
"withdrawn",
"comment",
"created_at",
]

Expand Down
17 changes: 17 additions & 0 deletions ami/main/migrations/0030_identification_comment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.2 on 2024-04-16 18:56

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("main", "0029_alter_deployment_device_and_more"),
]

operations = [
migrations.AddField(
model_name="identification",
name="comment",
field=models.TextField(blank=True),
),
]
5 changes: 5 additions & 0 deletions ami/main/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1285,6 +1285,7 @@ class Identification(BaseModel):
related_name="agreed_identifications",
)
score = 1.0 # Always 1 for humans, at this time
comment = models.TextField(blank=True)

class Meta:
ordering = [
Expand Down Expand Up @@ -1390,6 +1391,10 @@ class Classification(BaseModel):
)
# job = models.CharField(max_length=255, null=True)

# Type hints for auto-generated fields
taxon_id: int
algorithm_id: int

class Meta:
ordering = ["-created_at", "-score"]

Expand Down
50 changes: 50 additions & 0 deletions ami/main/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from django.db import connection
from django.test import TestCase
from rest_framework.test import APIRequestFactory, APITestCase
from rich import print

from ami.main.models import (
Expand All @@ -17,6 +18,7 @@
TaxonRank,
group_images_into_events,
)
from ami.users.models import User


def setup_test_project(reuse=True) -> tuple[Project, Deployment]:
Expand Down Expand Up @@ -547,3 +549,51 @@ def test_taxon_detail(self):
response = self.client.get(f"/api/v2/taxa/{taxon.pk}/")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["name"], taxon.name)


class TestIdentification(APITestCase):
def setUp(self) -> None:
project, deployment = setup_test_project()
create_taxa(project=project)
create_captures(deployment=deployment)
group_images_into_events(deployment=deployment)
create_occurrences(deployment=deployment, num=5)
self.project = project
self.user = User.objects.create_user( # type: ignore
email="[email protected]",
is_staff=True,
)
self.factory = APIRequestFactory()
self.client.force_authenticate(user=self.user)
return super().setUp()

def test_identification(self):
from ami.main.models import Identification, Taxon

"""
Post a new identification suggestion and check that it changed the occurrence's determination.
"""

suggest_id_endpoint = "/api/v2/identifications/"
taxa = Taxon.objects.filter(projects=self.project)
assert taxa.count() > 1

occurrence = Occurrence.objects.filter(project=self.project).exclude(determination=None)[0]
original_taxon = occurrence.determination
assert original_taxon is not None
new_taxon = Taxon.objects.exclude(pk=original_taxon.pk)[0]
comment = "Test identification comment"

response = self.client.post(
suggest_id_endpoint,
{
"occurrence_id": occurrence.pk,
"taxon_id": new_taxon.pk,
"comment": comment,
},
)
self.assertEqual(response.status_code, 201)
occurrence.refresh_from_db()
self.assertEqual(occurrence.determination, new_taxon)
identification = Identification.objects.get(pk=response.json()["id"])
self.assertEqual(identification.comment, comment)
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface IdentificationFieldValues {
}
occurrenceId: string
taxonId: string
comment?: string
}

const convertToServerFieldValues = (
Expand All @@ -20,6 +21,7 @@ const convertToServerFieldValues = (
agreed_with_prediction_id: fieldValues.agreeWith?.predictionId,
occurrence_id: fieldValues.occurrenceId,
taxon_id: fieldValues.taxonId,
comment: fieldValues.comment,
})

export const useCreateIdentification = (onSuccess?: () => void) => {
Expand Down
3 changes: 3 additions & 0 deletions ui/src/data-services/models/occurrence-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ export interface Identification {
id: string
overridden?: boolean
taxon: Taxon
comment?: string
userPermissions: UserPermission[]
createdAt: string
}

export interface HumanIdentification extends Identification {
comment: string
user: {
id: string
name: string
Expand Down Expand Up @@ -57,6 +59,7 @@ export class OccurrenceDetails extends Occurrence {
overridden,
taxon,
user: { id: `${i.user.id}`, name: i.user.name, image: i.user.image },
comment: i.comment,
userPermissions: i.user_permissions,
createdAt: i.created_at,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
.content {
display: flex;
flex-direction: column;
gap: 16px;
padding: 16px;
position: relative;
}
Expand All @@ -23,3 +22,10 @@
align-items: center;
justify-content: flex-end;
}

.comment {
display: block;
padding-top: 2px;
@include paragraph-small();
color: $color-neutral-600;
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ export const IdentificationCard = ({
})
}
/>
<div className={styles.comment}>
{identification.comment}
</div>
</IdentificationSummary>
<div className={styles.actions}>
{showAgree && (
Expand Down
5 changes: 4 additions & 1 deletion ui/src/pages/occurrence-details/suggest-id/suggest-id.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const SuggestId = ({
}: SuggestIdProps) => {
const { projectId } = useParams()
const [taxon, setTaxon] = useState<Taxon>()
const [comment, setComment] = useState("");
const { createIdentification, isLoading, error } =
useCreateIdentification(onCancel)
const formError = error ? parseServerError(error)?.message : undefined
Expand Down Expand Up @@ -66,7 +67,8 @@ export const SuggestId = ({
<Input
label={translate(STRING.FIELD_LABEL_COMMENT)}
name="comment"
disabled
value={comment}
onChange={(e) => setComment(e.target.value)}
/>
<div className={styles.formActions}>
<Button label={translate(STRING.CANCEL)} onClick={onCancel} />
Expand All @@ -82,6 +84,7 @@ export const SuggestId = ({
createIdentification({
occurrenceId: occurrenceId,
taxonId: taxon.id,
comment: comment,
})
}}
/>
Expand Down

0 comments on commit a4e4cec

Please sign in to comment.