Repository: translate/pootle

Issue:
Pootle breaks if vfolders are disabled
Unnecessary vfolder queries are being run even if a deployment disables them. This is especially a problem when using the search by location feature (i.e. clicking on the link of the locations text in a unit), which ends up breaking like this:

``` python
Traceback (most recent call last):
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "~/dev/translate/pootle/pootle/apps/pootle_misc/util.py", line 59, in wrapper
    return f(request, *args, **kwargs)
  File "~/dev/translate/pootle/pootle/apps/pootle_store/views.py", line 474, in get_units
    vfolder, pootle_path = extract_vfolder_from_path(pootle_path)
  File "~/dev/translate/pootle/pootle/apps/virtualfolder/helpers.py", line 63, in extract_vfolder_from_path
    for vf in vfolders:
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/django/db/models/query.py", line 141, in __iter__
    self._fetch_all()
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/django/db/models/query.py", line 966, in _fetch_all
    self._result_cache = list(self.iterator())
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/django/db/models/query.py", line 265, in iterator
    for row in compiler.results_iter():
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 701, in results_iter
    for rows in self.execute_sql(MULTI):
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 787, in execute_sql
    cursor.execute(sql, params)
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/django/db/backends/utils.py", line 81, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/django/db/backends/mysql/base.py", line 129, in execute
    return self.cursor.execute(query, args)
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/MySQLdb/cursors.py", line 205, in execute
    self.errorhandler(self, exc, value)
  File "~/.virtualenvs/pootle/lib/python2.7/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
OperationalError: (1054, "Unknown column 'virtualfolder_virtualfolder.is_public' in 'field list'")
```

This specific error happens because some migrations haven't been applied. In any case, what this raises is that having no virtualfolder DB tables has even worse consequences, as Pootle completely breaks.

If it should be possible to disable the virtualfolder feature (as the code advertises), this should be fixed.



Discussion:

Resolving patch:
diff --git a/pootle/apps/pootle_store/views.py b/pootle/apps/pootle_store/views.py
--- a/pootle/apps/pootle_store/views.py
+++ b/pootle/apps/pootle_store/views.py
@@ -38,8 +38,6 @@
 from pootle_misc.util import ajax_required, to_int, get_date_interval
 from pootle_statistics.models import (Submission, SubmissionFields,
                                       SubmissionTypes)
-from virtualfolder.helpers import extract_vfolder_from_path
-from virtualfolder.models import VirtualFolder
 
 from .decorators import get_unit_context
 from .fields import to_python
@@ -470,8 +468,12 @@ def get_units(request):
     User = get_user_model()
     request.profile = User.get(request.user)
     limit = request.profile.get_unit_rows()
+    vfolder = None
 
-    vfolder, pootle_path = extract_vfolder_from_path(pootle_path)
+    if 'virtualfolder' in settings.INSTALLED_APPS:
+        from virtualfolder.helpers import extract_vfolder_from_path
+
+        vfolder, pootle_path = extract_vfolder_from_path(pootle_path)
 
     units_qs = Unit.objects.get_for_path(pootle_path, request.profile)
 
@@ -764,20 +766,28 @@ def get_edit_unit(request, unit):
     project = translation_project.project
 
     priority = None
-    vfolder_pk = request.GET.get('vfolder', '')
 
-    if vfolder_pk:
-        try:
-            # If we are translating a virtual folder, then display its priority.
-            # Note that the passed virtual folder pk might be invalid.
-            priority = VirtualFolder.objects.get(pk=vfolder_pk).priority
-        except VirtualFolder.DoesNotExist:
-            pass
-
-    if priority is None:
-        # Retrieve the unit top priority, if any. This can happen if we are not
-        # in a virtual folder or if the passed virtual folder pk is invalid.
-        priority = unit.vfolders.aggregate(priority=Max('priority'))['priority']
+    if 'virtualfolder' in settings.INSTALLED_APPS:
+        vfolder_pk = request.GET.get('vfolder', '')
+
+        if vfolder_pk:
+            from virtualfolder.models import VirtualFolder
+
+            try:
+                # If we are translating a virtual folder, then display its
+                # priority.
+                # Note that the passed virtual folder pk might be invalid.
+                priority = VirtualFolder.objects.get(pk=vfolder_pk).priority
+            except VirtualFolder.DoesNotExist:
+                pass
+
+        if priority is None:
+            # Retrieve the unit top priority, if any. This can happen if we are
+            # not in a virtual folder or if the passed virtual folder pk is
+            # invalid.
+            priority = unit.vfolders.aggregate(
+                priority=Max('priority')
+            )['priority']
 
     template_vars = {
         'unit': unit,


Test patch: