소스 검색

HUE-6251 [editor] Log warnings and continue on failed bulk delete and copy actions

Jenny Kim 8 년 전
부모
커밋
523b324
2개의 변경된 파일87개의 추가작업 그리고 18개의 파일을 삭제
  1. 34 0
      desktop/libs/notebook/src/notebook/tests.py
  2. 53 18
      desktop/libs/notebook/src/notebook/views.py

+ 34 - 0
desktop/libs/notebook/src/notebook/tests.py

@@ -229,6 +229,40 @@ class TestNotebookApi(object):
     trash_uuids = [doc['uuid'] for doc in data['children']]
     assert_true(notebook_doc.uuid in trash_uuids, data)
 
+    # Test that any errors are reported in the response
+    nonexistant_doc = {
+      "id": 12345,
+      "uuid": "ea22da5f-b69c-4843-b17d-dea5c74c41d1",
+      "selectedSnippet": "hive",
+      "showHistory": False,
+      "description": "Test Hive Query",
+      "name": "Test Hive Query",
+      "sessions": [
+        {
+          "type": "hive",
+          "properties": [],
+          "id": None,
+        }
+      ],
+      "type": "query-hive",
+      "snippets": [{
+        "id": "e069ef32-5c95-4507-b961-e79c090b5abf",
+        "type": "hive",
+        "status": "ready",
+        "database": "default",
+        "statement": "select * from web_logs",
+        "statement_raw": "select * from web_logs",
+         "properties": {"settings": [], "files": [], "functions": []},
+        "result": {}
+      }]
+    }
+    trash_notebooks = [nonexistant_doc]
+    response = self.client.post(reverse('notebook:delete'), {'notebooks': json.dumps(trash_notebooks)})
+    data = json.loads(response.content)
+    assert_equal(0, data['status'], data)
+    assert_equal('Trashed 0 notebook(s) and failed to delete 1 notebook(s).', data['message'], data)
+    assert_equal(['ea22da5f-b69c-4843-b17d-dea5c74c41d1'], data['errors'])
+
 
   def test_query_error_encoding(self):
     @api_error_handler

+ 53 - 18
desktop/libs/notebook/src/notebook/views.py

@@ -27,7 +27,7 @@ from desktop.conf import USE_NEW_EDITOR
 from desktop.lib.django_util import render, JsonResponse
 from desktop.lib.exceptions_renderable import PopupException
 from desktop.lib.json_utils import JSONEncoderForHTML
-from desktop.models import Document2, Document
+from desktop.models import Document2, Document, FilesystemException
 
 from metadata.conf import has_optimizer, has_navigator
 
@@ -238,33 +238,68 @@ def execute_and_watch(request):
 
 @check_document_modify_permission()
 def delete(request):
+  response = {'status': -1}
+
   notebooks = json.loads(request.POST.get('notebooks', '[]'))
 
-  ctr = 0
-  for notebook in notebooks:
-    doc2 = Document2.objects.get_by_uuid(user=request.user, uuid=notebook['uuid'], perm_type='write')
-    doc = doc2.doc.get()
-    doc.can_write_or_exception(request.user)
-    doc2.trash()
-    ctr += 1
+  if not notebooks:
+    response['message'] = _('No notebooks have been selected for deletion.')
+  else:
+    ctr = 0
+    failures = []
+    for notebook in notebooks:
+      try:
+        doc2 = Document2.objects.get_by_uuid(user=request.user, uuid=notebook['uuid'], perm_type='write')
+        doc = doc2.doc.get()
+        doc.can_write_or_exception(request.user)
+        doc2.trash()
+        ctr += 1
+      except FilesystemException, e:
+        failures.append(notebook['uuid'])
+        LOG.exception("Failed to delete document with UUID %s that is writable by user %s, skipping." % (notebook['uuid'], request.user.username))
+
+    response['status'] = 0
+    if failures:
+      response['errors'] = failures
+      response['message'] = _('Trashed %d notebook(s) and failed to delete %d notebook(s).') % (ctr, len(failures))
+    else:
+      response['message'] = _('Trashed %d notebook(s)') % ctr
 
-  return JsonResponse({'status': 0, 'message': _('Trashed %d notebook(s)') % ctr})
+  return JsonResponse(response)
 
 
 @check_document_access_permission()
 def copy(request):
-  notebooks = json.loads(request.POST.get('notebooks', '[]'))
+  response = {'status': -1}
 
-  for notebook in notebooks:
-    doc2 = Document2.objects.get_by_uuid(user=request.user, uuid=notebook['uuid'])
-    doc = doc2.doc.get()
-
-    name = doc2.name + '-copy'
-    doc2 = doc2.copy(name=name, owner=request.user)
+  notebooks = json.loads(request.POST.get('notebooks', '[]'))
 
-    doc.copy(content_object=doc2, name=name, owner=request.user)
+  if len(notebooks) == 0:
+    response['message'] = _('No notebooks have been selected for copying.')
+  else:
+    ctr = 0
+    failures = []
+    for notebook in notebooks:
+      try:
+        doc2 = Document2.objects.get_by_uuid(user=request.user, uuid=notebook['uuid'])
+        doc = doc2.doc.get()
+
+        name = doc2.name + '-copy'
+        doc2 = doc2.copy(name=name, owner=request.user)
+
+        doc.copy(content_object=doc2, name=name, owner=request.user)
+      except FilesystemException, e:
+        failures.append(notebook['uuid'])
+        LOG.exception("Failed to copy document with UUID %s accessible by user %s, skipping." % (notebook['uuid'], request.user.username))
+
+    response['status'] = 0
+    if failures:
+      response['errors'] = failures
+      response['message'] = _('Copied %d notebook(s) and failed to copy %d notebook(s).') % (ctr, len(failures))
+    else:
+      response['message'] = _('Copied %d notebook(s)') % ctr
 
-  return JsonResponse({})
+  return JsonResponse(response)
 
 
 @check_document_access_permission()