Browse Source

[core] User default app preference can have duplicate rows

[21/Nov/2020 21:51:50 -0800] models       ERROR    Could not load back default app
Traceback (most recent call last):
  File "/usr/share/hue/desktop/core/src/desktop/models.py", line 1762, in get_main_quick_action
    UserPreferences.objects.get(user=self.user, key='default_app').value
  File "/usr/share/hue/build/env/local/lib/python2.7/site-packages/Django-1.11.29-py2.7.egg/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/share/hue/build/env/local/lib/python2.7/site-packages/Django-1.11.29-py2.7.egg/django/db/models/query.py", line 384, in get
    (self.model._meta.object_name, num)
MultipleObjectsReturned: get() returned more than one UserPreferences -- it returned 2!
Romain Rigaux 5 years ago
parent
commit
af374d43ce
1 changed files with 19 additions and 7 deletions
  1. 19 7
      desktop/core/src/desktop/models.py

+ 19 - 7
desktop/core/src/desktop/models.py

@@ -129,7 +129,10 @@ if not ENABLE_ORGANIZATIONS.get():
 
 
 
 
 class UserPreferences(models.Model):
 class UserPreferences(models.Model):
-  """Holds arbitrary key/value strings."""
+  """
+  Holds arbitrary key/value strings.
+  Note: ideally user/jkeu should be unique together.
+  """
   user = models.ForeignKey(User)
   user = models.ForeignKey(User)
   key = models.CharField(max_length=20)
   key = models.CharField(max_length=20)
   value = models.TextField(max_length=4096)
   value = models.TextField(max_length=4096)
@@ -1723,7 +1726,8 @@ class ClusterConfig(object):
           editors,
           editors,
           app_config.get('dashboard'),
           app_config.get('dashboard'),
           app_config.get('scheduler')
           app_config.get('scheduler')
-        ] if app is not None
+        ]
+        if app is not None
       ],
       ],
       'default_sql_interpreter': default_sql_interpreter,
       'default_sql_interpreter': default_sql_interpreter,
       'cluster_type': self.cluster_type,
       'cluster_type': self.cluster_type,
@@ -1758,15 +1762,18 @@ class ClusterConfig(object):
     default_interpreter = default_app.get('interpreters')
     default_interpreter = default_app.get('interpreters')
 
 
     try:
     try:
-      user_default_app = json.loads(
-        UserPreferences.objects.get(user=self.user, key='default_app').value
-      )
+      user_preference = get_user_preferences(user=self.user, key='default_app')
+      if not user_preference:
+        raise UserPreferences.DoesNotExist()
+      user_default_app = json.loads(user_preference.value)
       if apps.get(user_default_app['app']):
       if apps.get(user_default_app['app']):
         default_interpreter = []
         default_interpreter = []
         default_app = apps[user_default_app['app']]
         default_app = apps[user_default_app['app']]
         if default_app.get('interpreters'):
         if default_app.get('interpreters'):
-          interpreters = [interpreter for interpreter in default_app['interpreters']
-                          if interpreter['type'] == user_default_app['interpreter']]
+          interpreters = [
+            interpreter
+            for interpreter in default_app['interpreters'] if interpreter['type'] == user_default_app['interpreter']
+          ]
           if interpreters:
           if interpreters:
             default_interpreter = interpreters
             default_interpreter = interpreters
     except UserPreferences.DoesNotExist:
     except UserPreferences.DoesNotExist:
@@ -2177,10 +2184,15 @@ def get_user_preferences(user, key=None):
       return {key: x.value}
       return {key: x.value}
     except UserPreferences.DoesNotExist:
     except UserPreferences.DoesNotExist:
       return None
       return None
+    except UserPreferences.MultipleObjectsReturned:
+      for dup in UserPreferences.objects.filter(user=user, key=key)[1:]:
+        LOG.warn('Deleting UserPreferences duplicate %s' % dup)
+        dup.delete()
   else:
   else:
     return dict((x.key, x.value) for x in UserPreferences.objects.filter(user=user))
     return dict((x.key, x.value) for x in UserPreferences.objects.filter(user=user))
 
 
 
 
+
 def set_user_preferences(user, key, value):
 def set_user_preferences(user, key, value):
   try:
   try:
     x = UserPreferences.objects.get(user=user, key=key)
     x = UserPreferences.objects.get(user=user, key=key)