Repository: hydroshare/hydroshare

Issue:
User account deletion doesn't remove resources from SOLR index
**Description of the bug**
Deleting a user in mezzanine also cascades to delete the user's resources. However it looks like the resources are not removed from the SOLR index. They still show up in discover.

Steps to reproduce the bug:
1. make a new user account
2. add a resource and make it discoverable
3. login as admin user and delete the account that you created in step 1 (via the mezzanine admin panel)
4. See that the resource listing persists on the Discover search page

**Expected behavior**
User account deletion should remove the user's resources from the SOLR index

**Additional information**
HS v 2.9.2



Discussion:
for some reason we can't remove a resource from SOLR that has already been removed from django:
https://github.com/hydroshare/hydroshare/blob/develop/hs_core/management/commands/solr_update.py#L142
we should figure out why
I think we could probably figure out how to delete solr indexes that aren't in Django.  The remove method takes the django model instance or a string.  If you pass in the django model instance then it creates a string identifier from that looks like `<app.label>.<object_name>.<pk>`.  I don't see why we couldn't create that string manually and pass it into the remove method.

It is also possible to override the identifier method.  We could probably update the identifier method to just use the short_id. https://django-haystack.readthedocs.io/en/master/settings.html#haystack-identifier-method
#5218 updates the management command to remove previously deleted resources form the solr index.

Resolving patch:
diff --git a/hs_core/hydro_realtime_signal_processor.py b/hs_core/hydro_realtime_signal_processor.py
--- a/hs_core/hydro_realtime_signal_processor.py
+++ b/hs_core/hydro_realtime_signal_processor.py
@@ -21,11 +21,13 @@ def setup(self):
         if not getattr(settings, "DISABLE_HAYSTACK", False):
             models.signals.post_save.connect(self.handle_update, sender=Date)
             models.signals.post_save.connect(self.handle_access, sender=ResourceAccess)
+            models.signals.post_delete.connect(self.handle_delete, sender=BaseResource)
 
     def teardown(self):
         if not getattr(settings, "DISABLE_HAYSTACK", False):
             models.signals.post_save.disconnect(self.handle_update, sender=Date)
             models.signals.post_save.disconnect(self.handle_access, sender=ResourceAccess)
+            models.signals.post_delete.disconnect(self.handle_delete, sender=BaseResource)
 
     def handle_update(self, sender, instance, **kwargs):
         try:


Test patch:
diff --git a/hs_rest_api/tests/http/test_discover_res_delete.py b/hs_rest_api/tests/http/test_discover_res_delete.py
new file mode 100755
--- /dev/null
+++ b/hs_rest_api/tests/http/test_discover_res_delete.py
@@ -0,0 +1,84 @@
+import json
+import tempfile
+
+from django.core.management import call_command
+from django.urls import reverse
+from rest_framework import status
+
+from hs_core.tests.api.rest.base import HSRESTTestCase
+from hs_core import hydroshare
+
+
+class TestDiscoverResourceDelete(HSRESTTestCase):
+    def setUp(self):
+        super(TestDiscoverResourceDelete, self).setUp()
+
+        self.temp_dir = tempfile.mkdtemp()
+        self.resources_to_delete = []
+        # delete any existing records from haystack
+        call_command('clear_index', "--noinput")
+
+        self.admin = hydroshare.create_account(
+            'admin@gmail.com',
+            username='admin',
+            first_name='admin',
+            last_name='admin',
+            superuser=True,
+            groups=[]
+        )
+
+        self.owner = hydroshare.create_account(
+            'owner@gmail.com',
+            username='owner',
+            first_name='owner',
+            last_name='owner',
+            superuser=False,
+            groups=[]
+        )
+
+    def tearDown(self):
+        super(TestDiscoverResourceDelete, self).tearDown()
+        # clean up haystack
+        call_command('clear_index', "--noinput")
+
+    def test_discover_res_delete(self):
+        """Test that deleting user account cascades to remove resource from solr index
+        """
+        response = self.client.get(reverse('discover-hsapi', kwargs={}))
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        response_json = json.loads(response.content.decode())
+        # there should be no resources in the index
+        self.assertEqual(response_json.get("count"), 0)
+
+        resource = hydroshare.create_resource(
+            resource_type='CompositeResource',
+            owner=self.owner,
+            title='Test Resource',
+            metadata=[],
+        )
+
+        # set the resource to discoverable so that it shows up in the discover view
+        resource.raccess.discoverable = True
+        resource.raccess.save()
+
+        response = self.client.get(reverse('discover-hsapi', kwargs={}))
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        response_json = json.loads(response.content.decode())
+        # there should be 1 resource in the index
+        self.assertEqual(response_json.get("count"), 1)
+
+        # matching search test
+        response = self.client.get(reverse('discover-hsapi', kwargs={}) + "?title__contains=Test")
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        response_json = json.loads(response.content.decode())
+        # there should be one matching resource in the index
+        self.assertEqual(response_json.get("count"), 1)
+
+        # delete_resource(resource.short_id)
+        self.owner.delete()
+
+        response = self.client.get(reverse('discover-hsapi', kwargs={}) + "?title__contains=Test")
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        response_json = json.loads(response.content.decode())
+        # there should be no matching resources in the index
+        self.assertEqual(response_json.get("count"), 0)