From 16e5df94d14aa4c02f5e89f4ae46e4f7459253a6 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Mon, 2 Sep 2019 14:50:59 +0200
Subject: [PATCH] update: fix PUT on m2M relations

---
 djangoldp/models.py             |  6 +++-
 djangoldp/serializers.py        |  9 +++--
 djangoldp/tests/runner.py       | 20 +++++------
 djangoldp/tests/tests_temp.py   | 57 -----------------------------
 djangoldp/tests/tests_update.py | 64 +++++++++++++++++++++++++++++++++
 5 files changed, 85 insertions(+), 71 deletions(-)

diff --git a/djangoldp/models.py b/djangoldp/models.py
index 7507c0bf..778c5e7d 100644
--- a/djangoldp/models.py
+++ b/djangoldp/models.py
@@ -2,6 +2,7 @@ from django.contrib.auth.models import User
 from django.db import models
 from django.db.models.base import ModelBase
 from django.urls import get_resolver
+from django.utils.datastructures import MultiValueDict, MultiValueDictKeyError
 from django.utils.decorators import classonlymethod
 
 from djangoldp.permissions import LDPPermissions
@@ -53,7 +54,10 @@ class Model(models.Model):
         else:
             object_name = instance_or_model._meta.object_name.lower()
         view_name = '{}-detail'.format(object_name)
-        slug_field = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][1][0])
+        try :
+            slug_field = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][1][0])
+        except MultiValueDictKeyError:
+            slug_field = Model.get_meta(instance_or_model, 'lookup_field', 'pk')
         if slug_field.startswith('/'):
             slug_field = slug_field[1:]
         return slug_field
diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py
index ba22a039..4a3990f3 100644
--- a/djangoldp/serializers.py
+++ b/djangoldp/serializers.py
@@ -567,7 +567,7 @@ class LDPSerializer(HyperlinkedModelSerializer):
     def save_or_update_nested_list(self, instance, nested_fields):
         for (field_name, data) in nested_fields:
             manager = getattr(instance, field_name)
-            slug_field = Model.slug_field(instance)
+            slug_field = Model.slug_field(manager.model)
             try:
                 item_pk_to_keep = list(map(lambda e: e[slug_field], filter(lambda x: slug_field in x, data)))
             except TypeError:
@@ -587,8 +587,11 @@ class LDPSerializer(HyperlinkedModelSerializer):
                     saved_item = item
                 elif slug_field in item:
                     kwargs = {slug_field: item[slug_field]}
-                    old_obj = manager.model.objects.get(**kwargs)
-                    saved_item = self.update(instance=old_obj, validated_data=item)
+                    try:
+                        old_obj = manager.model.objects.get(**kwargs)
+                        saved_item = self.update(instance=old_obj, validated_data=item)
+                    except manager.model.DoesNotExist:
+                        saved_item = self.internal_create(validated_data=item, model=manager.model)
                 else:
                     rel = getattr(instance._meta.model, field_name).rel
                     try:
diff --git a/djangoldp/tests/runner.py b/djangoldp/tests/runner.py
index 57001ea8..6a4195f8 100644
--- a/djangoldp/tests/runner.py
+++ b/djangoldp/tests/runner.py
@@ -61,16 +61,16 @@ from django.test.runner import DiscoverRunner
 test_runner = DiscoverRunner(verbosity=1)
 
 failures = test_runner.run_tests([
-    # 'djangoldp.tests.tests_ldp_model',
-    # 'djangoldp.tests.tests_save',
-    # 'djangoldp.tests.tests_user_permissions',
-    # 'djangoldp.tests.tests_anonymous_permissions',
-    # 'djangoldp.tests.tests_update',
-    # 'djangoldp.tests.tests_auto_author',
-    # 'djangoldp.tests.tests_get',
-    # 'djangoldp.tests.tests_delete',
-    # 'djangoldp.tests.tests_sources',
-    # 'djangoldp.tests.tests_pagination',
+    'djangoldp.tests.tests_ldp_model',
+    'djangoldp.tests.tests_save',
+    'djangoldp.tests.tests_user_permissions',
+    'djangoldp.tests.tests_anonymous_permissions',
+    'djangoldp.tests.tests_update',
+    'djangoldp.tests.tests_auto_author',
+    'djangoldp.tests.tests_get',
+    'djangoldp.tests.tests_delete',
+    'djangoldp.tests.tests_sources',
+    'djangoldp.tests.tests_pagination',
     'djangoldp.tests.tests_temp'
 
 ])
diff --git a/djangoldp/tests/tests_temp.py b/djangoldp/tests/tests_temp.py
index 104dea95..21c77f6c 100644
--- a/djangoldp/tests/tests_temp.py
+++ b/djangoldp/tests/tests_temp.py
@@ -17,60 +17,3 @@ class TestTemp(TestCase):
     def tearDown(self):
         pass
 
