diff --git a/CHANGELOG.md b/CHANGELOG.md index eaa49be..d4c2bf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to ## [Unreleased] +### Added + +- ✨(contacts) add notes & force full_name #565 + ## [1.7.1] - 2024-11-28 ## [1.7.0] - 2024-11-28 diff --git a/src/backend/core/api/client/serializers.py b/src/backend/core/api/client/serializers.py index ff46554..d0b707d 100644 --- a/src/backend/core/api/client/serializers.py +++ b/src/backend/core/api/client/serializers.py @@ -17,10 +17,14 @@ class ContactSerializer(serializers.ModelSerializer): "base", "data", "full_name", + "notes", "owner", "short_name", ] read_only_fields = ["id", "owner"] + extra_kwargs = { + "base": {"required": False}, + } def update(self, instance, validated_data): """Make "base" field readonly but only for update/patch.""" diff --git a/src/backend/core/migrations/0006_contact_notes_alter_contact_full_name.py b/src/backend/core/migrations/0006_contact_notes_alter_contact_full_name.py new file mode 100644 index 0000000..0956836 --- /dev/null +++ b/src/backend/core/migrations/0006_contact_notes_alter_contact_full_name.py @@ -0,0 +1,24 @@ +# Generated by Django 5.1.3 on 2024-11-28 09:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0005_add_serviceprovider'), + ] + + operations = [ + migrations.AddField( + model_name='contact', + name='notes', + field=models.TextField(blank=True, default='', verbose_name='notes'), + ), + migrations.AlterField( + model_name='contact', + name='full_name', + field=models.CharField(default='-', max_length=150, verbose_name='full name'), + preserve_default=False, + ), + ] diff --git a/src/backend/core/models.py b/src/backend/core/models.py index cc99fbe..585ac52 100644 --- a/src/backend/core/models.py +++ b/src/backend/core/models.py @@ -113,11 +113,11 @@ class Contact(BaseModel): null=True, blank=True, ) - full_name = models.CharField(_("full name"), max_length=150, null=True, blank=True) + full_name = models.CharField(_("full name"), max_length=150) short_name = models.CharField(_("short name"), max_length=30, null=True, blank=True) # avatar = - # notes = + notes = models.TextField(_("notes"), blank=True, default="") data = models.JSONField( _("contact information"), help_text=_("A JSON object containing the contact information"), @@ -151,7 +151,7 @@ class Contact(BaseModel): ] def __str__(self): - return self.full_name or self.short_name + return self.full_name def clean(self): """Validate fields.""" diff --git a/src/backend/core/tests/test_api_contacts.py b/src/backend/core/tests/test_api_contacts.py index 12c4747..2672054 100644 --- a/src/backend/core/tests/test_api_contacts.py +++ b/src/backend/core/tests/test_api_contacts.py @@ -97,6 +97,7 @@ def test_api_contacts_list_authenticated_no_query(): "owner": str(contact2.owner.id), "data": contact2.data, "full_name": contact2.full_name, + "notes": "", "short_name": contact2.short_name, }, ] @@ -271,6 +272,7 @@ def test_api_contacts_retrieve_authenticated_owned(): "owner": str(contact.owner.id), "data": contact.data, "full_name": contact.full_name, + "notes": "", "short_name": contact.short_name, } @@ -293,6 +295,7 @@ def test_api_contacts_retrieve_authenticated_public(): "owner": None, "data": contact.data, "full_name": contact.full_name, + "notes": "", "short_name": contact.short_name, } @@ -328,7 +331,7 @@ def test_api_contacts_create_anonymous_forbidden(): def test_api_contacts_create_authenticated_missing_base(): - """Anonymous users should be able to create users.""" + """Authenticated user should be able to create contact without override.""" user = factories.UserFactory(profile_contact=None) client = APIClient() @@ -339,13 +342,23 @@ def test_api_contacts_create_authenticated_missing_base(): { "full_name": "David Bowman", "short_name": "Dave", + "data": {}, }, format="json", ) - assert response.status_code == 400 - assert models.Contact.objects.exists() is False + assert response.status_code == 201 - assert response.json() == {"base": ["This field is required."]} + new_contact = models.Contact.objects.get(owner=user) + + assert response.json() == { + "base": None, + "data": {}, + "full_name": "David Bowman", + "id": str(new_contact.pk), + "notes": "", + "owner": str(user.pk), + "short_name": "Dave", + } def test_api_contacts_create_authenticated_successful(): @@ -379,6 +392,7 @@ def test_api_contacts_create_authenticated_successful(): "base": str(base_contact.id), "data": CONTACT_DATA, "full_name": "David Bowman", + "notes": "", "owner": str(user.id), "short_name": "Dave", } @@ -408,6 +422,7 @@ def test_api_contacts_create_authenticated_existing_override(): { "base": str(base_contact.id), "full_name": "David Bowman", + "notes": "", "short_name": "Dave", "data": CONTACT_DATA, }, @@ -422,6 +437,45 @@ def test_api_contacts_create_authenticated_existing_override(): } +def test_api_contacts_create_authenticated_successful_with_notes(): + """Authenticated users should be able to create contacts with notes.""" + user = factories.UserFactory(profile_contact=None) + + client = APIClient() + client.force_login(user) + + response = client.post( + "/api/v1.0/contacts/", + { + "full_name": "David Bowman", + "short_name": "Dave", + "data": CONTACT_DATA, + "notes": "This is a note", + }, + format="json", + ) + + assert response.status_code == 201 + assert models.Contact.objects.count() == 1 + + contact = models.Contact.objects.get(owner=user) + assert response.json() == { + "id": str(contact.id), + "base": None, + "data": CONTACT_DATA, + "full_name": "David Bowman", + "notes": "This is a note", + "owner": str(user.id), + "short_name": "Dave", + } + + assert contact.full_name == "David Bowman" + assert contact.short_name == "Dave" + assert contact.data == CONTACT_DATA + assert contact.owner == user + assert contact.notes == "This is a note" + + def test_api_contacts_update_anonymous(): """Anonymous users should not be allowed to update a contact.""" contact = factories.ContactFactory() diff --git a/src/backend/core/tests/test_models_contacts.py b/src/backend/core/tests/test_models_contacts.py index 34c9b58..7434737 100644 --- a/src/backend/core/tests/test_models_contacts.py +++ b/src/backend/core/tests/test_models_contacts.py @@ -17,12 +17,6 @@ def test_models_contacts_str_full_name(): assert str(contact) == "David Bowman" -def test_models_contacts_str_short_name(): - """The str representation should be the contact's short name if full name is not set.""" - contact = factories.ContactFactory(full_name=None, short_name="Dave") - assert str(contact) == "Dave" - - def test_models_contacts_base_self(): """A contact should not point to itself as a base contact.""" contact = factories.ContactFactory()