-    # def test_m2m_existing_link(self):
-    #     resource = Resource.objects.create()
-    #     job = JobOffer.objects.create(title="first title", slug="job")
-    #     resource.joboffers.add(job)
-    #     resource.save()
-    #     body = {
-    #         'http://happy-dev.fr/owl/#joboffers': {
-    #             '@id': '/job-offers/{}'.format(job.slug),
-    #             'http://happy-dev.fr/owl/#title': "new job",
-    #         }
-    #     }
-    #
-    #     response = self.client.put('/resources/{}/'.format(resource.pk),
-    #                                data=json.dumps(body),
-    #                                content_type='application/ld+json')
-    #     self.assertEqual(response.status_code, 200)
-    #     self.assertEqual(response.data['joboffers']['ldp:contains'][0]['@id'],
-    #                      "http://testserver/job-offers/aaa/")
-    #     self.assertEqual(response.data['joboffers']['ldp:contains'][0]['title'], "new job")
-
-    def test_m2m_new_link(self):
-        resource = Resource.objects.create()
-        job = JobOffer.objects.create(title="first title", slug="job")
-        body = {
-            'http://happy-dev.fr/owl/#joboffers': {
-                '@id': 'http://testserver/job-offers/{}/'.format(job.slug),
-            }
-        }
-
-        response = self.client.put('/resources/{}/'.format(resource.pk),
-                                   data=json.dumps(body),
-                                   content_type='application/ld+json')
-        self.assertEqual(response.status_code, 200)
-        self.assertEqual(response.data['joboffers']['ldp:contains'][0]['@id'],
-                         "http://testserver/job-offers/{}/".format(job.slug))
-        self.assertEqual(response.data['joboffers']['ldp:contains'][0]['title'], "job")
-
-    def test_m2m_new_link_bis(self):
-        resource = Resource.objects.create()
-        job = JobOffer.objects.create(title="first title", slug="job")
-        body = {
-            'http://happy-dev.fr/owl/#joboffers':
-                {
-                    '@id': "http://testserver/resources/{}/joboffers/".format(resource.pk),
-                    "ldp:contains": [
-                        {'@id': 'http://testserver/job-offers/{}/'.format(job.slug)},
-                    ]
-                }
-        }
-
-        response = self.client.put('/resources/{}/'.format(resource.pk),
-                                   data=json.dumps(body),
-                                   content_type='application/ld+json')
-        self.assertEqual(response.status_code, 200)
-        self.assertEqual(response.data['joboffers']['ldp:contains'][0]['@id'],
-                         "http://testserver/job-offers/{}/".format(job.slug))
-        self.assertEqual(response.data['joboffers']['ldp:contains'][0]['title'], "job")
diff --git a/djangoldp/tests/tests_update.py b/djangoldp/tests/tests_update.py
index f9cab272..431db723 100644
--- a/djangoldp/tests/tests_update.py
+++ b/djangoldp/tests/tests_update.py
@@ -396,6 +396,46 @@ class Update(TestCase):
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.data['peer_user'], None)
 
+    def test_m2m_new_link(self):
+        resource = Resource.objects.create()
+        job = JobOffer.objects.create(title="first title", slug="job")
+        body = {
+            'http://happy-dev.fr/owl/#joboffers': {
+                '@id': 'http://testserver/job-offers/{}/'.format(job.slug),
+            }
+        }
+
+        response = self.client.put('/resources/{}/'.format(resource.pk),
+                                   data=json.dumps(body),
+                                   content_type='application/ld+json')
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.data['joboffers']['ldp:contains'][0]['@id'],
+                         "http://testserver/job-offers/{}/".format(job.slug))
+        self.assertEqual(response.data['joboffers']['ldp:contains'][0]['title'], "first title")
+
+    def test_m2m_new_link_bis(self):
+        resource = Resource.objects.create()
+        job = JobOffer.objects.create(title="first title", slug="job")
+        body = {
+            'http://happy-dev.fr/owl/#joboffers':
+                {
+                    '@id': "http://testserver/resources/{}/joboffers/".format(resource.pk),
+                    'ldp:contains': [
+                        {'@id': 'http://testserver/job-offers/{}/'.format(job.slug),
+                         'http://happy-dev.fr/owl/#title': "new job",
+                         },
+                    ]
+                }
+        }
+
+        response = self.client.put('/resources/{}/'.format(resource.pk),
+                                   data=json.dumps(body),
+                                   content_type='application/ld+json')
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.data['joboffers']['ldp:contains'][0]['@id'],
+                         "http://testserver/job-offers/{}/".format(job.slug))
+        self.assertEqual(response.data['joboffers']['ldp:contains'][0]['title'], "new job")
+
     def test_m2m_new_link_embedded(self):
         resource = Resource.objects.create()
         body = {
@@ -413,3 +453,27 @@ class Update(TestCase):
                          "http://testserver/job-offers/aaa/")
         self.assertEqual(response.data['joboffers']['ldp:contains'][0]['title'], "new job")
 
+    def test_m2m_existing_link(self):
+        resource = Resource.objects.create()
+        job = JobOffer.objects.create(title="first title", slug="job")
+        resource.joboffers.add(job)
+        resource.save()
+        body = {
+            'http://happy-dev.fr/owl/#joboffers': {
+                # '@id': "http://testserver/resources/{}/joboffers/".format(resource.pk),
+                'ldp:contains': [
+                    {
+                        '@id': 'http://testserver/job-offers/{}/'.format(job.slug),
+                        'http://happy-dev.fr/owl/#title': "new job",
+                    }
+                ]
+            }
+        }
+
+        response = self.client.put('/resources/{}/'.format(resource.pk),
+                                   data=json.dumps(body),
+                                   content_type='application/ld+json')
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.data['joboffers']['ldp:contains'][0]['@id'],
+                         "http://testserver/job-offers/{}/".format(job.slug))
+        self.assertEqual(response.data['joboffers']['ldp:contains'][0]['title'], "new job")
-- 
GitLab